static int cmd_deduplicate_box(struct doveadm_mail_cmd_context *_ctx, const struct mailbox_info *info, struct mail_search_args *search_args) { struct deduplicate_cmd_context *ctx = (struct deduplicate_cmd_context *)_ctx; struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; enum mail_error error; pool_t pool; HASH_TABLE(const char *, struct uidlist *) hash; const char *key, *errstr; struct uidlist *value; int ret = 0; if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, &iter) < 0) return -1; pool = pool_alloconly_create("deduplicate", 10240); hash_table_create(&hash, pool, 0, str_hash, strcmp); while (doveadm_mail_iter_next(iter, &mail)) { if (ctx->by_msgid) { if (mail_get_first_header(mail, "Message-ID", &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup Message-ID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } else { if (mail_get_special(mail, MAIL_FETCH_GUID, &key) < 0) { errstr = mailbox_get_last_error(mail->box, &error); if (error == MAIL_ERROR_NOTFOUND) continue; i_error("Couldn't lookup GUID: for UID=%u: %s", mail->uid, errstr); doveadm_mail_failed_error(_ctx, error); ret = -1; break; } } if (key != NULL && *key != '\0') { value = p_new(pool, struct uidlist, 1); value->uid = mail->uid; value->next = hash_table_lookup(hash, key); if (value->next == NULL) { key = p_strdup(pool, key); hash_table_insert(hash, key, value); } else { hash_table_update(hash, key, value); } } }
static int cmd_import_box_contents(struct doveadm_mail_iter *iter, struct mail *src_mail, struct mailbox *dest_box) { struct mail_save_context *save_ctx; struct mailbox_transaction_context *dest_trans; const char *mailbox = mailbox_get_vname(dest_box); int ret = 0; dest_trans = mailbox_transaction_begin(dest_box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); do { if (doveadm_debug) { i_debug("import: box=%s uid=%u", mailbox, src_mail->uid); } save_ctx = mailbox_save_alloc(dest_trans); mailbox_save_copy_flags(save_ctx, src_mail); if (mailbox_copy(&save_ctx, src_mail) < 0) { i_error("Copying box=%s uid=%u failed: %s", mailbox, src_mail->uid, mailbox_get_last_error(dest_box, NULL)); ret = -1; } } while (doveadm_mail_iter_next(iter, &src_mail)); if (mailbox_transaction_commit(&dest_trans) < 0) { i_error("Committing copied mails to %s failed: %s", mailbox, mailbox_get_last_error(dest_box, NULL)); ret = -1; } return ret; }
static int cmd_import_box(struct import_cmd_context *ctx, struct mail_user *dest_user, const struct mailbox_info *info, struct mail_search_args *search_args) { struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; int ret = 0; if (doveadm_mail_iter_init(&ctx->ctx, info, search_args, 0, NULL, &iter) < 0) return -1; if (doveadm_mail_iter_next(iter, &mail)) { /* at least one mail matches in this mailbox */ if (dest_mailbox_open_or_create(ctx, dest_user, info->vname, &box) < 0) ret = -1; else { if (cmd_import_box_contents(iter, mail, box) < 0) { doveadm_mail_failed_mailbox(&ctx->ctx, mail->box); ret = -1; } mailbox_free(&box); } } if (doveadm_mail_iter_deinit_sync(&iter) < 0) ret = -1; return ret; }
static int cmd_import_box(struct import_cmd_context *ctx, struct mail_user *dest_user, const struct mailbox_info *info, struct mail_search_args *search_args) { struct doveadm_mail_iter *iter; struct mailbox_transaction_context *trans; struct mailbox *box; struct mail *mail; int ret = 0; if (doveadm_mail_iter_init(info, search_args, &trans, &iter) < 0) return -1; mail = mail_alloc(trans, 0, NULL); if (doveadm_mail_iter_next(iter, mail)) { /* at least one mail matches in this mailbox */ if (dest_mailbox_open_or_create(ctx, dest_user, info->name, &box) == 0) { if (cmd_import_box_contents(iter, mail, box) < 0) ret = -1; mailbox_free(&box); } } mail_free(&mail); if (doveadm_mail_iter_deinit_sync(&iter) < 0) ret = -1; return ret; }
static int cmd_flags_run_box(struct flags_cmd_context *ctx, const struct mailbox_info *info) { struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; struct mail_keywords *kw = NULL; if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0, NULL, &iter) < 0) return -1; box = doveadm_mail_iter_get_mailbox(iter); if (ctx->keywords != NULL) { if (mailbox_keywords_create(box, ctx->keywords, &kw) < 0) { i_error("Invalid keywords: %s", mailbox_get_last_error(box, NULL)); (void)doveadm_mail_iter_deinit(&iter); ctx->ctx.exit_code = DOVEADM_EX_NOTPOSSIBLE; return -1; } } while (doveadm_mail_iter_next(iter, &mail)) { mail_update_flags(mail, ctx->modify_type, ctx->flags); if (kw != NULL) mail_update_keywords(mail, ctx->modify_type, kw); } if (kw != NULL) mailbox_keywords_unref(&kw); return doveadm_mail_iter_deinit(&iter); }
static int cmd_expunge_box(struct doveadm_mail_cmd_context *_ctx, const struct mailbox_info *info, struct mail_search_args *search_args) { struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx; struct doveadm_mail_iter *iter; struct mailbox *box; struct mail *mail; enum mail_error error; int ret = 0; if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL, FALSE, &iter) < 0) return -1; while (doveadm_mail_iter_next(iter, &mail)) { if (doveadm_debug) { i_debug("expunge: box=%s uid=%u", info->vname, mail->uid); } mail_expunge(mail); } if (doveadm_mail_iter_deinit_keep_box(&iter, &box) < 0) ret = -1; else if (mailbox_sync(box, 0) < 0) { i_error("Syncing mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_internal_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } if (ctx->delete_empty_mailbox && ret == 0) { if (mailbox_delete_empty(box) < 0) { error = mailbox_get_last_mail_error(box); if (error != MAIL_ERROR_EXISTS) { i_error("Deleting mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_internal_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } else { if (mailbox_set_subscribed(box, FALSE) < 0) { i_error("Unsubscribing mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_internal_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } } mailbox_free(&box); return ret; }
static int cmd_copy_box(struct copy_cmd_context *ctx, struct mailbox *destbox, const struct mailbox_info *info) { struct doveadm_mail_iter *iter; struct mailbox_transaction_context *desttrans; struct mail_save_context *save_ctx; struct mail *mail; int ret = 0; if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0, NULL, &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); 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) { if (ctx->move) mail_expunge(mail); } else { i_error("Copying message UID %u from '%s' failed: %s", mail->uid, info->vname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); ret = -1; } } if (mailbox_transaction_commit(&desttrans) < 0) { i_error("Committing %s mails failed: %s", ctx->move ? "moved" : "copied", mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); /* rollback expunges */ doveadm_mail_iter_deinit_rollback(&iter); ret = -1; } else { if (doveadm_mail_iter_deinit_sync(&iter) < 0) ret = -1; } return ret; }
static int cmd_altmove_box(struct doveadm_mail_cmd_context *ctx, const struct mailbox_info *info, struct mail_search_args *search_args, bool reverse) { struct doveadm_mail_iter *iter; struct mail *mail; enum modify_type modify_type = !reverse ? MODIFY_ADD : MODIFY_REMOVE; if (doveadm_mail_iter_init(ctx, info, search_args, 0, NULL, FALSE, &iter) < 0) return -1; while (doveadm_mail_iter_next(iter, &mail)) { if (doveadm_debug) { i_debug("altmove: box=%s uid=%u", info->vname, mail->uid); } mail_update_flags(mail, modify_type, (enum mail_flags)MAIL_INDEX_MAIL_FLAG_BACKEND); } return doveadm_mail_iter_deinit_sync(&iter); }