#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;
}
}
-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) {
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 {
if (ret < 0 && mail->expunged)
ret = 0;
- msgset_generator_next(&srcset_ctx, mail->uid);
+ msgset_generator_next(©_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(©_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;
}
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> */
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, ©_count);
+ i_zero(©_ctx);
+ copy_ctx.cmd = cmd;
+ copy_ctx.destbox = destbox;
+ copy_ctx.move = move;
+ src_uidset = t_str_new(256);
+ msgset_generator_init(©_ctx.srcset_ctx, src_uidset);
+ ret = fetch_and_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 ||
"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));
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);
if (ret <= 0 && move) {
/* move failed, don't expunge anything */
- mailbox_transaction_rollback(&src_trans);
+ mailbox_transaction_rollback(©_ctx.src_trans);
} else {
- if (mailbox_transaction_commit(&src_trans) < 0)
+ if (mailbox_transaction_commit(©_ctx.src_trans) < 0)
ret = -1;
}