diff src/lib-storage/index/index-search.c @ 1672:8920600a8cfc HEAD

Index cache file rewrite. It's not finished yet and mbox support is completely broken. But it's getting difficult to maintain outside cvs :)
author Timo Sirainen <tss@iki.fi>
date Wed, 06 Aug 2003 23:15:30 +0300
parents e95c0e462591
children 6c0c2ff2c113
line wrap: on
line diff
--- a/src/lib-storage/index/index-search.c	Wed Aug 06 23:13:57 2003 +0300
+++ b/src/lib-storage/index/index-search.c	Wed Aug 06 23:15:30 2003 +0300
@@ -8,7 +8,6 @@
 #include "message-body-search.h"
 #include "message-header-search.h"
 #include "imap-date.h"
-#include "imap-envelope.h"
 #include "index-storage.h"
 #include "index-messageset.h"
 #include "index-mail.h"
@@ -216,16 +215,17 @@
 				   enum mail_search_arg_type type,
 				   const char *value)
 {
-	time_t internal_date, search_time;
+	time_t date, search_time;
 	uoff_t virtual_size, search_size;
+	int timezone_offset;
 
 	switch (type) {
 	/* internal dates */
 	case SEARCH_BEFORE:
 	case SEARCH_ON:
 	case SEARCH_SINCE:
-		internal_date = ctx->mail->get_received_date(ctx->mail);
-		if (internal_date == (time_t)-1)
+		date = ctx->mail->get_received_date(ctx->mail);
+		if (date == (time_t)-1)
 			return -1;
 
 		if (!imap_parse_date(value, &search_time))
@@ -233,12 +233,39 @@
 
 		switch (type) {
 		case SEARCH_BEFORE:
-			return internal_date < search_time;
+			return date < search_time;
 		case SEARCH_ON:
-			return internal_date >= search_time &&
-				internal_date < search_time + 3600*24;
+			return date >= search_time &&
+				date < search_time + 3600*24;
 		case SEARCH_SINCE:
-			return internal_date >= search_time;
+			return date >= search_time;
+		default:
+			/* unreachable */
+			break;
+		}
+
+	/* sent dates */
+	case SEARCH_SENTBEFORE:
+	case SEARCH_SENTON:
+	case SEARCH_SENTSINCE:
+		/* NOTE: RFC-3501 specifies that timezone is ignored
+		   in searches. date is returned as UTC, so change it. */
+		date = ctx->mail->get_date(ctx->mail, &timezone_offset);
+		if (date == (time_t)-1)
+			return -1;
+		date += timezone_offset * 60;
+
+		if (!imap_parse_date(value, &search_time))
+			return 0;
+
+		switch (type) {
+		case SEARCH_SENTBEFORE:
+			return date < search_time;
+		case SEARCH_SENTON:
+			return date >= search_time &&
+				date < search_time + 3600*24;
+		case SEARCH_SENTSINCE:
+			return date >= search_time;
 		default:
 			/* unreachable */
 			break;
@@ -339,120 +366,6 @@
 	return arg->context;
 }
 
-/* Returns >0 = matched, 0 = not matched, -1 = unknown */
-static int search_arg_match_envelope(struct mail_search_context *ctx,
-				     struct mail_search_arg *arg)
-{
-	struct mail_index *index = ctx->ibox->index;
-	enum imap_envelope_field env_field;
-        struct header_search_context *hdr_search_ctx;
-	const char *envelope, *field;
-	int ret;
-
-	switch (arg->type) {
-	case SEARCH_SENTBEFORE:
-	case SEARCH_SENTON:
-	case SEARCH_SENTSINCE:
-                env_field = IMAP_ENVELOPE_DATE;
-		break;
-
-	case SEARCH_FROM:
-                env_field = IMAP_ENVELOPE_FROM;
-		break;
-	case SEARCH_TO:
-                env_field = IMAP_ENVELOPE_TO;
-		break;
-	case SEARCH_CC:
-                env_field = IMAP_ENVELOPE_CC;
-		break;
-	case SEARCH_BCC:
-                env_field = IMAP_ENVELOPE_BCC;
-		break;
-	case SEARCH_SUBJECT:
-                env_field = IMAP_ENVELOPE_SUBJECT;
-		break;
-
-	case SEARCH_IN_REPLY_TO:
-                env_field = IMAP_ENVELOPE_IN_REPLY_TO;
-		break;
-	case SEARCH_MESSAGE_ID:
-                env_field = IMAP_ENVELOPE_MESSAGE_ID;
-		break;
-	default:
-		return -1;
-	}
-
-	t_push();
-
-	/* get field from hopefully cached envelope */
-	envelope = index->lookup_field(index, ctx->imail.data.rec,
-				       DATA_FIELD_ENVELOPE);
-	if (envelope != NULL) {
-		ret = imap_envelope_parse(envelope, env_field,
-					  IMAP_ENVELOPE_RESULT_TYPE_STRING,
-					  &field) ? 1 : -1;
-	} else {
-		index->cache_fields_later(index, DATA_FIELD_ENVELOPE);
-		field = NULL;
-		ret = -1;
-	}
-
-	if (ret != -1) {
-		switch (arg->type) {
-		case SEARCH_SENTBEFORE:
-		case SEARCH_SENTON:
-		case SEARCH_SENTSINCE:
-			ret = search_sent(arg->type, arg->value.str,
-					  (const unsigned char *) field,
-					  (size_t)-1);
-			break;
-		default:
-			if (arg->value.str[0] == '\0') {
-				/* we're just testing existence of the field.
-				   assume it matches with non-NIL values. */
-				ret = field != NULL ? 1 : 0;
-				break;
-			}
-
-			if (field == NULL) {
-				/* doesn't exist */
-				ret = 0;
-				break;
-			}
-
-			hdr_search_ctx = search_header_context(ctx, arg);
-			if (hdr_search_ctx == NULL) {
-				ret = 0;
-				break;
-			}
-
-			ret = message_header_search(
-						(const unsigned char *) field,
-						strlen(field),
-						hdr_search_ctx) ? 1 : 0;
-		}
-	}
-	t_pop();
-	return ret;
-}
-
-static void search_envelope_arg(struct mail_search_arg *arg, void *context)
-{
-	struct mail_search_context *ctx = context;
-
-	switch (search_arg_match_envelope(ctx, arg)) {
-	case -1:
-		/* unknown */
-		break;
-	case 0:
-		ARG_SET_RESULT(arg, 0);
-		break;
-	default:
-		ARG_SET_RESULT(arg, 1);
-		break;
-	}
-}
-
 static void search_header_arg(struct mail_search_arg *arg, void *context)
 {
 	struct search_header_context *ctx = context;
@@ -477,35 +390,8 @@
 		}
 		return;
 
-	case SEARCH_FROM:
-		if (strcasecmp(ctx->hdr->name, "From") != 0)
-			return;
-		break;
-	case SEARCH_TO:
-		if (strcasecmp(ctx->hdr->name, "To") != 0)
-			return;
-		break;
-	case SEARCH_CC:
-		if (strcasecmp(ctx->hdr->name, "Cc") != 0)
-			return;
-		break;
-	case SEARCH_BCC:
-		if (strcasecmp(ctx->hdr->name, "Bcc") != 0)
-			return;
-		break;
-	case SEARCH_SUBJECT:
-		if (strcasecmp(ctx->hdr->name, "Subject") != 0)
-			return;
-		break;
-	case SEARCH_IN_REPLY_TO:
-		if (strcasecmp(ctx->hdr->name, "In-Reply-To") != 0)
-			return;
-		break;
-	case SEARCH_MESSAGE_ID:
-		if (strcasecmp(ctx->hdr->name, "Message-ID") != 0)
-			return;
-		break;
 	case SEARCH_HEADER:
+	case SEARCH_HEADER_ADDRESS:
 		ctx->custom_header = TRUE;
 
 		if (strcasecmp(ctx->hdr->name, arg->hdr_field_name) != 0)
@@ -532,8 +418,7 @@
 		hdr_search_ctx = search_header_context(ctx->index_context, arg);
 		if (hdr_search_ctx == NULL)
 			ret = 0;
-		else if (arg->type == SEARCH_FROM || arg->type == SEARCH_TO ||
-			 arg->type == SEARCH_CC || arg->type == SEARCH_BCC) {
+		else if (arg->type == SEARCH_HEADER_ADDRESS) {
 			/* we have to match against normalized address */
 			struct message_address *addr;
 			string_t *str;
@@ -574,14 +459,8 @@
 			ARG_SET_RESULT(arg, 0);
 		}
 		break;
-	case SEARCH_FROM:
-	case SEARCH_TO:
-	case SEARCH_CC:
-	case SEARCH_BCC:
-	case SEARCH_SUBJECT:
 	case SEARCH_HEADER:
-	case SEARCH_IN_REPLY_TO:
-	case SEARCH_MESSAGE_ID:
+	case SEARCH_HEADER_ADDRESS:
 		ARG_SET_RESULT(arg, 0);
 		break;
 	default:
@@ -605,15 +484,7 @@
 
 	index_mail_parse_header(part, hdr, ctx->index_context->mail);
 
-	if (ctx->custom_header ||
-	    strcasecmp(hdr->name, "Date") == 0 ||
-	    strcasecmp(hdr->name, "From") == 0 ||
-	    strcasecmp(hdr->name, "To") == 0 ||
-	    strcasecmp(hdr->name, "Cc") == 0 ||
-	    strcasecmp(hdr->name, "Bcc") == 0 ||
-	    strcasecmp(hdr->name, "Subject") == 0 ||
-	    strcasecmp(hdr->name, "In-Reply-To") == 0 ||
-	    strcasecmp(hdr->name, "Message-ID") == 0) {
+	if (ctx->custom_header || strcasecmp(hdr->name, "Date") == 0) {
 		ctx->hdr = hdr;
 
 		ctx->custom_header = FALSE;
@@ -649,17 +520,23 @@
 				 struct mail_search_context *ctx)
 {
 	struct istream *input;
-	int have_headers, have_body, have_text;
+	const char *const *headers;
+	int have_headers, have_body;
 
 	/* first check what we need to use */
-	mail_search_args_analyze(args, &have_headers, &have_body, &have_text);
-	if (!have_headers && !have_body && !have_text)
+	headers = mail_search_args_analyze(args, &have_headers, &have_body);
+	if (!have_headers && !have_body)
 		return TRUE;
 
-	if (have_headers || have_text) {
+	if (have_headers) {
 		struct search_header_context hdr_ctx;
 
-		input = ctx->mail->get_stream(ctx->mail, NULL, NULL);
+		if (have_body)
+			headers = NULL;
+
+		input = headers == NULL ?
+			ctx->mail->get_stream(ctx->mail, NULL, NULL) :
+			ctx->mail->get_headers(ctx->mail, headers);
 		if (input == NULL)
 			return FALSE;
 
@@ -668,7 +545,7 @@
 		hdr_ctx.custom_header = TRUE;
 		hdr_ctx.args = args;
 
-		index_mail_init_parse_header(&ctx->imail);
+		index_mail_parse_header_init(&ctx->imail, headers);
 		message_parse_header(NULL, input, NULL,
 				     search_header, &hdr_ctx);
 	} else {
@@ -681,7 +558,7 @@
 		i_stream_seek(input, hdr_size.physical_size);
 	}
 
-	if (have_text || have_body) {
+	if (have_body) {
 		struct search_body_context body_ctx;
 
 		memset(&body_ctx, 0, sizeof(body_ctx));
@@ -967,6 +844,11 @@
 			ret = FALSE;
 	}
 
+	if (ctx->ibox->fetch_mail.pool != NULL)
+		index_mail_deinit(&ctx->ibox->fetch_mail);
+	if (ctx->imail.pool != NULL)
+		index_mail_deinit(&ctx->imail);
+
 	if (!index_storage_lock(ctx->ibox, MAIL_LOCK_UNLOCK))
 		ret = FALSE;
 
@@ -978,18 +860,42 @@
 	if (ctx->hdr_pool != NULL)
 		pool_unref(ctx->hdr_pool);
 
-	if (ctx->ibox->fetch_mail.pool != NULL)
-		index_mail_deinit(&ctx->ibox->fetch_mail);
-        index_mail_deinit(&ctx->imail);
 	i_free(ctx);
 	return ret;
 }
 
+static int search_match_next(struct mail_search_context *ctx)
+{
+        struct mail_search_arg *arg;
+	int ret;
+
+	/* check the index matches first */
+	mail_search_args_reset(ctx->args);
+	ret = mail_search_args_foreach(ctx->args, search_index_arg, ctx);
+	if (ret >= 0)
+		return ret > 0;
+
+	/* next search only from cached arguments */
+	ret = mail_search_args_foreach(ctx->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->args, ctx))
+		return FALSE;
+
+	for (arg = ctx->args; arg != NULL; arg = arg->next) {
+		if (arg->result != 1)
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
 struct mail *index_storage_search_next(struct mail_search_context *ctx)
 {
 	const struct messageset_mail *msgset_mail;
-        struct mail_search_arg *arg;
-	int found, ret;
+	int ret;
 
 	if (ctx->msgset_ctx == NULL) {
 		/* initialization failed or didn't found any messages */
@@ -998,47 +904,35 @@
 
 	do {
 		msgset_mail = index_messageset_next(ctx->msgset_ctx);
-		if (msgset_mail == NULL)
-			return NULL;
+		if (msgset_mail == NULL) {
+			ret = -1;
+			break;
+		}
 
 		ctx->mail->seq = msgset_mail->client_seq;
 		ctx->mail->uid = msgset_mail->rec->uid;
+
 		ret = index_mail_next(&ctx->imail, msgset_mail->rec,
-				      msgset_mail->idx_seq);
-
-		if (ret < 0)
-			return NULL;
-
-		if (ret == 0)
-			found = FALSE;
-		else {
-			mail_search_args_reset(ctx->args);
-
-			t_push();
-
-			mail_search_args_foreach(ctx->args, search_index_arg,
-						 ctx);
-			mail_search_args_foreach(ctx->args, search_cached_arg,
-						 ctx);
-			mail_search_args_foreach(ctx->args, search_envelope_arg,
-						 ctx);
-			found = search_arg_match_text(ctx->args, ctx);
-
-			t_pop();
-
-			if (ctx->error != NULL)
-				return NULL;
+				      msgset_mail->idx_seq, TRUE);
+		if (ret <= 0) {
+			if (ret < 0)
+				break;
+			continue;
 		}
 
-		if (found) {
-			for (arg = ctx->args; arg != NULL; arg = arg->next) {
-				if (arg->result != 1) {
-					found = FALSE;
-					break;
-				}
-			}
-		}
-	} while (!found);
+		t_push();
+		ret = search_match_next(ctx);
+		t_pop();
+
+		if (ctx->error != NULL)
+			ret = -1;
+	} while (ret == 0);
+
+	if (ret < 0) {
+		/* error or last record */
+		index_mail_deinit(&ctx->imail);
+		return NULL;
+	}
 
 	return ctx->mail;
 }