struct mail_namespace *ns;
struct mailbox *box;
- if (!client_verify_mailbox_name(cmd, name,
- CLIENT_VERIFY_MAILBOX_SHOULD_EXIST_TRYCREATE))
- return NULL;
-
- ns = client_find_namespace(cmd, &name);
+ ns = client_find_namespace(cmd, &name,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST_TRYCREATE);
if (ns == NULL)
return NULL;
if (!client_verify_open_mailbox(cmd))
return TRUE;
- /* open the destination mailbox */
- if (!client_verify_mailbox_name(cmd, mailbox,
- CLIENT_VERIFY_MAILBOX_SHOULD_EXIST_TRYCREATE))
- return TRUE;
-
ret = imap_search_get_seqset(cmd, messageset, cmd->uid, &search_args);
if (ret <= 0)
return ret < 0;
- dest_ns = client_find_namespace(cmd, &mailbox);
+ /* open the destination mailbox */
+ dest_ns = client_find_namespace(cmd, &mailbox,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST_TRYCREATE);
if (dest_ns == NULL)
return TRUE;
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
+#include "imap-resp-code.h"
#include "mail-namespace.h"
#include "imap-commands.h"
return FALSE;
full_mailbox = mailbox;
- ns = client_find_namespace(cmd, &mailbox);
+ ns = client_find_namespace(cmd, &mailbox, CLIENT_VERIFY_MAILBOX_NONE);
if (ns == NULL)
return TRUE;
if (len == 0 || full_mailbox[len-1] != ns->sep)
directory = FALSE;
else if (*mailbox == '\0') {
- client_send_tagline(cmd, "NO Namespace already exists.");
+ client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS
+ "] Namespace already exists.");
return TRUE;
} else {
/* name ends with hierarchy separator - client is just
full_mailbox = t_strndup(full_mailbox, len-1);
}
- if (!client_verify_mailbox_name(cmd, full_mailbox,
- CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST))
+ mailbox = full_mailbox;
+ ns = client_find_namespace(cmd, &mailbox,
+ CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST);
+ if (ns == NULL)
return TRUE;
box = mailbox_alloc(ns->list, mailbox, NULL, 0);
return TRUE;
}
- ns = client_find_namespace(cmd, &name);
+ ns = client_find_namespace(cmd, &name,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST);
if (ns == NULL)
return TRUE;
ctx->inbox_found = TRUE;
flags = list_get_inbox_flags(ctx);
+ } else if (mailbox_list_mailbox(ctx->ns->list, "", &flags) > 0) {
+ /* mailbox with namespace prefix exists */
} else {
flags = MAILBOX_NONEXISTENT;
}
if (!client_read_string_args(cmd, 2, &oldname, &newname))
return FALSE;
- if (!client_verify_mailbox_name(cmd, oldname,
- CLIENT_VERIFY_MAILBOX_SHOULD_EXIST))
- return TRUE;
- if (!client_verify_mailbox_name(cmd, newname,
- CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST))
- return TRUE;
-
- old_ns = client_find_namespace(cmd, &oldname);
+ old_ns = client_find_namespace(cmd, &oldname,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST);
if (old_ns == NULL)
return TRUE;
- new_ns = client_find_namespace(cmd, &newname);
+ new_ns = client_find_namespace(cmd, &newname,
+ CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST);
if (new_ns == NULL)
return TRUE;
ctx = p_new(cmd->pool, struct imap_select_context, 1);
ctx->cmd = cmd;
- ctx->ns = client_find_namespace(cmd, &mailbox);
+ ctx->ns = client_find_namespace(cmd, &mailbox,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST);
if (ctx->ns == NULL)
return TRUE;
&items) < 0)
return TRUE;
- ns = client_find_namespace(cmd, &real_mailbox);
+ ns = client_find_namespace(cmd, &real_mailbox,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST);
if (ns == NULL)
return TRUE;
verify_name = mailbox;
real_name = mailbox;
- real_ns = client_find_namespace(cmd, &real_name);
+ real_ns = client_find_namespace(cmd, &real_name,
+ CLIENT_VERIFY_MAILBOX_NONE);
if (real_ns == NULL)
return TRUE;
verify_name)) {
/* subscribing to a listable namespace prefix, allow it. */
} else if (subscribe) {
- if (!client_verify_mailbox_name(cmd, verify_name,
- CLIENT_VERIFY_MAILBOX_SHOULD_EXIST))
+ if (client_find_namespace(cmd, &verify_name,
+ CLIENT_VERIFY_MAILBOX_SHOULD_EXIST) == NULL)
return TRUE;
} else {
- if (!client_verify_mailbox_name(cmd, verify_name,
- CLIENT_VERIFY_MAILBOX_NAME))
+ if (client_find_namespace(cmd, &verify_name,
+ CLIENT_VERIFY_MAILBOX_NAME) == NULL)
return TRUE;
}
#define MAILBOX_MAX_NAME_LEN 512
struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char **mailbox)
-{
- struct mail_namespace *ns;
-
- ns = mail_namespace_find(cmd->client->user->namespaces, mailbox);
- if (ns != NULL)
- return ns;
-
- client_send_tagline(cmd, "NO Unknown namespace.");
- return NULL;
-}
-
-bool client_verify_mailbox_name(struct client_command_context *cmd,
- const char *mailbox,
- enum client_verify_mailbox_mode mode)
+client_find_namespace(struct client_command_context *cmd, const char **mailboxp,
+ enum client_verify_mailbox_mode mode)
{
struct mail_namespace *ns;
enum mailbox_name_status mailbox_status;
- const char *orig_mailbox, *p, *resp_code = NULL;
+ const char *orig_mailbox, *mailbox, *p, *resp_code = NULL;
- orig_mailbox = mailbox;
- ns = client_find_namespace(cmd, &mailbox);
- if (ns == NULL)
- return FALSE;
+ orig_mailbox = *mailboxp;
+ ns = mail_namespace_find(cmd->client->user->namespaces, mailboxp);
+ if (ns == NULL) {
+ client_send_tagline(cmd, "NO Unknown namespace.");
+ return NULL;
+ }
+ mailbox = *mailboxp;
+
+ if (mode == CLIENT_VERIFY_MAILBOX_NONE)
+ return ns;
/* make sure it even looks valid */
- if (*mailbox == '\0') {
+ if (*mailbox == '\0' && !(*orig_mailbox != '\0' && ns->list)) {
client_send_tagline(cmd, "NO Empty mailbox name.");
- return FALSE;
+ return NULL;
}
if (ns->real_sep != ns->sep && ns->prefix_len < strlen(orig_mailbox)) {
"NO Character not allowed "
"in mailbox name: '%c'",
ns->real_sep));
- return FALSE;
+ return NULL;
}
}
}
for (p = mailbox+1; *p != '\0'; p++) {
if (p[0] == ns->real_sep && p[-1] == ns->real_sep) {
client_send_tagline(cmd, "NO Invalid mailbox name.");
- return FALSE;
+ return NULL;
}
}
if (strlen(mailbox) > MAILBOX_MAX_NAME_LEN) {
client_send_tagline(cmd, "NO Mailbox name too long.");
- return FALSE;
+ return NULL;
}
/* check what our storage thinks of it */
if (mailbox_list_get_mailbox_name_status(ns->list, mailbox,
&mailbox_status) < 0) {
client_send_list_error(cmd, ns->list);
- return FALSE;
+ return NULL;
}
switch (mailbox_status) {
case MAILBOX_NAME_EXISTS:
switch (mode) {
+ case CLIENT_VERIFY_MAILBOX_NONE:
case CLIENT_VERIFY_MAILBOX_NAME:
case CLIENT_VERIFY_MAILBOX_SHOULD_EXIST:
case CLIENT_VERIFY_MAILBOX_SHOULD_EXIST_TRYCREATE:
- return TRUE;
+ return ns;
case CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST:
break;
}
if (mode == CLIENT_VERIFY_MAILBOX_NAME ||
mode == CLIENT_VERIFY_MAILBOX_SHOULD_EXIST)
- return TRUE;
+ return ns;
client_send_tagline(cmd, t_strconcat(
"NO [", IMAP_RESP_CODE_ALREADYEXISTS,
switch (mode) {
case CLIENT_VERIFY_MAILBOX_NAME:
case CLIENT_VERIFY_MAILBOX_SHOULD_NOT_EXIST:
- return TRUE;
+ return ns;
case CLIENT_VERIFY_MAILBOX_SHOULD_EXIST:
resp_code = IMAP_RESP_CODE_NONEXISTENT;
break;
default:
i_unreached();
}
-
- return FALSE;
+ return NULL;
}
bool client_verify_open_mailbox(struct client_command_context *cmd)
#define IMAP_COMMANDS_UTIL_H
enum client_verify_mailbox_mode {
+ /* Don't verify mailbox name validity */
+ CLIENT_VERIFY_MAILBOX_NONE,
/* Verify only that the mailbox name is valid */
CLIENT_VERIFY_MAILBOX_NAME,
/* If mailbox doesn't exist, fail with [NONEXISTENT] resp code */
struct mail_full_flags;
struct mailbox_keywords;
-/* Finds namespace for given mailbox from namespaces. If not found,
- sends "Unknown namespace" error message to client. */
+/* Finds namespace for given mailbox from namespaces. If namespace isn't found
+ or mailbox name is invalid, sends a tagged NO reply to client. */
struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char **mailbox);
-
-/* Returns TRUE if verifications succeeds. If it fails, a tagged NO is sent to
- client. */
-bool client_verify_mailbox_name(struct client_command_context *cmd,
- const char *mailbox,
- enum client_verify_mailbox_mode mode);
+client_find_namespace(struct client_command_context *cmd, const char **mailbox,
+ enum client_verify_mailbox_mode mode);
/* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected"
error message to client. */
return -1;
/* tmp/ directory doesn't exist. does the maildir? */
- if (inbox || stat(box->path, &st) == 0) {
+ if (inbox || (*box->name != '\0' && stat(box->path, &st) == 0)) {
/* yes, we'll need to create the missing dirs */
mailbox_list_get_dir_permissions(box->list, box->name,
&mode, &gid, &gid_origin);
return -1;
return maildir_mailbox_open_existing(box);
- } else if (errno == ENOENT) {
+ } else if (*box->name == '\0' || errno == ENOENT) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
T_MAIL_ERR_MAILBOX_NOT_FOUND(box->name));
return -1;
maildir_list_get_dirname_path(struct mailbox_list *list, const char *dir,
const char *name)
{
- if (strcmp(list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0)
+ if (strcmp(list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 || *name == '\0')
return t_strdup_printf("%s/%s", dir, name);
return t_strdup_printf("%s/%c%s", dir, list->hierarchy_sep, name);
{
size_t len;
- if (*name == '\0' && *list->ns->prefix != '\0' &&
- (list->ns->flags & NAMESPACE_FLAG_INBOX) == 0) {
- /* an ugly way to get to Maildir/ root when it's not the
- INBOX. */
- return TRUE;
- }
-
if (!maildir_list_is_valid_common(list, name, &len))
return FALSE;
return namespaces->sep;
}
+static bool mail_namespace_is_usable_prefix(struct mail_namespace *ns,
+ const char *mailbox, bool inbox)
+{
+ if (strncmp(ns->prefix, mailbox, ns->prefix_len) == 0) {
+ /* true exact prefix match */
+ return TRUE;
+ }
+
+ if (inbox && strncmp(ns->prefix, "INBOX", 5) == 0 &&
+ strncmp(ns->prefix+5, mailbox+5, ns->prefix_len-5) == 0) {
+ /* we already checked that mailbox begins with case-insensitive
+ INBOX. this namespace also begins with INBOX and the rest
+ of the prefix matches too. */
+ return TRUE;
+ }
+
+ if (strncmp(ns->prefix, mailbox, ns->prefix_len-1) == 0 &&
+ mailbox[ns->prefix_len-1] == '\0' &&
+ ns->prefix[ns->prefix_len-1] == ns->sep) {
+ /* we're trying to access the namespace prefix itself */
+ return TRUE;
+ }
+ return FALSE;
+}
+
static struct mail_namespace *
mail_namespace_find_mask(struct mail_namespace *namespaces,
const char **mailbox,
struct mail_namespace *ns = namespaces;
const char *box = *mailbox;
struct mail_namespace *best = NULL;
- size_t best_len = 0;
+ unsigned int len, best_len = 0;
bool inbox;
inbox = strncasecmp(box, "INBOX", 5) == 0;
}
for (; ns != NULL; ns = ns->next) {
- if (ns->prefix_len >= best_len &&
- (strncmp(ns->prefix, box, ns->prefix_len) == 0 ||
- (inbox && strncmp(ns->prefix, "INBOX", 5) == 0 &&
- strncmp(ns->prefix+5, box+5, ns->prefix_len-5) == 0)) &&
- (ns->flags & mask) == flags) {
+ if (ns->prefix_len >= best_len && (ns->flags & mask) == flags &&
+ mail_namespace_is_usable_prefix(ns, box, inbox)) {
best = ns;
best_len = ns->prefix_len;
}
}
if (best != NULL) {
- if (best_len > 0)
- *mailbox += best_len;
- else if (inbox && (box[5] == best->sep || box[5] == '\0'))
+ if (best_len > 0) {
+ len = strlen(*mailbox);
+ *mailbox += I_MIN(len, best_len);
+ } else if (inbox && (box[5] == best->sep || box[5] == '\0'))
*mailbox = t_strconcat("INBOX", box+5, NULL);
*mailbox = mail_namespace_fix_sep(best, *mailbox);
}
-
return best;
}
bool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
const char *name)
{
+ if (*name == '\0' && *list->ns->prefix != '\0' &&
+ (list->ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0) {
+ /* an ugly way to get to mailbox root (e.g. Maildir/ when
+ it's not the INBOX) */
+ return TRUE;
+ }
+
return list->v.is_valid_existing_name(list, name);
}
*status = MAILBOX_NAME_INVALID;
return 0;
}
-
return list->v.get_mailbox_name_status(list, name, status);
}
return ctx->list->v.iter_deinit(ctx);
}
+int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
+ enum mailbox_info_flags *flags_r)
+{
+ struct mailbox_list_iterate_context ctx;
+ const char *path;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.list = list;
+
+ *flags_r = 0;
+ path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
+ return list->v.iter_is_mailbox(&ctx, path, "", "",
+ MAILBOX_LIST_FILE_TYPE_UNKNOWN,
+ flags_r);
+}
+
int mailbox_list_set_subscribed(struct mailbox_list *list,
const char *name, bool set)
{
int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
{
- if (!mailbox_list_is_valid_existing_name(list, name)) {
+ if (!mailbox_list_is_valid_existing_name(list, name) || *name == '\0') {
mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
return -1;
mailbox_list_get_closest_storage(newlist, &newstorage);
if (!mailbox_list_is_valid_existing_name(oldlist, oldname) ||
+ *oldname == '\0' ||
!mailbox_list_is_valid_create_name(newlist, newname)) {
mailbox_list_set_error(oldlist, MAIL_ERROR_PARAMS,
"Invalid mailbox name");
/* Deinitialize mailbox list request. Returns -1 if some error
occurred while listing. */
int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **ctx);
+/* List one mailbox. Returns 1 if info returned, 0 if mailbox doesn't exist,
+ -1 if error. */
+int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
+ enum mailbox_info_flags *flags_r);
/* Subscribe/unsubscribe mailbox. There should be no error when
subscribing to already subscribed mailbox. Subscribing to
return NULL;
}
- ns = client_find_namespace(cmd, &name);
+ ns = client_find_namespace(cmd, &name, CLIENT_VERIFY_MAILBOX_NONE);
if (ns == NULL)
return NULL;
}
real_mailbox = mailbox;
- ns = client_find_namespace(cmd, &real_mailbox);
+ ns = client_find_namespace(cmd, &real_mailbox,
+ CLIENT_VERIFY_MAILBOX_NONE);
if (ns == NULL)
return TRUE;
return FALSE;
orig_mailbox = mailbox;
- ns = client_find_namespace(cmd, &mailbox);
+ ns = client_find_namespace(cmd, &mailbox, CLIENT_VERIFY_MAILBOX_NONE);
if (ns == NULL)
return TRUE;