changeset 11247:f05909834219 HEAD

doveadm: Changed mail command handler API. This should help add some new future features.
author Timo Sirainen <tss@iki.fi>
date Fri, 30 Apr 2010 19:14:57 +0300
parents f195e11fd919
children 1fd45deee948
files src/doveadm/doveadm-mail-altmove.c src/doveadm/doveadm-mail-expunge.c src/doveadm/doveadm-mail-fetch.c src/doveadm/doveadm-mail-list.c src/doveadm/doveadm-mail-search.c src/doveadm/doveadm-mail.c src/doveadm/doveadm-mail.h src/plugins/quota/doveadm-quota.c
diffstat 8 files changed, 281 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/doveadm-mail-altmove.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail-altmove.c	Fri Apr 30 19:14:57 2010 +0300
@@ -9,6 +9,11 @@
 #include "doveadm-mail-iter.h"
 #include "doveadm-mail.h"
 
+struct altmove_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+	struct mail_search_args *search_args;
+};
+
 static int
 cmd_altmove_box(const struct mailbox_info *info,
 		struct mail_search_args *search_args)
@@ -41,14 +46,15 @@
 	}
 }
 
-void cmd_altmove(struct mail_user *user, const char *const args[])
+static void
+cmd_altmove_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct altmove_cmd_context *ctx = (struct altmove_cmd_context *)_ctx;
 	const enum mailbox_list_iter_flags iter_flags =
 		MAILBOX_LIST_ITER_RAW_LIST |
 		MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 		MAILBOX_LIST_ITER_NO_AUTO_INBOX |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	struct mail_search_args *search_args;
 	struct doveadm_mail_list_iter *iter;
 	const struct mailbox_info *info;
 	struct mail_namespace *ns, *prev_ns = NULL;
@@ -56,12 +62,8 @@
 	struct mail_storage *const *storages;
 	unsigned int i, count;
 
-	if (args[0] == NULL)
-		doveadm_mail_help_name("altmove");
-	search_args = doveadm_mail_build_search_args(args);
-
 	t_array_init(&purged_storages, 8);
-	iter = doveadm_mail_list_iter_init(user, search_args, iter_flags);
+	iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
 	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
 		if (info->ns != prev_ns) {
 			if (prev_ns != NULL) {
@@ -71,7 +73,7 @@
 			}
 			prev_ns = info->ns;
 		}
-		(void)cmd_altmove_box(info, search_args);
+		(void)cmd_altmove_box(info, ctx->search_args);
 	} T_END;
 	doveadm_mail_list_iter_deinit(&iter);
 
@@ -91,3 +93,16 @@
 		}
 	}
 }
+
+struct doveadm_mail_cmd_context *cmd_altmove(const char *const args[])
+{
+	struct altmove_cmd_context *ctx;
+
+	if (args[0] == NULL)
+		doveadm_mail_help_name("altmove");
+
+	ctx = doveadm_mail_cmd_init(struct altmove_cmd_context);
+	ctx->ctx.run = cmd_altmove_run;
+	ctx->search_args = doveadm_mail_build_search_args(args);
+	return &ctx->ctx;
+}
--- a/src/doveadm/doveadm-mail-expunge.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail-expunge.c	Fri Apr 30 19:14:57 2010 +0300
@@ -9,6 +9,11 @@
 #include "doveadm-mail-iter.h"
 #include "doveadm-mail.h"
 
+struct expunge_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+	struct mail_search_args *search_args;
+};
+
 static int
 cmd_expunge_box(const struct mailbox_info *info,
 		struct mail_search_args *search_args)
@@ -161,35 +166,45 @@
 	return FALSE;
 }
 
-void cmd_expunge(struct mail_user *user, const char *const args[])
+static void
+cmd_expunge_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx;
 	const enum mailbox_list_iter_flags iter_flags =
 		MAILBOX_LIST_ITER_RAW_LIST |
 		MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 		MAILBOX_LIST_ITER_NO_AUTO_INBOX |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	struct mail_search_args *search_args;
 	struct doveadm_mail_list_iter *iter;
 	const struct mailbox_info *info;
 
-	if (args[0] == NULL)
-		doveadm_mail_help_name("expunge");
-	search_args = doveadm_mail_build_search_args(args);
-	mail_search_args_simplify(search_args);
-
-	if (!expunge_search_args_is_mailbox_ok(search_args->args)) {
+	if (!expunge_search_args_is_mailbox_ok(ctx->search_args->args)) {
 		i_fatal("expunge: To avoid accidents, search query "
 			"must contain MAILBOX in all search branches");
 	}
-	if (!expunge_search_args_is_msgset_ok(search_args->args)) {
+	if (!expunge_search_args_is_msgset_ok(ctx->search_args->args)) {
 		i_fatal("expunge: To avoid accidents, each branch in "
 			"search query must contain something else "
 			"besides MAILBOX");
 	}
 
-	iter = doveadm_mail_list_iter_init(user, search_args, iter_flags);
+	iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
 	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
-		(void)cmd_expunge_box(info, search_args);
+		(void)cmd_expunge_box(info, ctx->search_args);
 	} T_END;
 	doveadm_mail_list_iter_deinit(&iter);
 }
+
+struct doveadm_mail_cmd_context *cmd_expunge(const char *const args[])
+{
+	struct expunge_cmd_context *ctx;
+
+	if (args[0] == NULL)
+		doveadm_mail_help_name("expunge");
+
+	ctx = doveadm_mail_cmd_init(struct expunge_cmd_context);
+	ctx->ctx.run = cmd_expunge_run;
+	ctx->search_args = doveadm_mail_build_search_args(args);
+	mail_search_args_simplify(ctx->search_args);
+	return &ctx->ctx;
+}
--- a/src/doveadm/doveadm-mail-fetch.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail-fetch.c	Fri Apr 30 19:14:57 2010 +0300
@@ -17,7 +17,9 @@
 
 #include <stdio.h>
 
-struct fetch_context {
+struct fetch_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+
 	struct mail_search_args *search_args;
 	struct ostream *output;
 	struct mail *mail;
@@ -31,7 +33,7 @@
 	bool print_field_prefix;
 };
 
-static int fetch_mailbox(struct fetch_context *ctx)
+static int fetch_mailbox(struct fetch_cmd_context *ctx)
 {
 	const char *value;
 
@@ -41,7 +43,7 @@
 	return 0;
 }
 
-static int fetch_mailbox_guid(struct fetch_context *ctx)
+static int fetch_mailbox_guid(struct fetch_cmd_context *ctx)
 {
 	uint8_t guid[MAIL_GUID_128_SIZE];
 
@@ -51,19 +53,19 @@
 	return 0;
 }
 
-static int fetch_seq(struct fetch_context *ctx)
+static int fetch_seq(struct fetch_cmd_context *ctx)
 {
 	str_printfa(ctx->hdr, "%u", ctx->mail->seq);
 	return 0;
 }
 
-static int fetch_uid(struct fetch_context *ctx)
+static int fetch_uid(struct fetch_cmd_context *ctx)
 {
 	str_printfa(ctx->hdr, "%u", ctx->mail->seq);
 	return 0;
 }
 
-static int fetch_guid(struct fetch_context *ctx)
+static int fetch_guid(struct fetch_cmd_context *ctx)
 {
 	const char *value;
 
@@ -73,20 +75,20 @@
 	return 0;
 }
 
-static int fetch_flags(struct fetch_context *ctx)
+static int fetch_flags(struct fetch_cmd_context *ctx)
 {
 	imap_write_flags(ctx->hdr, mail_get_flags(ctx->mail),
 			 mail_get_keywords(ctx->mail));
 	return 0;
 }
 
-static void flush_hdr(struct fetch_context *ctx)
+static void flush_hdr(struct fetch_cmd_context *ctx)
 {
 	o_stream_send(ctx->output, str_data(ctx->hdr), str_len(ctx->hdr));
 	str_truncate(ctx->hdr, 0);
 }
 
-static int fetch_hdr(struct fetch_context *ctx)
+static int fetch_hdr(struct fetch_cmd_context *ctx)
 {
 	struct istream *input;
 	struct message_size hdr_size;
@@ -112,7 +114,7 @@
 	return ret;
 }
 
-static int fetch_body(struct fetch_context *ctx)
+static int fetch_body(struct fetch_cmd_context *ctx)
 {
 	struct istream *input;
 	struct message_size hdr_size;
@@ -137,7 +139,7 @@
 	return ret;
 }
 
-static int fetch_text(struct fetch_context *ctx)
+static int fetch_text(struct fetch_cmd_context *ctx)
 {
 	struct istream *input;
 	int ret = 0;
@@ -160,7 +162,7 @@
 	return ret;
 }
 
-static int fetch_size_physical(struct fetch_context *ctx)
+static int fetch_size_physical(struct fetch_cmd_context *ctx)
 {
 	uoff_t size;
 
@@ -170,7 +172,7 @@
 	return 0;
 }
 
-static int fetch_size_virtual(struct fetch_context *ctx)
+static int fetch_size_virtual(struct fetch_cmd_context *ctx)
 {
 	uoff_t size;
 
@@ -180,7 +182,7 @@
 	return 0;
 }
 
-static int fetch_date_received(struct fetch_context *ctx)
+static int fetch_date_received(struct fetch_cmd_context *ctx)
 {
 	time_t t;
 
@@ -190,7 +192,7 @@
 	return 0;
 }
 
-static int fetch_date_sent(struct fetch_context *ctx)
+static int fetch_date_sent(struct fetch_cmd_context *ctx)
 {
 	time_t t;
 	int tz;
@@ -206,7 +208,7 @@
 	return 0;
 }
 
-static int fetch_date_saved(struct fetch_context *ctx)
+static int fetch_date_saved(struct fetch_cmd_context *ctx)
 {
 	time_t t;
 
@@ -219,7 +221,7 @@
 struct fetch_field {
 	const char *name;
 	enum mail_fetch_field wanted_fields;
-	int (*print)(struct fetch_context *ctx);
+	int (*print)(struct fetch_cmd_context *ctx);
 };
 
 static const struct fetch_field fetch_fields[] = {
@@ -261,7 +263,7 @@
 	fprintf(stderr, "\n");
 }
 
-static void parse_fetch_fields(struct fetch_context *ctx, const char *str)
+static void parse_fetch_fields(struct fetch_cmd_context *ctx, const char *str)
 {
 	const char *const *fields, *name;
 	const struct fetch_field *field;
@@ -283,7 +285,7 @@
 	ctx->print_field_prefix = array_count(&ctx->fields) > 1;
 }
 
-static void cmd_fetch_mail(struct fetch_context *ctx)
+static void cmd_fetch_mail(struct fetch_cmd_context *ctx)
 {
 	const struct fetch_field *field;
 	struct mail *mail = ctx->mail;
@@ -305,7 +307,7 @@
 }
 
 static int
-cmd_fetch_box(struct fetch_context *ctx, const struct mailbox_info *info)
+cmd_fetch_box(struct fetch_cmd_context *ctx, const struct mailbox_info *info)
 {
 	struct doveadm_mail_iter *iter;
 	struct mailbox_transaction_context *trans;
@@ -355,43 +357,59 @@
 	return have_mailbox && have_msg;
 }
 
-void cmd_fetch(struct mail_user *user, const char *const args[])
+static void
+cmd_fetch_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
 	const enum mailbox_list_iter_flags iter_flags =
 		MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 		MAILBOX_LIST_ITER_NO_AUTO_INBOX |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	const char *fetch_fields = args[0];
-	struct fetch_context ctx;
 	struct doveadm_mail_list_iter *iter;
 	const struct mailbox_info *info;
+
+	iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
+	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
+		(void)cmd_fetch_box(ctx, info);
+	} T_END;
+	doveadm_mail_list_iter_deinit(&iter);
+}
+
+static void cmd_fetch_deinit(struct doveadm_mail_cmd_context *_ctx)
+{
+	struct fetch_cmd_context *ctx = (struct fetch_cmd_context *)_ctx;
+
+	o_stream_unref(&ctx->output);
+	str_free(&ctx->hdr);
+}
+
+struct doveadm_mail_cmd_context *cmd_fetch(const char *const args[])
+{
+	const char *fetch_fields = args[0];
+	struct fetch_cmd_context *ctx;
 	unsigned char prefix_buf[9];
 
-	memset(&ctx, 0, sizeof(ctx));
 	if (fetch_fields == NULL || args[1] == NULL)
 		doveadm_mail_help_name("fetch");
-	parse_fetch_fields(&ctx, fetch_fields);
-	ctx.search_args = doveadm_mail_build_search_args(args + 1);
+
+	ctx = doveadm_mail_cmd_init(struct fetch_cmd_context);
+	ctx->ctx.run = cmd_fetch_run;
+	ctx->ctx.deinit = cmd_fetch_deinit;
 
-	ctx.output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE);
+	parse_fetch_fields(ctx, fetch_fields);
+	ctx->search_args = doveadm_mail_build_search_args(args + 1);
 
-	ctx.hdr = str_new(default_pool, 512);
-	if (search_args_have_unique_fetch(ctx.search_args))
-		ctx.prefix = "";
+	ctx->output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE);
+	ctx->hdr = str_new(default_pool, 512);
+	if (search_args_have_unique_fetch(ctx->search_args))
+		ctx->prefix = "";
 	else {
 		random_fill_weak(prefix_buf, sizeof(prefix_buf));
-		str_append(ctx.hdr, "===");
-		base64_encode(prefix_buf, sizeof(prefix_buf), ctx.hdr);
-		str_append_c(ctx.hdr, '\n');
-		ctx.prefix = t_strdup(str_c(ctx.hdr));
-		str_truncate(ctx.hdr, 0);
+		str_append(ctx->hdr, "===");
+		base64_encode(prefix_buf, sizeof(prefix_buf), ctx->hdr);
+		str_append_c(ctx->hdr, '\n');
+		ctx->prefix = t_strdup(str_c(ctx->hdr));
+		str_truncate(ctx->hdr, 0);
 	}
-
-	iter = doveadm_mail_list_iter_init(user, ctx.search_args, iter_flags);
-	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
-		(void)cmd_fetch_box(&ctx, info);
-	} T_END;
-	doveadm_mail_list_iter_deinit(&iter);
-	o_stream_unref(&ctx.output);
-	str_free(&ctx.hdr);
+	return &ctx->ctx;
 }
--- a/src/doveadm/doveadm-mail-list.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail-list.c	Fri Apr 30 19:14:57 2010 +0300
@@ -8,35 +8,51 @@
 
 #include <stdio.h>
 
-void cmd_list(struct mail_user *user, const char *const args[])
+struct list_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+	struct mail_search_args *search_args;
+};
+
+static void
+cmd_list_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct list_cmd_context *ctx = (struct list_cmd_context *)_ctx;
 	const enum mailbox_list_iter_flags iter_flags =
 		MAILBOX_LIST_ITER_RAW_LIST |
 		MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 		MAILBOX_LIST_ITER_NO_AUTO_INBOX |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	struct mail_search_args *search_args;
-	struct mail_search_arg *arg;
 	struct doveadm_mail_list_iter *iter;
 	const struct mailbox_info *info;
-	unsigned int i;
 
-	search_args = mail_search_build_init();
-	for (i = 0; args[i] != NULL; i++) {
-		arg = mail_search_build_add(search_args, SEARCH_MAILBOX_GLOB);
-		arg->value.str = p_strdup(search_args->pool, args[i]);
-	}
-	if (i > 1) {
-		struct mail_search_arg *subargs = search_args->args;
-
-		search_args->args = NULL;
-		arg = mail_search_build_add(search_args, SEARCH_OR);
-		arg->value.subargs = subargs;
-	}
-
-	iter = doveadm_mail_list_iter_init(user, search_args, iter_flags);
+	iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
 	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) {
 		printf("%s\n", info->name);
 	}
 	doveadm_mail_list_iter_deinit(&iter);
 }
+
+struct doveadm_mail_cmd_context *cmd_list(const char *const args[])
+{
+	struct list_cmd_context *ctx;
+	struct mail_search_arg *arg;
+	unsigned int i;
+
+	ctx = doveadm_mail_cmd_init(struct list_cmd_context);
+	ctx->ctx.run = cmd_list_run;
+
+	ctx->search_args = mail_search_build_init();
+	for (i = 0; args[i] != NULL; i++) {
+		arg = mail_search_build_add(ctx->search_args,
+					    SEARCH_MAILBOX_GLOB);
+		arg->value.str = p_strdup(ctx->search_args->pool, args[i]);
+	}
+	if (i > 1) {
+		struct mail_search_arg *subargs = ctx->search_args->args;
+
+		ctx->search_args->args = NULL;
+		arg = mail_search_build_add(ctx->search_args, SEARCH_OR);
+		arg->value.subargs = subargs;
+	}
+	return &ctx->ctx;
+}
--- a/src/doveadm/doveadm-mail-search.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail-search.c	Fri Apr 30 19:14:57 2010 +0300
@@ -8,6 +8,11 @@
 
 #include <stdio.h>
 
+struct search_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+	struct mail_search_args *search_args;
+};
+
 static int
 cmd_search_box(const struct mailbox_info *info,
 	       struct mail_search_args *search_args)
@@ -36,24 +41,34 @@
 	return ret;
 }
 
-void cmd_search(struct mail_user *user, const char *const args[])
+static void
+cmd_search_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct search_cmd_context *ctx = (struct search_cmd_context *)_ctx;
 	const enum mailbox_list_iter_flags iter_flags =
 		MAILBOX_LIST_ITER_RAW_LIST |
 		MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 		MAILBOX_LIST_ITER_NO_AUTO_INBOX |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	struct mail_search_args *search_args;
 	struct doveadm_mail_list_iter *iter;
 	const struct mailbox_info *info;
 
+	iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
+	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
+		(void)cmd_search_box(info, ctx->search_args);
+	} T_END;
+	doveadm_mail_list_iter_deinit(&iter);
+}
+
+struct doveadm_mail_cmd_context *cmd_search(const char *const args[])
+{
+	struct search_cmd_context *ctx;
+
 	if (args[0] == NULL)
 		doveadm_mail_help_name("search");
-	search_args = doveadm_mail_build_search_args(args);
 
-	iter = doveadm_mail_list_iter_init(user, search_args, iter_flags);
-	while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
-		(void)cmd_search_box(info, search_args);
-	} T_END;
-	doveadm_mail_list_iter_deinit(&iter);
+	ctx = doveadm_mail_cmd_init(struct search_cmd_context);
+	ctx->ctx.run = cmd_search_run;
+	ctx->search_args = doveadm_mail_build_search_args(args);
+	return &ctx->ctx;
 }
--- a/src/doveadm/doveadm-mail.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail.c	Fri Apr 30 19:14:57 2010 +0300
@@ -24,8 +24,23 @@
 
 static int killed_signo = 0;
 
+struct doveadm_mail_cmd_context *
+doveadm_mail_cmd_init_size(size_t size)
+{
+	struct doveadm_mail_cmd_context *ctx;
+	pool_t pool;
+
+	i_assert(size >= sizeof(struct doveadm_mail_cmd_context));
+
+	pool = pool_alloconly_create("doveadm mail cmd", 1024);
+	ctx = p_malloc(pool, size);
+	ctx->pool = pool;
+	return ctx;
+}
+
 static void
-cmd_purge(struct mail_user *user, const char *const args[] ATTR_UNUSED)
+cmd_purge_run(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED,
+	      struct mail_user *user)
 {
 	struct mail_namespace *ns;
 
@@ -40,6 +55,16 @@
 	}
 }
 
+static struct doveadm_mail_cmd_context *
+cmd_purge(const char *const args[] ATTR_UNUSED)
+{
+	struct doveadm_mail_cmd_context *ctx;
+
+	ctx = doveadm_mail_cmd_init(struct doveadm_mail_cmd_context);
+	ctx->run = cmd_purge_run;
+	return ctx;
+}
+
 static struct mailbox *
 mailbox_find_and_open(struct mail_user *user, const char *mailbox)
 {
@@ -90,30 +115,50 @@
 	return sargs;
 }
 
-static void cmd_force_resync(struct mail_user *user, const char *const args[])
+struct force_resync_cmd_context {
+	struct doveadm_mail_cmd_context ctx;
+	const char *mailbox;
+};
+
+static void cmd_force_resync_run(struct doveadm_mail_cmd_context *_ctx,
+				 struct mail_user *user)
 {
-	const char *mailbox = args[0];
+	struct force_resync_cmd_context *ctx =
+		(struct force_resync_cmd_context *)_ctx;
 	struct mail_storage *storage;
 	struct mailbox *box;
 
-	if (mailbox == NULL)
-		doveadm_mail_help_name("force-resync");
-
-	box = mailbox_find_and_open(user, mailbox);
+	box = mailbox_find_and_open(user, ctx->mailbox);
 	storage = mailbox_get_storage(box);
 	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FORCE_RESYNC |
 			 MAILBOX_SYNC_FLAG_FIX_INCONSISTENT) < 0) {
-		i_fatal("Forcing a resync on mailbox %s failed: %s", mailbox,
+		i_fatal("Forcing a resync on mailbox %s failed: %s",
+			ctx->mailbox,
 			mail_storage_get_last_error(storage, NULL));
 	}
 	mailbox_free(&box);
 }
 
+static struct doveadm_mail_cmd_context *
+cmd_force_resync(const char *const args[])
+{
+	struct force_resync_cmd_context *ctx;
+	const char *mailbox = args[0];
+
+	if (mailbox == NULL || args[1] != NULL)
+		doveadm_mail_help_name("force-resync");
+
+	ctx = doveadm_mail_cmd_init(struct force_resync_cmd_context);
+	ctx->ctx.run = cmd_force_resync_run;
+	ctx->mailbox = p_strdup(ctx->ctx.pool, mailbox);
+	return &ctx->ctx;
+}
+
 static int
-doveadm_mail_next_user(doveadm_mail_command_t *cmd,
+doveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx,
 		       struct mail_storage_service_ctx *storage_service,
 		       const struct mail_storage_service_input *input,
-		       const char *const args[], const char **error_r)
+		       const char **error_r)
 {
 	struct mail_storage_service_user *service_user;
 	struct mail_user *mail_user;
@@ -139,16 +184,16 @@
 		return ret;
 	}
 
-	cmd(mail_user, args);
+	ctx->run(ctx, mail_user);
 	mail_storage_service_user_free(&service_user);
 	mail_user_unref(&mail_user);
 	return 1;
 }
 
 static void
-doveadm_mail_single_user(doveadm_mail_command_t *cmd, const char *username,
-			 enum mail_storage_service_flags service_flags,
-			 const char *const args[])
+doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx,
+			 const char *username,
+			 enum mail_storage_service_flags service_flags)
 {
 	struct mail_storage_service_ctx *storage_service;
 	struct mail_storage_service_input input;
@@ -163,8 +208,7 @@
 
 	storage_service = mail_storage_service_init(master_service, NULL,
 						    service_flags);
-	ret = doveadm_mail_next_user(cmd, storage_service, &input,
-				     args, &error);
+	ret = doveadm_mail_next_user(ctx, storage_service, &input, &error);
 	if (ret < 0)
 		i_fatal("%s", error);
 	else if (ret == 0)
@@ -178,9 +222,8 @@
 }
 
 static void
-doveadm_mail_all_users(doveadm_mail_command_t *cmd,
-		       enum mail_storage_service_flags service_flags,
-		       const char *const args[])
+doveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx,
+		       enum mail_storage_service_flags service_flags)
 {
 	struct mail_storage_service_input input;
 	struct mail_storage_service_ctx *storage_service;
@@ -209,8 +252,8 @@
 						    &user)) > 0) {
 		input.username = user;
 		T_BEGIN {
-			ret = doveadm_mail_next_user(cmd, storage_service,
-						     &input, args, &error);
+			ret = doveadm_mail_next_user(ctx, storage_service,
+						     &input, &error);
 			if (ret < 0)
 				i_error("%s", error);
 			else if (ret == 0)
@@ -243,6 +286,7 @@
 {
 	enum mail_storage_service_flags service_flags =
 		MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
+	struct doveadm_mail_cmd_context *ctx;
 	const char *username;
 	bool all_users = FALSE;
 	int c;
@@ -272,14 +316,15 @@
 			cmd->name, argv[0]);
 	}
 
+	ctx = cmd->init((const void *)argv);
 	if (!all_users) {
-		doveadm_mail_single_user(cmd->cmd, username, service_flags,
-					 (const void *)argv);
+		doveadm_mail_single_user(ctx, username, service_flags);
 	} else {
 		service_flags |= MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP;
-		doveadm_mail_all_users(cmd->cmd, service_flags,
-				       (const void *)argv);
+		doveadm_mail_all_users(ctx, service_flags);
 	}
+	if (ctx->deinit != NULL)
+		ctx->deinit(ctx);
 }
 
 static bool
--- a/src/doveadm/doveadm-mail.h	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/doveadm/doveadm-mail.h	Fri Apr 30 19:14:57 2010 +0300
@@ -4,12 +4,19 @@
 #include "doveadm.h"
 
 struct mail_user;
+struct doveadm_mail_cmd_context;
 
-typedef void doveadm_mail_command_t(struct mail_user *mail_user,
-				    const char *const args[]);
+struct doveadm_mail_cmd_context {
+	pool_t pool;
+
+	void (*run)(struct doveadm_mail_cmd_context *ctx,
+		    struct mail_user *mail_user);
+	void (*deinit)(struct doveadm_mail_cmd_context *ctx);
+};
 
 struct doveadm_mail_cmd {
-	doveadm_mail_command_t *cmd;
+	struct doveadm_mail_cmd_context *
+		(*init)(const char *const args[]);
 	const char *name;
 	const char *usage_args;
 };
@@ -32,10 +39,15 @@
 struct mail_search_args *
 doveadm_mail_build_search_args(const char *const args[]);
 
-void cmd_expunge(struct mail_user *user, const char *const args[]);
-void cmd_search(struct mail_user *user, const char *const args[]);
-void cmd_fetch(struct mail_user *user, const char *const args[]);
-void cmd_altmove(struct mail_user *user, const char *const args[]);
-void cmd_list(struct mail_user *user, const char *const args[]);
+struct doveadm_mail_cmd_context *
+doveadm_mail_cmd_init_size(size_t size);
+#define doveadm_mail_cmd_init(type) \
+	(type *)doveadm_mail_cmd_init_size(sizeof(type))
+
+struct doveadm_mail_cmd_context *cmd_expunge(const char *const args[]);
+struct doveadm_mail_cmd_context *cmd_search(const char *const args[]);
+struct doveadm_mail_cmd_context *cmd_fetch(const char *const args[]);
+struct doveadm_mail_cmd_context *cmd_altmove(const char *const args[]);
+struct doveadm_mail_cmd_context *cmd_list(const char *const args[]);
 
 #endif
--- a/src/plugins/quota/doveadm-quota.c	Fri Apr 30 18:01:08 2010 +0300
+++ b/src/plugins/quota/doveadm-quota.c	Fri Apr 30 19:14:57 2010 +0300
@@ -39,7 +39,8 @@
 }
 
 static void
-cmd_quota_get(struct mail_user *user, const char *const args[] ATTR_UNUSED)
+cmd_quota_get_run(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED,
+		  struct mail_user *user)
 {
 	struct quota_user *quser = QUOTA_USER_CONTEXT(user);
 	struct quota_root *const *root;
@@ -48,8 +49,19 @@
 		cmd_quota_get_root(user, *root);
 }
 
+static struct doveadm_mail_cmd_context *
+cmd_quota_get(const char *const args[] ATTR_UNUSED)
+{
+	struct doveadm_mail_cmd_context *ctx;
+
+	ctx = doveadm_mail_cmd_init(struct doveadm_mail_cmd_context);
+	ctx->run = cmd_quota_get_run;
+	return ctx;
+}
+
 static void
-cmd_quota_recalc(struct mail_user *user, const char *const args[] ATTR_UNUSED)
+cmd_quota_recalc_run(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED,
+		     struct mail_user *user)
 {
 	struct quota_user *quser = QUOTA_USER_CONTEXT(user);
 	struct quota_root *const *root;
@@ -63,6 +75,16 @@
 		(void)(*root)->backend.v.update(*root, &trans);
 }
 
+static struct doveadm_mail_cmd_context *
+cmd_quota_recalc(const char *const args[] ATTR_UNUSED)
+{
+	struct doveadm_mail_cmd_context *ctx;
+
+	ctx = doveadm_mail_cmd_init(struct doveadm_mail_cmd_context);
+	ctx->run = cmd_quota_recalc_run;
+	return ctx;
+}
+
 static struct doveadm_mail_cmd quota_commands[] = {
 	{ cmd_quota_get, "quota get", NULL },
 	{ cmd_quota_recalc, "quota recalc", NULL }