]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: copy/move: Refactor to use struct cmd_copy_context
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 12 Dec 2019 14:25:30 +0000 (16:25 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Thu, 6 Feb 2020 16:14:32 +0000 (16:14 +0000)
src/imap/cmd-copy.c

index 9e050629c23924df29c70f019d16cfc593d2dc6d..2237cc603fffaebb8e7992bbda6f4f8688430da3 100644 (file)
 
 #define COPY_CHECK_INTERVAL 100
 
+struct cmd_copy_context {
+       struct client_command_context *cmd;
+       struct mailbox *destbox;
+       bool move;
+
+       struct mailbox_transaction_context *src_trans;
+       struct msgset_generator_context srcset_ctx;
+       unsigned int copy_count;
+};
+
 static void client_send_sendalive_if_needed(struct client *client)
 {
        time_t now, last_io;
@@ -30,32 +40,31 @@ static void client_send_sendalive_if_needed(struct client *client)
        }
 }
 
-static int fetch_and_copy(struct client_command_context *cmd, bool move,
-                         struct mailbox_transaction_context *t,
-                         struct mailbox_transaction_context **src_trans_r,
+static int fetch_and_copy(struct cmd_copy_context *copy_ctx,
                          struct mail_search_args *search_args,
-                         const char **src_uidset_r,
-                         unsigned int *copy_count_r)
+                         struct mail_transaction_commit_changes *changes_r)
 {
-       struct client *client = cmd->client;
+       struct client *client = copy_ctx->cmd->client;
+       struct mailbox_transaction_context *t;
        struct mail_search_context *search_ctx;
-        struct mailbox_transaction_context *src_trans;
        struct mail_save_context *save_ctx;
        struct mail *mail;
-       unsigned int copy_count = 0;
-       struct msgset_generator_context srcset_ctx;
-       string_t *src_uidset;
+       const char *cmd_reason;
        int ret;
 
        i_assert(o_stream_is_corked(client->output) ||
                 client->output->stream_errno != 0);
 
-       src_uidset = t_str_new(256);
-       msgset_generator_init(&srcset_ctx, src_uidset);
+       cmd_reason = imap_client_command_get_reason(copy_ctx->cmd);
+       t = mailbox_transaction_begin(copy_ctx->destbox,
+                                     MAILBOX_TRANSACTION_FLAG_EXTERNAL |
+                                     MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS,
+                                     cmd_reason);
 
-       src_trans = mailbox_transaction_begin(client->mailbox, 0,
-                                             imap_client_command_get_reason(cmd));
-       search_ctx = mailbox_search_init(src_trans, search_args, NULL, 0, NULL);
+       copy_ctx->src_trans =
+               mailbox_transaction_begin(client->mailbox, 0, cmd_reason);
+       search_ctx = mailbox_search_init(copy_ctx->src_trans, search_args,
+                                        NULL, 0, NULL);
 
        ret = 1;
        while (mailbox_search_next(search_ctx, &mail) && ret > 0) {
@@ -64,13 +73,13 @@ static int fetch_and_copy(struct client_command_context *cmd, bool move,
                        break;
                }
 
-               if ((++copy_count % COPY_CHECK_INTERVAL) == 0)
+               if ((++copy_ctx->copy_count % COPY_CHECK_INTERVAL) == 0)
                        client_send_sendalive_if_needed(client);
 
                save_ctx = mailbox_save_alloc(t);
                mailbox_save_copy_flags(save_ctx, mail);
 
-               if (move) {
+               if (copy_ctx->move) {
                        if (mailbox_move(&save_ctx, mail) < 0)
                                ret = -1;
                } else {
@@ -80,16 +89,25 @@ static int fetch_and_copy(struct client_command_context *cmd, bool move,
                if (ret < 0 && mail->expunged)
                        ret = 0;
 
-               msgset_generator_next(&srcset_ctx, mail->uid);
+               msgset_generator_next(&copy_ctx->srcset_ctx, mail->uid);
        }
-       msgset_generator_finish(&srcset_ctx);
+
+       if (ret <= 0)
+               mailbox_transaction_rollback(&t);
+       else if (mailbox_transaction_commit_get_changes(&t, changes_r) < 0) {
+               if (mailbox_get_last_mail_error(copy_ctx->destbox) == MAIL_ERROR_EXPUNGED) {
+                       /* storage backend didn't notice the expunge until
+                          at commit time. */
+                       ret = 0;
+               } else {
+                       ret = -1;
+               }
+       }
+
+       msgset_generator_finish(&copy_ctx->srcset_ctx);
 
        if (mailbox_search_deinit(&search_ctx) < 0)
                ret = -1;
-
-       *src_trans_r = src_trans;
-       *src_uidset_r = str_c(src_uidset);
-       *copy_count_r = copy_count;
        return ret;
 }
 
@@ -111,14 +129,13 @@ static bool cmd_copy_full(struct client_command_context *cmd, bool move)
        struct client *client = cmd->client;
        struct mail_storage *dest_storage;
        struct mailbox *destbox;
-       struct mailbox_transaction_context *t, *src_trans;
         struct mail_search_args *search_args;
-       const char *messageset, *mailbox, *src_uidset;
+       const char *messageset, *mailbox;
        enum mailbox_sync_flags sync_flags = 0;
        enum imap_sync_flags imap_flags = 0;
        struct mail_transaction_commit_changes changes;
-       unsigned int copy_count;
-       string_t *msg;
+       struct cmd_copy_context copy_ctx;
+       string_t *msg, *src_uidset;
        int ret;
 
        /* <message set> <mailbox> */
@@ -137,26 +154,19 @@ static bool cmd_copy_full(struct client_command_context *cmd, bool move)
                return TRUE;
        }
 
-       t = mailbox_transaction_begin(destbox,
-                                     MAILBOX_TRANSACTION_FLAG_EXTERNAL |
-                                     MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS,
-                                     imap_client_command_get_reason(cmd));
-       ret = fetch_and_copy(cmd, move, t, &src_trans, search_args,
-                            &src_uidset, &copy_count);
+       i_zero(&copy_ctx);
+       copy_ctx.cmd = cmd;
+       copy_ctx.destbox = destbox;
+       copy_ctx.move = move;
+       src_uidset = t_str_new(256);
+       msgset_generator_init(&copy_ctx.srcset_ctx, src_uidset);
+       ret = fetch_and_copy(&copy_ctx, search_args, &changes);
        mail_search_args_unref(&search_args);
 
        msg = t_str_new(256);
        if (ret <= 0)
-               mailbox_transaction_rollback(&t);
-       else if (mailbox_transaction_commit_get_changes(&t, &changes) < 0) {
-               if (mailbox_get_last_mail_error(destbox) == MAIL_ERROR_EXPUNGED) {
-                       /* storage backend didn't notice the expunge until
-                          at commit time. */
-                       ret = 0;
-               } else {
-                       ret = -1;
-               }
-       } else if (copy_count == 0) {
+               ;
+       else if (copy_ctx.copy_count == 0) {
                str_append(msg, "OK No messages found.");
                pool_unref(&changes.pool);
        } else if (seq_range_count(&changes.saved_uids) == 0 ||
@@ -167,11 +177,11 @@ static bool cmd_copy_full(struct client_command_context *cmd, bool move)
                           "OK Copy completed.");
                pool_unref(&changes.pool);
        } else if (move) {
-               i_assert(copy_count == seq_range_count(&changes.saved_uids));
-               copy_update_trashed(client, destbox, copy_count);
+               i_assert(copy_ctx.copy_count == seq_range_count(&changes.saved_uids));
+               copy_update_trashed(client, destbox, copy_ctx.copy_count);
 
                str_printfa(msg, "* OK [COPYUID %u %s ",
-                           changes.uid_validity, src_uidset);
+                           changes.uid_validity, str_c(src_uidset));
                imap_write_seq_range(msg, &changes.saved_uids);
                str_append(msg, "] Moved UIDs.");
                client_send_line(client, str_c(msg));
@@ -180,11 +190,11 @@ static bool cmd_copy_full(struct client_command_context *cmd, bool move)
                str_append(msg, "OK Move completed.");
                pool_unref(&changes.pool);
        } else {
-               i_assert(copy_count == seq_range_count(&changes.saved_uids));
-               copy_update_trashed(client, destbox, copy_count);
+               i_assert(copy_ctx.copy_count == seq_range_count(&changes.saved_uids));
+               copy_update_trashed(client, destbox, copy_ctx.copy_count);
 
                str_printfa(msg, "OK [COPYUID %u %s ", changes.uid_validity,
-                           src_uidset);
+                           str_c(src_uidset));
                imap_write_seq_range(msg, &changes.saved_uids);
                str_append(msg, "] Copy completed.");
                pool_unref(&changes.pool);
@@ -192,9 +202,9 @@ static bool cmd_copy_full(struct client_command_context *cmd, bool move)
 
        if (ret <= 0 && move) {
                /* move failed, don't expunge anything */
-               mailbox_transaction_rollback(&src_trans);
+               mailbox_transaction_rollback(&copy_ctx.src_trans);
        } else {
-               if (mailbox_transaction_commit(&src_trans) < 0)
+               if (mailbox_transaction_commit(&copy_ctx.src_trans) < 0)
                        ret = -1;
        }