dovecot: SEARCH_KEYWORDS now uses struct mail_keywords instead o...

dovecot at dovecot.org dovecot at dovecot.org
Sat Dec 8 19:21:30 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/ae369569e7de
changeset: 6965:ae369569e7de
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Dec 08 19:21:27 2007 +0200
description:
SEARCH_KEYWORDS now uses struct mail_keywords instead of a string array.

diffstat:

6 files changed, 147 insertions(+), 19 deletions(-)
src/imap/cmd-search.c                |   13 ++++---
src/imap/imap-search.c               |   41 +++++++++++++++++++++-
src/imap/imap-search.h               |    2 +
src/lib-storage/index/index-search.c |   44 +++++++++++++++++------
src/lib-storage/mail-search.c        |   63 ++++++++++++++++++++++++++++++++++
src/lib-storage/mail-search.h        |    3 +

diffs (truncated from 323 to 300 lines):

diff -r b9d674728523 -r ae369569e7de src/imap/cmd-search.c
--- a/src/imap/cmd-search.c	Sat Dec 08 19:08:41 2007 +0200
+++ b/src/imap/cmd-search.c	Sat Dec 08 19:21:27 2007 +0200
@@ -9,9 +9,11 @@
 #define OUTBUF_SIZE 65536
 
 struct imap_search_context {
-        struct mailbox_transaction_context *trans;
+	struct mailbox *box;
+	struct mailbox_transaction_context *trans;
         struct mail_search_context *search_ctx;
 	struct mail *mail;
+	struct mail_search_arg *sargs;
 
 	struct timeout *to;
 	string_t *output_buf;
@@ -22,13 +24,15 @@ struct imap_search_context {
 };
 
 static struct imap_search_context *
-imap_search_init(struct client_command_context *cmd, const char *charset,
-		 struct mail_search_arg *sargs)
+imap_search_init(struct client_command_context *cmd, struct mailbox *box,
+		 const char *charset, struct mail_search_arg *sargs)
 {
 	struct imap_search_context *ctx;
 
 	ctx = p_new(cmd->pool, struct imap_search_context, 1);
+	ctx->box = box;
 	ctx->trans = mailbox_transaction_begin(cmd->client->mailbox, 0);
+	ctx->sargs = sargs;
 	ctx->search_ctx = mailbox_search_init(ctx->trans, charset, sargs, NULL);
 	ctx->mail = mail_alloc(ctx->trans, 0, NULL);
 	(void)gettimeofday(&ctx->start_time, NULL);
@@ -58,6 +62,7 @@ static int imap_search_deinit(struct cli
 	if (ctx->to != NULL)
 		timeout_remove(&ctx->to);
 	str_free(&ctx->output_buf);
+	imap_search_args_free(ctx->box, ctx->sargs);
 
 	cmd->context = NULL;
 	return ret;
@@ -183,7 +188,7 @@ bool cmd_search(struct client_command_co
 		return TRUE;
 	}
 
-	ctx = imap_search_init(cmd, charset, sargs);
+	ctx = imap_search_init(cmd, cmd->client->mailbox, charset, sargs);
 	cmd->func = cmd_search_more;
 	cmd->context = ctx;
 
diff -r b9d674728523 -r ae369569e7de src/imap/imap-search.c
--- a/src/imap/imap-search.c	Sat Dec 08 19:08:41 2007 +0200
+++ b/src/imap/imap-search.c	Sat Dec 08 19:21:27 2007 +0200
@@ -125,6 +125,32 @@ arg_new_flags(struct search_build_data *
 	return TRUE;
 }
 
+static bool
+arg_new_keyword(struct search_build_data *data,
+		const struct imap_arg **args,
+		struct mail_search_arg **next_sarg)
+{
+	struct mail_search_arg *sarg;
+	const char *value, *keywords[2];
+	struct mail_storage *storage;
+	enum mail_error error;
+
+	*next_sarg = sarg = search_arg_new(data->pool, SEARCH_KEYWORDS);
+	if (!arg_get_next(data, args, &value))
+		return FALSE;
+
+	keywords[0] = value;
+	keywords[1] = NULL;
+
+	if (mailbox_keywords_create(data->box, keywords,
+				    &sarg->value.keywords) < 0) {
+		storage = mailbox_get_storage(data->box);
+		data->error = mail_storage_get_last_error(storage, &error);
+		return FALSE;
+	}
+	return TRUE;
+}
+
 #define ARG_NEW_SIZE(type) \
 	arg_new_size(data, args, next_sarg, type)
 static bool
@@ -304,7 +330,7 @@ static bool search_arg_build(struct sear
 	case 'K':
 		if (strcmp(str, "KEYWORD") == 0) {
 			/* <flag> */
-			return ARG_NEW_STR(SEARCH_KEYWORD);
+			return arg_new_keyword(data, args, next_sarg);
 		}
 		break;
 	case 'L':
@@ -446,7 +472,7 @@ static bool search_arg_build(struct sear
 			return TRUE;
 		} else if (strcmp(str, "UNKEYWORD") == 0) {
 			/* <flag> */
-			if (!ARG_NEW_STR(SEARCH_KEYWORD))
+			if (!arg_new_keyword(data, args, next_sarg))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
@@ -515,6 +541,7 @@ imap_search_args_build(pool_t pool, stru
 	first_sarg = NULL; sargs = &first_sarg;
 	while (args->type != IMAP_ARG_EOL) {
 		if (!search_arg_build(&data, &args, sargs)) {
+			imap_search_args_free(box, first_sarg);
 			*error_r = data.error;
 			return NULL;
 		}
@@ -552,6 +579,16 @@ static int imap_search_get_msgset_arg(st
 	return 0;
 }
 
+void imap_search_args_free(struct mailbox *box, struct mail_search_arg *args)
+{
+	for (; args != NULL; args = args->next) {
+		if (args->type == SEARCH_KEYWORDS)
+			mailbox_keywords_free(box, &args->value.keywords);
+		else if (args->type == SEARCH_SUB || args->type == SEARCH_OR)
+			imap_search_args_free(box, args->value.subargs);
+	}
+}
+
 static int
 imap_search_get_uidset_arg(pool_t pool, struct mailbox *box, const char *uidset,
 			   struct mail_search_arg **arg_r, const char **error_r)
diff -r b9d674728523 -r ae369569e7de src/imap/imap-search.h
--- a/src/imap/imap-search.h	Sat Dec 08 19:08:41 2007 +0200
+++ b/src/imap/imap-search.h	Sat Dec 08 19:21:27 2007 +0200
@@ -9,6 +9,8 @@ struct mail_search_arg *
 struct mail_search_arg *
 imap_search_args_build(pool_t pool, struct mailbox *box,
 		       const struct imap_arg *args, const char **error_r);
+/* Free allocated keywords */
+void imap_search_args_free(struct mailbox *box, struct mail_search_arg *args);
 
 struct mail_search_arg *
 imap_search_get_arg(struct client_command_context *cmd,
diff -r b9d674728523 -r ae369569e7de src/lib-storage/index/index-search.c
--- a/src/lib-storage/index/index-search.c	Sat Dec 08 19:08:41 2007 +0200
+++ b/src/lib-storage/index/index-search.c	Sat Dec 08 19:21:27 2007 +0200
@@ -78,30 +78,50 @@ static int seqset_contains(struct mail_s
 	return FALSE;
 }
 
+static int search_arg_match_keywords(struct index_mail *imail,
+				     struct mail_search_arg *arg)
+{
+	ARRAY_TYPE(keyword_indexes) keyword_indexes_arr;
+	const struct mail_keywords *search_kws = arg->value.keywords;
+	const unsigned int *keyword_indexes;
+	unsigned int i, j, count;
+
+	t_array_init(&keyword_indexes_arr, 128);
+	mail_index_lookup_keywords(imail->ibox->view, imail->mail.mail.seq,
+				   &keyword_indexes_arr);
+	keyword_indexes = array_get(&keyword_indexes_arr, &count);
+
+	/* there probably aren't many keywords, so O(n*m) for now */
+	for (i = 0; i < search_kws->count; i++) {
+		for (j = 0; j < count; j++) {
+			if (search_kws->idx[i] == keyword_indexes[j])
+				break;
+		}
+		if (j == count)
+			return 0;
+	}
+	return 1;
+}
+
 /* Returns >0 = matched, 0 = not matched, -1 = unknown */
 static int search_arg_match_index(struct index_mail *imail,
 				  struct mail_search_arg *arg)
 {
 	enum mail_flags flags;
-	const char *const *keywords;
+	int ret;
 
 	switch (arg->type) {
-	/* flags */
 	case SEARCH_FLAGS:
 		flags = imail->data.flags;
 		if ((arg->value.flags & MAIL_RECENT) != 0 &&
-		    index_mailbox_is_recent(imail->ibox,
-					    imail->mail.mail.uid))
+		    index_mailbox_is_recent(imail->ibox, imail->mail.mail.uid))
 			flags |= MAIL_RECENT;
 		return (flags & arg->value.flags) == arg->value.flags;
-	case SEARCH_KEYWORD:
-		keywords = mail_get_keywords(&imail->mail.mail);
-		while (*keywords != NULL) {
-			if (strcasecmp(*keywords, arg->value.str) == 0)
-				return 1;
-			keywords++;
-		}
-		return 0;
+	case SEARCH_KEYWORDS:
+		T_FRAME(
+			ret = search_arg_match_keywords(imail, arg);
+		);
+		return ret;
 
 	default:
 		return -1;
diff -r b9d674728523 -r ae369569e7de src/lib-storage/mail-search.c
--- a/src/lib-storage/mail-search.c	Sat Dec 08 19:08:41 2007 +0200
+++ b/src/lib-storage/mail-search.c	Sat Dec 08 19:21:27 2007 +0200
@@ -1,7 +1,9 @@
 /* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "buffer.h"
+#include "mail-index.h"
 #include "mail-search.h"
 
 void mail_search_args_reset(struct mail_search_arg *args, bool full_reset)
@@ -177,13 +179,46 @@ mail_search_args_analyze(struct mail_sea
 	return buffer_get_data(headers, NULL);
 }
 
+static struct mail_keywords *
+mail_search_keywords_merge(struct mail_keywords **_kw1,
+			   struct mail_keywords **_kw2)
+{
+	struct mail_keywords *kw1 = *_kw1, *kw2 = *_kw2;
+	struct mail_keywords *new_kw;
+
+	i_assert(kw1->index == kw2->index);
+	T_FRAME_BEGIN {
+		ARRAY_TYPE(keyword_indexes) new_indexes;
+		unsigned int i, j;
+
+		t_array_init(&new_indexes, kw1->count + kw2->count + 1);
+		array_append(&new_indexes, kw1->idx, kw1->count);
+		for (i = 0; i < kw2->count; i++) {
+			/* don't add duplicates */
+			for (j = 0; j < kw1->count; j++) {
+				if (kw1->idx[j] == kw2->idx[i])
+					break;
+			}
+			if (j == kw1->count)
+				array_append(&new_indexes, kw2->idx+i, 1);
+		}
+		new_kw = mail_index_keywords_create_from_indexes(kw1->index,
+								 &new_indexes);
+	} T_FRAME_END;
+	mail_index_keywords_free(_kw1);
+	mail_index_keywords_free(_kw2);
+	return new_kw;
+}
+
 static void
 mail_search_args_simplify_sub(struct mail_search_arg *args, bool parent_and)
 {
 	struct mail_search_arg *sub, *prev = NULL;
 	struct mail_search_arg *prev_flags_arg, *prev_not_flags_arg;
+	struct mail_search_arg *prev_kw_arg, *prev_not_kw_arg;
 
 	prev_flags_arg = prev_not_flags_arg = NULL;
+	prev_kw_arg = prev_not_kw_arg = NULL;
 	for (; args != NULL;) {
 		if (args->not && (args->type == SEARCH_SUB ||
 				  args->type == SEARCH_OR)) {
@@ -237,6 +272,34 @@ mail_search_args_simplify_sub(struct mai
 			}
 		}
 
+		/* merge all keywords arguments */
+		if (args->type == SEARCH_KEYWORDS && !args->not && parent_and) {
+			if (prev_kw_arg == NULL)
+				prev_kw_arg = args;
+			else {
+				prev_kw_arg->value.keywords =
+					mail_search_keywords_merge(
+						&prev_kw_arg->value.keywords,
+						&args->value.keywords);
+				prev->next = args->next;
+				args = args->next;
+				continue;
+			}
+		} else if (args->type == SEARCH_KEYWORDS && args->not &&
+			   !parent_and) {
+			if (prev_not_kw_arg == NULL)
+				prev_not_kw_arg = args;
+			else {
+				prev_not_kw_arg->value.keywords =
+					mail_search_keywords_merge(
+					       &prev_not_kw_arg->value.keywords,
+					       &args->value.keywords);
+				prev->next = args->next;
+				args = args->next;
+				continue;
+			}
+		}
+


More information about the dovecot-cvs mailing list