changeset 408:e057845d94ca HEAD

Dropped sent_time and alignment from MailIndexRecord. SEARCH can now use cached ENVELOPE data to search FROM, TO, CC, BCC, SUBJECT, HEADER MESSAGE-ID and HEADER IN-REPLY-TO. They're never cached anymore now. Also SEARCH SENT* had to be changed to use ENVELOPE (or fallback to Date-header parsing) because sent_time was removed.
author Timo Sirainen <tss@iki.fi>
date Sat, 12 Oct 2002 01:33:54 +0300
parents 6edfb92319cf
children 849f3846212a
files src/lib-imap/imap-envelope.c src/lib-imap/imap-envelope.h src/lib-imap/imap-parser.c src/lib-index/mail-index-update.c src/lib-index/mail-index.h src/lib-mail/rfc822-date.c src/lib-mail/rfc822-date.h src/lib-storage/index/index-fetch.c src/lib-storage/index/index-search.c src/lib-storage/mail-search.c src/lib-storage/mail-search.h
diffstat 11 files changed, 323 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap/imap-envelope.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-imap/imap-envelope.c	Sat Oct 12 01:33:54 2002 +0300
@@ -1,8 +1,10 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "iobuffer.h"
 #include "temp-string.h"
 #include "rfc822-address.h"
+#include "imap-parser.h"
 #include "imap-envelope.h"
 #include "imap-quote.h"
 
@@ -116,3 +118,139 @@
         imap_envelope_write_part_data(data, str);
 	return str->str;
 }
+
+static int imap_address_arg_append(ImapArg *arg, TempString *str, int *in_group)
+{
+	ImapArgList *list;
+	const char *args[4];
+	int i;
+
+	if (arg->type != IMAP_ARG_LIST)
+		return FALSE;
+	list = arg->data.list;
+
+	/* we require 4 arguments, strings or NILs */
+	for (i = 0; i < 4; i++) {
+		if (list == NULL)
+			return FALSE;
+
+		if (list->arg.type == IMAP_ARG_NIL)
+			args[i] = NULL;
+		else if (list->arg.type == IMAP_ARG_STRING)
+			args[i] = list->arg.data.str;
+		else
+			return FALSE;
+	}
+
+	if (str->len > 0)
+		t_string_append(str, ", ");
+
+	if (*in_group) {
+		if (args[0] == NULL && args[1] == NULL &&
+		    args[2] == NULL && args[3] == NULL) {
+			/* end of group */
+			t_string_append_c(str, ';');
+			*in_group = FALSE;
+			return TRUE;
+		}
+	} else {
+		if (args[0] == NULL && args[1] == NULL &&
+		    args[2] != NULL && args[3] == NULL) {
+			/* beginning of group */
+			t_string_append(str, args[2]);
+			t_string_append(str, ": ");
+			*in_group = TRUE;
+			return TRUE;
+		}
+	}
+
+        /* name <@route:mailbox@domain> */
+	if (args[0] != NULL) {
+		t_string_append(str, args[0]);
+		t_string_append_c(str, ' ');
+	}
+
+	t_string_append_c(str, '<');
+	if (args[1] != NULL) {
+		t_string_append_c(str, '@');
+		t_string_append(str, args[1]);
+		t_string_append_c(str, ':');
+	}
+	if (args[2] != NULL)
+		t_string_append(str, args[2]);
+	if (args[3] != NULL) {
+		t_string_append_c(str, '@');
+		t_string_append(str, args[3]);
+	}
+	t_string_append_c(str, '>');
+	return TRUE;
+}
+
+static const char *imap_envelope_parse_address(ImapArg *arg)
+{
+	ImapArgList *list;
+	TempString *str;
+	int in_group;
+
+	if (arg->type != IMAP_ARG_LIST)
+		return NULL;
+
+	in_group = FALSE;
+	str = t_string_new(128);
+	for (list = arg->data.list; list != NULL; list = list->next) {
+		if (!imap_address_arg_append(&list->arg, str, &in_group))
+			return NULL;
+	}
+
+	return str->str;
+}
+
+static const char *
+imap_envelope_parse_arg(ImapArg *arg, ImapEnvelopeField field,
+			const char *envelope)
+{
+	const char *value;
+
+	if (arg->type == IMAP_ARG_NIL)
+		return "";
+
+	if (field >= IMAP_ENVELOPE_FROM && field <= IMAP_ENVELOPE_BCC)
+		value = imap_envelope_parse_address(arg);
+	else if (arg->type == IMAP_ARG_STRING || arg->type == IMAP_ARG_ATOM)
+		value = t_strdup(arg->data.str);
+	else
+		value = NULL;
+
+	if (value == NULL) {
+		i_error("Invalid field %u in IMAP envelope: %s",
+			field, envelope);
+	}
+
+	return value;
+}
+
+const char *imap_envelope_parse(const char *envelope, ImapEnvelopeField field)
+{
+	IOBuffer *inbuf;
+	ImapParser *parser;
+	ImapArg *args;
+	const char *value;
+	int ret;
+
+	i_assert(field < IMAP_ENVELOPE_FIELDS);
+
+	inbuf = io_buffer_create_from_data(envelope, strlen(envelope),
+					   data_stack_pool);
+	parser = imap_parser_create(inbuf, NULL);
+
+	ret = imap_parser_read_args(parser, field, 0, &args);
+	if (ret < 0)
+		i_error("Error parsing IMAP envelope: %s", envelope);
+
+	value = ret < (int)field ? NULL :
+		imap_envelope_parse_arg(&args[field], field, envelope);
+
+	imap_parser_destroy(parser);
+	io_buffer_unref(inbuf);
+	return value;
+}
--- a/src/lib-imap/imap-envelope.h	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-imap/imap-envelope.h	Sat Oct 12 01:33:54 2002 +0300
@@ -3,12 +3,35 @@
 
 typedef struct _MessagePartEnvelopeData MessagePartEnvelopeData;
 
+typedef enum {
+	/* NOTE: in the same order as listed in ENVELOPE */
+	IMAP_ENVELOPE_DATE = 0,
+	IMAP_ENVELOPE_SUBJECT,
+	IMAP_ENVELOPE_FROM,
+	IMAP_ENVELOPE_SENDER,
+	IMAP_ENVELOPE_REPLY_TO,
+	IMAP_ENVELOPE_TO,
+	IMAP_ENVELOPE_CC,
+	IMAP_ENVELOPE_BCC,
+	IMAP_ENVELOPE_IN_REPLY_TO,
+	IMAP_ENVELOPE_MESSAGE_ID,
+
+	IMAP_ENVELOPE_FIELDS
+} ImapEnvelopeField;
+
+/* Update envelope data based from given header field */
 void imap_envelope_parse_header(Pool pool, MessagePartEnvelopeData **data,
 				const char *name,
 				const char *value, size_t value_len);
 
+/* Write envelope to given string */
 void imap_envelope_write_part_data(MessagePartEnvelopeData *data,
 				   TempString *str);
+/* Return envelope. */
 const char *imap_envelope_get_part_data(MessagePartEnvelopeData *data);
 
+/* Parse envelope and return specified field unquoted, or NULL if error
+   occured. NILs are returned as "". */
+const char *imap_envelope_parse(const char *envelope, ImapEnvelopeField field);
+
 #endif
--- a/src/lib-imap/imap-parser.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-imap/imap-parser.c	Sat Oct 12 01:33:54 2002 +0300
@@ -285,8 +285,10 @@
 			return FALSE;
 		}
 
-		io_buffer_send(parser->outbuf, "+ OK\r\n", 6);
-		io_buffer_send_flush(parser->outbuf);
+		if (parser->outbuf != NULL) {
+			io_buffer_send(parser->outbuf, "+ OK\r\n", 6);
+			io_buffer_send_flush(parser->outbuf);
+		}
 	}
 
 	parser->cur_type = ARG_PARSE_LITERAL_DATA;
--- a/src/lib-index/mail-index-update.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-index/mail-index-update.c	Sat Oct 12 01:33:54 2002 +0300
@@ -170,10 +170,9 @@
 			/* corrupted data file - old value had a field
 			   larger than expected */
 			index_set_corrupted(update->index,
-					    "full_field_size points outside "
-					    "data_size (field %d?)",
-					    update->index->filepath,
-					    rec == NULL ? -1 : (int)rec->field);
+				"full_field_size points outside data_size "
+				"(field %u?)", update->index->filepath,
+				rec == NULL ? 0 : rec->field);
 			return FALSE;
 		}
 		memcpy(destrec->data, src, src_size);
@@ -197,7 +196,7 @@
 	if (fpos == 0)
 		return FALSE;
 
-	/* update index file position - it's mmap()ed so it'll be writte
+	/* update index file position - it's mmap()ed so it'll be written
 	   into disk when index is unlocked. */
 	update->rec->data_position = fpos;
 	update->rec->data_size = pos;
@@ -283,45 +282,6 @@
 	update_field_full(update, field, value, size, 0);
 }
 
-static MailField mail_header_get_field(const char *str, size_t len)
-{
-	if (len == 7 && strncasecmp(str, "Subject", 7) == 0)
-		return FIELD_TYPE_SUBJECT;
-	if (len == 4 && strncasecmp(str, "From", 4) == 0)
-		return FIELD_TYPE_FROM;
-	if (len == 2 && strncasecmp(str, "To", 2) == 0)
-		return FIELD_TYPE_TO;
-	if (len == 2 && strncasecmp(str, "Cc", 2) == 0)
-		return FIELD_TYPE_CC;
-	if (len == 3 && strncasecmp(str, "Bcc", 3) == 0)
-		return FIELD_TYPE_BCC;
-
-	return 0;
-}
-
-static const char *field_get_value(const char *value, size_t len)
-{
-	char *ret, *p;
-	size_t i;
-
-	ret = t_malloc(len+1);
-
-	/* compress the long headers (remove \r?\n before space or tab) */
-	for (i = 0, p = ret; i < len; i++) {
-		if (value[i] == '\r' && i+1 != len && value[i+1] == '\n')
-			i++;
-
-		if (value[i] == '\n') {
-			i_assert(IS_LWSP(value[i+1]));
-		} else {
-			*p++ = value[i];
-		}
-	}
-	*p = '\0';
-
-	return ret;
-}
-
 typedef struct {
 	MailIndexUpdate *update;
 	Pool envelope_pool;
@@ -337,30 +297,11 @@
 			       void *context)
 {
 	HeaderUpdateContext *ctx = context;
-	MailField field;
-	const char *str;
 
 	if (part != NULL && part->parent != NULL)
 		return;
 
-	if (name_len == 4 && strncasecmp(name, "Date", 4) == 0) {
-		/* date is stored into index record itself */
-		str = field_get_value(value, value_len);
-		if (!rfc822_parse_date(str, &ctx->update->rec->sent_date))
-			ctx->update->rec->sent_date = ioloop_time;
-	}
-
 	/* see if we can do anything with this field */
-	field = mail_header_get_field(name, name_len);
-	if (field != 0) {
-		/* do we want to store this? */
-		if (ctx->update->index->header->cache_fields & field) {
-			str = field_get_value(value, value_len);
-			ctx->update->index->update_field(ctx->update,
-							 field, str, 0);
-		}
-	}
-
 	if (ctx->update->index->header->cache_fields & FIELD_TYPE_ENVELOPE) {
 		if (ctx->envelope_pool == NULL) {
 			ctx->envelope_pool =
@@ -372,7 +313,6 @@
 					   value, value_len);
 	}
 
-	/* keep this last, it may break the parameter data by moving mmaping */
 	if (ctx->header_func != NULL) {
 		ctx->header_func(part, name, name_len,
 				 value, value_len, ctx->context);
--- a/src/lib-index/mail-index.h	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-index/mail-index.h	Sat Oct 12 01:33:54 2002 +0300
@@ -34,21 +34,16 @@
 
 	   Location field is a good first field anyway, it's the one most
 	   often needed. With maildir format, it's the file name and with
-	   mbox format it's the file position as a string. */
+	   mbox format it's the file position. */
 	FIELD_TYPE_LOCATION		= 0x0001,
 	FIELD_TYPE_ENVELOPE		= 0x0002,
 	FIELD_TYPE_BODY			= 0x0004,
 	FIELD_TYPE_BODYSTRUCTURE	= 0x0008,
-	FIELD_TYPE_FROM			= 0x0010,
-	FIELD_TYPE_TO			= 0x0020,
-	FIELD_TYPE_CC			= 0x0040,
-	FIELD_TYPE_BCC			= 0x0080,
-	FIELD_TYPE_SUBJECT		= 0x0100,
-	FIELD_TYPE_MD5			= 0x0200,
-	FIELD_TYPE_MESSAGEPART		= 0x0400,
+	FIELD_TYPE_MD5			= 0x0010,
+	FIELD_TYPE_MESSAGEPART		= 0x0020,
 
-	FIELD_TYPE_LAST			= 0x0800,
-	FIELD_TYPE_MAX_BITS		= 11
+	FIELD_TYPE_LAST			= 0x0040,
+	FIELD_TYPE_MAX_BITS		= 6
 } MailField;
 
 typedef enum {
@@ -139,18 +134,15 @@
 	unsigned int uid;
 	unsigned int msg_flags; /* MailFlags */
 	time_t internal_date;
-	time_t sent_date;
-
-	uoff_t header_size;
-	uoff_t body_size;
 
 	unsigned int index_flags; /* MailIndexMailFlags */
-	unsigned int cached_fields;
+	unsigned int cached_fields; /* MailField */
 
+	unsigned int data_size;
 	uoff_t data_position;
-	unsigned int data_size;
 
-	unsigned int alignment;
+	uoff_t header_size; /* 0 if not known yet */
+	uoff_t body_size; /* if header_size == 0, the size of full message */
 };
 
 struct _MailIndexDataRecord {
--- a/src/lib-mail/rfc822-date.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-mail/rfc822-date.c	Sat Oct 12 01:33:54 2002 +0300
@@ -97,12 +97,11 @@
 	return ret;
 }
 
-int rfc822_parse_date(const char *str, time_t *time)
+int rfc822_parse_date(const char *str, time_t *time, int *timezone_offset)
 {
 	struct tm tm;
 	const Rfc822Token *tokens, *tok;
 	size_t i;
-	int zone_offset;
 
 	if (str == NULL || *str == '\0')
 		return FALSE;
@@ -198,14 +197,13 @@
 	if (tok == NULL || tok->token != 'A')
 		return FALSE;
 
-	zone_offset = parse_timezone(tok->ptr, tok->len);
+	*timezone_offset = parse_timezone(tok->ptr, tok->len);
 
 	tm.tm_isdst = -1;
 	*time = mktime(&tm);
 	if (*time < 0)
 		return FALSE;
 
-	*time -= zone_offset * 60;
 	return TRUE;
 }
 
--- a/src/lib-mail/rfc822-date.h	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-mail/rfc822-date.h	Sat Oct 12 01:33:54 2002 +0300
@@ -1,7 +1,12 @@
 #ifndef __RFC822_DATE
 #define __RFC822_DATE
 
-int rfc822_parse_date(const char *str, time_t *time);
+/* Parses RFC822 date/time string. time_t is filled with the date without
+   any timezone changes. timezone_offset is filled with the timezone's
+   difference to UTC in minutes. */
+int rfc822_parse_date(const char *str, time_t *time, int *timezone_offset);
+
+/* Create RFC822 date/time string from given time in local timezone. */
 const char *rfc822_to_date(time_t time);
 
 #endif
--- a/src/lib-storage/index/index-fetch.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-storage/index/index-fetch.c	Sat Oct 12 01:33:54 2002 +0300
@@ -226,12 +226,17 @@
 
         mail_cache_context = index_msgcache_get_context(ctx->index, rec);
 
-	virtual_header_size =
-		(rec->index_flags & INDEX_MAIL_FLAG_BINARY_HEADER) ?
-		rec->header_size : 0;
-	virtual_body_size =
-		(rec->index_flags & INDEX_MAIL_FLAG_BINARY_BODY) ?
-		rec->body_size : 0;
+	if (rec->header_size == 0) {
+		virtual_header_size = 0;
+		virtual_body_size = 0;
+	} else {
+		virtual_header_size =
+			(rec->index_flags & INDEX_MAIL_FLAG_BINARY_HEADER) ?
+			rec->header_size : 0;
+		virtual_body_size =
+			(rec->index_flags & INDEX_MAIL_FLAG_BINARY_BODY) ?
+			rec->body_size : 0;
+	}
 
 	imap_msgcache_open(ctx->cache, rec->uid, fields,
 			   virtual_header_size, virtual_body_size,
--- a/src/lib-storage/index/index-search.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-storage/index/index-search.c	Sat Oct 12 01:33:54 2002 +0300
@@ -4,7 +4,10 @@
 #include "iobuffer.h"
 #include "mmap-util.h"
 #include "rfc822-tokenize.h"
+#include "rfc822-date.h"
+#include "message-size.h"
 #include "imap-date.h"
+#include "imap-envelope.h"
 #include "index-storage.h"
 #include "mail-index-util.h"
 #include "mail-modifylog.h"
@@ -155,19 +158,6 @@
 			return FALSE;
 		return rec->internal_date >= t;
 
-	case SEARCH_SENTBEFORE:
-		if (!imap_parse_date(value, &t))
-			return FALSE;
-		return rec->sent_date < t;
-	case SEARCH_SENTON:
-		if (!imap_parse_date(value, &t))
-			return FALSE;
-		return rec->sent_date >= t && rec->sent_date < t + 3600*24;
-	case SEARCH_SENTSINCE:
-		if (!imap_parse_date(value, &t))
-			return FALSE;
-		return rec->sent_date >= t;
-
 	/* sizes, only with fastscanning */
 	case SEARCH_SMALLER:
 		if (!mail_index_get_virtual_size(ibox->index, rec, TRUE, &size))
@@ -201,21 +191,42 @@
 	}
 }
 
-static int match_field(MailIndex *index, MailIndexRecord *rec,
-		       MailField field, const char *value)
+static int search_sent(MailSearchArgType type, const char *value,
+		       const char *sent_value)
 {
-	const char *field_value;
-	size_t i, value_len;
+	time_t search_time, sent_time;
+	int timezone_offset;
+
+	if (!imap_parse_date(value, &search_time))
+		return 0;
+
+	/* NOTE: RFC2060 doesn't specify if timezones should affect
+	   matching, so we ignore them. */
+	if (!rfc822_parse_date(sent_value, &sent_time, &timezone_offset))
+		return 0;
 
-	field_value = index->lookup_field(index, rec, field);
-	if (field_value == NULL)
-		return -1;
+	switch (type) {
+	case SEARCH_SENTBEFORE:
+		return sent_time < search_time;
+	case SEARCH_SENTON:
+		return sent_time >= search_time &&
+			sent_time < search_time + 3600*24;
+	case SEARCH_SENTSINCE:
+		return sent_time >= search_time;
+	default:
+		i_assert(0);
+	}
+}
 
-	/* note: value is already uppercased */
-	value_len = strlen(value);
-	for (i = 0; field_value[i] != '\0'; i++) {
-		if (value[0] == i_toupper(field_value[i]) &&
-		    strncasecmp(value, field_value+i, value_len) == 0)
+static int search_substr(const char *haystack, const char *needle)
+{
+	size_t i, needle_len;
+
+	/* note: needle is already uppercased */
+	needle_len = strlen(needle);
+	for (i = 0; haystack[i] != '\0'; i++) {
+		if (needle[0] == i_toupper(haystack[i]) &&
+		    strncasecmp(needle, haystack+i, needle_len) == 0)
 			return 1;
 	}
 
@@ -226,20 +237,64 @@
 static int search_arg_match_cached(MailIndex *index, MailIndexRecord *rec,
 				   MailSearchArgType type, const char *value)
 {
+        ImapEnvelopeField env_field;
+	const char *envelope, *field;
+	int ret;
+
 	switch (type) {
+	case SEARCH_SENTBEFORE:
+	case SEARCH_SENTON:
+	case SEARCH_SENTSINCE:
+                env_field = IMAP_ENVELOPE_DATE;
+		break;
+
 	case SEARCH_FROM:
-		return match_field(index, rec, FIELD_TYPE_FROM, value);
+                env_field = IMAP_ENVELOPE_FROM;
+		break;
 	case SEARCH_TO:
-		return match_field(index, rec, FIELD_TYPE_TO, value);
+                env_field = IMAP_ENVELOPE_TO;
+		break;
 	case SEARCH_CC:
-		return match_field(index, rec, FIELD_TYPE_CC, value);
+                env_field = IMAP_ENVELOPE_CC;
+		break;
 	case SEARCH_BCC:
-		return match_field(index, rec, FIELD_TYPE_BCC, value);
+                env_field = IMAP_ENVELOPE_BCC;
+		break;
 	case SEARCH_SUBJECT:
-		return match_field(index, rec, FIELD_TYPE_SUBJECT, value);
+                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, rec, FIELD_TYPE_ENVELOPE);
+	field = envelope == NULL ? NULL :
+		imap_envelope_parse(envelope, env_field);
+
+	if (field == NULL)
+		ret = -1;
+	else {
+		switch (type) {
+		case SEARCH_SENTBEFORE:
+		case SEARCH_SENTON:
+		case SEARCH_SENTSINCE:
+			ret = search_sent(type, value, field);
+		default:
+			ret = search_substr(field, value);
+		}
+	}
+	t_pop();
+	return ret;
 }
 
 static void search_cached_arg(MailSearchArg *arg, void *context)
@@ -351,6 +406,17 @@
 
 	/* first check that the field name matches to argument. */
 	switch (arg->type) {
+	case SEARCH_SENTBEFORE:
+	case SEARCH_SENTON:
+	case SEARCH_SENTSINCE:
+		/* date is handled differently than others */
+		if (ctx->name_len == 4 &&
+		    strncasecmp(ctx->name, "Date", 4) == 0) {
+			search_sent(arg->type, arg->value.str,
+				    t_strndup(ctx->value, ctx->value_len));
+		}
+		return;
+
 	case SEARCH_FROM:
 		if (ctx->name_len != 4 ||
 		    strncasecmp(ctx->name, "From", 4) != 0)
@@ -407,6 +473,7 @@
 	SearchHeaderContext *ctx = context;
 
 	if ((name_len > 0 && ctx->custom_header) ||
+	    (name_len == 4 && strncasecmp(name, "Date", 4) == 0) ||
 	    (name_len == 4 && strncasecmp(name, "From", 4) == 0) ||
 	    (name_len == 2 && strncasecmp(name, "To", 2) == 0) ||
 	    (name_len == 2 && strncasecmp(name, "Cc", 2) == 0) ||
@@ -505,6 +572,7 @@
 				 MailSearchArg *args)
 {
 	IOBuffer *inbuf;
+	MessageSize hdr_size;
 	int have_headers, have_body, have_text;
 
 	/* first check what we need to use */
@@ -524,7 +592,15 @@
 		/* header checks */
 		ctx.custom_header = TRUE;
 		ctx.args = args;
-		message_parse_header(NULL, inbuf, NULL, search_header, &ctx);
+		message_parse_header(NULL, inbuf, &hdr_size,
+				     search_header, &ctx);
+
+		i_assert(rec->header_size == 0 ||
+			 hdr_size.physical_size == rec->header_size);
+	} else if (rec->header_size == 0) {
+		message_get_header_size(inbuf, &hdr_size);
+	} else {
+		hdr_size.physical_size = rec->header_size;
 	}
 
 	if (have_text) {
@@ -536,15 +612,14 @@
 			}
 		}
 
-		search_arg_match_data(inbuf, rec->header_size,
+		search_arg_match_data(inbuf, hdr_size.physical_size,
 				      args, search_text_header);
 	}
 
 	if (have_text || have_body) {
-		if (inbuf->offset != rec->header_size) {
+		if (inbuf->offset == 0) {
 			/* skip over headers */
-			i_assert(inbuf->offset == 0);
-			io_buffer_skip(inbuf, rec->header_size);
+			io_buffer_skip(inbuf, hdr_size.physical_size);
 		}
 
 		search_arg_match_data(inbuf, rec->body_size, args,
--- a/src/lib-storage/mail-search.c	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-storage/mail-search.c	Sat Oct 12 01:33:54 2002 +0300
@@ -161,6 +161,12 @@
 			} else if (strcmp(key, "SUBJECT") == 0) {
 				*args = (*args)->next;
 				return ARG_NEW(SEARCH_SUBJECT, 1);
+			} else if (strcmp(key, "IN-REPLY-TO") == 0) {
+				*args = (*args)->next;
+				return ARG_NEW(SEARCH_IN_REPLY_TO, 1);
+			} else if (strcmp(key, "MESSAGE-ID") == 0) {
+				*args = (*args)->next;
+				return ARG_NEW(SEARCH_MESSAGE_ID, 1);
 			} else {
 				return ARG_NEW(SEARCH_HEADER, 2);
 			}
@@ -466,11 +472,16 @@
 			subarg = subarg->next;
 		}
 		break;
+	case SEARCH_SENTBEFORE:
+	case SEARCH_SENTON:
+	case SEARCH_SENTSINCE:
 	case SEARCH_FROM:
 	case SEARCH_TO:
 	case SEARCH_CC:
 	case SEARCH_BCC:
 	case SEARCH_SUBJECT:
+	case SEARCH_IN_REPLY_TO:
+	case SEARCH_MESSAGE_ID:
 	case SEARCH_HEADER:
 		*have_headers = TRUE;
 		break;
--- a/src/lib-storage/mail-search.h	Fri Oct 11 15:46:18 2002 +0300
+++ b/src/lib-storage/mail-search.h	Sat Oct 12 01:33:54 2002 +0300
@@ -44,7 +44,11 @@
 
 	/* body */
 	SEARCH_BODY,
-	SEARCH_TEXT
+	SEARCH_TEXT,
+
+	/* our shortcuts for headers */
+        SEARCH_IN_REPLY_TO,
+        SEARCH_MESSAGE_ID
 } MailSearchArgType;
 
 struct _MailSearchArg {