changeset 21947:f98d4d45e16e

lib-imap: imap-bodystructure: Fixed handling of a multipart part without children in imap_bodystructure_parse(). In imap_bodystructure_write(), an empty multipart part is addressed by generating an empty text/plain part. However, when parsing that back with imap_bodystructure_parse() against a parsed message_part tree, this case needs to be considered explicitly. Otherwise, it will not be able to match the message part hierarchies. This adds a test suite item that tests both the write (previous commit) and parse functions.
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Tue, 11 Apr 2017 09:34:11 +0200
parents dd009c471bd2
children 52684cb827cd
files src/lib-imap/imap-bodystructure.c src/lib-imap/test-imap-bodystructure.c
diffstat 2 files changed, 50 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-imap/imap-bodystructure.c	Wed Apr 12 10:13:15 2017 +0200
+++ b/src/lib-imap/imap-bodystructure.c	Tue Apr 11 09:34:11 2017 +0200
@@ -377,10 +377,25 @@
 
 	multipart = FALSE;
 	if (!parsing_tree) {
-		child_part = part->children;
-		while (args->type == IMAP_ARG_LIST) {
-			if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
-				  child_part == NULL) {
+		if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
+			part->children == NULL) {
+			struct message_part_data dummy_part_data = {
+				.content_type = "text",
+				.content_subtype = "plain",
+				.content_transfer_encoding = "7bit"
+			};
+			struct message_part dummy_part = {
+				.parent = part,
+				.data = &dummy_part_data,
+				.flags = MESSAGE_PART_FLAG_TEXT
+			};
+			struct message_part *dummy_partp = &dummy_part;
+
+			/* no parts in multipart message,
+			   that's not allowed. expect a single
+			   0-length text/plain structure */
+			if (args->type != IMAP_ARG_LIST ||
+				(args+1)->type == IMAP_ARG_LIST) {
 				*error_r = "message_part hierarchy "
 					"doesn't match BODYSTRUCTURE";
 				return -1;
@@ -388,14 +403,33 @@
 
 			list_args = imap_arg_as_list(args);
 			if (imap_bodystructure_parse_args(list_args, pool,
-								&child_part, error_r) < 0)
+								&dummy_partp, error_r) < 0)
 				return -1;
-			child_part = child_part->next;
+			child_part = NULL;
 
 			multipart = TRUE;
 			args++;
+
+		} else {
+			child_part = part->children;
+			while (args->type == IMAP_ARG_LIST) {
+				if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
+						child_part == NULL) {
+					*error_r = "message_part hierarchy "
+						"doesn't match BODYSTRUCTURE";
+					return -1;
+				}
+
+				list_args = imap_arg_as_list(args);
+				if (imap_bodystructure_parse_args(list_args, pool,
+									&child_part, error_r) < 0)
+					return -1;
+				child_part = child_part->next;
+
+				multipart = TRUE;
+				args++;
+			}
 		}
-
 		if (multipart) {
 			if (child_part != NULL) {
 				*error_r = "message_part hierarchy "
--- a/src/lib-imap/test-imap-bodystructure.c	Wed Apr 12 10:13:15 2017 +0200
+++ b/src/lib-imap/test-imap-bodystructure.c	Tue Apr 11 09:34:11 2017 +0200
@@ -224,6 +224,15 @@
 			"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<foo@example.com>\" \"hellodescription\" \"7bit\" 7 1 \"Q2hlY2sgSW50ZWdyaXR5IQ==\" (\"inline\" (\"foo\" \"bar\")) (\"en\" \"fi\" \"se\") \"http://example.com/test.txt\")(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1 NIL NIL NIL NIL)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"sub1\") NIL NIL NIL) 21 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo bar\") NIL NIL NIL",
 		.body =
 			"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<foo@example.com>\" \"hellodescription\" \"7bit\" 7 1)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1) \"alternative\") 21) \"mixed\""
+	},{
+		.message =
+			"Content-Type: multipart/mixed; boundary=\"foo\"\n"
+			"\n",
+		.bodystructure =
+			"(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo\") NIL NIL NIL",
+		.body =
+			"(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 0 0) \"mixed\""
+
 	}
 };