diff options
Diffstat (limited to '')
-rw-r--r-- | src/doveadm/doveadm-mail-iter.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-mail-iter.c b/src/doveadm/doveadm-mail-iter.c new file mode 100644 index 0000000..eca5421 --- /dev/null +++ b/src/doveadm/doveadm-mail-iter.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ostream.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "mail-search.h" +#include "doveadm-print.h" +#include "doveadm-mail.h" +#include "doveadm-mail-iter.h" + +struct doveadm_mail_iter { + struct doveadm_mail_cmd_context *ctx; + struct mail_search_args *search_args; + enum doveadm_mail_iter_flags flags; + + struct mailbox *box; + struct mailbox_transaction_context *t; + struct mail_search_context *search_ctx; + bool killed; +}; + +int doveadm_mail_iter_init(struct doveadm_mail_cmd_context *ctx, + const struct mailbox_info *info, + struct mail_search_args *search_args, + enum mail_fetch_field wanted_fields, + const char *const *wanted_headers, + enum doveadm_mail_iter_flags flags, + struct doveadm_mail_iter **iter_r) +{ + struct doveadm_mail_iter *iter; + struct mailbox_header_lookup_ctx *headers_ctx; + const char *errstr; + enum mail_error error; + + enum mailbox_flags readonly_flag = + (flags & DOVEADM_MAIL_ITER_FLAG_READONLY) != 0 ? + MAILBOX_FLAG_READONLY : 0; + + iter = i_new(struct doveadm_mail_iter, 1); + iter->ctx = ctx; + iter->flags = flags; + iter->box = mailbox_alloc(info->ns->list, info->vname, + MAILBOX_FLAG_IGNORE_ACLS | readonly_flag); + iter->search_args = search_args; + + if (mailbox_sync(iter->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { + errstr = mailbox_get_last_internal_error(iter->box, &error); + if (error == MAIL_ERROR_NOTFOUND) { + /* just ignore this mailbox */ + *iter_r = iter; + return 0; + } + i_error("Syncing mailbox %s failed: %s", info->vname, errstr); + doveadm_mail_failed_mailbox(ctx, iter->box); + mailbox_free(&iter->box); + i_free(iter); + return -1; + } + + headers_ctx = wanted_headers == NULL || wanted_headers[0] == NULL ? + NULL : mailbox_header_lookup_init(iter->box, wanted_headers); + + mail_search_args_init(search_args, iter->box, FALSE, NULL); + iter->t = mailbox_transaction_begin(iter->box, ctx->transaction_flags, + ctx->cmd->name); + iter->search_ctx = mailbox_search_init(iter->t, search_args, NULL, + wanted_fields, headers_ctx); + mailbox_header_lookup_unref(&headers_ctx); + *iter_r = iter; + return 0; +} + +static int +doveadm_mail_iter_deinit_transaction(struct doveadm_mail_iter *iter, + bool commit) +{ + int ret = 0; + + if (iter->search_ctx != NULL) { + if (mailbox_search_deinit(&iter->search_ctx) < 0) { + i_error("Searching mailbox %s failed: %s", + mailbox_get_vname(iter->box), + mailbox_get_last_internal_error(iter->box, NULL)); + ret = -1; + } + } + if (iter->t == NULL) + ; + else if (commit) { + if (mailbox_transaction_commit(&iter->t) < 0) { + i_error("Committing mailbox %s failed: %s", + mailbox_get_vname(iter->box), + mailbox_get_last_internal_error(iter->box, 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, bool commit, bool keep_box) +{ + struct doveadm_mail_iter *iter = *_iter; + int ret; + + *_iter = NULL; + + ret = doveadm_mail_iter_deinit_transaction(iter, commit); + if (ret == 0 && sync) { + ret = mailbox_sync(iter->box, 0); + if (ret < 0) { + i_error("Mailbox %s: Mailbox sync failed: %s", + mailbox_get_vname(iter->box), + mailbox_get_last_internal_error(iter->box, NULL)); + } + } + if (ret < 0) + doveadm_mail_failed_mailbox(iter->ctx, iter->box); + else if (iter->killed) { + iter->ctx->exit_code = EX_TEMPFAIL; + ret = -1; + } + if (!keep_box) + mailbox_free(&iter->box); + i_free(iter); + return ret; +} + +int doveadm_mail_iter_deinit(struct doveadm_mail_iter **_iter) +{ + return doveadm_mail_iter_deinit_full(_iter, FALSE, TRUE, FALSE); +} + +int doveadm_mail_iter_deinit_sync(struct doveadm_mail_iter **_iter) +{ + return doveadm_mail_iter_deinit_full(_iter, TRUE, TRUE, FALSE); +} + +int doveadm_mail_iter_deinit_keep_box(struct doveadm_mail_iter **iter, + struct mailbox **box_r) +{ + *box_r = (*iter)->box; + return doveadm_mail_iter_deinit_full(iter, FALSE, TRUE, TRUE); +} + +void doveadm_mail_iter_deinit_rollback(struct doveadm_mail_iter **_iter) +{ + (void)doveadm_mail_iter_deinit_full(_iter, FALSE, FALSE, FALSE); +} + +bool doveadm_mail_iter_next(struct doveadm_mail_iter *iter, + struct mail **mail_r) +{ + if (iter->search_ctx == NULL) + return FALSE; + if (doveadm_is_killed()) { + iter->killed = TRUE; + return FALSE; + } + if ((iter->flags & DOVEADM_MAIL_ITER_FLAG_STOP_WITH_CLIENT) != 0 && + doveadm_print_ostream->stream_errno != 0) { + iter->killed = TRUE; + return FALSE; + } + return mailbox_search_next(iter->search_ctx, mail_r); +} + +struct mailbox *doveadm_mail_iter_get_mailbox(struct doveadm_mail_iter *iter) +{ + return iter->box; +} |