[evolution] EMailParserExtension: Collect EMailParts in a GQueue.



commit 3924dc759dbf38df0f9ff6941990dcf242478617
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed Dec 5 19:42:15 2012 -0500

    EMailParserExtension: Collect EMailParts in a GQueue.
    
    Collect EMailParts in a GQueue provided to the EMailParserExtension,
    and change the return type of parse() to gboolean to indicate whether
    the given CamelMimePart was handled (even if no parts were added to
    the output GQueue).
    
    This avoids the awkward corner case of a parser extension returning a
    linked list node with a NULL data member to indicate the CamelMimePart
    was handled but no EMailParts produced, and then having to watch out
    for that NULL data member corner case throughout the application.
    
    Also, remove the GCancellable parameter from e_mail_parser_error() and
    e_mail_parser_wrap_as_attachment() since neither function blocks.

 composer/e-msg-composer.c                          |   15 +-
 em-format/e-mail-parser-application-mbox.c         |   37 ++---
 em-format/e-mail-parser-application-smime.c        |   59 +++----
 em-format/e-mail-parser-attachment-bar.c           |   13 +-
 em-format/e-mail-parser-extension.c                |   48 +++--
 em-format/e-mail-parser-extension.h                |   10 +-
 em-format/e-mail-parser-headers.c                  |   12 +-
 em-format/e-mail-parser-image.c                    |   23 ++--
 em-format/e-mail-parser-inlinepgp-encrypted.c      |   64 ++++----
 em-format/e-mail-parser-inlinepgp-signed.c         |   57 +++----
 em-format/e-mail-parser-message-deliverystatus.c   |   19 ++-
 em-format/e-mail-parser-message-external.c         |   12 +-
 em-format/e-mail-parser-message-rfc822.c           |   42 +++---
 em-format/e-mail-parser-message.c                  |   33 ++--
 em-format/e-mail-parser-multipart-alternative.c    |   32 ++--
 em-format/e-mail-parser-multipart-appledouble.c    |   33 ++--
 em-format/e-mail-parser-multipart-digest.c         |   62 +++----
 em-format/e-mail-parser-multipart-encrypted.c      |   95 +++++------
 em-format/e-mail-parser-multipart-mixed.c          |   74 ++++-----
 em-format/e-mail-parser-multipart-related.c        |   50 +++---
 em-format/e-mail-parser-multipart-signed.c         |  100 +++++------
 em-format/e-mail-parser-secure-button.c            |    9 +-
 em-format/e-mail-parser-source.c                   |   12 +-
 em-format/e-mail-parser-text-enriched.c            |   23 ++--
 em-format/e-mail-parser-text-html.c                |   31 ++--
 em-format/e-mail-parser-text-plain.c               |   75 ++++-----
 em-format/e-mail-parser.c                          |  105 ++++++------
 em-format/e-mail-parser.h                          |   19 +-
 modules/audio-inline/e-mail-parser-audio-inline.c  |   25 ++-
 modules/itip-formatter/e-mail-parser-itip.c        |   17 +-
 modules/prefer-plain/e-mail-parser-prefer-plain.c  |  179 ++++++++++----------
 .../text-highlight/e-mail-parser-text-highlight.c  |   26 ++--
 .../e-mail-parser-tnef-attachment.c                |   34 ++--
 modules/vcard-inline/e-mail-parser-vcard-inline.c  |   29 ++--
 34 files changed, 725 insertions(+), 749 deletions(-)
---
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 4fa48a7..5cd9a70 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -194,7 +194,7 @@ emcu_part_to_html (CamelSession *session,
 	GString *part_id;
 	EShell *shell;
 	GtkWindow *window;
-	GSList *list;
+	GQueue queue = G_QUEUE_INIT;
 
 	shell = e_shell_get_default ();
 	window = e_shell_get_active_window (shell);
@@ -207,13 +207,12 @@ emcu_part_to_html (CamelSession *session,
 
 	part_id = g_string_sized_new (0);
 	parser = e_mail_parser_new (session);
-	list = e_mail_parser_parse_part (parser, part, part_id, cancellable);
-	while (list != NULL) {
-		if (list->data != NULL) {
-			e_mail_part_list_add_part (part_list, list->data);
-			e_mail_part_unref (list->data);
-		}
-		list = g_slist_delete_link (list, list);
+	e_mail_parser_parse_part (
+		parser, part, part_id, cancellable, &queue);
+	while (!g_queue_is_empty (&queue)) {
+		EMailPart *mail_part = g_queue_pop_head (&queue);
+		e_mail_part_list_add_part (part_list, mail_part);
+		e_mail_part_unref (mail_part);
 	}
 	g_string_free (part_id, TRUE);
 	g_object_unref (parser);
diff --git a/em-format/e-mail-parser-application-mbox.c b/em-format/e-mail-parser-application-mbox.c
index fb901af..35eedf9 100644
--- a/em-format/e-mail-parser-application-mbox.c
+++ b/em-format/e-mail-parser-application-mbox.c
@@ -60,24 +60,21 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "application/mbox",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_app_mbox_parse (EMailParserExtension *extension,
                      EMailParser *parser,
                      CamelMimePart *part,
                      GString *part_id,
-                     GCancellable *cancellable)
+                     GCancellable *cancellable,
+                     GQueue *out_mail_parts)
 {
 	CamelMimeParser *mime_parser;
 	CamelStream *mem_stream;
 	camel_mime_parser_state_t state;
 	gint old_len;
 	gint messages;
-	GSList *parts;
 	GError *error = NULL;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	/* Extract messages from the application/mbox part and
 	 * render them as a flat list of messages. */
 
@@ -103,14 +100,14 @@ empe_app_mbox_parse (EMailParserExtension *extension,
 
 	camel_mime_parser_init_with_stream (mime_parser, mem_stream, &error);
 	if (error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Error parsing MBOX part: %s"),
 			error->message);
 		g_object_unref (mem_stream);
 		g_object_unref (mime_parser);
 		g_error_free (error);
-		return parts;
+		return TRUE;
 	}
 
 	g_object_unref (mem_stream);
@@ -121,11 +118,10 @@ empe_app_mbox_parse (EMailParserExtension *extension,
 	messages = 0;
 	state = camel_mime_parser_step (mime_parser, NULL, NULL);
 
-	parts = NULL;
 	while (state == CAMEL_MIME_PARSER_STATE_FROM) {
+		GQueue work_queue = G_QUEUE_INIT;
 		CamelMimeMessage *message;
 		CamelMimePart *opart;
-		GSList *new_parts;
 
 		message = camel_mime_message_new ();
 		opart = CAMEL_MIME_PART (message);
@@ -142,23 +138,22 @@ empe_app_mbox_parse (EMailParserExtension *extension,
 		camel_medium_set_content (CAMEL_MEDIUM (opart), CAMEL_DATA_WRAPPER (message));
 		camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), "message/rfc822");
 
-		new_parts = e_mail_parser_parse_part_as (
-				parser, opart,
-				part_id, "message/rfc822", cancellable);
+		e_mail_parser_parse_part_as (
+			parser, opart, part_id, "message/rfc822",
+			cancellable, &work_queue);
 
 		/* Wrap every message as attachment */
-		new_parts = e_mail_parser_wrap_as_attachment (
-				parser, opart,
-				new_parts, part_id, cancellable);
+		e_mail_parser_wrap_as_attachment (
+			parser, opart, part_id, &work_queue);
 
 		/* Inline all messages in mbox */
-		if (new_parts && new_parts->data) {
-			EMailPart *p = new_parts->data;
+		if (!g_queue_is_empty (&work_queue)) {
+			EMailPart *p = g_queue_peek_head (&work_queue);
 
 			p->force_inline = TRUE;
 		}
 
-		parts = g_slist_concat (parts, new_parts);
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 		g_string_truncate (part_id, old_len);
 
@@ -175,7 +170,7 @@ empe_app_mbox_parse (EMailParserExtension *extension,
 
 	g_object_unref (mime_parser);
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/em-format/e-mail-parser-application-smime.c b/em-format/e-mail-parser-application-smime.c
index 9fbf24e..919af9d 100644
--- a/em-format/e-mail-parser-application-smime.c
+++ b/em-format/e-mail-parser-application-smime.c
@@ -65,28 +65,25 @@ static const gchar * parser_mime_types[] = { "application/xpkcs7mime",
 					    "application/x-pkcs7-signature",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_app_smime_parse (EMailParserExtension *extension,
                        EMailParser *parser,
                        CamelMimePart *part,
                        GString *part_id,
-                       GCancellable *cancellable)
+                       GCancellable *cancellable,
+                       GQueue *out_mail_parts)
 {
 	CamelCipherContext *context;
 	CamelMimePart *opart;
 	CamelCipherValidity *valid;
 	GError *local_error = NULL;
-	GSList *parts, *iter;
 	CamelContentType *ct;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	ct = camel_mime_part_get_content_type (part);
 	if (camel_content_type_is (ct, "application", "pkcs7-signature") ||
 	    camel_content_type_is (ct, "application", "xpkcs7-signature") ||
 	    camel_content_type_is (ct, "application", "x-pkcs7-signature")) {
-		return g_slist_alloc ();
+		return TRUE;
 	}
 
 	context = camel_smime_context_new (e_mail_parser_get_session (parser));
@@ -99,58 +96,60 @@ empe_app_smime_parse (EMailParserExtension *extension,
 	e_mail_part_preserve_charset_in_content_type (part, opart);
 
 	if (local_error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Could not parse S/MIME message: %s"),
 			local_error->message);
 		g_error_free (local_error);
 
 	} else {
+		GQueue work_queue = G_QUEUE_INIT;
+		GList *head, *link;
 		gint len = part_id->len;
 
 		g_string_append (part_id, ".encrypted");
 
-		parts = e_mail_parser_parse_part (
-			parser, opart, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, opart, part_id, cancellable, &work_queue);
 
 		g_string_truncate (part_id, len);
 
-		/* Update validity flags of all the involved subp-arts */
-		for (iter = parts; iter; iter = iter->next) {
+		head = g_queue_peek_head_link (&work_queue);
 
-			EMailPart *mail_part = iter->data;
-			if (!mail_part)
-				continue;
+		/* Update validity flags of all the involved subp-arts */
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			EMailPart *mail_part = link->data;
 
 			e_mail_part_update_validity (
 				mail_part, valid,
 				E_MAIL_PART_VALIDITY_ENCRYPTED |
 				E_MAIL_PART_VALIDITY_SMIME);
-
 		}
 
-		/* Add a widget with details about the encryption, but only when
-		 * the encrypted isn't itself secured, in that case it has created
-		 * the button itself */
+		e_queue_transfer (&work_queue, out_mail_parts);
+
+		/* Add a widget with details about the encryption, but only
+		 * when the encrypted isn't itself secured, in that case it
+		 * has created the button itself. */
 		if (!e_mail_part_is_secured (opart)) {
-			GSList *button;
 			EMailPart *mail_part;
+
 			g_string_append (part_id, ".encrypted.button");
 
-			button = e_mail_parser_parse_part_as (
-					parser, part, part_id,
-					"application/vnd.evolution.widget.secure-button",
-					cancellable);
-			if (button && button->data) {
-				mail_part = button->data;
+			e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.widget.secure-button",
+				cancellable, &work_queue);
+
+			mail_part = g_queue_peek_head (&work_queue);
 
+			if (mail_part != NULL)
 				e_mail_part_update_validity (
 					mail_part, valid,
 					E_MAIL_PART_VALIDITY_ENCRYPTED |
 					E_MAIL_PART_VALIDITY_SMIME);
-			}
 
-			parts = g_slist_concat (parts, button);
+			e_queue_transfer (&work_queue, out_mail_parts);
 
 			g_string_truncate (part_id, len);
 		}
@@ -161,7 +160,7 @@ empe_app_smime_parse (EMailParserExtension *extension,
 	g_object_unref (opart);
 	g_object_unref (context);
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/em-format/e-mail-parser-attachment-bar.c b/em-format/e-mail-parser-attachment-bar.c
index 5df1afa..f8c45fb 100644
--- a/em-format/e-mail-parser-attachment-bar.c
+++ b/em-format/e-mail-parser-attachment-bar.c
@@ -67,12 +67,13 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "application/vnd.evolution.widget.attachment-bar", NULL };
 
-static GSList *
+static gboolean
 empe_attachment_bar_parse (EMailParserExtension *extension,
                            EMailParser *parser,
                            CamelMimePart *part,
                            GString *part_id,
-                           GCancellable *cancellable)
+                           GCancellable *cancellable,
+                           GQueue *out_mail_parts)
 {
 	EMailPartAttachmentBar *empab;
 	gint len;
@@ -80,13 +81,15 @@ empe_attachment_bar_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append (part_id, ".attachment-bar");
 	empab = (EMailPartAttachmentBar *) e_mail_part_subclass_new (
-			part, part_id->str, sizeof (EMailPartAttachmentBar),
-			(GFreeFunc) mail_part_attachment_bar_free);
+		part, part_id->str, sizeof (EMailPartAttachmentBar),
+		(GFreeFunc) mail_part_attachment_bar_free);
 	empab->parent.mime_type = g_strdup ("application/vnd.evolution.widget.attachment-bar");
 	empab->store = E_ATTACHMENT_STORE (e_attachment_store_new ());
 	g_string_truncate (part_id, len);
 
-	return g_slist_append (NULL, empab);
+	g_queue_push_tail (out_mail_parts, empab);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-extension.c b/em-format/e-mail-parser-extension.c
index 72f1fd8..df8fc54 100644
--- a/em-format/e-mail-parser-extension.c
+++ b/em-format/e-mail-parser-extension.c
@@ -52,18 +52,20 @@ e_mail_parser_extension_default_init (EMailParserExtensionInterface *interface)
  * @part_id: a #GString to which parser will append ID of the parsed part.
  * @flags: #EMailParserFlags
  * @cancellable: (allow-none) A #GCancellable
+ * @out_mail_parts: a #GQueue to deposit #EMailPart instances
  *
  * A virtual function reimplemented in all mail parser extensions. The function
- * decodes and parses the @mime_part, creating one or more #EMailPart<!-//>s.
+ * decodes and parses the @mime_part, appending one or more #EMailPart<!-//>s
+ * to the @out_mail_parts queue.
  *
- * When the function is unable to parse the @mime_part (either because it's broken
- * or because it is a different mimetype then the extension is specialized for), the
- * function will return @NULL indicating the #EMailParser, that it should pick
- * another extension.
+ * When the function is unable to parse the @mime_part (either because it's
+ * broken or because it is a different MIME type then the extension is
+ * specialized for), the function will return %FALSE to indicate to the
+ * #EMailParser that it should pick another extension.
  *
- * When the @mime_part contains for example multipart/mixed of one RFC822 message
- * with an attachment and of one image, then parser must make sure that the
- * returned #GSList is correctly ordered:
+ * When the @mime_part contains for example multipart/mixed of one RFC822
+ * message with an attachment and of one image, then parser must make sure
+ * that parts are appeded to @out_mail_parts in the correct order.
  *
  * part1.rfc822.plain_text
  * part1.rfc822.attachment
@@ -71,25 +73,33 @@ e_mail_parser_extension_default_init (EMailParserExtensionInterface *interface)
  *
  * Implementation of this function must be thread-safe.
  *
- * Return value: Returns #GSList of #EMailPart<!-//>s when the part was succesfully
- * parsed, returns @NULL when the parser is not able to parse the part.
+ * Returns: %TRUE if the @mime_part was handled (even if no
+ *          #EMailPart<!-//>s were added to @out_mail_parts), or
+ *          %FALSE if the @mime_part was not handled
  */
-GSList *
+gboolean
 e_mail_parser_extension_parse (EMailParserExtension *extension,
-                              EMailParser *parser,
-                              CamelMimePart *mime_part,
-                              GString *part_id,
-                              GCancellable *cancellable)
+                               EMailParser *parser,
+                               CamelMimePart *mime_part,
+                               GString *part_id,
+                               GCancellable *cancellable,
+                               GQueue *out_mail_parts)
 {
 	EMailParserExtensionInterface *interface;
 
-	g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), NULL);
-	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
+	g_return_val_if_fail (E_IS_MAIL_PARSER_EXTENSION (extension), FALSE);
+	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), FALSE);
 
 	interface = E_MAIL_PARSER_EXTENSION_GET_INTERFACE (extension);
-	g_return_val_if_fail (interface->parse != NULL, NULL);
+	g_return_val_if_fail (interface->parse != NULL, FALSE);
 
-	return interface->parse (extension, parser, mime_part, part_id, cancellable);
+	/* Check for cancellation before calling the method. */
+	if (g_cancellable_is_cancelled (cancellable))
+		return FALSE;
+
+	return interface->parse (
+		extension, parser, mime_part, part_id,
+		cancellable, out_mail_parts);
 }
 
 guint32
diff --git a/em-format/e-mail-parser-extension.h b/em-format/e-mail-parser-extension.h
index 101c132..e5acece 100644
--- a/em-format/e-mail-parser-extension.h
+++ b/em-format/e-mail-parser-extension.h
@@ -68,11 +68,12 @@ typedef enum {
 struct _EMailParserExtensionInterface {
 	EMailExtensionInterface	parent_interface;
 
-	GSList *	(*parse)	(EMailParserExtension *extension,
+	gboolean	(*parse)	(EMailParserExtension *extension,
 					 EMailParser *parser,
 					 CamelMimePart *mime_part,
 					 GString *part_id,
-					 GCancellable *cancellable);
+					 GCancellable *cancellable,
+					 GQueue *out_mail_parts);
 
 	guint32		(*get_flags)	(EMailParserExtension *extension);
 
@@ -80,11 +81,12 @@ struct _EMailParserExtensionInterface {
 
 GType		e_mail_parser_extension_get_type
 						(void) G_GNUC_CONST;
-GSList *	e_mail_parser_extension_parse	(EMailParserExtension *extension,
+gboolean	e_mail_parser_extension_parse	(EMailParserExtension *extension,
 						 EMailParser *parser,
 						 CamelMimePart *mime_part,
 						 GString *part_id,
-						 GCancellable *cancellable);
+						 GCancellable *cancellable,
+						 GQueue *out_mail_parts);
 guint32		e_mail_parser_extension_get_flags
 						(EMailParserExtension *extension);
 
diff --git a/em-format/e-mail-parser-headers.c b/em-format/e-mail-parser-headers.c
index c66563a..edb6de4 100644
--- a/em-format/e-mail-parser-headers.c
+++ b/em-format/e-mail-parser-headers.c
@@ -88,19 +88,17 @@ empe_headers_bind_dom (EMailPart *part,
 	g_free (uri);
 }
 
-static GSList *
+static gboolean
 empe_headers_parse (EMailParserExtension *extension,
                     EMailParser *parser,
                     CamelMimePart *part,
                     GString *part_id,
-                    GCancellable *cancellable)
+                    GCancellable *cancellable,
+                    GQueue *out_mail_parts)
 {
 	EMailPart *mail_part;
 	gint len;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	len = part_id->len;
 	g_string_append (part_id, ".headers");
 
@@ -109,7 +107,9 @@ empe_headers_parse (EMailParserExtension *extension,
 	mail_part->bind_func = empe_headers_bind_dom;
 	g_string_truncate (part_id, len);
 
-	return g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-image.c b/em-format/e-mail-parser-image.c
index b252714..1224274 100644
--- a/em-format/e-mail-parser-image.c
+++ b/em-format/e-mail-parser-image.c
@@ -71,22 +71,21 @@ static const gchar *parser_mime_types[] = { "image/gif",
 					    "image/pjpeg",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_image_parse (EMailParserExtension *extension,
                   EMailParser *parser,
                   CamelMimePart *part,
                   GString *part_id,
-                  GCancellable *cancellable)
+                  GCancellable *cancellable,
+                  GQueue *out_mail_parts)
 {
+	GQueue work_queue = G_QUEUE_INIT;
 	EMailPart *mail_part;
 	const gchar *tmp;
 	gchar *cid;
 	gint len;
 	CamelContentType *ct;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	tmp = camel_mime_part_get_content_id (part);
 	if (tmp) {
 		cid = g_strdup_printf ("cid:%s", tmp);
@@ -107,13 +106,15 @@ empe_image_parse (EMailParserExtension *extension,
 
 	g_string_truncate (part_id, len);
 
-	if (!cid) {
-		return e_mail_parser_wrap_as_attachment (
-			parser, part, g_slist_append (NULL, mail_part),
-			part_id, cancellable);
-	}
+	g_queue_push_tail (&work_queue, mail_part);
+
+	if (cid == NULL)
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
 
-	return g_slist_append (NULL, mail_part);
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-inlinepgp-encrypted.c b/em-format/e-mail-parser-inlinepgp-encrypted.c
index 3a61a5e..ce3f372 100644
--- a/em-format/e-mail-parser-inlinepgp-encrypted.c
+++ b/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -58,12 +58,13 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "application/x-inlinepgp-encrypted",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
                                 EMailParser *parser,
                                 CamelMimePart *part,
                                 GString *part_id,
-                                GCancellable *cancellable)
+                                GCancellable *cancellable,
+                                GQueue *out_mail_parts)
 {
 	CamelCipherContext *cipher;
 	CamelCipherValidity *valid;
@@ -71,11 +72,9 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
 	CamelDataWrapper *dw;
 	gchar *mime_type;
 	gint len;
+	GQueue work_queue = G_QUEUE_INIT;
+	GList *head, *link;
 	GError *local_error = NULL;
-	GSList *parts, *iter;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
 
@@ -86,22 +85,21 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
 		cipher, part, opart, cancellable, &local_error);
 
 	if (local_error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Could not parse PGP message: %s"),
 			local_error->message);
 		g_error_free (local_error);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (parser,
-				part, part_id,
-				"application/vnd.evolution.source",
-				cancellable));
+		e_mail_parser_parse_part_as (parser,
+			part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 		g_object_unref (cipher);
 		g_object_unref (opart);
-		return parts;
+
+		return TRUE;
 	}
 
 	dw = camel_medium_get_content ((CamelMedium *) opart);
@@ -122,18 +120,17 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append (part_id, ".inlinepgp_encrypted");
 
-	parts = e_mail_parser_parse_part_as (
-			parser, opart, part_id,
-			camel_data_wrapper_get_mime_type (dw), cancellable);
+	e_mail_parser_parse_part_as (
+		parser, opart, part_id,
+		camel_data_wrapper_get_mime_type (dw),
+		cancellable, &work_queue);
 
 	g_string_truncate (part_id, len);
 
-	for (iter = parts; iter; iter = iter->next) {
-		EMailPart *mail_part;
+	head = g_queue_peek_head_link (&work_queue);
 
-		mail_part = iter->data;
-		if (!mail_part)
-			continue;
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		EMailPart *mail_part = link->data;
 
 		e_mail_part_update_validity (
 			mail_part, valid,
@@ -141,28 +138,29 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
 			E_MAIL_PART_VALIDITY_PGP);
 	}
 
+	e_queue_transfer (&work_queue, out_mail_parts);
+
 	/* Add a widget with details about the encryption, but only when
 	 * the encrypted isn't itself secured, in that case it has created
 	 * the button itself */
 	if (!e_mail_part_is_secured (opart)) {
-		GSList *button;
 		EMailPart *mail_part;
+
 		g_string_append (part_id, ".inlinepgp_encrypted.button");
 
-		button = e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.widget.secure-button",
-				cancellable);
-		if (button && button->data) {
-			mail_part = button->data;
+		e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.widget.secure-button",
+			cancellable, &work_queue);
 
+		mail_part = g_queue_peek_head (&work_queue);
+		if (mail_part != NULL)
 			e_mail_part_update_validity (
 				mail_part, valid,
 				E_MAIL_PART_VALIDITY_ENCRYPTED |
 				E_MAIL_PART_VALIDITY_PGP);
-		}
 
-		parts = g_slist_concat (parts, button);
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 		g_string_truncate (part_id, len);
 	}
@@ -172,7 +170,7 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
 	g_object_unref (opart);
 	g_object_unref (cipher);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-inlinepgp-signed.c b/em-format/e-mail-parser-inlinepgp-signed.c
index 2346129..723acc2 100644
--- a/em-format/e-mail-parser-inlinepgp-signed.c
+++ b/em-format/e-mail-parser-inlinepgp-signed.c
@@ -58,12 +58,13 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "application/x-inlinepgp-signed",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_inlinepgp_signed_parse (EMailParserExtension *extension,
                              EMailParser *parser,
                              CamelMimePart *part,
                              GString *part_id,
-                             GCancellable *cancellable)
+                             GCancellable *cancellable,
+                             GQueue *out_mail_parts)
 {
 	CamelStream *filtered_stream;
 	CamelMimeFilterPgp *pgp_filter;
@@ -73,14 +74,12 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
 	CamelDataWrapper *dw;
 	CamelMimePart *opart;
 	CamelStream *ostream;
+	GQueue work_queue = G_QUEUE_INIT;
+	GList *head, *link;
 	gchar *type;
 	gint len;
 	GError *local_error = NULL;
 	GByteArray *ba;
-	GSList *parts, *iter;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	cipher = camel_gpg_context_new (e_mail_parser_get_session (parser));
 
@@ -89,22 +88,21 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
 		cipher, part, cancellable, &local_error);
 
 	if (local_error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Error verifying signature: %s"),
 			local_error->message);
 
 		g_error_free (local_error);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source",
-				cancellable));
+		e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 		g_object_unref (cipher);
-		return parts;
+
+		return TRUE;
 	}
 
 	/* Setup output stream */
@@ -147,15 +145,13 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append (part_id, ".inlinepgp_signed");
 
-	parts = e_mail_parser_parse_part (
-		parser, opart, part_id, cancellable);
+	e_mail_parser_parse_part (
+		parser, opart, part_id, cancellable, &work_queue);
 
-	for (iter = parts; iter; iter = iter->next) {
-		EMailPart *mail_part;
+	head = g_queue_peek_head_link (&work_queue);
 
-		mail_part = iter->data;
-		if (!mail_part)
-			continue;
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		EMailPart *mail_part = link->data;
 
 		e_mail_part_update_validity (
 			mail_part, valid,
@@ -163,30 +159,31 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
 			E_MAIL_PART_VALIDITY_PGP);
 	}
 
+	e_queue_transfer (&work_queue, out_mail_parts);
+
 	g_string_truncate (part_id, len);
 
 	/* Add a widget with details about the encryption, but only when
 	 * the encrypted isn't itself secured, in that case it has created
 	 * the button itself */
 	if (!e_mail_part_is_secured (opart)) {
-		GSList *button;
 		EMailPart *mail_part;
+
 		g_string_append (part_id, ".inlinepgp_signed.button");
 
-		button = e_mail_parser_parse_part_as (
+		e_mail_parser_parse_part_as (
 			parser, part, part_id,
 			"application/vnd.evolution.widget.secure-button",
-			cancellable);
-		if (button && button->data) {
-			mail_part = button->data;
+			cancellable, &work_queue);
 
+		mail_part = g_queue_peek_head (&work_queue);
+		if (mail_part != NULL)
 			e_mail_part_update_validity (
 				mail_part, valid,
 				E_MAIL_PART_VALIDITY_SIGNED |
 				E_MAIL_PART_VALIDITY_PGP);
-		}
 
-		parts = g_slist_concat (parts, button);
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 		g_string_truncate (part_id, len);
 	}
@@ -197,7 +194,7 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
 	g_object_unref (ostream);
 	g_object_unref (cipher);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-message-deliverystatus.c b/em-format/e-mail-parser-message-deliverystatus.c
index 3a86a93..f219a97 100644
--- a/em-format/e-mail-parser-message-deliverystatus.c
+++ b/em-format/e-mail-parser-message-deliverystatus.c
@@ -60,19 +60,18 @@ static const gchar * parser_mime_types[] = { "message/delivery-status",
 					    "message/disposition-notification",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_msg_deliverystatus_parse (EMailParserExtension *extension,
                                EMailParser *parser,
                                CamelMimePart *part,
                                GString *part_id,
-                               GCancellable *cancellable)
+                               GCancellable *cancellable,
+                               GQueue *out_mail_parts)
 {
+	GQueue work_queue = G_QUEUE_INIT;
 	EMailPart *mail_part;
 	gsize len;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	len = part_id->len;
 	g_string_append (part_id, ".delivery-status");
 	mail_part = e_mail_part_new (part, part_id->str);
@@ -80,11 +79,15 @@ empe_msg_deliverystatus_parse (EMailParserExtension *extension,
 
 	g_string_truncate (part_id, len);
 
+	g_queue_push_tail (&work_queue, mail_part);
+
 	/* The only reason for having a separate parser for
 	 * message/delivery-status is to display the part as an attachment */
-	return e_mail_parser_wrap_as_attachment (
-			parser, part, g_slist_append (NULL, mail_part),
-			part_id, cancellable);
+	e_mail_parser_wrap_as_attachment (parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-message-external.c b/em-format/e-mail-parser-message-external.c
index 99b6b8b..5768e6e 100644
--- a/em-format/e-mail-parser-message-external.c
+++ b/em-format/e-mail-parser-message-external.c
@@ -58,12 +58,13 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "message/external-body",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_msg_external_parse (EMailParserExtension *extension,
                          EMailParser *parser,
                          CamelMimePart *part,
                          GString *part_id,
-                         GCancellable *cancellable)
+                         GCancellable *cancellable,
+                         GQueue *out_mail_parts)
 {
 	EMailPart *mail_part;
 	CamelMimePart *newpart;
@@ -74,9 +75,6 @@ empe_msg_external_parse (EMailParserExtension *extension,
 	gint len;
 	gchar *mime_type;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	newpart = camel_mime_part_new ();
 
 	/* needs to be cleaner */
@@ -177,7 +175,9 @@ addPart:
 	mail_part->mime_type = mime_type;
 	g_string_truncate (part_id, len);
 
-	return g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-message-rfc822.c b/em-format/e-mail-parser-message-rfc822.c
index 4632c6e..70bf8c8 100644
--- a/em-format/e-mail-parser-message-rfc822.c
+++ b/em-format/e-mail-parser-message-rfc822.c
@@ -62,14 +62,14 @@ static const gchar * parser_mime_types[] = { "message/rfc822",
 					    "message/news",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_msg_rfc822_parse (EMailParserExtension *extension,
                        EMailParser *eparser,
                        CamelMimePart *part,
                        GString *part_id,
-                       GCancellable *cancellable)
+                       GCancellable *cancellable,
+                       GQueue *out_mail_parts)
 {
-	GSList *parts = NULL;
 	EMailPart *mail_part;
 	gint len;
 	CamelMimePart *message;
@@ -81,13 +81,14 @@ empe_msg_rfc822_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append (part_id, ".rfc822");
 
-        /* Create an empty PURI that will represent start of the RFC message */
+	/* Create an empty PURI that will represent start of the RFC message */
 	mail_part = e_mail_part_new (part, part_id->str);
 	mail_part->mime_type = g_strdup ("message/rfc822");
-	parts = g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
 
-	/* Sometime the _actual_ message is encapsulated in another CamelMimePart,
-	 * sometimes the CamelMimePart actually represents the RFC822 message */
+	/* Sometime the actual message is encapsulated in another
+	 * CamelMimePart, sometimes the CamelMimePart itself represents
+	 * the RFC822 message. */
 	ct = camel_mime_part_get_content_type (part);
 	if (camel_content_type_is (ct, "message", "rfc822")) {
 		new_stream = camel_stream_mem_new ();
@@ -110,28 +111,29 @@ empe_msg_rfc822_parse (EMailParserExtension *extension,
 		message = g_object_ref (part);
 	}
 
-	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
-						eparser, message, part_id,
-						"application/vnd.evolution.message",
-						cancellable));
+	e_mail_parser_parse_part_as (
+		eparser, message, part_id,
+		"application/vnd.evolution.message",
+		cancellable, out_mail_parts);
 
 	g_object_unref (message);
 
-        /* Add another generic EMailPart that represents end of the RFC message.
-         * The em_format_write() function will skip all parts between the ".rfc822"
-         * part and ".rfc822.end" part as they will be rendered in an <iframe> */
+	/* Add another generic EMailPart that represents end of the RFC
+	 * message.  The em_format_write() function will skip all parts
+	 * between the ".rfc822" part and ".rfc822.end" part as they will
+	 * be rendered in an <iframe>. */
 	g_string_append (part_id, ".end");
 	mail_part = e_mail_part_new (message, part_id->str);
 	mail_part->is_hidden = TRUE;
-	parts = g_slist_append (parts, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
+
 	g_string_truncate (part_id, len);
 
-	if (e_mail_part_is_attachment (message)) {
-		return e_mail_parser_wrap_as_attachment (
-			eparser, message, parts, part_id, cancellable);
-	}
+	if (e_mail_part_is_attachment (message))
+		e_mail_parser_wrap_as_attachment (
+			eparser, message, part_id, out_mail_parts);
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/em-format/e-mail-parser-message.c b/em-format/e-mail-parser-message.c
index 7b6e620..df7d4b3 100644
--- a/em-format/e-mail-parser-message.c
+++ b/em-format/e-mail-parser-message.c
@@ -59,31 +59,28 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "application/vnd.evolution.message", NULL };
 
-static GSList *
+static gboolean
 empe_message_parse (EMailParserExtension *extension,
                     EMailParser *parser,
                     CamelMimePart *part,
                     GString *part_id,
-                    GCancellable *cancellable)
+                    GCancellable *cancellable,
+                    GQueue *out_mail_parts)
 {
-	GSList *parts;
 	CamelContentType *ct;
 	gchar *mime_type;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	/* Headers */
-	parts = g_slist_concat (NULL, e_mail_parser_parse_part_as (
-					parser, part, part_id,
-					"application/vnd.evolution.headers",
-					cancellable));
+	e_mail_parser_parse_part_as (
+		parser, part, part_id,
+		"application/vnd.evolution.headers",
+		cancellable, out_mail_parts);
 
 	/* Attachment Bar */
-	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
-					parser, part, part_id,
-					"application/vnd.evolution.widget.attachment-bar",
-					cancellable));
+	e_mail_parser_parse_part_as (
+		parser, part, part_id,
+		"application/vnd.evolution.widget.attachment-bar",
+		cancellable, out_mail_parts);
 
 	ct = camel_mime_part_get_content_type (part);
 	mime_type = camel_content_type_simple (ct);
@@ -103,13 +100,13 @@ empe_message_parse (EMailParserExtension *extension,
 	}
 
 	/* Actual message body */
-	parts = g_slist_concat (parts, e_mail_parser_parse_part_as (
-					parser, part, part_id, mime_type,
-					cancellable));
+	e_mail_parser_parse_part_as (
+		parser, part, part_id, mime_type,
+		cancellable, out_mail_parts);
 
 	g_free (mime_type);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-multipart-alternative.c b/em-format/e-mail-parser-multipart-alternative.c
index 74826da..de4261b 100644
--- a/em-format/e-mail-parser-multipart-alternative.c
+++ b/em-format/e-mail-parser-multipart-alternative.c
@@ -65,32 +65,28 @@ related_display_part_is_attachment (CamelMimePart *part)
 	return display_part && e_mail_part_is_attachment (display_part);
 }
 
-static GSList *
+static gboolean
 empe_mp_alternative_parse (EMailParserExtension *extension,
                            EMailParser *parser,
                            CamelMimePart *part,
                            GString *part_id,
-                           GCancellable *cancellable)
+                           GCancellable *cancellable,
+                           GQueue *out_mail_parts)
 {
 	CamelMultipart *mp;
 	gint i, nparts, bestid = 0;
 	CamelMimePart *best = NULL;
-	GSList *parts;
 	EMailExtensionRegistry *reg;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	reg = e_mail_parser_get_extension_registry (parser);
 
 	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
 
-	if (!CAMEL_IS_MULTIPART (mp)) {
+	if (!CAMEL_IS_MULTIPART (mp))
 		return e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source",
-				cancellable);
-	}
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 	/* as per rfc, find the last part we know how to display */
 	nparts = camel_multipart_get_number (mp);
@@ -103,7 +99,7 @@ empe_mp_alternative_parse (EMailParserExtension *extension,
 		gsize content_size;
 
 		if (g_cancellable_is_cancelled (cancellable))
-			return NULL;
+			return TRUE;
 
 		/* is it correct to use the passed in *part here? */
 		mpart = camel_multipart_get_part (mp, i);
@@ -148,16 +144,18 @@ empe_mp_alternative_parse (EMailParserExtension *extension,
 
 		g_string_append_printf (part_id, ".alternative.%d", bestid);
 
-		parts = e_mail_parser_parse_part (
-			parser, best, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, best, part_id,
+			cancellable, out_mail_parts);
 
 		g_string_truncate (part_id, len);
 	} else {
-		parts = e_mail_parser_parse_part_as (
-			parser, part, part_id, "multipart/mixed", cancellable);
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 	}
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-multipart-appledouble.c b/em-format/e-mail-parser-multipart-appledouble.c
index f8e1cf3..297ded6 100644
--- a/em-format/e-mail-parser-multipart-appledouble.c
+++ b/em-format/e-mail-parser-multipart-appledouble.c
@@ -52,26 +52,23 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar * parser_mime_types[] = { "multipart/appledouble", NULL };
 
-static GSList *
+static gboolean
 empe_mp_appledouble_parse (EMailParserExtension *extension,
                            EMailParser *parser,
                            CamelMimePart *part,
                            GString *part_id,
-                           GCancellable *cancellable)
+                           GCancellable *cancellable,
+                           GQueue *out_mail_parts)
 {
 	CamelMultipart *mp;
-	GSList *parts;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
 
 	if (!CAMEL_IS_MULTIPART (mp)) {
-		parts = e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source",
-				cancellable);
+		e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 	} else {
 		CamelMimePart *mime_part;
 		mime_part = camel_multipart_get_part (mp, 1);
@@ -82,21 +79,21 @@ empe_mp_appledouble_parse (EMailParserExtension *extension,
 			len = part_id->len;
 			g_string_append_printf (part_id, ".appledouble.1");
 
-			parts = e_mail_parser_parse_part (
-					parser, mime_part, part_id, cancellable);
+			e_mail_parser_parse_part (
+				parser, mime_part, part_id,
+				cancellable, out_mail_parts);
 
 			g_string_truncate (part_id, len);
 
 		} else {
-
-			parts = e_mail_parser_parse_part_as (
-					parser, part, part_id,
-					"application/vnd.evolution.source",
-					cancellable);
+			e_mail_parser_parse_part_as (
+				parser, part, part_id,
+				"application/vnd.evolution.source",
+				cancellable, out_mail_parts);
 		}
 	}
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-multipart-digest.c b/em-format/e-mail-parser-multipart-digest.c
index 2acd8ee..70f5eeb 100644
--- a/em-format/e-mail-parser-multipart-digest.c
+++ b/em-format/e-mail-parser-multipart-digest.c
@@ -56,31 +56,27 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "multipart/digest",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_mp_digest_parse (EMailParserExtension *extension,
                       EMailParser *parser,
                       CamelMimePart *part,
                       GString *part_id,
-                      GCancellable *cancellable)
+                      GCancellable *cancellable,
+                      GQueue *out_mail_parts)
 {
 	CamelMultipart *mp;
 	gint i, nparts, len;
-	GSList *parts;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
 
-	if (!CAMEL_IS_MULTIPART (mp)) {
+	if (!CAMEL_IS_MULTIPART (mp))
 		return e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source", cancellable);
-	}
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 	len = part_id->len;
 	nparts = camel_multipart_get_number (mp);
-	parts = NULL;
 	for (i = 0; i < nparts; i++) {
 		CamelMimePart *subpart;
 		CamelContentType *ct;
@@ -99,43 +95,39 @@ empe_mp_digest_parse (EMailParserExtension *extension,
 		if (ct && !camel_content_type_is (ct, "message", "rfc822")) {
 			cts = camel_content_type_simple (ct);
 
-			parts = g_slist_concat (
-				parts,
-				e_mail_parser_parse_part_as (
-					parser, subpart, part_id,
-					cts, cancellable));
+			e_mail_parser_parse_part_as (
+				parser, subpart, part_id, cts,
+				cancellable, out_mail_parts);
 
 			g_free (cts);
 		} else {
-			GSList *new_parts;
+			GQueue work_queue = G_QUEUE_INIT;
+			EMailPart *mail_part;
+
+			e_mail_parser_parse_part_as (
+				parser, subpart, part_id, "message/rfc822",
+				cancellable, &work_queue);
 
-			new_parts = e_mail_parser_parse_part_as (
-					parser, subpart, part_id,
-					"message/rfc822", cancellable);
+			mail_part = g_queue_peek_head (&work_queue);
 
 			/* Force the message to be collapsable */
-			if (new_parts && new_parts->data &&
-			    !E_MAIL_PART (new_parts->data)->is_attachment) {
-				new_parts = e_mail_parser_wrap_as_attachment (
-					parser, subpart, new_parts, part_id,
-					cancellable);
-			}
+			if (mail_part != NULL && !mail_part->is_attachment)
+				e_mail_parser_wrap_as_attachment (
+					parser, subpart, part_id, &work_queue);
+
+			mail_part = g_queue_peek_head (&work_queue);
 
 			/* Force the message to be expanded */
-			if (new_parts) {
-				EMailPart *p = new_parts->data;
-				if (p) {
-					p->force_inline = TRUE;
-				}
-			}
-
-			parts = g_slist_concat (parts, new_parts);
+			if (mail_part != NULL)
+				mail_part->force_inline = TRUE;
+
+			e_queue_transfer (&work_queue, out_mail_parts);
 		}
 
 		g_string_truncate (part_id, len);
 	}
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/em-format/e-mail-parser-multipart-encrypted.c b/em-format/e-mail-parser-multipart-encrypted.c
index db417fa..fedef39 100644
--- a/em-format/e-mail-parser-multipart-encrypted.c
+++ b/em-format/e-mail-parser-multipart-encrypted.c
@@ -28,6 +28,7 @@
 
 #include <glib/gi18n-lib.h>
 #include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
 
 typedef struct _EMailParserMultipartEncrypted {
 	GObject parent;
@@ -54,56 +55,50 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar * parser_mime_types[] = { "multipart/encrypted", NULL };
 
-static GSList *
+static gboolean
 empe_mp_encrypted_parse (EMailParserExtension *extension,
                          EMailParser *parser,
                          CamelMimePart *part,
                          GString *part_id,
-                         GCancellable *cancellable)
+                         GCancellable *cancellable,
+                         GQueue *out_mail_parts)
 {
 	CamelCipherContext *context;
 	const gchar *protocol;
 	CamelMimePart *opart;
 	CamelCipherValidity *valid;
 	CamelMultipartEncrypted *mpe;
+	GQueue work_queue = G_QUEUE_INIT;
+	GList *head, *link;
 	GError *local_error = NULL;
-	GSList *parts;
 	gint len;
-	GSList *iter;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part);
 	if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Could not parse MIME message. "
 			"Displaying as source."));
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution/source",
-				cancellable));
-
-		return parts;
+		e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution/source",
+			cancellable, out_mail_parts);
+
+		return TRUE;
 	}
 
 	/* Currently we only handle RFC2015-style PGP encryption. */
 	protocol = camel_content_type_param (
 		((CamelDataWrapper *) mpe)->mime_type, "protocol");
 	if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Unsupported encryption type for multipart/encrypted"));
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"multipart/mixed", cancellable));
-		return parts;
+		return TRUE;
 	}
 
 	context = camel_gpg_context_new (e_mail_parser_get_session (parser));
@@ -115,40 +110,34 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
 	e_mail_part_preserve_charset_in_content_type (part, opart);
 
 	if (local_error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Could not parse PGP/MIME message: %s"),
 			local_error->message);
-
-		g_error_free (local_error);
-
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"multipart/mixed", cancellable));
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 
 		g_object_unref (opart);
 		g_object_unref (context);
+		g_error_free (local_error);
 
-		return parts;
+		return TRUE;
 	}
 
 	len = part_id->len;
 	g_string_append (part_id, ".encrypted");
 
-	parts = e_mail_parser_parse_part (
-		parser, opart, part_id, cancellable);
+	e_mail_parser_parse_part (
+		parser, opart, part_id, cancellable, &work_queue);
 
 	g_string_truncate (part_id, len);
 
-	/* Update validity of all encrypted sub-parts */
-	for (iter = parts; iter; iter = iter->next) {
-		EMailPart *mail_part;
+	head = g_queue_peek_head_link (&work_queue);
 
-		mail_part = iter->data;
-		if (!mail_part)
-			continue;
+	/* Update validity of all encrypted sub-parts */
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		EMailPart *mail_part = link->data;
 
 		e_mail_part_update_validity (
 			mail_part, valid,
@@ -156,28 +145,30 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
 			E_MAIL_PART_VALIDITY_PGP);
 	}
 
+	e_queue_transfer (&work_queue, out_mail_parts);
+
 	/* Add a widget with details about the encryption, but only when
 	 * the decrypted part isn't itself secured, in that case it has
 	 * created the button itself. */
 	if (!e_mail_part_is_secured (opart)) {
-		GSList *button;
 		EMailPart *mail_part;
+
 		g_string_append (part_id, ".encrypted.button");
 
-		button = e_mail_parser_parse_part_as (
+		e_mail_parser_parse_part_as (
 			parser, part, part_id,
 			"application/vnd.evolution.widget.secure-button",
-			cancellable);
-		if (button && button->data) {
-			mail_part = button->data;
+			cancellable, &work_queue);
+
+		mail_part = g_queue_peek_head (&work_queue);
 
+		if (mail_part != NULL)
 			e_mail_part_update_validity (
 				mail_part, valid,
 				E_MAIL_PART_VALIDITY_ENCRYPTED |
 				E_MAIL_PART_VALIDITY_PGP);
-		}
 
-		parts = g_slist_concat (parts, button);
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 		g_string_truncate (part_id, len);
 	}
@@ -188,7 +179,7 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
 	g_object_unref (opart);
 	g_object_unref (context);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-multipart-mixed.c b/em-format/e-mail-parser-multipart-mixed.c
index 6988273..f416ffd 100644
--- a/em-format/e-mail-parser-multipart-mixed.c
+++ b/em-format/e-mail-parser-multipart-mixed.c
@@ -59,79 +59,73 @@ static const gchar * parser_mime_types[] = { "multipart/mixed",
 					    "multipart/*",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_mp_mixed_parse (EMailParserExtension *extension,
                      EMailParser *parser,
                      CamelMimePart *part,
                      GString *part_id,
-                     GCancellable *cancellable)
+                     GCancellable *cancellable,
+                     GQueue *out_mail_parts)
 {
 	CamelMultipart *mp;
 	gint i, nparts, len;
-	GSList *parts;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
 
-	if (!CAMEL_IS_MULTIPART (mp)) {
-		parts = e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source", cancellable);
-		return parts;
-	}
+	if (!CAMEL_IS_MULTIPART (mp))
+		return e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 	len = part_id->len;
-	parts = NULL;
 	nparts = camel_multipart_get_number (mp);
 	for (i = 0; i < nparts; i++) {
+		GQueue work_queue = G_QUEUE_INIT;
+		EMailPart *mail_part;
 		CamelMimePart *subpart;
 		CamelContentType *ct;
-		GSList *new_parts;
 
 		subpart = camel_multipart_get_part (mp, i);
 
 		g_string_append_printf (part_id, ".mixed.%d", i);
 
-		new_parts = e_mail_parser_parse_part (
-				parser, subpart, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, subpart, part_id, cancellable, &work_queue);
+
+		mail_part = g_queue_peek_head (&work_queue);
 
 		ct = camel_mime_part_get_content_type (subpart);
 
-		/* Display parts with CID as attachments (unless they already are
-		 * attachments) */
-		if (new_parts && new_parts->data &&
-			(E_MAIL_PART (new_parts->data)->cid != NULL) &&
-			!E_MAIL_PART (new_parts->data)->is_attachment) {
+		/* Display parts with CID as attachments
+		 * (unless they already are attachments). */
+		if (mail_part != NULL &&
+			mail_part->cid != NULL &&
+			!mail_part->is_attachment) {
 
-			parts = g_slist_concat (
-				parts,
-				e_mail_parser_wrap_as_attachment (
-					parser, subpart, new_parts,
-					part_id, cancellable));
+			e_mail_parser_wrap_as_attachment (
+				parser, subpart, part_id, &work_queue);
 
 			/* Force messages to be expandable */
-		} else if (!new_parts ||
+		} else if (mail_part == NULL ||
 		    (camel_content_type_is (ct, "message", "rfc822") &&
-		     new_parts && new_parts->data &&
-		     !E_MAIL_PART (new_parts->data)->is_attachment)) {
-
-			parts = g_slist_concat (
-				parts,
-				e_mail_parser_wrap_as_attachment (
-					parser, subpart, new_parts,
-					part_id, cancellable));
-			if (parts && parts->data)
-				E_MAIL_PART (parts->data)->force_inline = TRUE;
-		} else {
-			parts = g_slist_concat (parts, new_parts);
+		     mail_part != NULL && !mail_part->is_attachment)) {
+
+			e_mail_parser_wrap_as_attachment (
+				parser, subpart, part_id, &work_queue);
+
+			mail_part = g_queue_peek_head (&work_queue);
+
+			if (mail_part != NULL)
+				mail_part->force_inline = TRUE;
 		}
 
+		e_queue_transfer (&work_queue, out_mail_parts);
+
 		g_string_truncate (part_id, len);
 	}
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/em-format/e-mail-parser-multipart-related.c b/em-format/e-mail-parser-multipart-related.c
index e72b61e..0a368ea 100644
--- a/em-format/e-mail-parser-multipart-related.c
+++ b/em-format/e-mail-parser-multipart-related.c
@@ -57,79 +57,75 @@ G_DEFINE_TYPE_EXTENDED (
 static const gchar * parser_mime_types[] = { "multipart/related",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_mp_related_parse (EMailParserExtension *extension,
                        EMailParser *parser,
                        CamelMimePart *part,
                        GString *part_id,
-                       GCancellable *cancellable)
+                       GCancellable *cancellable,
+                       GQueue *out_mail_parts)
 {
 	CamelMultipart *mp;
 	CamelMimePart *body_part, *display_part = NULL;
 	gint i, nparts, partidlen, displayid = 0;
-	GSList *parts;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
 
 	mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
 
-	if (!CAMEL_IS_MULTIPART (mp)) {
+	if (!CAMEL_IS_MULTIPART (mp))
 		return e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source", cancellable);
-	}
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 	display_part = e_mail_part_get_related_display_part (part, &displayid);
 
-	if (display_part == NULL) {
+	if (display_part == NULL)
 		return e_mail_parser_parse_part_as (
-				parser, part, part_id, "multipart/mixed",
-				cancellable);
-	}
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 
 	/* The to-be-displayed part goes first */
 	partidlen = part_id->len;
 	g_string_append_printf (part_id, ".related.%d", displayid);
 
-	parts = e_mail_parser_parse_part (
-			parser, display_part, part_id, cancellable);
+	e_mail_parser_parse_part (
+		parser, display_part, part_id, cancellable, out_mail_parts);
 
 	g_string_truncate (part_id, partidlen);
 
 	/* Process the related parts */
 	nparts = camel_multipart_get_number (mp);
 	for (i = 0; i < nparts; i++) {
-		GSList *list, *iter;
+		GQueue work_queue = G_QUEUE_INIT;
+		GList *head, *link;
+
 		body_part = camel_multipart_get_part (mp, i);
-		list = NULL;
 
 		if (body_part == display_part)
 			continue;
 
 		g_string_append_printf (part_id, ".related.%d", i);
 
-		list = e_mail_parser_parse_part (
-				parser, body_part, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, body_part, part_id,
+			cancellable, &work_queue);
 
 		g_string_truncate (part_id, partidlen);
 
-		for (iter = list; iter; iter = iter->next) {
-			EMailPart *mail_part;
+		head = g_queue_peek_head_link (&work_queue);
 
-			mail_part = iter->data;
-			if (!mail_part)
-				continue;
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			EMailPart *mail_part = link->data;
 
 			/* Don't render the part on it's own! */
 			if (mail_part->cid != NULL)
 				mail_part->is_hidden = TRUE;
 		}
 
-		parts = g_slist_concat (parts, list);
+		e_queue_transfer (&work_queue, out_mail_parts);
 	}
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-multipart-signed.c b/em-format/e-mail-parser-multipart-signed.c
index b7d395a..60fac35 100644
--- a/em-format/e-mail-parser-multipart-signed.c
+++ b/em-format/e-mail-parser-multipart-signed.c
@@ -28,6 +28,7 @@
 
 #include <glib/gi18n-lib.h>
 #include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
 
 typedef struct _EMailParserMultipartSigned {
 	GObject parent;
@@ -56,33 +57,30 @@ static const gchar * parser_mime_types[] = { "multipart/signed",
 					    "application/pgp-signature",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_mp_signed_parse (EMailParserExtension *extension,
                       EMailParser *parser,
                       CamelMimePart *part,
                       GString *part_id,
-                      GCancellable *cancellable)
+                      GCancellable *cancellable,
+                      GQueue *out_mail_parts)
 {
 	CamelMimePart *cpart;
 	CamelMultipartSigned *mps;
 	CamelCipherContext *cipher = NULL;
 	CamelSession *session;
 	guint32 validity_type;
-	GSList *parts;
 	CamelCipherValidity *valid;
 	GError *local_error = NULL;
 	gint i, nparts, len;
 	gboolean secured;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	/* If the part is application/pgp-signature sub-part then skip it. */
 	if (!CAMEL_IS_MULTIPART (part)) {
 		CamelContentType *ct;
 		ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (part));
 		if (camel_content_type_is (ct, "application", "pgp-signature")) {
-			return g_slist_alloc ();
+			return TRUE;
 		}
 	}
 
@@ -92,18 +90,16 @@ empe_mp_signed_parse (EMailParserExtension *extension,
 		cpart = camel_multipart_get_part (
 			(CamelMultipart *) mps,
 		CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Could not parse MIME message. "
 			"Displaying as source."));
+		e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"application/vnd.evolution.source",
-				cancellable));
-		return parts;
+		return TRUE;
 	}
 
 	session = e_mail_parser_get_session (parser);
@@ -127,95 +123,89 @@ empe_mp_signed_parse (EMailParserExtension *extension,
 	}
 
 	if (cipher == NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Unsupported signature format"));
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"multipart/mixed", cancellable));
-
-		return parts;
+		return TRUE;
 	}
 
 	valid = camel_cipher_context_verify_sync (
 		cipher, part, cancellable, &local_error);
 
 	if (local_error != NULL) {
-		parts = e_mail_parser_error (
-			parser, cancellable,
+		e_mail_parser_error (
+			parser, out_mail_parts,
 			_("Error verifying signature: %s"),
 			local_error->message);
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, out_mail_parts);
 
+		g_object_unref (cipher);
 		g_error_free (local_error);
 
-		parts = g_slist_concat (
-			parts,
-			e_mail_parser_parse_part_as (
-				parser, part, part_id,
-				"multipart/mixed", cancellable));
-
-		g_object_unref (cipher);
-		return parts;
+		return TRUE;
 	}
 
 	nparts = camel_multipart_get_number (CAMEL_MULTIPART (mps));
 	secured = FALSE;
 	len = part_id->len;
-	parts = NULL;
 	for (i = 0; i < nparts; i++) {
+		GQueue work_queue = G_QUEUE_INIT;
+		GList *head, *link;
 		CamelMimePart *subpart;
-		GSList *mail_parts, *iter;
+
 		subpart = camel_multipart_get_part (CAMEL_MULTIPART (mps), i);
 
 		g_string_append_printf (part_id, ".signed.%d", i);
 
-		mail_parts = e_mail_parser_parse_part (
-			parser, subpart, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, subpart, part_id, cancellable, &work_queue);
 
 		g_string_truncate (part_id, len);
 
 		if (!secured)
 			secured = e_mail_part_is_secured (subpart);
 
-		for (iter = mail_parts; iter; iter = iter->next) {
-			EMailPart *mail_part;
+		head = g_queue_peek_head_link (&work_queue);
 
-			mail_part = iter->data;
-			if (!mail_part)
-				continue;
+		for (link = head; link != NULL; link = g_list_next (link)) {
+			EMailPart *mail_part = link->data;
 
 			e_mail_part_update_validity (
 				mail_part, valid,
 				validity_type | E_MAIL_PART_VALIDITY_SIGNED);
 		}
 
-		parts = g_slist_concat (parts, mail_parts);
+		e_queue_transfer (&work_queue, out_mail_parts);
 	}
 
 	/* Add a widget with details about the encryption, but only when
-		* the encrypted isn't itself secured, in that case it has created
-		* the button itself */
+	 * the encrypted isn't itself secured, in that case it has created
+	 * the button itself. */
 	if (!secured) {
-		GSList *button;
+		GQueue work_queue = G_QUEUE_INIT;
 		EMailPart *mail_part;
+
 		g_string_append (part_id, ".signed.button");
 
-		button = e_mail_parser_parse_part_as (
+		e_mail_parser_parse_part_as (
 			parser, part, part_id,
 			"application/vnd.evolution.widget.secure-button",
-			cancellable);
-		if (button && button->data) {
-			mail_part = button->data;
+			cancellable, &work_queue);
 
+		mail_part = g_queue_peek_head (&work_queue);
+
+		if (mail_part != NULL)
 			e_mail_part_update_validity (
 				mail_part, valid,
 				validity_type | E_MAIL_PART_VALIDITY_SIGNED);
-		}
 
-		parts = g_slist_concat (parts, button);
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 		g_string_truncate (part_id, len);
 	}
@@ -224,7 +214,7 @@ empe_mp_signed_parse (EMailParserExtension *extension,
 
 	g_object_unref (cipher);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-secure-button.c b/em-format/e-mail-parser-secure-button.c
index 92a0f61..cb4282c 100644
--- a/em-format/e-mail-parser-secure-button.c
+++ b/em-format/e-mail-parser-secure-button.c
@@ -54,12 +54,13 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "application/vnd.evolution.widget.secure-button", NULL };
 
-static GSList *
+static gboolean
 empe_secure_button_parse (EMailParserExtension *extension,
                           EMailParser *parser,
                           CamelMimePart *part,
                           GString *part_id,
-                          GCancellable *cancellable)
+                          GCancellable *cancellable,
+                          GQueue *out_mail_parts)
 {
 	EMailPart *mail_part;
 	gint len;
@@ -70,7 +71,9 @@ empe_secure_button_parse (EMailParserExtension *extension,
 	mail_part->mime_type = g_strdup ("application/vnd.evolution.widget.secure-button");
 	g_string_truncate (part_id, len);
 
-	return g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-source.c b/em-format/e-mail-parser-source.c
index db08144..ee563ac 100644
--- a/em-format/e-mail-parser-source.c
+++ b/em-format/e-mail-parser-source.c
@@ -54,19 +54,17 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "application/vnd.evolution.source", NULL };
 
-static GSList *
+static gboolean
 empe_source_parse (EMailParserExtension *extension,
                    EMailParser *parser,
                    CamelMimePart *part,
                    GString *part_id,
-                   GCancellable *cancellable)
+                   GCancellable *cancellable,
+                   GQueue *out_mail_parts)
 {
 	EMailPart *mail_part;
 	gint len;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	len = part_id->len;
 	g_string_append (part_id, ".source");
 
@@ -74,7 +72,9 @@ empe_source_parse (EMailParserExtension *extension,
 	mail_part->mime_type = g_strdup ("application/vnd.evolution.source");
 	g_string_truncate (part_id, len);
 
-	return g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
+
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-text-enriched.c b/em-format/e-mail-parser-text-enriched.c
index c231307..34a64c3 100644
--- a/em-format/e-mail-parser-text-enriched.c
+++ b/em-format/e-mail-parser-text-enriched.c
@@ -57,21 +57,20 @@ static const gchar *parser_mime_types[] = { "text/richtext",
 					    "text/enriched",
 					    NULL };
 
-static GSList *
+static gboolean
 empe_text_enriched_parse (EMailParserExtension *extension,
                           EMailParser *parser,
                           CamelMimePart *part,
                           GString *part_id,
-                          GCancellable *cancellable)
+                          GCancellable *cancellable,
+                          GQueue *out_mail_parts)
 {
+	GQueue work_queue = G_QUEUE_INIT;
 	EMailPart *mail_part;
 	const gchar *tmp;
 	gint len;
 	CamelContentType *ct;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	len = part_id->len;
 	g_string_append (part_id, ".text_enriched");
 
@@ -88,13 +87,15 @@ empe_text_enriched_parse (EMailParserExtension *extension,
 
 	g_string_truncate (part_id, len);
 
-	if (e_mail_part_is_attachment (part)) {
-		return e_mail_parser_wrap_as_attachment (
-				parser, part, g_slist_append (NULL, mail_part),
-				part_id, cancellable);
-	}
+	g_queue_push_tail (&work_queue, mail_part);
+
+	if (e_mail_part_is_attachment (part))
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
 
-	return g_slist_append (NULL, mail_part);
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-text-html.c b/em-format/e-mail-parser-text-html.c
index b824931..a28a8ff 100644
--- a/em-format/e-mail-parser-text-html.c
+++ b/em-format/e-mail-parser-text-html.c
@@ -57,22 +57,21 @@ G_DEFINE_TYPE_EXTENDED (
 
 static const gchar *parser_mime_types[] = { "text/html", NULL };
 
-static GSList *
+static gboolean
 empe_text_html_parse (EMailParserExtension *extension,
                       EMailParser *parser,
                       CamelMimePart *part,
                       GString *part_id,
-                      GCancellable *cancellable)
+                      GCancellable *cancellable,
+                      GQueue *out_mail_parts)
 {
-	EMailPart *empart;
+	GQueue work_queue = G_QUEUE_INIT;
+	EMailPart *mail_part;
 	const gchar *location;
 	gchar *cid = NULL;
 	const gchar *base;
 	gint len;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
-
 	cid = NULL;
 	base = camel_medium_get_header (CAMEL_MEDIUM (part), "content-base");
 	location = camel_mime_part_get_content_location (part);
@@ -93,18 +92,20 @@ empe_text_html_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append (part_id, ".text_html");
 
-	empart = e_mail_part_new (part, part_id->str);
-	empart->mime_type = g_strdup ("text/html");
-	empart->cid = cid;
+	mail_part = e_mail_part_new (part, part_id->str);
+	mail_part->mime_type = g_strdup ("text/html");
+	mail_part->cid = cid;
 	g_string_truncate (part_id, len);
 
-	if (e_mail_part_is_attachment (part)) {
-		return e_mail_parser_wrap_as_attachment (
-				parser, part, g_slist_append (NULL, empart),
-				part_id, cancellable);
-	}
+	g_queue_push_head (&work_queue, mail_part);
+
+	if (e_mail_part_is_attachment (part))
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
 
-	return g_slist_append (NULL, empart);
+	return TRUE;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser-text-plain.c b/em-format/e-mail-parser-text-plain.c
index bdfcd15..4c9c0b3 100644
--- a/em-format/e-mail-parser-text-plain.c
+++ b/em-format/e-mail-parser-text-plain.c
@@ -80,32 +80,30 @@ part_is_empty (CamelMimePart *part)
 	return TRUE;
 }
 
-static GSList *
+static gboolean
 process_part (EMailParser *parser,
               GString *part_id,
               gint part_number,
               CamelMimePart *part,
               gboolean is_attachment,
-              GCancellable *cancellable)
+              GCancellable *cancellable,
+              GQueue *out_mail_parts)
 {
 	CamelContentType *type;
 	EMailPart *empart;
 	gint s_len = part_id->len;
-	GSList *parts;
 
-	if (part_is_empty (part)) {
-		return g_slist_alloc ();
-	}
+	if (part_is_empty (part))
+		return TRUE;
 
 	type = camel_mime_part_get_content_type (part);
 	if (!camel_content_type_is (type, "text", "*")) {
-
-		parts = e_mail_parser_parse_part (
-				parser, CAMEL_MIME_PART (part),
-				part_id, cancellable);
-		return parts;
+		e_mail_parser_parse_part (
+			parser, CAMEL_MIME_PART (part), part_id,
+			cancellable, out_mail_parts);
 
 	} else if (!camel_content_type_is (type, "text", "calendar")) {
+		GQueue work_queue = G_QUEUE_INIT;
 
 		g_string_append_printf (part_id, ".plain_text.%d", part_number);
 
@@ -114,37 +112,35 @@ process_part (EMailParser *parser,
 
 		g_string_truncate (part_id, s_len);
 
-		if (is_attachment) {
-
-			return e_mail_parser_wrap_as_attachment (
-					parser, part,
-					g_slist_append (NULL, empart),
-					part_id, cancellable);
+		g_queue_push_tail (&work_queue, empart);
 
-		}
+		if (is_attachment)
+			e_mail_parser_wrap_as_attachment (
+				parser, part, part_id, &work_queue);
 
-		return g_slist_append (NULL, empart);
-	}
+		e_queue_transfer (&work_queue, out_mail_parts);
 
-	g_string_append_printf (part_id, ".inline.%d", part_number);
+	} else {
+		g_string_append_printf (part_id, ".inline.%d", part_number);
 
-	parts = e_mail_parser_parse_part (
-			parser, CAMEL_MIME_PART (part),
-			part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, CAMEL_MIME_PART (part), part_id,
+			cancellable, out_mail_parts);
 
-	g_string_truncate (part_id, s_len);
+		g_string_truncate (part_id, s_len);
+	}
 
-	return parts;
+	return TRUE;
 }
 
-static GSList *
+static gboolean
 empe_text_plain_parse (EMailParserExtension *extension,
                        EMailParser *parser,
                        CamelMimePart *part,
                        GString *part_id,
-                       GCancellable *cancellable)
+                       GCancellable *cancellable,
+                       GQueue *out_mail_parts)
 {
-	GSList *parts;
 	CamelStream *filtered_stream, *null;
 	CamelMultipart *mp;
 	CamelDataWrapper *dw;
@@ -154,13 +150,11 @@ empe_text_plain_parse (EMailParserExtension *extension,
 	gboolean charset_added = FALSE;
 	const gchar *snoop_type = NULL;
 	gboolean is_attachment;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
+	gint n_parts_added = 0;
 
 	dw = camel_medium_get_content ((CamelMedium *) part);
 	if (!dw)
-		return NULL;
+		return FALSE;
 
 	/* This scans the text part for inline-encoded data, creates
 	 * a multipart of all the parts inside it. */
@@ -206,7 +200,7 @@ empe_text_plain_parse (EMailParserExtension *extension,
 		return process_part (
 			parser, part_id, 0,
 			part, e_mail_part_is_attachment (part),
-			cancellable);
+			cancellable, out_mail_parts);
 	}
 
 	mp = e_mail_inline_filter_get_multipart (inline_filter);
@@ -220,7 +214,6 @@ empe_text_plain_parse (EMailParserExtension *extension,
 
 	/* We handle our made-up multipart here, so we don't recursively call ourselves */
 	count = camel_multipart_get_number (mp);
-	parts = NULL;
 
 	is_attachment = ((count == 1) && (e_mail_part_is_attachment (part)));
 
@@ -230,17 +223,15 @@ empe_text_plain_parse (EMailParserExtension *extension,
 		if (!newpart)
 			continue;
 
-		parts = g_slist_concat (
-			parts,
-			process_part (
-				parser, part_id, i,
-				newpart, is_attachment,
-				cancellable));
+		n_parts_added += process_part (
+			parser, part_id, i,
+			newpart, is_attachment,
+			cancellable, out_mail_parts);
 	}
 
 	g_object_unref (mp);
 
-	return parts;
+	return n_parts_added;
 }
 
 static const gchar **
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
index 8e5ccd4..55e6eef 100644
--- a/em-format/e-mail-parser.c
+++ b/em-format/e-mail-parser.c
@@ -62,11 +62,11 @@ mail_parser_run (EMailParser *parser,
 {
 	EMailExtensionRegistry *reg;
 	CamelMimeMessage *message;
-	EMailPart *part;
+	EMailPart *mail_part;
 	GQueue *parsers;
+	GQueue mail_part_queue = G_QUEUE_INIT;
 	GList *iter;
 	GString *part_id;
-	GSList *list_of_parts;
 
 	message = e_mail_part_list_get_message (part_list);
 
@@ -79,18 +79,19 @@ mail_parser_run (EMailParser *parser,
 		parsers = e_mail_extension_registry_get_for_mime_type (
 			reg, "message/*");
 
-	/* parsers == NULL means, that the internal Evolution parser
-	 * extensions were not loaded. Something is terribly wrong. */
+	/* No parsers means the internal Evolution parser
+	 * extensions were not loaded. Something is terribly wrong! */
 	g_return_if_fail (parsers != NULL);
 
 	part_id = g_string_new (".message");
 
-	part = e_mail_part_new (CAMEL_MIME_PART (message), ".message");
-	e_mail_part_list_add_part (part_list, part);
-	e_mail_part_unref (part);
+	mail_part = e_mail_part_new (CAMEL_MIME_PART (message), ".message");
+	e_mail_part_list_add_part (part_list, mail_part);
+	e_mail_part_unref (mail_part);
 
 	for (iter = parsers->head; iter; iter = iter->next) {
 		EMailParserExtension *extension;
+		gboolean message_handled;
 
 		if (g_cancellable_is_cancelled (cancellable))
 			break;
@@ -99,24 +100,19 @@ mail_parser_run (EMailParser *parser,
 		if (!extension)
 			continue;
 
-		list_of_parts = e_mail_parser_extension_parse (
+		message_handled = e_mail_parser_extension_parse (
 			extension, parser,
 			CAMEL_MIME_PART (message),
-			part_id, cancellable);
+			part_id, cancellable, &mail_part_queue);
 
-		if (list_of_parts != NULL)
+		if (message_handled)
 			break;
 	}
 
-	while (list_of_parts != NULL) {
-		part = list_of_parts->data;
-		if (part != NULL) {
-			e_mail_part_list_add_part (part_list, part);
-			e_mail_part_unref (part);
-		}
-
-		list_of_parts = g_slist_delete_link (
-			list_of_parts, list_of_parts);
+	while (!g_queue_is_empty (&mail_part_queue)) {
+		mail_part = g_queue_pop_head (&mail_part_queue);
+		e_mail_part_list_add_part (part_list, mail_part);
+		e_mail_part_unref (mail_part);
 	}
 
 	g_string_free (part_id, TRUE);
@@ -428,15 +424,16 @@ e_mail_parser_parse_finish (EMailParser *parser,
 	return g_object_ref (part_list);
 }
 
-GSList *
+gboolean
 e_mail_parser_parse_part (EMailParser *parser,
                           CamelMimePart *part,
                           GString *part_id,
-                          GCancellable *cancellable)
+                          GCancellable *cancellable,
+                          GQueue *out_mail_parts)
 {
 	CamelContentType *ct;
 	gchar *mime_type;
-	GSList *list;
+	gint n_parts_queued = 0;
 
 	ct = camel_mime_part_get_content_type (part);
 	if (!ct) {
@@ -448,32 +445,31 @@ e_mail_parser_parse_part (EMailParser *parser,
 		g_free (tmp);
 	}
 
-	list = e_mail_parser_parse_part_as (
-		parser, part, part_id, mime_type, cancellable);
+	n_parts_queued = e_mail_parser_parse_part_as (
+		parser, part, part_id, mime_type,
+		cancellable, out_mail_parts);
 
 	if (ct) {
 		g_free (mime_type);
 	}
 
-	return list;
+	return n_parts_queued;
 }
 
-GSList *
+gboolean
 e_mail_parser_parse_part_as (EMailParser *parser,
                              CamelMimePart *part,
                              GString *part_id,
                              const gchar *mime_type,
-                             GCancellable *cancellable)
+                             GCancellable *cancellable,
+                             GQueue *out_mail_parts)
 {
 	GQueue *parsers;
 	GList *iter;
 	EMailExtensionRegistry *reg;
 	EMailParserClass *parser_class;
-	GSList *part_list = NULL;
 	gchar *as_mime_type;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return NULL;
+	gboolean mime_part_handled = FALSE;
 
 	if (mime_type)
 		as_mime_type = g_ascii_strdown (mime_type, -1);
@@ -491,9 +487,10 @@ e_mail_parser_parse_part_as (EMailParser *parser,
 	if (as_mime_type)
 		g_free (as_mime_type);
 
-	if (!parsers) {
-		return e_mail_parser_wrap_as_attachment (
-			parser, part, NULL, part_id, cancellable);
+	if (parsers == NULL) {
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, out_mail_parts);
+		return TRUE;
 	}
 
 	for (iter = parsers->head; iter; iter = iter->next) {
@@ -503,19 +500,20 @@ e_mail_parser_parse_part_as (EMailParser *parser,
 		if (!extension)
 			continue;
 
-		part_list = e_mail_parser_extension_parse (
-			extension, parser, part, part_id, cancellable);
+		mime_part_handled = e_mail_parser_extension_parse (
+			extension, parser, part, part_id,
+			cancellable, out_mail_parts);
 
-		if (part_list)
+		if (mime_part_handled)
 			break;
 	}
 
-	return part_list;
+	return mime_part_handled;
 }
 
-GSList *
+void
 e_mail_parser_error (EMailParser *parser,
-                     GCancellable *cancellable,
+                     GQueue *out_mail_parts,
                      const gchar *format,
                      ...)
 {
@@ -525,8 +523,9 @@ e_mail_parser_error (EMailParser *parser,
 	gchar *uri;
 	va_list ap;
 
-	g_return_val_if_fail (E_IS_MAIL_PARSER (parser), NULL);
-	g_return_val_if_fail (format != NULL, NULL);
+	g_return_if_fail (E_IS_MAIL_PARSER (parser));
+	g_return_if_fail (out_mail_parts != NULL);
+	g_return_if_fail (format != NULL);
 
 	va_start (ap, format);
 	errmsg = g_strdup_vprintf (format, ap);
@@ -551,7 +550,7 @@ e_mail_parser_error (EMailParser *parser,
 	g_free (uri);
 	g_object_unref (part);
 
-	return g_slist_append (NULL, mail_part);
+	g_queue_push_tail (out_mail_parts, mail_part);
 }
 
 static void
@@ -581,14 +580,14 @@ load_attachment_idle (EAttachment *attachment)
 	return FALSE;
 }
 
-GSList *
+void
 e_mail_parser_wrap_as_attachment (EMailParser *parser,
                                   CamelMimePart *part,
-                                  GSList *parts,
                                   GString *part_id,
-                                  GCancellable *cancellable)
+                                  GQueue *parts_queue)
 {
 	EMailPartAttachment *empa;
+	EMailPart *first_part;
 	const gchar *snoop_mime_type, *cid;
 	GQueue *extensions;
 	CamelContentType *ct;
@@ -644,7 +643,12 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
 		e_mail_part_is_inline (part, extensions));
 	empa->snoop_mime_type = snoop_mime_type;
 	empa->attachment = e_attachment_new ();
-	empa->attachment_view_part_id = parts ? g_strdup (E_MAIL_PART (parts->data)->id) : NULL;
+
+	first_part = g_queue_peek_head (parts_queue);
+	if (first_part != NULL) {
+		empa->attachment_view_part_id = g_strdup (first_part->id);
+		first_part->is_hidden = TRUE;
+	}
 
 	cid = camel_mime_part_get_content_id (part);
 	if (cid)
@@ -692,13 +696,10 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
 		g_object_unref (fileinfo);
 	}
 
-	if (parts && parts->data) {
-		E_MAIL_PART (parts->data)->is_hidden = TRUE;
-	}
-
 	g_string_truncate (part_id, part_id_len);
 
-	return g_slist_prepend (parts, empa);
+	/* Push to head, not tail. */
+	g_queue_push_head (parts_queue, empa);
 }
 
 CamelSession *
diff --git a/em-format/e-mail-parser.h b/em-format/e-mail-parser.h
index 202e28d..77818b8 100644
--- a/em-format/e-mail-parser.h
+++ b/em-format/e-mail-parser.h
@@ -80,28 +80,29 @@ EMailPartList *	e_mail_parser_parse_finish	(EMailParser *parser,
 						 GAsyncResult *result,
 						 GError **error);
 
-GSList *	e_mail_parser_parse_part	(EMailParser *parser,
+gboolean	e_mail_parser_parse_part	(EMailParser *parser,
 						 CamelMimePart *part,
 						 GString *part_id,
-						 GCancellable *cancellable);
+						 GCancellable *cancellable,
+						 GQueue *out_mail_parts);
 
-GSList *	e_mail_parser_parse_part_as	(EMailParser *parser,
+gboolean	e_mail_parser_parse_part_as	(EMailParser *parser,
 						 CamelMimePart *part,
 						 GString *part_id,
 						 const gchar *mime_type,
-						 GCancellable *cancellable);
-
-GSList *	e_mail_parser_error		(EMailParser *parser,
 						 GCancellable *cancellable,
+						 GQueue *out_mail_parts);
+
+void		e_mail_parser_error		(EMailParser *parser,
+						 GQueue *out_mail_parts,
 						 const gchar *format,
 						 ...) G_GNUC_PRINTF (3, 4);
 
-GSList *	e_mail_parser_wrap_as_attachment
+void		e_mail_parser_wrap_as_attachment
 						(EMailParser *parser,
 						 CamelMimePart *part,
-						 GSList *parts,
 						 GString *part_id,
-						 GCancellable *cancellable);
+						 GQueue *parts_queue);
 
 CamelSession *	e_mail_parser_get_session	(EMailParser *parser);
 
diff --git a/modules/audio-inline/e-mail-parser-audio-inline.c b/modules/audio-inline/e-mail-parser-audio-inline.c
index 5509306..ca87693 100644
--- a/modules/audio-inline/e-mail-parser-audio-inline.c
+++ b/modules/audio-inline/e-mail-parser-audio-inline.c
@@ -101,15 +101,18 @@ mail_part_audio_inline_free (EMailPart *mail_part)
 	}
 }
 
-static GSList *
+static gint
 empe_audio_inline_parse (EMailParserExtension *extension,
                          EMailParser *parser,
                          CamelMimePart *part,
                          GString *part_id,
-                         GCancellable *cancellable)
+                         GCancellable *cancellable,
+                         GQueue *out_mail_queue)
 {
 	EMailPartAudioInline *mail_part;
+	GQueue work_queue = G_QUEUE_INIT;
 	gint len;
+	gint n_parts_added = 0;
 
 	len = part_id->len;
 	g_string_append (part_id, ".org-gnome-audio-inline-button-panel");
@@ -117,16 +120,22 @@ empe_audio_inline_parse (EMailParserExtension *extension,
 	d (printf ("audio inline formatter: format classid %s\n", part_id->str));
 
 	mail_part = (EMailPartAudioInline *) e_mail_part_subclass_new (
-			part, part_id->str, sizeof (EMailPartAudioInline),
-			(GFreeFunc) mail_part_audio_inline_free);
+		part, part_id->str, sizeof (EMailPartAudioInline),
+		(GFreeFunc) mail_part_audio_inline_free);
 	mail_part->parent.mime_type = camel_content_type_simple (
-			camel_mime_part_get_content_type (part));
+		camel_mime_part_get_content_type (part));
 	mail_part->parent.is_attachment = TRUE;
 	g_string_truncate (part_id, len);
 
-	return e_mail_parser_wrap_as_attachment (
-			parser, part, g_slist_append (NULL, mail_part),
-			part_id, cancellable);
+	g_queue_push_tail (&work_queue, mail_part);
+	n_parts_added++;
+
+	e_mail_parser_wrap_as_attachment (
+		parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_queue);
+
+	return TRUE;
 }
 
 static guint32
diff --git a/modules/itip-formatter/e-mail-parser-itip.c b/modules/itip-formatter/e-mail-parser-itip.c
index 56bbd53..5058428 100644
--- a/modules/itip-formatter/e-mail-parser-itip.c
+++ b/modules/itip-formatter/e-mail-parser-itip.c
@@ -180,12 +180,13 @@ bind_itip_view (EMailPart *part,
 
 /*******************************************************************************/
 
-static GSList *
+static gboolean
 empe_itip_parse (EMailParserExtension *extension,
                  EMailParser *parser,
                  CamelMimePart *part,
                  GString *part_id,
-                 GCancellable *cancellable)
+                 GCancellable *cancellable,
+                 GQueue *out_mail_parts)
 {
 	EShell *shell;
 	GSettings *settings;
@@ -195,7 +196,7 @@ empe_itip_parse (EMailParserExtension *extension,
 	GByteArray *byte_array;
 	gint len;
 	const CamelContentDisposition *disposition;
-	GSList *parts;
+	GQueue work_queue = G_QUEUE_INIT;
 
 	len = part_id->len;
 	g_string_append_printf (part_id, ".itip");
@@ -234,18 +235,20 @@ empe_itip_parse (EMailParserExtension *extension,
 
 	g_object_unref (stream);
 
-	parts = g_slist_append (NULL, itip_part);
+	g_queue_push_tail (&work_queue, itip_part);
 
 	disposition = camel_mime_part_get_content_disposition (part);
 	if (disposition &&
 	    (g_strcmp0 (disposition->disposition, "attachment") == 0)) {
-		parts = e_mail_parser_wrap_as_attachment (
-			parser, part, parts, part_id, cancellable);
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
 	}
 
+	e_queue_transfer (&work_queue, out_mail_parts);
+
 	g_string_truncate (part_id, len);
 
-	return parts;
+	return TRUE;
 }
 
 static guint32
diff --git a/modules/prefer-plain/e-mail-parser-prefer-plain.c b/modules/prefer-plain/e-mail-parser-prefer-plain.c
index 66ff321..296369e 100644
--- a/modules/prefer-plain/e-mail-parser-prefer-plain.c
+++ b/modules/prefer-plain/e-mail-parser-prefer-plain.c
@@ -99,18 +99,19 @@ enum {
 	PROP_SHOW_SUPPRESSED
 };
 
-static GSList *
+static void
 make_part_attachment (EMailParser *parser,
                       CamelMimePart *part,
                       GString *part_id,
                       gboolean force_html,
-                      GCancellable *cancellable)
+                      GCancellable *cancellable,
+                      GQueue *out_mail_parts)
 {
-	GSList *parts;
-
 	if (camel_content_type_is (camel_mime_part_get_content_type (part), "text", "html")) {
+		GQueue work_queue = G_QUEUE_INIT;
 		EMailPart *mail_part;
 		gint len;
+
 		/* always show HTML as attachments and not inline */
 		camel_mime_part_set_disposition (part, "attachment");
 
@@ -126,9 +127,12 @@ make_part_attachment (EMailParser *parser,
 		mail_part->mime_type = g_strdup ("text/html");
 		g_string_truncate (part_id, len);
 
-		parts = e_mail_parser_wrap_as_attachment (
-				parser, part, g_slist_append (NULL, mail_part),
-				part_id, cancellable);
+		g_queue_push_tail (&work_queue, mail_part);
+
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
+
+		e_queue_transfer (&work_queue, out_mail_parts);
 
 	} else if (force_html && CAMEL_IS_MIME_MESSAGE (part)) {
 		/* message was asked to be formatted as text/html;
@@ -137,52 +141,51 @@ make_part_attachment (EMailParser *parser,
 		CamelDataWrapper *content;
 
 		content = camel_medium_get_content (CAMEL_MEDIUM (part));
-		g_return_val_if_fail (content != NULL, NULL);
+		g_return_if_fail (content != NULL);
 
 		new_part = camel_mime_part_new ();
 		camel_medium_set_content (CAMEL_MEDIUM (new_part), content);
 
-		parts = e_mail_parser_parse_part (
-				parser, new_part, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, new_part, part_id,
+			cancellable, out_mail_parts);
 
 		g_object_unref (new_part);
 	} else {
-		parts = e_mail_parser_parse_part (
-				parser, part, part_id, cancellable);
+		e_mail_parser_parse_part (
+			parser, part, part_id, cancellable, out_mail_parts);
 	}
-
-	return parts;
 }
 
 static void
-hide_parts (GSList *parts)
+hide_parts (GQueue *work_queue)
 {
-	GSList *iter;
+	GList *head, *link;
 
-	for (iter = parts; iter; iter = g_slist_next (iter)) {
-		EMailPart *p = iter->data;
+	head = g_queue_peek_head_link (work_queue);
 
-		if (!p)
-			continue;
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		EMailPart *mail_part = link->data;
 
-		p->is_hidden = TRUE;
+		mail_part->is_hidden = TRUE;
 	}
 }
 
-static GSList *
+static gboolean
 empe_prefer_plain_parse (EMailParserExtension *extension,
                          EMailParser *parser,
                          CamelMimePart *part,
                          GString *part_id,
-                         GCancellable *cancellable)
+                         GCancellable *cancellable,
+                         GQueue *out_mail_parts)
 {
 	EMailParserPreferPlain *emp_pp;
 	CamelMultipart *mp;
 	gint i, nparts, partidlen;
-	GSList *parts;
 	CamelContentType *ct;
 	gboolean has_calendar = FALSE;
-	GSList *plain_text_parts = NULL;
+	GQueue plain_text_parts = G_QUEUE_INIT;
+	GQueue work_queue = G_QUEUE_INIT;
 
 	emp_pp = (EMailParserPreferPlain *) extension;
 
@@ -194,36 +197,35 @@ empe_prefer_plain_parse (EMailParserExtension *extension,
 
 		/* Prevent recursion, fall back to next (real text/html) parser */
 		if (strstr (part_id->str, ".alternative-prefer-plain.") != NULL)
-			return NULL;
+			return FALSE;
 
 		/* Not enforcing text/plain, so use real parser */
 		if (emp_pp->mode != ONLY_PLAIN)
-			return NULL;
+			return FALSE;
 
 		/* Enforcing text/plain, but got only HTML part, so add it
 		 * as attachment, to not show empty message preview, which
 		 * is confusing. */
-		return make_part_attachment (
-			parser, part, part_id,
-			FALSE, cancellable);
+		make_part_attachment (
+			parser, part, part_id, FALSE,
+			cancellable, out_mail_parts);
+
+		return TRUE;
 	}
 
-	parts = NULL;
 	partidlen = part_id->len;
 
 	mp = (CamelMultipart *) camel_medium_get_content (CAMEL_MEDIUM (part));
 
-	if (!CAMEL_IS_MULTIPART (mp)) {
+	if (!CAMEL_IS_MULTIPART (mp))
 		return e_mail_parser_parse_part_as (
 			parser, part, part_id,
-			"application/vnd.evolution.source", cancellable);
-	}
+			"application/vnd.evolution.source",
+			cancellable, out_mail_parts);
 
 	nparts = camel_multipart_get_number (mp);
 	for (i = 0; i < nparts; i++) {
-
 		CamelMimePart *sp;
-		GSList *sparts = NULL;
 
 		sp = camel_multipart_get_part (mp, i);
 		ct = camel_mime_part_get_content_type (sp);
@@ -232,61 +234,52 @@ empe_prefer_plain_parse (EMailParserExtension *extension,
 		g_string_append_printf (part_id, ".alternative-prefer-plain.%d", i);
 
 		if (camel_content_type_is (ct, "text", "html")) {
-
 			if (emp_pp->mode != PREFER_HTML) {
 				if (emp_pp->show_suppressed) {
-					sparts = make_part_attachment (
-						parser, sp, part_id,
-						FALSE, cancellable);
+					make_part_attachment (
+						parser, sp, part_id, FALSE,
+						cancellable, &work_queue);
 				}
 			} else {
-				sparts = e_mail_parser_parse_part (
-					parser, sp, part_id, cancellable);
+				e_mail_parser_parse_part (
+					parser, sp, part_id,
+					cancellable, &work_queue);
 			}
 
-			parts = g_slist_concat (parts, sparts);
-			continue;
-		}
-
-		if (camel_content_type_is (ct, "text", "plain")) {
-
-			sparts = e_mail_parser_parse_part (
-					parser, sp, part_id, cancellable);
-
-			plain_text_parts = g_slist_concat (plain_text_parts, sparts);
-			continue;
-		}
+		} else if (camel_content_type_is (ct, "text", "plain")) {
+			e_mail_parser_parse_part (
+				parser, sp, part_id,
+				cancellable, &plain_text_parts);
 
 		/* Always show calendar part! */
-		if (camel_content_type_is (ct, "text", "calendar") ||
+		} else if (camel_content_type_is (ct, "text", "calendar") ||
 		    camel_content_type_is (ct, "text", "x-calendar")) {
 
-			/* Hide everything else, displaying native calendar part only */
-			hide_parts (parts);
+			/* Hide everything else, displaying
+			 * native calendar part only. */
+			hide_parts (&work_queue);
 
-			sparts = e_mail_parser_parse_part (
-					parser, sp, part_id, cancellable);
+			e_mail_parser_parse_part (
+				parser, sp, part_id, cancellable, &work_queue);
 
-			parts = g_slist_concat (parts, sparts);
 			has_calendar = TRUE;
-			continue;
-		}
 
 		/* Multiparts can represent a text/html with inline images or so */
-		if (camel_content_type_is (ct, "multipart", "*")) {
-			GSList *iter;
+		} else if (camel_content_type_is (ct, "multipart", "*")) {
+			GQueue inner_queue = G_QUEUE_INIT;
+			GList *head, *link;
 			gboolean has_html = FALSE;
 
-			sparts = e_mail_parser_parse_part (
-					parser, sp, part_id, cancellable);
+			e_mail_parser_parse_part (
+				parser, sp, part_id, cancellable, &inner_queue);
+
+			head = g_queue_peek_head_link (&inner_queue);
 
 			/* Check whether the multipart contains a text/html part */
-			for (iter = sparts; iter; iter = g_slist_next (iter)) {
-				EMailPart *p = iter->data;
-				if (!p)
-					continue;
+			for (link = head; link != NULL; link = g_list_next (link)) {
+				EMailPart *mail_part = link->data;
 
-				if (strstr (p->id, ".text_html") != NULL) {
+				if (strstr (mail_part->id, ".text_html") != NULL) {
 					has_html = TRUE;
 					break;
 				}
@@ -294,41 +287,41 @@ empe_prefer_plain_parse (EMailParserExtension *extension,
 
 			if (has_html && (emp_pp->mode != PREFER_HTML)) {
 				if (emp_pp->show_suppressed) {
-					sparts =  e_mail_parser_wrap_as_attachment (
-							parser, sp, sparts, part_id,
-							cancellable);
+					e_mail_parser_wrap_as_attachment (
+						parser, sp, part_id,
+						&inner_queue);
 				} else {
-					hide_parts (sparts);
+					hide_parts (&inner_queue);
 				}
 			}
 
-			parts = g_slist_concat (parts, sparts);
-			continue;
-		}
+			e_queue_transfer (&inner_queue, &work_queue);
 
 		/* Parse everything else as an attachment */
-		sparts = e_mail_parser_parse_part (
-				parser, sp, part_id, cancellable);
-		parts = g_slist_concat (
-				parts,
-				e_mail_parser_wrap_as_attachment (
-					parser, sp, sparts, part_id,
-					cancellable));
+		} else {
+			GQueue inner_queue = G_QUEUE_INIT;
+
+			e_mail_parser_parse_part (
+				parser, sp, part_id,
+				cancellable, &inner_queue);
+			e_mail_parser_wrap_as_attachment (
+				parser, sp, part_id, &inner_queue);
+
+			e_queue_transfer (&inner_queue, &work_queue);
+		}
 	}
 
 	/* Don't hide the plain text if there's nothing else to display */
-	if (has_calendar || (nparts > 1 && emp_pp->mode == PREFER_HTML)) {
-		hide_parts (plain_text_parts);
-	}
+	if (has_calendar || (nparts > 1 && emp_pp->mode == PREFER_HTML))
+		hide_parts (&plain_text_parts);
 
-	if (plain_text_parts) {
-		/* plain_text parts should be always first */
-		parts = g_slist_concat (plain_text_parts, parts);
-	}
+	/* plain_text parts should be always first */
+	e_queue_transfer (&plain_text_parts, out_mail_parts);
+	e_queue_transfer (&work_queue, out_mail_parts);
 
 	g_string_truncate (part_id, partidlen);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/modules/text-highlight/e-mail-parser-text-highlight.c b/modules/text-highlight/e-mail-parser-text-highlight.c
index 69aa1cc..eb56162 100644
--- a/modules/text-highlight/e-mail-parser-text-highlight.c
+++ b/modules/text-highlight/e-mail-parser-text-highlight.c
@@ -58,21 +58,20 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (
 		E_TYPE_MAIL_PARSER_EXTENSION,
 		e_mail_parser_parser_extension_interface_init));
 
-static GSList *
+static gboolean
 empe_text_highlight_parse (EMailParserExtension *extension,
                            EMailParser *parser,
                            CamelMimePart *part,
                            GString *part_id,
-                           GCancellable *cancellable)
+                           GCancellable *cancellable,
+                           GQueue *out_mail_parts)
 {
-	GSList *parts;
-	gint len;
 	CamelContentType *ct;
+	gint len;
 
 	/* Prevent recursion */
-	if (strstr (part_id->str, ".text-highlight") != NULL) {
-		return NULL;
-	}
+	if (strstr (part_id->str, ".text-highlight") != NULL)
+		return FALSE;
 
 	/* Don't parse text/html if it's not an attachment */
 	ct = camel_mime_part_get_content_type (part);
@@ -80,9 +79,8 @@ empe_text_highlight_parse (EMailParserExtension *extension,
 		const CamelContentDisposition *disp;
 
 		disp = camel_mime_part_get_content_disposition (part);
-		if (!disp || (g_strcmp0 (disp->disposition, "attachment") != 0)) {
-			return NULL;
-		}
+		if (!disp || (g_strcmp0 (disp->disposition, "attachment") != 0))
+			return FALSE;
 	}
 
 	len = part_id->len;
@@ -90,12 +88,14 @@ empe_text_highlight_parse (EMailParserExtension *extension,
 
 	/* All source codes and scripts are in general plain texts,
 	 * so let text/plain parser handle it. */
-	parts = e_mail_parser_parse_part_as (
-			parser, part, part_id, "text/plain", cancellable);
+
+	e_mail_parser_parse_part_as (
+		parser, part, part_id, "text/plain",
+		cancellable, out_mail_parts);
 
 	g_string_truncate (part_id, len);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/modules/tnef-attachment/e-mail-parser-tnef-attachment.c b/modules/tnef-attachment/e-mail-parser-tnef-attachment.c
index 3de54e6..a0342aa 100644
--- a/modules/tnef-attachment/e-mail-parser-tnef-attachment.c
+++ b/modules/tnef-attachment/e-mail-parser-tnef-attachment.c
@@ -114,12 +114,13 @@ sanitize_filename (const gchar *filename)
 	}
 }
 
-static GSList *
+static gboolean
 empe_tnef_attachment_parse (EMailParserExtension *extension,
                             EMailParser *parser,
                             CamelMimePart *part,
                             GString *part_id,
-                            GCancellable *cancellable)
+                            GCancellable *cancellable,
+                            GQueue *out_mail_parts)
 {
 	gchar *tmpdir, *name;
 	CamelStream *out;
@@ -130,30 +131,30 @@ empe_tnef_attachment_parse (EMailParserExtension *extension,
 	CamelDataWrapper *content;
 	gint len;
 	TNEFStruct tnef;
-	GSList *parts;
+	GQueue work_queue = G_QUEUE_INIT;
 
 	tmpdir = e_mkdtemp ("tnef-attachment-XXXXXX");
 	if (tmpdir == NULL)
-		return NULL;
+		return FALSE;
 
 	name = g_build_filename (tmpdir, ".evo-attachment.tnef", NULL);
 
 	out = camel_stream_fs_new_with_name (name, O_RDWR | O_CREAT, 0666, NULL);
 	if (out == NULL) {
 	    g_free (name);
-	    return NULL;
+	    return FALSE;
 	}
 	content = camel_medium_get_content ((CamelMedium *) part);
 	if (content == NULL) {
 		g_free (name);
 		g_object_unref (out);
-		return NULL;
+		return FALSE;
 	}
 	if (camel_data_wrapper_decode_to_stream_sync (content, out, NULL, NULL) == -1
 	    || camel_stream_close (out, NULL, NULL) == -1) {
 		g_object_unref (out);
 		g_free (name);
-		return NULL;
+		return FALSE;
 	}
 	g_object_unref (out);
 
@@ -172,7 +173,7 @@ empe_tnef_attachment_parse (EMailParserExtension *extension,
 	if (dir == NULL) {
 	    g_object_unref (out);
 	    g_free (name);
-	    return NULL;
+	    return FALSE;
 	}
 
 	mainpart = camel_mime_part_new ();
@@ -226,7 +227,6 @@ empe_tnef_attachment_parse (EMailParserExtension *extension,
 	len = part_id->len;
 	g_string_append_printf (part_id, ".tnef");
 
-	parts = NULL;
 	if (camel_multipart_get_number (mp) > 0) {
 
 		CamelMimePart *part = camel_mime_part_new ();
@@ -235,18 +235,20 @@ empe_tnef_attachment_parse (EMailParserExtension *extension,
 			(CamelMedium *) part,
 			CAMEL_DATA_WRAPPER (mp));
 
-		parts = e_mail_parser_parse_part_as (
-			parser, part, part_id,
-			"multipart/mixed", cancellable);
+		e_mail_parser_parse_part_as (
+			parser, part, part_id, "multipart/mixed",
+			cancellable, &work_queue);
 
 		g_object_unref (part);
 	}
 
 	g_string_truncate (part_id, len);
 
-	if (parts)
-		parts = e_mail_parser_wrap_as_attachment (
-			parser, part, parts, part_id, cancellable);
+	if (!g_queue_is_empty (&work_queue))
+		e_mail_parser_wrap_as_attachment (
+			parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
 
 	g_object_unref (mp);
 	g_object_unref (mainpart);
@@ -254,7 +256,7 @@ empe_tnef_attachment_parse (EMailParserExtension *extension,
 	g_free (name);
 	g_free (tmpdir);
 
-	return parts;
+	return TRUE;
 }
 
 static const gchar **
diff --git a/modules/vcard-inline/e-mail-parser-vcard-inline.c b/modules/vcard-inline/e-mail-parser-vcard-inline.c
index 319775b..84f4f2f 100644
--- a/modules/vcard-inline/e-mail-parser-vcard-inline.c
+++ b/modules/vcard-inline/e-mail-parser-vcard-inline.c
@@ -328,39 +328,46 @@ decode_vcard (EMailPartVCardInline *vcard_part,
 	g_object_unref (stream);
 }
 
-static GSList *
+static gboolean
 empe_vcard_inline_parse (EMailParserExtension *extension,
                          EMailParser *parser,
                          CamelMimePart *part,
                          GString *part_id,
-                         GCancellable *cancellable)
+                         GCancellable *cancellable,
+                         GQueue *out_mail_parts)
 {
 	EMailPartVCardInline *vcard_part;
+	GQueue work_queue = G_QUEUE_INIT;
 	gint len;
 
 	len = part_id->len;
 	g_string_append (part_id, ".org-gnome-vcard-inline-display");
 
 	vcard_part = (EMailPartVCardInline *) e_mail_part_subclass_new (
-			part, part_id->str, sizeof (EMailPartVCardInline),
-			(GFreeFunc) mail_part_vcard_inline_free);
+		part, part_id->str, sizeof (EMailPartVCardInline),
+		(GFreeFunc) mail_part_vcard_inline_free);
 	vcard_part->parent.mime_type = camel_content_type_simple (
-					camel_mime_part_get_content_type (part));
+		camel_mime_part_get_content_type (part));
 	vcard_part->parent.bind_func = (EMailPartDOMBindFunc) bind_dom;
 	vcard_part->parent.is_attachment = TRUE;
 	vcard_part->formatter = g_object_new (
-					EAB_TYPE_CONTACT_FORMATTER,
-				       "display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT,
-				       "render-maps", FALSE, NULL);
+		EAB_TYPE_CONTACT_FORMATTER,
+		"display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT,
+		"render-maps", FALSE, NULL);
 	g_object_ref (part);
 
 	decode_vcard (vcard_part, part);
 
 	g_string_truncate (part_id, len);
 
-	return e_mail_parser_wrap_as_attachment (
-			parser, part, g_slist_append (NULL, vcard_part),
-			part_id, cancellable);
+	g_queue_push_tail (&work_queue, vcard_part);
+
+	e_mail_parser_wrap_as_attachment (
+		parser, part, part_id, &work_queue);
+
+	e_queue_transfer (&work_queue, out_mail_parts);
+
+	return TRUE;
 }
 
 static guint32



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