From: Timo Sirainen Date: Mon, 6 Dec 2010 00:30:36 +0000 (+0000) Subject: imap: Avoid using mailbox_list_get_mailbox_name_status() X-Git-Tag: 2.1.alpha1~454 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=62f49ddfc6fddae2c512961e17d8c7b963108bb4;p=thirdparty%2Fdovecot%2Fcore.git imap: Avoid using mailbox_list_get_mailbox_name_status() The validity checks should already be done by the actual commands in most cases (if they didn't, there would be race condition bugs). The only exception is SUBSCRIBE. It doesn't require that the mailbox exists, but we want to enforce that anyway via IMAP. --- diff --git a/src/imap/cmd-append.c b/src/imap/cmd-append.c index 7e6b9a1ba8..93e464fb13 100644 --- a/src/imap/cmd-append.c +++ b/src/imap/cmd-append.c @@ -445,47 +445,6 @@ static bool cmd_append_continue_message(struct client_command_context *cmd) return FALSE; } -static struct mailbox * -get_mailbox(struct client_command_context *cmd, const char *name) -{ - struct mail_namespace *ns; - struct mailbox *box; - enum mailbox_name_status status; - const char *storage_name; - - ns = client_find_namespace(cmd, name, &storage_name, &status); - if (ns == NULL) - return NULL; - - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, name, "TRYCREATE", status); - return NULL; - } - - if (cmd->client->mailbox != NULL && - mailbox_equals(cmd->client->mailbox, ns, storage_name)) - return cmd->client->mailbox; - - box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_SAVEONLY | - MAILBOX_FLAG_KEEP_RECENT); - if (mailbox_open(box) < 0) { - client_send_storage_error(cmd, mailbox_get_storage(box)); - mailbox_free(&box); - return NULL; - } - if (cmd->client->enabled_features != 0) - mailbox_enable(box, cmd->client->enabled_features); - return box; -} - bool cmd_append(struct client_command_context *cmd) { struct client *client = cmd->client; @@ -509,8 +468,7 @@ bool cmd_append(struct client_command_context *cmd) ctx = p_new(cmd->pool, struct cmd_append_context, 1); ctx->cmd = cmd; ctx->client = client; - ctx->box = get_mailbox(cmd, mailbox); - if (ctx->box == NULL) + if (client_open_save_dest_box(cmd, mailbox, &ctx->box) < 0) ctx->failed = TRUE; else { ctx->storage = mailbox_get_storage(ctx->box); diff --git a/src/imap/cmd-copy.c b/src/imap/cmd-copy.c index 3cd415a9af..38b393ab93 100644 --- a/src/imap/cmd-copy.c +++ b/src/imap/cmd-copy.c @@ -85,13 +85,11 @@ static int fetch_and_copy(struct client *client, bool cmd_copy(struct client_command_context *cmd) { struct client *client = cmd->client; - struct mail_namespace *dest_ns; struct mail_storage *dest_storage; struct mailbox *destbox; struct mailbox_transaction_context *t; struct mail_search_args *search_args; - const char *messageset, *mailbox, *storage_name, *src_uidset; - enum mailbox_name_status status; + const char *messageset, *mailbox, *src_uidset; enum mailbox_sync_flags sync_flags = 0; enum imap_sync_flags imap_flags = 0; struct mail_transaction_commit_changes changes; @@ -110,41 +108,9 @@ bool cmd_copy(struct client_command_context *cmd) if (ret <= 0) return ret < 0; - /* open the destination mailbox */ - dest_ns = client_find_namespace(cmd, mailbox, &storage_name, &status); - if (dest_ns == NULL) + if (client_open_save_dest_box(cmd, mailbox, &destbox) < 0) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - "TRYCREATE", status); - return NULL; - } - - if (mailbox_equals(client->mailbox, dest_ns, storage_name)) - destbox = client->mailbox; - else { - destbox = mailbox_alloc(dest_ns->list, storage_name, - MAILBOX_FLAG_SAVEONLY | - MAILBOX_FLAG_KEEP_RECENT); - if (mailbox_open(destbox) < 0) { - client_send_storage_error(cmd, - mailbox_get_storage(destbox)); - mailbox_free(&destbox); - return TRUE; - } - if (client->enabled_features != 0) - mailbox_enable(destbox, client->enabled_features); - } - t = mailbox_transaction_begin(destbox, MAILBOX_TRANSACTION_FLAG_EXTERNAL | MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); diff --git a/src/imap/cmd-create.c b/src/imap/cmd-create.c index e0a8184f7b..941fcfd726 100644 --- a/src/imap/cmd-create.c +++ b/src/imap/cmd-create.c @@ -7,7 +7,6 @@ bool cmd_create(struct client_command_context *cmd) { - enum mailbox_name_status status; struct mail_namespace *ns; const char *mailbox, *storage_name; struct mailbox *box; @@ -18,7 +17,7 @@ bool cmd_create(struct client_command_context *cmd) if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; - ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; @@ -34,26 +33,18 @@ bool cmd_create(struct client_command_context *cmd) informing us that it wants to create children under this mailbox. */ directory = TRUE; - storage_name = t_strndup(storage_name, strlen(storage_name)-1); mailbox = t_strndup(mailbox, len-1); + + /* drop also from storage_name. it's already dropped when + WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */ + len = strlen(storage_name); + if (storage_name[len-1] == ns->real_sep) + storage_name = t_strndup(storage_name, len-1); } - ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_EXISTS_DIR: - if (!directory) - break; - /* fall through */ - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - return TRUE; - } box = mailbox_alloc(ns->list, storage_name, 0); if (mailbox_create(box, NULL, directory) < 0) diff --git a/src/imap/cmd-delete.c b/src/imap/cmd-delete.c index 098780c1f2..a65327a8ae 100644 --- a/src/imap/cmd-delete.c +++ b/src/imap/cmd-delete.c @@ -6,7 +6,6 @@ bool cmd_delete(struct client_command_context *cmd) { struct client *client = cmd->client; - enum mailbox_name_status status; struct mail_namespace *ns; struct mailbox *box; const char *name, *storage_name; @@ -21,19 +20,9 @@ bool cmd_delete(struct client_command_context *cmd) return TRUE; } - ns = client_find_namespace(cmd, name, &storage_name, &status); + ns = client_find_namespace(cmd, name, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, name, NULL, status); - return TRUE; - } box = mailbox_alloc(ns->list, storage_name, 0); if (client->mailbox != NULL && diff --git a/src/imap/cmd-rename.c b/src/imap/cmd-rename.c index b31563891d..56a97fc2ca 100644 --- a/src/imap/cmd-rename.c +++ b/src/imap/cmd-rename.c @@ -6,7 +6,6 @@ bool cmd_rename(struct client_command_context *cmd) { - enum mailbox_name_status status; struct mail_namespace *old_ns, *new_ns; struct mailbox *old_box, *new_box; const char *oldname, *newname, *storage_oldname, *storage_newname; @@ -16,33 +15,12 @@ bool cmd_rename(struct client_command_context *cmd) if (!client_read_string_args(cmd, 2, &oldname, &newname)) return FALSE; - old_ns = client_find_namespace(cmd, oldname, &storage_oldname, &status); + old_ns = client_find_namespace(cmd, oldname, &storage_oldname); if (old_ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, oldname, NULL, status); - return TRUE; - } - - new_ns = client_find_namespace(cmd, newname, &storage_newname, &status); + new_ns = client_find_namespace(cmd, newname, &storage_newname); if (new_ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, newname, NULL, status); - return TRUE; - } if (old_ns == new_ns) { /* disallow box -> box/child, because it may break clients and diff --git a/src/imap/cmd-select.c b/src/imap/cmd-select.c index 5951f171d3..14d43878f8 100644 --- a/src/imap/cmd-select.c +++ b/src/imap/cmd-select.c @@ -372,7 +372,6 @@ bool cmd_select_full(struct client_command_context *cmd, bool readonly) struct client *client = cmd->client; struct imap_select_context *ctx; const struct imap_arg *args, *list_args; - enum mailbox_name_status status; const char *mailbox, *storage_name; int ret; @@ -388,24 +387,11 @@ bool cmd_select_full(struct client_command_context *cmd, bool readonly) ctx = p_new(cmd->pool, struct imap_select_context, 1); ctx->cmd = cmd; - ctx->ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ctx->ns = client_find_namespace(cmd, mailbox, &storage_name); if (ctx->ns == NULL) { close_selected_mailbox(client); return TRUE; } - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - close_selected_mailbox(client); - return TRUE; - } if (imap_arg_get_list(&args[1], &list_args)) { if (!select_parse_options(ctx, list_args)) { diff --git a/src/imap/cmd-status.c b/src/imap/cmd-status.c index b4d6959c67..20fd2bf086 100644 --- a/src/imap/cmd-status.c +++ b/src/imap/cmd-status.c @@ -9,7 +9,6 @@ bool cmd_status(struct client_command_context *cmd) { struct client *client = cmd->client; - enum mailbox_name_status status; const struct imap_arg *args, *list_args; struct imap_status_items items; struct imap_status_result result; @@ -31,21 +30,9 @@ bool cmd_status(struct client_command_context *cmd) if (imap_status_parse_items(cmd, list_args, &items) < 0) return TRUE; - ns = client_find_namespace(cmd, mailbox, &storage_name, &status); + ns = client_find_namespace(cmd, mailbox, &storage_name); if (ns == NULL) return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - break; - case MAILBOX_NAME_EXISTS_DIR: - status = MAILBOX_NAME_VALID; - /* fall through */ - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, NULL, status); - return TRUE; - } selected_mailbox = client->mailbox != NULL && mailbox_equals(client->mailbox, ns, storage_name); diff --git a/src/imap/cmd-subscribe.c b/src/imap/cmd-subscribe.c index 8e44ada278..345c3e7eaa 100644 --- a/src/imap/cmd-subscribe.c +++ b/src/imap/cmd-subscribe.c @@ -26,9 +26,39 @@ static bool have_listable_namespace_prefix(struct mail_namespace *ns, return FALSE; } +static bool +subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox) +{ + enum mailbox_name_status name_status; + struct mail_namespace *ns; + const char *storage_name; + + if (have_listable_namespace_prefix(cmd->client->user->namespaces, + mailbox)) { + /* subscribing to a listable namespace prefix, allow it. */ + return TRUE; + } + + /* see if the mailbox exists */ + ns = client_find_namespace(cmd, mailbox, &storage_name); + if (ns == NULL) + return FALSE; + + if (mailbox_list_get_mailbox_name_status(ns->list, storage_name, + &name_status) < 0) { + client_send_list_error(cmd, ns->list); + return FALSE; + } + if (name_status == MAILBOX_NAME_NONEXISTENT) { + client_send_tagline(cmd, t_strdup_printf( + "NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox)); + return FALSE; + } + return TRUE; +} + bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) { - enum mailbox_name_status status; struct mail_namespace *ns, *box_ns; const char *mailbox, *storage_name, *subs_name, *subs_name2 = NULL; bool unsubscribed_mailbox2; @@ -37,7 +67,7 @@ bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; - box_ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); + box_ns = client_find_namespace(cmd, mailbox, &storage_name); if (box_ns == NULL) return TRUE; @@ -69,39 +99,9 @@ bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) subs_name = t_strndup(subs_name, strlen(subs_name)-1); } - if (have_listable_namespace_prefix(cmd->client->user->namespaces, - mailbox)) { - /* subscribing to a listable namespace prefix, allow it. */ - } else if (subscribe) { - if (client_find_namespace(cmd, mailbox, - &storage_name, &status) == NULL) - return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - break; - case MAILBOX_NAME_VALID: - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - NULL, status); - return TRUE; - } - } else { - if (client_find_namespace(cmd, mailbox, - &storage_name, &status) == NULL) - return TRUE; - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - case MAILBOX_NAME_VALID: - break; - case MAILBOX_NAME_INVALID: - case MAILBOX_NAME_NOINFERIORS: - client_fail_mailbox_name_status(cmd, mailbox, - NULL, status); + if (subscribe) { + if (!subscribe_is_valid_name(cmd, mailbox)) return TRUE; - } } unsubscribed_mailbox2 = FALSE; diff --git a/src/imap/imap-commands-util.c b/src/imap/imap-commands-util.c index 5e4bf9b8dd..658ab66517 100644 --- a/src/imap/imap-commands-util.c +++ b/src/imap/imap-commands-util.c @@ -13,16 +13,9 @@ #include "mail-namespace.h" #include "imap-commands-util.h" -/* Maximum length for mailbox name, including it's path. This isn't fully - exact since the user can create folder hierarchy with small names, then - rename them to larger names. Mail storages should set more strict limits - to them, mbox/maildir currently allow paths only up to PATH_MAX. */ -#define MAILBOX_MAX_NAME_LEN 512 - struct mail_namespace * client_find_namespace(struct client_command_context *cmd, const char *mailbox, - const char **storage_name_r, - enum mailbox_name_status *mailbox_status_r) + const char **storage_name_r) { struct mail_namespace *namespaces = cmd->client->user->namespaces; struct mail_namespace *ns; @@ -39,17 +32,6 @@ client_find_namespace(struct client_command_context *cmd, const char *mailbox, return NULL; } - if (mailbox_status_r == NULL) { - *storage_name_r = storage_name; - return ns; - } - - /* make sure it even looks valid */ - if (*storage_name == '\0' && !(*mailbox != '\0' && ns->list)) { - client_send_tagline(cmd, "NO Empty mailbox name."); - return NULL; - } - storage_name_len = strlen(storage_name); if ((cmd->client->set->parsed_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 && @@ -74,66 +56,10 @@ client_find_namespace(struct client_command_context *cmd, const char *mailbox, } } - /* make sure two hierarchy separators aren't next to each others */ - for (p = storage_name+1; *p != '\0'; p++) { - if (p[0] == ns->real_sep && p[-1] == ns->real_sep) { - client_send_tagline(cmd, "NO Invalid mailbox name."); - return NULL; - } - } - - if (storage_name_len > MAILBOX_MAX_NAME_LEN) { - client_send_tagline(cmd, "NO Mailbox name too long."); - return NULL; - } - - /* check what our storage thinks of it */ - if (mailbox_list_get_mailbox_name_status(ns->list, storage_name, - mailbox_status_r) < 0) { - client_send_list_error(cmd, ns->list); - return NULL; - } *storage_name_r = storage_name; return ns; } -void client_fail_mailbox_name_status(struct client_command_context *cmd, - const char *mailbox_name, - const char *resp_code, - enum mailbox_name_status status) -{ - switch (status) { - case MAILBOX_NAME_EXISTS_MAILBOX: - case MAILBOX_NAME_EXISTS_DIR: - client_send_tagline(cmd, t_strconcat( - "NO [", IMAP_RESP_CODE_ALREADYEXISTS, - "] Mailbox already exists: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_VALID: - if (resp_code == NULL) - resp_code = ""; - else - resp_code = t_strconcat("[", resp_code, "] ", NULL); - client_send_tagline(cmd, t_strconcat( - "NO ", resp_code, "Mailbox doesn't exist: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_INVALID: - client_send_tagline(cmd, t_strconcat( - "NO Invalid mailbox name: ", - str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN), - NULL)); - break; - case MAILBOX_NAME_NOINFERIORS: - client_send_tagline(cmd, - "NO Parent mailbox doesn't allow child mailboxes."); - break; - } -} - bool client_verify_open_mailbox(struct client_command_context *cmd) { if (cmd->client->mailbox != NULL) @@ -144,6 +70,44 @@ bool client_verify_open_mailbox(struct client_command_context *cmd) } } +int client_open_save_dest_box(struct client_command_context *cmd, + const char *name, struct mailbox **destbox_r) +{ + struct mail_namespace *ns; + struct mailbox *box; + const char *storage_name, *error_string; + enum mail_error error; + + ns = client_find_namespace(cmd, name, &storage_name); + if (ns == NULL) + return -1; + + if (cmd->client->mailbox != NULL && + mailbox_equals(cmd->client->mailbox, ns, storage_name)) { + *destbox_r = cmd->client->mailbox; + return 0; + } + box = mailbox_alloc(ns->list, storage_name, + MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_KEEP_RECENT); + if (mailbox_open(box) < 0) { + struct mail_storage *storage = mailbox_get_storage(box); + + error_string = mail_storage_get_last_error(storage, &error); + if (error == MAIL_ERROR_NOTFOUND) { + client_send_tagline(cmd, t_strdup_printf( + "NO [TRYCREATE] %s", error_string)); + } else { + client_send_storage_error(cmd, storage); + } + mailbox_free(&box); + return -1; + } + if (cmd->client->enabled_features != 0) + mailbox_enable(box, cmd->client->enabled_features); + *destbox_r = box; + return 0; +} + const char * imap_get_error_string(struct client_command_context *cmd, const char *error_string, enum mail_error error) diff --git a/src/imap/imap-commands-util.h b/src/imap/imap-commands-util.h index 8fe49269f5..6eb6c50473 100644 --- a/src/imap/imap-commands-util.h +++ b/src/imap/imap-commands-util.h @@ -13,19 +13,16 @@ struct mailbox_keywords; 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, - const char **storage_name_r, - enum mailbox_name_status *mailbox_status_r); - -/* Send tagged NO reply based on mailbox name status. */ -void client_fail_mailbox_name_status(struct client_command_context *cmd, - const char *mailbox_name, - const char *resp_code, - enum mailbox_name_status status); + const char **storage_name_r); /* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected" error message to client. */ bool client_verify_open_mailbox(struct client_command_context *cmd); +/* Open APPEND/COPY destination mailbox. */ +int client_open_save_dest_box(struct client_command_context *cmd, + const char *name, struct mailbox **destbox_r); + const char * imap_get_error_string(struct client_command_context *cmd, const char *error_string, enum mail_error error);