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;
}
Beispiel #2
0
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;
}
Beispiel #5
0
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;
}