[dovecot-cvs] dovecot/src/lib-storage/index index-mail.c,1.6,1.7 index-mail.h,1.2,1.3 index-save.c,1.29,1.30 index-search.c,1.68,1.69 index-storage.h,1.34,1.35

cras at procontrol.fi cras at procontrol.fi
Wed Mar 26 19:29:05 EET 2003


Update of /home/cvs/dovecot/src/lib-storage/index
In directory danu:/tmp/cvs-serv10853/lib-storage/index

Modified Files:
	index-mail.c index-mail.h index-save.c index-search.c 
	index-storage.h 
Log Message:
Better handling for multiline headers. Before we skipped headers larger than
input buffer size (8k with read (default), 256k with mmap). The skipping was
also a bit buggy.

Now we parse the lines one at a time. There's also a way to read the header
fully into memory before parsing it, if really needed.



Index: index-mail.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-mail.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- index-mail.c	26 Mar 2003 15:40:16 -0000	1.6
+++ index-mail.c	26 Mar 2003 17:29:02 -0000	1.7
@@ -16,55 +16,6 @@
 
 #include <ctype.h>
 
-static int get_envelope_header_field(const char *name,
-				     enum imap_envelope_field *ret)
-{
-	*ret = (enum imap_envelope_field)-1;
-
-	switch (i_toupper(*name)) {
-	case 'B':
-		if (strcasecmp(name, "bcc") == 0)
-			*ret = IMAP_ENVELOPE_BCC;
-		break;
-	case 'C':
-		if (strcasecmp(name, "cc") == 0)
-			*ret = IMAP_ENVELOPE_CC;
-		break;
-	case 'D':
-		if (strcasecmp(name, "date") == 0)
-			*ret = IMAP_ENVELOPE_DATE;
-		break;
-	case 'F':
-		if (strcasecmp(name, "from") == 0)
-			*ret = IMAP_ENVELOPE_FROM;
-		break;
-	case 'I':
-		if (strcasecmp(name, "in-reply-to") == 0)
-			*ret = IMAP_ENVELOPE_IN_REPLY_TO;
-		break;
-	case 'M':
-		if (strcasecmp(name, "message-id") == 0)
-			*ret = IMAP_ENVELOPE_MESSAGE_ID;
-		break;
-	case 'R':
-		if (strcasecmp(name, "reply-to") == 0)
-			*ret = IMAP_ENVELOPE_REPLY_TO;
-		break;
-	case 'S':
-		if (strcasecmp(name, "subject") == 0)
-			*ret = IMAP_ENVELOPE_SUBJECT;
-		if (strcasecmp(name, "sender") == 0)
-			*ret = IMAP_ENVELOPE_SENDER;
-		break;
-	case 'T':
-		if (strcasecmp(name, "to") == 0)
-			*ret = IMAP_ENVELOPE_TO;
-		break;
-	}
-
-	return *ret != (enum imap_envelope_field)-1;
-}
-
 static struct message_part *get_cached_parts(struct index_mail *mail)
 {
 	struct message_part *part;
@@ -192,20 +143,17 @@
 }
 
 void index_mail_parse_header(struct message_part *part __attr_unused__,
-			     const unsigned char *name, size_t name_len,
-			     const unsigned char *value, size_t value_len,
-			     void *context)
+			     struct message_header_line *hdr, void *context)
 {
 	struct index_mail *mail = context;
 	struct index_mail_data *data = &mail->data;
-	struct cached_header *hdr;
+	struct cached_header *cached_hdr;
 
 	if (data->save_envelope) {
+		imap_envelope_parse_header(mail->pool,
+					   &data->envelope_data, hdr);
 
-		imap_envelope_parse_header(mail->pool, &data->envelope_data,
-					   name, name_len, value, value_len);
-
-		if (name_len == 0) {
+		if (hdr == NULL) {
 			/* finalize the envelope */
 			string_t *str;
 
@@ -215,37 +163,51 @@
 		}
 	}
 
-	if (name_len == 4 && data->save_sent_time &&
-	    memcasecmp(name, "date",4) == 0) {
-		if (!message_date_parse(value, value_len, &data->sent_time,
-					&data->sent_timezone)) {
-			/* 0 == parse error */
+	if (hdr == NULL) {
+		/* end of headers */
+		if (data->save_sent_time) {
+			/* not found */
 			data->sent_time = 0;
 			data->sent_timezone = 0;
+			data->save_sent_time = FALSE;
 		}
-		data->save_sent_time = FALSE;
+		return;
 	}
 
-	if (name_len == 0) {
-		/* end of headers */
-		if (data->save_sent_time) {
-			/* not found */
+	if (data->save_sent_time && strcasecmp(hdr->name, "Date") == 0) {
+		if (hdr->continues) {
+			hdr->use_full_value = TRUE;
+			return;
+		}
+		if (!message_date_parse(hdr->full_value, hdr->full_value_len,
+					&data->sent_time,
+					&data->sent_timezone)) {
+			/* 0 == parse error */
 			data->sent_time = 0;
 			data->sent_timezone = 0;
-			data->save_sent_time = FALSE;
 		}
+		data->save_sent_time = FALSE;
 	}
 
-	for (hdr = data->headers; hdr != NULL; hdr = hdr->next) {
-		if (hdr->name_len == name_len &&
-		    memcasecmp(hdr->name, name, name_len) == 0) {
+        cached_hdr = data->headers;
+	while (cached_hdr != NULL) {
+		if (cached_hdr->name_len == hdr->name_len &&
+		    memcasecmp(hdr->name, hdr->name, hdr->name_len) == 0) {
 			/* save only the first header */
-			if (hdr->value == NULL) {
-				hdr->value = p_strndup(mail->pool,
-						       value, value_len);
+			if (cached_hdr->value != NULL)
+				break;
+
+			if (hdr->continues) {
+				hdr->use_full_value = TRUE;
+				break;
 			}
+
+			cached_hdr->value = p_strndup(mail->pool,
+						      hdr->full_value,
+						      hdr->full_value_len);
 			break;
 		}
+                cached_hdr = cached_hdr->next;
 	}
 }
 
@@ -479,7 +441,7 @@
 	}
 
 	if (data->parse_header || data->envelope == NULL ||
-	    !get_envelope_header_field(field, &env_field)) {
+	    !imap_envelope_get_field(field, &env_field)) {
 		/* if we have to parse the header, do it even if we could use
 		   envelope - envelope parsing would just slow up. */
                 prepend_cached_header(mail, field);
@@ -528,7 +490,7 @@
 	const char *ret = NULL;
 
 	if (data->envelope != NULL &&
-	    get_envelope_header_field(field, &env_field)) {
+	    imap_envelope_get_field(field, &env_field)) {
 		/* prefer parsing envelope - faster than having to actually
 		   parse the header field */
 		t_push();
@@ -748,7 +710,7 @@
 		int envelope_headers = FALSE;
 
 		for (tmp = mail->wanted_headers; *tmp != NULL; tmp++) {
-			if (get_envelope_header_field(*tmp, &env_field))
+			if (imap_envelope_get_field(*tmp, &env_field))
 				envelope_headers = TRUE;
 			else {
 				open_mail = TRUE;

Index: index-mail.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-mail.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- index-mail.h	21 Jan 2003 19:56:33 -0000	1.2
+++ index-mail.h	26 Mar 2003 17:29:02 -0000	1.3
@@ -38,6 +38,7 @@
 
 	pool_t pool;
 	struct index_mailbox *ibox;
+	buffer_t *header_buf;
 
 	enum mail_fetch_field wanted_fields;
 	const char *const *wanted_headers;
@@ -51,8 +52,6 @@
 
 void index_mail_init_parse_header(struct index_mail *mail);
 void index_mail_parse_header(struct message_part *part,
-			     const unsigned char *name, size_t name_len,
-			     const unsigned char *value, size_t value_len,
-			     void *context);
+			     struct message_header_line *hdr, void *context);
 
 #endif

Index: index-save.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-save.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- index-save.c	5 Mar 2003 01:43:16 -0000	1.29
+++ index-save.c	26 Mar 2003 17:29:02 -0000	1.30
@@ -9,19 +9,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-struct save_header_context {
-	struct mail_storage *storage;
-	const char *path;
-
-	struct ostream *output;
-	write_func_t *write_func;
-
-	header_callback_t *header_callback;
-	void *context;
-
-	int failed;
-};
-
 static int write_with_crlf(struct ostream *output, const void *v_data,
 			   size_t size)
 {
@@ -103,45 +90,53 @@
 	}
 }
 
-static void save_header_callback(struct message_part *part __attr_unused__,
-				 const unsigned char *name, size_t name_len,
-				 const unsigned char *value, size_t value_len,
-				 void *context)
+static int save_headers(struct istream *input, struct ostream *output,
+			header_callback_t *header_callback, void *context,
+			write_func_t *write_func)
 {
-	struct save_header_context *ctx = context;
-	int ret;
+	struct message_header_parser_ctx *hdr_ctx;
+	struct message_header_line *hdr;
+	int ret, failed = FALSE;
 
-	if (ctx->failed)
-		return;
+	hdr_ctx = message_parse_header_init(input, NULL);
+	while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) {
+		ret = header_callback(hdr->name, write_func, context);
+		if (ret <= 0) {
+			if (ret < 0) {
+				failed = TRUE;
+				break;
+			}
+			continue;
+		}
 
-	ret = ctx->header_callback(name, name_len, ctx->write_func,
-				   ctx->context);
-	if (ret <= 0) {
-		if (ret < 0)
-			ctx->failed = TRUE;
-		return;
+		if (!hdr->eoh) {
+			if (!hdr->continued) {
+				(void)o_stream_send(output, hdr->name,
+						    hdr->name_len);
+				(void)o_stream_send(output, ": ", 2);
+			}
+			(void)o_stream_send(output, hdr->value, hdr->value_len);
+			if (!hdr->no_newline)
+				write_func(output, "\n", 1);
+		}
 	}
+	if (!failed) {
+		if (header_callback(NULL, write_func, context) < 0)
+			failed = TRUE;
 
-	if (name_len == 0) {
-		name = "\n"; value_len = 1;
-	} else {
-		if (value[value_len] == '\r')
-			value_len++;
-		i_assert(value[value_len] == '\n');
-		value_len += (size_t) (value-name) + 1;
+		/* end of headers */
+		write_func(output, "\n", 1);
 	}
+	message_parse_header_deinit(hdr_ctx);
 
-	if (ctx->write_func(ctx->output, name, value_len) < 0) {
-		set_write_error(ctx->storage, ctx->output, ctx->path);
-		ctx->failed = TRUE;
-	}
+	return !failed;
 }
 
 int index_storage_save(struct mail_storage *storage, const char *path,
 		       struct istream *input, struct ostream *output,
 		       header_callback_t *header_callback, void *context)
 {
-	int (*write_func)(struct ostream *, const void *, size_t);
+        write_func_t *write_func;
 	const unsigned char *data;
 	size_t size;
 	ssize_t ret;
@@ -150,20 +145,8 @@
 	write_func = getenv("MAIL_SAVE_CRLF") ? write_with_crlf : write_with_lf;
 
 	if (header_callback != NULL) {
-		struct save_header_context ctx;
-
-		memset(&ctx, 0, sizeof(ctx));
-		ctx.storage = storage;
-		ctx.output = output;
-		ctx.path = path;
-		ctx.write_func = write_func;
-		ctx.header_callback = header_callback;
-		ctx.context = context;
-
-		message_parse_header(NULL, input, NULL,
-				     save_header_callback, &ctx);
-
-		if (ctx.failed)
+		if (!save_headers(input, output, header_callback,
+				  context, write_func))
 			return FALSE;
 	}
 

Index: index-search.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-search.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -d -r1.68 -r1.69
--- index-search.c	1 Feb 2003 11:37:22 -0000	1.68
+++ index-search.c	26 Mar 2003 17:29:02 -0000	1.69
@@ -41,8 +41,7 @@
         struct mail_search_context *index_context;
 	struct mail_search_arg *args;
 
-	const unsigned char *name, *value;
-	size_t name_len, value_len;
+        struct message_header_line *hdr;
 
 	unsigned int custom_header:1;
 	unsigned int threading:1;
@@ -283,7 +282,7 @@
 }
 
 static int search_sent(enum mail_search_arg_type type, const char *search_value,
-		       const char *sent_value)
+		       const unsigned char *sent_value, size_t sent_value_len)
 {
 	time_t search_time, sent_time;
 	int timezone_offset;
@@ -296,7 +295,7 @@
 
 	/* NOTE: Latest IMAP4rev1 draft specifies that timezone is ignored
 	   in searches. sent_time is returned as UTC, so change it. */
-	if (!message_date_parse((const unsigned char *) sent_value, (size_t)-1,
+	if (!message_date_parse(sent_value, sent_value_len,
 				&sent_time, &timezone_offset))
 		return 0;
 	sent_time -= timezone_offset * 60;
@@ -404,7 +403,9 @@
 		case SEARCH_SENTBEFORE:
 		case SEARCH_SENTON:
 		case SEARCH_SENTSINCE:
-			ret = search_sent(arg->type, arg->value.str, field);
+			ret = search_sent(arg->type, arg->value.str,
+					  (const unsigned char *) field,
+					  (size_t)-1);
 			break;
 		default:
 			if (arg->value.str[0] == '\0') {
@@ -457,7 +458,6 @@
 {
 	struct search_header_context *ctx = context;
         struct header_search_context *hdr_search_ctx;
-	size_t len;
 	int ret;
 
 	/* first check that the field name matches to argument. */
@@ -466,41 +466,50 @@
 	case SEARCH_SENTON:
 	case SEARCH_SENTSINCE:
 		/* date is handled differently than others */
-		if (ctx->name_len == 4 &&
-		    memcasecmp(ctx->name, "Date", 4) == 0) {
+		if (strcasecmp(ctx->hdr->name, "Date") == 0) {
+			if (ctx->hdr->continues) {
+				ctx->hdr->use_full_value = TRUE;
+				return;
+			}
 			ret = search_sent(arg->type, arg->value.str,
-				t_strndup(ctx->value, ctx->value_len));
+					  ctx->hdr->full_value,
+					  ctx->hdr->full_value_len);
 			ARG_SET_RESULT(arg, ret);
 		}
 		return;
 
 	case SEARCH_FROM:
-		if (ctx->name_len != 4 || memcasecmp(ctx->name, "From", 4) != 0)
+		if (strcasecmp(ctx->hdr->name, "From") != 0)
 			return;
 		break;
 	case SEARCH_TO:
-		if (ctx->name_len != 2 || memcasecmp(ctx->name, "To", 2) != 0)
+		if (strcasecmp(ctx->hdr->name, "To") != 0)
 			return;
 		break;
 	case SEARCH_CC:
-		if (ctx->name_len != 2 || memcasecmp(ctx->name, "Cc", 2) != 0)
+		if (strcasecmp(ctx->hdr->name, "Cc") != 0)
 			return;
 		break;
 	case SEARCH_BCC:
-		if (ctx->name_len != 3 || memcasecmp(ctx->name, "Bcc", 3) != 0)
+		if (strcasecmp(ctx->hdr->name, "Bcc") != 0)
 			return;
 		break;
 	case SEARCH_SUBJECT:
-		if (ctx->name_len != 7 ||
-		    memcasecmp(ctx->name, "Subject", 7) != 0)
+		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:
 		ctx->custom_header = TRUE;
 
-		len = strlen(arg->hdr_field_name);
-		if (ctx->name_len != len ||
-		    memcasecmp(ctx->name, arg->hdr_field_name, len) != 0)
+		if (strcasecmp(ctx->hdr->name, arg->hdr_field_name) != 0)
 			return;
 	case SEARCH_TEXT:
 		/* TEXT goes through all headers */
@@ -514,6 +523,11 @@
 		/* we're just testing existence of the field. always matches. */
 		ret = 1;
 	} else {
+		if (ctx->hdr->continues) {
+			ctx->hdr->use_full_value = TRUE;
+			return;
+		}
+
 		t_push();
 
 		hdr_search_ctx = search_header_context(ctx->index_context, arg);
@@ -526,14 +540,16 @@
 			string_t *str;
 
 			addr = message_address_parse(data_stack_pool,
-						     ctx->value, ctx->value_len,
+						     ctx->hdr->full_value,
+						     ctx->hdr->full_value_len,
 						     0);
-			str = t_str_new(ctx->value_len);
+			str = t_str_new(ctx->hdr->value_len);
 			message_address_write(str, addr);
 			ret = message_header_search(str_data(str), str_len(str),
 						    hdr_search_ctx) ? 1 : 0;
 		} else {
-			ret = message_header_search(ctx->value, ctx->value_len,
+			ret = message_header_search(ctx->hdr->full_value,
+						    ctx->hdr->full_value_len,
 						    hdr_search_ctx) ? 1 : 0;
 		}
 		t_pop();
@@ -565,6 +581,8 @@
 	case SEARCH_BCC:
 	case SEARCH_SUBJECT:
 	case SEARCH_HEADER:
+	case SEARCH_IN_REPLY_TO:
+	case SEARCH_MESSAGE_ID:
 		ARG_SET_RESULT(arg, 0);
 		break;
 	default:
@@ -573,32 +591,34 @@
 }
 
 static void search_header(struct message_part *part,
-			  const unsigned char *name, size_t name_len,
-			  const unsigned char *value, size_t value_len,
-			  void *context)
+                          struct message_header_line *hdr, void *context)
 {
 	struct search_header_context *ctx = context;
 
-	index_mail_parse_header(part, name, name_len, value, value_len,
-				ctx->index_context->mail);
+	if (hdr == NULL) {
+		/* end of headers, mark all unknown SEARCH_HEADERs unmatched */
+		mail_search_args_foreach(ctx->args, search_header_unmatch, ctx);
+		return;
+	}
 
-	if ((ctx->custom_header && name_len > 0) ||
-	    (name_len == 4 && memcasecmp(name, "Date", 4) == 0) ||
-	    (name_len == 4 && memcasecmp(name, "From", 4) == 0) ||
-	    (name_len == 2 && memcasecmp(name, "To", 2) == 0) ||
-	    (name_len == 2 && memcasecmp(name, "Cc", 2) == 0) ||
-	    (name_len == 3 && memcasecmp(name, "Bcc", 3) == 0) ||
-	    (name_len == 7 && memcasecmp(name, "Subject", 7) == 0)) {
-		ctx->name = name;
-		ctx->value = value;
-		ctx->name_len = name_len;
-		ctx->value_len = value_len;
+	if (hdr->eoh)
+		return;
+
+	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) {
+		ctx->hdr = hdr;
 
 		ctx->custom_header = FALSE;
 		mail_search_args_foreach(ctx->args, search_header_arg, ctx);
-	} else if (name_len == 0) {
-		/* last header, mark all unknown SEARCH_HEADERs unmatched */
-		mail_search_args_foreach(ctx->args, search_header_unmatch, ctx);
 	}
 }
 

Index: index-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-storage.h,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- index-storage.h	5 Mar 2003 01:43:16 -0000	1.34
+++ index-storage.h	26 Mar 2003 17:29:02 -0000	1.35
@@ -8,7 +8,7 @@
 typedef int write_func_t(struct ostream *, const void *, size_t);
 
 /* Return -1 = failure, 0 = don't write the header, 1 = write it */
-typedef int header_callback_t(const unsigned char *name, size_t len,
+typedef int header_callback_t(const char *name,
 			      write_func_t *write_func, void *context);
 
 struct index_autosync_file {




More information about the dovecot-cvs mailing list