changeset 11063:dbc864c0cff7 HEAD

lib-imap: Changed imap_arg accessing APIs. The new one is easier for both coders and static analyzers.
author Timo Sirainen <tss@iki.fi>
date Mon, 05 Apr 2010 07:54:55 +0300
parents 314f230b3a00
children 1786d44bf90f
files src/imap-login/client-authenticate.c src/imap-login/client.c src/imap/cmd-append.c src/imap/cmd-cancelupdate.c src/imap/cmd-enable.c src/imap/cmd-expunge.c src/imap/cmd-fetch.c src/imap/cmd-list.c src/imap/cmd-search.c src/imap/cmd-select.c src/imap/cmd-sort.c src/imap/cmd-status.c src/imap/cmd-store.c src/imap/cmd-thread.c src/imap/imap-client.c src/imap/imap-commands-util.c src/imap/imap-fetch-body.c src/imap/imap-search-args.c src/imap/imap-search.c src/imap/imap-status.c src/lib-imap/Makefile.am src/lib-imap/imap-arg.c src/lib-imap/imap-arg.h src/lib-imap/imap-bodystructure.c src/lib-imap/imap-envelope.c src/lib-imap/imap-id.c src/lib-imap/imap-parser.c src/lib-imap/imap-parser.h src/lib-imap/imap-util.c src/lib-storage/mail-search-build.c src/plugins/imap-quota/imap-quota-plugin.c src/plugins/imap-zlib/imap-zlib-plugin.c
diffstat 32 files changed, 613 insertions(+), 569 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap-login/client-authenticate.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap-login/client-authenticate.c	Mon Apr 05 07:54:55 2010 +0300
@@ -125,22 +125,18 @@
 int cmd_authenticate(struct imap_client *imap_client,
 		     const struct imap_arg *args)
 {
-	const char *mech_name, *init_resp = NULL;
+	const char *mech_name, *init_resp;
 
-	/* we want only one argument: authentication mechanism name */
-	if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
+	/* <auth mechanism name> [<initial SASL response>] */
+	if (!imap_arg_get_atom(&args[0], &mech_name) || *mech_name == '\0')
 		return -1;
-	if (args[1].type != IMAP_ARG_EOL) {
-		/* optional SASL initial response */
-		if (args[1].type != IMAP_ARG_ATOM ||
-		    args[2].type != IMAP_ARG_EOL)
-			return -1;
-		init_resp = IMAP_ARG_STR(&args[1]);
-	}
+	if (imap_arg_get_atom(&args[1], &init_resp))
+		args++;
+	else
+		init_resp = NULL;
+	if (!IMAP_ARG_IS_EOL(&args[1]))
+		return -1;
 
-	mech_name = IMAP_ARG_STR(&args[0]);
-	if (*mech_name == '\0')
-		return -1;
 	return imap_client_auth_begin(imap_client, mech_name, init_resp);
 }
 
@@ -151,15 +147,10 @@
 	string_t *plain_login, *base64;
 
 	/* two arguments: username and password */
-	if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
-		return -1;
-	if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
+	if (!imap_arg_get_astring(&args[0], &user) ||
+	    !imap_arg_get_astring(&args[1], &pass) ||
+	    !IMAP_ARG_IS_EOL(&args[2]))
 		return -1;
-	if (args[2].type != IMAP_ARG_EOL)
-		return -1;
-
-	user = IMAP_ARG_STR(&args[0]);
-	pass = IMAP_ARG_STR(&args[1]);
 
 	if (!client_check_plaintext_auth(client, TRUE))
 		return 1;
--- a/src/imap-login/client.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap-login/client.c	Mon Apr 05 07:54:55 2010 +0300
@@ -97,14 +97,11 @@
 {
 	const char *key, *value;
 
-	if (args->type != IMAP_ARG_LIST)
+	if (!imap_arg_get_list(args, &args))
 		return;
-	args = IMAP_ARG_LIST_ARGS(args);
 
-	while (args->type == IMAP_ARG_STRING &&
-	       args[1].type == IMAP_ARG_STRING) {
-		key = IMAP_ARG_STR_NONULL(&args[0]);
-		value = IMAP_ARG_STR_NONULL(&args[1]);
+	while (imap_arg_get_string(&args[0], &key) &&
+	       imap_arg_get_nstring(&args[1], &value)) {
 		if (strcasecmp(key, "x-originating-ip") == 0)
 			(void)net_addr2ip(value, &client->common.ip);
 		else if (strcasecmp(key, "x-originating-port") == 0)
--- a/src/imap/cmd-append.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-append.c	Mon Apr 05 07:54:55 2010 +0300
@@ -103,29 +103,25 @@
 			 bool *nonsync_r)
 {
 	/* [<flags>] */
-	if (args->type != IMAP_ARG_LIST)
+	if (!imap_arg_get_list(args, flags_r))
 		*flags_r = NULL;
-	else {
-		*flags_r = IMAP_ARG_LIST_ARGS(args);
+	else
 		args++;
-	}
 
 	/* [<internal date>] */
 	if (args->type != IMAP_ARG_STRING)
 		*internal_date_r = NULL;
 	else {
-		*internal_date_r = IMAP_ARG_STR(args);
+		*internal_date_r = imap_arg_as_astring(args);
 		args++;
 	}
 
-	if (args->type != IMAP_ARG_LITERAL_SIZE &&
-	    args->type != IMAP_ARG_LITERAL_SIZE_NONSYNC) {
+	if (!imap_arg_get_literal_size(args, msg_size_r)) {
 		*nonsync_r = FALSE;
 		return FALSE;
 	}
 
 	*nonsync_r = args->type == IMAP_ARG_LITERAL_SIZE_NONSYNC;
-	*msg_size_r = IMAP_ARG_LITERAL_SIZE(args);
 	return TRUE;
 }
 
@@ -241,7 +237,7 @@
 		return FALSE;
 	}
 
-	if (args->type == IMAP_ARG_EOL) {
+	if (IMAP_ARG_IS_EOL(args)) {
 		/* last message */
 		enum mailbox_sync_flags sync_flags;
 		enum imap_sync_flags imap_flags;
--- a/src/imap/cmd-cancelupdate.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-cancelupdate.c	Mon Apr 05 07:54:55 2010 +0300
@@ -21,23 +21,24 @@
 bool cmd_cancelupdate(struct client_command_context *cmd)
 {
 	const struct imap_arg *args;
-	const char *str;
+	const char *tag;
 	unsigned int i;
 
 	if (!client_read_args(cmd, 0, 0, &args))
 		return FALSE;
 
 	for (i = 0; args[i].type == IMAP_ARG_STRING; i++) ;
-	if (args[i].type != IMAP_ARG_EOL || i == 0) {
+	if (!IMAP_ARG_IS_EOL(&args[i]) || i == 0) {
 		client_send_tagline(cmd, "BAD Invalid parameters.");
 		return TRUE;
 	}
-	for (i = 0; args[i].type == IMAP_ARG_STRING; i++) {
-		str = IMAP_ARG_STR_NONULL(&args[i]);
-		if (!client_search_update_cancel(cmd->client, str)) {
+
+	while (imap_arg_get_quoted(args, &tag)) {
+		if (!client_search_update_cancel(cmd->client, tag)) {
 			client_send_tagline(cmd, "BAD Unknown tag.");
 			return TRUE;
 		}
+		args++;
 	}
 	client_send_tagline(cmd, "OK Updates cancelled.");
 	return TRUE;
--- a/src/imap/cmd-enable.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-enable.c	Mon Apr 05 07:54:55 2010 +0300
@@ -14,12 +14,12 @@
 
 	reply = t_str_new(64);
 	str_append(reply, "* ENABLED");
-	for (; args->type != IMAP_ARG_EOL; args++) {
-		if (args->type != IMAP_ARG_ATOM) {
+	for (; !IMAP_ARG_IS_EOL(args); args++) {
+		if (!imap_arg_get_atom(args, &str)) {
 			client_send_command_error(cmd, "Invalid arguments.");
 			return TRUE;
 		}
-		str = t_str_ucase(IMAP_ARG_STR(args));
+		str = t_str_ucase(str);
 		if (strcmp(str, "CONDSTORE") == 0) {
 			client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE);
 			str_append(reply, " CONDSTORE");
--- a/src/imap/cmd-expunge.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-expunge.c	Mon Apr 05 07:54:55 2010 +0300
@@ -58,8 +58,7 @@
 	if (!client_verify_open_mailbox(cmd))
 		return TRUE;
 
-	uidset = imap_arg_string(&args[0]);
-	if (uidset == NULL) {
+	if (!imap_arg_get_astring(&args[0], &uidset)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
--- a/src/imap/cmd-fetch.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-fetch.c	Mon Apr 05 07:54:55 2010 +0300
@@ -30,8 +30,8 @@
 		if (!imap_fetch_init_handler(ctx, "UID", &arg))
 			return FALSE;
 	}
-	if (arg->type == IMAP_ARG_ATOM) {
-		str = t_str_ucase(IMAP_ARG_STR(arg));
+	if (imap_arg_get_atom(arg, &str)) {
+		str = t_str_ucase(str);
 		arg++;
 
 		/* handle macros first */
@@ -56,14 +56,14 @@
 		*next_arg_r = arg;
 	} else {
 		*next_arg_r = arg + 1;
-		arg = IMAP_ARG_LIST_ARGS(arg);
-		while (arg->type == IMAP_ARG_ATOM) {
-			str = t_str_ucase(IMAP_ARG_STR(arg));
+		arg = imap_arg_as_list(arg);
+		while (imap_arg_get_atom(arg, &str)) {
+			str = t_str_ucase(str);
 			arg++;
 			if (!imap_fetch_init_handler(ctx, str, &arg))
 				return FALSE;
 		}
-		if (arg->type != IMAP_ARG_EOL) {
+		if (!IMAP_ARG_IS_EOL(arg)) {
 			client_send_command_error(ctx->cmd,
 				"FETCH list contains non-atoms.");
 			return FALSE;
@@ -76,15 +76,16 @@
 fetch_parse_modifier(struct imap_fetch_context *ctx,
 		     const char *name, const struct imap_arg **args)
 {
+	const char *str;
 	unsigned long long num;
 
 	if (strcmp(name, "CHANGEDSINCE") == 0) {
-		if ((*args)->type != IMAP_ARG_ATOM) {
+		if (!imap_arg_get_atom(*args, &str)) {
 			client_send_command_error(ctx->cmd,
 				"Invalid CHANGEDSINCE modseq.");
 			return FALSE;
 		}
-		num = strtoull(imap_arg_string(*args), NULL, 10);
+		num = strtoull(str, NULL, 10);
 		*args += 1;
 		return imap_fetch_add_changed_since(ctx, num);
 	}
@@ -109,15 +110,14 @@
 {
 	const char *name;
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &name)) {
 			client_send_command_error(ctx->cmd,
 				"FETCH modifiers contain non-atoms.");
 			return FALSE;
 		}
-		name = t_str_ucase(IMAP_ARG_STR(args));
 		args++;
-		if (!fetch_parse_modifier(ctx, name, &args))
+		if (!fetch_parse_modifier(ctx, t_str_ucase(name), &args))
 			return FALSE;
 	}
 	if (ctx->send_vanished &&
@@ -184,7 +184,7 @@
 {
 	struct client *client = cmd->client;
 	struct imap_fetch_context *ctx;
-	const struct imap_arg *args, *next_arg;
+	const struct imap_arg *args, *next_arg, *list_arg;
 	struct mail_search_args *search_args;
 	const char *messageset;
 	int ret;
@@ -196,10 +196,9 @@
 		return TRUE;
 
 	/* <messageset> <field(s)> [(modifiers)] */
-	messageset = imap_arg_string(&args[0]);
-	if (messageset == NULL ||
+	if (!imap_arg_get_atom(&args[0], &messageset) ||
 	    (args[1].type != IMAP_ARG_LIST && args[1].type != IMAP_ARG_ATOM) ||
-	    (args[2].type != IMAP_ARG_EOL && args[2].type != IMAP_ARG_LIST)) {
+	    (!IMAP_ARG_IS_EOL(&args[2]) && args[2].type != IMAP_ARG_LIST)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
@@ -218,8 +217,8 @@
 	ctx->search_args = search_args;
 
 	if (!fetch_parse_args(ctx, &args[1], &next_arg) ||
-	    (next_arg->type == IMAP_ARG_LIST &&
-	     !fetch_parse_modifiers(ctx, IMAP_ARG_LIST_ARGS(next_arg)))) {
+	    (imap_arg_get_list(next_arg, &list_arg) &&
+	     !fetch_parse_modifiers(ctx, list_arg))) {
 		imap_fetch_deinit(ctx);
 		return TRUE;
 	}
--- a/src/imap/cmd-list.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-list.c	Mon Apr 05 07:54:55 2010 +0300
@@ -93,23 +93,21 @@
 parse_select_flags(struct cmd_list_context *ctx, const struct imap_arg *args)
 {
 	enum mailbox_list_iter_flags list_flags = 0;
-	const char *atom;
+	const char *str;
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &str)) {
 			client_send_command_error(ctx->cmd,
 				"List options contains non-atoms.");
 			return FALSE;
 		}
 
-		atom = IMAP_ARG_STR(args);
-
-		if (strcasecmp(atom, "SUBSCRIBED") == 0) {
+		if (strcasecmp(str, "SUBSCRIBED") == 0) {
 			list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 				MAILBOX_LIST_ITER_RETURN_SUBSCRIBED;
-		} else if (strcasecmp(atom, "RECURSIVEMATCH") == 0)
+		} else if (strcasecmp(str, "RECURSIVEMATCH") == 0)
 			list_flags |= MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH;
-		else if (strcasecmp(atom, "REMOTE") == 0) {
+		else if (strcasecmp(str, "REMOTE") == 0) {
 			/* not supported, ignore */
 		} else {
 			/* skip also optional list value */
@@ -135,26 +133,24 @@
 parse_return_flags(struct cmd_list_context *ctx, const struct imap_arg *args)
 {
 	enum mailbox_list_iter_flags list_flags = 0;
-	const char *atom;
+	const struct imap_arg *list_args;
+	const char *str;
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &str)) {
 			client_send_command_error(ctx->cmd,
 				"List options contains non-atoms.");
 			return FALSE;
 		}
 
-		atom = IMAP_ARG_STR(args);
-
-		if (strcasecmp(atom, "SUBSCRIBED") == 0)
+		if (strcasecmp(str, "SUBSCRIBED") == 0)
 			list_flags |= MAILBOX_LIST_ITER_RETURN_SUBSCRIBED;
-		else if (strcasecmp(atom, "CHILDREN") == 0)
+		else if (strcasecmp(str, "CHILDREN") == 0)
 			list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
-		else if (strcasecmp(atom, "STATUS") == 0 &&
-			 args[1].type == IMAP_ARG_LIST) {
-			if (imap_status_parse_items(ctx->cmd,
-						IMAP_ARG_LIST_ARGS(&args[1]),
-						&ctx->status_items) < 0)
+		else if (strcasecmp(str, "STATUS") == 0 &&
+			 imap_arg_get_list(&args[1], &list_args)) {
+			if (imap_status_parse_items(ctx->cmd, list_args,
+						    &ctx->status_items) < 0)
 				return FALSE;
 			ctx->used_status = TRUE;
 			args++;
@@ -837,7 +833,8 @@
 bool cmd_list_full(struct client_command_context *cmd, bool lsub)
 {
 	struct client *client = cmd->client;
-	const struct imap_arg *args, *arg;
+	const struct imap_arg *args, *list_args;
+	unsigned int arg_count;
         struct cmd_list_context *ctx;
 	ARRAY_DEFINE(patterns, const char *) = ARRAY_INIT;
 	const char *pattern, *const *patterns_strarr;
@@ -854,40 +851,33 @@
 
 	cmd->context = ctx;
 
-	if (args[0].type == IMAP_ARG_LIST && !lsub) {
+	if (!lsub && imap_arg_get_list(&args[0], &list_args)) {
 		/* LIST-EXTENDED selection options */
 		ctx->used_listext = TRUE;
-		if (!parse_select_flags(ctx, IMAP_ARG_LIST_ARGS(&args[0])))
+		if (!parse_select_flags(ctx, list_args))
 			return TRUE;
 		args++;
 	}
 
-	ctx->ref = imap_arg_string(&args[0]);
-	if (ctx->ref == NULL) {
-		/* broken */
+	if (!imap_arg_get_astring(&args[0], &ctx->ref)) {
 		client_send_command_error(cmd, "Invalid reference.");
 		return TRUE;
 	}
-	if (args[1].type == IMAP_ARG_LIST) {
+	if (imap_arg_get_list_full(&args[1], &list_args, &arg_count)) {
 		ctx->used_listext = TRUE;
 		/* convert pattern list to string array */
-		p_array_init(&patterns, cmd->pool,
-			     IMAP_ARG_LIST_COUNT(&args[1]));
-		arg = IMAP_ARG_LIST_ARGS(&args[1]);
-		for (; arg->type != IMAP_ARG_EOL; arg++) {
-			if (!IMAP_ARG_TYPE_IS_STRING(arg->type)) {
-				/* broken */
+		p_array_init(&patterns, cmd->pool, arg_count);
+		for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
+			if (!imap_arg_get_astring(list_args, &pattern)) {
 				client_send_command_error(cmd,
 					"Invalid pattern list.");
 				return TRUE;
 			}
-			pattern = imap_arg_string(arg);
 			array_append(&patterns, &pattern, 1);
 		}
 		args += 2;
 	} else {
-		pattern = imap_arg_string(&args[1]);
-		if (pattern == NULL) {
+		if (!imap_arg_get_astring(&args[1], &pattern)) {
 			client_send_command_error(cmd, "Invalid pattern.");
 			return TRUE;
 		}
@@ -903,11 +893,11 @@
 		}
 	}
 
-	if (args[0].type == IMAP_ARG_ATOM && args[1].type == IMAP_ARG_LIST &&
-	    strcasecmp(imap_arg_string(&args[0]), "RETURN") == 0) {
+	if (imap_arg_atom_equals(&args[0], "RETURN") &&
+	    imap_arg_get_list(&args[1], &list_args)) {
 		/* LIST-EXTENDED return options */
 		ctx->used_listext = TRUE;
-		if (!parse_return_flags(ctx, IMAP_ARG_LIST_ARGS(&args[1])))
+		if (!parse_return_flags(ctx, list_args))
 			return TRUE;
 		args += 2;
 	}
@@ -923,7 +913,7 @@
 		ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
 	}
 
-	if (args[0].type != IMAP_ARG_EOL) {
+	if (!IMAP_ARG_IS_EOL(args)) {
 		client_send_command_error(cmd, "Extra arguments.");
 		return TRUE;
 	}
--- a/src/imap/cmd-search.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-search.c	Mon Apr 05 07:54:55 2010 +0300
@@ -26,19 +26,14 @@
 		return ret < 0;
 	}
 
-	if (args->type == IMAP_ARG_ATOM &&
-	    strcasecmp(IMAP_ARG_STR_NONULL(args), "CHARSET") == 0) {
+	if (imap_arg_atom_equals(args, "CHARSET")) {
 		/* CHARSET specified */
-		args++;
-		if (args->type != IMAP_ARG_ATOM &&
-		    args->type != IMAP_ARG_STRING) {
+		if (!imap_arg_get_astring(&args[1], &charset)) {
 			client_send_command_error(cmd,
-						  "Invalid charset argument.");
+				"Invalid charset argument.");
 			return TRUE;
 		}
-
-		charset = IMAP_ARG_STR(args);
-		args++;
+		args += 2;
 	} else {
 		charset = "UTF-8";
 	}
--- a/src/imap/cmd-select.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-select.c	Mon Apr 05 07:54:55 2010 +0300
@@ -65,10 +65,48 @@
 }
 
 static bool
+select_parse_qresync_known_set(struct imap_select_context *ctx,
+			       const struct imap_arg *args)
+{
+	ARRAY_TYPE(seq_range) seqset, uidset;
+	const char *str;
+
+	t_array_init(&seqset, 32);
+	if (!imap_arg_get_atom(args, &str) ||
+	    imap_seq_set_parse(str, &seqset) < 0) {
+		client_send_command_error(ctx->cmd,
+			"Invalid QRESYNC known-sequence-set");
+		return FALSE;
+	}
+	args++;
+
+	t_array_init(&uidset, 32);
+	if (!imap_arg_get_atom(args, &str) ||
+	    imap_seq_set_parse(str, &uidset) < 0) {
+		client_send_command_error(ctx->cmd,
+			"Invalid QRESYNC known-uid-set");
+		return FALSE;
+	}
+	args++;
+
+	if (select_qresync_get_uids(ctx, &seqset, &uidset) < 0) {
+		client_send_command_error(ctx->cmd, "Invalid QRESYNC sets");
+		return FALSE;
+	}
+	if (!IMAP_ARG_IS_EOL(args)) {
+		client_send_command_error(ctx->cmd,
+			"Too many parameters to QRESYNC known set");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static bool
 select_parse_qresync(struct imap_select_context *ctx,
 		     const struct imap_arg *args)
 {
-	ARRAY_TYPE(seq_range) seqset, uidset;
+	const struct imap_arg *list_args;
+	const char *arg1, *arg2;
 	unsigned int count;
 
 	if ((ctx->cmd->client->enabled_features &
@@ -76,68 +114,44 @@
 		client_send_command_error(ctx->cmd, "QRESYNC not enabled");
 		return FALSE;
 	}
-	if (args->type != IMAP_ARG_LIST) {
+	if (!imap_arg_get_list_full(args, &args, &count)) {
 		client_send_command_error(ctx->cmd,
 					  "QRESYNC parameters missing");
 		return FALSE;
 	}
-	args = IMAP_ARG_LIST_ARGS(args);
-	for (count = 0; args[count].type != IMAP_ARG_EOL; count++) ;
 
-	if (count < 2 || count > 4 ||
-	    args[0].type != IMAP_ARG_ATOM ||
-	    args[1].type != IMAP_ARG_ATOM ||
-	    (count > 2 && args[2].type != IMAP_ARG_ATOM) ||
-	    (count > 3 && args[3].type != IMAP_ARG_LIST)) {
+	if (!imap_arg_get_atom(&args[0], &arg1) ||
+	    !imap_arg_get_atom(&args[1], &arg2)) {
 		client_send_command_error(ctx->cmd,
 					  "Invalid QRESYNC parameters");
 		return FALSE;
 	}
-	ctx->qresync_uid_validity =
-		strtoul(IMAP_ARG_STR_NONULL(&args[0]), NULL, 10);
-	ctx->qresync_modseq =
-		strtoull(IMAP_ARG_STR_NONULL(&args[1]), NULL, 10);
-	if (count > 2) {
+	args += 2;
+	ctx->qresync_uid_validity = strtoul(arg1, NULL, 10);
+	ctx->qresync_modseq = strtoull(arg2, NULL, 10);
+
+	if (!imap_arg_get_atom(args, &arg1)) {
 		i_array_init(&ctx->qresync_known_uids, 64);
-		if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[2]),
-				       &ctx->qresync_known_uids) < 0) {
+		seq_range_array_add_range(&ctx->qresync_known_uids,
+					  1, (uint32_t)-1);
+	} else {
+		i_array_init(&ctx->qresync_known_uids, 64);
+		if (imap_seq_set_parse(arg1, &ctx->qresync_known_uids) < 0) {
 			client_send_command_error(ctx->cmd,
 						  "Invalid QRESYNC known-uids");
 			return FALSE;
 		}
-	} else {
-		i_array_init(&ctx->qresync_known_uids, 64);
-		seq_range_array_add_range(&ctx->qresync_known_uids,
-					  1, (uint32_t)-1);
-	}
-	if (count > 3) {
-		args = IMAP_ARG_LIST_ARGS(&args[3]);
-		if (args[0].type != IMAP_ARG_ATOM ||
-		    args[1].type != IMAP_ARG_ATOM ||
-		    args[2].type != IMAP_ARG_EOL) {
-			client_send_command_error(ctx->cmd,
-				"Invalid QRESYNC known set parameters");
-			return FALSE;
+		args++;
+		if (imap_arg_get_list(args, &list_args)) {
+			if (!select_parse_qresync_known_set(ctx, list_args))
+				return FALSE;
+			args++;
 		}
-		t_array_init(&seqset, 32);
-		if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[0]),
-				       &seqset) < 0) {
-			client_send_command_error(ctx->cmd,
-				"Invalid QRESYNC known-sequence-set");
-			return FALSE;
-		}
-		t_array_init(&uidset, 32);
-		if (imap_seq_set_parse(IMAP_ARG_STR_NONULL(&args[1]),
-				       &uidset) < 0) {
-			client_send_command_error(ctx->cmd,
-				"Invalid QRESYNC known-uid-set");
-			return FALSE;
-		}
-		if (select_qresync_get_uids(ctx, &seqset, &uidset) < 0) {
-			client_send_command_error(ctx->cmd,
-				"Invalid QRESYNC sets");
-			return FALSE;
-		}
+	}
+	if (!IMAP_ARG_IS_EOL(args)) {
+		client_send_command_error(ctx->cmd,
+					  "Invalid QRESYNC parameters");
+		return FALSE;
 	}
 	return TRUE;
 }
@@ -148,13 +162,13 @@
 {
 	const char *name;
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &name)) {
 			client_send_command_error(ctx->cmd,
 				"SELECT options contain non-atoms.");
 			return FALSE;
 		}
-		name = t_str_ucase(IMAP_ARG_STR(args));
+		name = t_str_ucase(name);
 		args++;
 
 		if (strcmp(name, "CONDSTORE") == 0)
@@ -340,7 +354,7 @@
 	struct client *client = cmd->client;
 	struct mailbox *box;
 	struct imap_select_context *ctx;
-	const struct imap_arg *args;
+	const struct imap_arg *args, *list_args;
 	enum mailbox_name_status status;
 	const char *mailbox, *storage_name;
 	int ret;
@@ -349,11 +363,10 @@
 	if (!client_read_args(cmd, 0, 0, &args))
 		return FALSE;
 
-	if (!IMAP_ARG_TYPE_IS_STRING(args[0].type)) {
+	if (!imap_arg_get_astring(args, &mailbox)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return FALSE;
 	}
-	mailbox = IMAP_ARG_STR(&args[0]);
 
 	ctx = p_new(cmd->pool, struct imap_select_context, 1);
 	ctx->cmd = cmd;
@@ -373,8 +386,8 @@
 		return TRUE;
 	}
 
-	if (args[1].type == IMAP_ARG_LIST) {
-		if (!select_parse_options(ctx, IMAP_ARG_LIST_ARGS(&args[1]))) {
+	if (imap_arg_get_list(&args[1], &list_args)) {
+		if (!select_parse_options(ctx, list_args)) {
 			select_context_free(ctx);
 			return TRUE;
 		}
--- a/src/imap/cmd-sort.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-sort.c	Mon Apr 05 07:54:55 2010 +0300
@@ -32,20 +32,18 @@
 		 enum mail_sort_type program[MAX_SORT_PROGRAM_SIZE])
 {
 	enum mail_sort_type mask = 0;
+	const char *arg;
 	unsigned int i, pos;
 	bool reverse, last_reverse;
 
-	if (args->type == IMAP_ARG_EOL) {
+	if (IMAP_ARG_IS_EOL(args)) {
 		/* empyty list */
 		client_send_command_error(cmd, "Empty sort program.");
 		return -1;
 	}
 
 	pos = 0; reverse = last_reverse = FALSE;
-	for (; args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING;
-	     args++) {
-		const char *arg = IMAP_ARG_STR(args);
-
+	for (; imap_arg_get_astring(args, &arg); args++) {
 		last_reverse = strcasecmp(arg, "reverse") == 0;
 		if (last_reverse) {
 			reverse = !reverse;
@@ -80,7 +78,7 @@
 	}
 	program[pos] = MAIL_SORT_END;
 
-	if (args->type != IMAP_ARG_EOL) {
+	if (!IMAP_ARG_IS_EOL(args)) {
 		client_send_command_error(cmd,
 					  "Invalid sort list argument.");
 		return -1;
@@ -94,7 +92,7 @@
 	struct imap_search_context *ctx;
 	struct mail_search_args *sargs;
 	enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
-	const struct imap_arg *args;
+	const struct imap_arg *args, *list_args;
 	const char *charset;
 	int ret;
 
@@ -113,22 +111,20 @@
 	}
 
 	/* sort program */
-	if (args->type != IMAP_ARG_LIST) {
+	if (!imap_arg_get_list(args, &list_args)) {
 		client_send_command_error(cmd, "Invalid sort argument.");
 		return TRUE;
 	}
 
-	if (get_sort_program(cmd, IMAP_ARG_LIST_ARGS(args), sort_program) < 0)
+	if (get_sort_program(cmd, list_args, sort_program) < 0)
 		return TRUE;
 	args++;
 
 	/* charset */
-	if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
-		client_send_command_error(cmd,
-					  "Invalid charset argument.");
+	if (!imap_arg_get_astring(args, &charset)) {
+		client_send_command_error(cmd, "Invalid charset argument.");
 		return TRUE;
 	}
-	charset = IMAP_ARG_STR(args);
 	args++;
 
 	ret = imap_search_args_build(cmd, args, charset, &sargs);
--- a/src/imap/cmd-status.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-status.c	Mon Apr 05 07:54:55 2010 +0300
@@ -10,7 +10,7 @@
 {
 	struct client *client = cmd->client;
 	enum mailbox_name_status status;
-	const struct imap_arg *args;
+	const struct imap_arg *args, *list_args;
 	struct imap_status_items items;
 	struct imap_status_result result;
 	struct mail_namespace *ns;
@@ -21,15 +21,14 @@
 	if (!client_read_args(cmd, 2, 0, &args))
 		return FALSE;
 
-	mailbox = imap_arg_string(&args[0]);
-	if (mailbox == NULL || args[1].type != IMAP_ARG_LIST) {
-		client_send_command_error(cmd, "Status items must be list.");
+	if (!imap_arg_get_astring(&args[0], &mailbox) ||
+	    !imap_arg_get_list(&args[1], &list_args)) {
+		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
 
 	/* get the items client wants */
-	if (imap_status_parse_items(cmd, IMAP_ARG_LIST_ARGS(&args[1]),
-				    &items) < 0)
+	if (imap_status_parse_items(cmd, list_args, &items) < 0)
 		return TRUE;
 
 	ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
--- a/src/imap/cmd-store.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-store.c	Mon Apr 05 07:54:55 2010 +0300
@@ -46,20 +46,18 @@
 store_parse_modifiers(struct imap_store_context *ctx,
 		      const struct imap_arg *args)
 {
-	const char *name;
+	const char *name, *value;
 
-	for (; args->type != IMAP_ARG_EOL; args++) {
-		if (args->type != IMAP_ARG_ATOM ||
-		    args[1].type != IMAP_ARG_ATOM) {
+	for (; !IMAP_ARG_IS_EOL(args); args += 2) {
+		if (!imap_arg_get_atom(&args[0], &name) ||
+		    !imap_arg_get_atom(&args[1], &value)) {
 			client_send_command_error(ctx->cmd,
-				"STORE modifiers contain non-atoms.");
+				"Invalid STORE modifiers.");
 			return FALSE;
 		}
-		name = IMAP_ARG_STR(args);
+
 		if (strcasecmp(name, "UNCHANGEDSINCE") == 0) {
-			args++;
-			ctx->max_modseq =
-				strtoull(imap_arg_string(args), NULL, 10);
+			ctx->max_modseq = strtoull(value, NULL, 10);
 			client_enable(ctx->cmd->client,
 				      MAILBOX_FEATURE_CONDSTORE);
 		} else {
@@ -75,24 +73,26 @@
 store_parse_args(struct imap_store_context *ctx, const struct imap_arg *args)
 {
 	struct client_command_context *cmd = ctx->cmd;
+	const struct imap_arg *list_args;
 	const char *type;
 	const char *const *keywords_list = NULL;
 
 	ctx->max_modseq = (uint64_t)-1;
-	if (args->type == IMAP_ARG_LIST) {
-		if (!store_parse_modifiers(ctx, IMAP_ARG_LIST_ARGS(args)))
+	if (imap_arg_get_list(args, &list_args)) {
+		if (!store_parse_modifiers(ctx, list_args))
 			return FALSE;
 		args++;
 	}
 
-	type = imap_arg_string(args++);
-	if (type == NULL || !get_modify_type(ctx, type)) {
+	if (!imap_arg_get_astring(args, &type) ||
+	    !get_modify_type(ctx, type)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return FALSE;
 	}
+	args++;
 
-	if (args->type == IMAP_ARG_LIST) {
-		if (!client_parse_mail_flags(cmd, IMAP_ARG_LIST_ARGS(args),
+	if (imap_arg_get_list(args, &list_args)) {
+		if (!client_parse_mail_flags(cmd, list_args,
 					     &ctx->flags, &keywords_list))
 			return FALSE;
 	} else {
@@ -125,7 +125,7 @@
 	ARRAY_TYPE(seq_range) modified_set, uids;
 	enum mailbox_transaction_flags flags = 0;
 	enum imap_sync_flags imap_sync_flags = 0;
-	const char *reply, *tagged_reply;
+	const char *set, *reply, *tagged_reply;
 	string_t *str;
 	int ret;
 
@@ -135,12 +135,11 @@
 	if (!client_verify_open_mailbox(cmd))
 		return TRUE;
 
-	if (args->type != IMAP_ARG_ATOM) {
+	if (!imap_arg_get_atom(args, &set)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
-	ret = imap_search_get_seqset(cmd, IMAP_ARG_STR_NONULL(args),
-				     cmd->uid, &search_args);
+	ret = imap_search_get_seqset(cmd, set, cmd->uid, &search_args);
 	if (ret <= 0)
 		return ret < 0;
 
--- a/src/imap/cmd-thread.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/cmd-thread.c	Mon Apr 05 07:54:55 2010 +0300
@@ -117,26 +117,17 @@
 	if (!client_verify_open_mailbox(cmd))
 		return TRUE;
 
-	if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
-		client_send_command_error(cmd,
-					  "Invalid thread algorithm argument.");
+	if (!imap_arg_get_astring(&args[0], &str) ||
+	    !imap_arg_get_astring(&args[1], &charset)) {
+		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
+	args += 2;
 
-	str = IMAP_ARG_STR(args);
 	if (!mail_thread_type_parse(str, &thread_type)) {
 		client_send_command_error(cmd, "Unknown thread algorithm.");
 		return TRUE;
 	}
-	args++;
-
-	/* charset */
-	if (args->type != IMAP_ARG_ATOM && args->type != IMAP_ARG_STRING) {
-		client_send_command_error(cmd, "Invalid charset argument.");
-		return TRUE;
-	}
-	charset = IMAP_ARG_STR(args);
-	args++;
 
 	ret = imap_search_args_build(cmd, args, charset, &sargs);
 	if (ret <= 0)
@@ -146,7 +137,7 @@
 	mail_search_args_unref(&sargs);
 	if (ret < 0) {
 		client_send_storage_error(cmd,
-					  mailbox_get_storage(client->mailbox));
+			mailbox_get_storage(client->mailbox));
 		return TRUE;
 	}
 
--- a/src/imap/imap-client.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-client.c	Mon Apr 05 07:54:55 2010 +0300
@@ -383,13 +383,12 @@
 	for (i = 0; i < count; i++) {
 		const char **ret = va_arg(va, const char **);
 
-		if (imap_args[i].type == IMAP_ARG_EOL) {
+		if (IMAP_ARG_IS_EOL(&imap_args[i])) {
 			client_send_command_error(cmd, "Missing arguments.");
 			break;
 		}
 
-		str = imap_arg_string(&imap_args[i]);
-		if (str == NULL) {
+		if (!imap_arg_get_astring(&imap_args[i], &str)) {
 			client_send_command_error(cmd, "Invalid arguments.");
 			break;
 		}
--- a/src/imap/imap-commands-util.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-commands-util.c	Mon Apr 05 07:54:55 2010 +0300
@@ -244,14 +244,13 @@
 	*keywords_r = NULL;
 	p_array_init(&keywords, cmd->pool, 16);
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &atom)) {
 			client_send_command_error(cmd,
 				"Flags list contains non-atoms.");
 			return FALSE;
 		}
 
-		atom = IMAP_ARG_STR(args);
 		if (*atom == '\\') {
 			/* system flag */
 			atom = t_str_ucase(atom);
--- a/src/imap/imap-fetch-body.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-fetch-body.c	Mon Apr 05 07:54:55 2010 +0300
@@ -758,7 +758,7 @@
 			       unsigned int args_count)
 {
 	string_t *str;
-	const char **arr;
+	const char **arr, *value;
 	size_t i;
 
 	str = str_new(ctx->cmd->pool, 128);
@@ -769,8 +769,7 @@
 	arr = p_new(ctx->cmd->pool, const char *, args_count + 1);
 
 	for (i = 0; i < args_count; i++) {
-		if (args[i].type != IMAP_ARG_ATOM &&
-		    args[i].type != IMAP_ARG_STRING) {
+		if (!imap_arg_get_astring(&args[i], &value)) {
 			client_send_command_error(ctx->cmd,
 				"Invalid BODY[..] parameter: "
 				"Header list contains non-strings");
@@ -779,7 +778,7 @@
 
 		if (i != 0)
 			str_append_c(str, ' ');
-		arr[i] = t_str_ucase(IMAP_ARG_STR(&args[i]));
+		arr[i] = t_str_ucase(value);
 
 		if (args[i].type == IMAP_ARG_ATOM)
 			str_append(str, arr[i]);
@@ -802,7 +801,9 @@
 			     const struct imap_arg **args)
 {
 	struct imap_fetch_body_data *body;
-	const char *partial;
+	const struct imap_arg *list_args;
+	unsigned int list_count;
+	const char *partial, *str;
 	const char *p = name + 4;
 
 	body = p_new(ctx->cmd->pool, struct imap_fetch_body_data, 1);
@@ -821,19 +822,17 @@
 		return FALSE;
 	}
 
-	if ((*args)[0].type == IMAP_ARG_LIST) {
+	if (imap_arg_get_list_full(&(*args)[0], &list_args, &list_count)) {
 		/* BODY[HEADER.FIELDS.. (headers list)] */
-		if ((*args)[1].type != IMAP_ARG_ATOM ||
-		    IMAP_ARG_STR(&(*args)[1])[0] != ']') {
+		if (!imap_arg_get_atom(&(*args)[1], &str) ||
+		    str[0] != ']') {
 			client_send_command_error(ctx->cmd,
 				"Invalid BODY[..] parameter: Missing ']'");
 			return FALSE;
 		}
-		if (!body_section_build(ctx, body, p+1,
-					IMAP_ARG_LIST_ARGS(&(*args)[0]),
-					IMAP_ARG_LIST_COUNT(&(*args)[0])))
+		if (!body_section_build(ctx, body, p+1, list_args, list_count))
 			return FALSE;
-		p = IMAP_ARG_STR(&(*args)[1]);
+		p = str;
 		*args += 2;
 	} else {
 		/* no headers list */
--- a/src/imap/imap-search-args.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-search-args.c	Mon Apr 05 07:54:55 2010 +0300
@@ -42,7 +42,7 @@
 	struct mail_search_args *sargs;
 	const char *error;
 
-	if (args->type == IMAP_ARG_EOL) {
+	if (IMAP_ARG_IS_EOL(args)) {
 		client_send_command_error(cmd, "Missing search parameters");
 		return -1;
 	}
--- a/src/imap/imap-search.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-search.c	Mon Apr 05 07:54:55 2010 +0300
@@ -47,13 +47,13 @@
 	const char *name, *str;
 	unsigned int idx;
 
-	while (args->type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_ATOM) {
+	while (!IMAP_ARG_IS_EOL(args)) {
+		if (!imap_arg_get_atom(args, &name)) {
 			client_send_command_error(cmd,
 				"SEARCH return options contain non-atoms.");
 			return FALSE;
 		}
-		name = t_str_ucase(IMAP_ARG_STR_NONULL(args));
+		name = t_str_ucase(name);
 		args++;
 		if (strcmp(name, "MIN") == 0)
 			ctx->return_options |= SEARCH_RETURN_MIN;
@@ -74,12 +74,11 @@
 				return FALSE;
 			}
 			ctx->return_options |= SEARCH_RETURN_PARTIAL;
-			if (args->type != IMAP_ARG_ATOM) {
+			if (!imap_arg_get_atom(args, &str)) {
 				client_send_command_error(cmd,
 					"PARTIAL range missing.");
 				return FALSE;
 			}
-			str = IMAP_ARG_STR_NONULL(args);
 			if (imap_partial_range_parse(ctx, str) < 0) {
 				client_send_command_error(cmd,
 					"PARTIAL range broken.");
@@ -445,19 +444,17 @@
 int cmd_search_parse_return_if_found(struct imap_search_context *ctx,
 				     const struct imap_arg **_args)
 {
-	const struct imap_arg *args = *_args;
+	const struct imap_arg *list_args, *args = *_args;
 	struct client_command_context *cmd = ctx->cmd;
 
-	if (!(args->type == IMAP_ARG_ATOM && args[1].type == IMAP_ARG_LIST &&
-	      strcasecmp(IMAP_ARG_STR_NONULL(args), "RETURN") == 0)) {
+	if (!imap_arg_atom_equals(&args[0], "RETURN") ||
+	    !imap_arg_get_list(&args[1], &list_args)) {
 		ctx->return_options = SEARCH_RETURN_ALL;
 		return 1;
 	}
 
-	args++;
-	if (!search_parse_return_options(ctx, IMAP_ARG_LIST_ARGS(args)))
+	if (!search_parse_return_options(ctx, list_args))
 		return -1;
-	args++;
 
 	if ((ctx->return_options & SEARCH_RETURN_SAVE) != 0) {
 		/* wait if there is another SEARCH SAVE command running. */
@@ -472,7 +469,7 @@
 			i_array_init(&cmd->client->search_saved_uidset, 128);
 	}
 
-	*_args = args;
+	*_args = args + 2;
 	return 1;
 }
 
--- a/src/imap/imap-status.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/imap/imap-status.c	Mon Apr 05 07:54:55 2010 +0300
@@ -15,16 +15,15 @@
 
 	memset(items_r, 0, sizeof(*items_r));
 	items = 0;
-	for (; args->type != IMAP_ARG_EOL; args++) {
-		if (args->type != IMAP_ARG_ATOM) {
+	for (; !IMAP_ARG_IS_EOL(args); args++) {
+		if (!imap_arg_get_atom(args, &item)) {
 			/* list may contain only atoms */
 			client_send_command_error(cmd,
 				"Status list contains non-atoms.");
 			return -1;
 		}
 
-		item = t_str_ucase(IMAP_ARG_STR(args));
-
+		item = t_str_ucase(item);
 		if (strcmp(item, "MESSAGES") == 0)
 			items |= STATUS_MESSAGES;
 		else if (strcmp(item, "RECENT") == 0)
--- a/src/lib-imap/Makefile.am	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/Makefile.am	Mon Apr 05 07:54:55 2010 +0300
@@ -7,6 +7,7 @@
 	-I$(top_srcdir)/src/lib-mail
 
 libimap_la_SOURCES = \
+	imap-arg.c \
 	imap-base-subject.c \
 	imap-bodystructure.c \
 	imap-date.c \
@@ -20,6 +21,7 @@
 	imap-util.c
 
 headers = \
+	imap-arg.h \
 	imap-base-subject.h \
 	imap-bodystructure.h \
 	imap-date.h \
@@ -57,16 +59,16 @@
 test_imap_match_DEPENDENCIES = imap-match.lo $(test_libs)
 
 test_imap_parser_SOURCES = test-imap-parser.c
-test_imap_parser_LDADD = imap-parser.lo $(test_libs)
-test_imap_parser_DEPENDENCIES = imap-parser.lo $(test_libs)
+test_imap_parser_LDADD = imap-parser.lo imap-arg.lo $(test_libs)
+test_imap_parser_DEPENDENCIES = imap-parser.lo imap-arg.lo $(test_libs)
 
 test_imap_utf7_SOURCES = test-imap-utf7.c
 test_imap_utf7_LDADD = imap-utf7.lo $(test_libs)
 test_imap_utf7_DEPENDENCIES = imap-utf7.lo $(test_libs)
 
 test_imap_util_SOURCES = test-imap-util.c
-test_imap_util_LDADD = imap-util.lo $(test_libs)
-test_imap_util_DEPENDENCIES = imap-util.lo $(test_libs)
+test_imap_util_LDADD = imap-util.lo imap-arg.lo $(test_libs)
+test_imap_util_DEPENDENCIES = imap-util.lo imap-arg.lo $(test_libs)
 
 check: check-am check-test
 check-test: all-am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-imap/imap-arg.c	Mon Apr 05 07:54:55 2010 +0300
@@ -0,0 +1,130 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "imap-arg.h"
+
+bool imap_arg_get_atom(const struct imap_arg *arg, const char **str_r)
+{
+	if (arg->type != IMAP_ARG_ATOM)
+		return FALSE;
+
+	*str_r = arg->_data.str;
+	return TRUE;
+}
+
+bool imap_arg_get_quoted(const struct imap_arg *arg, const char **str_r)
+{
+	if (arg->type != IMAP_ARG_STRING)
+		return FALSE;
+
+	*str_r = arg->_data.str;
+	return TRUE;
+}
+
+bool imap_arg_get_string(const struct imap_arg *arg, const char **str_r)
+{
+	if (arg->type != IMAP_ARG_STRING && arg->type != IMAP_ARG_LITERAL)
+		return FALSE;
+
+	*str_r = arg->_data.str;
+	return TRUE;
+}
+
+bool imap_arg_get_astring(const struct imap_arg *arg, const char **str_r)
+{
+	if (!IMAP_ARG_IS_ASTRING(arg))
+		return FALSE;
+
+	*str_r = arg->_data.str;
+	return TRUE;
+}
+
+bool imap_arg_get_nstring(const struct imap_arg *arg, const char **str_r)
+{
+	if (arg->type == IMAP_ARG_NIL) {
+		*str_r = NULL;
+		return TRUE;
+	}
+	return imap_arg_get_astring(arg, str_r);
+}
+
+bool imap_arg_get_literal_size(const struct imap_arg *arg, uoff_t *size_r)
+{
+	if (arg->type != IMAP_ARG_LITERAL_SIZE &&
+	    arg->type != IMAP_ARG_LITERAL_SIZE_NONSYNC)
+		return FALSE;
+
+	*size_r = arg->_data.literal_size;
+	return TRUE;
+}
+
+bool imap_arg_get_list(const struct imap_arg *arg,
+		       const struct imap_arg **list_r)
+{
+	unsigned int count;
+
+	return imap_arg_get_list_full(arg, list_r, &count);
+}
+
+bool imap_arg_get_list_full(const struct imap_arg *arg,
+			    const struct imap_arg **list_r,
+			    unsigned int *list_count_r)
+{
+	unsigned int count;
+
+	if (arg->type != IMAP_ARG_LIST)
+		return FALSE;
+
+	*list_r = array_get(&arg->_data.list, &count);
+
+	/* drop IMAP_ARG_EOL from list size */
+	i_assert(count > 0);
+	*list_count_r = count - 1;
+	return TRUE;
+}
+
+const char *imap_arg_as_astring(const struct imap_arg *arg)
+{
+	const char *str;
+
+	if (!imap_arg_get_astring(arg, &str))
+		i_unreached();
+	return str;
+}
+
+const char *imap_arg_as_nstring(const struct imap_arg *arg)
+{
+	const char *str;
+
+	if (!imap_arg_get_nstring(arg, &str))
+		i_unreached();
+	return str;
+}
+
+uoff_t imap_arg_as_literal_size(const struct imap_arg *arg)
+{
+	uoff_t size;
+
+	if (!imap_arg_get_literal_size(arg, &size))
+		i_unreached();
+	return size;
+}
+
+const struct imap_arg *
+imap_arg_as_list(const struct imap_arg *arg)
+{
+	const struct imap_arg *ret;
+
+	if (!imap_arg_get_list(arg, &ret))
+		i_unreached();
+	return ret;
+}
+
+bool imap_arg_atom_equals(const struct imap_arg *arg, const char *str)
+{
+	const char *value;
+
+	if (!imap_arg_get_atom(arg, &value))
+		return FALSE;
+	return strcasecmp(value, str) == 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-imap/imap-arg.h	Mon Apr 05 07:54:55 2010 +0300
@@ -0,0 +1,87 @@
+#ifndef IMAP_ARG_H
+#define IMAP_ARG_H
+
+#include "array.h"
+
+/* We use this macro to read atoms from input. It should probably contain
+   everything some day, but for now we can't handle some input otherwise:
+
+   ']' is required for parsing section (FETCH BODY[])
+   '%', '*' and ']' are valid list-chars for LIST patterns
+   '\' is used in flags */
+#define IS_ATOM_SPECIAL_INPUT(c) \
+	((c) == '(' || (c) == ')' || (c) == '{' || \
+	 (c) == '"' || (c) <= 32 || (c) == 0x7f)
+
+#define IS_ATOM_SPECIAL(c) \
+	(IS_ATOM_SPECIAL_INPUT(c) || \
+	 (c) == ']' || (c) == '%' || (c) == '*' || (c) == '\\')
+
+enum imap_arg_type {
+	IMAP_ARG_NIL = 0,
+	IMAP_ARG_ATOM,
+	IMAP_ARG_STRING,
+	IMAP_ARG_LIST,
+
+	/* literals are returned as IMAP_ARG_STRING by default */
+	IMAP_ARG_LITERAL,
+	IMAP_ARG_LITERAL_SIZE,
+	IMAP_ARG_LITERAL_SIZE_NONSYNC,
+
+	IMAP_ARG_EOL /* end of argument list */
+};
+
+ARRAY_DEFINE_TYPE(imap_arg_list, struct imap_arg);
+struct imap_arg {
+	enum imap_arg_type type;
+        struct imap_arg *parent; /* always of type IMAP_ARG_LIST */
+
+	union {
+		const char *str;
+		uoff_t literal_size;
+		ARRAY_TYPE(imap_arg_list) list;
+	} _data;
+};
+
+/* RFC 3501's astring type */
+#define IMAP_ARG_TYPE_IS_ASTRING(type) \
+	((type) == IMAP_ARG_ATOM || \
+	 (type) == IMAP_ARG_STRING || \
+	 (type) == IMAP_ARG_LITERAL)
+#define IMAP_ARG_IS_ASTRING(arg) \
+	IMAP_ARG_TYPE_IS_ASTRING((arg)->type)
+#define IMAP_ARG_IS_EOL(arg) \
+	((arg)->type == IMAP_ARG_EOL)
+
+bool imap_arg_get_atom(const struct imap_arg *arg, const char **str_r)
+	ATTR_WARN_UNUSED_RESULT;
+bool imap_arg_get_quoted(const struct imap_arg *arg, const char **str_r)
+	ATTR_WARN_UNUSED_RESULT;
+bool imap_arg_get_string(const struct imap_arg *arg, const char **str_r)
+	ATTR_WARN_UNUSED_RESULT;
+bool imap_arg_get_astring(const struct imap_arg *arg, const char **str_r)
+	ATTR_WARN_UNUSED_RESULT;
+/* str is set to NULL for NIL. */
+bool imap_arg_get_nstring(const struct imap_arg *arg, const char **str_r)
+	ATTR_WARN_UNUSED_RESULT;
+
+bool imap_arg_get_literal_size(const struct imap_arg *arg, uoff_t *size_r)
+	ATTR_WARN_UNUSED_RESULT;
+
+bool imap_arg_get_list(const struct imap_arg *arg,
+		       const struct imap_arg **list_r)
+	ATTR_WARN_UNUSED_RESULT;
+bool imap_arg_get_list_full(const struct imap_arg *arg,
+			    const struct imap_arg **list_r,
+			    unsigned int *list_count_r) ATTR_WARN_UNUSED_RESULT;
+
+/* Similar to above, but assumes that arg is already of correct type. */
+const char *imap_arg_as_astring(const struct imap_arg *arg);
+const char *imap_arg_as_nstring(const struct imap_arg *arg);
+uoff_t imap_arg_as_literal_size(const struct imap_arg *arg);
+const struct imap_arg *imap_arg_as_list(const struct imap_arg *arg);
+
+/* Returns TRUE if arg is atom and case-insensitively matches str */
+bool imap_arg_atom_equals(const struct imap_arg *arg, const char *str);
+
+#endif
--- a/src/lib-imap/imap-bodystructure.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-bodystructure.c	Mon Apr 05 07:54:55 2010 +0300
@@ -534,47 +534,54 @@
 
 static bool str_append_imap_arg(string_t *str, const struct imap_arg *arg)
 {
+	const char *cstr;
+
+	if (!imap_arg_get_nstring(arg, &cstr))
+		return FALSE;
+
 	switch (arg->type) {
 	case IMAP_ARG_NIL:
 		str_append(str, "NIL");
 		break;
 	case IMAP_ARG_ATOM:
-		str_append(str, IMAP_ARG_STR(arg));
+		str_append(str, cstr);
 		break;
 	case IMAP_ARG_STRING:
 		str_append_c(str, '"');
-		str_append(str, IMAP_ARG_STR(arg));
+		/* NOTE: we're parsing with no-unescape flag,
+		   so don't double-escape it here */
+		str_append(str, cstr);
 		str_append_c(str, '"');
 		break;
 	case IMAP_ARG_LITERAL: {
-		const char *argstr = IMAP_ARG_STR(arg);
-
-		str_printfa(str, "{%"PRIuSIZE_T"}\r\n", strlen(argstr));
-		str_append(str, argstr);
+		str_printfa(str, "{%"PRIuSIZE_T"}\r\n", strlen(cstr));
+		str_append(str, cstr);
 		break;
 	}
 	default:
+		i_unreached();
 		return FALSE;
 	}
-
 	return TRUE;
 }
 
 static bool imap_write_list(const struct imap_arg *args, string_t *str)
 {
+	const struct imap_arg *children;
+
 	/* don't do any typechecking, just write it out */
 	str_append_c(str, '(');
-	while (args->type != IMAP_ARG_EOL) {
+	while (!IMAP_ARG_IS_EOL(args)) {
 		if (!str_append_imap_arg(str, args)) {
-			if (args->type != IMAP_ARG_LIST)
+			if (!imap_arg_get_list(args, &children))
 				return FALSE;
 
-			if (!imap_write_list(IMAP_ARG_LIST_ARGS(args), str))
+			if (!imap_write_list(children, str))
 				return FALSE;
 		}
 		args++;
 
-		if (args->type != IMAP_ARG_EOL)
+		if (!IMAP_ARG_IS_EOL(args))
 			str_append_c(str, ' ');
 	}
 	str_append_c(str, ')');
@@ -586,13 +593,14 @@
 {
 	const struct imap_arg *subargs;
 	const struct imap_arg *list_args;
+	const char *value, *content_type, *subtype;
 	bool multipart, text, message_rfc822;
 	int i;
 
 	multipart = FALSE;
 	while (args->type == IMAP_ARG_LIST) {
 		str_append_c(str, '(');
-		list_args = IMAP_ARG_LIST_ARGS(args);
+		list_args = imap_arg_as_list(args);
 		if (!imap_parse_bodystructure_args(list_args, str))
 			return FALSE;
 		str_append_c(str, ')');
@@ -608,7 +616,8 @@
 	}
 
 	/* "content type" "subtype" */
-	if (args[0].type == IMAP_ARG_NIL || args[1].type == IMAP_ARG_NIL)
+	if (!imap_arg_get_astring(&args[0], &content_type) ||
+	    !imap_arg_get_astring(&args[1], &subtype))
 		return FALSE;
 
 	if (!str_append_imap_arg(str, &args[0]))
@@ -617,18 +626,16 @@
 	if (!str_append_imap_arg(str, &args[1]))
 		return FALSE;
 
-	text = strcasecmp(IMAP_ARG_STR_NONULL(&args[0]), "text") == 0;
-	message_rfc822 =
-		strcasecmp(IMAP_ARG_STR_NONULL(&args[0]), "message") == 0 &&
-		strcasecmp(IMAP_ARG_STR_NONULL(&args[1]), "rfc822") == 0;
+	text = strcasecmp(content_type, "text") == 0;
+	message_rfc822 = strcasecmp(content_type, "message") == 0 &&
+		strcasecmp(subtype, "rfc822") == 0;
 
 	args += 2;
 
 	/* ("content type param key" "value" ...) | NIL */
-	if (args->type == IMAP_ARG_LIST) {
+	if (imap_arg_get_list(args, &subargs)) {
 		str_append(str, " (");
-                subargs = IMAP_ARG_LIST_ARGS(args);
-		for (; subargs->type != IMAP_ARG_EOL; ) {
+		while (!IMAP_ARG_IS_EOL(subargs)) {
 			if (!str_append_imap_arg(str, &subargs[0]))
 				return FALSE;
 			str_append_c(str, ' ');
@@ -636,7 +643,7 @@
 				return FALSE;
 
 			subargs += 2;
-			if (subargs->type == IMAP_ARG_EOL)
+			if (IMAP_ARG_IS_EOL(subargs))
 				break;
 			str_append_c(str, ' ');
 		}
@@ -658,32 +665,31 @@
 
 	if (text) {
 		/* text/xxx - text lines */
-		if (args->type != IMAP_ARG_ATOM)
+		if (!imap_arg_get_atom(args, &value))
 			return FALSE;
 
 		str_append_c(str, ' ');
-		str_append(str, IMAP_ARG_STR(args));
+		str_append(str, value);
 	} else if (message_rfc822) {
 		/* message/rfc822 - envelope + bodystructure + text lines */
-		if (args[0].type != IMAP_ARG_LIST ||
-		    args[1].type != IMAP_ARG_LIST ||
-		    args[2].type != IMAP_ARG_ATOM)
-			return FALSE;
-
 		str_append_c(str, ' ');
 
-		list_args = IMAP_ARG_LIST_ARGS(&args[0]);
+		if (!imap_arg_get_list(&args[0], &list_args))
+			return FALSE;
 		if (!imap_write_list(list_args, str))
 			return FALSE;
 
 		str_append(str, " (");
 
-		list_args = IMAP_ARG_LIST_ARGS(&args[1]);
+		if (!imap_arg_get_list(&args[1], &list_args))
+			return FALSE;
 		if (!imap_parse_bodystructure_args(list_args, str))
 			return FALSE;
 
 		str_append(str, ") ");
-		str_append(str, IMAP_ARG_STR(&args[2]));
+		if (!imap_arg_get_atom(&args[2], &value))
+			return FALSE;
+		str_append(str, value);
 	}
 
 	return TRUE;
--- a/src/lib-imap/imap-envelope.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-envelope.c	Mon Apr 05 07:54:55 2010 +0300
@@ -221,22 +221,15 @@
 	const char *args[4];
 	int i;
 
-	if (arg->type != IMAP_ARG_LIST)
+	if (!imap_arg_get_list_full(arg, &list_args, &list_count))
 		return FALSE;
-	list_args = IMAP_ARG_LIST_ARGS(arg);
-	list_count = IMAP_ARG_LIST_COUNT(arg);
 
 	/* we require 4 arguments, strings or NILs */
 	if (list_count < 4)
 		return FALSE;
 
 	for (i = 0; i < 4; i++) {
-		if (list_args[i].type == IMAP_ARG_NIL)
-			args[i] = NULL;
-		else if (list_args[i].type == IMAP_ARG_STRING ||
-			 list_args[i].type == IMAP_ARG_ATOM)
-			args[i] = IMAP_ARG_STR(&list_args[i]);
-		else
+		if (!imap_arg_get_nstring(&list_args[i], &args[i]))
 			return FALSE;
 	}
 
@@ -298,14 +291,13 @@
 	string_t *str;
 	bool in_group;
 
-	if (arg->type != IMAP_ARG_LIST)
+	if (!imap_arg_get_list(arg, &list_args))
 		return NULL;
 
 	in_group = FALSE;
 	str = t_str_new(128);
 
-	list_args = IMAP_ARG_LIST_ARGS(arg);
-	for (; list_args->type != IMAP_ARG_EOL; list_args++) {
+	for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
 		if (!imap_address_arg_append(list_args, str, &in_group))
 			return NULL;
 	}
@@ -316,21 +308,22 @@
 static const char *imap_envelope_parse_first_mailbox(const struct imap_arg *arg)
 {
 	const struct imap_arg *list_args;
+	const char *str;
+	unsigned int list_count;
 
 	/* ((...)(...) ...) */
-	if (arg->type != IMAP_ARG_LIST)
+	if (!imap_arg_get_list(arg, &list_args))
 		return NULL;
-
-	list_args = IMAP_ARG_LIST_ARGS(arg);
-	if (list_args->type == IMAP_ARG_EOL)
+	if (IMAP_ARG_IS_EOL(list_args))
 		return "";
 
 	/* (name route mailbox domain) */
-	if (IMAP_ARG_LIST_COUNT(list_args) != 4)
+	if (!imap_arg_get_list_full(arg, &list_args, &list_count) ||
+	    list_count != 4)
 		return NULL;
-
-	list_args = IMAP_ARG_LIST_ARGS(list_args);
-	return t_strdup(imap_arg_string(&list_args[2]));
+	if (!imap_arg_get_nstring(&list_args[2], &str))
+		return NULL;
+	return t_strdup(str);
 }
 
 static bool
@@ -351,8 +344,10 @@
 	case IMAP_ENVELOPE_RESULT_TYPE_STRING:
 		if (field >= IMAP_ENVELOPE_FROM && field <= IMAP_ENVELOPE_BCC)
 			value = imap_envelope_parse_address(arg);
-		else
-			value = t_strdup(imap_arg_string(arg));
+		else {
+			if (imap_arg_get_nstring(arg, &value))
+				value = t_strdup(value);
+		}
 		break;
 	case IMAP_ENVELOPE_RESULT_TYPE_FIRST_MAILBOX:
 		i_assert(field >= IMAP_ENVELOPE_FROM &&
--- a/src/lib-imap/imap-id.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-id.c	Mon Apr 05 07:54:55 2010 +0300
@@ -55,34 +55,32 @@
 	string_t *str;
 	const char *key, *value;
 
-	if (args->type == IMAP_ARG_EOL)
+	if (IMAP_ARG_IS_EOL(args))
 		return "NIL";
 
 	str = t_str_new(256);
 	str_append_c(str, '(');
-	for (; args->type != IMAP_ARG_EOL; args++) {
-		if (!IMAP_ARG_TYPE_IS_STRING(args->type)) {
+	for (; !IMAP_ARG_IS_EOL(args); args++) {
+		if (!imap_arg_get_astring(args, &key)) {
 			/* broken input */
-			if (args[1].type == IMAP_ARG_EOL)
+			if (IMAP_ARG_IS_EOL(&args[1]))
 				break;
 			args++;
 		} else {
 			/* key */
 			if (str_len(str) > 1)
 				str_append_c(str, ' ');
-			key = IMAP_ARG_STR_NONULL(args);
 			imap_dquote_append(str, key);
 			str_append_c(str, ' ');
 			/* value */
-			if (args[1].type == IMAP_ARG_EOL) {
+			if (IMAP_ARG_IS_EOL(&args[1])) {
 				str_append(str, "NIL");
 				break;
 			}
 			args++;
-			if (!IMAP_ARG_TYPE_IS_STRING(args->type))
+			if (!imap_arg_get_astring(args, &value))
 				value = NULL;
 			else {
-				value = IMAP_ARG_STR_NONULL(args);
 				if (strcmp(value, "*") == 0)
 					value = imap_id_get_default(key);
 			}
@@ -132,22 +130,21 @@
 	string_t *reply;
 	bool log_all;
 
-	if (settings == NULL || *settings == '\0' ||
-	    args->type != IMAP_ARG_LIST)
+	if (settings == NULL || *settings == '\0')
 		return NULL;
-
-	args = IMAP_ARG_LIST_ARGS(args);
+	if (!imap_arg_get_list(args, &args))
+		return NULL;
 
 	log_all = strcmp(settings, "*") == 0;
 	reply = t_str_new(256);
 	keys = t_strsplit_spaces(settings, " ");
-	while (args->type != IMAP_ARG_EOL && args[1].type != IMAP_ARG_EOL) {
-		if (args->type != IMAP_ARG_STRING) {
+	while (!IMAP_ARG_IS_EOL(&args[0]) &&
+	       !IMAP_ARG_IS_EOL(&args[1])) {
+		if (!imap_arg_get_string(args, &key)) {
 			/* broken input */
 			args += 2;
 			continue;
 		}
-		key = IMAP_ARG_STR_NONULL(args);
 		args++;
 		if (strlen(key) > 30) {
 			/* broken: ID spec requires fields to be max. 30
@@ -157,12 +154,10 @@
 		}
 
 		if (log_all || str_array_icase_find(keys, key)) {
-			if (IMAP_ARG_TYPE_IS_STRING(args->type))
-				value = IMAP_ARG_STR_NONULL(args);
-			else if (args->type == IMAP_ARG_NIL)
+			if (!imap_arg_get_nstring(args, &value))
+				value = "";
+			else if (value == NULL)
 				value = "NIL";
-			else
-				value = "";
 			if (str_len(reply) > 0)
 				str_append(reply, ", ");
 			str_append(reply, str_sanitize(key, 30));
--- a/src/lib-imap/imap-parser.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-parser.c	Mon Apr 05 07:54:55 2010 +0300
@@ -652,8 +652,7 @@
 	if (last_arg == NULL)
 		return FALSE;
 
-	*size_r = IMAP_ARG_LITERAL_SIZE(last_arg);
-	return TRUE;
+	return imap_arg_get_literal_size(last_arg, size_r);
 }
 
 void imap_parser_read_last_literal(struct imap_parser *parser)
@@ -717,19 +716,3 @@
 		return NULL;
 	}
 }
-
-const char *imap_arg_string(const struct imap_arg *arg)
-{
-	switch (arg->type) {
-	case IMAP_ARG_NIL:
-		return "";
-
-	case IMAP_ARG_ATOM:
-	case IMAP_ARG_STRING:
-	case IMAP_ARG_LITERAL:
-		return arg->_data.str;
-
-	default:
-		return NULL;
-	}
-}
--- a/src/lib-imap/imap-parser.h	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-parser.h	Mon Apr 05 07:54:55 2010 +0300
@@ -1,21 +1,7 @@
 #ifndef IMAP_PARSER_H
 #define IMAP_PARSER_H
 
-#include "array.h"
-
-/* We use this macro to read atoms from input. It should probably contain
-   everything some day, but for now we can't handle some input otherwise:
-
-   ']' is required for parsing section (FETCH BODY[])
-   '%', '*' and ']' are valid list-chars for LIST patterns
-   '\' is used in flags */
-#define IS_ATOM_SPECIAL_INPUT(c) \
-	((c) == '(' || (c) == ')' || (c) == '{' || \
-	 (c) == '"' || (c) <= 32 || (c) == 0x7f)
-
-#define IS_ATOM_SPECIAL(c) \
-	(IS_ATOM_SPECIAL_INPUT(c) || \
-	 (c) == ']' || (c) == '%' || (c) == '*' || (c) == '\\')
+#include "imap-arg.h"
 
 enum imap_parser_flags {
 	/* Set this flag if you wish to read only size of literal argument
@@ -33,61 +19,8 @@
 	IMAP_PARSE_FLAG_MULTILINE_STR	= 0x10
 };
 
-enum imap_arg_type {
-	IMAP_ARG_NIL = 0,
-	IMAP_ARG_ATOM,
-	IMAP_ARG_STRING,
-	IMAP_ARG_LIST,
-
-	/* literals are returned as IMAP_ARG_STRING by default */
-	IMAP_ARG_LITERAL,
-	IMAP_ARG_LITERAL_SIZE,
-	IMAP_ARG_LITERAL_SIZE_NONSYNC,
-
-	IMAP_ARG_EOL /* end of argument list */
-};
-
 struct imap_parser;
 
-ARRAY_DEFINE_TYPE(imap_arg_list, struct imap_arg);
-struct imap_arg {
-	enum imap_arg_type type;
-        struct imap_arg *parent; /* always of type IMAP_ARG_LIST */
-
-	union {
-		const char *str;
-		uoff_t literal_size;
-		ARRAY_TYPE(imap_arg_list) list;
-	} _data;
-};
-
-#define IMAP_ARG_TYPE_IS_STRING(type) \
-	((type) == IMAP_ARG_ATOM || (type) == IMAP_ARG_STRING || \
-	 (type) == IMAP_ARG_LITERAL)
-
-#define IMAP_ARG_STR(arg) \
-	((arg)->type == IMAP_ARG_NIL ? NULL : \
-	 IMAP_ARG_TYPE_IS_STRING((arg)->type) ? \
-	 (arg)->_data.str : imap_arg_str_error())
-
-#define IMAP_ARG_STR_NONULL(arg) \
-	((arg)->type == IMAP_ARG_ATOM || (arg)->type == IMAP_ARG_STRING || \
-	 (arg)->type == IMAP_ARG_LITERAL ? \
-	 (arg)->_data.str : imap_arg_str_error())
-
-#define IMAP_ARG_LITERAL_SIZE(arg) \
-	(((arg)->type == IMAP_ARG_LITERAL_SIZE || \
-	 (arg)->type == IMAP_ARG_LITERAL_SIZE_NONSYNC) ? \
-	 (arg)->_data.literal_size : imap_arg_literal_size_error())
-
-#define IMAP_ARG_LIST(arg) \
-	((arg)->type == IMAP_ARG_LIST ? \
-	 &(arg)->_data.list : imap_arg_list_error())
-#define IMAP_ARG_LIST_ARGS(arg) \
-	array_idx(IMAP_ARG_LIST(arg), 0)
-#define IMAP_ARG_LIST_COUNT(arg) \
-	(array_count(IMAP_ARG_LIST(arg)) - 1)
-
 /* Create new IMAP argument parser. output is used for sending command
    continuation requests for literals.
 
@@ -144,35 +77,4 @@
    Returns NULL if more data is needed. */
 const char *imap_parser_read_word(struct imap_parser *parser);
 
-/* Returns the imap argument as string. NIL returns "" and list returns NULL. */
-const char *imap_arg_string(const struct imap_arg *arg);
-
-/* Error functions */
-static inline char * ATTR_NORETURN
-imap_arg_str_error(void)
-{
-	i_unreached();
-#ifndef ATTRS_DEFINED
-	return NULL;
 #endif
-}
-
-static inline uoff_t ATTR_NORETURN
-imap_arg_literal_size_error(void)
-{
-	i_unreached();
-#ifndef ATTRS_DEFINED
-	return 0;
-#endif
-}
-
-static inline ARRAY_TYPE(imap_arg_list) * ATTR_NORETURN
-imap_arg_list_error(void)
-{
-	i_unreached();
-#ifndef ATTRS_DEFINED
-	return NULL;
-#endif
-}
-
-#endif
--- a/src/lib-imap/imap-util.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-imap/imap-util.c	Mon Apr 05 07:54:55 2010 +0300
@@ -75,10 +75,9 @@
 
 void imap_write_args(string_t *dest, const struct imap_arg *args)
 {
-	const ARRAY_TYPE(imap_arg_list) *list;
 	bool first = TRUE;
 
-	for (; args->type != IMAP_ARG_EOL; args++) {
+	for (; !IMAP_ARG_IS_EOL(args); args++) {
 		if (first)
 			first = FALSE;
 		else
@@ -89,15 +88,15 @@
 			str_append(dest, "NIL");
 			break;
 		case IMAP_ARG_ATOM:
-			str_append(dest, IMAP_ARG_STR(args));
+			str_append(dest, imap_arg_as_astring(args));
 			break;
 		case IMAP_ARG_STRING:
 			str_append_c(dest, '"');
-			str_append(dest, str_escape(IMAP_ARG_STR(args)));
+			str_append(dest, str_escape(imap_arg_as_astring(args)));
 			str_append_c(dest, '"');
 			break;
 		case IMAP_ARG_LITERAL: {
-			const char *strarg = IMAP_ARG_STR(args);
+			const char *strarg = imap_arg_as_astring(args);
 			str_printfa(dest, "{%"PRIuSIZE_T"}\r\n",
 				    strlen(strarg));
 			str_append(dest, strarg);
@@ -105,14 +104,13 @@
 		}
 		case IMAP_ARG_LIST:
 			str_append_c(dest, '(');
-			list = IMAP_ARG_LIST(args);
-			imap_write_args(dest, array_idx(list, 0));
+			imap_write_args(dest, imap_arg_as_list(args));
 			str_append_c(dest, ')');
 			break;
 		case IMAP_ARG_LITERAL_SIZE:
 		case IMAP_ARG_LITERAL_SIZE_NONSYNC:
 			str_printfa(dest, "{%"PRIuUOFF_T"}\r\n",
-				    IMAP_ARG_LITERAL_SIZE(args));
+				    imap_arg_as_literal_size(args));
 			str_append(dest, "<too large>");
 			break;
 		case IMAP_ARG_EOL:
--- a/src/lib-storage/mail-search-build.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/lib-storage/mail-search-build.c	Mon Apr 05 07:54:55 2010 +0300
@@ -3,7 +3,7 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "imap-date.h"
-#include "imap-parser.h"
+#include "imap-arg.h"
 #include "imap-seqset.h"
 #include "mail-search-build.h"
 #include "mail-storage.h"
@@ -30,17 +30,15 @@
 arg_get_next(struct search_build_data *data, const struct imap_arg **args,
 	     const char **value_r)
 {
-	if ((*args)->type == IMAP_ARG_EOL) {
+	if (IMAP_ARG_IS_EOL(*args)) {
 		data->error = "Missing parameter for argument";
 		return FALSE;
 	}
-	if ((*args)->type != IMAP_ARG_ATOM &&
-	    (*args)->type != IMAP_ARG_STRING) {
+	if (!imap_arg_get_astring(*args, value_r)) {
 		data->error = "Invalid parameter for argument";
 		return FALSE;
 	}
 
-	*value_r = IMAP_ARG_STR(*args);
 	*args += 1;
 	return TRUE;
 }
@@ -266,33 +264,30 @@
 			     struct mail_search_arg **next_sarg)
 {
 	struct mail_search_arg **subargs, *sarg;
-	const struct imap_arg *arg;
-	const char *str;
+	const struct imap_arg *arg, *listargs;
+	const char *key, *value;
 
-	if ((*args)->type == IMAP_ARG_EOL) {
+	if (IMAP_ARG_IS_EOL(*args)) {
 		data->error = "Missing argument";
 		return FALSE;
 	}
 
 	arg = *args;
-
 	if (arg->type == IMAP_ARG_NIL) {
 		/* NIL not allowed */
 		data->error = "NIL not allowed";
 		return FALSE;
 	}
 
-	if (arg->type == IMAP_ARG_LIST) {
-		const struct imap_arg *listargs = IMAP_ARG_LIST_ARGS(arg);
-
-		if (listargs->type == IMAP_ARG_EOL) {
+	if (imap_arg_get_list(arg, &listargs)) {
+		if (IMAP_ARG_IS_EOL(listargs)) {
 			data->error = "Empty list not allowed";
 			return FALSE;
 		}
 
 		*next_sarg = search_arg_new(data->pool, SEARCH_SUB);
 		subargs = &(*next_sarg)->value.subargs;
-		while (listargs->type != IMAP_ARG_EOL) {
+		while (IMAP_ARG_IS_EOL(listargs)) {
 			if (!search_arg_build(data, &listargs, subargs))
 				return FALSE;
 			subargs = &(*subargs)->next;
@@ -302,91 +297,84 @@
 		return TRUE;
 	}
 
-	i_assert(arg->type == IMAP_ARG_ATOM ||
-		 arg->type == IMAP_ARG_STRING);
-
 	/* string argument - get the name and jump to next */
-	str = IMAP_ARG_STR(arg);
+	key = imap_arg_as_astring(arg);
 	*args += 1;
-	str = t_str_ucase(str);
+	key = t_str_ucase(key);
 
-	switch (*str) {
+	switch (*key) {
 	case 'A':
-		if (strcmp(str, "ANSWERED") == 0)
+		if (strcmp(key, "ANSWERED") == 0)
 			return ARG_NEW_FLAGS(MAIL_ANSWERED);
-		else if (strcmp(str, "ALL") == 0)
+		else if (strcmp(key, "ALL") == 0)
 			return ARG_NEW_SINGLE(SEARCH_ALL);
 		break;
 	case 'B':
-		if (strcmp(str, "BODY") == 0) {
+		if (strcmp(key, "BODY") == 0) {
 			/* <string> */
-			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
-			    *IMAP_ARG_STR(*args) == '\0') {
+			if (imap_arg_get_astring(*args, &value) &&
+			    *value == '\0') {
+				/* optimization: BODY "" matches everything */
 				*args += 1;
 				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
 			return ARG_NEW_STR(SEARCH_BODY);
-		} else if (strcmp(str, "BEFORE") == 0) {
+		} else if (strcmp(key, "BEFORE") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_BEFORE);
-		} else if (strcmp(str, "BCC") == 0) {
+		} else if (strcmp(key, "BCC") == 0) {
 			/* <string> */
-			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
+			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, key);
 		}
 		break;
 	case 'C':
-		if (strcmp(str, "CC") == 0) {
+		if (strcmp(key, "CC") == 0) {
 			/* <string> */
-			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
+			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, key);
 		}
 		break;
 	case 'D':
-		if (strcmp(str, "DELETED") == 0)
+		if (strcmp(key, "DELETED") == 0)
 			return ARG_NEW_FLAGS(MAIL_DELETED);
-		else if (strcmp(str, "DRAFT") == 0)
+		else if (strcmp(key, "DRAFT") == 0)
 			return ARG_NEW_FLAGS(MAIL_DRAFT);
 		break;
 	case 'F':
-		if (strcmp(str, "FLAGGED") == 0)
+		if (strcmp(key, "FLAGGED") == 0)
 			return ARG_NEW_FLAGS(MAIL_FLAGGED);
-		else if (strcmp(str, "FROM") == 0) {
+		else if (strcmp(key, "FROM") == 0) {
 			/* <string> */
-			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
+			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, key);
 		}
 		break;
 	case 'H':
-		if (strcmp(str, "HEADER") == 0) {
+		if (strcmp(key, "HEADER") == 0) {
 			/* <field-name> <string> */
-			const char *key;
-
-			if ((*args)->type == IMAP_ARG_EOL) {
+			if (IMAP_ARG_IS_EOL(*args)) {
 				data->error = "Missing parameter for HEADER";
 				return FALSE;
 			}
-			if ((*args)->type != IMAP_ARG_ATOM &&
-			    (*args)->type != IMAP_ARG_STRING) {
+			if (!imap_arg_get_astring(*args, &value)) {
 				data->error = "Invalid parameter for HEADER";
 				return FALSE;
 			}
 
-			key = t_str_ucase(IMAP_ARG_STR(*args));
 			*args += 1;
-			return ARG_NEW_HEADER(SEARCH_HEADER, key);
+			return ARG_NEW_HEADER(SEARCH_HEADER,
+					      t_str_ucase(value));
 		}
 		break;
 	case 'I':
-		if (strcmp(str, "INTHREAD") == 0) {
+		if (strcmp(key, "INTHREAD") == 0) {
 			/* <algorithm> <search key> */
 			enum mail_thread_type thread_type;
-			const char *str;
 
-			if ((*args)->type != IMAP_ARG_ATOM) {
+			if (!imap_arg_get_atom(*args, &value)) {
 				data->error = "Invalid parameter for INTHREAD";
 				return FALSE;
 			}
 
-			str = IMAP_ARG_STR_NONULL(*args);
-			if (!mail_thread_type_parse(str, &thread_type)) {
+			if (!mail_thread_type_parse(value, &thread_type)) {
 				data->error = "Unknown thread algorithm";
 				return FALSE;
 			}
@@ -400,29 +388,29 @@
 		}
 		break;
 	case 'K':
-		if (strcmp(str, "KEYWORD") == 0) {
+		if (strcmp(key, "KEYWORD") == 0) {
 			return ARG_NEW_STR(SEARCH_KEYWORDS);
 		}
 		break;
 	case 'L':
-		if (strcmp(str, "LARGER") == 0) {
+		if (strcmp(key, "LARGER") == 0) {
 			/* <n> */
 			return ARG_NEW_SIZE(SEARCH_LARGER);
 		}
 		break;
 	case 'M':
-		if (strcmp(str, "MODSEQ") == 0) {
+		if (strcmp(key, "MODSEQ") == 0) {
 			/* [<name> <type>] <n> */
 			return ARG_NEW_MODSEQ();
 		}
   		break;
 	case 'N':
-		if (strcmp(str, "NOT") == 0) {
+		if (strcmp(key, "NOT") == 0) {
 			if (!search_arg_build(data, args, next_sarg))
 				return FALSE;
 			(*next_sarg)->not = !(*next_sarg)->not;
 			return TRUE;
-		} else if (strcmp(str, "NEW") == 0) {
+		} else if (strcmp(key, "NEW") == 0) {
 			/* NEW == (RECENT UNSEEN) */
 			*next_sarg = search_arg_new(data->pool, SEARCH_SUB);
 
@@ -437,7 +425,7 @@
 		}
 		break;
 	case 'O':
-		if (strcmp(str, "OR") == 0) {
+		if (strcmp(key, "OR") == 0) {
 			/* <search-key1> <search-key2> */
 			*next_sarg = search_arg_new(data->pool, SEARCH_OR);
 
@@ -450,12 +438,8 @@
 
 				/* <key> OR <key> OR ... <key> - put them all
 				   under one SEARCH_OR list. */
-				if ((*args)->type == IMAP_ARG_EOL)
-					break;
-
-				if ((*args)->type != IMAP_ARG_ATOM ||
-				    strcasecmp(IMAP_ARG_STR_NONULL(*args),
-					       "OR") != 0)
+				if (!imap_arg_get_atom(*args, &value) ||
+				    strcasecmp(value, "OR") != 0)
 					break;
 
 				*args += 1;
@@ -464,17 +448,17 @@
 			if (!search_arg_build(data, args, subargs))
 				return FALSE;
 			return TRUE;
-		} if (strcmp(str, "ON") == 0) {
+		} if (strcmp(key, "ON") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_ON);
-		} if (strcmp(str, "OLD") == 0) {
+		} if (strcmp(key, "OLD") == 0) {
 			/* OLD == NOT RECENT */
 			if (!ARG_NEW_FLAGS(MAIL_RECENT))
 				return FALSE;
 
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} if (strcmp(str, "OLDER") == 0) {
+		} if (strcmp(key, "OLDER") == 0) {
 			/* <interval> - WITHIN extension */
 			if (!ARG_NEW_INTERVAL(SEARCH_BEFORE))
 				return FALSE;
@@ -486,48 +470,49 @@
 		}
 		break;
 	case 'R':
-		if (strcmp(str, "RECENT") == 0)
+		if (strcmp(key, "RECENT") == 0)
 			return ARG_NEW_FLAGS(MAIL_RECENT);
 		break;
 	case 'S':
-		if (strcmp(str, "SEEN") == 0)
+		if (strcmp(key, "SEEN") == 0)
 			return ARG_NEW_FLAGS(MAIL_SEEN);
-		else if (strcmp(str, "SUBJECT") == 0) {
+		else if (strcmp(key, "SUBJECT") == 0) {
 			/* <string> */
-			return ARG_NEW_HEADER(SEARCH_HEADER_COMPRESS_LWSP, str);
-		} else if (strcmp(str, "SENTBEFORE") == 0) {
+			return ARG_NEW_HEADER(SEARCH_HEADER_COMPRESS_LWSP, key);
+		} else if (strcmp(key, "SENTBEFORE") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_SENTBEFORE);
-		} else if (strcmp(str, "SENTON") == 0) {
+		} else if (strcmp(key, "SENTON") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_SENTON);
-		} else if (strcmp(str, "SENTSINCE") == 0) {
+		} else if (strcmp(key, "SENTSINCE") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_SENTSINCE);
-		} else if (strcmp(str, "SINCE") == 0) {
+		} else if (strcmp(key, "SINCE") == 0) {
 			/* <date> */
 			return ARG_NEW_DATE(SEARCH_SINCE);
-		} else if (strcmp(str, "SMALLER") == 0) {
+		} else if (strcmp(key, "SMALLER") == 0) {
 			/* <n> */
 			return ARG_NEW_SIZE(SEARCH_SMALLER);
 		}
 		break;
 	case 'T':
-		if (strcmp(str, "TEXT") == 0) {
+		if (strcmp(key, "TEXT") == 0) {
 			/* <string> */
-			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
-			    *IMAP_ARG_STR(*args) == '\0') {
+			if (imap_arg_get_astring(*args, &value) &&
+			    *value == '\0') {
+				/* optimization: TEXT "" matches everything */
 				*args += 1;
 				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
 			return ARG_NEW_STR(SEARCH_TEXT);
-		} else if (strcmp(str, "TO") == 0) {
+		} else if (strcmp(key, "TO") == 0) {
 			/* <string> */
-			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
+			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, key);
 		}
 		break;
 	case 'U':
-		if (strcmp(str, "UID") == 0) {
+		if (strcmp(key, "UID") == 0) {
 			/* <message set> */
 			if (!ARG_NEW_STR(SEARCH_UIDSET))
 				return FALSE;
@@ -544,32 +529,32 @@
 				return FALSE;
 			}
 			return TRUE;
-		} else if (strcmp(str, "UNANSWERED") == 0) {
+		} else if (strcmp(key, "UNANSWERED") == 0) {
 			if (!ARG_NEW_FLAGS(MAIL_ANSWERED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} else if (strcmp(str, "UNDELETED") == 0) {
+		} else if (strcmp(key, "UNDELETED") == 0) {
 			if (!ARG_NEW_FLAGS(MAIL_DELETED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} else if (strcmp(str, "UNDRAFT") == 0) {
+		} else if (strcmp(key, "UNDRAFT") == 0) {
 			if (!ARG_NEW_FLAGS(MAIL_DRAFT))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} else if (strcmp(str, "UNFLAGGED") == 0) {
+		} else if (strcmp(key, "UNFLAGGED") == 0) {
 			if (!ARG_NEW_FLAGS(MAIL_FLAGGED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} else if (strcmp(str, "UNKEYWORD") == 0) {
+		} else if (strcmp(key, "UNKEYWORD") == 0) {
 			if (!ARG_NEW_STR(SEARCH_KEYWORDS))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
-		} else if (strcmp(str, "UNSEEN") == 0) {
+		} else if (strcmp(key, "UNSEEN") == 0) {
 			if (!ARG_NEW_FLAGS(MAIL_SEEN))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
@@ -577,50 +562,54 @@
 		}
 		break;
 	case 'Y':
-		if (strcmp(str, "YOUNGER") == 0) {
+		if (strcmp(key, "YOUNGER") == 0) {
 			/* <interval> - WITHIN extension */
 			return ARG_NEW_INTERVAL(SEARCH_SINCE);
 		}
 		break;
 	case 'X':
-		if (strcmp(str, "X-BODY-FAST") == 0) {
+		if (strcmp(key, "X-BODY-FAST") == 0) {
 			/* <string> */
-			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
-			    *IMAP_ARG_STR(*args) == '\0') {
+			if (imap_arg_get_astring(*args, &value) &&
+			    *value == '\0') {
+				/* optimization: X-BODY-FAST "" matches
+				   everything */
 				*args += 1;
 				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
 			return ARG_NEW_STR(SEARCH_BODY_FAST);
-		} else if (strcmp(str, "X-TEXT-FAST") == 0) {
+		} else if (strcmp(key, "X-TEXT-FAST") == 0) {
 			/* <string> */
-			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
-			    *IMAP_ARG_STR(*args) == '\0') {
+			if (imap_arg_get_astring(*args, &value) &&
+			    *value == '\0') {
+				/* optimization: X-TEXT-FAST "" matches
+				   everything */
 				*args += 1;
 				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
 			return ARG_NEW_STR(SEARCH_TEXT_FAST);
-		} else if (strcmp(str, "X-GUID") == 0) {
+		} else if (strcmp(key, "X-GUID") == 0) {
 			/* <string> */
 			return ARG_NEW_STR(SEARCH_GUID);
-		} else if (strcmp(str, "X-MAILBOX") == 0) {
+		} else if (strcmp(key, "X-MAILBOX") == 0) {
 			/* <string> */
 			return ARG_NEW_STR(SEARCH_MAILBOX);
 		}
 		break;
 	default:
-		if (*str == '*' || (*str >= '0' && *str <= '9')) {
+		if (*key == '*' || (*key >= '0' && *key <= '9')) {
 			/* <message-set> */
 			if (!ARG_NEW_SINGLE(SEARCH_SEQSET))
 				return FALSE;
 
 			p_array_init(&(*next_sarg)->value.seqset,
 				     data->pool, 16);
-			if (imap_seq_set_parse(str, &(*next_sarg)->value.seqset) < 0) {
+			if (imap_seq_set_parse(key, &(*next_sarg)->value.seqset) < 0) {
 				data->error = "Invalid messageset";
 				return FALSE;
 			}
 			return TRUE;
-		} else if (strcmp(str, "$") == 0) {
+		} else if (strcmp(key, "$") == 0) {
 			/* SEARCHRES: delay initialization */
 			if (!ARG_NEW_SINGLE(SEARCH_UIDSET))
 				return FALSE;
@@ -633,7 +622,7 @@
 		break;
 	}
 
-	data->error = t_strconcat("Unknown argument ", str, NULL);
+	data->error = t_strconcat("Unknown argument ", key, NULL);
 	return FALSE;
 }
 
@@ -656,7 +645,7 @@
 	data.error = NULL;
 
 	sargs = &args->args;
-	while (imap_args->type != IMAP_ARG_EOL) {
+	while (!IMAP_ARG_IS_EOL(imap_args)) {
 		if (!search_arg_build(&data, &imap_args, sargs)) {
 			pool_unref(&args->pool);
 			*error_r = data.error;
--- a/src/plugins/imap-quota/imap-quota-plugin.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/plugins/imap-quota/imap-quota-plugin.c	Mon Apr 05 07:54:55 2010 +0300
@@ -158,16 +158,16 @@
 static bool cmd_setquota(struct client_command_context *cmd)
 {
 	struct quota_root *root;
-        const struct imap_arg *args, *arg;
-	const char *root_name, *name, *error;
+        const struct imap_arg *args, *list_args;
+	const char *root_name, *name, *value_str, *error;
 	uint64_t value;
 
 	/* <quota root> <resource limits> */
 	if (!client_read_args(cmd, 2, 0, &args))
 		return FALSE;
 
-	root_name = imap_arg_string(&args[0]);
-	if (args[1].type != IMAP_ARG_LIST || root_name == NULL) {
+	if (!imap_arg_get_astring(&args[0], &root_name) ||
+	    !imap_arg_get_list(&args[1], &list_args)) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
@@ -178,16 +178,15 @@
 		return TRUE;
 	}
 
-        arg = IMAP_ARG_LIST_ARGS(&args[1]);
-	for (; arg->type != IMAP_ARG_EOL; arg += 2) {
-		name = imap_arg_string(arg);
-		if (name == NULL || arg[1].type != IMAP_ARG_ATOM ||
-		    !is_numeric(IMAP_ARG_STR(&arg[1]), '\0')) {
+	for (; !IMAP_ARG_IS_EOL(list_args); list_args += 2) {
+		if (!imap_arg_get_atom(&list_args[0], &name) ||
+		    !imap_arg_get_atom(&list_args[1], &value_str) ||
+		    !is_numeric(value_str, '\0')) {
 			client_send_command_error(cmd, "Invalid arguments.");
 			return TRUE;
 		}
 
-                value = strtoull(IMAP_ARG_STR_NONULL(&arg[1]), NULL, 10);
+                value = strtoull(value_str, NULL, 10);
 		if (quota_set_resource(root, name, value, &error) < 0) {
 			client_send_command_error(cmd, error);
 			return TRUE;
--- a/src/plugins/imap-zlib/imap-zlib-plugin.c	Mon Apr 05 05:19:24 2010 +0300
+++ b/src/plugins/imap-zlib/imap-zlib-plugin.c	Mon Apr 05 07:54:55 2010 +0300
@@ -76,8 +76,8 @@
 	if (!client_read_args(cmd, 0, 0, &args))
 		return FALSE;
 
-	mechanism = imap_arg_string(&args[0]);
-	if (mechanism == NULL || args[1].type != IMAP_ARG_EOL) {
+	if (!imap_arg_get_atom(args, &mechanism) ||
+	    !IMAP_ARG_IS_EOL(&args[1])) {
 		client_send_command_error(cmd, "Invalid arguments.");
 		return TRUE;
 	}
@@ -93,7 +93,6 @@
 		return TRUE;
 	}
 
-
 	handler = zlib_find_zlib_handler(t_str_lcase(mechanism));
 	if (handler == NULL || handler->create_istream == NULL) {
 		client_send_tagline(cmd, "NO Unknown compression mechanism.");