changeset 5506:6cd889c652b0 HEAD

Removed message_parse_from_parts(). Added message_parser_init_from_parts() instead. Searching code now uses it whenever possible.
author Timo Sirainen <tss@iki.fi>
date Tue, 03 Apr 2007 19:22:40 +0300
parents d0caa9a44d1c
children 65250cfebd74
files src/lib-mail/message-parser.c src/lib-mail/message-parser.h src/lib-storage/index/index-mail-headers.c src/lib-storage/index/index-mail.c
diffstat 4 files changed, 161 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/message-parser.c	Tue Apr 03 18:02:36 2007 +0300
+++ b/src/lib-mail/message-parser.c	Tue Apr 03 19:22:40 2007 +0300
@@ -37,6 +37,7 @@
 	int (*parse_next_block)(struct message_parser_ctx *ctx,
 				struct message_block *block_r);
 
+	unsigned int return_body_blocks:1;
 	unsigned int part_seen_content_type:1;
 };
 
@@ -48,6 +49,8 @@
 				       struct message_block *block_r);
 static int parse_next_body_to_eof(struct message_parser_ctx *ctx,
 				  struct message_block *block_r);
+static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
+					    struct message_block *block_r);
 
 static struct message_boundary *
 boundary_find(struct message_boundary *boundaries,
@@ -538,6 +541,123 @@
 	return parse_next_header(ctx, block_r);
 }
 
+static int preparsed_parse_eof(struct message_parser_ctx *ctx __attr_unused__,
+			       struct message_block *block_r __attr_unused__)
+{
+	return -1;
+}
+
+static void preparsed_skip_to_next(struct message_parser_ctx *ctx)
+{
+	ctx->parse_next_block = preparsed_parse_next_header_init;
+	while (ctx->part != NULL) {
+		if (ctx->part->next != NULL) {
+			ctx->part = ctx->part->next;
+			break;
+		}
+		ctx->part = ctx->part->parent;
+	}
+	if (ctx->part == NULL)
+		ctx->parse_next_block = preparsed_parse_eof;
+}
+
+static int preparsed_parse_body_finish(struct message_parser_ctx *ctx,
+				       struct message_block *block_r)
+{
+	i_stream_skip(ctx->input, ctx->skip);
+	ctx->skip = 0;
+
+	preparsed_skip_to_next(ctx);
+	return ctx->parse_next_block(ctx, block_r);
+}
+
+static int preparsed_parse_body_more(struct message_parser_ctx *ctx,
+				     struct message_block *block_r)
+{
+	uoff_t end_offset = ctx->part->physical_pos +
+		ctx->part->header_size.physical_size +
+		ctx->part->body_size.physical_size;
+	int ret;
+
+	ret = message_parser_read_more(ctx, block_r);
+	if (ret <= 0)
+		return ret;
+
+	if (ctx->input->v_offset + block_r->size >= end_offset) {
+		block_r->size = end_offset - ctx->input->v_offset;
+		ctx->parse_next_block = preparsed_parse_body_finish;
+	}
+	ctx->skip = block_r->size;
+	return 1;
+}
+
+static int preparsed_parse_body_init(struct message_parser_ctx *ctx,
+				     struct message_block *block_r)
+{
+	uoff_t offset = ctx->part->physical_pos +
+		ctx->part->header_size.physical_size;
+
+	i_assert(offset >= ctx->input->v_offset);
+	i_stream_skip(ctx->input, offset - ctx->input->v_offset);
+
+	ctx->parse_next_block = preparsed_parse_body_more;
+	return preparsed_parse_body_more(ctx, block_r);
+}
+
+static int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
+					 struct message_block *block_r)
+{
+	if (ctx->part->children != NULL) {
+		ctx->parse_next_block = preparsed_parse_next_header_init;
+		ctx->part = ctx->part->children;
+	} else if (ctx->return_body_blocks) {
+		ctx->parse_next_block = preparsed_parse_body_init;
+	} else {
+		preparsed_skip_to_next(ctx);
+	}
+	return ctx->parse_next_block(ctx, block_r);
+}
+
+static int preparsed_parse_next_header(struct message_parser_ctx *ctx,
+				       struct message_block *block_r)
+{
+	struct message_header_line *hdr;
+	int ret;
+
+	ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
+	if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0))
+		return ret;
+
+	if (hdr != NULL) {
+		block_r->hdr = hdr;
+		block_r->size = 0;
+		return 1;
+	}
+	message_parse_header_deinit(&ctx->hdr_parser_ctx);
+
+	ctx->parse_next_block = preparsed_parse_finish_header;
+
+	/* return empty block as end of headers */
+	block_r->hdr = NULL;
+	block_r->size = 0;
+	return 1;
+}
+
+static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
+					    struct message_block *block_r)
+{
+	i_assert(ctx->hdr_parser_ctx == NULL);
+
+	i_assert(ctx->part->physical_pos >= ctx->input->v_offset);
+	i_stream_skip(ctx->input, ctx->part->physical_pos -
+		      ctx->input->v_offset);
+
+	ctx->hdr_parser_ctx = message_parse_header_init(ctx->input, NULL, TRUE);
+
+	ctx->parse_next_block = preparsed_parse_next_header;
+	return preparsed_parse_next_header(ctx, block_r);
+}
+
 struct message_parser_ctx *
 message_parser_init(pool_t part_pool, struct istream *input)
 {
@@ -549,11 +669,25 @@
 	ctx->parser_pool = pool;
 	ctx->part_pool = part_pool;
 	ctx->input = input;
-	ctx->parts = ctx->part = p_new(part_pool, struct message_part, 1);
+	ctx->parts = ctx->part = part_pool == NULL ? NULL :
+		p_new(part_pool, struct message_part, 1);
 	ctx->parse_next_block = parse_next_header_init;
 	return ctx;
 }
 
+struct message_parser_ctx *
+message_parser_init_from_parts(struct message_part *parts,
+			       struct istream *input, bool return_body_blocks)
+{
+	struct message_parser_ctx *ctx;
+
+	ctx = message_parser_init(NULL, input);
+	ctx->return_body_blocks = return_body_blocks;
+	ctx->parts = ctx->part = parts;
+	ctx->parse_next_block = preparsed_parse_next_header_init;
+	return ctx;
+}
+
 struct message_part *message_parser_deinit(struct message_parser_ctx **_ctx)
 {
         struct message_parser_ctx *ctx = *_ctx;
@@ -588,7 +722,7 @@
 
 	block_r->part = ctx->part;
 
-	if (ret < 0) {
+	if (ret < 0 && ctx->part != NULL) {
 		i_assert(ctx->input->eof);
 		while (ctx->part->parent != NULL) {
 			message_size_add(&ctx->part->parent->body_size,
@@ -642,46 +776,6 @@
 	i_assert(ret != 0);
 }
 
-static void part_parse_headers(struct message_part *part, struct istream *input,
-			       message_part_header_callback_t *callback,
-			       void *context)
-{
-	struct message_header_parser_ctx *hdr_ctx;
-	struct message_header_line *hdr;
-	int ret;
-
-	while (part != NULL) {
-		/* note that we want to parse the header of all
-		   the message parts, multiparts too. */
-		i_assert(part->physical_pos >= input->v_offset);
-		i_stream_skip(input, part->physical_pos - input->v_offset);
-
-		hdr_ctx = message_parse_header_init(input, NULL, TRUE);
-		while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
-			callback(part, hdr, context);
-		i_assert(ret != 0);
-		message_parse_header_deinit(&hdr_ctx);
-
-		/* call after the final skipping */
-		callback(part, NULL, context);
-
-		if (part->children != NULL) {
-			part_parse_headers(part->children, input,
-					   callback, context);
-		}
-
-		part = part->next;
-	}
-}
-
-#undef message_parse_from_parts
-void message_parse_from_parts(struct message_part *part, struct istream *input,
-			      message_part_header_callback_t *callback,
-			      void *context)
-{
-	part_parse_headers(part, input, callback, context);
-}
-
 static void
 message_parser_set_crlfs_diff(struct message_part *parts, bool use_crlf,
 			      off_t diff)
--- a/src/lib-mail/message-parser.h	Tue Apr 03 18:02:36 2007 +0300
+++ b/src/lib-mail/message-parser.h	Tue Apr 03 19:22:40 2007 +0300
@@ -61,6 +61,10 @@
    are allocated from. */
 struct message_parser_ctx *
 message_parser_init(pool_t part_pool, struct istream *input);
+/* Use preparsed parts to speed up parsing. */
+struct message_parser_ctx *
+message_parser_init_from_parts(struct message_part *parts,
+			       struct istream *input, bool return_body_blocks);
 struct message_part *message_parser_deinit(struct message_parser_ctx **ctx);
 
 /* Read the next block of a message. Returns 1 if block is returned, 0 if
@@ -104,22 +108,6 @@
 		(message_part_header_callback_t *)callback, context)
 #endif
 
-/* callback is called for each field in message header. */
-void message_parse_from_parts(struct message_part *part, struct istream *input,
-			      message_part_header_callback_t *callback,
-			      void *context);
-#ifdef CONTEXT_TYPE_SAFETY
-#  define message_parse_from_parts(part, input, callback, context) \
-	({(void)(1 ? 0 : callback((struct message_part *)0, \
-				  (struct message_header_line *)0, context)); \
-	  message_parse_from_parts(part, input, \
-		(message_part_header_callback_t *)callback, context); })
-#else
-#  define message_parse_from_parts(part, input, callback, context) \
-	  message_parse_from_parts(part, input, \
-		(message_part_header_callback_t *)callback, context)
-#endif
-
 /* Update the physical_size of all parts. If use_crlf is TRUE, they're set
    to same as virtual_size. If use_crlf is FALSE, they're set to
    virtual_size - lines. physical_pos fields are also updated. */
--- a/src/lib-storage/index/index-mail-headers.c	Tue Apr 03 18:02:36 2007 +0300
+++ b/src/lib-storage/index/index-mail-headers.c	Tue Apr 03 19:22:40 2007 +0300
@@ -340,6 +340,23 @@
 	index_mail_parse_header(mail->data.parts, hdr, mail);
 }
 
+static void index_mail_init_parser(struct index_mail *mail)
+{
+	struct index_mail_data *data = &mail->data;
+
+	if (data->parser_ctx != NULL)
+		(void)message_parser_deinit(&data->parser_ctx);
+
+	if (data->parts == NULL) {
+		data->parser_ctx =
+			message_parser_init(mail->data_pool, data->stream);
+	} else {
+		data->parser_ctx =
+			message_parser_init_from_parts(data->parts,
+						       data->stream, FALSE);
+	}
+}
+
 int index_mail_parse_headers(struct index_mail *mail,
 			     struct mailbox_header_lookup_ctx *headers)
 {
@@ -357,10 +374,7 @@
 					 data->save_bodystructure_header)) {
 		/* initialize bodystructure parsing in case we read the whole
 		   message. */
-		if (data->parser_ctx != NULL)
-			(void)message_parser_deinit(&mail->data.parser_ctx);
-		data->parser_ctx =
-			message_parser_init(mail->data_pool, data->stream);
+		index_mail_init_parser(mail);
 		message_parser_parse_header(data->parser_ctx, &data->hdr_size,
 					    index_mail_parse_part_header_cb,
 					    mail);
--- a/src/lib-storage/index/index-mail.c	Tue Apr 03 18:02:36 2007 +0300
+++ b/src/lib-storage/index/index-mail.c	Tue Apr 03 19:22:40 2007 +0300
@@ -581,7 +581,6 @@
 	struct index_mail_data *data = &mail->data;
 	uoff_t old_offset;
 
-	i_assert(data->parts == NULL);
 	i_assert(data->parser_ctx != NULL);
 
 	old_offset = data->stream->v_offset;
@@ -619,6 +618,7 @@
 		i_stream_seek(data->stream, 0);
 		if (!data->hdr_size_set) {
 			if ((data->access_part & PARSE_HDR) != 0) {
+				(void)get_cached_parts(mail);
 				if (index_mail_parse_headers(mail, NULL) < 0)
 					return NULL;
 			} else {
@@ -675,30 +675,12 @@
 		/* we haven't parsed the header yet */
 		data->save_bodystructure_header = TRUE;
 		data->save_bodystructure_body = TRUE;
+		(void)get_cached_parts(mail);
 		if (index_mail_parse_headers(mail, NULL) < 0)
 			return;
 	}
 
-	if (data->parts == NULL)
-		index_mail_parse_body(mail, field);
-	else {
-		/* body structure is known already, so use it to parse only
-		   the MIME headers */
-		uoff_t old_offset;
-
-		i_assert(data->parts->next == NULL);
-
-		old_offset = data->stream->v_offset;
-		i_stream_seek(data->stream,
-			      data->hdr_size.physical_size);
-
-		message_parse_from_parts(data->parts->children,
-					 data->stream,
-					 parse_bodystructure_part_header,
-					 mail->data_pool);
-		data->parsed_bodystructure = TRUE;
-		i_stream_seek(data->stream, old_offset);
-	}
+	index_mail_parse_body(mail, field);
 }
 
 static void