changeset 19875:1de13e5296ff

doveadm: Changed v2 command APIs to be easier to use.
author Aki Tuomi <aki.tuomi@dovecot.fi>
date Sun, 28 Feb 2016 18:27:35 +0200
parents 971cef290c5b
children 68601371950b
files src/doveadm/client-connection-http.c src/doveadm/client-connection.c src/doveadm/doveadm-cmd.c src/doveadm/doveadm-cmd.h src/doveadm/doveadm-mail.c src/doveadm/doveadm-mail.h src/doveadm/doveadm-penalty.c src/doveadm/doveadm-stats.c src/doveadm/doveadm.c
diffstat 9 files changed, 156 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/client-connection-http.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/client-connection-http.c	Sun Feb 28 18:27:35 2016 +0200
@@ -276,8 +276,7 @@
 static void
 doveadm_http_server_command_execute(struct client_connection_http *conn)
 {
-	const struct doveadm_cmd_param *cpar;
-	struct doveadm_cmd_attributes attrs;
+	struct doveadm_cmd_context cctx;
 
 	/* final preflight check */
 	if (!doveadm_client_is_allowed_command(conn->client.set, conn->cmd->name))
@@ -295,26 +294,28 @@
 		return;
 	}
 
-	int pargc;
 	struct istream *is;
 	struct ioloop *ioloop,*prev_ioloop = current_ioloop;
+	memset(&cctx, 0, sizeof(cctx));
 
 	// create iostream
 	doveadm_print_ostream = iostream_temp_create("/tmp/doveadm.", 0);
 
 	doveadm_print_init(DOVEADM_PRINT_TYPE_JSON);
 	/* then call it */
-	cpar = array_get(&conn->pargv, (unsigned int*)&pargc);
+	cctx.argv = array_get(&conn->pargv, (unsigned int*)&cctx.argc);
 	ioloop = io_loop_create();
 	lib_signals_reset_ioloop();
 	doveadm_exit_code = 0;
-	memset(&attrs, 0, sizeof(attrs));
-	attrs.local_ip = conn->client.local_ip;
-	attrs.local_port = conn->client.local_port;
-	attrs.remote_ip = conn->client.remote_ip;
-	attrs.remote_port = conn->client.remote_port;
 
-	conn->cmd->cmd(conn->cmd,pargc, cpar);
+	cctx.cmd = conn->cmd;
+	cctx.cli = FALSE;
+	cctx.local_ip = conn->client.local_ip;
+	cctx.local_port = conn->client.local_port;
+	cctx.remote_ip = conn->client.remote_ip;
+	cctx.remote_port = conn->client.remote_port;
+
+	cctx.cmd->cmd(&cctx);
 
 	io_loop_set_current(prev_ioloop);
 	lib_signals_reset_ioloop();
--- a/src/doveadm/client-connection.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/client-connection.c	Sun Feb 28 18:27:35 2016 +0200
@@ -68,31 +68,32 @@
 
 static void
 doveadm_cmd_server_run_ver2(struct client_connection *conn,
-			    const struct doveadm_cmd_ver2 *cmd,
-			    const struct doveadm_cmd_attributes *attrs)
+			    int argc, const char **argv,
+			    struct doveadm_cmd_context *cctx)
 {
 	i_getopt_reset();
 	doveadm_exit_code = 0;
-	if (doveadm_cmd_run_ver2(cmd, attrs) < 0)
+	if (doveadm_cmd_run_ver2(argc, argv, cctx) < 0)
 		doveadm_exit_code = EX_USAGE;
-	doveadm_cmd_server_post(conn, cmd->name);
+	doveadm_cmd_server_post(conn, cctx->cmd->name);
 }
 
 static void
 doveadm_cmd_server_run(struct client_connection *conn,
-		       const struct doveadm_cmd *cmd,
-		       const struct doveadm_cmd_attributes *attrs)
+		       int argc, const char **argv,
+		       const struct doveadm_cmd *cmd)
 {
 	i_getopt_reset();
 	doveadm_exit_code = 0;
-	cmd->cmd(attrs->argc, (char **)attrs->argv);
+	cmd->cmd(argc, (char **)argv);
 	doveadm_cmd_server_post(conn, cmd->name);
 }
 
 static int
 doveadm_mail_cmd_server_parse(const struct doveadm_mail_cmd *cmd,
 			      const struct doveadm_settings *set,
-			      const struct doveadm_cmd_attributes *attrs,
+			      int argc, const char **argv,
+			      struct doveadm_cmd_context *cctx,
 			      struct doveadm_mail_cmd_context **ctx_r)
 {
 	struct doveadm_mail_cmd_context *ctx;
@@ -101,7 +102,7 @@
 	int c;
 
 	ctx = doveadm_mail_cmd_init(cmd, set);
-	ctx->full_args = attrs->argv + 1;
+	ctx->full_args = argv+1;
 	ctx->proxying = TRUE;
 
 	ctx->service_flags |=
@@ -112,7 +113,7 @@
 
 	i_getopt_reset();
 	getopt_args = t_strconcat("AF:S:u:", ctx->getopt_args, NULL);
-	while ((c = getopt(attrs->argc, (char **)attrs->argv, getopt_args)) > 0) {
+	while ((c = getopt(argc, (char **)argv, getopt_args)) > 0) {
 		switch (c) {
 		case 'A':
 		case 'F':
@@ -139,20 +140,20 @@
 		}
 	}
 
-	if (attrs->argv[optind] != NULL && cmd->usage_args == NULL) {
+	if (argv[optind] != NULL && cmd->usage_args == NULL) {
 		i_error("doveadm %s: Client sent unknown parameter: %s",
-			cmd->name, attrs->argv[optind]);
+			cmd->name, argv[optind]);
 		ctx->v.deinit(ctx);
 		pool_unref(&ctx->pool);
 		return -1;
 	}
-	ctx->args = attrs->argv+optind;
+	ctx->args = argv+optind;
 
 	if (doveadm_print_is_initialized() && add_username_header) {
 		doveadm_print_header("username", "Username",
 				     DOVEADM_PRINT_HEADER_FLAG_STICKY |
 				     DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
-		doveadm_print_sticky("username", attrs->username);
+		doveadm_print_sticky("username", cctx->username);
 	}
 	*ctx_r = ctx;
 	return 0;
@@ -161,7 +162,7 @@
 static void
 doveadm_mail_cmd_server_run(struct client_connection *conn,
 			    struct doveadm_mail_cmd_context *ctx,
-			    const struct doveadm_cmd_attributes *attrs)
+			    struct doveadm_cmd_context *cctx)
 {
 	const char *error;
 	int ret;
@@ -172,7 +173,7 @@
 	if (ctx->v.preinit != NULL)
 		ctx->v.preinit(ctx);
 
-	ret = doveadm_mail_single_user(ctx, attrs, &error);
+	ret = doveadm_mail_single_user(ctx, cctx, &error);
 	doveadm_mail_server_flush();
 	ctx->v.deinit(ctx);
 	doveadm_print_flush();
@@ -217,30 +218,31 @@
 
 static int doveadm_cmd_handle(struct client_connection *conn,
 			      const char *cmd_name,
-			      const struct doveadm_cmd_attributes *attrs)
+			      int argc, const char **argv,
+			      struct doveadm_cmd_context *cctx)
 {
 	struct ioloop *ioloop, *prev_ioloop = current_ioloop;
 	const struct doveadm_cmd *cmd = NULL;
 	const struct doveadm_mail_cmd *mail_cmd;
 	struct doveadm_mail_cmd_context *ctx;
 	const struct doveadm_cmd_ver2 *cmd_ver2;
-	struct doveadm_cmd_attributes cmd_attrs;
 
-	if ((cmd_ver2 = doveadm_cmd_find_with_args_ver2(cmd_name, attrs->argc, attrs->argv)) == NULL) {
-		cmd_attrs = *attrs;
-		cmd = doveadm_cmd_find_with_args(cmd_name, &cmd_attrs.argc, &cmd_attrs.argv);
-		if (cmd == NULL) {
-			mail_cmd = doveadm_mail_cmd_find(cmd_name);
-			if (mail_cmd == NULL) {
+	if ((cmd_ver2 = doveadm_cmd_find_with_args_ver2(cmd_name, argc, argv)) == NULL) {
+		mail_cmd = doveadm_mail_cmd_find(cmd_name);
+		if (mail_cmd == NULL) {
+			cmd = doveadm_cmd_find_with_args(cmd_name, &argc, &argv);
+			if (cmd == NULL) {
 				i_error("doveadm: Client sent unknown command: %s", cmd_name);
 				return -1;
 			}
+		} else {
 			if (doveadm_mail_cmd_server_parse(mail_cmd, conn->set,
-							  attrs, &ctx) < 0)
+							  argc, argv,
+							  cctx, &ctx) < 0)
 				return -1;
-		} else {
-			attrs = &cmd_attrs;
 		}
+	} else {
+		cctx->cmd = cmd_ver2;
 	}
 
 	/* some commands will want to call io_loop_run(), but we're already
@@ -250,11 +252,11 @@
 	lib_signals_reset_ioloop();
 
 	if (cmd_ver2 != NULL)
-		doveadm_cmd_server_run_ver2(conn, cmd_ver2, attrs);
+		doveadm_cmd_server_run_ver2(conn, argc, argv, cctx);
 	else if (cmd != NULL)
-		doveadm_cmd_server_run(conn, cmd, attrs);
+		doveadm_cmd_server_run(conn, argc, argv, cmd);
 	else
-		doveadm_mail_cmd_server_run(conn, ctx, attrs);
+		doveadm_mail_cmd_server_run(conn, ctx, cctx);
 
 	io_loop_set_current(prev_ioloop);
 	lib_signals_reset_ioloop();
@@ -270,7 +272,7 @@
 
 static bool client_handle_command(struct client_connection *conn, char **args)
 {
-	struct doveadm_cmd_attributes attrs;
+	struct doveadm_cmd_context cctx;
 	const char *flags, *cmd_name;
 	unsigned int argc;
 
@@ -281,18 +283,16 @@
 		i_error("doveadm client: No command given");
 		return FALSE;
 	}
-	memset(&attrs, 0, sizeof(attrs));
-	/* leave the command name as args[0] so getopt() works */
-	attrs.argv = (const char **)args + 2;
-	attrs.argc = argc - 2;
+	memset(&cctx, 0, sizeof(cctx));
+	cctx.cli = FALSE;
 
-	attrs.local_ip = conn->local_ip;
-	attrs.remote_ip = conn->remote_ip;
-	attrs.local_port = conn->local_port;
-	attrs.remote_port = conn->remote_port;
+	cctx.local_ip = conn->local_ip;
+	cctx.remote_ip = conn->remote_ip;
+	cctx.local_port = conn->local_port;
+	cctx.remote_port = conn->remote_port;
 
 	flags = args[0];
-	attrs.username = args[1];
+	cctx.username = args[1];
 	cmd_name = args[2];
 
 	doveadm_debug = FALSE;
@@ -320,7 +320,7 @@
 	}
 
 	o_stream_cork(conn->output);
-	if (doveadm_cmd_handle(conn, cmd_name, &attrs) < 0)
+	if (doveadm_cmd_handle(conn, cmd_name, argc-2, (const char**)(args+2), &cctx) < 0)
 		o_stream_nsend(conn->output, "\n-\n", 3);
 	o_stream_uncork(conn->output);
 
--- a/src/doveadm/doveadm-cmd.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-cmd.c	Sun Feb 28 18:27:35 2016 +0200
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
+/* Copyright (c) 2009-2r016 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
 #include "array.h"
@@ -182,22 +182,23 @@
 }
 
 static const struct doveadm_cmd_param*
-doveadm_cmd_param_get(int argc, const struct doveadm_cmd_param *params,
+doveadm_cmd_param_get(const struct doveadm_cmd_context *cctx,
 		      const char *name)
 {
-	i_assert(params != NULL);
-	for(int i = 0; i < argc; i++) {
-		if (strcmp(params[i].name, name) == 0 && params[i].value_set)
-			return &(params[i]);
+	i_assert(cctx != NULL);
+	i_assert(cctx->argv != NULL);
+	for(int i = 0; i < cctx->argc; i++) {
+		if (strcmp(cctx->argv[i].name, name) == 0 && cctx->argv[i].value_set)
+			return &(cctx->argv[i]);
 	}
 	return NULL;
 }
 
-bool doveadm_cmd_param_bool(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
 			    const char *name, bool *value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 
 	if (param->type == CMD_PARAM_BOOL) {
 		*value_r = param->value.v_bool;
@@ -206,11 +207,11 @@
 	return FALSE;
 }
 
-bool doveadm_cmd_param_int64(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
 			     const char *name, int64_t *value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 
 	if (param->type == CMD_PARAM_INT64) {
 		*value_r = param->value.v_int64;
@@ -219,11 +220,11 @@
 	return FALSE;
 }
 
-bool doveadm_cmd_param_str(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
 			   const char *name, const char **value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 
 	if (param->type == CMD_PARAM_STR) {
 		*value_r = param->value.v_string;
@@ -232,11 +233,11 @@
 	return FALSE;
 }
 
-bool doveadm_cmd_param_ip(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
 			  const char *name, struct ip_addr *value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 
 	if (param->type == CMD_PARAM_IP) {
 		memcpy(value_r, &param->value.v_ip, sizeof(struct ip_addr));
@@ -245,11 +246,11 @@
 	return FALSE;
 }
 
-bool doveadm_cmd_param_array(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
 			     const char *name, ARRAY_TYPE(const_string) **value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 	if (param->type == CMD_PARAM_ARRAY) {
 		*value_r = (ARRAY_TYPE(const_string)*)&(param->value.v_array);
 		return TRUE;
@@ -257,11 +258,11 @@
 	return FALSE;
 }
 
-bool doveadm_cmd_param_istream(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
 			       const char *name, struct istream **value_r)
 {
 	const struct doveadm_cmd_param *param;
-	if ((param = doveadm_cmd_param_get(argc, params, name))==NULL) return FALSE;
+	if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE;
 
 	if (param->type == CMD_PARAM_ISTREAM) {
 		*value_r = param->value.v_istream;
@@ -314,20 +315,19 @@
 }
 
 void
-doveadm_cmd_ver2_to_cmd_wrapper(const struct doveadm_cmd_ver2* cmd,
-	int argc, const struct doveadm_cmd_param* param)
+doveadm_cmd_ver2_to_cmd_wrapper(struct doveadm_cmd_context *cctx)
 {
 	unsigned int pargc;
 	const char **pargv;
 
-	i_assert(cmd->old_cmd != NULL);
+	i_assert(cctx->cmd->old_cmd != NULL);
 
 	ARRAY_TYPE(const_string) nargv;
 	t_array_init(&nargv, 8);
-	doveadm_cmd_params_to_argv(cmd->name, argc, param, &nargv);
+	doveadm_cmd_params_to_argv(cctx->cmd->name, cctx->argc, cctx->argv, &nargv);
 	pargv = array_get_modifiable(&nargv, &pargc);
 	i_getopt_reset();
-	cmd->old_cmd(pargc-1, (char**)pargv);
+	cctx->cmd->old_cmd(pargc-1, (char**)pargv);
 }
 
 static void
@@ -393,21 +393,23 @@
 }
 
 bool doveadm_cmd_try_run_ver2(const char *cmd_name,
-			      const struct doveadm_cmd_attributes *attrs)
+			      int argc, const char **argv,
+			      struct doveadm_cmd_context *cctx)
 {
 	const struct doveadm_cmd_ver2 *cmd;
 
-	cmd = doveadm_cmd_find_with_args_ver2(cmd_name, attrs->argc, attrs->argv);
+	cmd = doveadm_cmd_find_with_args_ver2(cmd_name, argc, argv);
 	if (cmd == NULL)
 		return FALSE;
 
-	if (doveadm_cmd_run_ver2(cmd, attrs) < 0)
+	cctx->cmd = cmd;
+	if (doveadm_cmd_run_ver2(argc, argv, cctx) < 0)
 		doveadm_exit_code = EX_USAGE;
 	return TRUE;
 }
 
-int doveadm_cmd_run_ver2(const struct doveadm_cmd_ver2 *cmd,
-			 const struct doveadm_cmd_attributes *attrs)
+int doveadm_cmd_run_ver2(int argc, const char **argv,
+			 struct doveadm_cmd_context *cctx)
 {
 	struct doveadm_cmd_param *param;
 	ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv;
@@ -421,18 +423,18 @@
 	p_array_init(&opts, pool, 4);
 
 	// build parameters
-	doveadm_build_options(cmd->parameters, optbuf, &opts);
+	doveadm_build_options(cctx->cmd->parameters, optbuf, &opts);
 
 	p_array_init(&pargv, pool, 20);
 
-	for(pargc=0;cmd->parameters[pargc].name != NULL;pargc++) {
+	for(pargc=0;cctx->cmd->parameters[pargc].name != NULL;pargc++) {
 		param = array_append_space(&pargv);
-		memcpy(param, &(cmd->parameters[pargc]), sizeof(struct doveadm_cmd_param));
+		memcpy(param, &(cctx->cmd->parameters[pargc]), sizeof(struct doveadm_cmd_param));
 		param->value_set = FALSE;
 	}
 	i_assert(pargc == array_count(&opts)-1); /* opts is NULL-terminated */
 
-	while((c = getopt_long(attrs->argc, (char*const*)attrs->argv, str_c(optbuf), array_idx(&opts, 0), &li)) > -1) {
+	while((c = getopt_long(argc, (char*const*)argv, str_c(optbuf), array_idx(&opts, 0), &li)) > -1) {
 		switch(c) {
 		case 0:
 			doveadm_fill_param(array_idx_modifiable(&pargv,li), optarg, pool);
@@ -451,17 +453,17 @@
 		}
 	}
 
-	cptr = cmd->name;
+	cptr = cctx->cmd->name;
 	while((cptr = strchr(cptr+1, ' ')) != NULL) optind++;
 
 	/* process positional arguments */
-	for(;optind<attrs->argc;optind++) {
+	for(;optind<cctx->argc;optind++) {
 		struct doveadm_cmd_param *ptr;
 		bool found = FALSE;
 		array_foreach_modifiable(&pargv, ptr) {
 			if ((ptr->flags & CMD_PARAM_FLAG_POSITIONAL) != 0 &&
 			    (ptr->value_set == FALSE || ptr->type == CMD_PARAM_ARRAY)) {
-				doveadm_fill_param(ptr, attrs->argv[optind], pool);
+				doveadm_fill_param(ptr, argv[optind], pool);
 				found = TRUE;
 				break;
 			}
@@ -473,9 +475,10 @@
 		}
 	}
 
-	param = array_get_modifiable(&pargv, &pargc);
+	cctx->argv = array_get_modifiable(&pargv, &pargc);
+	cctx->argc = pargc;
 
-	cmd->cmd(cmd, pargc, param);
+	cctx->cmd->cmd(cctx);
 
 	doveadm_cmd_params_clean(&pargv);
 	return 0;
--- a/src/doveadm/doveadm-cmd.h	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-cmd.h	Sun Feb 28 18:27:35 2016 +0200
@@ -8,6 +8,7 @@
 #define DOVEADM_CMD_PARAMS_END { .short_opt = '\0', .name = NULL, .type = CMD_PARAM_BOOL, .flags = CMD_PARAM_FLAG_NONE } }
 
 struct doveadm_cmd_ver2;
+struct doveadm_cmd_context;
 struct doveadm_mail_cmd_context;
 
 typedef void doveadm_command_t(int argc, char *argv[]);
@@ -49,8 +50,7 @@
 };
 ARRAY_DEFINE_TYPE(doveadm_cmd_param_arr_t, struct doveadm_cmd_param);
 
-typedef void doveadm_command_ver2_t(const struct doveadm_cmd_ver2* cmd,
-	int argc, const struct doveadm_cmd_param[]);
+typedef void doveadm_command_ver2_t(struct doveadm_cmd_context *cctx);
 
 struct doveadm_cmd {
 	doveadm_command_t *cmd;
@@ -68,11 +68,14 @@
 	const struct doveadm_cmd_param *parameters;
 };
 
-struct doveadm_cmd_attributes {
+struct doveadm_cmd_context {
+	const struct doveadm_cmd_ver2 *cmd; /* for help */
+
 	int argc;
-	const char **argv;
+	const struct doveadm_cmd_param *argv;
 
 	const char *username;
+	bool cli;
 	struct ip_addr local_ip, remote_ip;
 	in_port_t local_port, remote_port;
 };
@@ -110,10 +113,8 @@
 void doveadm_cmds_init(void);
 void doveadm_cmds_deinit(void);
 
-void doveadm_cmd_ver2_to_cmd_wrapper(const struct doveadm_cmd_ver2* cmd,
-	int argc, const struct doveadm_cmd_param[]);
-void doveadm_cmd_ver2_to_mail_cmd_wrapper(const struct doveadm_cmd_ver2* cmd,
-	int argc, const struct doveadm_cmd_param argv[]);
+void doveadm_cmd_ver2_to_cmd_wrapper(struct doveadm_cmd_context *cctx);
+void doveadm_cmd_ver2_to_mail_cmd_wrapper(struct doveadm_cmd_context *cctx);
 
 void doveadm_cmd_register_ver2(struct doveadm_cmd_ver2 *cmd);
 const struct doveadm_cmd_ver2 *
@@ -121,22 +122,23 @@
 const struct doveadm_cmd_ver2 *doveadm_cmd_find_ver2(const char *cmd_name);
 /* Returns FALSE if cmd_name doesn't exist, TRUE if it exists. */
 bool doveadm_cmd_try_run_ver2(const char *cmd_name,
-	const struct doveadm_cmd_attributes *attrs);
+	int argc, const char **argv,
+	struct doveadm_cmd_context *cctx);
 /* Returns 0 if success, -1 if parameters were invalid. */
-int doveadm_cmd_run_ver2(const struct doveadm_cmd_ver2 *cmd,
-	const struct doveadm_cmd_attributes *attrs);
+int doveadm_cmd_run_ver2(int argc, const char **argv,
+	struct doveadm_cmd_context *cctx);
 
-bool doveadm_cmd_param_bool(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
 			    const char *name, bool *value_r);
-bool doveadm_cmd_param_int64(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
 			     const char *name, int64_t *value_r);
-bool doveadm_cmd_param_str(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
 			   const char *name, const char **value_r);
-bool doveadm_cmd_param_ip(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
 			  const char *name, struct ip_addr *value_r);
-bool doveadm_cmd_param_array(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
 			     const char *name, ARRAY_TYPE(const_string) **value_r);
-bool doveadm_cmd_param_istream(int argc, const struct doveadm_cmd_param *params,
+bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
 			       const char *name, struct istream **value_r);
 
 void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv);
--- a/src/doveadm/doveadm-mail.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-mail.c	Sun Feb 28 18:27:35 2016 +0200
@@ -335,33 +335,33 @@
 }
 
 static void
-doveadm_attrs_to_storage_service_input(const struct doveadm_cmd_attributes *attrs,
+doveadm_cctx_to_storage_service_input(const struct doveadm_cmd_context *cctx,
 					struct mail_storage_service_input *input_r)
 {
 	memset(input_r, 0, sizeof(*input_r));
 	input_r->service = "doveadm";
-	input_r->remote_ip = attrs->remote_ip;
-	input_r->remote_port = attrs->remote_port;
-	input_r->local_ip = attrs->local_ip;
-	input_r->local_port = attrs->local_port;
-	input_r->username = attrs->username;
+	input_r->remote_ip = cctx->remote_ip;
+	input_r->remote_port = cctx->remote_port;
+	input_r->local_ip = cctx->local_ip;
+	input_r->local_port = cctx->local_port;
+	input_r->username = cctx->username;
 }
 
 static int
 doveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx,
-		       const struct doveadm_cmd_attributes *attrs,
+		       const struct doveadm_cmd_context *cctx,
 		       const char **error_r)
 {
 	struct mail_storage_service_input input;
 	const char *error, *ip;
 	int ret;
 
-	ip = net_ip2addr(&attrs->remote_ip);
+	ip = net_ip2addr(&cctx->remote_ip);
 	if (ip[0] == '\0')
-		i_set_failure_prefix("doveadm(%s): ", attrs->username);
+		i_set_failure_prefix("doveadm(%s): ", cctx->username);
 	else
-		i_set_failure_prefix("doveadm(%s,%s): ", ip, attrs->username);
-	doveadm_attrs_to_storage_service_input(attrs, &input);
+		i_set_failure_prefix("doveadm(%s,%s): ", ip, cctx->username);
+	doveadm_cctx_to_storage_service_input(cctx, &input);
 
 	/* see if we want to execute this command via (another)
 	   doveadm server */
@@ -411,14 +411,14 @@
 }
 
 int doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx,
-			     const struct doveadm_cmd_attributes *attrs,
+			     const struct doveadm_cmd_context *cctx,
 			     const char **error_r)
 {
-	i_assert(attrs->username != NULL);
+	i_assert(cctx->username != NULL);
 
-	doveadm_attrs_to_storage_service_input(attrs, &ctx->storage_service_input);
-	ctx->cur_client_ip = attrs->remote_ip;
-	ctx->cur_username = attrs->username;
+	doveadm_cctx_to_storage_service_input(cctx, &ctx->storage_service_input);
+	ctx->cur_client_ip = cctx->remote_ip;
+	ctx->cur_username = cctx->username;
 	ctx->storage_service = mail_storage_service_init(master_service, NULL,
 							 ctx->service_flags);
 	ctx->v.init(ctx, ctx->args);
@@ -428,23 +428,23 @@
 	lib_signals_set_handler(SIGINT, 0, sig_die, NULL);
 	lib_signals_set_handler(SIGTERM, 0, sig_die, NULL);
 
-	return doveadm_mail_next_user(ctx, attrs, error_r);
+	return doveadm_mail_next_user(ctx, cctx, error_r);
 }
 
 static void
 doveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx,
 		       const char *wildcard_user)
 {
-	struct doveadm_cmd_attributes attrs;
+	struct doveadm_cmd_context cctx;
 	unsigned int user_idx;
 	const char *ip, *user, *error;
 	int ret;
 
 	ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
 
-	memset(&attrs, 0, sizeof(attrs));
+	memset(&cctx, 0, sizeof(cctx));
 
-	doveadm_attrs_to_storage_service_input(&attrs, &ctx->storage_service_input);
+	doveadm_cctx_to_storage_service_input(&cctx, &ctx->storage_service_input);
 	ctx->storage_service = mail_storage_service_init(master_service, NULL,
 							 ctx->service_flags);
         lib_signals_set_handler(SIGINT, 0, sig_die, NULL);
@@ -463,11 +463,11 @@
 			if (!wildcard_match_icase(user, wildcard_user))
 				continue;
 		}
-		attrs.username = user;
+		cctx.username = user;
 		ctx->cur_username = user;
 		doveadm_print_sticky("username", user);
 		T_BEGIN {
-			ret = doveadm_mail_next_user(ctx, &attrs, &error);
+			ret = doveadm_mail_next_user(ctx, &cctx, &error);
 			if (ret < 0)
 				i_error("%s", error);
 			else if (ret == 0)
@@ -580,14 +580,14 @@
 	}
 
 	if (ctx->iterate_single_user) {
-		struct doveadm_cmd_attributes attrs;
+		struct doveadm_cmd_context cctx;
 
 		if (ctx->cur_username == NULL)
 			i_fatal_status(EX_USAGE, "USER environment is missing and -u option not used");
 
-		memset(&attrs, 0, sizeof(attrs));
-		attrs.username = ctx->cur_username;
-		ret = doveadm_mail_single_user(ctx, &attrs, &error);
+		memset(&cctx, 0, sizeof(cctx));
+		cctx.username = ctx->cur_username;
+		ret = doveadm_mail_single_user(ctx, &cctx, &error);
 		if (ret < 0) {
 			/* user lookup/init failed somehow */
 			doveadm_exit_code = EX_TEMPFAIL;
@@ -915,8 +915,7 @@
 }
 
 void
-doveadm_cmd_ver2_to_mail_cmd_wrapper(const struct doveadm_cmd_ver2* cmd,
-	int argc, const struct doveadm_cmd_param argv[])
+doveadm_cmd_ver2_to_mail_cmd_wrapper(struct doveadm_cmd_context *cctx)
 {
 	struct doveadm_mail_cmd_context *ctx;
 	const char *wildcard_user;
@@ -925,7 +924,7 @@
 	ARRAY_TYPE(const_string) pargv;
 	int i;
 	struct doveadm_mail_cmd mail_cmd = {
-		cmd->mail_cmd, cmd->name, cmd->usage
+		cctx->cmd->mail_cmd, cctx->cmd->name, cctx->cmd->usage
 	};
 
 	ctx = doveadm_mail_cmdline_init(&mail_cmd);
@@ -934,8 +933,8 @@
 	wildcard_user = NULL;
 	p_array_init(&pargv, ctx->pool, 8);
 
-	for(i=0;i<argc;i++) {
-		const struct doveadm_cmd_param *arg = &argv[i];
+	for(i=0;i<cctx->argc;i++) {
+		const struct doveadm_cmd_param *arg = &cctx->argv[i];
 
 		if (!arg->value_set)
 			continue;
--- a/src/doveadm/doveadm-mail.h	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-mail.h	Sun Feb 28 18:27:35 2016 +0200
@@ -134,7 +134,7 @@
 doveadm_mail_cmd_init(const struct doveadm_mail_cmd *cmd,
 		      const struct doveadm_settings *set);
 int doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx,
-			     const struct doveadm_cmd_attributes *attrs,
+			     const struct doveadm_cmd_context *cctx,
 			     const char **error_r);
 int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
 			     const struct mail_storage_service_input *input,
--- a/src/doveadm/doveadm-penalty.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-penalty.c	Sun Feb 28 18:27:35 2016 +0200
@@ -86,16 +86,16 @@
 	i_stream_destroy(&input);
 }
 
-static void cmd_penalty(const struct doveadm_cmd_ver2 *cmd ATTR_UNUSED, int argc, const struct doveadm_cmd_param *argv)
+static void cmd_penalty(struct doveadm_cmd_context *cctx)
 {
 	struct penalty_context ctx;
 	const char *netmask;
 
 	memset(&ctx, 0, sizeof(ctx));
-	if (!doveadm_cmd_param_str(argc, argv, "socket-path", &(ctx.anvil_path)))
+	if (!doveadm_cmd_param_str(cctx, "socket-path", &(ctx.anvil_path)))
 		ctx.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
 
-	if (doveadm_cmd_param_str(argc, argv, "netmask", &netmask)) {
+	if (doveadm_cmd_param_str(cctx, "netmask", &netmask)) {
 		if (net_parse_range(netmask, &ctx.net_ip, &ctx.net_bits) != 0) {
 			doveadm_exit_code = EX_USAGE;
 			i_error("Invalid netmask '%s' given", netmask);
--- a/src/doveadm/doveadm-stats.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm-stats.c	Sun Feb 28 18:27:35 2016 +0200
@@ -116,23 +116,23 @@
 }
 
 static void
-cmd2_stats_dump(const struct doveadm_cmd_ver2* dcmd ATTR_UNUSED, int argc, const struct doveadm_cmd_param *argv)
+doveadm_cmd_stats_dump(struct doveadm_cmd_context* cctx)
 {
 	const char *path, *cmd;
 	const char *args[3] = {0};
 
-	if (!doveadm_cmd_param_str(argc, argv, "socket-path", &path))
+	if (!doveadm_cmd_param_str(cctx, "socket-path", &path))
 		path = t_strconcat(doveadm_settings->base_dir, "/stats", NULL);
 
-	if (!doveadm_cmd_param_str(argc, argv, "type", &args[0])) {
+	if (!doveadm_cmd_param_str(cctx, "type", &args[0])) {
 		i_error("Missing type parameter");
 		doveadm_exit_code = EX_USAGE;
 		return;
 	}
 
 	/* purely optional */
-	doveadm_cmd_param_str(argc, argv, "filter", &args[1]);
-	args[2] = NULL;
+	if (!doveadm_cmd_param_str(cctx, "filter", &args[1]))
+		args[1] = NULL;
 
 	cmd = t_strdup_printf("EXPORT\t%s\n", t_strarray_join(args, "\t"));
 
@@ -598,7 +598,7 @@
 }
 
 struct doveadm_cmd_ver2 doveadm_cmd_stats_dump_ver2 = {
-	.cmd = cmd2_stats_dump,
+	.cmd = doveadm_cmd_stats_dump,
 	.name = "stats dump",
 	.usage = "[-s <stats socket path>] <type> [<filter>]",
 DOVEADM_CMD_PARAMS_START
--- a/src/doveadm/doveadm.c	Sun Feb 28 18:25:31 2016 +0200
+++ b/src/doveadm/doveadm.c	Sun Feb 28 18:27:35 2016 +0200
@@ -283,12 +283,15 @@
 	enum master_service_flags service_flags =
 		MASTER_SERVICE_FLAG_STANDALONE |
 		MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
-	struct doveadm_cmd_attributes attrs;
+	struct doveadm_cmd_context cctx;
 	const char *cmd_name;
 	unsigned int i;
 	bool quick_init = FALSE;
 	int c;
 
+	memset(&cctx,0,sizeof(cctx));
+	cctx.cli = TRUE;
+
 	i_set_failure_exit_callback(failure_exit_callback);
 	doveadm_dsync_main(&argc, &argv);
 
@@ -365,11 +368,7 @@
 		i_set_debug_file("/dev/null");
 	}
 
-	memset(&attrs, 0, sizeof(attrs));
-	attrs.argc = argc;
-	attrs.argv = (const char **)argv;
-
-	if (!doveadm_cmd_try_run_ver2(cmd_name, &attrs) &&
+	if (!doveadm_cmd_try_run_ver2(cmd_name, argc, (const char**)argv, &cctx) &&
 	    !doveadm_try_run(cmd_name, argc, (const char **)argv) &&
 	    !doveadm_mail_try_run(cmd_name, argc, argv)) {
 		if (doveadm_has_subcommands(cmd_name))