changeset 369:d037915978ca HEAD

message_parse_header() now calls the function with empty name/value at end of headers. we use this feature with mbox to allow usage of Content-Length header field.
author Timo Sirainen <tss@iki.fi>
date Sun, 06 Oct 2002 12:20:20 +0300
parents 44751b4d92e1
children b0a62e264b22
files src/lib-imap/imap-message-cache.c src/lib-index/mail-index-update.c src/lib-index/mbox/mbox-append.c src/lib-index/mbox/mbox-fsck.c src/lib-index/mbox/mbox-index.c src/lib-index/mbox/mbox-index.h src/lib-index/mbox/mbox-rewrite.c src/lib-mail/message-parser.c src/lib-mail/message-parser.h src/lib-storage/index/index-fetch-section.c src/lib-storage/index/index-search.c
diffstat 11 files changed, 141 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap/imap-message-cache.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-imap/imap-message-cache.c	Sun Oct 06 12:20:20 2002 +0300
@@ -242,12 +242,6 @@
 						     msg);
 			}
 
-			if (msg->envelope == NULL) {
-				imap_envelope_parse_header(msg->pool,
-							   &msg->envelope,
-							   "", "", 0);
-			}
-
 			value = imap_envelope_get_part_data(msg->envelope);
 		}
 
--- a/src/lib-index/mail-index-update.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mail-index-update.c	Sun Oct 06 12:20:20 2002 +0300
@@ -343,11 +343,6 @@
 	if (part != NULL && part->parent != NULL)
 		return;
 
-	if (ctx->header_func != NULL) {
-		ctx->header_func(part, name, name_len,
-				 value, value_len, ctx->context);
-	}
-
 	if (name_len == 4 && strncasecmp(name, "Date", 4) == 0) {
 		/* date is stored into index record itself */
 		str = field_get_value(value, value_len);
@@ -376,6 +371,12 @@
 					   t_strndup(name, name_len),
 					   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);
+	}
 }
 
 void mail_index_update_headers(MailIndexUpdate *update, IOBuffer *inbuf,
--- a/src/lib-index/mbox/mbox-append.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mbox/mbox-append.c	Sun Oct 06 12:20:20 2002 +0300
@@ -29,7 +29,7 @@
 	MailIndexUpdate *update;
         MboxHeaderContext ctx;
 	time_t internal_date;
-	uoff_t abs_start_offset, stop_offset;
+	uoff_t abs_start_offset, eoh_offset;
 	unsigned char *data, md5_digest[16];
 	size_t size, pos;
 	int failed;
@@ -65,9 +65,10 @@
 	io_buffer_skip(inbuf, pos+1);
 	abs_start_offset = inbuf->start_offset + inbuf->offset;
 
-	/* now, find the ending "[\r]\nFrom " */
-	mbox_skip_message(inbuf);
-	stop_offset = inbuf->offset;
+	/* now, find the end of header. also stops at "\nFrom " if it's
+	   found (broken messages) */
+	mbox_skip_header(inbuf);
+	eoh_offset = inbuf->offset;
 
 	/* add message to index */
 	rec = mail_index_record_append_begin(index, internal_date);
@@ -82,18 +83,18 @@
 
 	/* parse the header and cache wanted fields. get the message flags
 	   from Status and X-Status fields. temporarily limit the buffer size
-	   so the message body is parsed properly (FIXME: does this have
-	   side effects?) */
-	mbox_header_init_context(&ctx, index);
+	   so the message body is parsed properly */
+	mbox_header_init_context(&ctx, index, inbuf);
+        ctx.set_read_limit = TRUE;
 
 	io_buffer_seek(inbuf, abs_start_offset - inbuf->start_offset);
 
-	io_buffer_set_read_limit(inbuf, stop_offset);
+	io_buffer_set_read_limit(inbuf, eoh_offset);
 	mail_index_update_headers(update, inbuf, 0, mbox_header_func, &ctx);
+
+	io_buffer_seek(inbuf, inbuf->limit);
 	io_buffer_set_read_limit(inbuf, 0);
 
-	io_buffer_seek(inbuf, stop_offset);
-
 	/* save MD5 */
 	md5_final(&ctx.md5, md5_digest);
 	index->update_field_raw(update, FIELD_TYPE_MD5,
--- a/src/lib-index/mbox/mbox-fsck.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mbox/mbox-fsck.c	Sun Oct 06 12:20:20 2002 +0300
@@ -41,41 +41,6 @@
                 memcmp(old_digest, current_digest, 16) == 0;
 }
 
-static int verify_end_of_body(IOBuffer *inbuf, uoff_t end_offset)
-{
-	unsigned char *data;
-	size_t size;
-
-	/* don't bother parsing the whole body, just make
-	   sure it ends properly */
-	io_buffer_seek(inbuf, end_offset);
-
-	if (inbuf->offset == inbuf->size) {
-		/* end of file. a bit unexpected though,
-		   since \n is missing. */
-		return TRUE;
-	}
-
-	/* read forward a bit */
-	if (io_buffer_read_data_blocking(inbuf, &data, &size, 6) < 0)
-		return FALSE;
-
-	/* either there should be the next From-line,
-	   or [\r]\n at end of file */
-	if (size > 0 && data[0] == '\r') {
-		data++; size--;
-	}
-	if (size > 0) {
-		if (data[0] != '\n')
-			return FALSE;
-
-		data++; size--;
-	}
-
-	return size == 0 ||
-		(size >= 5 && strncmp((char *) data, "From ", 5) == 0);
-}
-
 static int mail_update_header_size(MailIndex *index, MailIndexRecord *rec,
 				   MailIndexUpdate *update,
 				   MessageSize *hdr_size)
@@ -137,14 +102,14 @@
 	if (rec->body_size == 0) {
 		/* possibly broken message, find the From-line to make sure
 		   header parser won't pass it. */
-		mbox_skip_message(inbuf);
+		mbox_skip_header(inbuf);
 		io_buffer_set_read_limit(inbuf, inbuf->offset);
 		io_buffer_seek(inbuf, header_offset);
 	}
 
 	/* get the MD5 sum of fixed headers and the current message flags
 	   in Status and X-Status fields */
-        mbox_header_init_context(&ctx, index);
+        mbox_header_init_context(&ctx, index, inbuf);
 	message_parse_header(NULL, inbuf, &hdr_size, mbox_header_func, &ctx);
 	md5_final(&ctx.md5, current_digest);
 
@@ -154,7 +119,8 @@
 	body_offset = inbuf->offset;
 	do {
 		if (verify_header_md5sum(index, rec, current_digest) &&
-		    verify_end_of_body(inbuf, body_offset + rec->body_size)) {
+		    mbox_verify_end_of_body(inbuf,
+					    body_offset + rec->body_size)) {
 			/* valid message */
 			update = index->update_begin(index, rec);
 
--- a/src/lib-index/mbox/mbox-index.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.c	Sun Oct 06 12:20:20 2002 +0300
@@ -54,12 +54,14 @@
 	}
 }
 
-void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index)
+void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index,
+			      IOBuffer *inbuf)
 {
 	memset(ctx, 0, sizeof(MboxHeaderContext));
 	md5_init(&ctx->md5);
 
 	ctx->index = index;
+	ctx->inbuf = inbuf;
 	ctx->custom_flags = mail_custom_flags_list_get(index->custom_flags);
 }
 
@@ -188,10 +190,33 @@
 		      void *context)
 {
 	MboxHeaderContext *ctx = context;
+	uoff_t start_offset, end_offset;
+	size_t i;
 	int fixed = FALSE;
 
 	/* Pretty much copy&pasted from popa3d by Solar Designer */
 	switch (*name) {
+	case '\0':
+		/* End of headers */
+		if (!ctx->set_read_limit)
+			break;
+
+		/* a) use Content-Length, b) search for "From "-line */
+		start_offset = ctx->inbuf->offset;
+		io_buffer_set_read_limit(ctx->inbuf, 0);
+
+		end_offset = start_offset + ctx->content_length;
+		if (ctx->content_length == 0 ||
+		    !mbox_verify_end_of_body(ctx->inbuf, end_offset)) {
+			mbox_skip_message(ctx->inbuf);
+			end_offset = ctx->inbuf->offset;
+			ctx->content_length = end_offset - start_offset;
+		}
+
+		io_buffer_seek(ctx->inbuf, start_offset);
+		io_buffer_set_read_limit(ctx->inbuf, end_offset);
+		break;
+
 	case 'R':
 	case 'r':
 		if (!ctx->received && name_len == 8 &&
@@ -201,6 +226,25 @@
 		}
 		break;
 
+	case 'C':
+	case 'c':
+		if (name_len == 14 &&
+		    strncasecmp(name, "Content-Length", 14) == 0) {
+			/* manual parsing, so we can deal with uoff_t */
+			ctx->content_length = 0;
+			for (i = 0; i < value_len; i++) {
+				if (value[i] < '0' || value[i] > '9') {
+					/* invalid */
+					ctx->content_length = 0;
+					break;
+				}
+
+				ctx->content_length = ctx->content_length * 10 +
+					(value[i] - '0');
+			}
+		}
+		break;
+
 	case 'D':
 	case 'd':
 		if (name_len == 12)
@@ -369,7 +413,7 @@
 	return FALSE;
 }
 
-void mbox_skip_message(IOBuffer *inbuf)
+static void mbox_skip_forward(IOBuffer *inbuf, int header)
 {
 	unsigned char *msg;
 	size_t i, size, startpos;
@@ -379,6 +423,16 @@
 	startpos = i = 0; lastmsg = TRUE;
 	while (io_buffer_read_data_blocking(inbuf, &msg, &size, startpos) > 0) {
 		for (i = startpos; i < size; i++) {
+			if (msg[i] == '\n' && header && i >= 1) {
+				/* \n[\r]\n - end of header? */
+				if (msg[i-1] == '\n' ||
+				    (msg[i-1] == '\r' && i >= 2 &&
+				     msg[i-2] == '\r')) {
+					i++;
+					break;
+				}
+			}
+
 			if (msg[i] == ' ' && i >= 5) {
 				/* See if it's space after "From" */
 				if (msg[i-5] == '\n' && msg[i-4] == 'F' &&
@@ -425,6 +479,51 @@
 	io_buffer_skip(inbuf, startpos);
 }
 
+void mbox_skip_header(IOBuffer *inbuf)
+{
+	mbox_skip_forward(inbuf, TRUE);
+}
+
+void mbox_skip_message(IOBuffer *inbuf)
+{
+	mbox_skip_forward(inbuf, FALSE);
+}
+
+int mbox_verify_end_of_body(IOBuffer *inbuf, uoff_t end_offset)
+{
+	unsigned char *data;
+	size_t size;
+
+	/* don't bother parsing the whole body, just make
+	   sure it ends properly */
+	io_buffer_seek(inbuf, end_offset);
+
+	if (inbuf->offset == inbuf->size) {
+		/* end of file. a bit unexpected though,
+		   since \n is missing. */
+		return TRUE;
+	}
+
+	/* read forward a bit */
+	if (io_buffer_read_data_blocking(inbuf, &data, &size, 6) < 0)
+		return FALSE;
+
+	/* either there should be the next From-line,
+	   or [\r]\n at end of file */
+	if (size > 0 && data[0] == '\r') {
+		data++; size--;
+	}
+	if (size > 0) {
+		if (data[0] != '\n')
+			return FALSE;
+
+		data++; size--;
+	}
+
+	return size == 0 ||
+		(size >= 5 && strncmp((char *) data, "From ", 5) == 0);
+}
+
 int mbox_mail_get_start_offset(MailIndex *index, MailIndexRecord *rec,
 			       uoff_t *offset)
 {
--- a/src/lib-index/mbox/mbox-index.h	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mbox/mbox-index.h	Sun Oct 06 12:20:20 2002 +0300
@@ -10,6 +10,10 @@
 	const char **custom_flags;
 	MD5Context md5;
 	int received;
+
+	IOBuffer *inbuf;
+	uoff_t content_length;
+	int set_read_limit;
 } MboxHeaderContext;
 
 int mbox_set_syscall_error(MailIndex *index, const char *function);
@@ -20,7 +24,8 @@
 IOBuffer *mbox_file_open(MailIndex *index, uoff_t offset, int reopen);
 void mbox_file_close(MailIndex *index);
 
-void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index);
+void mbox_header_init_context(MboxHeaderContext *ctx, MailIndex *index,
+			      IOBuffer *inbuf);
 void mbox_header_free_context(MboxHeaderContext *ctx);
 void mbox_header_func(MessagePart *part __attr_unused__,
 		      const char *name, size_t name_len,
@@ -32,7 +37,9 @@
 			 void *context);
 int mbox_skip_crlf(IOBuffer *inbuf);
 void mbox_skip_empty_lines(IOBuffer *inbuf);
+void mbox_skip_header(IOBuffer *inbuf);
 void mbox_skip_message(IOBuffer *inbuf);
+int mbox_verify_end_of_body(IOBuffer *inbuf, uoff_t end_offset);
 int mbox_mail_get_start_offset(MailIndex *index, MailIndexRecord *rec,
 			       uoff_t *offset);
 
--- a/src/lib-index/mbox/mbox-rewrite.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-index/mbox/mbox-rewrite.c	Sun Oct 06 12:20:20 2002 +0300
@@ -254,7 +254,7 @@
 			ctx->ximapbase_found = TRUE;
 			(void)mbox_write_ximapbase(ctx);
 		}
-	} else {
+	} else if (name_len > 0) {
 		/* save this header */
 		(void)io_buffer_send(ctx->outbuf, name, name_len);
 		(void)io_buffer_send(ctx->outbuf, ": ", 2);
--- a/src/lib-mail/message-parser.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-mail/message-parser.c	Sun Oct 06 12:20:20 2002 +0300
@@ -425,6 +425,11 @@
 			hdr_size->physical_size + missing_cr_count;
 		i_assert(hdr_size->virtual_size >= hdr_size->physical_size);
 	}
+
+	if (func != NULL) {
+		/* "end of headers" notify */
+		func(part, "", 0, "", 0, context);
+	}
 }
 
 static MessageBoundary *boundary_find(MessageBoundary *boundaries,
--- a/src/lib-mail/message-parser.h	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-mail/message-parser.h	Sun Oct 06 12:20:20 2002 +0300
@@ -36,7 +36,8 @@
 	void *context;
 };
 
-/* NOTE: name and value aren't \0-terminated */
+/* NOTE: name and value aren't \0-terminated. Also called once at end of
+   headers with name_len = value_len = 0. */
 typedef void (*MessageHeaderFunc)(MessagePart *part,
 				  const char *name, size_t name_len,
 				  const char *value, size_t value_len,
--- a/src/lib-storage/index/index-fetch-section.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-storage/index/index-fetch-section.c	Sun Oct 06 12:20:20 2002 +0300
@@ -78,7 +78,8 @@
 {
 	const char *field, *name_start, *name_end;
 
-	i_assert(size > 0);
+	if (size == 0)
+		return FALSE;
 
 	name_start = name;
 	name_end = name + size;
--- a/src/lib-storage/index/index-search.c	Sun Oct 06 10:41:06 2002 +0300
+++ b/src/lib-storage/index/index-search.c	Sun Oct 06 12:20:20 2002 +0300
@@ -406,7 +406,7 @@
 {
 	SearchHeaderContext *ctx = context;
 
-	if (ctx->custom_header ||
+	if ((name_len > 0 && ctx->custom_header) ||
 	    (name_len == 4 && strncasecmp(name, "From", 4) == 0) ||
 	    (name_len == 2 && strncasecmp(name, "To", 2) == 0) ||
 	    (name_len == 2 && strncasecmp(name, "Cc", 2) == 0) ||