changeset 6962:659e4a606aae HEAD

Replaced SEARCH_<flag> with a generic SEARCH_FLAGS. Use value.size for SEARCH_LARGER and SEARCH_SMALLER and give an error if it's not a valid number.
author Timo Sirainen <tss@iki.fi>
date Sat, 08 Dec 2007 18:26:42 +0200
parents 16f761cdc910
children 5fb86ed98860
files src/imap/imap-expunge.c src/imap/imap-search.c src/lib-storage/index/index-search.c src/lib-storage/mail-search.h
diffstat 4 files changed, 177 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/imap-expunge.c	Sat Dec 08 17:47:48 2007 +0200
+++ b/src/imap/imap-expunge.c	Sat Dec 08 18:26:42 2007 +0200
@@ -19,7 +19,8 @@
 	}
 
 	memset(&search_arg, 0, sizeof(search_arg));
-	search_arg.type = SEARCH_DELETED;
+	search_arg.type = SEARCH_FLAGS;
+	search_arg.value.flags = MAIL_DELETED;
 	search_arg.next = next_search_arg;
 
 	t = mailbox_transaction_begin(box, 0);
--- a/src/imap/imap-search.c	Sat Dec 08 17:47:48 2007 +0200
+++ b/src/imap/imap-search.c	Sat Dec 08 18:26:42 2007 +0200
@@ -8,6 +8,8 @@
 #include "imap-parser.h"
 #include "imap-messageset.h"
 
+#include <stdlib.h>
+
 struct search_build_data {
 	pool_t pool;
         struct mailbox *box;
@@ -63,58 +65,125 @@
 	return arg;
 }
 
-#define ARG_NEW(type) \
-	arg_new(data, args, next_sarg, type, TRUE, NULL)
-
-#define ARG_NEW_FLAG(type) \
-	arg_new(data, args, next_sarg, type, FALSE, NULL)
-
-#define ARG_NEW_HEADER(type, hdr_name) \
-	arg_new(data, args, next_sarg, type, TRUE, hdr_name)
-
-static bool arg_new(struct search_build_data *data,
-		    const struct imap_arg **args,
-		    struct mail_search_arg **next_sarg,
-		    enum mail_search_arg_type type, bool have_value,
-		    const char *hdr_name)
+static bool
+arg_get_next(struct search_build_data *data, const struct imap_arg **args,
+	     const char **value_r)
 {
-	struct mail_search_arg *sarg;
-
-	*next_sarg = sarg = search_arg_new(data->pool, type);
-	if (!have_value)
-		return TRUE;
-
 	if ((*args)->type == IMAP_ARG_EOL) {
 		data->error = "Missing parameter for argument";
 		return FALSE;
 	}
-
 	if ((*args)->type != IMAP_ARG_ATOM &&
 	    (*args)->type != IMAP_ARG_STRING) {
 		data->error = "Invalid parameter for argument";
 		return FALSE;
 	}
 
-	switch (type) {
-	case SEARCH_BEFORE:
-	case SEARCH_ON:
-	case SEARCH_SINCE:
-	case SEARCH_SENTBEFORE:
-	case SEARCH_SENTON:
-	case SEARCH_SENTSINCE:
-		if (!imap_parse_date(IMAP_ARG_STR(*args), &sarg->value.time)) {
-			data->error = "Invalid search date parameter";
-			return FALSE;
-		}
-	default:
-		sarg->value.str = p_strdup(data->pool, IMAP_ARG_STR(*args));
-		break;
+	*value_r = IMAP_ARG_STR(*args);
+	*args += 1;
+	return TRUE;
+}
+
+#define ARG_NEW_SINGLE(type) \
+	arg_new_single(data, next_sarg, type)
+static bool
+arg_new_single(struct search_build_data *data,
+	       struct mail_search_arg **next_sarg,
+	       enum mail_search_arg_type type)
+{
+	*next_sarg = search_arg_new(data->pool, type);
+	return TRUE;
+}
+
+#define ARG_NEW_STR(type) \
+	arg_new_str(data, args, next_sarg, type)
+static bool
+arg_new_str(struct search_build_data *data,
+	    const struct imap_arg **args, struct mail_search_arg **next_sarg,
+	    enum mail_search_arg_type type)
+{
+	struct mail_search_arg *sarg;
+	const char *value;
+
+	*next_sarg = sarg = search_arg_new(data->pool, type);
+	if (!arg_get_next(data, args, &value))
+		return FALSE;
+	sarg->value.str = p_strdup(data->pool, value);
+	return TRUE;
+}
+
+#define ARG_NEW_FLAGS(flags) \
+	arg_new_flags(data, next_sarg, flags)
+static bool
+arg_new_flags(struct search_build_data *data,
+	      struct mail_search_arg **next_sarg, enum mail_flags flags)
+{
+	struct mail_search_arg *sarg;
+
+	*next_sarg = sarg = search_arg_new(data->pool, SEARCH_FLAGS);
+	sarg->value.flags = flags;
+	return TRUE;
+}
+
+#define ARG_NEW_SIZE(type) \
+	arg_new_size(data, args, next_sarg, type)
+static bool
+arg_new_size(struct search_build_data *data,
+	     const struct imap_arg **args, struct mail_search_arg **next_sarg,
+	     enum mail_search_arg_type type)
+{
+	struct mail_search_arg *sarg;
+	const char *value;
+	char *p;
+
+	*next_sarg = sarg = search_arg_new(data->pool, type);
+	if (!arg_get_next(data, args, &value))
+		return FALSE;
+
+	sarg->value.size = strtoull(value, &p, 10);
+	if (*p != '\0') {
+		data->error = "Invalid search size parameter";
+		return FALSE;
 	}
-	*args += 1;
+	return TRUE;
+}
+
+#define ARG_NEW_DATE(type) \
+	arg_new_date(data, args, next_sarg, type)
+static bool
+arg_new_date(struct search_build_data *data,
+	     const struct imap_arg **args, struct mail_search_arg **next_sarg,
+	     enum mail_search_arg_type type)
+{
+	struct mail_search_arg *sarg;
+	const char *value;
 
-	if (hdr_name != NULL)
-                sarg->hdr_field_name = p_strdup(data->pool, hdr_name);
+	*next_sarg = sarg = search_arg_new(data->pool, type);
+	if (!arg_get_next(data, args, &value))
+		return FALSE;
+	if (!imap_parse_date(value, &sarg->value.time)) {
+		data->error = "Invalid search date parameter";
+		return FALSE;
+	}
+	return TRUE;
+}
 
+#define ARG_NEW_HEADER(type, hdr_name) \
+	arg_new_header(data, args, next_sarg, type, hdr_name)
+static bool
+arg_new_header(struct search_build_data *data,
+	       const struct imap_arg **args, struct mail_search_arg **next_sarg,
+	       enum mail_search_arg_type type, const char *hdr_name)
+{
+	struct mail_search_arg *sarg;
+	const char *value;
+
+	*next_sarg = sarg = search_arg_new(data->pool, type);
+	if (!arg_get_next(data, args, &value))
+		return FALSE;
+
+	sarg->hdr_field_name = p_strdup(data->pool, hdr_name);
+	sarg->value.str = p_strdup(data->pool, value);
 	return TRUE;
 }
 
@@ -171,9 +240,9 @@
 	switch (*str) {
 	case 'A':
 		if (strcmp(str, "ANSWERED") == 0)
-			return ARG_NEW_FLAG(SEARCH_ANSWERED);
+			return ARG_NEW_FLAGS(MAIL_ANSWERED);
 		else if (strcmp(str, "ALL") == 0)
-			return ARG_NEW_FLAG(SEARCH_ALL);
+			return ARG_NEW_SINGLE(SEARCH_ALL);
 		break;
 	case 'B':
 		if (strcmp(str, "BODY") == 0) {
@@ -181,12 +250,12 @@
 			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
 			    *IMAP_ARG_STR(*args) == '\0') {
 				*args += 1;
-				return ARG_NEW_FLAG(SEARCH_ALL);
+				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
-			return ARG_NEW(SEARCH_BODY);
+			return ARG_NEW_STR(SEARCH_BODY);
 		} else if (strcmp(str, "BEFORE") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_BEFORE);
+			return ARG_NEW_DATE(SEARCH_BEFORE);
 		} else if (strcmp(str, "BCC") == 0) {
 			/* <string> */
 			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
@@ -200,13 +269,13 @@
 		break;
 	case 'D':
 		if (strcmp(str, "DELETED") == 0)
-			return ARG_NEW_FLAG(SEARCH_DELETED);
+			return ARG_NEW_FLAGS(MAIL_DELETED);
 		else if (strcmp(str, "DRAFT") == 0)
-			return ARG_NEW_FLAG(SEARCH_DRAFT);
+			return ARG_NEW_FLAGS(MAIL_DRAFT);
 		break;
 	case 'F':
 		if (strcmp(str, "FLAGGED") == 0)
-			return ARG_NEW_FLAG(SEARCH_FLAGGED);
+			return ARG_NEW_FLAGS(MAIL_FLAGGED);
 		else if (strcmp(str, "FROM") == 0) {
 			/* <string> */
 			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
@@ -235,13 +304,13 @@
 	case 'K':
 		if (strcmp(str, "KEYWORD") == 0) {
 			/* <flag> */
-			return ARG_NEW(SEARCH_KEYWORD);
+			return ARG_NEW_STR(SEARCH_KEYWORD);
 		}
 		break;
 	case 'L':
 		if (strcmp(str, "LARGER") == 0) {
 			/* <n> */
-			return ARG_NEW(SEARCH_LARGER);
+			return ARG_NEW_SIZE(SEARCH_LARGER);
 		}
 		break;
 	case 'N':
@@ -255,9 +324,11 @@
 			*next_sarg = search_arg_new(data->pool, SEARCH_SUB);
 
 			subargs = &(*next_sarg)->value.subargs;
-			*subargs = search_arg_new(data->pool, SEARCH_RECENT);
+			*subargs = search_arg_new(data->pool, SEARCH_FLAGS);
+			(*subargs)->value.flags = MAIL_RECENT;
 			(*subargs)->next = search_arg_new(data->pool,
-							  SEARCH_SEEN);
+							  SEARCH_FLAGS);
+			(*subargs)->next->value.flags = MAIL_SEEN;
 			(*subargs)->next->not = TRUE;
 			return TRUE;
 		}
@@ -292,10 +363,10 @@
 			return TRUE;
 		} if (strcmp(str, "ON") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_ON);
+			return ARG_NEW_DATE(SEARCH_ON);
 		} if (strcmp(str, "OLD") == 0) {
 			/* OLD == NOT RECENT */
-			if (!ARG_NEW_FLAG(SEARCH_RECENT))
+			if (!ARG_NEW_FLAGS(MAIL_RECENT))
 				return FALSE;
 
 			(*next_sarg)->not = TRUE;
@@ -304,29 +375,29 @@
 		break;
 	case 'R':
 		if (strcmp(str, "RECENT") == 0)
-			return ARG_NEW_FLAG(SEARCH_RECENT);
+			return ARG_NEW_FLAGS(MAIL_RECENT);
 		break;
 	case 'S':
 		if (strcmp(str, "SEEN") == 0)
-			return ARG_NEW_FLAG(SEARCH_SEEN);
+			return ARG_NEW_FLAGS(MAIL_SEEN);
 		else if (strcmp(str, "SUBJECT") == 0) {
 			/* <string> */
 			return ARG_NEW_HEADER(SEARCH_HEADER, str);
 		} else if (strcmp(str, "SENTBEFORE") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_SENTBEFORE);
+			return ARG_NEW_DATE(SEARCH_SENTBEFORE);
 		} else if (strcmp(str, "SENTON") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_SENTON);
+			return ARG_NEW_DATE(SEARCH_SENTON);
 		} else if (strcmp(str, "SENTSINCE") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_SENTSINCE);
+			return ARG_NEW_DATE(SEARCH_SENTSINCE);
 		} else if (strcmp(str, "SINCE") == 0) {
 			/* <date> */
-			return ARG_NEW(SEARCH_SINCE);
+			return ARG_NEW_DATE(SEARCH_SINCE);
 		} else if (strcmp(str, "SMALLER") == 0) {
 			/* <n> */
-			return ARG_NEW(SEARCH_SMALLER);
+			return ARG_NEW_SIZE(SEARCH_SMALLER);
 		}
 		break;
 	case 'T':
@@ -335,9 +406,9 @@
 			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
 			    *IMAP_ARG_STR(*args) == '\0') {
 				*args += 1;
-				return ARG_NEW_FLAG(SEARCH_ALL);
+				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
-			return ARG_NEW(SEARCH_TEXT);
+			return ARG_NEW_STR(SEARCH_TEXT);
 		} else if (strcmp(str, "TO") == 0) {
 			/* <string> */
 			return ARG_NEW_HEADER(SEARCH_HEADER_ADDRESS, str);
@@ -346,7 +417,7 @@
 	case 'U':
 		if (strcmp(str, "UID") == 0) {
 			/* <message set> */
-			if (!ARG_NEW(SEARCH_SEQSET))
+			if (!ARG_NEW_STR(SEARCH_SEQSET))
 				return FALSE;
 
 			return imap_uidset_parse(data->pool, data->box,
@@ -354,33 +425,33 @@
 						 &(*next_sarg)->value.seqset,
 						 &data->error) == 0;
 		} else if (strcmp(str, "UNANSWERED") == 0) {
-			if (!ARG_NEW_FLAG(SEARCH_ANSWERED))
+			if (!ARG_NEW_FLAGS(MAIL_ANSWERED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
 		} else if (strcmp(str, "UNDELETED") == 0) {
-			if (!ARG_NEW_FLAG(SEARCH_DELETED))
+			if (!ARG_NEW_FLAGS(MAIL_DELETED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
 		} else if (strcmp(str, "UNDRAFT") == 0) {
-			if (!ARG_NEW_FLAG(SEARCH_DRAFT))
+			if (!ARG_NEW_FLAGS(MAIL_DRAFT))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
 		} else if (strcmp(str, "UNFLAGGED") == 0) {
-			if (!ARG_NEW_FLAG(SEARCH_FLAGGED))
+			if (!ARG_NEW_FLAGS(MAIL_FLAGGED))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
 		} else if (strcmp(str, "UNKEYWORD") == 0) {
 			/* <flag> */
-			if (!ARG_NEW(SEARCH_KEYWORD))
+			if (!ARG_NEW_STR(SEARCH_KEYWORD))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
 		} else if (strcmp(str, "UNSEEN") == 0) {
-			if (!ARG_NEW_FLAG(SEARCH_SEEN))
+			if (!ARG_NEW_FLAGS(MAIL_SEEN))
 				return FALSE;
 			(*next_sarg)->not = TRUE;
 			return TRUE;
@@ -392,17 +463,17 @@
 			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
 			    *IMAP_ARG_STR(*args) == '\0') {
 				*args += 1;
-				return ARG_NEW_FLAG(SEARCH_ALL);
+				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
-			return ARG_NEW(SEARCH_BODY_FAST);
+			return ARG_NEW_STR(SEARCH_BODY_FAST);
 		} else if (strcmp(str, "X-TEXT-FAST") == 0) {
 			/* <string> */
 			if (IMAP_ARG_TYPE_IS_STRING((*args)->type) &&
 			    *IMAP_ARG_STR(*args) == '\0') {
 				*args += 1;
-				return ARG_NEW_FLAG(SEARCH_ALL);
+				return ARG_NEW_SINGLE(SEARCH_ALL);
 			}
-			return ARG_NEW(SEARCH_TEXT_FAST);
+			return ARG_NEW_STR(SEARCH_TEXT_FAST);
 		}
 		break;
 	default:
@@ -414,7 +485,7 @@
 				return FALSE;
 			}
 
-			if (!ARG_NEW_FLAG(SEARCH_SEQSET))
+			if (!ARG_NEW_SINGLE(SEARCH_SEQSET))
 				return FALSE;
 
 			(*next_sarg)->value.seqset = seqset;
--- a/src/lib-storage/index/index-search.c	Sat Dec 08 17:47:48 2007 +0200
+++ b/src/lib-storage/index/index-search.c	Sat Dec 08 18:26:42 2007 +0200
@@ -40,6 +40,7 @@
 	unsigned int failed:1;
 	unsigned int sorted:1;
 	unsigned int have_seqsets:1;
+	unsigned int have_flags:1;
 };
 
 struct search_header_context {
@@ -77,48 +78,26 @@
 	return FALSE;
 }
 
-static uoff_t str_to_uoff_t(const char *str)
-{
-	uoff_t num;
-
-	num = 0;
-	while (*str != '\0') {
-		if (*str < '0' || *str > '9')
-			return 0;
-
-		num = num*10 + (*str - '0');
-		str++;
-	}
-
-	return num;
-}
-
 /* Returns >0 = matched, 0 = not matched, -1 = unknown */
 static int search_arg_match_index(struct index_mail *imail,
-				  enum mail_search_arg_type type,
-				  const char *value)
+				  struct mail_search_arg *arg)
 {
-	enum mail_flags flags = imail->data.flags;
+	enum mail_flags flags;
 	const char *const *keywords;
 
-	switch (type) {
+	switch (arg->type) {
 	/* flags */
-	case SEARCH_ANSWERED:
-		return flags & MAIL_ANSWERED;
-	case SEARCH_DELETED:
-		return flags & MAIL_DELETED;
-	case SEARCH_DRAFT:
-		return flags & MAIL_DRAFT;
-	case SEARCH_FLAGGED:
-		return flags & MAIL_FLAGGED;
-	case SEARCH_SEEN:
-		return flags & MAIL_SEEN;
-	case SEARCH_RECENT:
-		return mail_get_flags(&imail->mail.mail) & MAIL_RECENT;
+	case SEARCH_FLAGS:
+		flags = imail->data.flags;
+		if ((arg->value.flags & MAIL_RECENT) != 0 &&
+		    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, value) == 0)
+			if (strcasecmp(*keywords, arg->value.str) == 0)
 				return 1;
 			keywords++;
 		}
@@ -159,8 +138,7 @@
 static void search_index_arg(struct mail_search_arg *arg,
 			     struct index_search_context *ctx)
 {
-	switch (search_arg_match_index(ctx->imail, arg->type,
-				       arg->value.str)) {
+	switch (search_arg_match_index(ctx->imail, arg)) {
 	case -1:
 		/* unknown */
 		break;
@@ -177,7 +155,7 @@
 static int search_arg_match_cached(struct index_search_context *ctx,
 				   struct mail_search_arg *arg)
 {
-	uoff_t virtual_size, search_size;
+	uoff_t virtual_size;
 	time_t date;
 	int timezone_offset;
 
@@ -231,11 +209,10 @@
 		if (mail_get_virtual_size(ctx->mail, &virtual_size) < 0)
 			return -1;
 
-		search_size = str_to_uoff_t(arg->value.str);
 		if (arg->type == SEARCH_SMALLER)
-			return virtual_size < search_size;
+			return virtual_size < arg->value.size;
 		else
-			return virtual_size > search_size;
+			return virtual_size > arg->value.size;
 
 	default:
 		return -1;
@@ -757,8 +734,14 @@
 				  uint32_t *seq1, uint32_t *seq2)
 {
 	for (; args != NULL; args = args->next) {
-		switch (args->type) {
-		case SEARCH_SEEN:
+		if (args->type != SEARCH_FLAGS) {
+			if (args->type == SEARCH_ALL) {
+				if (args->not)
+					return FALSE;
+			}
+			continue;
+		}
+		if ((args->value.flags & MAIL_SEEN) != 0) {
 			/* SEEN with 0 seen? */
 			if (!args->not && hdr->seen_messages_count == 0)
 				return FALSE;
@@ -775,8 +758,8 @@
 				search_limit_lowwater(ctx,
                                 	hdr->first_unseen_uid_lowwater, seq1);
 			}
-			break;
-		case SEARCH_DELETED:
+		}
+		if ((args->value.flags & MAIL_DELETED) != 0) {
 			/* DELETED with 0 deleted? */
 			if (!args->not && hdr->deleted_messages_count == 0)
 				return FALSE;
@@ -794,13 +777,6 @@
 				search_limit_lowwater(ctx,
                                 	hdr->first_deleted_uid_lowwater, seq1);
 			}
-			break;
-		case SEARCH_ALL:
-			if (args->not)
-				return FALSE;
-			break;
-		default:
-			break;
 		}
 	}
 
--- a/src/lib-storage/mail-search.h	Sat Dec 08 17:47:48 2007 +0200
+++ b/src/lib-storage/mail-search.h	Sat Dec 08 18:26:42 2007 +0200
@@ -1,6 +1,8 @@
 #ifndef MAIL_SEARCH_H
 #define MAIL_SEARCH_H
 
+#include "mail-types.h"
+
 enum mail_search_arg_type {
 	SEARCH_OR,
 	SEARCH_SUB,
@@ -10,12 +12,7 @@
 	SEARCH_SEQSET,
 
 	/* flags */
-	SEARCH_ANSWERED,
-	SEARCH_DELETED,
-	SEARCH_DRAFT,
-	SEARCH_FLAGGED,
-	SEARCH_SEEN,
-	SEARCH_RECENT,
+	SEARCH_FLAGS,
 	SEARCH_KEYWORD,
 
 	/* dates */
@@ -55,6 +52,8 @@
                 struct mail_search_seqset *seqset;
 		const char *str;
 		time_t time;
+		uoff_t size;
+		enum mail_flags flags;
 	} value;
 
         void *context;