summaryrefslogtreecommitdiffstats
path: root/src/doveadm/doveadm-mail-iter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doveadm/doveadm-mail-iter.c')
-rw-r--r--src/doveadm/doveadm-mail-iter.c176
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;
+}