diff options
Diffstat (limited to 'src/doveadm/doveadm-mail-save.c')
-rw-r--r-- | src/doveadm/doveadm-mail-save.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-mail-save.c b/src/doveadm/doveadm-mail-save.c new file mode 100644 index 0000000..d8312c8 --- /dev/null +++ b/src/doveadm/doveadm-mail-save.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2015-2018 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 (input->stream_errno != 0) { + i_error("open(%s) failed: %s", + i_stream_get_name(input), + i_stream_get_error(input)); + ctx->ctx.exit_code = EX_TEMPFAIL; + return -1; + } + + if (mailbox_open(box) < 0) { + i_error("Failed to open mailbox %s: %s", + mailbox_get_vname(box), + mailbox_get_last_internal_error(box, NULL)); + doveadm_mail_failed_storage(&ctx->ctx, storage); + return -1; + } + + trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL | + ctx->ctx.transaction_flags, __func__); + save_ctx = mailbox_save_alloc(trans); + if (mailbox_save_begin(&save_ctx, input) < 0) { + i_error("Saving failed: %s", + mailbox_get_last_internal_error(box, NULL)); + doveadm_mail_failed_storage(&ctx->ctx, storage); + mailbox_transaction_rollback(&trans); + return -1; + } + do { + if (mailbox_save_continue(save_ctx) < 0) { + save_failed = TRUE; + ret = -1; + break; + } + } while ((ret = i_stream_read(input)) > 0); + 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_internal_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_internal_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_internal_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_cmd_ver2 doveadm_cmd_save_ver2 = { + .name = "save", + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-m mailbox]", + .mail_cmd = cmd_save_alloc, +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('m', "mailbox", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "file", CMD_PARAM_ISTREAM, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; |