Mercurial > dovecot > core-2.2
changeset 12904:d7a02077d91f
doveadm: Added "move" command for moving mails between mailboxes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 23 Mar 2011 22:16:24 +0200 |
parents | a94abbccea0f |
children | a5f9264674fb |
files | src/doveadm/Makefile.am src/doveadm/doveadm-mail-expunge.c src/doveadm/doveadm-mail-iter.c src/doveadm/doveadm-mail-iter.h src/doveadm/doveadm-mail-move.c src/doveadm/doveadm-mail.c src/doveadm/doveadm-mail.h |
diffstat | 7 files changed, 179 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/src/doveadm/Makefile.am Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/Makefile.am Wed Mar 23 22:16:24 2011 +0200 @@ -66,6 +66,7 @@ doveadm-mail-iter.c \ doveadm-mail-mailbox.c \ doveadm-mail-mailbox-status.c \ + doveadm-mail-move.c \ doveadm-mail-list-iter.c \ doveadm-mail-search.c \ doveadm-print.c \
--- a/src/doveadm/doveadm-mail-expunge.c Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/doveadm-mail-expunge.c Wed Mar 23 22:16:24 2011 +0200 @@ -178,6 +178,20 @@ doveadm_mail_list_iter_deinit(&iter); } +void expunge_search_args_check(struct mail_search_args *args, const char *cmd) +{ + mail_search_args_simplify(args); + if (!expunge_search_args_is_mailbox_ok(args->args)) { + i_fatal("%s: To avoid accidents, search query " + "must contain MAILBOX in all search branches", cmd); + } + if (!expunge_search_args_is_msgset_ok(args->args)) { + i_fatal("%s: To avoid accidents, each branch in " + "search query must contain something else " + "besides MAILBOX", cmd); + } +} + static void cmd_expunge_init(struct doveadm_mail_cmd_context *ctx, const char *const args[]) { @@ -185,17 +199,7 @@ doveadm_mail_help_name("expunge"); ctx->search_args = doveadm_mail_build_search_args(args); - mail_search_args_simplify(ctx->search_args); - - if (!expunge_search_args_is_mailbox_ok(ctx->search_args->args)) { - i_fatal("expunge: To avoid accidents, search query " - "must contain MAILBOX in all search branches"); - } - if (!expunge_search_args_is_msgset_ok(ctx->search_args->args)) { - i_fatal("expunge: To avoid accidents, each branch in " - "search query must contain something else " - "besides MAILBOX"); - } + expunge_search_args_check(ctx->search_args, "expunge"); } static struct doveadm_mail_cmd_context *cmd_expunge_alloc(void)
--- a/src/doveadm/doveadm-mail-iter.c Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/doveadm-mail-iter.c Wed Mar 23 22:16:24 2011 +0200 @@ -50,7 +50,8 @@ } static int -doveadm_mail_iter_deinit_transaction(struct doveadm_mail_iter *iter) +doveadm_mail_iter_deinit_transaction(struct doveadm_mail_iter *iter, + bool commit) { int ret = 0; @@ -60,25 +61,30 @@ mail_storage_get_last_error(iter->storage, NULL)); ret = -1; } - if (mailbox_transaction_commit(&iter->t) < 0) { - i_error("Commiting mailbox %s failed: %s", - mailbox_get_vname(iter->box), - mail_storage_get_last_error(iter->storage, NULL)); - ret = -1; + if (commit) { + if (mailbox_transaction_commit(&iter->t) < 0) { + i_error("Commiting mailbox %s failed: %s", + mailbox_get_vname(iter->box), + mail_storage_get_last_error(iter->storage, NULL)); + ret = -1; + } + } else { + mailbox_transaction_rollback(&iter->t); } mail_search_args_deinit(iter->search_args); return ret; } static int -doveadm_mail_iter_deinit_full(struct doveadm_mail_iter **_iter, bool sync) +doveadm_mail_iter_deinit_full(struct doveadm_mail_iter **_iter, + bool sync, bool commit) { struct doveadm_mail_iter *iter = *_iter; int ret; *_iter = NULL; - ret = doveadm_mail_iter_deinit_transaction(iter); + ret = doveadm_mail_iter_deinit_transaction(iter, commit); if (ret == 0 && sync) ret = mailbox_sync(iter->box, 0); mailbox_free(&iter->box); @@ -88,12 +94,17 @@ int doveadm_mail_iter_deinit(struct doveadm_mail_iter **_iter) { - return doveadm_mail_iter_deinit_full(_iter, FALSE); + return doveadm_mail_iter_deinit_full(_iter, FALSE, TRUE); } int doveadm_mail_iter_deinit_sync(struct doveadm_mail_iter **_iter) { - return doveadm_mail_iter_deinit_full(_iter, TRUE); + return doveadm_mail_iter_deinit_full(_iter, TRUE, TRUE); +} + +void doveadm_mail_iter_deinit_rollback(struct doveadm_mail_iter **_iter) +{ + (void)doveadm_mail_iter_deinit_full(_iter, FALSE, FALSE); } bool doveadm_mail_iter_next(struct doveadm_mail_iter *iter, struct mail *mail)
--- a/src/doveadm/doveadm-mail-iter.h Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/doveadm-mail-iter.h Wed Mar 23 22:16:24 2011 +0200 @@ -9,6 +9,7 @@ struct doveadm_mail_iter **iter_r); int doveadm_mail_iter_deinit(struct doveadm_mail_iter **iter); int doveadm_mail_iter_deinit_sync(struct doveadm_mail_iter **iter); +void doveadm_mail_iter_deinit_rollback(struct doveadm_mail_iter **iter); bool doveadm_mail_iter_next(struct doveadm_mail_iter *iter, struct mail *mail);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doveadm/doveadm-mail-move.c Wed Mar 23 22:16:24 2011 +0200 @@ -0,0 +1,137 @@ +/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "doveadm-print.h" +#include "doveadm-mail-list-iter.h" +#include "doveadm-mail-iter.h" +#include "doveadm-mail.h" + +#include <stdio.h> + +struct move_cmd_context { + struct doveadm_mail_cmd_context ctx; + + const char *destname; +}; + +static int +cmd_move_box(struct move_cmd_context *ctx, struct mailbox *destbox, + const struct mailbox_info *info) +{ + struct doveadm_mail_iter *iter; + struct mailbox_transaction_context *trans; + struct mailbox_transaction_context *desttrans; + struct mail_storage *deststorage = mailbox_get_storage(destbox); + struct mail_save_context *save_ctx; + struct mail *mail; + int ret = 0; + + if (doveadm_mail_iter_init(info, ctx->ctx.search_args, + &trans, &iter) < 0) + return -1; + + /* use a separately committed transaction for each mailbox. + this guarantees that mails aren't expunged without actually having + been copied. */ + desttrans = mailbox_transaction_begin(destbox, + MAILBOX_TRANSACTION_FLAG_EXTERNAL); + + mail = mail_alloc(trans, 0, NULL); + while (doveadm_mail_iter_next(iter, mail)) { + save_ctx = mailbox_save_alloc(desttrans); + mailbox_save_copy_flags(save_ctx, mail); + if (mailbox_copy(&save_ctx, mail) == 0) + mail_expunge(mail); + else { + i_error("Copying messsage UID %u from '%s' failed: %s", + mail->uid, info->name, + mail_storage_get_last_error(deststorage, NULL)); + ret = -1; + } + } + mail_free(&mail); + + if (mailbox_transaction_commit(&desttrans) < 0) { + i_error("Committing moved mails failed: %s", + mail_storage_get_last_error(deststorage, NULL)); + /* rollback expunges */ + doveadm_mail_iter_deinit_rollback(&iter); + ret = -1; + } else { + if (doveadm_mail_iter_deinit_sync(&iter) < 0) + ret = -1; + } + return ret; +} + +static void +cmd_move_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) +{ + struct move_cmd_context *ctx = (struct move_cmd_context *)_ctx; + const enum mailbox_list_iter_flags iter_flags = + MAILBOX_LIST_ITER_RAW_LIST | + MAILBOX_LIST_ITER_NO_AUTO_INBOX | + MAILBOX_LIST_ITER_RETURN_NO_FLAGS; + struct doveadm_mail_list_iter *iter; + struct mail_namespace *ns; + struct mailbox *destbox; + struct mail_storage *storage; + const struct mailbox_info *info; + const char *storage_name = ctx->destname; + + ns = mail_namespace_find(user->namespaces, &storage_name); + if (ns == NULL) + i_fatal("Can't find namespace for: %s", ctx->destname); + + destbox = mailbox_alloc(ns->list, storage_name, + MAILBOX_FLAG_SAVEONLY | + MAILBOX_FLAG_KEEP_RECENT); + storage = mailbox_get_storage(destbox); + if (mailbox_open(destbox) < 0) { + i_error("Can't open mailbox '%s': %s", ctx->destname, + mail_storage_get_last_error(storage, NULL)); + mailbox_free(&destbox); + return; + } + + iter = doveadm_mail_list_iter_init(user, _ctx->search_args, iter_flags); + while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN { + (void)cmd_move_box(ctx, destbox, info); + } T_END; + doveadm_mail_list_iter_deinit(&iter); + + (void)mailbox_sync(destbox, 0); + mailbox_free(&destbox); + +} + +static void cmd_move_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct move_cmd_context *ctx = (struct move_cmd_context *)_ctx; + const char *destname = args[0]; + + if (destname == NULL || args[1] == NULL) + doveadm_mail_help_name("move"); + + ctx->destname = p_strdup(ctx->ctx.pool, destname); + ctx->ctx.search_args = doveadm_mail_build_search_args(args + 1); + expunge_search_args_check(ctx->ctx.search_args, "move"); +} + +static struct doveadm_mail_cmd_context *cmd_move_alloc(void) +{ + struct move_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct move_cmd_context); + ctx->ctx.v.init = cmd_move_init; + ctx->ctx.v.run = cmd_move_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); + return &ctx->ctx; +} + +struct doveadm_mail_cmd cmd_move = { + cmd_move_alloc, "move", "<destination> <search query>" +};
--- a/src/doveadm/doveadm-mail.c Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/doveadm-mail.c Wed Mar 23 22:16:24 2011 +0200 @@ -566,6 +566,7 @@ &cmd_fetch, &cmd_import, &cmd_altmove, + &cmd_move, &cmd_mailbox_list, &cmd_mailbox_create, &cmd_mailbox_delete,
--- a/src/doveadm/doveadm-mail.h Tue Mar 22 23:03:41 2011 +0200 +++ b/src/doveadm/doveadm-mail.h Wed Mar 23 22:16:24 2011 +0200 @@ -97,6 +97,8 @@ struct mail_search_args * doveadm_mail_mailbox_search_args_build(const char *const args[]); +void expunge_search_args_check(struct mail_search_args *args, const char *cmd); + struct doveadm_mail_cmd_context * doveadm_mail_cmd_alloc_size(size_t size); #define doveadm_mail_cmd_alloc(type) \ @@ -107,6 +109,7 @@ struct doveadm_mail_cmd cmd_fetch; struct doveadm_mail_cmd cmd_import; struct doveadm_mail_cmd cmd_altmove; +struct doveadm_mail_cmd cmd_move; struct doveadm_mail_cmd cmd_mailbox_list; struct doveadm_mail_cmd cmd_mailbox_create; struct doveadm_mail_cmd cmd_mailbox_delete;