]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Implemented imap-response-codes draft.
authorTimo Sirainen <tss@iki.fi>
Sat, 15 Nov 2008 18:59:54 +0000 (20:59 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 15 Nov 2008 18:59:54 +0000 (20:59 +0200)
--HG--
branch : HEAD

19 files changed:
src/imap-login/client-authenticate.c
src/imap/client.c
src/imap/cmd-copy.c
src/imap/cmd-fetch.c
src/imap/cmd-search.c
src/imap/cmd-status.c
src/imap/commands-util.c
src/lib-storage/index/cydir/cydir-storage.c
src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/index-search.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/list/mailbox-list-fs.c
src/lib-storage/list/mailbox-list-maildir.c
src/lib-storage/mail-error.h
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.c
src/lib-storage/mail-storage.h
src/lib-storage/mailbox-list.c

index a29b8d5289efbf50660a968708202b2378f268a4..3348942adfdfa54a710b63da9b871aea4f6617ff 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 
 #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;
        }
 
index 5b8a762bb691a20d6ecd07522711ead8f33145ea..e2faa1719e0d8e2a80039e73e8e970a35972bb1e 100644 (file)
@@ -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;
index 305ddcc7680e283801cbf626823cd7fd14f5d564..7b0148b7aaf61f1dd294be6846f01fad6cf16525 100644 (file)
@@ -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;
index 91c52eb9aead1a150c563bef2bfb58a3213de606..44f4a783184eca6f238ee803d75c58cdc020abf3 100644 (file)
@@ -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;
 
index 20c8fa8865ce355e9cf504e9b30ce5cc53299bd1..e696f1926944f71c6d458924309e717ab8041a33 100644 (file)
@@ -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)));
 }
index 0ef1712ffed7af6c819732b019061d7f061be0a9..94581910e70f72a367666b6bda760efbcf490356 100644 (file)
@@ -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;
 
        /* <mailbox> <status items> */
        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;
 }
index 8413dd7da20a769746c7db8dbd6bf11701f169e7..535a7654c6fbde3297590c07271f743ad9cb4553 100644 (file)
@@ -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,
index 288dd02b17c7953684e47f79f15f63ef5eab8cc6..2f7f789e834b7ed81a2ed695c5a284bc80fb5b81 100644 (file)
@@ -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;
index bb54bb894aca06c18f7f3c090cc94ae0b41414ba..8dca62bd82379fdf69433a2271568f8fdc99b2f2 100644 (file)
@@ -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) {
index 249790683e17c929157d043f81bb254c6342eff6..d3a1cf5f3f1bdabe449942bc5fc338759506a1f7 100644 (file)
@@ -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
index d9d59629d3cc568101805daf844bc313ef08146b..d739ca3b53dfb738c7c7d77e4b9cc6e5a34a1af9 100644 (file)
@@ -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;
index 5bb5098e1f562f0d0dcb2d59ef2d9f029a7ed23c..8828dd33281c6d181089453267375dd9a506def3 100644 (file)
@@ -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)) {
index fc70f5e77f18e3fe9d2a1c3622133a1b5b52f911..0ef86142e103e472a70127ad937d0e1d16309746 100644 (file)
@@ -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) {
index 852280982cac0b87bbcb4aa93e23027a9a57fc40..c310e1f7136662e308b90ade02fc009444d8e146 100644 (file)
@@ -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",
index 80ee6f8b8a65cba369a7f30598f0bc21c5ead33e..ab9536d7103e7dca8a4ef96c7023098aa9df4359 100644 (file)
@@ -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,
index e4b9b531bf3a79d7dd864b9454e80f9ed2b12766..2bd036da0673251ef99ceb80087e9dd741a1ab3c 100644 (file)
@@ -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 {
index 11ad1cc4a29ae1759c888d69776018afa6f2aeac..107103a13dd346c574333641d36e0a97c294f142 100644 (file)
@@ -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,
index be3158205f529139ced938b4a5e7f569ffeba66d..d515040223096d49f43b28b960bc0f15482dde2f 100644 (file)
@@ -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. */
index c0e49303e647fb59cc469632277876f09e404b49..0de285fb5f6d9c1648056ad1dc003b8d9520083a 100644 (file)
@@ -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 {