static int cmd_mailbox_metadata_list_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; struct mail_namespace *ns; struct mailbox *box; int ret = 0; ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "list attributes", &ns, &box); if (ret != 0) return ret; if (ctx->key == NULL || ctx->key_type == MAIL_ATTRIBUTE_TYPE_PRIVATE) { if (cmd_mailbox_metadata_list_run_iter(ctx, box, MAIL_ATTRIBUTE_TYPE_PRIVATE) < 0) { doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } if (ctx->key == NULL || ctx->key_type == MAIL_ATTRIBUTE_TYPE_SHARED) { if (cmd_mailbox_metadata_list_run_iter(ctx, box, MAIL_ATTRIBUTE_TYPE_SHARED) < 0) { doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } } mailbox_free(&box); return ret; }
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 dest_mailbox_open_or_create(struct import_cmd_context *ctx, struct mail_user *user, const struct mailbox_info *info, struct mailbox **box_r) { struct mail_namespace *ns; struct mailbox *box; enum mail_error error; const char *name, *errstr; if (*ctx->dest_parent != '\0') { /* prefix destination mailbox name with given parent mailbox */ ns = mail_namespace_find(user->namespaces, ctx->dest_parent); } else { ns = mail_namespace_find(user->namespaces, info->vname); } name = convert_vname_separators(info->vname, mail_namespace_get_sep(info->ns), mail_namespace_get_sep(ns)); if (*ctx->dest_parent != '\0') { name = t_strdup_printf("%s%c%s", ctx->dest_parent, mail_namespace_get_sep(ns), name); } box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY); if (mailbox_create(box, NULL, FALSE) < 0) { errstr = mailbox_get_last_error(box, &error); if (error != MAIL_ERROR_EXISTS) { i_error("Couldn't create mailbox %s: %s", name, errstr); doveadm_mail_failed_mailbox(&ctx->ctx, box); mailbox_free(&box); return -1; } } if (ctx->subscribe) { if (mailbox_set_subscribed(box, TRUE) < 0) { i_error("Couldn't subscribe to mailbox %s: %s", name, mailbox_get_last_error(box, NULL)); } } if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { i_error("Syncing mailbox %s failed: %s", name, mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, box); mailbox_free(&box); return -1; } *box_r = box; return 0; }
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_acl_mailbox_open(struct doveadm_mail_cmd_context *ctx, struct mail_user *user, const char *mailbox, struct mailbox **box_r) { struct acl_user *auser = ACL_USER_CONTEXT(user); struct mail_namespace *ns; struct mailbox *box; if (auser == NULL) { i_error("ACL not enabled for %s", user->username); doveadm_mail_failed_error(ctx, MAIL_ERROR_NOTFOUND); return -1; } ns = mail_namespace_find(user->namespaces, mailbox); box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_IGNORE_ACLS); if (mailbox_open(box) < 0) { i_error("Can't open mailbox %s: %s", mailbox, mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(ctx, box); mailbox_free(&box); return -1; } *box_r = box; return 0; }
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_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; struct mail_namespace *ns; struct mailbox *box; struct mail_attribute_value value; int ret; ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "get attribute", &ns, &box); if (ret != 0) return ret; ret = mailbox_attribute_get_stream(box, ctx->key_type, ctx->key, &value); if (ret < 0) { i_error("Failed to get attribute: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); } else if (ret == 0) { /* not found, print as empty */ doveadm_print(""); } else if (value.value_stream != NULL) { doveadm_print_istream(value.value_stream); } else { doveadm_print(value.value); } mailbox_free(&box); return ret; }
static int cmd_deduplicate_uidlist(struct doveadm_mail_cmd_context *_ctx, struct mailbox *box, struct uidlist *uidlist) { struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; struct mail_search_args *search_args; struct mail_search_arg *arg; struct mail *mail; ARRAY_TYPE(seq_range) uids; int ret = 0; /* the uidlist is reversed with oldest mails at the end. we'll delete everything but the oldest mail. */ if (uidlist->next == NULL) return 0; t_array_init(&uids, 8); for (; uidlist->next != NULL; uidlist = uidlist->next) seq_range_array_add(&uids, uidlist->uid); search_args = mail_search_build_init(); arg = mail_search_build_add(search_args, SEARCH_UIDSET); arg->value.seqset = uids; trans = mailbox_transaction_begin(box, 0); search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(search_ctx, &mail)) mail_expunge(mail); if (mailbox_search_deinit(&search_ctx) < 0) { i_error("Searching mailbox '%s' failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } if (mailbox_transaction_commit(&trans) < 0) { i_error("Committing mailbox '%s' transaction failed: %s", mailbox_get_vname(box), mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } return ret; }
static int cmd_copy_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct copy_cmd_context *ctx = (struct copy_cmd_context *)_ctx; const enum mailbox_list_iter_flags iter_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS; struct doveadm_mailbox_list_iter *iter; struct mail_user *src_user; struct mail_namespace *ns; struct mailbox *destbox; const struct mailbox_info *info; int ret = 0; if (ctx->source_username != NULL && ctx->source_user == NULL) cmd_copy_alloc_source_user(ctx); ns = mail_namespace_find(user->namespaces, ctx->destname); destbox = mailbox_alloc(ns->list, ctx->destname, MAILBOX_FLAG_SAVEONLY); if (mailbox_open(destbox) < 0) { i_error("Can't open mailbox '%s': %s", ctx->destname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); mailbox_free(&destbox); return -1; } src_user = ctx->source_user != NULL ? ctx->source_user : user; iter = doveadm_mailbox_list_iter_init(_ctx, src_user, _ctx->search_args, iter_flags); while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN { if (cmd_copy_box(ctx, destbox, info) < 0) ret = -1; } T_END; if (doveadm_mailbox_list_iter_deinit(&iter) < 0) ret = -1; if (mailbox_sync(destbox, 0) < 0) { i_error("Syncing mailbox '%s' failed: %s", ctx->destname, mailbox_get_last_error(destbox, NULL)); doveadm_mail_failed_mailbox(&ctx->ctx, destbox); ret = -1; } mailbox_free(&destbox); return ret; }
static int cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; struct mail_namespace *ns; struct mailbox *box; struct mailbox_transaction_context *trans; int ret; ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "set attribute", &ns, &box); if (ret != 0) return ret; trans = mailbox_transaction_begin(box, ctx->empty_mailbox_name ? MAILBOX_TRANSACTION_FLAG_EXTERNAL : 0); ret = ctx->value.value == NULL ? mailbox_attribute_unset(trans, ctx->key_type, ctx->key) : mailbox_attribute_set(trans, ctx->key_type, ctx->key, &ctx->value); if (ret < 0) { i_error("Failed to set attribute: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); mailbox_transaction_rollback(&trans); } else if (mailbox_transaction_commit(&trans) < 0) { i_error("Failed to commit transaction: %s", mailbox_get_last_error(box, NULL)); doveadm_mail_failed_mailbox(_ctx, box); ret = -1; } mailbox_free(&box); return ret; }
static int status_mailbox(struct status_cmd_context *ctx, const struct mailbox_info *info) { struct mailbox *box; struct mailbox_status status; struct mailbox_metadata metadata; box = doveadm_mailbox_find(ctx->ctx.cur_mail_user, info->vname); if (mailbox_get_status(box, ctx->status_items, &status) < 0 || mailbox_get_metadata(box, ctx->metadata_items, &metadata) < 0) { doveadm_mail_failed_mailbox(&ctx->ctx, box); mailbox_free(&box); return -1; } if (!ctx->total_sum) status_output(ctx, box, &status, &metadata); else status_sum(ctx, &status, &metadata); mailbox_free(&box); return 0; }
static int cmd_mailbox_metadata_open_mailbox(struct metadata_cmd_context *mctx, struct mail_user *user, const char *op, struct mail_namespace **ns_r, struct mailbox **box_r) { mctx->empty_mailbox_name = mctx->mailbox[0] == '\0'; if (mctx->empty_mailbox_name) { if (!mctx->ctx.allow_empty_mailbox_name) { i_error("Failed to %s: %s", op, "mailbox name cannot be empty"); mctx->ctx.exit_code = EX_USAGE; return -1; } /* server attribute */ *ns_r = mail_namespace_find_inbox(user->namespaces); *box_r = mailbox_alloc((*ns_r)->list, "INBOX", 0); mctx->key = t_strconcat(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER, mctx->key, NULL); } else { /* mailbox attributes */ *ns_r = mail_namespace_find(user->namespaces, mctx->mailbox); *box_r = mailbox_alloc((*ns_r)->list, mctx->mailbox, 0); } if (mailbox_open(*box_r) < 0) { i_error("Failed to open mailbox: %s", mailbox_get_last_error(*box_r, NULL)); doveadm_mail_failed_mailbox(&mctx->ctx, *box_r); mailbox_free(box_r); return -1; } return 0; }