From: Timo Sirainen Date: Sat, 15 Nov 2008 18:59:54 +0000 (+0200) Subject: Implemented imap-response-codes draft. X-Git-Tag: 1.2.alpha4~78 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4321f6c969e7b8f6b243ff5bb6b8d297921676f6;p=thirdparty%2Fdovecot%2Fcore.git Implemented imap-response-codes draft. --HG-- branch : HEAD --- diff --git a/src/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c index a29b8d5289..3348942adf 100644 --- a/src/imap-login/client-authenticate.c +++ b/src/imap-login/client-authenticate.c @@ -18,6 +18,7 @@ #include #define IMAP_SERVICE_NAME "imap" +#define IMAP_AUTH_FAILED_MSG "[AUTHENTICATIONFAILED] "AUTH_FAILED_MSG const char *client_authenticate_get_capabilities(bool secured) { @@ -178,10 +179,12 @@ static bool client_handle_args(struct imap_client *client, reply = t_str_new(128); if (reason != NULL) str_printfa(reply, "NO %s", reason); - else if (temp || proxy_self) - str_append(reply, "NO "AUTH_TEMP_FAILED_MSG); - else - str_append(reply, "NO "AUTH_FAILED_MSG); + else if (temp || proxy_self) { + str_append(reply, "NO [UNAVAILABLE] " + AUTH_TEMP_FAILED_MSG); + } else { + str_append(reply, "NO "IMAP_AUTH_FAILED_MSG); + } client_send_tagline(client, str_c(reply)); } else { /* normal login/failure */ @@ -227,8 +230,8 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, } msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD "; - msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG, - NULL); + msg = t_strconcat(msg, data != NULL ? data : + IMAP_AUTH_FAILED_MSG, NULL); client_send_tagline(client, msg); if (!client->destroyed) @@ -334,7 +337,8 @@ int cmd_login(struct imap_client *client, const struct imap_arg *args) "* BAD [ALERT] Plaintext authentication is disabled, " "but your client sent password in plaintext anyway. " "If anyone was listening, the password was exposed."); - client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG); + client_send_tagline(client, "NO [CLIENTBUG] " + AUTH_PLAINTEXT_DISABLED_MSG); return 1; } diff --git a/src/imap/client.c b/src/imap/client.c index 5b8a762bb6..e2faa1719e 100644 --- a/src/imap/client.c +++ b/src/imap/client.c @@ -409,8 +409,8 @@ static bool client_command_check_ambiguity(struct client_command_context *cmd) } if (broken_client) { - client_send_line(cmd->client, - "* BAD Command pipelining results in ambiguity."); + client_send_line(cmd->client, "* BAD [CLIENTBUG] " + "Command pipelining results in ambiguity."); } return TRUE; diff --git a/src/imap/cmd-copy.c b/src/imap/cmd-copy.c index 305ddcc768..7b0148b7aa 100644 --- a/src/imap/cmd-copy.c +++ b/src/imap/cmd-copy.c @@ -171,8 +171,8 @@ bool cmd_copy(struct client_command_context *cmd) return cmd_sync(cmd, sync_flags, imap_flags, msg); else if (ret == 0) { /* some messages were expunged, sync them */ - return cmd_sync(cmd, 0, 0, - "NO Some of the requested messages no longer exist."); + return cmd_sync(cmd, 0, 0, "NO [EXPUNGEISSUED] " + "Some of the requested messages no longer exist."); } else { client_send_storage_error(cmd, storage); return TRUE; diff --git a/src/imap/cmd-fetch.c b/src/imap/cmd-fetch.c index 91c52eb9ae..44f4a78318 100644 --- a/src/imap/cmd-fetch.c +++ b/src/imap/cmd-fetch.c @@ -131,6 +131,11 @@ static bool cmd_fetch_finish(struct imap_fetch_context *ctx) struct client_command_context *cmd = ctx->cmd; static const char *ok_message = "OK Fetch completed."; + if (ctx->partial_fetch) { + ok_message = "OK [EXPUNGEISSUED] " + "Some messages were already expunged."; + } + if (imap_fetch_deinit(ctx) < 0) ctx->failed = TRUE; diff --git a/src/imap/cmd-search.c b/src/imap/cmd-search.c index 20c8fa8865..e696f19269 100644 --- a/src/imap/cmd-search.c +++ b/src/imap/cmd-search.c @@ -366,7 +366,7 @@ static bool cmd_search_more(struct client_command_context *cmd) const struct seq_range *range; unsigned int count; uint32_t id, id_min, id_max; - bool tryagain, minmax; + bool tryagain, minmax, lost_data; if (cmd->cancel) { (void)imap_search_deinit(ctx); @@ -440,6 +440,7 @@ static bool cmd_search_more(struct client_command_context *cmd) } } + lost_data = mailbox_search_seen_lost_data(ctx->search_ctx); if (imap_search_deinit(ctx) < 0) { client_send_storage_error(cmd, mailbox_get_storage(cmd->client->mailbox)); @@ -459,7 +460,8 @@ static bool cmd_search_more(struct client_command_context *cmd) if (!cmd->uid || ctx->have_seqsets) sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES; return cmd_sync(cmd, sync_flags, 0, - t_strdup_printf("OK Search completed (%d.%03d secs).", + t_strdup_printf("OK %sSearch completed (%d.%03d secs).", + lost_data ? "[EXPUNGEISSUED] " : "", (int)end_time.tv_sec, (int)(end_time.tv_usec/1000))); } diff --git a/src/imap/cmd-status.c b/src/imap/cmd-status.c index 0ef1712ffe..94581910e7 100644 --- a/src/imap/cmd-status.c +++ b/src/imap/cmd-status.c @@ -13,6 +13,7 @@ bool cmd_status(struct client_command_context *cmd) enum mailbox_status_items items; struct mail_storage *storage; const char *mailbox, *real_mailbox; + bool selected_mailbox; /* */ if (!client_read_args(cmd, 2, 0, &args)) @@ -33,13 +34,19 @@ bool cmd_status(struct client_command_context *cmd) if (storage == NULL) return TRUE; + selected_mailbox = client->mailbox != NULL && + mailbox_equals(client->mailbox, storage, real_mailbox); if (!imap_status_get(client, storage, real_mailbox, items, &status)) { client_send_storage_error(cmd, storage); return TRUE; } imap_status_send(client, mailbox, items, &status); - client_send_tagline(cmd, "OK Status completed."); - + if (!selected_mailbox) + client_send_tagline(cmd, "OK Status completed."); + else { + client_send_tagline(cmd, "OK [CLIENTBUG] " + "Status on selected mailbox completed."); + } return TRUE; } diff --git a/src/imap/commands-util.c b/src/imap/commands-util.c index 8413dd7da2..535a7654c6 100644 --- a/src/imap/commands-util.c +++ b/src/imap/commands-util.c @@ -143,6 +143,46 @@ bool client_verify_open_mailbox(struct client_command_context *cmd) } } +static const char * +get_error_string(const char *error_string, enum mail_error error) +{ + const char *resp_code = NULL; + + switch (error) { + case MAIL_ERROR_NONE: + break; + case MAIL_ERROR_TEMP: + resp_code = "SERVERBUG"; + break; + case MAIL_ERROR_NOTPOSSIBLE: + case MAIL_ERROR_PARAMS: + resp_code = "CANNOT"; + break; + case MAIL_ERROR_PERM: + resp_code = "ACL"; + break; + case MAIL_ERROR_NOSPACE: + resp_code = "OVERQUOTA"; + break; + case MAIL_ERROR_NOTFOUND: + resp_code = "NONEXISTENT"; + break; + case MAIL_ERROR_EXISTS: + resp_code = "ALREADYEXISTS"; + break; + case MAIL_ERROR_EXPUNGED: + resp_code = "EXPUNGEISSUED"; + break; + case MAIL_ERROR_INUSE: + resp_code = "INUSE"; + break; + } + if (resp_code == NULL || *error_string == '[') + return t_strconcat("NO ", error_string, NULL); + else + return t_strdup_printf("NO [%s] %s", resp_code, error_string); +} + void client_send_list_error(struct client_command_context *cmd, struct mailbox_list *list) { @@ -150,7 +190,7 @@ void client_send_list_error(struct client_command_context *cmd, enum mail_error error; error_string = mailbox_list_get_last_error(list, &error); - client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL)); + client_send_tagline(cmd, get_error_string(error_string, error)); } void client_send_storage_error(struct client_command_context *cmd, @@ -168,7 +208,7 @@ void client_send_storage_error(struct client_command_context *cmd, } error_string = mail_storage_get_last_error(storage, &error); - client_send_tagline(cmd, t_strconcat("NO ", error_string, NULL)); + client_send_tagline(cmd, get_error_string(error_string, error)); } void client_send_untagged_storage_error(struct client *client, diff --git a/src/lib-storage/index/cydir/cydir-storage.c b/src/lib-storage/index/cydir/cydir-storage.c index 288dd02b17..2f7f789e83 100644 --- a/src/lib-storage/index/cydir/cydir-storage.c +++ b/src/lib-storage/index/cydir/cydir-storage.c @@ -224,7 +224,7 @@ static int cydir_mailbox_create(struct mail_storage *_storage, path = mailbox_list_get_path(_storage->list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX); if (stat(path, &st) == 0) { - mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(_storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); return -1; } @@ -293,7 +293,7 @@ cydir_delete_nonrecursive(struct mailbox_list *list, const char *path, } if (!unlinked_something) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, t_strdup_printf("Directory %s isn't empty, " "can't delete it.", name)); return -1; diff --git a/src/lib-storage/index/dbox/dbox-storage.c b/src/lib-storage/index/dbox/dbox-storage.c index bb54bb894a..8dca62bd82 100644 --- a/src/lib-storage/index/dbox/dbox-storage.c +++ b/src/lib-storage/index/dbox/dbox-storage.c @@ -344,7 +344,7 @@ static int dbox_mailbox_create(struct mail_storage *_storage, directory ? MAILBOX_LIST_PATH_TYPE_DIR : MAILBOX_LIST_PATH_TYPE_MAILBOX); if (stat(path, &st) == 0) { - mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(_storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); return -1; } @@ -355,7 +355,7 @@ static int dbox_mailbox_create(struct mail_storage *_storage, it. */ alt_path = directory ? NULL : dbox_get_alt_path(storage, path); if (alt_path != NULL && stat(alt_path, &st) == 0) { - mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(_storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); return -1; } @@ -426,7 +426,7 @@ dbox_delete_nonrecursive(struct mailbox_list *list, const char *path, } if (!unlinked_something) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, t_strdup_printf("Directory %s isn't empty, " "can't delete it.", name)); return -1; @@ -501,7 +501,7 @@ dbox_list_delete_mailbox(struct mailbox_list *list, const char *name) else if (errno == ENOTEMPTY) { if (deleted) return 0; - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, t_strdup_printf("Directory %s isn't empty, " "can't delete it.", name)); } else if (!mailbox_list_set_error_from_errno(list)) { @@ -547,7 +547,7 @@ dbox_list_rename_mailbox_pre(struct mailbox_list *list, if (stat(alt_newpath, &st) == 0) { /* race condition or a directory left there lying around? safest to just report error. */ - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_EXISTS, "Target mailbox already exists"); return -1; } else if (errno != ENOENT) { diff --git a/src/lib-storage/index/index-search.c b/src/lib-storage/index/index-search.c index 249790683e..d3a1cf5f3f 100644 --- a/src/lib-storage/index/index-search.c +++ b/src/lib-storage/index/index-search.c @@ -1207,6 +1207,9 @@ int index_storage_search_next_nonblock(struct mail_search_context *_ctx, } else T_BEGIN { ret = search_match_next(ctx) ? 1 : 0; + if (ctx->mail->expunged) + _ctx->seen_lost_data = TRUE; + if (ret == 0 && search_has_static_nonmatches(_ctx->args->args)) { /* if there are saved search results remember diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index d9d59629d3..d739ca3b53 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -312,7 +312,7 @@ static int mkdir_verify(struct mail_storage *storage, if (errno == EEXIST) { if (verify) return 0; - mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); } else if (errno == ENOENT) { mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND, @@ -370,7 +370,7 @@ static int create_maildir(struct mail_storage *storage, ret = maildir_check_tmp(storage, dir); if (ret > 0) { if (!verify) { - mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); return -1; } @@ -718,7 +718,7 @@ maildir_delete_nonrecursive(struct mailbox_list *list, const char *path, } if (!unlinked_something) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, t_strdup_printf("Directory %s isn't empty, " "can't delete it.", name)); return -1; diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index 5bb5098e1f..8828dd3328 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -715,7 +715,7 @@ static int mbox_mailbox_create(struct mail_storage *_storage, const char *name, path = mailbox_list_get_path(_storage->list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX); if (stat(path, &st) == 0) { - mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(_storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); return -1; } @@ -760,7 +760,7 @@ static int mbox_mailbox_create(struct mail_storage *_storage, const char *name, if (errno == EEXIST) { /* mailbox was just created between stat() and open() call.. */ - mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE, + mail_storage_set_error(_storage, MAIL_ERROR_EXISTS, "Mailbox already exists"); } else if (!mail_storage_set_error_from_errno(_storage)) { mail_storage_set_critical(_storage, @@ -947,7 +947,7 @@ static int mbox_list_delete_mailbox(struct mailbox_list *list, mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); } else if (errno == ENOTEMPTY) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, t_strdup_printf("Directory %s isn't empty, " "can't delete it.", name)); } else if (!mailbox_list_set_error_from_errno(list)) { diff --git a/src/lib-storage/list/mailbox-list-fs.c b/src/lib-storage/list/mailbox-list-fs.c index fc70f5e77f..0ef86142e1 100644 --- a/src/lib-storage/list/mailbox-list-fs.c +++ b/src/lib-storage/list/mailbox-list-fs.c @@ -305,7 +305,7 @@ static int fs_list_rename_mailbox(struct mailbox_list *list, possibility that someone actually tries to rename two mailboxes to same new one */ if (lstat(newpath, &st) == 0) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_EXISTS, "Target mailbox already exists"); return -1; } else if (errno == ENOTDIR) { diff --git a/src/lib-storage/list/mailbox-list-maildir.c b/src/lib-storage/list/mailbox-list-maildir.c index 852280982c..c310e1f713 100644 --- a/src/lib-storage/list/mailbox-list-maildir.c +++ b/src/lib-storage/list/mailbox-list-maildir.c @@ -426,7 +426,7 @@ static int maildir_list_rename_mailbox(struct mailbox_list *list, } if (EDESTDIREXISTS(errno)) { - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_EXISTS, "Target mailbox already exists"); } else { mailbox_list_set_critical(list, "rename(%s, %s) failed: %m", diff --git a/src/lib-storage/mail-error.h b/src/lib-storage/mail-error.h index 80ee6f8b8a..ab9536d710 100644 --- a/src/lib-storage/mail-error.h +++ b/src/lib-storage/mail-error.h @@ -26,10 +26,15 @@ enum mail_error { MAIL_ERROR_PERM, /* Out of disk space or quota */ MAIL_ERROR_NOSPACE, - /* Item (eg. mailbox) doesn't exist or it's not visible to us */ + /* Item (e.g. mailbox) doesn't exist or it's not visible to us */ MAIL_ERROR_NOTFOUND, + /* Item (e.g. mailbox) already exists */ + MAIL_ERROR_EXISTS, /* Tried to access an expunged message */ - MAIL_ERROR_EXPUNGED + MAIL_ERROR_EXPUNGED, + /* Operation cannot be done because another session prevents it + (e.g. lock timeout) */ + MAIL_ERROR_INUSE }; /* Convert errno to mail_error and an error string. Returns TRUE if successful, diff --git a/src/lib-storage/mail-storage-private.h b/src/lib-storage/mail-storage-private.h index e4b9b531bf..2bd036da06 100644 --- a/src/lib-storage/mail-storage-private.h +++ b/src/lib-storage/mail-storage-private.h @@ -311,6 +311,8 @@ struct mail_search_context { uint32_t seq; ARRAY_DEFINE(module_contexts, union mail_search_module_context *); + + unsigned int seen_lost_data:1; }; struct mail_save_context { diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 11ad1cc4a2..107103a13d 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -699,6 +699,11 @@ int mailbox_search_next_nonblock(struct mail_search_context *ctx, return ret; } +bool mailbox_search_seen_lost_data(struct mail_search_context *ctx) +{ + return ctx->seen_lost_data; +} + int mailbox_search_result_build(struct mailbox_transaction_context *t, struct mail_search_args *args, enum mailbox_search_result_flags flags, diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index be3158205f..d515040223 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -431,6 +431,10 @@ int mailbox_search_next(struct mail_search_context *ctx, struct mail *mail); finished, and TRUE if more results will by calling the function again. */ int mailbox_search_next_nonblock(struct mail_search_context *ctx, struct mail *mail, bool *tryagain_r); +/* Returns TRUE if some messages were already expunged and we couldn't + determine correctly if those messages should have been returned in this + search. */ +bool mailbox_search_seen_lost_data(struct mail_search_context *ctx); /* Remember the search result for future use. This must be called before the first mailbox_search_next*() call. */ diff --git a/src/lib-storage/mailbox-list.c b/src/lib-storage/mailbox-list.c index c0e49303e6..0de285fb5f 100644 --- a/src/lib-storage/mailbox-list.c +++ b/src/lib-storage/mailbox-list.c @@ -554,7 +554,7 @@ static int mailbox_list_try_delete(struct mailbox_list *list, const char *dir) if (errno == ENOTEMPTY) { /* We're most likely using NFS and we can't delete .nfs* files. */ - mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + mailbox_list_set_error(list, MAIL_ERROR_INUSE, "Mailbox is still open in another session, " "can't delete it."); } else {