changeset 7642:077bb84e9e77 HEAD

Make mail_search_args an independent structure that can be used for multiple separate searches.
author Timo Sirainen <tss@iki.fi>
date Wed, 04 Jun 2008 00:51:58 +0300
parents d5cae1f5fb6a
children 803e3574f4f5
files src/imap/cmd-copy.c src/imap/cmd-expunge.c src/imap/cmd-fetch.c src/imap/cmd-search.c src/imap/cmd-select.c src/imap/cmd-sort.c src/imap/cmd-store.c src/imap/cmd-thread.c src/imap/imap-expunge.c src/imap/imap-expunge.h src/imap/imap-fetch.c src/imap/imap-fetch.h src/imap/imap-search.c src/imap/imap-search.h src/imap/imap-sort.c src/imap/imap-sort.h src/imap/imap-thread.c src/imap/imap-thread.h src/lib-storage/index/index-search.c src/lib-storage/index/index-storage.h src/lib-storage/mail-search-build.c src/lib-storage/mail-search-build.h src/lib-storage/mail-search.c src/lib-storage/mail-search.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/plugins/convert/convert-storage.c src/plugins/expire/expire-tool.c src/plugins/fts-squat/fts-backend-squat.c src/plugins/fts/fts-search.c src/plugins/fts/fts-storage.c src/plugins/fts/fts-storage.h src/plugins/mbox-snarf/mbox-snarf-plugin.c src/plugins/quota/quota-count.c src/plugins/quota/quota-storage.c src/plugins/trash/trash-plugin.c src/pop3/client.c src/pop3/commands.c
diffstat 39 files changed, 499 insertions(+), 364 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-copy.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-copy.c	Wed Jun 04 00:51:58 2008 +0300
@@ -28,7 +28,7 @@
 
 static int fetch_and_copy(struct client *client, struct mailbox *destbox,
 			  struct mailbox_transaction_context *t,
-			  struct mail_search_arg *search_args,
+			  struct mail_search_args *search_args,
 			  const char **src_uidset_r,
 			  unsigned int *copy_count_r)
 {
@@ -46,7 +46,7 @@
 	msgset_generator_init(&srcset_ctx, src_uidset);
 
 	src_trans = mailbox_transaction_begin(client->mailbox, 0);
-	search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL);
+	search_ctx = mailbox_search_init(src_trans, search_args, NULL);
 
 	mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
 			  MAIL_FETCH_STREAM_BODY, NULL);
@@ -90,7 +90,7 @@
 	struct mail_storage *storage;
 	struct mailbox *destbox;
 	struct mailbox_transaction_context *t;
-        struct mail_search_arg *search_arg;
+        struct mail_search_args *search_args;
 	const char *messageset, *mailbox, *src_uidset, *msg = NULL;
 	enum mailbox_sync_flags sync_flags = 0;
 	enum imap_sync_flags imap_flags = 0;
@@ -109,7 +109,7 @@
 	if (!client_verify_mailbox_name(cmd, mailbox, TRUE, FALSE))
 		return TRUE;
 
-	ret = imap_search_get_seqset(cmd, messageset, cmd->uid, &search_arg);
+	ret = imap_search_get_seqset(cmd, messageset, cmd->uid, &search_args);
 	if (ret <= 0)
 		return ret < 0;
 
@@ -135,8 +135,9 @@
 	t = mailbox_transaction_begin(destbox,
 				      MAILBOX_TRANSACTION_FLAG_EXTERNAL |
 				      MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS);
-	ret = fetch_and_copy(client, destbox, t, search_arg,
+	ret = fetch_and_copy(client, destbox, t, search_args,
 			     &src_uidset, &copy_count);
+	mail_search_args_unref(&search_args);
 
 	if (ret <= 0)
 		mailbox_transaction_rollback(&t);
--- a/src/imap/cmd-expunge.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-expunge.c	Wed Jun 04 00:51:58 2008 +0300
@@ -36,15 +36,17 @@
 }
 
 static bool cmd_expunge_finish(struct client_command_context *cmd,
-			       struct mail_search_arg *search_arg)
+			       struct mail_search_args *search_args)
 {
 	struct client *client = cmd->client;
 
-	if (imap_expunge(client->mailbox, search_arg) < 0) {
+	if (imap_expunge(client->mailbox, search_args->args) < 0) {
 		client_send_storage_error(cmd,
 					  mailbox_get_storage(client->mailbox));
 		return TRUE;
 	}
+	if (search_args != NULL)
+		mail_search_args_unref(&search_args);
 
 	client->sync_seen_deletes = FALSE;
 	client->sync_seen_expunges = FALSE;
@@ -60,7 +62,7 @@
 bool cmd_uid_expunge(struct client_command_context *cmd)
 {
 	const struct imap_arg *args;
-	struct mail_search_arg *search_arg;
+	struct mail_search_args *search_args;
 	const char *uidset;
 	int ret;
 
@@ -76,10 +78,10 @@
 		return TRUE;
 	}
 
-	ret = imap_search_get_seqset(cmd, uidset, TRUE, &search_arg);
+	ret = imap_search_get_seqset(cmd, uidset, TRUE, &search_args);
 	if (ret <= 0)
 		return ret < 0;
-	return cmd_expunge_finish(cmd, search_arg);
+	return cmd_expunge_finish(cmd, search_args);
 }
 
 bool cmd_expunge(struct client_command_context *cmd)
--- a/src/imap/cmd-fetch.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-fetch.c	Wed Jun 04 00:51:58 2008 +0300
@@ -117,8 +117,8 @@
 			return FALSE;
 	}
 	if (ctx->send_vanished &&
-	    (ctx->search_args->next == NULL ||
-	     ctx->search_args->next->type != SEARCH_MODSEQ)) {
+	    (ctx->search_args->args->next == NULL ||
+	     ctx->search_args->args->next->type != SEARCH_MODSEQ)) {
 		client_send_command_error(ctx->cmd,
 			"VANISHED used without CHANGEDSINCE");
 		return FALSE;
@@ -175,7 +175,7 @@
 	struct client *client = cmd->client;
 	struct imap_fetch_context *ctx;
 	const struct imap_arg *args;
-	struct mail_search_arg *search_arg;
+	struct mail_search_args *search_args;
 	const char *messageset;
 	int ret;
 
@@ -196,14 +196,14 @@
 
 	/* UID FETCH VANISHED needs the uidset, so convert it to
 	   sequence set later */
-	ret = imap_search_get_anyset(cmd, messageset, cmd->uid, &search_arg);
+	ret = imap_search_get_anyset(cmd, messageset, cmd->uid, &search_args);
 	if (ret <= 0)
 		return ret < 0;
 
 	ctx = imap_fetch_init(cmd, client->mailbox);
 	if (ctx == NULL)
 		return TRUE;
-	ctx->search_args = search_arg;
+	ctx->search_args = search_args;
 
 	if (!fetch_parse_args(ctx, &args[1]) ||
 	    (args[2].type == IMAP_ARG_LIST &&
--- a/src/imap/cmd-search.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-search.c	Wed Jun 04 00:51:58 2008 +0300
@@ -5,7 +5,6 @@
 #include "str.h"
 #include "seq-range-array.h"
 #include "commands.h"
-#include "mail-search.h"
 #include "mail-search-build.h"
 #include "imap-quote.h"
 #include "imap-util.h"
@@ -29,7 +28,7 @@
 	struct mailbox_transaction_context *trans;
         struct mail_search_context *search_ctx;
 	struct mail *mail;
-	struct mail_search_arg *sargs;
+	struct mail_search_args *sargs;
 	enum search_return_options return_options;
 
 	struct timeout *to;
@@ -98,10 +97,10 @@
 }
 
 static struct imap_search_context *
-imap_search_init(struct imap_search_context *ctx, const char *charset,
-		 struct mail_search_arg *sargs)
+imap_search_init(struct imap_search_context *ctx,
+		 struct mail_search_args *sargs)
 {
-	if (imap_search_args_have_modseq(sargs)) {
+	if (imap_search_args_have_modseq(sargs->args)) {
 		ctx->return_options |= SEARCH_RETURN_MODSEQ;
 		client_enable(ctx->cmd->client, MAILBOX_FEATURE_CONDSTORE);
 	}
@@ -109,7 +108,7 @@
 	ctx->box = ctx->cmd->client->mailbox;
 	ctx->trans = mailbox_transaction_begin(ctx->box, 0);
 	ctx->sargs = sargs;
-	ctx->search_ctx = mailbox_search_init(ctx->trans, charset, sargs, NULL);
+	ctx->search_ctx = mailbox_search_init(ctx->trans, sargs, NULL);
 	ctx->mail = mail_alloc(ctx->trans, 0, NULL);
 	(void)gettimeofday(&ctx->start_time, NULL);
 	i_array_init(&ctx->result, 128);
@@ -212,7 +211,8 @@
 	if (ctx->to != NULL)
 		timeout_remove(&ctx->to);
 	array_free(&ctx->result);
-	mail_search_args_deinit(ctx->sargs, ctx->box);
+	mail_search_args_deinit(ctx->sargs);
+	mail_search_args_unref(&ctx->sargs);
 
 	ctx->cmd->context = NULL;
 	return ret;
@@ -358,7 +358,7 @@
 {
 	struct client *client = cmd->client;
 	struct imap_search_context *ctx;
-	struct mail_search_arg *sargs;
+	struct mail_search_args *sargs;
 	const struct imap_arg *args;
 	enum search_return_options return_options;
 	int ret, args_count;
@@ -426,11 +426,11 @@
 		charset = "UTF-8";
 	}
 
-	ret = imap_search_args_build(cmd, args, &sargs);
+	ret = imap_search_args_build(cmd, args, charset, &sargs);
 	if (ret <= 0)
 		return ret < 0;
 
-	imap_search_init(ctx, charset, sargs);
+	imap_search_init(ctx, sargs);
 	cmd->func = cmd_search_more;
 	cmd->context = ctx;
 
--- a/src/imap/cmd-select.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-select.c	Wed Jun 04 00:51:58 2008 +0300
@@ -3,7 +3,7 @@
 #include "common.h"
 #include "seq-range-array.h"
 #include "commands.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "imap-messageset.h"
 #include "imap-fetch.h"
 #include "imap-sync.h"
@@ -217,17 +217,18 @@
 static int select_qresync(struct imap_select_context *ctx)
 {
 	struct imap_fetch_context *fetch_ctx;
-	struct mail_search_arg *search_arg;
+	struct mail_search_args *search_args;
 
-	search_arg = p_new(ctx->cmd->pool, struct mail_search_arg, 1);
-	search_arg->type = SEARCH_UIDSET;
-	search_arg->value.seqset = ctx->qresync_known_uids;
+	search_args = mail_search_build_init();
+	search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
+	search_args->args->type = SEARCH_UIDSET;
+	search_args->args->value.seqset = ctx->qresync_known_uids;
 
 	fetch_ctx = imap_fetch_init(ctx->cmd, ctx->box);
 	if (fetch_ctx == NULL)
 		return -1;
 
-	fetch_ctx->search_args = search_arg;
+	fetch_ctx->search_args = search_args;
 	fetch_ctx->send_vanished = TRUE;
 	fetch_ctx->qresync_sample_seqset = &ctx->qresync_sample_seqset;
 	fetch_ctx->qresync_sample_uidset = &ctx->qresync_sample_uidset;
--- a/src/imap/cmd-sort.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-sort.c	Wed Jun 04 00:51:58 2008 +0300
@@ -85,7 +85,7 @@
 bool cmd_sort(struct client_command_context *cmd)
 {
 	struct client *client = cmd->client;
-	struct mail_search_arg *sargs;
+	struct mail_search_args *sargs;
 	enum mail_sort_type sorting[MAX_SORT_PROGRAM_SIZE];
 	const struct imap_arg *args;
 	int args_count;
@@ -125,11 +125,13 @@
 	charset = IMAP_ARG_STR(args);
 	args++;
 
-	ret = imap_search_args_build(cmd, args, &sargs);
+	ret = imap_search_args_build(cmd, args, charset, &sargs);
 	if (ret <= 0)
 		return ret < 0;
 
-	if (imap_sort(cmd, charset, sargs, sorting) < 0) {
+	ret = imap_sort(cmd, sargs, sorting);
+	mail_search_args_unref(&sargs);
+	if (ret < 0) {
 		client_send_storage_error(cmd,
 					  mailbox_get_storage(client->mailbox));
 		return TRUE;
--- a/src/imap/cmd-store.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-store.c	Wed Jun 04 00:51:58 2008 +0300
@@ -117,7 +117,7 @@
 {
 	struct client *client = cmd->client;
 	const struct imap_arg *args;
-	struct mail_search_arg *search_arg;
+	struct mail_search_args *search_args;
 	struct mail_search_context *search_ctx;
         struct mailbox_transaction_context *t;
 	struct mail *mail;
@@ -140,7 +140,7 @@
 		return TRUE;
 	}
 	ret = imap_search_get_seqset(cmd, IMAP_ARG_STR_NONULL(args),
-				     cmd->uid, &search_arg);
+				     cmd->uid, &search_args);
 	if (ret <= 0)
 		return ret < 0;
 
@@ -154,7 +154,8 @@
 	if (ctx.max_modseq < (uint64_t)-1)
 		flags |= MAILBOX_TRANSACTION_FLAG_REFRESH;
 	t = mailbox_transaction_begin(client->mailbox, flags);
-	search_ctx = mailbox_search_init(t, NULL, search_arg, NULL);
+	search_ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
 	/* FIXME: UNCHANGEDSINCE should be atomic, but this requires support
 	   from mail-storage API. So for now we fake it. */
--- a/src/imap/cmd-thread.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/cmd-thread.c	Wed Jun 04 00:51:58 2008 +0300
@@ -10,7 +10,7 @@
 {
 	struct client *client = cmd->client;
 	enum mail_thread_type threading;
-	struct mail_search_arg *sargs;
+	struct mail_search_args *sargs;
 	const struct imap_arg *args;
 	int ret, args_count;
 	const char *charset, *str;
@@ -57,11 +57,13 @@
 	charset = IMAP_ARG_STR(args);
 	args++;
 
-	ret = imap_search_args_build(cmd, args, &sargs);
+	ret = imap_search_args_build(cmd, args, charset, &sargs);
 	if (ret <= 0)
 		return ret < 0;
 
-	if (imap_thread(cmd, charset, sargs, threading) < 0) {
+	ret = imap_thread(cmd, sargs, threading);
+	mail_search_args_unref(&sargs);
+	if (ret < 0) {
 		client_send_storage_error(cmd,
 					  mailbox_get_storage(client->mailbox));
 		return TRUE;
--- a/src/imap/imap-expunge.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-expunge.c	Wed Jun 04 00:51:58 2008 +0300
@@ -2,7 +2,7 @@
 
 #include "common.h"
 #include "mail-storage.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "imap-expunge.h"
 
 int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg)
@@ -10,7 +10,7 @@
 	struct mail_search_context *ctx;
         struct mailbox_transaction_context *t;
 	struct mail *mail;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	bool expunges = FALSE;
 
 	if (mailbox_is_readonly(box)) {
@@ -18,15 +18,17 @@
 		return 0;
 	}
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_FLAGS;
-	search_arg.value.flags = MAIL_DELETED;
-	search_arg.next = next_search_arg;
+	search_args = mail_search_build_init();
+	search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
+	search_args->args->type = SEARCH_FLAGS;
+	search_args->args->value.flags = MAIL_DELETED;
+	search_args->args->next = next_search_arg;
 
 	/* Refresh the flags so we'll expunge all messages marked as \Deleted
 	   by any session. */
 	t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_REFRESH);
-	ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
+	ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
 	mail = mail_alloc(t, 0, NULL);
 	while (mailbox_search_next(ctx, mail) > 0) {
--- a/src/imap/imap-expunge.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-expunge.h	Wed Jun 04 00:51:58 2008 +0300
@@ -1,6 +1,8 @@
 #ifndef IMAP_EXPUNGE_H
 #define IMAP_EXPUNGE_H
 
+struct mail_search_arg;
+
 int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg);
 
 #endif
--- a/src/imap/imap-fetch.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-fetch.c	Wed Jun 04 00:51:58 2008 +0300
@@ -9,7 +9,6 @@
 #include "message-send.h"
 #include "message-size.h"
 #include "imap-date.h"
-#include "mail-search.h"
 #include "mail-search-build.h"
 #include "commands.h"
 #include "imap-fetch.h"
@@ -113,14 +112,14 @@
 {
 	struct mail_search_arg *search_arg;
 
-	search_arg = p_new(ctx->cmd->pool, struct mail_search_arg, 1);
+	search_arg = p_new(ctx->search_args->pool, struct mail_search_arg, 1);
 	search_arg->type = SEARCH_MODSEQ;
 	search_arg->value.modseq =
 		p_new(ctx->cmd->pool, struct mail_search_modseq, 1);
 	search_arg->value.modseq->modseq = modseq;
 
-	search_arg->next = ctx->search_args->next;
-	ctx->search_args->next = search_arg;
+	search_arg->next = ctx->search_args->args->next;
+	ctx->search_args->args->next = search_arg;
 
 	return imap_fetch_init_handler(ctx, "MODSEQ", NULL);
 }
@@ -200,7 +199,7 @@
 				 ARRAY_TYPE(seq_range) *expunges)
 {
 	struct mailbox_transaction_context *trans;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail_search_context *search_ctx;
 	struct mail *mail;
 	const struct seq_range *uid_range;
@@ -215,14 +214,17 @@
 	next_uid = uid_range[0].seq1;
 
 	/* search UIDs in given range */
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_UIDSET;
-	i_array_init(&search_arg.value.seqset, array_count(uids));
-	array_append_array(&search_arg.value.seqset, uids);
+	search_args = mail_search_build_init();
+	search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
+	search_args->args->type = SEARCH_UIDSET;
+	i_array_init(&search_args->args->value.seqset, array_count(uids));
+	array_append_array(&search_args->args->value.seqset, uids);
 
 	trans = mailbox_transaction_begin(ctx->box, 0);
 	mail = mail_alloc(trans, 0, NULL);
-	search_ctx = mailbox_search_init(trans, NULL, &search_arg, NULL);
+	search_ctx = mailbox_search_init(trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	while (mailbox_search_next(search_ctx, mail) > 0) {
 		if (mail->uid == next_uid) {
 			if (next_uid < uid_range[i].seq2)
@@ -279,7 +281,7 @@
 static int
 imap_fetch_send_vanished(struct imap_fetch_context *ctx)
 {
-	const struct mail_search_arg *uidarg = ctx->search_args;
+	const struct mail_search_arg *uidarg = ctx->search_args->args;
 	const struct mail_search_arg *modseqarg = uidarg->next;
 	const ARRAY_TYPE(seq_range) *uids = &uidarg->value.seqset;
 	uint64_t modseq = modseqarg->value.modseq->modseq;
@@ -352,7 +354,7 @@
 	mail_search_args_init(ctx->search_args, ctx->box, TRUE,
 			      &ctx->cmd->client->search_saved_uidset);
 	ctx->search_ctx =
-		mailbox_search_init(ctx->trans, NULL, ctx->search_args, NULL);
+		mailbox_search_init(ctx->trans, ctx->search_args, NULL);
 	return 0;
 }
 
--- a/src/imap/imap-fetch.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-fetch.h	Wed Jun 04 00:51:58 2008 +0300
@@ -33,7 +33,7 @@
 	struct mailbox *box;
 
 	struct mailbox_transaction_context *trans;
-	struct mail_search_arg *search_args;
+	struct mail_search_args *search_args;
 	struct mail_search_context *search_ctx;
 	struct mail *mail;
 
--- a/src/imap/imap-search.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-search.c	Wed Jun 04 00:51:58 2008 +0300
@@ -2,7 +2,6 @@
 
 #include "common.h"
 #include "mail-storage.h"
-#include "mail-search.h"
 #include "mail-search-build.h"
 #include "imap-search.h"
 #include "imap-parser.h"
@@ -37,19 +36,19 @@
 }
 
 int imap_search_args_build(struct client_command_context *cmd,
-			   const struct imap_arg *args,
-			   struct mail_search_arg **search_args_r)
+			   const struct imap_arg *args, const char *charset,
+			   struct mail_search_args **search_args_r)
 {
-	struct mail_search_arg *sargs;
+	struct mail_search_args *sargs;
 	const char *error;
 
-	sargs = mail_search_build_from_imap_args(cmd->pool, args, &error);
-	if (sargs == NULL) {
+	if (mail_search_build_from_imap_args(args, charset,
+					     &sargs, &error) < 0) {
 		client_send_command_error(cmd, error);
 		return -1;
 	}
 
-	if (search_args_have_searchres(sargs)) {
+	if (search_args_have_searchres(sargs->args)) {
 		if (client_handle_search_save_ambiguity(cmd))
 			return 0;
 	}
@@ -89,51 +88,54 @@
 
 static int imap_search_get_msgset_arg(struct client_command_context *cmd,
 				      const char *messageset,
-				      struct mail_search_arg **arg_r,
+				      struct mail_search_args **args_r,
 				      const char **error_r)
 {
-	struct mail_search_arg *arg;
+	struct mail_search_args *args;
 
-	arg = p_new(cmd->pool, struct mail_search_arg, 1);
-	arg->type = SEARCH_SEQSET;
-	p_array_init(&arg->value.seqset, cmd->pool, 16);
-	if (imap_messageset_parse(&arg->value.seqset, messageset) < 0 ||
-	    !msgset_is_valid(&arg->value.seqset, cmd->client->messages_count)) {
+	args = mail_search_build_init();
+	args->args = p_new(args->pool, struct mail_search_arg, 1);
+	args->args->type = SEARCH_SEQSET;
+	p_array_init(&args->args->value.seqset, args->pool, 16);
+	if (imap_messageset_parse(&args->args->value.seqset, messageset) < 0 ||
+	    !msgset_is_valid(&args->args->value.seqset,
+			     cmd->client->messages_count)) {
 		*error_r = "Invalid messageset";
 		return -1;
 	}
-	*arg_r = arg;
+	*args_r = args;
 	return 0;
 }
 
 static int
 imap_search_get_uidset_arg(struct client_command_context *cmd,
-			   const char *uidset,
-			   struct mail_search_arg **arg_r, const char **error_r)
+			   const char *uidset, struct mail_search_args **args_r,
+			   const char **error_r)
 {
-	struct mail_search_arg *arg;
+	struct mail_search_args *args;
 
-	arg = p_new(cmd->pool, struct mail_search_arg, 1);
-	arg->type = SEARCH_UIDSET;
-	p_array_init(&arg->value.seqset, cmd->pool, 16);
-	if (imap_messageset_parse(&arg->value.seqset, uidset) < 0) {
+	args = mail_search_build_init();
+	args->args = p_new(args->pool, struct mail_search_arg, 1);
+	args->args->type = SEARCH_UIDSET;
+	p_array_init(&args->args->value.seqset, cmd->pool, 16);
+	if (imap_messageset_parse(&args->args->value.seqset, uidset) < 0) {
 		*error_r = "Invalid uidset";
 		return -1;
 	}
 
-	*arg_r = arg;
+	*args_r = args;
 	return 0;
 }
 
 int imap_search_get_seqset(struct client_command_context *cmd,
 			   const char *set, bool uid,
-			   struct mail_search_arg **search_arg_r)
+			   struct mail_search_args **search_args_r)
 {
 	int ret;
 
-	ret = imap_search_get_anyset(cmd, set, uid, search_arg_r);
+	ret = imap_search_get_anyset(cmd, set, uid, search_args_r);
 	if (ret > 0) {
-		mail_search_args_init(*search_arg_r,
+		mail_search_args_init(*search_args_r,
 				      cmd->client->mailbox, TRUE,
 				      &cmd->client->search_saved_uidset);
 	}
@@ -141,31 +143,34 @@
 }
 
 static int imap_search_get_searchres(struct client_command_context *cmd,
-				     struct mail_search_arg **search_arg_r)
+				     struct mail_search_args **search_args_r)
 {
-	struct mail_search_arg *search_arg;
+	struct mail_search_args *search_args;
 
 	if (client_handle_search_save_ambiguity(cmd))
 		return 0;
-	search_arg = p_new(cmd->pool, struct mail_search_arg, 1);
+
+	search_args = mail_search_build_init();
+	search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
 	if (array_is_created(&cmd->client->search_saved_uidset)) {
-		search_arg->type = SEARCH_UIDSET;
-		p_array_init(&search_arg->value.seqset, cmd->pool,
+		search_args->args->type = SEARCH_UIDSET;
+		p_array_init(&search_args->args->value.seqset,
+			     search_args->pool,
 			     array_count(&cmd->client->search_saved_uidset));
-		array_append_array(&search_arg->value.seqset,
+		array_append_array(&search_args->args->value.seqset,
 				   &cmd->client->search_saved_uidset);
 	} else {
 		/* $ not set yet, match nothing */
-		search_arg->type = SEARCH_ALL;
-		search_arg->not = TRUE;
+		search_args->args->type = SEARCH_ALL;
+		search_args->args->not = TRUE;
 	}
-	*search_arg_r = search_arg;
+	*search_args_r = search_args;
 	return 1;
 }
 
 int imap_search_get_anyset(struct client_command_context *cmd,
 			   const char *set, bool uid,
-			   struct mail_search_arg **search_arg_r)
+			   struct mail_search_args **search_args_r)
 {
 	const char *error = NULL;
 	int ret;
@@ -173,12 +178,15 @@
 	if (strcmp(set, "$") == 0) {
 		/* SEARCHRES extension: replace $ with the last saved
 		   search result */
-		return imap_search_get_searchres(cmd, search_arg_r);
+		return imap_search_get_searchres(cmd, search_args_r);
 	}
-	if (!uid)
-		ret = imap_search_get_msgset_arg(cmd, set, search_arg_r, &error);
-	else
-		ret = imap_search_get_uidset_arg(cmd, set, search_arg_r, &error);
+	if (!uid) {
+		ret = imap_search_get_msgset_arg(cmd, set, search_args_r,
+						 &error);
+	} else {
+		ret = imap_search_get_uidset_arg(cmd, set, search_args_r,
+						 &error);
+	}
 	if (ret < 0) {
 		client_send_command_error(cmd, error);
 		return -1;
--- a/src/imap/imap-search.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-search.h	Wed Jun 04 00:51:58 2008 +0300
@@ -1,6 +1,8 @@
 #ifndef IMAP_SEARCH_H
 #define IMAP_SEARCH_H
 
+#include "mail-search.h"
+
 struct imap_arg;
 struct mailbox;
 struct client_command_context;
@@ -9,16 +11,16 @@
    arguments are invalid, 0 if we have to wait for unambiguity,
    1 if we can continue. */
 int imap_search_args_build(struct client_command_context *cmd,
-			   const struct imap_arg *args,
-			   struct mail_search_arg **search_args_r);
+			   const struct imap_arg *args, const char *charset,
+			   struct mail_search_args **search_args_r);
 
 /* Returns -1 if set is invalid, 0 if we have to wait for unambiguity,
    1 if we can continue. */
 int imap_search_get_seqset(struct client_command_context *cmd,
 			   const char *set, bool uid,
-			   struct mail_search_arg **search_arg_r);
+			   struct mail_search_args **search_args_r);
 int imap_search_get_anyset(struct client_command_context *cmd,
 			   const char *set, bool uid,
-			   struct mail_search_arg **search_arg_r);
+			   struct mail_search_args **search_args_r);
 
 #endif
--- a/src/imap/imap-sort.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-sort.c	Wed Jun 04 00:51:58 2008 +0300
@@ -37,8 +37,7 @@
 	bool written;
 };
 
-int imap_sort(struct client_command_context *cmd, const char *charset,
-	      struct mail_search_arg *args,
+int imap_sort(struct client_command_context *cmd, struct mail_search_args *args,
 	      const enum mail_sort_type *sort_program)
 {
 	struct client *client = cmd->client;
@@ -82,7 +81,7 @@
 		mailbox_header_lookup_init(client->mailbox, wanted_headers);
 
 	t = mailbox_transaction_begin(client->mailbox, 0);
-	search_ctx = mailbox_search_init(t, charset, args, sort_program);
+	search_ctx = mailbox_search_init(t, args, sort_program);
 
 	str = t_str_new(STRBUF_SIZE);
 	str_append(str, "* SORT");
--- a/src/imap/imap-sort.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-sort.h	Wed Jun 04 00:51:58 2008 +0300
@@ -1,8 +1,7 @@
 #ifndef IMAP_SORT_H
 #define IMAP_SORT_H
 
-int imap_sort(struct client_command_context *cmd, const char *charset,
-	      struct mail_search_arg *args,
+int imap_sort(struct client_command_context *cmd, struct mail_search_args *args,
 	      const enum mail_sort_type *sort_program);
 
 #endif
--- a/src/imap/imap-thread.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-thread.c	Wed Jun 04 00:51:58 2008 +0300
@@ -101,8 +101,8 @@
 	pool_unref(&ctx->pool);
 }
 
-int imap_thread(struct client_command_context *cmd, const char *charset,
-		struct mail_search_arg *args, enum mail_thread_type type)
+int imap_thread(struct client_command_context *cmd,
+		struct mail_search_args *args, enum mail_thread_type type)
 {
 	static const char *wanted_headers[] = {
 		"message-id", "in-reply-to", "references", "subject",
@@ -121,7 +121,7 @@
 
 	/* initialize searching */
 	ctx->t = mailbox_transaction_begin(client->mailbox, 0);
-	ctx->search_ctx = mailbox_search_init(ctx->t, charset, args, NULL);
+	ctx->search_ctx = mailbox_search_init(ctx->t, args, NULL);
 
 	ctx->box = client->mailbox;
 	ctx->output = client->output;
--- a/src/imap/imap-thread.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/imap/imap-thread.h	Wed Jun 04 00:51:58 2008 +0300
@@ -7,7 +7,7 @@
 	MAIL_THREAD_REFERENCES
 };
 
-int imap_thread(struct client_command_context *cmd, const char *charset,
-		struct mail_search_arg *args, enum mail_thread_type type);
+int imap_thread(struct client_command_context *cmd,
+		struct mail_search_args *args, enum mail_thread_type type);
 
 #endif
--- a/src/lib-storage/index/index-search.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/index/index-search.c	Wed Jun 04 00:51:58 2008 +0300
@@ -329,7 +329,7 @@
 		MESSAGE_SEARCH_FLAG_SKIP_HEADERS : 0;
 
 	ret = message_search_init(ctx->search_pool, arg->value.str,
-				  ctx->mail_ctx.charset, flags,
+				  ctx->mail_ctx.args->charset, flags,
 				  &arg_ctx);
 	if (ret > 0) {
 		arg->context = arg_ctx;
@@ -849,7 +849,7 @@
 
 struct mail_search_context *
 index_storage_search_init(struct mailbox_transaction_context *_t,
-			  const char *charset, struct mail_search_arg *args,
+			  struct mail_search_args *args,
 			  const enum mail_sort_type *sort_program)
 {
 	struct index_transaction_context *t =
@@ -860,20 +860,19 @@
 	ctx->mail_ctx.transaction = _t;
 	ctx->ibox = t->ibox;
 	ctx->view = t->trans_view;
-	ctx->mail_ctx.charset = i_strdup(charset);
 	ctx->mail_ctx.args = args;
 	ctx->mail_ctx.sort_program = index_sort_program_init(_t, sort_program);
 
 	array_create(&ctx->mail_ctx.module_contexts, default_pool,
 		     sizeof(void *), 5);
 
-	mail_search_args_reset(ctx->mail_ctx.args, TRUE);
+	mail_search_args_reset(ctx->mail_ctx.args->args, TRUE);
 
-	search_get_seqset(ctx, args);
-	(void)mail_search_args_foreach(args, search_init_arg, ctx);
+	search_get_seqset(ctx, args->args);
+	(void)mail_search_args_foreach(args->args, search_init_arg, ctx);
 
 	/* Need to reset results for match_always cases */
-	mail_search_args_reset(ctx->mail_ctx.args, FALSE);
+	mail_search_args_reset(ctx->mail_ctx.args->args, FALSE);
 	return &ctx->mail_ctx;
 }
 
@@ -900,8 +899,8 @@
 				       MAIL_ERROR_PARAMS, ctx->error);
 	}
 
-	mail_search_args_reset(ctx->mail_ctx.args, FALSE);
-	(void)mail_search_args_foreach(ctx->mail_ctx.args,
+	mail_search_args_reset(ctx->mail_ctx.args->args, FALSE);
+	(void)mail_search_args_foreach(ctx->mail_ctx.args->args,
 				       search_arg_deinit, NULL);
 
 	if (ctx->search_pool != NULL)
@@ -910,7 +909,6 @@
 	if (ctx->mail_ctx.sort_program != NULL)
 		index_sort_program_deinit(&ctx->mail_ctx.sort_program);
 	array_free(&ctx->mail_ctx.module_contexts);
-	i_free(ctx->mail_ctx.charset);
 	i_free(ctx);
 	return ret;
 }
@@ -921,16 +919,16 @@
 	int ret;
 
 	/* next search only from cached arguments */
-	ret = mail_search_args_foreach(ctx->mail_ctx.args,
+	ret = mail_search_args_foreach(ctx->mail_ctx.args->args,
 				       search_cached_arg, ctx);
 	if (ret >= 0)
 		return ret > 0;
 
 	/* open the mail file and check the rest */
-	if (!search_arg_match_text(ctx->mail_ctx.args, ctx))
+	if (!search_arg_match_text(ctx->mail_ctx.args->args, ctx))
 		return FALSE;
 
-	for (arg = ctx->mail_ctx.args; arg != NULL; arg = arg->next) {
+	for (arg = ctx->mail_ctx.args->args; arg != NULL; arg = arg->next) {
 		if (arg->result != 1)
 			return FALSE;
 	}
@@ -1005,7 +1003,7 @@
 			ret = search_match_next(ctx) ? 1 : 0;
 		} T_END;
 
-		mail_search_args_reset(ctx->mail_ctx.args, FALSE);
+		mail_search_args_reset(ctx->mail_ctx.args->args, FALSE);
 
 		if (ctx->error != NULL)
 			ret = -1;
@@ -1056,14 +1054,14 @@
 	ret = 0;
 	while (_ctx->seq <= ctx->seq2) {
 		/* check if the sequence matches */
-		ret = mail_search_args_foreach(ctx->mail_ctx.args,
+		ret = mail_search_args_foreach(ctx->mail_ctx.args->args,
 					       search_seqset_arg, ctx);
 		if (ret != 0) {
 			/* check if flags/keywords match before anything else
 			   is done. mail_set_seq() can be a bit slow. */
 			if (!ctx->have_index_args)
 				break;
-			ret = mail_search_args_foreach(ctx->mail_ctx.args,
+			ret = mail_search_args_foreach(ctx->mail_ctx.args->args,
 						       search_index_arg, ctx);
 			if (ret != 0)
 				break;
@@ -1071,7 +1069,7 @@
 
 		/* doesn't, try next one */
 		_ctx->seq++;
-		mail_search_args_reset(ctx->mail_ctx.args, FALSE);
+		mail_search_args_reset(ctx->mail_ctx.args->args, FALSE);
 	}
 	return ret == 0 ? 0 : 1;
 }
--- a/src/lib-storage/index/index-storage.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/index/index-storage.h	Wed Jun 04 00:51:58 2008 +0300
@@ -156,7 +156,7 @@
 
 struct mail_search_context *
 index_storage_search_init(struct mailbox_transaction_context *t,
-			  const char *charset, struct mail_search_arg *args,
+			  struct mail_search_args *args,
 			  const enum mail_sort_type *sort_program);
 int index_storage_search_deinit(struct mail_search_context *ctx);
 int index_storage_search_next(struct mail_search_context *ctx,
--- a/src/lib-storage/mail-search-build.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-search-build.c	Wed Jun 04 00:51:58 2008 +0300
@@ -5,7 +5,6 @@
 #include "imap-date.h"
 #include "imap-parser.h"
 #include "imap-messageset.h"
-#include "mail-search.h"
 #include "mail-search-build.h"
 #include "mail-storage.h"
 
@@ -608,131 +607,71 @@
 	return FALSE;
 }
 
-struct mail_search_arg *
-mail_search_build_from_imap_args(pool_t pool, const struct imap_arg *args,
-				 const char **error_r)
+int mail_search_build_from_imap_args(const struct imap_arg *imap_args,
+				     const char *charset,
+				     struct mail_search_args **args_r,
+				     const char **error_r)
 {
         struct search_build_data data;
-	struct mail_search_arg *first_sarg, **sargs;
+	struct mail_search_args *args;
+	struct mail_search_arg **sargs;
 
-	data.pool = pool;
+	*args_r = NULL;
+	*error_r = NULL;
+
+	args = mail_search_build_init();
+	args->charset = p_strdup(args->pool, charset);
+
+	data.pool = args->pool;
 	data.error = NULL;
 
-	first_sarg = NULL; sargs = &first_sarg;
-	while (args->type != IMAP_ARG_EOL) {
-		if (!search_arg_build(&data, &args, sargs)) {
-			first_sarg = NULL;
-			break;
+	sargs = &args->args;
+	while (imap_args->type != IMAP_ARG_EOL) {
+		if (!search_arg_build(&data, &imap_args, sargs)) {
+			pool_unref(&args->pool);
+			*error_r = data.error;
+			return -1;
 		}
 		sargs = &(*sargs)->next;
 	}
 
-	*error_r = data.error;
-	return first_sarg;
+	*args_r = args;
+	return 0;
 }
 
-static void
-mailbox_uidset_change(struct mail_search_arg *arg, struct mailbox *box,
-		      const ARRAY_TYPE(seq_range) *search_saved_uidset)
+struct mail_search_args *mail_search_build_init(void)
 {
-	struct seq_range *uids;
-	unsigned int i, count;
-	uint32_t seq1, seq2;
-
-	if (strcmp(arg->value.str, "$") == 0) {
-		/* SEARCHRES: Replace with saved uidset */
-		array_clear(&arg->value.seqset);
-		if (search_saved_uidset == NULL ||
-		    !array_is_created(search_saved_uidset))
-			return;
-
-		array_append_array(&arg->value.seqset, search_saved_uidset);
-		return;
-	}
-
-	arg->type = SEARCH_SEQSET;
+	struct mail_search_args *args;
+	pool_t pool;
 
-	/* make a copy of the UIDs */
-	count = array_count(&arg->value.seqset);
-	if (count == 0) {
-		/* empty set, keep it */
-		return;
-	}
-	uids = t_new(struct seq_range, count);
-	memcpy(uids, array_idx(&arg->value.seqset, 0), sizeof(*uids) * count);
-
-	/* put them back to the range as sequences */
-	array_clear(&arg->value.seqset);
-	for (i = 0; i < count; i++) {
-		mailbox_get_uids(box, uids[i].seq1, uids[i].seq2, &seq1, &seq2);
-		if (seq1 != 0) {
-			seq_range_array_add_range(&arg->value.seqset,
-						  seq1, seq2);
-		}
-		if (uids[i].seq2 == (uint32_t)-1) {
-			/* make sure the last message is in the range */
-			mailbox_get_uids(box, 1, (uint32_t)-1, &seq1, &seq2);
-			seq_range_array_add(&arg->value.seqset, 0, seq2);
-		}
-	}
+	pool = pool_alloconly_create("mail search args", 1024);
+	args = p_new(pool, struct mail_search_args, 1);
+	args->pool = pool;
+	args->refcount = 1;
+	return args;
 }
 
-void mail_search_args_init(struct mail_search_arg *args,
-			   struct mailbox *box, bool change_uidsets,
-			   const ARRAY_TYPE(seq_range) *search_saved_uidset)
+void mail_search_build_add_all(struct mail_search_args *args)
 {
-	const char *keywords[2];
+	struct mail_search_arg *arg;
 
-	for (; args != NULL; args = args->next) {
-		switch (args->type) {
-		case SEARCH_UIDSET:
-			if (change_uidsets) T_BEGIN {
-				mailbox_uidset_change(args, box,
-						      search_saved_uidset);
-			} T_END;
-			break;
-		case SEARCH_MODSEQ:
-			if (args->value.str == NULL)
-				break;
-			/* modseq with keyword */
-		case SEARCH_KEYWORDS:
-			keywords[0] = args->value.str;
-			keywords[1] = NULL;
+	arg = p_new(args->pool, struct mail_search_arg, 1);
+	arg->type = SEARCH_ALL;
 
-			i_assert(args->value.keywords == NULL);
-			args->value.keywords =
-				mailbox_keywords_create_valid(box, keywords);
-			break;
-
-		case SEARCH_SUB:
-		case SEARCH_OR:
-			mail_search_args_init(args->value.subargs, box,
-					      change_uidsets,
-					      search_saved_uidset);
-			break;
-		default:
-			break;
-		}
-	}
+	arg->next = args->args;
+	args->args = arg;
 }
 
-void mail_search_args_deinit(struct mail_search_arg *args,
-			     struct mailbox *box)
+void mail_search_build_add_seqset(struct mail_search_args *args,
+				  uint32_t seq1, uint32_t seq2)
 {
-	for (; args != NULL; args = args->next) {
-		switch (args->type) {
-		case SEARCH_MODSEQ:
-		case SEARCH_KEYWORDS:
-			if (args->value.keywords == NULL)
-				break;
-			mailbox_keywords_free(box, &args->value.keywords);
-			break;
-		case SEARCH_SUB:
-		case SEARCH_OR:
-			mail_search_args_deinit(args->value.subargs, box);
-			break;
-		default:
-			break;
-		}
-	}
+	struct mail_search_arg *arg;
+
+	arg = p_new(args->pool, struct mail_search_arg, 1);
+	arg->type = SEARCH_SEQSET;
+	p_array_init(&arg->value.seqset, args->pool, 1);
+	seq_range_array_add_range(&arg->value.seqset, seq1, seq2);
+
+	arg->next = args->args;
+	args->args = arg;
 }
--- a/src/lib-storage/mail-search-build.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-search-build.h	Wed Jun 04 00:51:58 2008 +0300
@@ -1,20 +1,20 @@
 #ifndef MAIL_SEARCH_BUILD_H
 #define MAIL_SEARCH_BUILD_H
 
+#include "mail-search.h"
+
 struct imap_arg;
 struct mailbox;
 
-struct mail_search_arg *
-mail_search_build_from_imap_args(pool_t pool, const struct imap_arg *args,
-				 const char **error_r);
+struct mail_search_args *mail_search_build_init(void);
 
-/* Allocate keywords for search arguments. If change_uidsets is TRUE,
-   change uidsets to seqsets. */
-void mail_search_args_init(struct mail_search_arg *args,
-			   struct mailbox *box, bool change_uidsets,
-			   const ARRAY_TYPE(seq_range) *search_saved_uidset);
-/* Free keywords. The args can initialized afterwards again if needed. */
-void mail_search_args_deinit(struct mail_search_arg *args,
-			     struct mailbox *box);
+int mail_search_build_from_imap_args(const struct imap_arg *imap_args,
+				     const char *charset,
+				     struct mail_search_args **args_r,
+				     const char **error_r);
+
+void mail_search_build_add_all(struct mail_search_args *args);
+void mail_search_build_add_seqset(struct mail_search_args *args,
+				  uint32_t seq1, uint32_t seq2);
 
 #endif
--- a/src/lib-storage/mail-search.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-search.c	Wed Jun 04 00:51:58 2008 +0300
@@ -4,8 +4,151 @@
 #include "array.h"
 #include "buffer.h"
 #include "mail-index.h"
+#include "mail-storage.h"
 #include "mail-search.h"
 
+static void
+mailbox_uidset_change(struct mail_search_arg *arg, struct mailbox *box,
+		      const ARRAY_TYPE(seq_range) *search_saved_uidset)
+{
+	struct seq_range *uids;
+	unsigned int i, count;
+	uint32_t seq1, seq2;
+
+	if (arg->value.str != NULL && strcmp(arg->value.str, "$") == 0) {
+		/* SEARCHRES: Replace with saved uidset */
+		array_clear(&arg->value.seqset);
+		if (search_saved_uidset == NULL ||
+		    !array_is_created(search_saved_uidset))
+			return;
+
+		array_append_array(&arg->value.seqset, search_saved_uidset);
+		return;
+	}
+
+	arg->type = SEARCH_SEQSET;
+
+	/* make a copy of the UIDs */
+	count = array_count(&arg->value.seqset);
+	if (count == 0) {
+		/* empty set, keep it */
+		return;
+	}
+	uids = t_new(struct seq_range, count);
+	memcpy(uids, array_idx(&arg->value.seqset, 0), sizeof(*uids) * count);
+
+	/* put them back to the range as sequences */
+	array_clear(&arg->value.seqset);
+	for (i = 0; i < count; i++) {
+		mailbox_get_uids(box, uids[i].seq1, uids[i].seq2, &seq1, &seq2);
+		if (seq1 != 0) {
+			seq_range_array_add_range(&arg->value.seqset,
+						  seq1, seq2);
+		}
+		if (uids[i].seq2 == (uint32_t)-1) {
+			/* make sure the last message is in the range */
+			mailbox_get_uids(box, 1, (uint32_t)-1, &seq1, &seq2);
+			seq_range_array_add(&arg->value.seqset, 0, seq2);
+		}
+	}
+}
+
+static void
+mail_search_args_init_sub(struct mail_search_arg *args,
+			  struct mailbox *box, bool change_uidsets,
+			  const ARRAY_TYPE(seq_range) *search_saved_uidset)
+{
+	const char *keywords[2];
+
+	for (; args != NULL; args = args->next) {
+		switch (args->type) {
+		case SEARCH_UIDSET:
+			if (change_uidsets) T_BEGIN {
+				mailbox_uidset_change(args, box,
+						      search_saved_uidset);
+			} T_END;
+			break;
+		case SEARCH_MODSEQ:
+			if (args->value.str == NULL)
+				break;
+			/* modseq with keyword */
+		case SEARCH_KEYWORDS:
+			keywords[0] = args->value.str;
+			keywords[1] = NULL;
+
+			i_assert(args->value.keywords == NULL);
+			args->value.keywords =
+				mailbox_keywords_create_valid(box, keywords);
+			break;
+
+		case SEARCH_SUB:
+		case SEARCH_OR:
+			mail_search_args_init_sub(args->value.subargs, box,
+						  change_uidsets,
+						  search_saved_uidset);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void mail_search_args_init(struct mail_search_args *args,
+			   struct mailbox *box, bool change_uidsets,
+			   const ARRAY_TYPE(seq_range) *search_saved_uidset)
+{
+	args->box = box;
+	mail_search_args_init_sub(args->args, box, change_uidsets,
+				  search_saved_uidset);
+}
+
+static void mail_search_args_deinit_sub(struct mail_search_args *args,
+					struct mail_search_arg *arg)
+{
+	for (; arg != NULL; arg = arg->next) {
+		switch (arg->type) {
+		case SEARCH_MODSEQ:
+		case SEARCH_KEYWORDS:
+			if (arg->value.keywords == NULL)
+				break;
+			mailbox_keywords_free(args->box, &arg->value.keywords);
+			break;
+		case SEARCH_SUB:
+		case SEARCH_OR:
+			mail_search_args_deinit_sub(args, arg->value.subargs);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void mail_search_args_deinit(struct mail_search_args *args)
+{
+	mail_search_args_deinit_sub(args, args->args);
+}
+
+void mail_search_args_ref(struct mail_search_args *args)
+{
+	i_assert(args->refcount > 0);
+
+	args->refcount++;
+}
+
+void mail_search_args_unref(struct mail_search_args **_args)
+{
+	struct mail_search_args *args = *_args;
+
+	i_assert(args->refcount > 0);
+
+	*_args = NULL;
+	if (--args->refcount > 0)
+		return;
+
+	mail_search_args_deinit(args);
+	pool_unref(&args->pool);
+}
+
 void mail_search_args_reset(struct mail_search_arg *args, bool full_reset)
 {
 	while (args != NULL) {
--- a/src/lib-storage/mail-search.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-search.h	Wed Jun 04 00:51:58 2008 +0300
@@ -85,6 +85,14 @@
 	int result; /* -1 = unknown, 0 = unmatched, 1 = matched */
 };
 
+struct mail_search_args {
+	int refcount;
+	pool_t pool;
+	struct mailbox *box;
+	struct mail_search_arg *args;
+	const char *charset;
+};
+
 #define ARG_SET_RESULT(arg, res) \
 	STMT_START { \
 		(arg)->result = !(arg)->not ? (res) : \
@@ -94,6 +102,17 @@
 typedef void mail_search_foreach_callback_t(struct mail_search_arg *arg,
 					    void *context);
 
+/* Allocate keywords for search arguments. If change_uidsets is TRUE,
+   change uidsets to seqsets. */
+void mail_search_args_init(struct mail_search_args *args,
+			   struct mailbox *box, bool change_uidsets,
+			   const ARRAY_TYPE(seq_range) *search_saved_uidset);
+/* Free keywords. The args can initialized afterwards again if needed. */
+void mail_search_args_deinit(struct mail_search_args *args);
+
+void mail_search_args_ref(struct mail_search_args *args);
+void mail_search_args_unref(struct mail_search_args **args);
+
 /* Reset the results in search arguments. match_always is reset only if
    full_reset is TRUE. */
 void mail_search_args_reset(struct mail_search_arg *args, bool full_reset);
--- a/src/lib-storage/mail-storage-private.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-storage-private.h	Wed Jun 04 00:51:58 2008 +0300
@@ -141,7 +141,7 @@
 
 	struct mail_search_context *
 	(*search_init)(struct mailbox_transaction_context *t,
-		       const char *charset, struct mail_search_arg *args,
+		       struct mail_search_args *args,
 		       const enum mail_sort_type *sort_program);
 	int (*search_deinit)(struct mail_search_context *ctx);
 	int (*search_next_nonblock)(struct mail_search_context *ctx,
@@ -288,8 +288,7 @@
 struct mail_search_context {
 	struct mailbox_transaction_context *transaction;
 
-	char *charset;
-	struct mail_search_arg *args;
+	struct mail_search_args *args;
 	struct mail_search_sort_program *sort_program;
 
 	uint32_t seq;
--- a/src/lib-storage/mail-storage.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-storage.c	Wed Jun 04 00:51:58 2008 +0300
@@ -631,11 +631,11 @@
 
 struct mail_search_context *
 mailbox_search_init(struct mailbox_transaction_context *t,
-		    const char *charset, struct mail_search_arg *args,
+		    struct mail_search_args *args,
 		    const enum mail_sort_type *sort_program)
 {
-	mail_search_args_simplify(args);
-	return t->box->v.search_init(t, charset, args, sort_program);
+	mail_search_args_simplify(args->args);
+	return t->box->v.search_init(t, args, sort_program);
 }
 
 int mailbox_search_deinit(struct mail_search_context **_ctx)
--- a/src/lib-storage/mail-storage.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/lib-storage/mail-storage.h	Wed Jun 04 00:51:58 2008 +0300
@@ -158,7 +158,7 @@
 struct message_part;
 struct mail_namespace;
 struct mail_storage;
-struct mail_search_arg;
+struct mail_search_args;
 struct mail_keywords;
 struct mail_save_context;
 struct mailbox;
@@ -376,7 +376,7 @@
    returned in the requested order, otherwise from first to last. */
 struct mail_search_context *
 mailbox_search_init(struct mailbox_transaction_context *t,
-		    const char *charset, struct mail_search_arg *args,
+		    struct mail_search_args *args,
 		    const enum mail_sort_type *sort_program);
 /* Deinitialize search request. */
 int mailbox_search_deinit(struct mail_search_context **ctx);
--- a/src/plugins/convert/convert-storage.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/convert/convert-storage.c	Wed Jun 04 00:51:58 2008 +0300
@@ -6,7 +6,7 @@
 #include "file-dotlock.h"
 #include "mail-storage-private.h"
 #include "mail-namespace.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "convert-storage.h"
 
 #include <stdio.h>
@@ -35,7 +35,7 @@
 	struct mail_search_context *ctx;
 	struct mailbox_transaction_context *src_trans, *dest_trans;
 	struct mail *mail;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	int ret = 0;
 
 	if (mailbox_sync(srcbox, MAILBOX_SYNC_FLAG_FULL_READ, 0, NULL) < 0) {
@@ -44,14 +44,16 @@
 	}
 	*error_r = NULL;
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
 
 	src_trans = mailbox_transaction_begin(srcbox, 0);
 	dest_trans = mailbox_transaction_begin(destbox,
 					MAILBOX_TRANSACTION_FLAG_EXTERNAL);
 
-	ctx = mailbox_search_init(src_trans, NULL, &search_arg, NULL);
+	ctx = mailbox_search_init(src_trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	mail = mail_alloc(src_trans,
 			  MAIL_FETCH_FLAGS | MAIL_FETCH_RECEIVED_DATE |
 			  MAIL_FETCH_STREAM_HEADER | MAIL_FETCH_STREAM_BODY |
--- a/src/plugins/expire/expire-tool.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/expire/expire-tool.c	Wed Jun 04 00:51:58 2008 +0300
@@ -7,7 +7,7 @@
 #include "lib-signals.h"
 #include "dict-client.h"
 #include "mail-index.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-storage.h"
 #include "mail-namespace.h"
 #include "auth-client.h"
@@ -64,7 +64,7 @@
 	struct mailbox *box;
 	struct mail_search_context *search_ctx;
 	struct mailbox_transaction_context *t;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail *mail;
 	const char *ns_mailbox;
 	time_t now, save_time;
@@ -85,10 +85,6 @@
 		ctx->user = i_strdup(user);
 	}
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
-	search_arg.next = NULL;
-
 	ns_mailbox = mailbox;
 	ns = mail_namespace_find(ctx->ns, &ns_mailbox);
 	if (ns == NULL) {
@@ -108,8 +104,13 @@
 		return 0;
 	}
 
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+
 	t = mailbox_transaction_begin(box, 0);
-	search_ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
+	search_ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	mail = mail_alloc(t, 0, NULL);
 
 	now = time(NULL);
--- a/src/plugins/fts-squat/fts-backend-squat.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/fts-squat/fts-backend-squat.c	Wed Jun 04 00:51:58 2008 +0300
@@ -3,7 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "mail-storage-private.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "squat-trie.h"
 #include "fts-squat-plugin.h"
 
@@ -110,16 +110,18 @@
 {
 	struct mailbox_transaction_context *t;
 	struct mail_search_context *search_ctx;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail *mail;
 	int ret = 0;
 
 	t = mailbox_transaction_begin(box, 0);
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
+	mail = mail_alloc(t, 0, NULL);
 
-	mail = mail_alloc(t, 0, NULL);
-	search_ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	search_ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	while ((ret = mailbox_search_next(search_ctx, mail)) > 0) {
 		/* *2 because even/odd is for body/header */
 		seq_range_array_add_range(uids, mail->uid * 2,
--- a/src/plugins/fts/fts-search.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/fts/fts-search.c	Wed Jun 04 00:51:58 2008 +0300
@@ -86,7 +86,8 @@
 
 	/* convert key to titlecase */
 	key_utf8 = t_str_new(128);
-	if (charset_to_utf8_str(fctx->charset, CHARSET_FLAG_DECOMP_TITLECASE,
+	if (charset_to_utf8_str(fctx->args->charset,
+				CHARSET_FLAG_DECOMP_TITLECASE,
 				key, key_utf8, &result) < 0) {
 		/* unknown charset, can't handle this */
 		ret = 0;
@@ -123,7 +124,7 @@
 		ret = fts_search_lookup_arg(fctx, fctx->best_arg, FALSE);
 	} T_END;
 	/* filter the rest */
-	for (arg = fctx->args; arg != NULL && ret == 0; arg = arg->next) {
+	for (arg = fctx->args->args; arg != NULL && ret == 0; arg = arg->next) {
 		if (arg != fctx->best_arg) {
 			T_BEGIN {
 				ret = fts_search_lookup_arg(fctx, arg, TRUE);
@@ -196,7 +197,8 @@
 {
 	struct mail_search_arg *best_fast_arg = NULL, *best_substr_arg = NULL;
 
-	fts_search_args_find_best(fctx->args, &best_fast_arg, &best_substr_arg);
+	fts_search_args_find_best(fctx->args->args, &best_fast_arg,
+				  &best_substr_arg);
 
 	if (best_fast_arg != NULL && fctx->fbox->backend_fast != NULL) {
 		/* use fast backend whenever possible */
--- a/src/plugins/fts/fts-storage.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/fts/fts-storage.c	Wed Jun 04 00:51:58 2008 +0300
@@ -7,7 +7,7 @@
 #include "istream.h"
 #include "message-parser.h"
 #include "message-decoder.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-storage-private.h"
 #include "fts-api-private.h"
 #include "fts-storage.h"
@@ -25,7 +25,7 @@
 
 struct fts_storage_build_context {
 	struct mail_search_context *search_ctx;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail *mail;
 	struct fts_backend_build_context *build;
 
@@ -167,6 +167,7 @@
 static int fts_build_init(struct fts_search_context *fctx)
 {
 	struct mailbox_transaction_context *t = fctx->t;
+	struct mail_search_args *search_args;
 	struct fts_backend *backend = fctx->build_backend;
 	struct fts_storage_build_context *ctx;
 	struct fts_backend_build_context *build;
@@ -201,15 +202,15 @@
 		}
 	}
 
+	search_args = mail_search_build_init();
+	mail_search_build_add_seqset(search_args, seq1, seq2);
+
 	ctx = i_new(struct fts_storage_build_context, 1);
 	ctx->build = build;
-	ctx->search_arg.type = SEARCH_SEQSET;
-	i_array_init(&ctx->search_arg.value.seqset, 1);
-	seq_range_array_add_range(&ctx->search_arg.value.seqset, seq1, seq2);
-
 	ctx->headers = str_new(default_pool, 512);
 	ctx->mail = mail_alloc(t, 0, NULL);
-	ctx->search_ctx = mailbox_search_init(t, NULL, &ctx->search_arg, NULL);
+	ctx->search_ctx = mailbox_search_init(t, search_args, NULL);
+	ctx->search_args = search_args;
 
 	fctx->build_ctx = ctx;
 	return 0;
@@ -239,7 +240,7 @@
 	}
 
 	str_free(&ctx->headers);
-	array_free(&ctx->search_arg.value.seqset);
+	mail_search_args_unref(&ctx->search_args);
 	i_free(ctx);
 	return ret;
 }
@@ -256,7 +257,7 @@
 		   already spent some time indexing the mailbox */
 		ctx->search_start_time = ioloop_timeval;
 	} else if (box->storage->callbacks->notify_ok != NULL) {
-		range = array_idx(&ctx->search_arg.value.seqset, 0);
+		range = array_idx(&ctx->search_args->args->value.seqset, 0);
 		percentage = (ctx->mail->seq - range->seq1) * 100.0 /
 			(range->seq2 - range->seq1);
 		msecs = (ioloop_timeval.tv_sec -
@@ -330,21 +331,19 @@
 
 static struct mail_search_context *
 fts_mailbox_search_init(struct mailbox_transaction_context *t,
-			const char *charset, struct mail_search_arg *args,
+			struct mail_search_args *args,
 			const enum mail_sort_type *sort_program)
 {
 	struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
 	struct mail_search_context *ctx;
 	struct fts_search_context *fctx;
 
-	ctx = fbox->module_ctx.super.
-		search_init(t, charset, args, sort_program);
+	ctx = fbox->module_ctx.super.search_init(t, args, sort_program);
 
 	fctx = i_new(struct fts_search_context, 1);
 	fctx->fbox = fbox;
 	fctx->t = t;
 	fctx->args = args;
-	fctx->charset = ctx->charset;
 	MODULE_CONTEXT_SET(ctx, fts_storage_module, fctx);
 
 	if (fbox->backend_substr == NULL && fbox->backend_fast == NULL)
@@ -395,7 +394,7 @@
 {
 	struct mail_search_arg *arg;
 
-	for (arg = fctx->args; arg != NULL; arg = arg->next) {
+	for (arg = fctx->args->args; arg != NULL; arg = arg->next) {
 		switch (arg->type) {
 		case SEARCH_TEXT:
 		case SEARCH_BODY:
@@ -474,7 +473,7 @@
 		if (ret <= 0 || wanted_seq == ctx->seq)
 			break;
 		wanted_seq = ctx->seq;
-		mail_search_args_reset(ctx->args, FALSE);
+		mail_search_args_reset(ctx->args->args, FALSE);
 	}
 
 	if (!use_maybe) {
--- a/src/plugins/fts/fts-storage.h	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/fts/fts-storage.h	Wed Jun 04 00:51:58 2008 +0300
@@ -15,9 +15,8 @@
 
 	struct fts_mailbox *fbox;
 	struct mailbox_transaction_context *t;
-	struct mail_search_arg *args;
+	struct mail_search_args *args;
 	struct mail_search_arg *best_arg;
-	const char *charset;
 
 	ARRAY_TYPE(seq_range) definite_seqs, maybe_seqs;
 	unsigned int definite_idx, maybe_idx;
--- a/src/plugins/mbox-snarf/mbox-snarf-plugin.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/mbox-snarf/mbox-snarf-plugin.c	Wed Jun 04 00:51:58 2008 +0300
@@ -3,7 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "home-expand.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-storage-private.h"
 #include "mailbox-list-private.h"
 #include "mbox-snarf-plugin.h"
@@ -37,7 +37,7 @@
 
 static int mbox_snarf(struct mailbox *srcbox, struct mailbox *destbox)
 {
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail_search_context *search_ctx;
         struct mailbox_transaction_context *src_trans, *dest_trans;
 	struct mail *mail;
@@ -46,13 +46,14 @@
 	if (mailbox_sync(srcbox, MAILBOX_SYNC_FLAG_FULL_READ, 0, NULL) < 0)
 		return -1;
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
-
 	src_trans = mailbox_transaction_begin(srcbox, 0);
 	dest_trans = mailbox_transaction_begin(destbox,
 					MAILBOX_TRANSACTION_FLAG_EXTERNAL);
-	search_ctx = mailbox_search_init(src_trans, NULL, &search_arg, NULL);
+
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	search_ctx = mailbox_search_init(src_trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
 	mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
 			  MAIL_FETCH_STREAM_BODY, NULL);
--- a/src/plugins/quota/quota-count.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/quota/quota-count.c	Wed Jun 04 00:51:58 2008 +0300
@@ -2,7 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-storage.h"
 #include "quota-private.h"
 
@@ -13,7 +13,7 @@
 	struct mailbox_transaction_context *trans;
 	struct mail_search_context *ctx;
 	struct mail *mail;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	uoff_t size;
 	int ret = 0;
 
@@ -27,12 +27,14 @@
 		return -1;
 	}
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
+	trans = mailbox_transaction_begin(box, 0);
+	mail = mail_alloc(trans, MAIL_FETCH_PHYSICAL_SIZE, NULL);
 
-	trans = mailbox_transaction_begin(box, 0);
-	ctx = mailbox_search_init(trans, NULL, &search_arg, NULL);
-	mail = mail_alloc(trans, MAIL_FETCH_PHYSICAL_SIZE, NULL);
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	ctx = mailbox_search_init(trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	while (mailbox_search_next(ctx, mail) > 0) {
 		if (mail_get_physical_size(mail, &size) == 0)
 			*bytes_r += size;
--- a/src/plugins/quota/quota-storage.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/quota/quota-storage.c	Wed Jun 04 00:51:58 2008 +0300
@@ -3,7 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "istream.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-storage-private.h"
 #include "mailbox-list-private.h"
 #include "quota-private.h"
@@ -392,7 +392,7 @@
         struct mailbox_transaction_context *t;
 	struct quota_transaction_context *qt;
 	struct mail *mail;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	enum mail_error error;
 	int ret;
 
@@ -416,12 +416,13 @@
 		return -1;
 	}
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
-
 	t = mailbox_transaction_begin(box, 0);
 	qt = QUOTA_CONTEXT(t);
-	ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
+
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
 	mail = mail_alloc(t, 0, NULL);
 	while (mailbox_search_next(ctx, mail) > 0)
--- a/src/plugins/trash/trash-plugin.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/plugins/trash/trash-plugin.c	Wed Jun 04 00:51:58 2008 +0300
@@ -5,7 +5,7 @@
 #include "istream.h"
 #include "home-expand.h"
 #include "mail-namespace.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "quota-private.h"
 #include "quota-plugin.h"
 #include "trash-plugin.h"
@@ -26,7 +26,6 @@
 	/* temporarily set while cleaning: */
 	struct mailbox *box;
 	struct mailbox_transaction_context *trans;
-        struct mail_search_arg search_arg;
 	struct mail_search_context *search_ctx;
 	struct mail *mail;
 
@@ -44,6 +43,8 @@
 
 static int trash_clean_mailbox_open(struct trash_mailbox *trash)
 {
+	struct mail_search_args *search_args;
+
 	trash->box = mailbox_open(trash->storage, trash->name, NULL,
 				  MAILBOX_OPEN_KEEP_RECENT);
 	if (trash->box == NULL)
@@ -53,12 +54,15 @@
 		return -1;
 
 	trash->trans = mailbox_transaction_begin(trash->box, 0);
-
-	trash->search_ctx = mailbox_search_init(trash->trans, NULL,
-						&trash->search_arg, NULL);
 	trash->mail = mail_alloc(trash->trans, MAIL_FETCH_PHYSICAL_SIZE |
 				 MAIL_FETCH_RECEIVED_DATE, NULL);
 
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	trash->search_ctx = mailbox_search_init(trash->trans,
+						search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	return mailbox_search_next(trash->search_ctx, trash->mail);
 }
 
@@ -259,7 +263,6 @@
 		trash = array_append_space(&trash_boxes);
 		trash->name = p_strdup(config_pool, name+1);
 		trash->priority = atoi(t_strdup_until(line, name));
-		trash->search_arg.type = SEARCH_ALL;
 
 		if (getenv("DEBUG") != NULL) {
 			i_info("trash plugin: Added '%s' with priority %d",
--- a/src/pop3/client.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/pop3/client.c	Wed Jun 04 00:51:58 2008 +0300
@@ -10,7 +10,7 @@
 #include "var-expand.h"
 #include "mail-storage.h"
 #include "commands.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "mail-namespace.h"
 
 #include <stdlib.h>
@@ -47,7 +47,7 @@
 
 static bool init_mailbox(struct client *client, const char **error_r)
 {
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
         struct mailbox_transaction_context *t;
 	struct mail_search_context *ctx;
         struct mailbox_status status;
@@ -60,8 +60,8 @@
 
 	message_sizes_buf = buffer_create_dynamic(default_pool, 512);
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_ALL;
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
 
 	for (i = 0; i < 2; i++) {
 		expunged = FALSE;
@@ -73,7 +73,7 @@
 		client->uid_validity = status.uidvalidity;
 
 		t = mailbox_transaction_begin(client->mailbox, 0);
-		ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
+		ctx = mailbox_search_init(t, search_args, NULL);
 
 		client->last_seen = 0;
 		client->total_size = 0;
@@ -114,6 +114,7 @@
 			client->trans = t;
 			client->message_sizes =
 				buffer_free_without_data(&message_sizes_buf);
+			mail_search_args_unref(&search_args);
 			return TRUE;
 		}
 
@@ -121,6 +122,7 @@
 		   sizes, make sure they get committed. */
 		(void)mailbox_transaction_commit(&t);
 	}
+	mail_search_args_unref(&search_args);
 
 	if (expunged) {
 		client_send_line(client,
--- a/src/pop3/commands.c	Sun Mar 16 12:10:57 2008 +0200
+++ b/src/pop3/commands.c	Wed Jun 04 00:51:58 2008 +0300
@@ -8,7 +8,7 @@
 #include "var-expand.h"
 #include "message-size.h"
 #include "mail-storage.h"
-#include "mail-search.h"
+#include "mail-search-build.h"
 #include "capability.h"
 #include "commands.h"
 
@@ -183,9 +183,24 @@
 	return 1;
 }
 
+static struct mail_search_args *
+pop3_search_build(struct client *client, uint32_t seq)
+{
+	struct mail_search_args *search_args;
+
+	search_args = mail_search_build_init();
+	if (seq == 0) {
+		mail_search_build_add_seqset(search_args,
+					     1, client->messages_count);
+	} else {
+		mail_search_build_add_seqset(search_args, seq, seq);
+	}
+	return search_args;
+}
+
 static bool expunge_mails(struct client *client)
 {
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 	struct mail_search_context *ctx;
 	struct mail *mail;
 	uint32_t idx;
@@ -198,13 +213,10 @@
 		return TRUE;
 	}
 
-	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_SEQSET;
-	t_array_init(&search_arg.value.seqset, 1);
-	seq_range_array_add_range(&search_arg.value.seqset,
-				  1, client->messages_count);
+	search_args = pop3_search_build(client, 0);
+	ctx = mailbox_search_init(client->trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
-	ctx = mailbox_search_init(client->trans, NULL, &search_arg, NULL);
 	mail = mail_alloc(client->trans, 0, NULL);
 	while (mailbox_search_next(ctx, mail) > 0) {
 		idx = mail->seq - 1;
@@ -253,8 +265,6 @@
 	struct istream *stream;
 	uoff_t body_lines;
 
-	struct mail_search_arg search_arg;
-
 	unsigned char last;
 	bool cr_skipped, in_body;
 };
@@ -262,7 +272,6 @@
 static void fetch_deinit(struct fetch_context *ctx)
 {
 	(void)mailbox_search_deinit(&ctx->search_ctx);
-	array_free(&ctx->search_arg.value.seqset);
 	mail_free(&ctx->mail);
 	i_free(ctx);
 }
@@ -367,15 +376,14 @@
 static void fetch(struct client *client, unsigned int msgnum, uoff_t body_lines)
 {
         struct fetch_context *ctx;
+	struct mail_search_args *search_args;
+
+	search_args = pop3_search_build(client, msgnum+1);
 
 	ctx = i_new(struct fetch_context, 1);
+	ctx->search_ctx = mailbox_search_init(client->trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
-	ctx->search_arg.type = SEARCH_SEQSET;
-	i_array_init(&ctx->search_arg.value.seqset, 1);
-	seq_range_array_add(&ctx->search_arg.value.seqset, 0, msgnum+1);
-
-	ctx->search_ctx = mailbox_search_init(client->trans, NULL,
-					      &ctx->search_arg, NULL);
 	ctx->mail = mail_alloc(client->trans, MAIL_FETCH_STREAM_HEADER |
 			       MAIL_FETCH_STREAM_BODY, NULL);
 
@@ -430,7 +438,7 @@
 {
 	struct mail_search_context *search_ctx;
 	struct mail *mail;
-	struct mail_search_arg search_arg;
+	struct mail_search_args *search_args;
 
 	client->last_seen = 0;
 
@@ -443,14 +451,11 @@
 
 	if (enable_last_command) {
 		/* remove all \Seen flags (as specified by RFC 1460) */
-		memset(&search_arg, 0, sizeof(search_arg));
-		search_arg.type = SEARCH_SEQSET;
-		t_array_init(&search_arg.value.seqset, 1);
-		seq_range_array_add_range(&search_arg.value.seqset,
-					  1, client->messages_count);
+		search_args = pop3_search_build(client, 0);
+		search_ctx = mailbox_search_init(client->trans,
+						 search_args, NULL);
+		mail_search_args_unref(&search_args);
 
-		search_ctx = mailbox_search_init(client->trans, NULL,
-						 &search_arg, NULL);
 		mail = mail_alloc(client->trans, 0, NULL);
 		while (mailbox_search_next(search_ctx, mail) > 0)
 			mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN);
@@ -598,26 +603,21 @@
 cmd_uidl_init(struct client *client, unsigned int message)
 {
         struct cmd_uidl_context *ctx;
+	struct mail_search_args *search_args;
 	enum mail_fetch_field wanted_fields;
 
+	search_args = pop3_search_build(client, message);
+
 	ctx = i_new(struct cmd_uidl_context, 1);
-
-	ctx->search_arg.type = SEARCH_SEQSET;
-	i_array_init(&ctx->search_arg.value.seqset, 1);
-	if (message == 0) {
-		seq_range_array_add_range(&ctx->search_arg.value.seqset,
-					  1, client->messages_count);
-	} else {
-		ctx->message = message;
-		seq_range_array_add(&ctx->search_arg.value.seqset, 0, message);
-	}
+	ctx->message = message;
 
 	wanted_fields = 0;
 	if ((uidl_keymask & UIDL_MD5) != 0)
 		wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
-	ctx->search_ctx = mailbox_search_init(client->trans, NULL,
-					      &ctx->search_arg, NULL);
+	ctx->search_ctx = mailbox_search_init(client->trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
 	ctx->mail = mail_alloc(client->trans, wanted_fields, NULL);
 	if (message == 0) {
 		client->cmd = cmd_uidl_callback;