changeset 19883:653a6a1bfd61

lib-mail: Added message_parser_deinit_from_parts() The returned error strings could still be improved to give more details, especially give an approximate offset of where the problem is.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Sun, 28 Feb 2016 20:46:57 +0200
parents 0ff471005aa0
children 3675442a1515
files src/lib-mail/message-parser.c src/lib-mail/message-parser.h
diffstat 2 files changed, 29 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/message-parser.c	Sun Feb 28 20:19:45 2016 +0200
+++ b/src/lib-mail/message-parser.c	Sun Feb 28 20:46:57 2016 +0200
@@ -26,6 +26,7 @@
 	pool_t parser_pool, part_pool;
 	struct istream *input;
 	struct message_part *parts, *part;
+	const char *broken_reason;
 
 	enum message_header_parser_flags hdr_flags;
 	enum message_parser_flags flags;
@@ -44,7 +45,6 @@
 				struct message_block *block_r);
 
 	unsigned int part_seen_content_type:1;
-	unsigned int broken:1;
 	unsigned int eof:1;
 };
 
@@ -748,7 +748,7 @@
 
 		/* [\r]\n--boundary[\r]\n */ 
 		if (block_r->size < 5 || *cur != '\n') {
-			ctx->broken = TRUE;
+			ctx->broken_reason = "Prologue boundary end not at expected position";
 			return -1;
 		}
 		
@@ -761,7 +761,7 @@
 		}
 
 		if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
-			ctx->broken = TRUE;
+			ctx->broken_reason = "Prologue boundary beginning not at expected position";
 			return -1;
 		}
 
@@ -822,7 +822,7 @@
 	int ret;
 
 	if (end_offset - ctx->input->v_offset < 7) {
-		ctx->broken = TRUE;
+		ctx->broken_reason = "Epilogue position is wrong";
 		return -1;
 	}
 
@@ -842,7 +842,7 @@
 	if (*cur == '\r') cur++;
 
 	if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') {
-		ctx->broken = TRUE;
+		ctx->broken_reason = "Epilogue boundary start not at expected position";
 		return -1;
 	}
 
@@ -850,7 +850,7 @@
 	cur += 3;
 	if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) {
 		if (end_offset < ctx->input->v_offset + size) {
-			ctx->broken = TRUE;
+			ctx->broken_reason = "Epilogue boundary end not at expected position";
 			return -1;
 		} else if (ctx->input->v_offset + size < end_offset &&
 			   size < BOUNDARY_END_MAX_LEN &&
@@ -874,7 +874,7 @@
 
 	if (offset < ctx->input->v_offset) {
 		/* header was actually larger than the cached size suggested */
-		ctx->broken = TRUE;
+		ctx->broken_reason = "Header larger than its cached size";
 		return -1;
 	}
 	i_stream_skip(ctx->input, offset - ctx->input->v_offset);
@@ -901,7 +901,7 @@
 	if (offset < ctx->input->v_offset) {
 		/* last child was actually larger than the cached size
 		   suggested */
-		ctx->broken = TRUE;
+		ctx->broken_reason = "Part larger than its cached size";
 		return -1;
 	}
 	i_stream_skip(ctx->input, offset - ctx->input->v_offset);
@@ -957,7 +957,7 @@
 	i_assert(ctx->skip == 0);
 	if (ctx->input->v_offset != ctx->part->physical_pos +
 	    ctx->part->header_size.physical_size) {
-		ctx->broken = TRUE;
+		ctx->broken_reason = "Cached header size mismatch";
 		return -1;
 	}
 	return 1;
@@ -1030,11 +1030,21 @@
 int message_parser_deinit(struct message_parser_ctx **_ctx,
 			  struct message_part **parts_r)
 {
+	const char *error;
+
+	return message_parser_deinit_from_parts(_ctx, parts_r, &error);
+}
+
+int message_parser_deinit_from_parts(struct message_parser_ctx **_ctx,
+				     struct message_part **parts_r,
+				     const char **error_r)
+{
         struct message_parser_ctx *ctx = *_ctx;
-	int ret = ctx->broken ? -1 : 0;
+	int ret = ctx->broken_reason != NULL ? -1 : 0;
 
 	*_ctx = NULL;
 	*parts_r = ctx->parts;
+	*error_r = ctx->broken_reason;
 
 	if (ctx->hdr_parser_ctx != NULL)
 		message_parse_header_deinit(&ctx->hdr_parser_ctx);
@@ -1069,7 +1079,8 @@
 	if (ret < 0 && ctx->part != NULL) {
 		/* Successful EOF or unexpected failure */
 		i_assert(ctx->input->eof || ctx->input->closed ||
-			 ctx->input->stream_errno != 0 || ctx->broken);
+			 ctx->input->stream_errno != 0 ||
+			 ctx->broken_reason != NULL);
 		while (ctx->part->parent != NULL) {
 			message_size_add(&ctx->part->parent->body_size,
 					 &ctx->part->body_size);
--- a/src/lib-mail/message-parser.h	Sun Feb 28 20:19:45 2016 +0200
+++ b/src/lib-mail/message-parser.h	Sun Feb 28 20:46:57 2016 +0200
@@ -57,6 +57,13 @@
    didn't match the current message */
 int message_parser_deinit(struct message_parser_ctx **ctx,
 			  struct message_part **parts_r);
+/* Same as message_parser_deinit(), but return an error message describing
+   why the preparsed parts didn't match the message. This can also safely be
+   called even when preparsed parts weren't used - it'll always just return
+   success in that case. */
+int message_parser_deinit_from_parts(struct message_parser_ctx **_ctx,
+				     struct message_part **parts_r,
+				     const char **error_r);
 
 /* Read the next block of a message. Returns 1 if block is returned, 0 if
    input stream is non-blocking and more data needs to be read, -1 when all is