[evolution-mapi] Bug #608662 - multipart/related items are not getting rendered.



commit f37d0432a734b6ebff6729c8c9a45fa59f9f9a21
Author: Johnny Jacob <johnnyjacob gmail com>
Date:   Tue Feb 2 16:24:03 2010 +0530

    Bug #608662 - multipart/related items are not getting rendered.
    
    MIME generation rework. Initial bits for MS-OXCMAIL compliance.

 src/camel/camel-mapi-folder.c |  287 +++++++++++++++++++++++++----------------
 1 files changed, 177 insertions(+), 110 deletions(-)
---
diff --git a/src/camel/camel-mapi-folder.c b/src/camel/camel-mapi-folder.c
index cdfe349..f3ca3cb 100644
--- a/src/camel/camel-mapi-folder.c
+++ b/src/camel/camel-mapi-folder.c
@@ -1391,7 +1391,7 @@ fetch_item_cb (FetchItemsCallbackData *item_data, gpointer data)
 
 
 static void
-mapi_msg_set_recipient_list (CamelMimeMessage *msg, MapiItem *item)
+mapi_mime_set_recipient_list (CamelMimeMessage *msg, MapiItem *item)
 {
 	GSList *l = NULL;
 	CamelInternetAddress *to_addr, *cc_addr, *bcc_addr;
@@ -1456,7 +1456,7 @@ mapi_msg_set_recipient_list (CamelMimeMessage *msg, MapiItem *item)
 
 
 static void
-mapi_populate_details_from_item (CamelFolder *folder, CamelMimeMessage *msg, MapiItem *item)
+mapi_mime_set_msg_headers (CamelFolder *folder, CamelMimeMessage *msg, MapiItem *item)
 {
 	char *temp_str = NULL;
 	const char *from_email;
@@ -1532,12 +1532,24 @@ mapi_populate_details_from_item (CamelFolder *folder, CamelMimeMessage *msg, Map
 		camel_internet_address_add(addr, item->header.from, item->header.from_email);
 		camel_mime_message_set_from(msg, addr);
 	}
+
+	/* Threading */
+	if (item->header.message_id)
+		camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", item->header.message_id);
+
+	if (item->header.references)
+		camel_medium_add_header (CAMEL_MEDIUM (msg), "References", item->header.references);
+
+	if (item->header.in_reply_to)
+		camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", item->header.in_reply_to);
+
 }
 
 
-static void
-mapi_populate_msg_body_from_item (CamelMimePart *part, MapiItem *item, ExchangeMAPIStream *body)
+static CamelMimePart *
+mapi_mime_msg_body (MapiItem *item, const ExchangeMAPIStream *body)
 {
+	CamelMimePart *part = camel_mime_part_new ();
 	camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_8BIT);
 	
 	if (body) {
@@ -1563,8 +1575,13 @@ mapi_populate_msg_body_from_item (CamelMimePart *part, MapiItem *item, ExchangeM
 		g_free (buff);
 	} else
 		camel_mime_part_set_content (part, "", strlen (""), "text/plain");
+
+	return part;
 }
 
+#if 0
+
+/* GCompareFunc. Used for ordering body types in a GSList.*/
 static gint
 sort_bodies_cb (gconstpointer a, gconstpointer b)
 {
@@ -1592,143 +1609,193 @@ sort_bodies_cb (gconstpointer a, gconstpointer b)
 	return aidx - bidx;
 }
 
-static CamelMimeMessage *
-mapi_folder_item_to_msg( CamelFolder *folder,
-			 MapiItem *item,
-			 CamelException *ex )
-{
-	CamelMimeMessage *msg = NULL;
-	CamelMultipart *multipart = NULL;
-	CamelMimePart *part = NULL;
-	CamelDataWrapper *msg_content = NULL;
-
-	GSList *attach_list = NULL;
-	GSList *body_part_list = NULL;
-
-	attach_list = item->attachments;
-	msg = camel_mime_message_new ();
-
-	/* Threading */
-	if (item->header.message_id)
-		camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", item->header.message_id);
+#endif
 
-	if (item->header.references)
-		camel_medium_add_header (CAMEL_MEDIUM (msg), "References", item->header.references);
+/* Adds parts to multipart. Convenience function. */
+static void
+mapi_mime_multipart_add_attachments (CamelMultipart *multipart, GSList *attachs)
+{
+	CamelMimePart *part;
+	while (attachs) {
+		part = attachs->data;
+		camel_multipart_add_part (multipart, part);
+		camel_object_unref (part);
+		attachs = attachs->next;
+	}
+}
 
-	if (item->header.in_reply_to)
-		camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", item->header.in_reply_to);
+/* Process body stream and related objects into a MIME mulitpart */
+static CamelMultipart *
+mapi_mime_build_multipart_related (MapiItem *item, const ExchangeMAPIStream *stream,
+				   GSList *inline_attachs)
+{
+	CamelMimePart *part;
+	CamelMultipart *m_related = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_related), "multipart/related");
+	camel_multipart_set_boundary (m_related, NULL);
+	
+	part = mapi_mime_msg_body (item, stream);
+	camel_multipart_add_part (m_related, part);
+	camel_object_unref (part);
 
-	/* Set recipient details */
-	mapi_msg_set_recipient_list (msg, item);
-	mapi_populate_details_from_item (folder, msg, item);
+	mapi_mime_multipart_add_attachments (m_related, inline_attachs);
 
-	if (g_slist_length (attach_list) > 0) {
-		multipart = camel_multipart_new ();
-		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/mixed");
-		camel_multipart_set_boundary (multipart, NULL);
+	return m_related;
+}
 
-		msg_content = CAMEL_DATA_WRAPPER (multipart);
+/* Process multiple body types and pack them in a MIME mulitpart */
+static CamelMultipart *
+mapi_mime_build_multipart_alternative (MapiItem *item, GSList *body_parts, GSList *inline_attachs)
+{
+	CamelMimePart *part;
+	CamelMultipart *m_alternative = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_alternative), 
+					  "multipart/alternative");
+	camel_multipart_set_boundary (m_alternative, NULL);
+
+	while (body_parts) {
+		const ExchangeMAPIStream *stream = (ExchangeMAPIStream *) body_parts->data;
+		part = camel_mime_part_new ();
+		if ((stream->proptag == PR_HTML || stream->proptag == PR_BODY_HTML_UNICODE)
+		    && inline_attachs) {
+			CamelMultipart *m_related;
+			m_related = mapi_mime_build_multipart_related (item, stream,
+								       inline_attachs);
+			camel_medium_set_content_object (CAMEL_MEDIUM (part),
+							 CAMEL_DATA_WRAPPER (m_related));
+			camel_object_unref (m_related);
+		} else
+			part = mapi_mime_msg_body (item, stream);
+		
+		camel_multipart_add_part (m_alternative, part);
+		camel_object_unref (part);
 	}
 
-	if (g_slist_length (item->msg.body_parts) > 1) {
-		multipart = camel_multipart_new ();
-		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart), "multipart/alternative");
-		camel_multipart_set_boundary (multipart, NULL);
+	return m_alternative;
+}
+
+static CamelMultipart *
+mapi_mime_build_multipart_mixed (CamelMultipart *content, GSList *attachs)
+{
+	CamelMimePart *part = camel_mime_part_new ();
+	CamelMultipart *m_mixed = camel_multipart_new ();
+	camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_mixed), 
+					  "multipart/mixed");
+	camel_multipart_set_boundary (m_mixed, NULL);
 
-		item->msg.body_parts = g_slist_sort (item->msg.body_parts, sort_bodies_cb);
+	camel_medium_set_content_object (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
+	camel_multipart_add_part (m_mixed, part);
 
-		/* Handle Multipart */
-		for (body_part_list = item->msg.body_parts; body_part_list; body_part_list = g_slist_next (body_part_list)) {
-			part = camel_mime_part_new ();
+	if (attachs)
+		mapi_mime_multipart_add_attachments (m_mixed, attachs);
 
-			mapi_populate_msg_body_from_item (part, item, body_part_list->data);
+	return m_mixed;
+}
 
-			camel_multipart_add_part (CAMEL_MULTIPART (msg_content), part);
-			camel_object_unref (part);
-		}
+/*Takes raw attachment streams and converts to MIME Parts. Parts are added to
+  either inline / non-inline lists.*/
+static void
+mapi_mime_classify_attachments (GSList *attachments, GSList **inline_attachs, GSList **noninline)
+{
+	for (;attachments != NULL; attachments = attachments->next) {
+		ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)attachments->data;
+		ExchangeMAPIStream *stream = NULL;
+		const char *filename, *mime_type, *content_id = NULL; 
+		CamelContentType *content_type;
+		CamelMimePart *part;
 
-		if (msg_content) {
-			part = camel_mime_part_new ();
-			camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (part), "multipart/alternative");
-			camel_medium_set_content_object (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (multipart));
-			camel_object_unref (multipart);
+		stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
 
-			camel_multipart_add_part (CAMEL_MULTIPART (msg_content), part);
-			camel_object_unref (part);
-		} else {
-			msg_content = CAMEL_DATA_WRAPPER (multipart);
-		}
-	} else {
-		if (msg_content) {
-			part = camel_mime_part_new ();
-			mapi_populate_msg_body_from_item (part, item, item->msg.body_parts ? item->msg.body_parts->data : NULL);
-			camel_multipart_add_part (CAMEL_MULTIPART (msg_content), part);
-			camel_object_unref (part);
-		} else {
-			msg_content = CAMEL_DATA_WRAPPER (msg);
-			mapi_populate_msg_body_from_item (CAMEL_MIME_PART (msg), item, item->msg.body_parts ? item->msg.body_parts->data : NULL);
+		if (!stream || stream->value->len <= 0) {
+			continue;
 		}
-	}
 
-	/* Attachment Handling */
-	if (attach_list) {
-		GSList *al;
+		part = camel_mime_part_new ();
 
-		multipart = CAMEL_MULTIPART (msg_content);
+		filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
+											 PR_ATTACH_LONG_FILENAME);
 
-		for (al = attach_list; al != NULL; al = al->next) {
-			ExchangeMAPIAttachment *attach = (ExchangeMAPIAttachment *)al->data;
-			ExchangeMAPIStream *stream = NULL;
-			const char *filename, *mime_type, *content_id = NULL; 
-			CamelContentType *content_type;
+		if (!(filename && *filename))
+			filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
+												 PR_ATTACH_FILENAME);
+		camel_mime_part_set_filename(part, g_strdup(filename));
+		camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
 
-			stream = exchange_mapi_util_find_stream (attach->streams, PR_ATTACH_DATA_BIN);
+		/*Content-Type*/
+		mime_type = (const char *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
+		if (!mime_type)
+			mime_type = "application/octet-stream";
 
-			if (!stream || stream->value->len <= 0) {
-				continue;
-			}
+		camel_mime_part_set_content (part, (const char *) stream->value->data, stream->value->len, mime_type);
 
-			part = camel_mime_part_new ();
 
-			filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
-												 PR_ATTACH_LONG_FILENAME);
-
-			if (!(filename && *filename))
-				filename = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
-													 PR_ATTACH_FILENAME);
-			camel_mime_part_set_filename(part, g_strdup(filename));
-			camel_content_type_set_param (((CamelDataWrapper *) part)->mime_type, "name", filename);
+		content_type = camel_mime_part_get_content_type (part);
+		if (content_type && camel_content_type_is (content_type, "text", "*"))
+			camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
+		else
+			camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
 
-			/*Content-Type*/
-			mime_type = (const char *) exchange_mapi_util_find_SPropVal_array_propval (attach->lpProps, PR_ATTACH_MIME_TAG);
-			if (!mime_type)
-				mime_type = "application/octet-stream";
+		/*Content-ID*/
+		content_id = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
+											   PR_ATTACH_CONTENT_ID);
+		/* TODO : Add disposition */
+		if (content_id) {
+			camel_mime_part_set_content_id (part, content_id);
+			*inline_attachs = g_slist_append (*inline_attachs, part);
+		} else
+			*noninline = g_slist_append (*noninline, part);
+	}
+}
 
-			camel_mime_part_set_content (part, (const char *) stream->value->data, stream->value->len, mime_type);
+static CamelMimeMessage *
+mapi_folder_item_to_msg( CamelFolder *folder, MapiItem *item, CamelException *ex )
+{
+	CamelMimeMessage *msg = NULL;
+	CamelMultipart *multipart_body = NULL;
 
-			/*Content-ID*/
-			content_id = (const char *) exchange_mapi_util_find_SPropVal_array_propval(attach->lpProps, 
-												   PR_ATTACH_CONTENT_ID);
+	GSList *attach_list = NULL;
+	GSList *inline_attachs =  NULL; /*Used for mulitpart/related*/
+	GSList *noninline_attachs = NULL; 
 
-			camel_mime_part_set_content_id (part, content_id);
+	gboolean build_alternative = FALSE;
+	gboolean build_related = FALSE;
 
-			content_type = camel_mime_part_get_content_type (part);
-			if (content_type && camel_content_type_is (content_type, "text", "*"))
-				camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
-			else
-				camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+	attach_list = item->attachments;
+	msg = camel_mime_message_new ();
 
-			camel_multipart_add_part (multipart, part);
-			camel_object_unref (part);
-			
-		}
+	mapi_mime_set_recipient_list (msg, item);
+	mapi_mime_set_msg_headers (folder, msg, item);
+	mapi_mime_classify_attachments (attach_list, &inline_attachs, &noninline_attachs);
+
+	build_alternative = (g_slist_length (item->msg.body_parts) > 1) && inline_attachs;
+	build_related = !build_alternative && inline_attachs;
+
+	if (build_alternative) {
+		multipart_body = mapi_mime_build_multipart_alternative (item, item->msg.body_parts,
+									inline_attachs);
+	} else if (build_related) {
+		multipart_body = mapi_mime_build_multipart_related (item,
+								    item->msg.body_parts->data,
+								    inline_attachs);
+	} else { /* Simple multipart/mixed */
+		CamelMimePart *part;
+		multipart_body = camel_multipart_new ();
+		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body),
+						  "multipart/mixed");
+		camel_multipart_set_boundary (multipart_body, NULL);
+		part = mapi_mime_msg_body (item, item->msg.body_parts->data);
+		camel_multipart_add_part (multipart_body, part);
+		camel_object_unref (part);
 	}
 
-	if (msg_content != CAMEL_DATA_WRAPPER (msg)) {
-		camel_medium_set_content_object (CAMEL_MEDIUM (msg), msg_content);
-		camel_object_unref (msg_content);
+	if (noninline_attachs) { /* multipart/mixed */
+		multipart_body = mapi_mime_build_multipart_mixed (multipart_body, 
+								  noninline_attachs);
 	}
 
+	camel_medium_set_content_object(CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER(multipart_body));
+	camel_object_unref (multipart_body);
+
 	return msg;
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]