]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Added "save" command to directly save mail to specified mailbox.
authorTimo Sirainen <tss@iki.fi>
Sun, 15 Feb 2015 08:11:01 +0000 (10:11 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 15 Feb 2015 08:11:01 +0000 (10:11 +0200)
The mail is read from stdin.

src/doveadm/Makefile.am
src/doveadm/doveadm-mail-save.c [new file with mode: 0644]
src/doveadm/doveadm-mail.c
src/doveadm/doveadm-mail.h

index 355232d74de237d43a0e9dbd54e67284b362cff3..b3936d6ddf8dd93f0df66c73d83a4fed075e312d 100644 (file)
@@ -93,6 +93,7 @@ doveadm_common_mail_cmds = \
        doveadm-mail-mailbox-status.c \
        doveadm-mail-copymove.c \
        doveadm-mailbox-list-iter.c \
+       doveadm-mail-save.c \
        doveadm-mail-search.c \
        doveadm-mail-server.c
 
diff --git a/src/doveadm/doveadm-mail-save.c b/src/doveadm/doveadm-mail-save.c
new file mode 100644 (file)
index 0000000..7092e4a
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream.h"
+#include "mail-storage.h"
+#include "doveadm-mail.h"
+
+struct save_cmd_context {
+       struct doveadm_mail_cmd_context ctx;
+       const char *mailbox;
+};
+
+static int
+cmd_save_to_mailbox(struct save_cmd_context *ctx, struct mailbox *box,
+                   struct istream *input)
+{
+       struct mail_storage *storage = mailbox_get_storage(box);
+       struct mailbox_transaction_context *trans;
+       struct mail_save_context *save_ctx;
+       ssize_t ret;
+       bool save_failed = FALSE;
+
+       if (mailbox_open(box) < 0) {
+               i_error("Failed to open mailbox %s: %s",
+                       mailbox_get_vname(box), mailbox_get_last_error(box, NULL));
+               doveadm_mail_failed_storage(&ctx->ctx, storage);
+               return -1;
+       }
+
+       trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
+       save_ctx = mailbox_save_alloc(trans);
+       if (mailbox_save_begin(&save_ctx, input) < 0) {
+               i_error("Saving failed: %s", mailbox_get_last_error(box, NULL));
+               doveadm_mail_failed_storage(&ctx->ctx, storage);
+               mailbox_transaction_rollback(&trans);
+               return -1;
+       }
+       while ((ret = i_stream_read(input)) > 0 || ret == -2) {
+               if (mailbox_save_continue(save_ctx) < 0) {
+                       save_failed = TRUE;
+                       ret = -1;
+                       break;
+               }
+       }
+       i_assert(ret == -1);
+
+       if (input->stream_errno != 0) {
+               i_error("read(msg input) failed: %s", i_stream_get_error(input));
+               doveadm_mail_failed_error(&ctx->ctx, MAIL_ERROR_TEMP);
+       } else if (save_failed) {
+               i_error("Saving failed: %s", mailbox_get_last_error(box, NULL));
+               doveadm_mail_failed_storage(&ctx->ctx, storage);
+       } else if (mailbox_save_finish(&save_ctx) < 0) {
+               i_error("Saving failed: %s",
+                       mailbox_get_last_error(box, NULL));
+               doveadm_mail_failed_storage(&ctx->ctx, storage);
+       } else if (mailbox_transaction_commit(&trans) < 0) {
+               i_error("Save transaction commit failed: %s",
+                       mailbox_get_last_error(box, NULL));
+               doveadm_mail_failed_storage(&ctx->ctx, storage);
+       } else {
+               ret = 0;
+       }
+       if (save_ctx != NULL)
+               mailbox_save_cancel(&save_ctx);
+       if (trans != NULL)
+               mailbox_transaction_rollback(&trans);
+       i_assert(input->eof);
+       return ret < 0 ? -1 : 0;
+}
+
+static int
+cmd_save_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
+{
+       struct save_cmd_context *ctx = (struct save_cmd_context *)_ctx;
+       struct mail_namespace *ns;
+       struct mailbox *box;
+       int ret;
+
+       ns = mail_namespace_find(user->namespaces, ctx->mailbox);
+       box = mailbox_alloc(ns->list, ctx->mailbox, MAILBOX_FLAG_SAVEONLY);
+       ret = cmd_save_to_mailbox(ctx, box, _ctx->cmd_input);
+       mailbox_free(&box);
+       return ret;
+}
+
+static void cmd_save_init(struct doveadm_mail_cmd_context *_ctx,
+                         const char *const args[] ATTR_UNUSED)
+{
+       doveadm_mail_get_input(_ctx);
+}
+
+static bool
+cmd_mailbox_save_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
+{
+       struct save_cmd_context *ctx = (struct save_cmd_context *)_ctx;
+
+       switch (c) {
+       case 'm':
+               ctx->mailbox = optarg;
+               break;
+       default:
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static struct doveadm_mail_cmd_context *cmd_save_alloc(void)
+{
+       struct save_cmd_context *ctx;
+
+       ctx = doveadm_mail_cmd_alloc(struct save_cmd_context);
+       ctx->ctx.getopt_args = "m:";
+       ctx->ctx.v.parse_arg = cmd_mailbox_save_parse_arg;
+       ctx->ctx.v.init = cmd_save_init;
+       ctx->ctx.v.run = cmd_save_run;
+       ctx->mailbox = "INBOX";
+       return &ctx->ctx;
+}
+
+struct doveadm_mail_cmd cmd_save = {
+       cmd_save_alloc, "save", "[-m mailbox]"
+};
index 3cefd757cd41a5419eae2f28faf12e68c3ece934..9b63f725068c4214513c5585755b65e9fb02238c 100644 (file)
@@ -787,6 +787,7 @@ static struct doveadm_mail_cmd *mail_commands[] = {
        &cmd_force_resync,
        &cmd_purge,
        &cmd_expunge,
+       &cmd_save,
        &cmd_search,
        &cmd_fetch,
        &cmd_flags_add,
index 4106acb79f9760fea05f003797956ce15f79c6ef..4914a87512eb73e04d0517ec092ce439709f8f86 100644 (file)
@@ -167,6 +167,7 @@ void doveadm_mail_failed_list(struct doveadm_mail_cmd_context *ctx,
                              struct mailbox_list *list);
 
 extern struct doveadm_mail_cmd cmd_expunge;
+extern struct doveadm_mail_cmd cmd_save;
 extern struct doveadm_mail_cmd cmd_search;
 extern struct doveadm_mail_cmd cmd_fetch;
 extern struct doveadm_mail_cmd cmd_flags_add;