[evolution/webkit: 136/171] Convert EMFormatPURI to a thread-safe EMPart object



commit 5eda7074dcbf0f2d8169644f8b50bda5f2bc74d0
Author: Dan VrÃtil <dvratil redhat com>
Date:   Tue Feb 7 17:34:40 2012 +0100

    Convert EMFormatPURI to a thread-safe EMPart object
    
    EMFormatPURI structures are now represented by a EMPart objects which
    wrap all the PURI's properties as private and make them accessible only
    via em_part_{get,set}_* methods which take care of locking. Also the
    EMPart is a subclass of GObject, thus it's possible to use reference
    counting to ensure life-span of the object.
    
    Unfortunately it's now a little bit more complicated to create subclasses,
    because it is necessary to define a whole new class.
    
    TODO:
     - convert image-inline, itip-formatter, mail-to-task, tnef-attachments
     	and vcard-inline plugins
     - move EMPart's private mutex to EMPartClass so that subclasses don't have
     	to have their own mutex.
    
    Note: won't compile due to EMailDisplay not being ported

 em-format/Makefile.am                |    2 +
 em-format/em-format-quote.c          |  125 ++++---
 em-format/em-format.c                |  249 +++++-------
 em-format/em-format.h                |   75 ++---
 em-format/em-part.c                  |  678 +++++++++++++++++++++++++++++++
 em-format/em-part.h                  |  140 +++++++
 mail/Makefile.am                     |    2 +
 mail/e-mail-request.c                |   78 +++--
 mail/em-format-html-display-parts.c  |  722 ++++++++++++++++++++++++++++++++++
 mail/em-format-html-display-parts.h  |  242 ++++++++++++
 mail/em-format-html-display.c        |  395 ++++++++++---------
 mail/em-format-html-display.h        |   46 ---
 mail/em-format-html-print.c          |  190 ++++++---
 mail/em-format-html.c                |  295 +++++++++------
 mail/em-format-html.h                |    1 -
 mail/em-utils.c                      |   12 +-
 plugins/audio-inline/Makefile.am     |    4 +-
 plugins/audio-inline/audio-inline.c  |  232 +++++------
 plugins/audio-inline/em-part-audio.c |  346 ++++++++++++++++
 plugins/audio-inline/em-part-audio.h |  112 ++++++
 widgets/misc/e-web-view.c            |  185 +---------
 widgets/misc/e-web-view.h            |    4 -
 22 files changed, 3114 insertions(+), 1021 deletions(-)
---
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 392a195..186f300 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -6,6 +6,7 @@ emformatinclude_HEADERS =				\
 	em-format.h					\
 	em-format-quote.h				\
 	em-inline-filter.h				\
+	em-part.h					\
 	em-stripsig-filter.h
 
 libemformat_la_CPPFLAGS =				\
@@ -21,6 +22,7 @@ libemformat_la_SOURCES =				\
 	em-format.c					\
 	em-format-quote.c				\
 	em-inline-filter.c				\
+	em-part.c					\
 	em-stripsig-filter.c
 
 libemformat_la_LDFLAGS = -avoid-version $(NO_UNDEFINED)
diff --git a/em-format/em-format-quote.c b/em-format/em-format-quote.c
index 23994f2..d107757 100644
--- a/em-format/em-format-quote.c
+++ b/em-format/em-format-quote.c
@@ -32,6 +32,7 @@
 #include "em-inline-filter.h"
 #include "em-stripsig-filter.h"
 #include "em-format-quote.h"
+#include "em-part.h"
 
 #define EM_FORMAT_QUOTE_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -53,9 +54,9 @@ static void emfq_parse_text_enriched    (EMFormat *emf, CamelMimePart *part, GSt
 static void emfq_parse_text_html        (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 static void emfq_parse_attachment       (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 
-static void emfq_write_text_plain	(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void emfq_write_text_enriched	(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void emfq_write_text_html	(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emfq_write_text_plain	(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emfq_write_text_enriched	(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emfq_write_text_html	(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
 
 static gpointer parent_class;
 
@@ -386,8 +387,8 @@ emfq_parse_text_plain (EMFormat* emf,
                        EMFormatParserInfo* info,
                        GCancellable* cancellable)
 {
-        EMFormatPURI *puri;
-		CamelMimePart *mp;
+        EMPart *emp;
+	CamelMimePart *mp;
         gint len;
 
         len = part_id->len;
@@ -403,10 +404,9 @@ emfq_parse_text_plain (EMFormat* emf,
 			g_object_unref (mp);
 		}
 
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-        puri->write_func = emfq_write_text_plain;
-        puri->mime_type = g_strdup ("text/html");
-        em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, emfq_write_text_plain);
+        em_part_set_mime_type (emp, "text/html");
+	em_format_add_part_object (emf, emp);
 
         g_string_truncate (part_id, len);
 }
@@ -418,16 +418,15 @@ emfq_parse_text_html (EMFormat* emf,
                       EMFormatParserInfo* info,
                       GCancellable* cancellable)
 {
-        EMFormatPURI *puri;
+        EMPart *emp;
         gint len;
 
         len = part_id->len;
         g_string_append (part_id, ".text_html");
 
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-        puri->write_func = emfq_write_text_html;
-        puri->mime_type = g_strdup ("text/html");
-        em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, emfq_write_text_html);
+        em_part_set_mime_type (emp, "text/html");
+	em_format_add_part_object (emf, emp);
 
         g_string_truncate (part_id, len);
 }
@@ -439,16 +438,15 @@ emfq_parse_text_enriched (EMFormat* emf,
                           EMFormatParserInfo* info,
                           GCancellable* cancellable)
 {
-        EMFormatPURI *puri;
+        EMPart *emp;
         gint len;
 
         len = part_id->len;
         g_string_append (part_id, ".text_enriched");
 
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-        puri->write_func = emfq_write_text_enriched;
-        puri->mime_type = g_strdup ("text/html");
-        em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, emfq_write_text_enriched);
+	em_part_set_mime_type (emp, "text/html");
+	em_format_add_part_object (emf, emp);
 
         g_string_truncate (part_id, len);
 }
@@ -460,17 +458,16 @@ emfq_parse_attachment (EMFormat* emf,
                        EMFormatParserInfo* info,
                        GCancellable* cancellable)
 {
-        EMFormatPURI *puri;
+        EMPart *emp;
         gint len;
 
         len = part_id->len;
         g_string_append (part_id, ".attachment");
 
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-        puri->write_func = emfq_write_text_html;
-        puri->mime_type = g_strdup ("text/html");
-        puri->is_attachment = TRUE;
-        em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, emfq_write_text_html);
+        em_part_set_mime_type (emp, "text/html");
+        em_part_set_is_attachment (emp, TRUE);
+        em_format_add_part_object (emf, emp);
 
         g_string_truncate (part_id, len);
 }
@@ -483,7 +480,7 @@ emfq_parse_attachment (EMFormat* emf,
 
 static void
 emfq_write_attachment (EMFormat *emf,
-		       EMFormatPURI *puri,
+		       EMPart *emp,
                        CamelStream *stream,
                        EMFormatWriterInfo *info,
                        GCancellable *cancellable)
@@ -492,9 +489,13 @@ emfq_write_attachment (EMFormat *emf,
 	const EMFormatHandler *handler;
 	gchar *text, *html;
 	CamelContentType *ct;
+	CamelMimePart *part;
 	const gchar *mime_type;
+	gchar *uri;
 
-	ct = camel_mime_part_get_content_type (puri->part);
+	part = em_part_get_mime_part (emp);
+	uri = em_part_get_uri (emp);
+	ct = camel_mime_part_get_content_type (part);
 	if (ct) {
 		mime_type = camel_content_type_simple (ct);
 		camel_content_type_unref (ct);
@@ -504,15 +505,18 @@ emfq_write_attachment (EMFormat *emf,
 
 	handler = em_format_find_handler (emf, mime_type);
 
-	if (!em_format_is_inline (emf, puri->uri, puri->part, handler))
+	if (!em_format_is_inline (emf, uri, part, handler)) {
+		g_free (uri);
+		g_object_unref (part);
 		return;
+	}
 
 	camel_stream_write_string (
 		stream, "<table border=1 cellspacing=0 cellpadding=0>"
 		"<tr><td><font size=-1>\n", cancellable, NULL);
 
 	/* output some info about it */
-	text = em_format_describe_part (puri->part, mime_type);
+	text = em_format_describe_part (part, mime_type);
 	html = camel_text_to_html (
 		text, emfq->priv->text_html_flags &
 		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
@@ -524,7 +528,10 @@ emfq_write_attachment (EMFormat *emf,
 		stream, "</font></td></tr></table>", cancellable, NULL);
 
 	if (handler && handler->write_func)
-		handler->write_func (emf, puri, stream, info, cancellable);
+		handler->write_func (emf, emp, stream, info, cancellable);
+
+	g_object_unref (part);
+	g_free (uri);
 }
 
 static void
@@ -627,7 +634,7 @@ em_format_quote_write (EMFormatQuote* emfq,
 		camel_stream_write_string (
 			stream, "<br>\n", cancellable, NULL);
 	g_object_unref (settings);
-       
+
         if (emfq->priv->credits && *emfq->priv->credits) {
                 gchar *credits = g_strdup_printf ("%s<br/>", emfq->priv->credits);
                 camel_stream_write_string (stream, credits, cancellable, NULL);
@@ -643,21 +650,26 @@ em_format_quote_write (EMFormatQuote* emfq,
                         "<blockquote type=cite>\n", cancellable, NULL);
 
         for (iter = emf->mail_part_list; iter; iter = iter->next) {
-                EMFormatPURI *puri = iter->data;
-
-                if (puri->is_attachment || !puri->write_func)
+                EMPart *emp = iter->data;
+		EMPartObjectWriteFunc write_func;
+		
+		write_func = em_part_get_write_func (emp);
+		if (em_part_get_is_attachment (emp) || !write_func)
                         continue;
 
-                puri = iter->data;
-
-                if (emfq->priv->flags & EM_FORMAT_QUOTE_HEADERS) {
+		if (emfq->priv->flags & EM_FORMAT_QUOTE_HEADERS) {
                         GString *buffer = g_string_new ("");
-                        emfq_format_headers (emfq, buffer, (CamelMedium *) puri->part);
+			CamelMimePart *part;
+
+			part = em_part_get_mime_part (emp);
+                        emfq_format_headers (emfq, buffer, (CamelMedium *) part);
                         camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
                         g_string_free (buffer, TRUE);
+			g_object_unref (part);
                 }
 
-                puri->write_func (emf, puri, stream, &info, cancellable);
+                em_part_write (emp, stream, &info, cancellable);
         }
 
         if (emfq->priv->flags & EM_FORMAT_QUOTE_CITE)
@@ -669,7 +681,7 @@ em_format_quote_write (EMFormatQuote* emfq,
 
 static void
 emfq_write_text_plain (EMFormat *emf,
-		       EMFormatPURI *puri,
+		       EMPart *emp,
 		       CamelStream *stream,
 		       EMFormatWriterInfo *info,
 		       GCancellable *cancellable)
@@ -679,16 +691,16 @@ emfq_write_text_plain (EMFormat *emf,
 	CamelMimeFilter *html_filter;
 	CamelMimeFilter *sig_strip;
 	CamelContentType *type;
+	CamelMimePart *part;
 	const gchar *format;
 	guint32 rgb = 0x737373, flags;
 
-	if (!puri->part)
-		return;
-
 	flags = emfq->priv->text_html_flags;
 
+	part = em_part_get_mime_part (emp);
+
 	/* Check for RFC 2646 flowed text. */
-	type = camel_mime_part_get_content_type (puri->part);
+	type = camel_mime_part_get_content_type (part);
 	if (camel_content_type_is(type, "text", "plain")
 	    && (format = camel_content_type_param(type, "format"))
 	    && !g_ascii_strcasecmp(format, "flowed"))
@@ -710,15 +722,17 @@ emfq_write_text_plain (EMFormat *emf,
 
 	em_format_format_text (
 		EM_FORMAT (emfq), filtered_stream,
-		CAMEL_DATA_WRAPPER (puri->part), cancellable);
+		CAMEL_DATA_WRAPPER (part), cancellable);
 
 	camel_stream_flush (filtered_stream, cancellable, NULL);
 	g_object_unref (filtered_stream);
+
+	g_object_unref (part);
 }
 
 static void
 emfq_write_text_enriched (EMFormat *emf,
-			  EMFormatPURI *puri,
+			  EMPart *emp,
                     	  CamelStream *stream,
                     	  EMFormatWriterInfo *info,
                     	  GCancellable *cancellable)
@@ -727,9 +741,12 @@ emfq_write_text_enriched (EMFormat *emf,
 	CamelMimeFilter *enriched;
 	guint32 flags = 0;
 	CamelContentType *ct;
+	CamelMimePart *part;
 	const gchar *mime_type = NULL;
 
-	ct = camel_mime_part_get_content_type (puri->part);
+	part = em_part_get_mime_part (emp);
+
+	ct = camel_mime_part_get_content_type (part);
 	if (ct) {
 		mime_type = camel_content_type_simple (ct);
 		camel_content_type_unref (ct);
@@ -754,21 +771,25 @@ emfq_write_text_enriched (EMFormat *emf,
 
 	camel_stream_write_string (stream, "<br><hr><br>", cancellable, NULL);
 	em_format_format_text (
-		emf, filtered_stream, CAMEL_DATA_WRAPPER (puri->part), cancellable);
+		emf, filtered_stream, CAMEL_DATA_WRAPPER (part), cancellable);
 	camel_stream_flush (filtered_stream, cancellable, NULL);
 	g_object_unref (filtered_stream);
+
+	g_object_unref (part);
 }
 
 static void
 emfq_write_text_html (EMFormat *emf,
-		      EMFormatPURI *puri,
+		      EMPart *emp,
 	              CamelStream *stream,
 	              EMFormatWriterInfo *info,
 	              GCancellable *cancellable)
 {
 	EMFormatQuotePrivate *priv;
+	CamelMimePart *part;
 
 	priv = EM_FORMAT_QUOTE_GET_PRIVATE (emf);
+	part = em_part_get_mime_part (emp);
 
 	camel_stream_write_string (
 		stream, "\n<!-- text/html -->\n", cancellable, NULL);
@@ -786,14 +807,16 @@ emfq_write_text_html (EMFormat *emf,
 
 		em_format_format_text (
 			emf, filtered_stream,
-			(CamelDataWrapper *) puri->part, cancellable);
+			(CamelDataWrapper *) part, cancellable);
 		camel_stream_flush (filtered_stream, cancellable, NULL);
 		g_object_unref (filtered_stream);
 	} else {
 		em_format_format_text (
 			emf, stream,
-			(CamelDataWrapper *) puri->part, cancellable);
+			(CamelDataWrapper *) part, cancellable);
 	}
+
+	g_object_unref (part);
 }
 
 /****************************************************************************/
diff --git a/em-format/em-format.c b/em-format/em-format.c
index a7c2935..caf0cdb 100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@ -92,9 +92,9 @@ static void emf_parse_post_headers		(EMFormat *emf, CamelMimePart *part, GString
 static void emf_parse_source			(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 
 /* WRITERS */
-static void emf_write_text			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void emf_write_source			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void emf_write_error			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emf_write_text			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emf_write_source			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void emf_write_error			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
 
 /**************************************************************************/
 
@@ -636,7 +636,7 @@ emf_parse_multipart_signed (EMFormat *emf,
 					emf, "%s",
 					local_error->message);
 			g_clear_error (&local_error);
-			emf_parse_multipart_mixed (emf, part, part_id,info,  cancellable);
+			emf_parse_multipart_mixed (emf, part, part_id, info, cancellable);
 		} else {
 			gint i, nparts, len = part_id->len;
 			gboolean secured;
@@ -792,7 +792,7 @@ emf_parse_message_deliverystatus (EMFormat *emf,
                             	  EMFormatParserInfo *info,
                             	  GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	gint len;
 
 	if (g_cancellable_is_cancelled (cancellable))
@@ -801,15 +801,14 @@ emf_parse_message_deliverystatus (EMFormat *emf,
 	len = part_id->len;
 	g_string_append (part_id, ".deliverystatus");
 
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = emf_write_text;
-	puri->mime_type = g_strdup ("text/html");
-	puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-	puri->validity_type = info->validity_type;
+        emp = em_part_new (emf, part, part_id->str, emf_write_text);
+        em_part_set_mime_type (emp, "text/html");
+        em_part_set_validity (emp, info->validity);
+	em_part_set_validity_type (emp, info->validity_type);
 
 	g_string_truncate (part_id, len);
 
-	em_format_add_puri (emf, puri);
+	em_format_add_part_object (emf, emp);
 }
 
 static void
@@ -1044,16 +1043,15 @@ emf_parse_headers (EMFormat *emf,
 		   EMFormatParserInfo *info,
 		   GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	gint len;
 
 	len = part_id->len;
 	g_string_append (part_id, ".headers");
 
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = info->handler->write_func;
-	puri->mime_type = g_strdup ("text/html");
-	em_format_add_puri (emf, puri);
+        emp = em_part_new (emf, part, part_id->str, info->handler->write_func);
+	em_part_set_mime_type (emp, "text/html");
+        em_format_add_part_object (emf, emp);
 
 	g_string_truncate (part_id, len);
 }
@@ -1078,7 +1076,7 @@ emf_parse_source (EMFormat *emf,
 		  EMFormatParserInfo *info,
 		  GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	gint len;
 
 	if (g_cancellable_is_cancelled (cancellable))
@@ -1087,19 +1085,18 @@ emf_parse_source (EMFormat *emf,
 	len = part_id->len;
 	g_string_append (part_id, ".source");
 
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = info->handler->write_func;
-	puri->mime_type = g_strdup ("text/html");
-	g_string_truncate (part_id, len);
+        emp = em_part_new (emf, part, part_id->str, info->handler->write_func);
+	em_part_set_mime_type (emp, "text/html");
+        em_format_add_part_object (emf, emp);
 
-	em_format_add_puri (emf, puri);
+        g_string_truncate (part_id, len);
 }
 
 /**************************************************************************/
 
 void
 em_format_empty_writer (EMFormat *emf,
-			EMFormatPURI *puri,
+			EMPart *emp,
 			CamelStream *stream,
 			EMFormatWriterInfo *info,
 			GCancellable *cancellable)
@@ -1109,48 +1106,62 @@ em_format_empty_writer (EMFormat *emf,
 
 static void
 emf_write_error (EMFormat* emf,
-		 EMFormatPURI* puri,
+		 EMPart *emp,
 		 CamelStream* stream,
 		 EMFormatWriterInfo* info,
 		 GCancellable* cancellable)
 {
-	camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) puri->part,
+        CamelMimePart *part;
+
+        part = em_part_get_mime_part (emp);
+	camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) part,
 		stream, cancellable, NULL);
+
+        g_object_unref (part);
 }
 
 static void
 emf_write_text (EMFormat *emf,
-		EMFormatPURI *puri,
+		EMPart *emp,
 		CamelStream *stream,
 		EMFormatWriterInfo *info,
 		GCancellable *cancellable)
 {
 	CamelContentType *ct;
+        CamelMimePart *part;
 
-	ct = camel_mime_part_get_content_type (puri->part);
+        part = em_part_get_mime_part (emp);
+	ct = camel_mime_part_get_content_type (part);
 	if (!camel_content_type_is (ct, "text", "plain")) {
 		camel_stream_write_string (stream, _("Cannot proccess non-text mime/part"),
 			cancellable, NULL);
+
+                g_object_unref (part);
 		return;
 	}
-
-	camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) puri->part,
+	
+	camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) part,
 		stream, cancellable, NULL);
+
+        g_object_unref (part);
 }
 
 static void
 emf_write_source (EMFormat *emf,
-		  EMFormatPURI *puri,
+		  EMPart *emp,
 		  CamelStream *stream,
 		  EMFormatWriterInfo *info,
 		  GCancellable *cancellable)
 {
+        CamelMimePart *part;
 	GByteArray *ba;
 	gchar *data;
 
 	g_return_if_fail (EM_IS_FORMAT (emf));
 
-	ba = camel_data_wrapper_get_byte_array ((CamelDataWrapper *) puri->part);
+        part = em_part_get_mime_part (emp);
+	ba = camel_data_wrapper_get_byte_array ((CamelDataWrapper *) part);
+        g_object_unref (part);
 
 	data = g_strndup ((gchar *) ba->data, ba->len);
 	camel_stream_write_string (stream, data, cancellable, NULL);
@@ -1322,8 +1333,7 @@ em_format_finalize (GObject *object)
 	}
 
 	if (emf->mail_part_table) {
-		/* This will destroy all the EMFormatPURI objects stored
-		 * inside!!!! */
+		/* This will destroy all the EMPartObjects stored inside!!!! */
 		g_hash_table_destroy (emf->mail_part_table);
 		emf->mail_part_table = NULL;
 	}
@@ -1430,9 +1440,9 @@ static void
 mail_part_table_item_free (gpointer data)
 {
 	GList *iter = data;
-	EMFormatPURI *puri = iter->data;
+	EMPart *emp = iter->data;
 
-	em_format_puri_free (puri);
+	g_object_unref (emp);
 }
 
 static void
@@ -1448,8 +1458,7 @@ em_format_init (EMFormat *emf)
 	emf->folder = NULL;
 	emf->mail_part_list = NULL;
 	emf->mail_part_table = g_hash_table_new_full (g_str_hash, g_str_equal,
-			NULL, (GDestroyNotify) mail_part_table_item_free);
-	/* No need to free the key, because it's owned and free'd by the PURI */
+			                g_free, mail_part_table_item_free);
 	
 	shell = e_shell_get_default ();
 	shell_settings = e_shell_get_shell_settings (shell);
@@ -1725,27 +1734,48 @@ em_format_remove_header_struct (EMFormat* emf,
 	em_format_remove_header (emf, header->name, header->value);
 }
 
+/**
+ * em_format_add_part_object:
+ * 
+ * @emf: an #EMFormat
+ * @emp: an #EMPart to be added
+ * 
+ * Reference count of @emp is not increased, the #EMFormat takes
+ * ownership from caller.
+ */
 void
-em_format_add_puri (EMFormat *emf,
-                    EMFormatPURI *puri)
+em_format_add_part_object (EMFormat *emf,
+                           EMPart *emp)
 {
         GList *item;
+        gchar *uri;
 
         g_return_if_fail (EM_IS_FORMAT (emf));
-        g_return_if_fail (puri != NULL);
+        g_return_if_fail (EM_IS_PART (emp));
 
-        emf->mail_part_list = g_list_append (emf->mail_part_list, puri);
+        emf->mail_part_list = g_list_append (emf->mail_part_list, emp);
         item = g_list_last (emf->mail_part_list);
 
-        g_hash_table_insert (emf->mail_part_table,
-                        puri->uri, item);
+        uri = em_part_get_uri (emp);
+        g_hash_table_insert (emf->mail_part_table, uri, item);
 
-        d(printf("Added PURI %s\n", puri->uri));
+        d(printf("Added EMPart %s\n", uri));
 }
 
-EMFormatPURI*
-em_format_find_puri (EMFormat *emf,
-		     const gchar *id)
+/**
+ * em_format_find_part_object:
+ *
+ * @emf: an #EMFormat object
+ * @id: an part URI or CID.
+ *
+ * Looks up EMPartObject by it's URI or CID.
+ *
+ * Returns: Referenced #EMPart that has to be unreferenced when no
+ *          longer needed, or %NULL when no part with such %id is found.
+ */
+EMPart *
+em_format_find_part_object (EMFormat *emf,
+                            const gchar *id)
 {
 	GList *list_iter;
 
@@ -1756,9 +1786,11 @@ em_format_find_puri (EMFormat *emf,
 
 		g_hash_table_iter_init (&iter, emf->mail_part_table);
 		while (g_hash_table_iter_next (&iter, &key, &value)) {
-			EMFormatPURI *puri = ((GList *) value)->data;
-			if (g_strcmp0 (puri->cid, id) == 0)
-				return puri;
+                        EMPart *emp = ((GList *) value)->data;
+                        gchar *cid = em_part_get_cid (emp);
+
+			if (g_strcmp0 (cid, id) == 0)
+				return g_object_ref (emp);
 		}
 
 		return NULL;
@@ -1766,7 +1798,7 @@ em_format_find_puri (EMFormat *emf,
 
 	list_iter = g_hash_table_lookup (emf->mail_part_table, id);
 	if (list_iter)
-		return list_iter->data;
+		return g_object_ref (list_iter->data);
 
 	return NULL;
 }
@@ -1872,7 +1904,7 @@ em_format_parse (EMFormat *emf,
 		 GCancellable *cancellable)
 {
 	GString *part_id;
-	EMFormatPURI *puri;
+	EMPart *emp;
 	EMFormatParserInfo info = { 0 };
 
 	g_return_if_fail (EM_IS_FORMAT (emf));
@@ -1902,11 +1934,10 @@ em_format_parse (EMFormat *emf,
 
 	part_id = g_string_new (".message");
 
-	/* Create a special PURI with entire message */
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI),
-		(CamelMimePart *) emf->message, part_id->str);
-	puri->mime_type = g_strdup ("text/html");
-	em_format_add_puri (emf, puri);
+        /* Create a special EMPart with entire message */
+        emp = em_part_new (emf, (CamelMimePart *) emf->message, part_id->str, NULL);
+        em_part_set_mime_type (emp, "text/plain");
+        em_format_add_part_object (emf, emp);
 
         info.force_handler = TRUE;
 	em_format_parse_part_as (emf, CAMEL_MIME_PART (emf->message), part_id, &info,
@@ -1962,6 +1993,7 @@ em_format_parse_async (EMFormat *emf,
 
 	result = g_simple_async_result_new (G_OBJECT (emf), callback,
 					    user_data, em_format_parse_async);
+
 	g_simple_async_result_run_in_thread (result, emf_start_async_parser,
 					     G_PRIORITY_DEFAULT, cancellable);
 }
@@ -2062,7 +2094,7 @@ em_format_format_error (EMFormat *emf,
                         const gchar *format,
                         ...)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	CamelMimePart *part;
 	const EMFormatHandler *handler;
 	gchar *errmsg;
@@ -2084,14 +2116,16 @@ em_format_format_error (EMFormat *emf,
 
 	emf->priv->last_error++;
 	uri = g_strdup_printf (".error.%d", emf->priv->last_error);
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, uri);
-	puri->mime_type = g_strdup ("text/html");
+
+        emp = em_part_new (emf, part, uri, NULL);
+	em_part_set_mime_type (emp, "text/html");
+
 	if (handler && handler->write_func)
-		puri->write_func = handler->write_func;
+		em_part_set_write_func (emp, handler->write_func);
 	else
-		puri->write_func = emf_write_error;
+		em_part_set_write_func (emp, emf_write_error);
 
-	em_format_add_puri (emf, puri);
+	em_format_add_part_object (emf, emp);
 
 	g_free (uri);
 	g_object_unref (part);
@@ -2509,95 +2543,6 @@ em_format_redraw (EMFormat *emf)
 
 
 /**************************************************************************/
-EMFormatPURI*
-em_format_puri_new (EMFormat *emf,
-		    gsize puri_size,
-		    CamelMimePart *part,
-		    const gchar *uri)
-{
-	EMFormatPURI *puri;
-
-	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
-	g_return_val_if_fail (puri_size >= sizeof (EMFormatPURI), NULL);
-
-	puri = (EMFormatPURI *) g_malloc0 (puri_size);
-	puri->emf = emf;
-
-	if (part)
-		puri->part = g_object_ref (part);
-
-	if (uri)
-		puri->uri = g_strdup (uri);
-
-	return puri;
-}
-
-void
-em_format_puri_free (EMFormatPURI *puri)
-{
-	g_return_if_fail (puri);
-
-	if (puri->part)
-		g_object_unref (puri->part);
-
-	if (puri->uri)
-		g_free (puri->uri);
-
-	if (puri->cid)
-		g_free (puri->cid);
-
-	if (puri->mime_type)
-		g_free (puri->mime_type);
-
-	if (puri->validity)
-		camel_cipher_validity_free (puri->validity);
-
-	if (puri->validity_parent)
-		camel_cipher_validity_free (puri->validity_parent);
-
-	if (puri->free)
-		puri->free(puri);
-
-	g_free (puri);
-}
-
-
-void
-em_format_puri_write (EMFormatPURI *puri,
-		      CamelStream *stream,
-		      EMFormatWriterInfo *info,
-		      GCancellable *cancellable)
-{
-	g_return_if_fail (puri);
-	g_return_if_fail (CAMEL_IS_STREAM (stream));
-
-	if (info->mode == EM_FORMAT_WRITE_MODE_SOURCE) {
-		const EMFormatHandler *handler;
-		handler = em_format_find_handler (puri->emf, "x-evolution/message/source");
-		handler->write_func (puri->emf, puri, stream, info, cancellable);
-		return;
-	}
-
-	if (puri->write_func) {
-		puri->write_func (puri->emf, puri, stream, info, cancellable);
-	} else {
-		const EMFormatHandler *handler;
-		const gchar *mime_type;
-
-		if (puri->mime_type) {
-			mime_type = puri->mime_type;
-		} else {
-			mime_type = (gchar *) "plain/text";
-		}
-
-		handler = em_format_find_handler (puri->emf, mime_type);
-		if (handler && handler->write_func) {
-			handler->write_func (puri->emf,
-					puri, stream, info, cancellable);
-		}
-	}
-}
-
 EMFormatHeader*
 em_format_header_new (const gchar *name,
 		      const gchar *value)
diff --git a/em-format/em-format.h b/em-format/em-format.h
index c9c38be..d9c27d8 100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@ -60,26 +60,29 @@ typedef struct _EMFormat EMFormat;
 typedef struct _EMFormatClass EMFormatClass;
 typedef struct _EMFormatPrivate EMFormatPrivate;
 
-typedef struct _EMFormatPURI EMFormatPURI;
 typedef struct _EMFormatHeader EMFormatHeader;
 typedef struct _EMFormatHandler EMFormatHandler;
 typedef struct _EMFormatParserInfo EMFormatParserInfo;
 typedef struct _EMFormatWriterInfo EMFormatWriterInfo;
 
+typedef struct _EMPart EMPart;
+
 typedef void		(*EMFormatParseFunc)	(EMFormat *emf,
 					 	 CamelMimePart *part,
 					 	 GString *part_id,
 					 	 EMFormatParserInfo *info,
 					 	 GCancellable *cancellable);
-typedef void		(*EMFormatWriteFunc)	(EMFormat *emf,
-					 	 EMFormatPURI *puri,
-					 	 CamelStream *stream,
-					 	 EMFormatWriterInfo *info,
-					 	 GCancellable *cancellable);
-typedef GtkWidget*	(*EMFormatWidgetFunc)	(EMFormat *emf,
-					 	 EMFormatPURI *puri,
-					 	 GCancellable *cancellable);
-
+/* FIXME: Redeclared in em-part-object.h */
+typedef void            (*EMPartObjectWriteFunc)
+                                                (EMFormat *emf,
+                                                 EMPart *empo,
+                                                 CamelStream *stream,
+                                                 EMFormatWriterInfo *info,
+                                                 GCancellable *cancellable);
+typedef GtkWidget*      (*EMPartObjectWidgetFunc)
+                                                (EMFormat *emf,
+                                                 EMPart *empo,
+                                                 GCancellable *cancellable);
 
 typedef enum {
 	EM_FORMAT_HANDLER_INLINE = 1 << 0,
@@ -97,7 +100,7 @@ typedef enum {
 struct _EMFormatHandler {
 	gchar *mime_type;
 	EMFormatParseFunc parse_func;
-	EMFormatWriteFunc write_func;
+	EMPartObjectWriteFunc write_func;
 	EMFormatHandlerFlags flags;
 
 	EMFormatHandler *old;
@@ -124,7 +127,7 @@ struct _EMFormatWriterInfo {
 	gboolean headers_collapsable;
 	gboolean headers_collapsed;
 
-	/* When TRUE, EMFormatWriteFunc's will put the content of the PURI part
+	/* When TRUE, EMPartObjectWriteFunc's will put the content of the EMPart
 	   between EFH_HTML_HEADER and EFH_HTML_FOOTER */
 	gboolean with_html_header;
 };
@@ -138,28 +141,6 @@ struct _EMFormatHeader {
 #define EM_FORMAT_HEADER_BOLD (1<<0)
 #define EM_FORMAT_HEADER_LAST (1<<4) /* reserve 4 slots */
 
-
-struct _EMFormatPURI {
-	CamelMimePart *part;
-
-	EMFormat *emf;
-	EMFormatWriteFunc write_func;
-	EMFormatWidgetFunc widget_func;
-
-	gchar *uri;
-	gchar *cid;
-	gchar *mime_type;
-
-	/* EM_FORMAT_VALIDITY_* flags */
-	guint32 validity_type;
-	CamelCipherValidity *validity;
-	CamelCipherValidity *validity_parent;
-
-	gboolean is_attachment;
-
-	void (*free)(EMFormatPURI *puri); /* optional callback for freeing user-fields */
-};
-
 struct _EMFormat {
 	GObject parent;
 	EMFormatPrivate *priv;
@@ -232,9 +213,9 @@ void	        	em_format_remove_header		(EMFormat *emf,
 void                    em_format_remove_header_struct	(EMFormat *emf,
 							 const EMFormatHeader *header);
 
-void			em_format_add_puri		(EMFormat *emf,
-							 EMFormatPURI *puri);
-EMFormatPURI*		em_format_find_puri		(EMFormat *emf,
+void			em_format_add_part_object	(EMFormat *emf,
+							 EMPart *empo);
+EMPart*			em_format_find_part_object	(EMFormat *emf,
 							 const gchar *id);
 
 void			em_format_class_add_handler	(EMFormatClass *emfc,
@@ -252,6 +233,11 @@ void			em_format_parse			(EMFormat *emf,
 							 CamelFolder *folder,
 							 GCancellable *cancellable);
 
+void                    em_format_write                 (EMFormat *emf,
+                                                         CamelStream *stream,
+                                                         EMFormatWriterInfo *info,
+                                                         GCancellable *cancellable);
+
 void                    em_format_parse_async           (EMFormat *emf,
                                                          CamelMimeMessage *message,
                                                          CamelFolder *folder,
@@ -303,10 +289,10 @@ void			em_format_empty_parser 		(EMFormat *emf,
 							 EMFormatParserInfo *info,
 							 GCancellable *cancellable);
 
-/* EMFormatWriteFunc that does nothing. Use it to disable
+/* EMPartObjectWriteFunc that does nothing. Use it to disable
  * writing of a specific mime type parts */
 void			em_format_empty_writer 		(EMFormat *emf,
-							 EMFormatPURI *puri,
+							 EMPart *empo,
 							 CamelStream *stream,
 							 EMFormatWriterInfo *info,
 							 GCancellable *cancellable);
@@ -314,17 +300,6 @@ void			em_format_empty_writer 		(EMFormat *emf,
 void			em_format_redraw		(EMFormat *emf);
 
 
-EMFormatPURI*		em_format_puri_new 		(EMFormat *emf,
-							 gsize puri_size,
-							 CamelMimePart *part,
-							 const gchar *uri);
-void			em_format_puri_free 		(EMFormatPURI *puri);
-
-void			em_format_puri_write 		(EMFormatPURI *puri,
-							 CamelStream *stream,
-							 EMFormatWriterInfo *info,
-							 GCancellable *cancellable);
-
 EMFormatHeader*		em_format_header_new		(const gchar *name,
 							 const gchar *value);
 void			em_format_header_free		(EMFormatHeader *header);
diff --git a/em-format/em-part.c b/em-format/em-part.c
new file mode 100644
index 0000000..26c4c4b
--- /dev/null
+++ b/em-format/em-part.c
@@ -0,0 +1,678 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "em-part.h"
+#include "em-format.h"
+
+G_DEFINE_TYPE (EMPart, em_part, G_TYPE_OBJECT);
+
+struct _EMPartPrivate {
+
+	CamelMimePart *part;
+
+	EMFormat *formatter;
+	EMPartWriteFunc write_func;
+	EMPartWidgetFunc widget_func;
+
+	gchar *uri;
+	gchar *cid;
+	gchar *mime_type;
+
+	/* EM_FORMAT_VALIDITY_* flags */
+	guint32 validity_type;
+	CamelCipherValidity *validity;
+	CamelCipherValidity *validity_parent;
+
+	gboolean is_attachment;
+
+	GMutex *mutex;
+};
+
+static void
+em_part_finalize (GObject *object)
+{
+	EMPartPrivate *priv = EM_PART (object)->priv;
+
+	g_mutex_lock (priv->mutex);
+
+	if (priv->cid) {
+		g_free (priv->cid);
+		priv->cid = NULL;
+	}
+
+	if (priv->formatter) {
+		g_object_unref (priv->formatter);
+		priv->formatter = NULL;
+	}
+
+	if (priv->mime_type) {
+		g_free (priv->mime_type);
+		priv->mime_type = NULL;
+	}
+
+	if (priv->part) {
+		g_object_unref (priv->part);
+		priv->part = NULL;
+	}
+
+	if (priv->uri) {
+		g_free (priv->uri);
+		priv->uri = NULL;
+	}
+
+	if (priv->validity) {
+		camel_cipher_validity_free (priv->validity);
+		priv->validity = NULL;
+	}
+
+	if (priv->validity_parent) {
+		camel_cipher_validity_free (priv->validity_parent);
+		priv->validity_parent = NULL;
+	}
+
+	g_mutex_unlock (priv->mutex);
+	g_mutex_free (priv->mutex);
+}
+
+static void
+em_part_class_init (EMPartClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EMPartPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = em_part_finalize;
+
+}
+
+static void
+em_part_init (EMPart *emp)
+{
+	emp->priv = G_TYPE_INSTANCE_GET_PRIVATE (emp,
+			EM_TYPE_PART, EMPartPrivate);
+
+	emp->priv->mutex = g_mutex_new ();
+	emp->priv->cid = NULL;
+	emp->priv->formatter = NULL;
+	emp->priv->is_attachment = FALSE;
+	emp->priv->mime_type = NULL;
+	emp->priv->part = NULL;
+	emp->priv->uri = NULL;
+	emp->priv->validity = NULL;
+	emp->priv->validity_parent = NULL;
+	emp->priv->validity_type = 0;
+	emp->priv->widget_func = NULL;
+	emp->priv->write_func = NULL;
+}
+
+/**
+ * em_part_new:
+ * @emf: an #EMFormat
+ * @part: a #CamelMimePart which this objects wraps
+ * @uri: an URI of the object within hierarchy of mime parts
+ * @write_func: an #EMPartWriteFunc that will write parsed content of the
+ *              @part to a stream, or %NULL.
+ *
+ * Constructs a new #EMPart.
+ *
+ * Returns: A new #EMPart, or %NULL on failure.
+ */
+EMPart *
+em_part_new (EMFormat *emf,
+	     CamelMimePart *part,
+	     const gchar *uri,
+	     EMPartWriteFunc write_func)
+{
+	EMPart *emp;
+
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+	g_return_val_if_fail ((part == NULL) || CAMEL_IS_MIME_PART (part), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	emp = EM_PART (g_object_new (EM_TYPE_PART, NULL));
+
+	em_part_set_mime_part (emp, part);
+	em_part_set_formatter (emp, emf);
+	em_part_set_uri (emp, uri);
+
+	if (write_func)
+		em_part_set_write_func (emp, write_func);
+
+	return emp;
+}
+
+void
+em_part_set_formatter (EMPart *emp,
+		       EMFormat *emf)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+	g_return_if_fail (EM_IS_FORMAT (emf));
+
+	g_mutex_lock (emp->priv->mutex);
+
+	g_object_ref (emf);
+
+	if (emp->priv->formatter)
+		g_object_unref (emp->priv->formatter);
+
+	emp->priv->formatter = emf;
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+/**
+ * em_part_get_formatter:
+ *
+ * @emp: an #EMPart
+ *
+ * Returns: An #EMFormat that has to ne unreferenced when no longer needed.
+ */
+EMFormat *
+em_part_get_formatter (EMPart *emp)
+{
+	EMFormat *formatter;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->formatter)
+		formatter = g_object_ref (emp->priv->formatter);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return formatter;
+}
+
+
+/**
+ * em_part_set_mime_part:
+ *
+ * @emp: an #EMPart
+ * @widget_func: a #CamelMimePart, or %NULL to unset.
+ */
+void
+em_part_set_mime_part (EMPart *emp,
+		       CamelMimePart *part)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+	g_return_if_fail ((part == NULL) || CAMEL_IS_MIME_PART (part));
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (part)
+		g_object_ref (part);
+
+	if (emp->priv->part)
+		g_object_unref (emp->priv->part);
+
+	emp->priv->part = part;
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+/**
+ * em_part_get_mime_part:
+ *
+ * @emp: an #EMPart
+ *
+ * Returns: A #CamelMimePart that has to be unreferenced when no longer needed.
+ */
+CamelMimePart *
+em_part_get_mime_part (EMPart *emp)
+{
+	CamelMimePart *part;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->part)
+		part = g_object_ref (emp->priv->part);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return part;
+}
+
+/**
+ * em_part_set_write_func:
+ *
+ * @emp: an #EMPart
+ * @write_func: an #EMPartWriteFunc, or %NULL to unset.
+ */
+void
+em_part_set_write_func (EMPart *emp,
+			EMPartWriteFunc write_func)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+	emp->priv->write_func = write_func;
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+EMPartWriteFunc
+em_part_get_write_func (EMPart *emp)
+{
+	EMPartWriteFunc write_func;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+	write_func = emp->priv->write_func;
+	g_mutex_unlock (emp->priv->mutex);
+
+	return write_func;
+}
+
+/**
+ * em_part_set_widget_func:
+ *
+ * @emp: an #EMPart
+ * @widget_func: an #EMPartWidgetFunc, or %NULL to unset.
+ */
+void
+em_part_set_widget_func (EMPart *emp,
+			 EMPartWidgetFunc widget_func)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+	emp->priv->widget_func = widget_func;
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+EMPartWidgetFunc
+em_part_get_widget_func (EMPart *emp)
+{
+	EMPartWidgetFunc widget_func;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+	widget_func = emp->priv->widget_func;
+	g_mutex_unlock (emp->priv->mutex);
+
+	return widget_func;
+}
+
+void
+em_part_set_uri (EMPart *emp,
+		 const gchar *uri)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+	g_return_if_fail (uri && *uri);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->uri)
+		g_free (emp->priv->uri);
+
+	emp->priv->uri = g_strdup (uri);
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+gchar *
+em_part_get_uri (EMPart *emp)
+{
+	gchar *uri = NULL;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->uri)
+		uri = g_strdup (emp->priv->uri);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return uri;
+}
+
+/**
+ * em_part_set_cid:
+ *
+ * @emp: an #EMPart
+ * @cid: part content ID, or %NULL to unset
+ */
+void
+em_part_set_cid (EMPart *emp,
+		 const gchar *cid)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->cid)
+		g_free (emp->priv->cid);
+
+	if (cid)
+		emp->priv->cid = g_strdup (cid);
+	else
+		emp->priv->cid = NULL;
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+gchar *
+em_part_get_cid (EMPart *emp)
+{
+	gchar *cid = NULL;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (cid)
+		cid = g_strdup (emp->priv->cid);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return cid;
+}
+
+void
+em_part_set_mime_type (EMPart *emp,
+		       const gchar *mime_type)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+	g_return_if_fail (mime_type && *mime_type);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->mime_type)
+		g_free (emp->priv->mime_type);
+
+	emp->priv->mime_type = g_strdup (mime_type);
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+gchar *
+em_part_get_mime_type (EMPart *emp)
+{
+	gchar *mime_type = NULL;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (mime_type)
+		mime_type = g_strdup (emp->priv->mime_type);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return mime_type;
+}
+
+
+
+void
+em_part_set_validity_type (EMPart *emp,
+			   guint32 validity_type)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+	emp->priv->validity_type = validity_type;
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+guint32
+em_part_get_validity_type (EMPart *emp)
+{
+	guint32 validity_type;
+
+	g_return_val_if_fail (EM_IS_PART (emp), 0);
+
+	g_mutex_lock (emp->priv->mutex);
+	validity_type = emp->priv->validity_type;
+	g_mutex_unlock (emp->priv->mutex);
+
+	return validity_type;
+}
+
+/**
+ * em_part_set_validity:
+ *
+ * @emp: an #EMPart
+ * @validity: a #CamelCipherValidity object, or %NULL to unset
+ */
+void
+em_part_set_validity (EMPart *emp,
+		      CamelCipherValidity *validity)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->validity)
+		camel_cipher_validity_free (emp->priv->validity);
+
+	if (validity)
+		emp->priv->validity = camel_cipher_validity_clone (validity);
+	else
+		emp->priv->validity = NULL;
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+/**
+ * em_part_get_validity:
+ *
+ * @emp: an #EMPart
+ *
+ * Returns: A copy of #CamelCipherValidity. Must be freed when no longer needed.
+ */
+CamelCipherValidity *
+em_part_get_validity (EMPart *emp)
+{
+	CamelCipherValidity *validity = NULL;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->validity)
+		validity = camel_cipher_validity_clone (emp->priv->validity);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return validity;
+}
+
+/**
+ * em_part_set_validity_parent:
+ *
+ * @emp: an #EMPart
+ * @validity: a #CamelCipherValidity object, or %NULL to unset
+ */
+void
+em_part_set_validity_parent (EMPart *emp,
+			     CamelCipherValidity *validity)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->validity_parent)
+		camel_cipher_validity_free (emp->priv->validity_parent);
+
+	if (validity)
+		emp->priv->validity_parent = camel_cipher_validity_clone (validity);
+	else
+		emp->priv->validity_parent = NULL;
+
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+/**
+ * em_part_get_validity_parent:
+ *
+ * @emp: an #EMPart
+ *
+ * Returns: A copy of #CamelCipherValidity. Must be freed when no longer needed.
+ */
+CamelCipherValidity *
+em_part_get_validity_parent (EMPart *emp)
+{
+	CamelCipherValidity *validity = NULL;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+
+	if (emp->priv->validity_parent)
+		validity = camel_cipher_validity_clone (emp->priv->validity_parent);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	return validity;
+}
+
+void
+em_part_set_is_attachment (EMPart *emp,
+			   gboolean is_attachment)
+{
+	g_return_if_fail (EM_IS_PART (emp));
+
+	g_mutex_lock (emp->priv->mutex);
+	emp->priv->is_attachment = is_attachment;
+	g_mutex_unlock (emp->priv->mutex);
+}
+
+gboolean
+em_part_get_is_attachment (EMPart *emp)
+{
+	gboolean is_attachment;
+
+	g_return_val_if_fail (EM_IS_PART (emp), FALSE);
+
+	g_mutex_lock (emp->priv->mutex);
+	is_attachment = emp->priv->is_attachment;
+	g_mutex_unlock (emp->priv->mutex);
+
+	return is_attachment;
+}
+
+/**
+ * em_part_get_widget:
+ *
+ * @emp: an #EMPart
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Calls assigned #EMPartWidgetFunc to get GtkWidget
+ * representing content of the mime part.
+ *
+ * Returns: a #GtkWidget that has to be unreferenced when no longer needed.
+ */
+GtkWidget *
+em_part_get_widget (EMPart *emp,
+		    GCancellable *cancellable)
+{
+	EMPartWidgetFunc widget_func;
+	EMFormat *formatter;
+	GtkWidget *widget;
+
+	g_return_val_if_fail (EM_IS_PART (emp), NULL);
+
+	g_mutex_lock (emp->priv->mutex);
+	widget_func = emp->priv->widget_func;
+	formatter = g_object_ref (emp->priv->formatter);
+	g_mutex_unlock (emp->priv->mutex);
+
+	if (!widget_func)
+		return NULL;
+
+	g_object_ref (emp);
+	widget = widget_func (formatter, emp, cancellable);
+	g_object_unref (emp);
+
+	return widget;
+}
+
+/**
+ * em_part_write:
+ *
+ * @emp: an #EMPart
+ * @stream: a #CamelStream to which the data should be written
+ * @info: additional information for write function, or %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ *
+ * Calls assigned #EMPartWriteFunc to write parsed
+ * content of mime part to the @stream.
+ */
+void
+em_part_write (EMPart *emp,
+	       CamelStream *stream,
+	       EMFormatWriterInfo *info,
+	       GCancellable *cancellable)
+{
+	EMPartWriteFunc write_func;
+	EMFormat *formatter;
+	gchar *mime_type = NULL;
+
+	g_return_if_fail (EM_IS_PART (emp));
+	g_return_if_fail (CAMEL_IS_STREAM (stream));
+
+	g_mutex_lock (emp->priv->mutex);
+	write_func = emp->priv->write_func;
+	formatter = g_object_ref (emp->priv->formatter);
+
+	if (emp->priv->mime_type)
+		mime_type = g_strdup (emp->priv->mime_type);
+
+	g_mutex_unlock (emp->priv->mutex);
+
+	g_object_ref (emp);
+
+	if (info->mode == EM_FORMAT_WRITE_MODE_SOURCE) {
+		const EMFormatHandler *handler;
+		handler = em_format_find_handler (formatter, "x-evolution/message/source");
+		handler->write_func (formatter, emp, stream, info, cancellable);
+
+	} else {
+
+		if (write_func) {
+			write_func (formatter, emp, stream, info, cancellable);
+		} else {
+			const EMFormatHandler *handler;
+
+			if (!mime_type)
+				mime_type = g_strdup ("plain/text");
+
+			handler = em_format_find_handler (formatter, mime_type);
+
+			if (handler && handler->write_func) {
+				handler->write_func (formatter, emp,
+				     stream, info, cancellable);
+			}
+		}
+	}
+
+	g_object_unref (emp);
+	g_object_unref (formatter);
+
+	if (mime_type)
+		g_free (mime_type);
+}
diff --git a/em-format/em-part.h b/em-format/em-part.h
new file mode 100644
index 0000000..2b20be5
--- /dev/null
+++ b/em-format/em-part.h
@@ -0,0 +1,140 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EM_PART_H
+#define EM_PART_H
+
+#include <camel/camel.h>
+#include <glib-object.h>
+
+#include <em-format.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_PART \
+	(em_part_get_type ())
+#define EM_PART(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), EM_TYPE_PART, EMPart))
+#define EM_PART_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), EM_TYPE_PART, EMPartClass))
+#define EM_IS_PART(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), EM_TYPE_PART))
+#define EM_IS_PART_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), EM_TYPE_PART))
+#define EM_PART_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), EM_TYPE_PART, EMPartClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMPart EMPart;
+typedef struct _EMPartClass EMPartClass;
+typedef struct _EMPartPrivate EMPartPrivate;
+
+
+typedef void		(*EMPartWriteFunc)	(EMFormat *emf,
+						 EMPart *emp,
+						 CamelStream *stream,
+						 EMFormatWriterInfo *info,
+						 GCancellable *cancellable);
+typedef GtkWidget*	(*EMPartWidgetFunc)	(EMFormat *emf,
+						 EMPart *emp,
+						 GCancellable *cancellable);
+
+
+struct _EMPart {
+        GObject parent;
+        EMPartPrivate *priv;
+};
+
+struct _EMPartClass {
+        GObjectClass parent_class;
+
+};
+
+EMPart*			em_part_new      	(EMFormat *emf,
+                                                 CamelMimePart *part,
+                                                 const gchar *uri,
+                                                 EMPartWriteFunc write_func);
+
+GType                   em_part_get_type ();
+
+void                    em_part_set_formatter	(EMPart *emp,
+                                                 EMFormat *emf);
+
+EMFormat*               em_part_get_formatter	(EMPart *emp);
+
+void                    em_part_set_mime_part	(EMPart *emp,
+                                                 CamelMimePart *part);
+CamelMimePart*          em_part_get_mime_part	(EMPart * emp);
+
+void                    em_part_set_write_func	(EMPart *emp,
+                                                 EMPartWriteFunc write_func);
+EMPartWriteFunc		em_part_get_write_func	(EMPart *emp);
+
+void                    em_part_set_widget_func	(EMPart *emp,
+                                                 EMPartWidgetFunc widget_func);
+EMPartWidgetFunc	em_part_get_widget_func	(EMPart *emp);
+
+void                    em_part_set_uri  	(EMPart *emp,
+                                                 const gchar *uri);
+gchar*                  em_part_get_uri  	(EMPart *emp);
+
+void                    em_part_set_cid  	(EMPart *emp,
+                                                 const gchar *cid);
+gchar*                  em_part_get_cid  	(EMPart *emp);
+
+void			em_part_set_mime_type
+						(EMPart *emp,
+						 const gchar *mime_type);
+gchar*			em_part_get_mime_type	(EMPart *emp);
+
+void                    em_part_set_validity_type
+						(EMPart *emp,
+                                                 guint32 validity_type);
+guint32                 em_part_get_validity_type
+                                                (EMPart *emp);
+
+void                    em_part_set_validity	(EMPart *emp,
+                                                 CamelCipherValidity *validity);
+CamelCipherValidity*    em_part_get_validity	(EMPart *emp);
+
+void                    em_part_set_validity_parent
+                                                (EMPart *emp,
+                                                 CamelCipherValidity *validity);
+CamelCipherValidity*    em_part_get_validity_parent
+                                                (EMPart *emp);
+
+void                    em_part_set_is_attachment
+                                                (EMPart *emp,
+                                                 gboolean is_attachment);
+gboolean                em_part_get_is_attachment
+                                                (EMPart *emp);
+
+GtkWidget*              em_part_get_widget	(EMPart *emp,
+                                                 GCancellable *cancellable);
+
+void                    em_part_write		(EMPart *emp,
+                                                 CamelStream *stream,
+                                                 EMFormatWriterInfo *info,
+                                                 GCancellable *cancellable);
+
+G_END_DECLS
+
+#endif /* EM_PART_H */
\ No newline at end of file
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 48119c1..3ca6fc4 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -83,6 +83,7 @@ mailinclude_HEADERS =					\
 	em-folder-utils.h				\
 	em-format-hook.h				\
 	em-format-html-display.h			\
+	em-format-html-display-parts.h			\
 	em-format-html-print.h				\
 	em-format-html.h				\
 	em-search-context.h				\
@@ -149,6 +150,7 @@ libevolution_mail_la_SOURCES =				\
 	em-folder-utils.c				\
 	em-format-hook.c				\
 	em-format-html-display.c			\
+	em-format-html-display-parts.c			\
 	em-format-html-print.c				\
 	em-format-html.c				\
 	em-search-context.c				\
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index ea59a6d..4220058 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -11,6 +11,8 @@
 
 #include "em-format-html.h"
 
+#include <em-format/em-part.h>
+
 #include <e-util/e-icon-factory.h>
 #include <e-util/e-util.h>
 
@@ -23,7 +25,7 @@ struct _EMailRequestPrivate {
 	EMFormatHTML *efh;
 
 	CamelStream *output_stream;
-	EMFormatPURI *puri;
+	EMPart *emp;
 	gchar *mime_type;
 
 	gint content_length;
@@ -45,6 +47,8 @@ handle_mail_request (GSimpleAsyncResult *res,
 	GInputStream *stream;
 	GByteArray *ba;
 	gchar *part_id;
+        EMFormatWriterInfo info = {0};
+        gchar *val;
 
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
@@ -57,34 +61,33 @@ handle_mail_request (GSimpleAsyncResult *res,
 
 	part_id = g_hash_table_lookup (request->priv->uri_query, "part_id");
 
-	if (part_id) {
-                /* original part_id is owned by the GHashTable */
-                part_id = soup_uri_decode (part_id);
-		request->priv->puri = em_format_find_puri (emf, part_id);
+        val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsed");
+        if (val)
+                info.headers_collapsed = atoi (val);
 
-		if (request->priv->puri) {
-			EMFormatWriterInfo info = {0};
-			gchar *val;
+        val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsable");
+        if (val)
+                info.headers_collapsable = atoi (val);
 
-			val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsed");
-			if (val)
-				info.headers_collapsed = atoi (val);
+        val = g_hash_table_lookup (request->priv->uri_query, "mode");
+        if (val)
+                info.mode = atoi (val);
 
-			val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsable");
-			if (val)
-				info.headers_collapsable = atoi (val);
+        val = g_hash_table_lookup (request->priv->uri_query, "with_html_headers");
+        if (val)
+                info.with_html_header = atoi (val);
+        else
+                info.with_html_header = FALSE; /* By default this is TRUE!! */
 
-			val = g_hash_table_lookup (request->priv->uri_query, "mode");
-			if (val)
-				info.mode = atoi (val);
 
-			val = g_hash_table_lookup (request->priv->uri_query, "with_html_headers");
-			if (val)
-				info.with_html_header = atoi (val);
-			else
-				info.with_html_header = TRUE; /* By default this is TRUE!! */
+	if (part_id) {
+                /* original part_id is owned by the GHashTable */
+                part_id = soup_uri_decode (part_id);
+                request->priv->emp = em_format_find_part_object (emf, part_id);
 
-			em_format_puri_write (request->priv->puri, request->priv->output_stream, &info, NULL);
+		if (request->priv->emp) {
+                        em_part_write (request->priv->emp, request->priv->output_stream,
+                                &info, NULL);
 		} else {
 			g_warning ("Failed to lookup requested part '%s' - this should not happen!", part_id);
 		}
@@ -436,7 +439,7 @@ e_mail_request_init (EMailRequest *request)
 	request->priv->efh = NULL;
 	request->priv->output_stream = NULL;
 	request->priv->uri_query = NULL;
-	request->priv->puri = NULL;
+	request->priv->emp = NULL;
 	request->priv->mime_type = NULL;
 	request->priv->content_length = 0;
 }
@@ -471,6 +474,11 @@ mail_request_finalize (GObject *object)
                 request->priv->ret_data = NULL;
         }
 
+        if (request->priv->emp) {
+		g_object_unref (request->priv->emp);
+		request->priv->emp = NULL;
+	}
+
 	G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
 }
 
@@ -526,7 +534,7 @@ mail_request_send_async (SoupRequest *request,
         formatters = g_object_get_data (G_OBJECT (session), "formatters");
                                         g_return_if_fail (formatters != NULL);
 
-        /* Get HTML content of given PURI part */
+        /* Get HTML content of given EMPart */
         if (g_strcmp0 (uri->scheme, "mail") == 0) {
                 gchar *uri_str;
 
@@ -613,17 +621,27 @@ static const gchar*
 mail_request_get_content_type (SoupRequest *request)
 {
 	EMailRequest *emr = E_MAIL_REQUEST (request);
-	gchar *mime_type;
+	gchar *mime_type, *part_mime_type;
+
+	if (emr->priv->emp)
+		part_mime_type = em_part_get_mime_type (emr->priv->emp);
+	else
+		part_mime_type = NULL;
 
 	if (emr->priv->mime_type) {
 		mime_type = g_strdup (emr->priv->mime_type);
-	} else if (!emr->priv->puri) {
+	} else if (!emr->priv->emp) {
 		mime_type = g_strdup ("text/html");
-	} else if (!emr->priv->puri->mime_type) {
-		CamelContentType *ct = camel_mime_part_get_content_type (emr->priv->puri->part);
+	} else if (!part_mime_type) {
+		CamelMimePart *part;
+		CamelContentType *ct;
+		
+		part = em_part_get_mime_part (emr->priv->emp);
+		ct = camel_mime_part_get_content_type (part);
 		mime_type = camel_content_type_simple (ct);
+		g_object_unref (part);
 	} else {
-		mime_type = g_strdup (emr->priv->puri->mime_type);
+		mime_type = em_part_get_mime_type (emr->priv->emp);
 	}
 
 	if (g_strcmp0 (mime_type, "text/html") == 0) {
diff --git a/mail/em-format-html-display-parts.c b/mail/em-format-html-display-parts.c
new file mode 100644
index 0000000..d7c7965
--- /dev/null
+++ b/mail/em-format-html-display-parts.c
@@ -0,0 +1,722 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "em-format-html-display-parts.h"
+
+#include <glib.h>
+
+struct _EMPartAttachmentBarPrivate {
+	EAttachmentStore *store;
+	
+	GMutex *mutex;
+};
+
+G_DEFINE_TYPE (EMPartAttachmentBar, em_part_attachment_bar, EM_TYPE_PART);
+
+static void
+em_part_attachment_bar_finalize (GObject *object)
+{
+	EMPartAttachmentBarPrivate *priv =
+		EM_PART_ATTACHMENT_BAR (object)->priv;
+
+	g_mutex_lock (priv->mutex);
+
+	if (priv->store) {
+		g_object_unref (priv->store);
+		priv->store = NULL;
+	}
+
+	g_mutex_unlock (priv->mutex);
+	g_mutex_free (priv->mutex);
+}
+
+static void
+em_part_attachment_bar_class_init (EMPartAttachmentBarClass *klass)
+{
+	GObjectClass *object_class;
+	
+	g_type_class_add_private (klass, sizeof (EMPartAttachmentBarPrivate));
+	
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = em_part_attachment_bar_finalize;
+}
+
+
+static void
+em_part_attachment_bar_init (EMPartAttachmentBar *empab)
+{
+
+	empab->priv = G_TYPE_INSTANCE_GET_PRIVATE (empab,
+			EM_TYPE_PART_ATTACHMENT_BAR, EMPartAttachmentBarPrivate);
+
+	empab->priv->store = NULL;
+
+	empab->priv->mutex = g_mutex_new ();
+}
+
+EMPart*
+em_part_attachment_bar_new (EMFormat *emf,
+			    CamelMimePart *part,
+			    const gchar *uri,
+			    EMPartWriteFunc write_func)
+{
+	EMPart *emp;
+
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+	g_return_val_if_fail ((part == NULL) || CAMEL_IS_MIME_PART (part), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	emp = (EMPart *) g_object_new (EM_TYPE_PART_ATTACHMENT_BAR, NULL);
+	em_part_set_formatter (emp, emf);
+	em_part_set_mime_part (emp, part);
+	em_part_set_uri (emp, uri);
+	em_part_set_write_func (emp, write_func);
+
+	return emp;
+}
+
+void
+em_part_attachment_bar_set_store (EMPartAttachmentBar *empab,
+				  EAttachmentStore *store)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT_BAR (empab));
+	g_return_if_fail ((store == NULL) || E_IS_ATTACHMENT_STORE (store));
+
+	g_mutex_lock (empab->priv->mutex);
+
+	if (store)
+		g_object_ref (store);
+
+	if (empab->priv->store)
+		g_object_unref (empab->priv->store);
+
+	empab->priv->store = store;
+
+	g_mutex_unlock (empab->priv->mutex);
+}
+
+
+EAttachmentStore*
+em_part_attachment_bar_get_store (EMPartAttachmentBar *empab)
+{
+	EAttachmentStore *store = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT_BAR (empab), NULL);
+
+	g_mutex_lock (empab->priv->mutex);
+	if (empab->priv->store)
+		store = g_object_ref (empab->priv->store);
+	g_mutex_unlock (empab->priv->mutex);
+
+	return store;
+}
+
+/******************************************************************************/
+
+struct _EMPartAttachmentPrivate {
+
+	gchar *snoop_mime_type;
+
+	/* The > and v buttons */
+	GtkWidget *forward;
+	GtkWidget *down;
+	gint shown:1;
+
+	EAttachment *attachment;
+	gchar *view_part_id;
+	gchar *description;
+
+	CamelStream *mstream;
+
+	const EMFormatHandler *handler;
+
+	GMutex *mutex;
+};
+
+G_DEFINE_TYPE (EMPartAttachment, em_part_attachment, EM_TYPE_PART);
+
+static void
+em_part_attachment_finalize (GObject *object)
+{
+	EMPartAttachmentPrivate *priv = EM_PART_ATTACHMENT (object)->priv;
+
+	g_mutex_lock (priv->mutex);
+
+	if (priv->attachment) {
+		g_object_unref (priv->attachment);
+		priv->attachment = NULL;
+	}
+
+	if (priv->description) {
+		g_free (priv->description);
+		priv->description = NULL;
+	}
+
+	if (priv->down) {
+		g_object_unref (priv->down);
+		priv->down = NULL;
+	}
+
+	if (priv->forward) {
+		g_object_unref (priv->forward);
+		priv->forward = NULL;
+	}
+
+	if (priv->mstream) {
+		g_object_unref (priv->mstream);
+		priv->mstream = NULL;
+	}
+
+	if (priv->snoop_mime_type) {
+		g_free (priv->snoop_mime_type);
+		priv->snoop_mime_type = NULL;
+	}
+
+	if (priv->view_part_id) {
+		g_free (priv->view_part_id);
+		priv->view_part_id = NULL;
+	}
+
+	g_mutex_unlock (priv->mutex);
+	g_mutex_free (priv->mutex);
+}
+
+static void
+em_part_attachment_class_init (EMPartAttachmentClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EMPartAttachmentPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = em_part_attachment_finalize;
+}
+
+static void
+em_part_attachment_init (EMPartAttachment *empa)
+{
+	empa->priv = G_TYPE_INSTANCE_GET_PRIVATE (empa,
+			EM_TYPE_PART_ATTACHMENT, EMPartAttachmentPrivate);
+
+	empa->priv->attachment = NULL;
+	empa->priv->description = NULL;
+	empa->priv->down = NULL;
+	empa->priv->forward = NULL;
+	empa->priv->mstream = NULL;
+	empa->priv->shown = FALSE;
+	empa->priv->snoop_mime_type = NULL;
+	empa->priv->view_part_id = NULL;
+	empa->priv->handler = NULL;
+	
+	empa->priv->mutex = g_mutex_new ();	
+}
+
+EMPart*
+em_part_attachment_new (EMFormat *emf,
+			CamelMimePart *part,
+			const gchar *uri,
+			EMPartWriteFunc write_func)
+{
+	EMPart *emp;
+
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+	g_return_val_if_fail ((part == NULL) || (CAMEL_IS_MIME_PART (part)), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	emp = (EMPart *) g_object_new (EM_TYPE_PART_ATTACHMENT, NULL);
+	em_part_set_formatter (emp, emf);
+	em_part_set_mime_part (emp, part);
+	em_part_set_uri (emp, uri);
+	em_part_set_write_func (emp, write_func);
+
+	return emp;
+}
+
+void
+em_part_attachment_set_snoop_mime_type (EMPartAttachment *empa,
+					const gchar *snoop_mime_type)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (empa->priv->snoop_mime_type)
+		g_free (empa->priv->snoop_mime_type);
+
+	if (snoop_mime_type)
+		empa->priv->snoop_mime_type = g_strdup (snoop_mime_type);
+	else
+		empa->priv->snoop_mime_type = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gchar*
+em_part_attachment_get_snoop_mime_part (EMPartAttachment *empa)
+{
+	gchar *mime_type = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->snoop_mime_type)
+		mime_type = g_strdup (empa->priv->snoop_mime_type);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return mime_type;
+}
+
+void
+em_part_attachment_set_forward_widget (EMPartAttachment *empa,
+				       GtkWidget *forward)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+	g_return_if_fail ((forward == NULL) || GTK_IS_WIDGET (forward));
+
+	g_mutex_lock (empa->priv->mutex);
+	
+	if (forward)
+		g_object_ref (forward);
+
+	if (empa->priv->forward)
+		g_object_unref (empa->priv->forward);
+
+	if (forward)
+		empa->priv->forward = forward;
+	else
+		empa->priv->forward = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GtkWidget*
+em_part_attachment_get_forward_widget (EMPartAttachment *empa)
+{
+	GtkWidget *widget = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->down)
+		widget = g_object_ref (empa->priv->down);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return widget;
+}
+
+
+void 
+em_part_attachment_set_down_widget (EMPartAttachment *empa,
+				    GtkWidget *down)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+	g_return_if_fail ((down == NULL) || GTK_IS_WIDGET (down));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (down)
+		g_object_ref (down);
+
+	if (empa->priv->down)
+		g_object_unref (empa->priv->down);
+
+	if (down)
+		empa->priv->down = down;
+	else
+		empa->priv->down = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GtkWidget*
+em_part_attachment_get_down_widget (EMPartAttachment *empa)
+{
+	GtkWidget *widget = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->down)
+		widget = g_object_ref (empa->priv->down);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return widget;
+}
+
+void
+em_part_attachment_set_is_shown (EMPartAttachment *empa,
+				 gboolean is_shown)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+	empa->priv->shown = is_shown;
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gboolean
+em_part_attachment_get_is_shown (EMPartAttachment *empa)
+{
+	gboolean is_shown;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), FALSE);
+
+	g_mutex_lock (empa->priv->mutex);
+	is_shown = empa->priv->shown;
+	g_mutex_unlock (empa->priv->mutex);
+
+	return is_shown;
+}
+
+void
+em_part_attachment_set_attachment (EMPartAttachment *empa,
+				   EAttachment *attachment)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+	g_return_if_fail ((attachment == NULL) || E_IS_ATTACHMENT (attachment));
+
+	if (attachment)
+		g_object_ref (attachment);
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (empa->priv->attachment)
+		g_object_unref (empa->priv->attachment);
+
+	if (attachment)
+		empa->priv->attachment = attachment;
+	else
+		empa->priv->attachment = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+EAttachment*
+em_part_attachment_get_attachment (EMPartAttachment *empa)
+{
+	EAttachment *attachment = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->mutex)
+		attachment = g_object_ref (empa->priv->attachment);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return attachment;
+}
+
+void
+em_part_attachment_set_view_part_id (EMPartAttachment *empa,
+				     const gchar *view_part_id)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (empa->priv->view_part_id)
+		g_free (empa->priv->view_part_id);
+
+	if (view_part_id)
+		empa->priv->view_part_id = g_strdup (view_part_id);
+	else
+		empa->priv->view_part_id = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gchar*
+em_part_attachment_get_view_part_id (EMPartAttachment *empa)
+{
+	gchar *view_part_id = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+	
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->view_part_id)
+		view_part_id = g_strdup (view_part_id);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return view_part_id;	
+}
+
+void
+em_part_attachment_set_description (EMPartAttachment *empa,
+				    const gchar *description)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (empa->priv->description)
+		g_free (empa->priv->description);
+
+	if (description)
+		empa->priv->description = g_strdup (description);
+	else
+		empa->priv->description = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gchar*
+em_part_attachment_get_description (EMPartAttachment *empa)
+{
+	gchar *description = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->description)
+		description = g_strdup (empa->priv->description);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return description;
+}
+
+void 
+em_part_attachment_set_mstream (EMPartAttachment *empa,
+				CamelStream *mstream)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+	g_return_if_fail ((mstream == NULL) || CAMEL_IS_STREAM (mstream));
+
+	g_mutex_lock (empa->priv->mutex);
+	if (mstream)
+		g_object_ref (mstream);
+
+	if (empa->priv->mstream)
+		g_object_unref (empa->priv->mstream);
+
+	empa->priv->mstream = mstream;
+		
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+CamelStream*
+em_part_attachment_get_mstream (EMPartAttachment *empa)
+{
+	CamelStream *stream = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->mstream)
+		stream = g_object_ref (empa->priv->mstream);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return stream;
+}
+
+void
+em_part_attachment_set_handler (EMPartAttachment *empa,
+				const EMFormatHandler *handler)
+{
+	g_return_if_fail (EM_IS_PART_ATTACHMENT (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+	empa->priv->handler = handler;
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+const EMFormatHandler*
+em_part_attachment_get_handler (EMPartAttachment *empa)
+{
+	const EMFormatHandler *handler;
+
+	g_return_val_if_fail (EM_IS_PART_ATTACHMENT (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	handler = empa->priv->handler;
+	g_mutex_unlock (empa->priv->mutex);
+
+	return handler;
+}
+
+
+
+/******************************************************************************/
+
+struct _EMPartSMIMEPrivate {
+	gchar *description;
+	gint signature;
+	GtkWidget *widget;
+
+	GMutex *mutex;
+};
+
+G_DEFINE_TYPE (EMPartSMIME, em_part_smime, EM_TYPE_PART);
+
+
+static void
+em_part_smime_finalize (GObject *object)
+{
+	EMPartSMIMEPrivate *priv = EM_PART_SMIME (object)->priv;
+	
+	g_mutex_lock (priv->mutex);
+	
+	if (priv->description) {
+		g_free (priv->description);
+		priv->description = NULL;
+	}
+
+	if (priv->widget) {
+		g_object_unref (priv->widget);
+		priv->widget = NULL;
+	}
+	
+	g_mutex_unlock (priv->mutex);
+	g_mutex_free (priv->mutex);
+}
+
+static void
+em_part_smime_class_init (EMPartSMIMEClass *klass)
+{
+	GObjectClass *object_class;
+	
+	g_type_class_add_private (klass, sizeof (EMPartSMIMEPrivate));
+	
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = em_part_smime_finalize;
+}
+
+static void
+em_part_smime_init (EMPartSMIME *emps)
+{
+	emps->priv = G_TYPE_INSTANCE_GET_PRIVATE (emps,
+			EM_TYPE_PART_SMIME, EMPartSMIMEPrivate);
+	
+	emps->priv->description = NULL;
+	emps->priv->signature = 0;
+	emps->priv->widget = NULL;
+	
+	emps->priv->mutex = g_mutex_new ();	
+}
+
+EMPart*
+em_part_smime_new (EMFormat *emf,
+		   CamelMimePart *part,
+		   const gchar *uri,
+		   EMPartWriteFunc write_func)
+{
+	EMPart *emp;
+
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+	g_return_val_if_fail ((part == NULL) || CAMEL_IS_MIME_PART (part), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	emp = (EMPart *) g_object_new (EM_TYPE_PART_SMIME, NULL);
+	em_part_set_formatter (emp, emf);
+	em_part_set_mime_part (emp, part);
+	em_part_set_uri (emp, uri);
+	em_part_set_write_func (emp, write_func);
+
+	return emp;
+}
+
+void
+em_part_smime_set_description (EMPartSMIME *emps,
+			       const gchar *description)
+{
+	g_return_if_fail (EM_IS_PART_SMIME (emps));
+
+	g_mutex_lock (emps->priv->mutex);
+
+	if (emps->priv->description)
+		g_free (emps->priv->description);
+
+	if (description)
+		emps->priv->description = g_strdup (description);
+	else
+		emps->priv->description = NULL;
+
+	g_mutex_unlock (emps->priv->mutex);
+}
+
+gchar*
+em_part_smime_get_description (EMPartSMIME *emps)
+{
+	gchar *description = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_SMIME (emps), NULL);
+
+	g_mutex_lock (emps->priv->mutex);
+	if (emps->priv->description)
+		description = g_strdup (emps->priv->description);
+	g_mutex_unlock (emps->priv->mutex);
+
+	return description;
+}
+
+void
+em_part_smime_set_signature (EMPartSMIME *emps,
+			     gint signature)
+{
+	g_return_if_fail (EM_IS_PART_SMIME (emps));
+
+	g_mutex_lock (emps->priv->mutex);
+	emps->priv->signature = signature;
+	g_mutex_unlock (emps->priv->mutex);
+}
+
+gint
+em_part_smime_get_signature (EMPartSMIME *emps)
+{
+	gint signature;
+
+	g_return_val_if_fail (EM_IS_PART_SMIME (emps), 0);
+
+	g_mutex_lock (emps->priv->mutex);
+	signature = emps->priv->signature;
+	g_mutex_unlock (emps->priv->mutex);
+
+	return signature;
+}
+
+void
+em_part_smime_set_widget (EMPartSMIME *emps,
+			  GtkWidget *widget)
+{
+	g_return_if_fail (EM_IS_PART_SMIME (emps));
+	g_return_if_fail ((widget == NULL) || GTK_IS_WIDGET (widget));
+
+	if (widget)
+		g_object_ref (widget);
+
+	g_mutex_lock (emps->priv->mutex);
+
+	if (emps->priv->widget)
+		g_object_unref (emps->priv->widget);
+
+	emps->priv->widget = widget;
+
+	g_mutex_unlock (emps->priv->mutex);
+}
+
+GtkWidget*
+em_part_smime_get_widget (EMPartSMIME *emps)
+{
+	GtkWidget *widget = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_SMIME (emps), NULL);
+
+	g_mutex_lock (emps->priv->mutex);
+	if (emps->priv->widget)
+		widget = g_object_ref (emps->priv->widget);
+	g_mutex_unlock (emps->priv->mutex);
+
+	return widget;
+}
diff --git a/mail/em-format-html-display-parts.h b/mail/em-format-html-display-parts.h
new file mode 100644
index 0000000..78967d0
--- /dev/null
+++ b/mail/em-format-html-display-parts.h
@@ -0,0 +1,242 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EM_FORMAT_HTML_DISPLAY_PARTS_H
+#define EM_FORMAT_HTML_DISPLAY_PARTS_H
+
+#include <em-format/em-part.h>
+#include <widgets/misc/e-attachment-store.h>
+#include <widgets/misc/e-attachment.h>
+#include <camel/camel.h>
+#include <gtk/gtk.h>
+
+
+/* Standard GObject macros */
+#define EM_TYPE_PART_ATTACHMENT_BAR \
+	(em_part_attachment_bar_get_type ())
+#define EM_PART_ATTACHMENT_BAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), EM_TYPE_PART_ATTACHMENT_BAR, EMPartAttachmentBar))
+#define EM_PART_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), EM_TYPE_PART_ATTACHMENT_BAR, EMPartAttachmentBarClass))
+#define EM_IS_PART_ATTACHMENT_BAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), EM_TYPE_PART_ATTACHMENT_BAR))
+#define EM_IS_PART_ATTACHMENT_BAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), EM_TYPE_PART_ATTACHMENT_BAR))
+#define EM_PART_ATTACHMENT_BAR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), EM_TYPE_PART_ATTACHMENT_BAR, EMPartAttachmentBarClass))
+
+G_BEGIN_DECLS	
+	
+typedef struct _EMPartAttachmentBar EMPartAttachmentBar;
+typedef struct _EMPartAttachmentBarClass EMPartAttachmentBarClass;
+typedef struct _EMPartAttachmentBarPrivate EMPartAttachmentBarPrivate;
+
+struct _EMPartAttachmentBar {
+	EMPart parent;
+	EMPartAttachmentBarPrivate *priv;
+};
+
+struct _EMPartAttachmentBarClass {
+	EMPartClass parent_class;
+};
+
+EMPart*			em_part_attachment_bar_new 
+					(EMFormat *emf,
+					 CamelMimePart *part,
+					 const gchar *uri,
+					 EMPartWriteFunc write_func);
+
+GType			em_part_attachment_bar_get_type ();
+
+void			em_part_attachment_bar_set_store
+					(EMPartAttachmentBar *empab,
+					 EAttachmentStore *store);
+
+EAttachmentStore*	em_part_attachment_bar_get_store
+					(EMPartAttachmentBar *empab);
+
+G_END_DECLS
+
+/******************************************************************************/
+
+/* Standard GObject macros */
+#define EM_TYPE_PART_ATTACHMENT \
+	(em_part_attachment_get_type ())
+#define EM_PART_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), EM_TYPE_PART_ATTACHMENT, EMPartAttachment))
+#define EM_PART_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), EM_TYPE_PART_ATTACHMENT, EMPartAttachmentClass))
+#define EM_IS_PART_ATTACHMENT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), EM_TYPE_PART_ATTACHMENT))
+#define EM_IS_PART_ATTACHMENT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), EM_TYPE_PART_ATTACHMENT))
+#define EM_PART_ATTACHMENT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), EM_TYPE_PART_ATTACHMENT, EMPartAttachmentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMPartAttachment EMPartAttachment;
+typedef struct _EMPartAttachmentClass EMPartAttachmentClass;
+typedef struct _EMPartAttachmentPrivate EMPartAttachmentPrivate;
+
+struct _EMPartAttachment {
+	EMPart parent;
+	EMPartAttachmentPrivate *priv;
+};
+
+struct _EMPartAttachmentClass {
+	EMPartClass parent_class;
+};
+
+EMPart*			em_part_attachment_new (EMFormat *emf,
+						CamelMimePart *part,
+					     	const gchar *uri,
+					     	EMPartWriteFunc write_func);
+
+GType			em_part_attachment_get_type ();
+
+void			em_part_attachment_set_snoop_mime_type
+						(EMPartAttachment *empa,
+						 const gchar *snoop_mime_type);
+gchar*			em_part_attachment_get_snoop_mime_part
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_forward_widget
+						(EMPartAttachment *empa,
+						 GtkWidget *forward);
+GtkWidget*		em_part_attachment_get_forward_widget
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_down_widget
+						(EMPartAttachment *empa,
+						 GtkWidget *down);
+GtkWidget*		em_part_attachment_get_down_widget
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_is_shown
+						(EMPartAttachment *empa,
+						 gboolean is_shown);
+gboolean		em_part_attachment_get_is_shown
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_attachment
+						(EMPartAttachment *empa,
+						 EAttachment *attachment);
+EAttachment*		em_part_attachment_get_attachment
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_view_part_id
+						(EMPartAttachment *empa,
+						 const gchar *view_part_id);
+gchar*			em_part_attachment_get_view_part_id
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_description
+						(EMPartAttachment *empa,
+						 const gchar *description);
+gchar*			em_part_attachment_get_description
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_mstream
+						(EMPartAttachment *empa,
+						 CamelStream *mstream);
+CamelStream*		em_part_attachment_get_mstream
+						(EMPartAttachment *empa);
+
+void			em_part_attachment_set_handler
+						(EMPartAttachment *empa,
+						 const EMFormatHandler *handler);
+
+const EMFormatHandler*	em_part_attachment_get_handler
+						(EMPartAttachment *empa);
+
+G_END_DECLS
+
+/******************************************************************************/
+
+/* Standard GObject macros */
+#define EM_TYPE_PART_SMIME \
+	(em_part_smime_get_type ())
+#define EM_PART_SMIME(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), EM_TYPE_PART_SMIME, EMPartSMIME))
+#define EM_PART_SMIME_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), EM_TYPE_PART_SMIME, EMPartSMIMEClass))
+#define EM_IS_PART_SMIME(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), EM_TYPE_PART_SMIME))
+#define EM_IS_PART_SMIME_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), EM_TYPE_PART_SMIME))
+#define EM_PART_SMIME_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), EM_TYPE_PART_SMIME, EMPartSMIMEClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMPartSMIME EMPartSMIME;
+typedef struct _EMPartSMIMEClass EMPartSMIMEClass;
+typedef struct _EMPartSMIMEPrivate EMPartSMIMEPrivate;
+
+struct _EMPartSMIME {
+	EMPart parent;
+	EMPartSMIMEPrivate *priv;
+};
+
+struct _EMPartSMIMEClass {
+	EMPartClass parent_class;
+};
+
+EMPart*			em_part_smime_new 
+					(EMFormat *emf,
+					 CamelMimePart *part,
+				  	 const gchar *uri,
+				  	 EMPartWriteFunc write_func);
+
+GType			em_part_smime_get_type ();
+
+void			em_part_smime_set_description
+					(EMPartSMIME *emps,
+					 const gchar *description);
+gchar*			em_part_smime_get_description
+					(EMPartSMIME *emps);
+
+void			em_part_smime_set_signature
+					(EMPartSMIME *emps,
+					 gint signature);
+gint			em_part_smime_get_signature
+					(EMPartSMIME *emps);
+
+void			em_part_smime_set_widget
+					(EMPartSMIME *emps,
+					 GtkWidget *widget);
+GtkWidget*		em_part_smime_get_widget
+					(EMPartSMIME *emps);
+
+G_END_DECLS
+
+#endif /* EM_FORMAT_HTML_DISPLAY_PARTS_H */
\ No newline at end of file
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index e989019..130b4bd 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -60,6 +60,7 @@
 #include "e-mail-display.h"
 #include "e-mail-attachment-bar.h"
 #include "em-format-html-display.h"
+#include "em-format-html-display-parts.h"
 #include "em-utils.h"
 #include "widgets/misc/e-attachment.h"
 #include "widgets/misc/e-attachment-button.h"
@@ -113,11 +114,10 @@ static void efhd_parse_attachment	(EMFormat *emf, CamelMimePart *part, GString *
 static void efhd_parse_secure		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 static void efhd_parse_optional		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 
-static GtkWidget* efhd_attachment_bar		(EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable);
-static GtkWidget* efhd_attachment_button	(EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable);
-static GtkWidget* efhd_attachment_optional	(EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable);
+static GtkWidget* efhd_attachment_bar		(EMFormat *emf, EMPart *emp, GCancellable *cancellable);
+static GtkWidget* efhd_attachment_button	(EMFormat *emf, EMPart *emp, GCancellable *cancellable);
+static GtkWidget* efhd_attachment_optional	(EMFormat *emf, EMPart *emp, GCancellable *cancellable);
 
-static void efhd_free_attach_puri_data (EMFormatPURI *puri);
 static void efhd_builtin_init (EMFormatHTMLDisplayClass *efhc);
 
 static gpointer parent_class;
@@ -126,7 +126,7 @@ static EAttachmentStore*
 find_parent_attachment_store (EMFormatHTMLDisplay *efhd, GString *part_id)
 {
 	EMFormat *emf = (EMFormat *) efhd;
-	EMFormatAttachmentBarPURI *abp;
+        EMPartAttachmentBar *empab;
 	gchar *tmp, *pos;
         GList *item;
 
@@ -151,55 +151,27 @@ find_parent_attachment_store (EMFormatHTMLDisplay *efhd, GString *part_id)
 
 	g_free (tmp);
 
-	abp = (EMFormatAttachmentBarPURI *) item->data;
+	empab = item->data;
 
-        if (abp)
-	        return abp->store;
+        if (empab)
+	        return em_part_attachment_bar_get_store (empab);
         else
                 return NULL;
 }
 
 static void
-efhd_attachment_bar_puri_free (EMFormatPURI *puri)
-{
-	EMFormatAttachmentBarPURI *abp;
-
-	abp = (EMFormatAttachmentBarPURI *) puri;
-
-	if (abp->store) {
-		g_object_unref (abp->store);
-		abp->store = NULL;
-	}
-}
-
-static void
-efhd_xpkcs7mime_free (EMFormatPURI *puri)
-{
-	EMFormatSMIMEPURI *sp = (EMFormatSMIMEPURI *) puri;
-
-	if (sp->widget)
-		gtk_widget_destroy (sp->widget);
-
-	if (sp->description)
-		g_free (sp->description);
-
-	if (sp->valid)
-		camel_cipher_validity_free (sp->valid);
-}
-
-static void
 efhd_xpkcs7mime_info_response (GtkWidget *widget,
                                guint button,
-                               EMFormatSMIMEPURI *po)
+                               EMPartSMIME *emps)
 {
 	gtk_widget_destroy (widget);
-	po->widget = NULL;
+	em_part_smime_set_widget (emps, NULL);
 }
 
 #if defined (HAVE_NSS) && defined (ENABLE_SMIME)
 static void
 efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
-                                  EMFormatSMIMEPURI *po)
+                                  EMPartSMIME *emps)
 {
 	CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info");
 	ECert *ec = NULL;
@@ -209,6 +181,7 @@ efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
 
 	if (ec != NULL) {
 		GtkWidget *w = certificate_viewer_show (ec);
+		GtkWidget *widget;
 
 		/* oddly enough certificate_viewer_show doesn't ... */
 		gtk_widget_show (w);
@@ -216,8 +189,12 @@ efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
 			w, "response",
 			G_CALLBACK (gtk_widget_destroy), NULL);
 
-		if (w && po->widget)
-			gtk_window_set_transient_for ((GtkWindow *) w, (GtkWindow *) po->widget);
+		widget = em_part_smime_get_widget (emps);
+		if (w && widget)
+			gtk_window_set_transient_for ((GtkWindow *) w, (GtkWindow *) widget);
+
+		if (widget)
+			g_object_unref (widget);
 
 		g_object_unref (ec);
 	} else {
@@ -229,7 +206,7 @@ efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
 static void
 efhd_xpkcs7mime_add_cert_table (GtkWidget *grid,
                                 GQueue *certlist,
-                                EMFormatSMIMEPURI *po)
+                                EMPartSMIME *emps)
 {
 	GList *head, *link;
 	GtkTable *table;
@@ -291,31 +268,39 @@ efhd_xpkcs7mime_add_cert_table (GtkWidget *grid,
 
 static void
 efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
-                                  EMFormatPURI *puri)
+                                  EMPartSMIME *emps)
 {
-	EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri;
 	GtkBuilder *builder;
 	GtkWidget *grid, *w;
+	GtkWidget *part_widget;
+	CamelCipherValidity *validity;
 
-	if (po->widget)
+	part_widget = em_part_smime_get_widget (emps);
+	if (part_widget) {
+		g_object_unref (part_widget);
 		/* FIXME: window raise? */
 		return;
+	}
+
+	validity = em_part_get_validity ((EMPart *) emps);
 
 	builder = gtk_builder_new ();
 	e_load_ui_builder_definition (builder, "mail-dialogs.ui");
 
-	po->widget = e_builder_get_widget(builder, "message_security_dialog");
+	part_widget = e_builder_get_widget(builder, "message_security_dialog");
+	em_part_smime_set_widget (emps, part_widget);
 
 	grid = e_builder_get_widget(builder, "signature_grid");
-	w = gtk_label_new (_(smime_sign_table[po->valid->sign.status].description));
+	w = gtk_label_new (_(smime_sign_table[validity->sign.status].description));
 	gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
 	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
 	gtk_container_add (GTK_CONTAINER (grid), w);
-	if (po->valid->sign.description) {
+	if (validity->sign.description) {
 		GtkTextBuffer *buffer;
 
 		buffer = gtk_text_buffer_new (NULL);
-		gtk_text_buffer_set_text (buffer, po->valid->sign.description, strlen (po->valid->sign.description));
+		gtk_text_buffer_set_text (buffer, validity->sign.description, 
+			strlen (validity->sign.description));
 		w = g_object_new (gtk_scrolled_window_get_type (),
 				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
 				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
@@ -335,20 +320,21 @@ efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
 	}
 
 	if (!g_queue_is_empty (&po->valid->sign.signers))
-		efhd_xpkcs7mime_add_cert_table (grid, &po->valid->sign.signers, po);
+		efhd_xpkcs7mime_add_cert_table (grid, &validity->sign.signers, emps);
 
 	gtk_widget_show_all (grid);
 
 	grid = e_builder_get_widget(builder, "encryption_grid");
-	w = gtk_label_new (_(smime_encrypt_table[po->valid->encrypt.status].description));
+	w = gtk_label_new (_(smime_encrypt_table[validity->encrypt.status].description));
 	gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
 	gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
 	gtk_container_add (GTK_CONTAINER (grid), w);
-	if (po->valid->encrypt.description) {
+	if (validity->encrypt.description) {
 		GtkTextBuffer *buffer;
 
 		buffer = gtk_text_buffer_new (NULL);
-		gtk_text_buffer_set_text (buffer, po->valid->encrypt.description, strlen (po->valid->encrypt.description));
+		gtk_text_buffer_set_text (buffer, validity->encrypt.description,
+			strlen (validity->encrypt.description));
 		w = g_object_new (gtk_scrolled_window_get_type (),
 				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
 				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
@@ -368,38 +354,47 @@ efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
 	}
 
 	if (!g_queue_is_empty (&po->valid->encrypt.encrypters))
-		efhd_xpkcs7mime_add_cert_table (grid, &po->valid->encrypt.encrypters, po);
+		efhd_xpkcs7mime_add_cert_table (grid, 
+			&validity->encrypt.encrypters, emps);
 
 	gtk_widget_show_all (grid);
 
 	g_object_unref (builder);
 
 	g_signal_connect (
-		po->widget, "response",
-		G_CALLBACK (efhd_xpkcs7mime_info_response), po);
+	        part_widget, "response", 
+		G_CALLBACK(efhd_xpkcs7mime_info_response), emps);
+	gtk_widget_show (part_widget);
 
-	gtk_widget_show (po->widget);
+	g_object_unref (part_widget);
+	camel_cipher_validity_free (validity);
 }
 
 static GtkWidget*
 efhd_xpkcs7mime_button (EMFormat *emf,
-                        EMFormatPURI *puri,
+                        EMPart *emp,
                         GCancellable *cancellable)
 {
 	GtkWidget *box, *button, *layout, *widget;
-	EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri;
+	EMPartSMIME *emps = (EMPartSMIME *) emp;
 	const gchar *icon_name;
+	gchar *description;
+	CamelCipherValidity *validity;
+
+	validity = em_part_get_validity (emp);
+	if (!validity)
+		return NULL;
 
 	/* FIXME: need to have it based on encryption and signing too */
-	if (po->valid->sign.status != 0)
-		icon_name = smime_sign_table[po->valid->sign.status].icon;
+	if (validity->sign.status != 0)
+		icon_name = smime_sign_table[validity->sign.status].icon;
 	else
-		icon_name = smime_encrypt_table[po->valid->encrypt.status].icon;
+		icon_name = smime_encrypt_table[validity->encrypt.status].icon;
 
 	box = gtk_event_box_new ();
-	if (po->valid->sign.status != 0)
+	if (validity->sign.status != 0)
 		gtk_widget_override_background_color (box, GTK_STATE_FLAG_NORMAL,
-			&smime_sign_colour[po->valid->sign.status]);
+			&smime_sign_colour[validity->sign.status]);
 
 	layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
 	gtk_container_add (GTK_CONTAINER (box), layout);
@@ -407,17 +402,21 @@ efhd_xpkcs7mime_button (EMFormat *emf,
 	button = gtk_button_new ();
 	gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0);
 	g_signal_connect (button, "clicked",
-		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), puri);
+		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), emp);
 
 	widget = gtk_image_new_from_icon_name (
 			icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
 	gtk_button_set_image (GTK_BUTTON (button), widget);
 
-	widget = gtk_label_new (po->description);
+	description = em_part_smime_get_description (emps);
+	widget = gtk_label_new (description);
 	gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0);
 
 	gtk_widget_show_all (box);
 
+	g_free (description);
+	camel_cipher_validity_free (validity);
+
 	return box;
 }
 
@@ -465,8 +464,9 @@ efhd_parse_attachment (EMFormat *emf,
 {
 	gchar *text, *html;
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
-	EMFormatAttachmentPURI *puri;
+	EMPartAttachment *empa;
 	EAttachmentStore *store;
+	EAttachment *attachment;
 	const EMFormatHandler *handler;
 	CamelContentType *ct;
 	gchar *mime_type;
@@ -496,39 +496,46 @@ efhd_parse_attachment (EMFormat *emf,
 	g_free (text);
 	g_free (mime_type);
 
-	puri = (EMFormatAttachmentPURI*) em_format_puri_new (
-			emf, sizeof (EMFormatAttachmentPURI), part, part_id->str);
-	puri->puri.free = efhd_free_attach_puri_data;
-	puri->puri.widget_func = efhd_attachment_button;
-	puri->shown = (handler && em_format_is_inline (emf, part_id->str, part, handler));
-	puri->snoop_mime_type = em_format_snoop_type (part);
-	puri->attachment = e_attachment_new ();
-	puri->attachment_view_part_id = g_strdup (part_id->str);
-	puri->description = html;
-	puri->handle = handler;
-        if (info->validity)
-                puri->puri.validity = camel_cipher_validity_clone (info->validity);
+        attachment = e_attachment_new ();
+        empa = EM_PART_ATTACHMENT (em_part_attachment_new (emf, part, 
+                        part_id->str, NULL));
+        em_part_set_widget_func ((EMPart *) empa, efhd_attachment_button);
+        em_part_attachment_set_is_shown (empa, 
+                (handler && em_format_is_inline (emf, part_id->str, part, handler)));
+        em_part_attachment_set_snoop_mime_type (empa, em_format_snoop_type (part));
+	em_part_attachment_set_attachment (empa, attachment);
+        em_part_attachment_set_view_part_id (empa, part_id->str);
+        em_part_attachment_set_description (empa, html);
+	em_part_attachment_set_handler (empa, handler);
+        em_part_set_validity ((EMPart *) empa, info->validity);
 
 	cid = camel_mime_part_get_content_id (part);
-	if (cid)
-		puri->puri.cid = g_strdup_printf ("cid:%s", cid);
+	if (cid) {
+                gchar *new_cid = g_strdup_printf ("cid:%s", cid);
+                em_part_set_cid ((EMPart *) empa, new_cid);
+		g_free (new_cid);
+        }
 
 	if (handler) {
                 CamelContentType *ct;
-                puri->puri.write_func = handler->write_func;
+                em_part_set_write_func ((EMPart *) empa, handler->write_func);
 
                 /* This mime_type is important for WebKit to determine content type.
                  * We have converted text/ * to text/html, other (binary) formats remained
                  * untouched. */
                 ct = camel_content_type_decode (handler->mime_type);
                 if (g_strcmp0 (ct->type, "text") == 0)
-                        puri->puri.mime_type = g_strdup ("text/html");
-                else
-                        puri->puri.mime_type = camel_content_type_simple (ct);
+                        em_part_set_mime_type ((EMPart *) empa, "text/html");
+                else {
+                        gchar *ct_s = camel_content_type_simple (ct);
+                        em_part_set_mime_type ((EMPart *) empa, ct_s);
+                        g_free (ct_s);
+                }
+
                 camel_content_type_unref (ct);
         }
 
-	em_format_add_puri (emf, (EMFormatPURI *) puri);
+        em_format_add_part_object (emf, (EMPart *) empa);
 
         /* Though it is an attachment, we still might be able to parse it and
          * so discover some parts that we might be event able to display. */
@@ -537,34 +544,34 @@ efhd_parse_attachment (EMFormat *emf,
              (handler->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION))) {
                 EMFormatParserInfo attachment_info = { .handler = handler,
                                                        .is_attachment = TRUE };
-                handler->parse_func (emf, puri->puri.part, part_id, &attachment_info, cancellable);
+                handler->parse_func (emf, part, part_id, &attachment_info, cancellable);
         }
 
-	e_attachment_set_mime_part (puri->attachment, part);
-	e_attachment_set_shown (puri->attachment, puri->shown);
-        if (puri->puri.validity) {
-	        e_attachment_set_signed (puri->attachment, puri->puri.validity->sign.status);
-	        e_attachment_set_encrypted (puri->attachment, puri->puri.validity->encrypt.status);
+	e_attachment_set_mime_part (attachment, part);
+	e_attachment_set_shown (attachment, em_part_attachment_get_is_shown (empa));
+        if (info->validity) {
+	        e_attachment_set_signed (attachment, info->validity->sign.status);
+	        e_attachment_set_encrypted (attachment, info->validity->encrypt.status);
         }
-	e_attachment_set_can_show (puri->attachment, puri->handle != NULL && puri->handle->write_func);
+	e_attachment_set_can_show (attachment, handler != NULL && handler->write_func);
 
 	store = find_parent_attachment_store (efhd, part_id);
-	e_attachment_store_add_attachment (store, puri->attachment);
+	e_attachment_store_add_attachment (store, attachment);
 
 	if (emf->folder && emf->folder->summary && emf->message_uid) {
-                CamelDataWrapper *dw = camel_medium_get_content (CAMEL_MEDIUM (puri->puri.part));
+                CamelDataWrapper *dw = camel_medium_get_content (CAMEL_MEDIUM (part));
                 GByteArray *ba;
                 ba = camel_data_wrapper_get_byte_array (dw);
                 if (ba) {
                         size = ba->len;
 
-                        if (camel_mime_part_get_encoding (puri->puri.part) == CAMEL_TRANSFER_ENCODING_BASE64)
+                        if (camel_mime_part_get_encoding (part) == CAMEL_TRANSFER_ENCODING_BASE64)
                                 size = size / 1.37;
                 }
 	}
 
 	load_data = g_new0 (struct attachment_load_data, 1);
-	load_data->attachment = g_object_ref (puri->attachment);
+	load_data->attachment = g_object_ref (attachment);
 	load_data->flag = e_flag_new ();
 
         e_flag_clear (load_data->flag);
@@ -581,9 +588,9 @@ efhd_parse_attachment (EMFormat *emf,
 	if (size != 0) {
 		GFileInfo *fileinfo;
 
-		fileinfo = e_attachment_get_file_info (puri->attachment);
+		fileinfo = e_attachment_get_file_info (attachment);
 		g_file_info_set_size (fileinfo, size);
-		e_attachment_set_file_info (puri->attachment, fileinfo);
+		e_attachment_set_file_info (attachment, fileinfo);
 	}
 
 	g_string_truncate (part_id, len);
@@ -596,35 +603,42 @@ efhd_parse_optional (EMFormat *emf,
                      EMFormatParserInfo *info,
                      GCancellable *cancellable)
 {
-	EMFormatAttachmentPURI *puri;
+	EMPartAttachment *empa;
+	EAttachment *attachment;
+	CamelStream *stream;
         gint len;
 
         len = part_id->len;
         g_string_append (part_id, ".optional");
 
-	puri = (EMFormatAttachmentPURI *) em_format_puri_new (
-			emf, sizeof (EMFormatAttachmentPURI), part, part_id->str);
-	puri->puri.free = efhd_free_attach_puri_data;
-	puri->puri.widget_func = efhd_attachment_optional;
-	puri->attachment_view_part_id = g_strdup (part_id->str);
-	puri->handle = em_format_find_handler (emf, "text/plain");
-	puri->shown = FALSE;
-	puri->snoop_mime_type = "text/plain";
-	puri->attachment = e_attachment_new ();
-	e_attachment_set_mime_part (puri->attachment, puri->puri.part);
-	puri->description = g_strdup(_("Evolution cannot render this email as it is too "
-				       "large to process. You can view it unformatted or "
-				       "with an external text editor."));
+	attachment = e_attachment_new ();
+	empa = (EMPartAttachment *) em_part_attachment_new (
+			emf, part, part_id->str, NULL);
+	em_part_attachment_set_view_part_id (empa, part_id->str);
+	em_part_attachment_set_handler (empa, em_format_find_handler (emf, "text/plain"));
+	em_part_attachment_set_is_shown (empa, FALSE);
+	em_part_attachment_set_snoop_mime_type (empa, "text/plain");
+	em_part_attachment_set_attachment (empa, attachment);
+	em_part_set_widget_func ((EMPart *) empa, efhd_attachment_optional);
 	
-	puri->mstream = CAMEL_STREAM_MEM (camel_stream_mem_new ());
+	e_attachment_set_mime_part (attachment, part);
+	em_part_attachment_set_description (empa, 
+		N_("Evolution cannot render this email as it is too "
+		  "large to process. You can view it unformatted or "
+		  "with an external text editor."));
+	
+
+	stream = camel_stream_mem_new ();
+	em_part_attachment_set_mstream (empa, stream);	
+
 	camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) part, 
-		(CamelStream *) puri->mstream, cancellable, NULL);
+		(CamelStream *) stream, cancellable, NULL);
 
 	if (info->validity) {
-		puri->puri.validity = camel_cipher_validity_clone (info->validity);
+		em_part_set_validity ((EMPart *) empa, info->validity);
 	}
 
-	em_format_add_puri (emf, (EMFormatPURI *) puri);
+	em_format_add_part_object (emf, (EMPart *) empa);
 
 	g_string_truncate (part_id, len);
 }
@@ -640,15 +654,13 @@ efhd_parse_secure (EMFormat *emf,
 	    && (info->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
 		|| info->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
 		GString *buffer;
-		EMFormatSMIMEPURI *pobj;
+                EMPart *emp;
 
-		pobj = (EMFormatSMIMEPURI *) em_format_puri_new (
-				emf, sizeof (EMFormatSMIMEPURI), part, part_id->str);
-		pobj->puri.free = efhd_xpkcs7mime_free;
-		pobj->valid = camel_cipher_validity_clone (info->validity);
-		pobj->puri.widget_func = efhd_xpkcs7mime_button;
-
-		em_format_add_puri (emf, (EMFormatPURI*) pobj);
+                emp = em_part_smime_new (emf, part, part_id->str, NULL);
+                em_part_set_widget_func (emp, efhd_xpkcs7mime_button);
+                em_part_set_validity (emp, info->validity);
+		
+                em_format_add_part_object (emf, emp);
 
 		buffer = g_string_new ("");
 
@@ -677,7 +689,8 @@ efhd_parse_secure (EMFormat *emf,
 			g_string_append (buffer, gettext (desc));
 		}
 
-		pobj->description = g_string_free (buffer, FALSE);
+		em_part_smime_set_description ((EMPartSMIME *) emp, buffer->str);
+		g_string_free (buffer, TRUE);
 	}
 }
 
@@ -788,20 +801,25 @@ efhd_message_prefix (EMFormat *emf,
 	time_t date;
 	gchar *iconpath, *due_date_str;
 	GString *buffer;
-	EMFormatAttachmentPURI *puri;
+	EMPartAttachment *empa;
 
-	if (emf->folder == NULL || emf->message_uid == NULL
-	    || (flag = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "follow-up")) == NULL
-	    || flag[0] == 0)
+	if ((emf->folder == NULL) || (emf->message_uid == NULL)
+	    || ((flag = camel_folder_get_message_user_tag (emf->folder,
+				emf->message_uid, "follow-up")) == NULL)
+	    || (flag[0] == 0))
 		return;
 
-	puri = (EMFormatAttachmentPURI *) em_format_puri_new (
-			emf, sizeof (EMFormatAttachmentPURI), part, ".message_prefix");
-
-	puri->attachment_view_part_id = g_strdup (part_id->str);
+	empa = (EMPartAttachment *) em_part_attachment_new (
+			emf, part, ".message_prefix", NULL);
+	em_part_attachment_set_view_part_id (empa, part_id->str);
 
 	comp = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "completed-on");
-	iconpath = e_icon_factory_get_icon_filename (comp && comp[0] ? "stock_mail-flag-for-followup-done" : "stock_mail-flag-for-followup", GTK_ICON_SIZE_MENU);
+	iconpath = e_icon_factory_get_icon_filename (
+		comp && comp[0] ?
+			"stock_mail-flag-for-followup-done" :
+			"stock_mail-flag-for-followup", 
+		GTK_ICON_SIZE_MENU);
+
 	if (iconpath) {
 		gchar *classid;
 
@@ -810,7 +828,7 @@ efhd_message_prefix (EMFormat *emf,
 			part_id->str,
 			comp && comp[0] ? "comp" : "uncomp");
 
-		puri->puri.uri = classid;
+		em_part_set_uri ((EMPart *) empa, classid);
 
 		g_free (classid);
 	}
@@ -826,7 +844,8 @@ efhd_message_prefix (EMFormat *emf,
 			flag, _("Completed on"),
 			due_date_str ? due_date_str : "???");
 		g_free (due_date_str);
-	} else if ((due = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "due-by")) != NULL && due[0]) {
+	} else if ((due = camel_folder_get_message_user_tag (emf->folder, 
+			emf->message_uid, "due-by")) != NULL && due[0]) {
 		time_t now;
 
 		date = camel_header_decode_date (due, NULL);
@@ -850,7 +869,8 @@ efhd_message_prefix (EMFormat *emf,
 		g_string_append (buffer, flag);
 	}
 
-	puri->description = g_string_free (buffer, FALSE);
+	em_part_attachment_set_description (empa, buffer->str);
+	g_string_free (buffer, TRUE);
 }
 
 /* ********************************************************************** */
@@ -858,10 +878,11 @@ efhd_message_prefix (EMFormat *emf,
 /* attachment button callback */
 static GtkWidget*
 efhd_attachment_button (EMFormat *emf,
-			EMFormatPURI *puri,
+			EMPart *emp,
 			GCancellable *cancellable)
 {
-	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
+	EMPartAttachment *empa = (EMPartAttachment *) emp;
+	EAttachment *attachment;
 	GtkWidget *widget;
 
 	/* FIXME: handle default shown case */
@@ -870,29 +891,38 @@ efhd_attachment_button (EMFormat *emf,
 	if (g_cancellable_is_cancelled (cancellable))
 		return NULL;
 
-	if (!info || info->forward) {
+	widget = em_part_attachment_get_forward_widget (empa);
+	if (widget) {
 		g_warning ("unable to expand the attachment\n");
+		g_object_unref (widget);
 		return NULL;
 	}
+	g_object_unref (widget);
 
+	attachment = em_part_attachment_get_attachment (empa);
 	widget = e_attachment_button_new ();
 	e_attachment_button_set_attachment (
-		E_ATTACHMENT_BUTTON (widget), info->attachment);
+		E_ATTACHMENT_BUTTON (widget), attachment);
 	gtk_widget_set_can_focus (widget, TRUE);
 	gtk_widget_show (widget);
 
+	g_object_unref (attachment);
+
 	return widget;
 }
 
 static GtkWidget*
 efhd_attachment_bar (EMFormat *emf,
-		     EMFormatPURI *puri,
+		     EMPart *emp,
 		     GCancellable *cancellable)
 {
-	EMFormatAttachmentBarPURI *abp = (EMFormatAttachmentBarPURI *) puri;
+	EMPartAttachmentBar *empab = (EMPartAttachmentBar *) emp;
 	GtkWidget *widget;
+	EAttachmentStore *store;
 
-	widget = e_mail_attachment_bar_new (abp->store);
+	store = em_part_attachment_bar_get_store (empab);
+	widget = e_mail_attachment_bar_new (store);
+	g_object_unref (store);
 
 	return widget;
 }
@@ -904,7 +934,8 @@ efhd_message_add_bar (EMFormat *emf,
                       EMFormatParserInfo *info,
                       GCancellable *cancellable)
 {
-	EMFormatAttachmentBarPURI *puri;
+	EMPart *emp;
+	EAttachmentStore *store;
 	gint len;
 
 	if (g_cancellable_is_cancelled (cancellable))
@@ -912,15 +943,18 @@ efhd_message_add_bar (EMFormat *emf,
 
 	len = part_id->len;
 	g_string_append (part_id, ".attachment-bar");
-	puri = (EMFormatAttachmentBarPURI *) em_format_puri_new (
-			emf, sizeof (EMFormatAttachmentBarPURI), part, part_id->str);
-	puri->puri.widget_func = efhd_attachment_bar;
-	puri->puri.free = efhd_attachment_bar_puri_free;
-	puri->store = E_ATTACHMENT_STORE (e_attachment_store_new ());
 
-	em_format_add_puri (emf, (EMFormatPURI*) puri);
+        store = E_ATTACHMENT_STORE (e_attachment_store_new ());
+
+        emp = em_part_attachment_bar_new (emf, part, part_id->str, NULL);
+        em_part_set_widget_func (emp, efhd_attachment_bar);
+        em_part_attachment_bar_set_store ((EMPartAttachmentBar *) emp, store);
+        em_format_add_part_object (emf, emp);
 
 	g_string_truncate (part_id, len);
+
+        /* Store is now owned only by the EMPart */
+        g_object_unref (store);
 }
 
 static void
@@ -942,7 +976,7 @@ efhd_optional_button_show (GtkWidget *widget,
 /* optional render attachment button callback */
 static GtkWidget*
 efhd_attachment_optional (EMFormat *efh,
-			  EMFormatPURI *puri,
+			  EMPart *emp,
 			  GCancellable *cancellable)
 {
 	GtkWidget *hbox, *vbox, *button, *mainbox, *scroll, *label, *img;
@@ -950,7 +984,9 @@ efhd_attachment_optional (EMFormat *efh,
 	GtkWidget *view;
 	GtkTextBuffer *buffer;
 	GByteArray *byte_array;
-	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
+	EMPartAttachment *empa = (EMPartAttachment *) emp;
+	const EMFormatHandler *handler;
+	CamelStream *stream;
 
 	if (g_cancellable_is_cancelled (cancellable))
 		return NULL;
@@ -958,10 +994,13 @@ efhd_attachment_optional (EMFormat *efh,
 	/* FIXME: handle default shown case */
 	d(printf("adding attachment button/content for optional rendering\n"));
 
-	if (!info || info->forward) {
+	button = em_part_attachment_get_forward_widget (empa);
+	if (button) {
 		g_warning ("unable to expand the attachment\n");
+		g_object_unref (button);
 		return NULL;
 	}
+	g_object_unref (button);
 
 	scroll = gtk_scrolled_window_new (NULL, NULL);
 	mainbox = gtk_hbox_new (FALSE, 0);
@@ -976,7 +1015,9 @@ efhd_attachment_optional (EMFormat *efh,
 	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2);
 	gtk_widget_show_all (hbox);
 	gtk_container_add (GTK_CONTAINER (button), GTK_WIDGET (hbox));
-	if (info->handle)
+
+	handler = em_part_attachment_get_handler (empa);
+	if (handler)
 		g_signal_connect (
 			button, "clicked",
 			G_CALLBACK (efhd_optional_button_show), scroll);
@@ -1013,11 +1054,14 @@ efhd_attachment_optional (EMFormat *efh,
 	gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-	byte_array = camel_stream_mem_get_byte_array (info->mstream);
+
+	stream = em_part_attachment_get_mstream (empa);
+	byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
 	gtk_text_buffer_set_text (
 		buffer, (gchar *) byte_array->data, byte_array->len);
-	g_object_unref (info->mstream);
-	info->mstream = NULL;
+	g_object_unref (stream);
+	em_part_attachment_set_mstream (empa, NULL);
+
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
 					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
@@ -1025,39 +1069,12 @@ efhd_attachment_optional (EMFormat *efh,
 	gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 6);
 	gtk_widget_show (GTK_WIDGET (view));
 
-	if (!info->shown)
+	if (!em_part_attachment_get_is_shown (empa))
 		gtk_widget_hide (scroll);
 
 	gtk_widget_show (vbox);
-	info->handle = NULL;
 
-	return view;
-}
-
-static void
-efhd_free_attach_puri_data (EMFormatPURI *puri)
-{
-	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
-
-	g_return_if_fail (puri != NULL);
-
-	if (info->attachment) {
-		g_object_unref (info->attachment);
-		info->attachment = NULL;
-	}
+	em_part_attachment_set_handler (empa, NULL);
 
-	if (info->description) {
-		g_free (info->description);
-		info->description = NULL;
-	}
-
-	if (info->attachment_view_part_id) {
-		g_free (info->attachment_view_part_id);
-		info->attachment_view_part_id = NULL;
-	}
-
-	if (info->mstream) {
-		g_object_unref (info->mstream);
-		info->mstream = NULL;
-	}
+	return view;
 }
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index cf3cac4..52d95e0 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -52,52 +52,6 @@ G_BEGIN_DECLS
 typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay;
 typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass;
 typedef struct _EMFormatHTMLDisplayPrivate EMFormatHTMLDisplayPrivate;
-typedef struct _EMFormatAttachmentBarPURI EMFormatAttachmentBarPURI;
-typedef struct _EMFormatAttachmentPURI EMFormatAttachmentPURI;
-typedef struct _EMFormatSMIMEPURI EMFormatSMIMEPURI;
-
-struct _EMFormatAttachmentBarPURI {
-	EMFormatPURI puri;
-
-	EAttachmentStore *store;
-};
-
-struct _EMFormatAttachmentPURI {
-	EMFormatPURI puri;
-
-	const EMFormatHandler *handle;
-
-	const gchar *snoop_mime_type;
-
-	/* for the > and V buttons */
-	GtkWidget *forward, *down;
-	guint shown:1;
-
-	/* Attachment */
-	EAttachment *attachment;
-	gchar *attachment_view_part_id;
-	gchar *description;
-
-	/* image stuff */
-	gint fit_width;
-	gint fit_height;
-	GtkImage *image;
-	GtkWidget *event_box;
-
-	/* Optional Text Mem Stream */
-	CamelStreamMem *mstream;
-};
-
-struct _EMFormatSMIMEPURI {
-	EMFormatPURI puri;
-
-	gchar *description;
-
-	gint signature;
-	CamelCipherValidity *valid;
-	GtkWidget *widget;
-};
-
 
 struct _EMFormatHTMLDisplay {
 	EMFormatHTML parent;
diff --git a/mail/em-format-html-print.c b/mail/em-format-html-print.c
index f968ede..a86e7fb 100644
--- a/mail/em-format-html-print.c
+++ b/mail/em-format-html-print.c
@@ -31,6 +31,7 @@
 
 #include "em-format-html-print.h"
 #include "em-format-html-display.h"
+#include "em-format-html-display-parts.h"
 #include "e-mail-attachment-bar.h"
 #include <e-util/e-print.h>
 #include <e-util/e-util.h>
@@ -39,14 +40,15 @@
 
 #include "em-format-html-print.h"
 
+
 static gpointer parent_class = NULL;
 
 struct _EMFormatHTMLPrintPrivate {
 
 	EMFormatHTML *original_formatter;
-	EMFormatPURI *top_level_puri;
+	EMPart *top_level_part;
 
-        /* List of attachment PURIs */
+        /* List of attachment EMParts */
         GList *attachments;
 
 };
@@ -56,9 +58,9 @@ enum {
 	PROP_ORIGINAL_FORMATTER
 };
 
-static void efhp_write_print_layout	(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efhp_write_headers		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efhp_write_inline_attachment(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efhp_write_print_layout	(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efhp_write_headers		(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efhp_write_inline_attachment(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
 
 static void
 efhp_write_attachments_list (EMFormatHTMLPrint *efhp,
@@ -79,17 +81,20 @@ efhp_write_attachments_list (EMFormatHTMLPrint *efhp,
                 _("Attachments"), _("Name"), _("Size"));
 
         for (iter = efhp->priv->attachments; iter; iter = iter->next) {
-                EMFormatPURI *puri = iter->data;
+                EMPart *emp = iter->data;
                 EAttachment *attachment;
                 GFileInfo *fi;
                 gchar *name, *size;
                 GByteArray *ba;
                 CamelDataWrapper *dw;
+		CamelMimePart *part;
 
-                attachment = ((EMFormatAttachmentPURI *) puri)->attachment;
+                attachment = em_part_attachment_get_attachment (EM_PART_ATTACHMENT (emp));
                 fi = e_attachment_get_file_info (attachment);
-                if (!fi)
+                if (!fi) {
+			g_object_unref (attachment);
                         continue;
+		}
 
                 if (e_attachment_get_description (attachment) &&
                     *e_attachment_get_description (attachment)) {
@@ -100,7 +105,8 @@ efhp_write_attachments_list (EMFormatHTMLPrint *efhp,
                         name = g_strdup (g_file_info_get_display_name (fi));
                 }
 
-                dw = camel_medium_get_content ((CamelMedium *) puri->part);
+                part = em_part_get_mime_part (emp);
+                dw = camel_medium_get_content ((CamelMedium *) part);
                 ba = camel_data_wrapper_get_byte_array (dw);
                 size = g_format_size (ba->len);
 
@@ -109,6 +115,9 @@ efhp_write_attachments_list (EMFormatHTMLPrint *efhp,
 
                 g_free (name);
                 g_free (size);
+
+		g_object_unref (attachment);
+		g_object_unref (part);
         }
 
         g_string_append (str, "</table>\n");
@@ -119,7 +128,7 @@ efhp_write_attachments_list (EMFormatHTMLPrint *efhp,
 
 static void
 efhp_write_headers (EMFormat *emf,
-		    EMFormatPURI *puri,
+		    EMPart *emp,
 		    CamelStream *stream,
 		    EMFormatWriterInfo *info,
 		    GCancellable *cancellable)
@@ -128,12 +137,17 @@ efhp_write_headers (EMFormat *emf,
 	GString *str, *tmp;
 	gchar *subject;
 	const gchar *buf;
-	EMFormatPURI *p;
+	EMPart *p;
 	GList *iter;
 	gint attachments_count;
         gchar *puri_prefix;
+	CamelMimePart *part;
+	gchar *uri;
+
+	part = em_part_get_mime_part (emp);
+	buf = camel_medium_get_header (CAMEL_MEDIUM (part), "subject");
+	g_object_unref (part);
 
-	buf = camel_medium_get_header (CAMEL_MEDIUM (puri->part), "subject");
 	subject = camel_header_decode_string (buf, "UTF-8");
 	str = g_string_new ("<table border=\"0\" cellspacing=\"5\" " \
                             "cellpadding=\"0\" class=\"printing-header\">\n");
@@ -153,7 +167,7 @@ efhp_write_headers (EMFormat *emf,
 		if (header->value && *header->value) {
 			raw_header.value = header->value;
 			em_format_html_format_header (emf, str,
-				CAMEL_MEDIUM (puri->part), &raw_header,
+				CAMEL_MEDIUM (part), &raw_header,
 				header->flags | EM_FORMAT_HTML_HEADER_NOLINKS,
 				"UTF-8");
 		} else {
@@ -162,7 +176,7 @@ efhp_write_headers (EMFormat *emf,
 
 			if (raw_header.value && *raw_header.value) {
 				em_format_html_format_header (emf, str,
-					CAMEL_MEDIUM (puri->part), &raw_header,
+					CAMEL_MEDIUM (part), &raw_header,
 					header->flags | EM_FORMAT_HTML_HEADER_NOLINKS,
 					"UTF-8");
 			}
@@ -172,40 +186,51 @@ efhp_write_headers (EMFormat *emf,
 		}
 	}
 
-        /* Get prefix of this PURI */
-        puri_prefix = g_strndup (puri->uri, g_strrstr (puri->uri, ".") - puri->uri);
+        /* Get prefix of this EMPart */
+	uri = em_part_get_uri (emp);
+        puri_prefix = g_strndup (uri, g_strrstr (uri, ".") - uri);
+	g_free (uri);
 
 	/* Add encryption/signature header */
 	raw_header.name = _("Security");
 	tmp = g_string_new ("");
 	/* Find first secured part. */
-	for (iter = emf->mail_part_list, puri; iter; iter = iter->next) {
+	for (iter = emf->mail_part_list, emp; iter; iter = iter->next) {
+
+		gint32 validity_type;
+		gchar *uri;
 
 		p = iter->data;
 
-                if (p->validity_type == 0)
+		validity_type = em_part_get_validity_type (p);
+
+                if (validity_type == 0)
                         continue;
 
-                if (!g_str_has_prefix (p->uri, puri_prefix))
+		uri = em_part_get_uri (p);
+                if (!g_str_has_prefix (uri, puri_prefix)) {
+			g_free (uri);
                         continue;
+		}
+		g_free (uri);
 
-		if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) &&
-		    (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) {
+		if ((validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) &&
+		    (validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) {
 			g_string_append (tmp, _("GPG signed"));
 		}
-		if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) &&
-		    (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) {
+		if ((validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) &&
+		    (validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) {
 			if (tmp->len > 0) g_string_append (tmp, ", ");
 			g_string_append (tmp, _("GPG encrpyted"));
 		}
-		if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) &&
-		    (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) {
+		if ((validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) &&
+		    (validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) {
 
 			if (tmp->len > 0) g_string_append (tmp, ", ");
 			g_string_append (tmp, _("S/MIME signed"));
 		}
-		if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) &&
-		    (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) {
+		if ((validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) &&
+		    (validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) {
 
 			if (tmp->len > 0) g_string_append (tmp, ", ");
 			g_string_append (tmp, _("S/MIME encrpyted"));
@@ -214,11 +239,19 @@ efhp_write_headers (EMFormat *emf,
 		break;
 	}
 
+	if (!p) {
+                g_free (puri_prefix);
+		g_string_free (str, TRUE);
+		return;
+	}
+
+	part = em_part_get_mime_part (p);
 	if (tmp->len > 0) {
 		raw_header.value = tmp->str;
-		em_format_html_format_header (emf, str, CAMEL_MEDIUM (p->part),
+		em_format_html_format_header (emf, str, CAMEL_MEDIUM (part),
 			&raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8");
 	}
+	g_object_unref (p);
 	g_string_free (tmp, TRUE);
 
 	/* Count attachments and display the number as a header */
@@ -226,21 +259,31 @@ efhp_write_headers (EMFormat *emf,
 
 	for (iter = emf->mail_part_list; iter; iter = iter->next) {
 
+		gchar *uri;
+
 		p = iter->data;
 
-                if (!g_str_has_prefix (p->uri, puri_prefix))
+		uri = em_part_get_uri (p);
+                if (!g_str_has_prefix (uri, puri_prefix)) {
+			g_free (uri);
                         continue;
+		}
 
-		if (p->is_attachment || g_str_has_suffix(p->uri, ".attachment"))
+		if (em_part_get_is_attachment (p) || g_str_has_suffix(uri, ".attachment"))
 			attachments_count++;
+
+		g_free (uri);
 	}
+
+	part = em_part_get_mime_part (emp);	
 	if (attachments_count > 0) {
 		raw_header.name = _("Attachments");
 		raw_header.value = g_strdup_printf ("%d", attachments_count);
-		em_format_html_format_header (emf, str, CAMEL_MEDIUM (puri->part),
+		em_format_html_format_header (emf, str, CAMEL_MEDIUM (part),
 			&raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8");
 		g_free (raw_header.value);
 	}
+	g_object_unref (part);
 
 	g_string_append (str, "</table>");
 
@@ -251,17 +294,17 @@ efhp_write_headers (EMFormat *emf,
 
 static void
 efhp_write_inline_attachment (EMFormat *emf,
-                              EMFormatPURI *puri,
+                              EMPart *emp,
                               CamelStream *stream,
                               EMFormatWriterInfo *info,
                               GCancellable *cancellable)
 {
         gchar *name;
-        EMFormatAttachmentPURI *att_puri = (EMFormatAttachmentPURI *) puri;
+	EMPartAttachment *empa = (EMPartAttachment *) emp;
         EAttachment *attachment;
         GFileInfo *fi;
 
-        attachment = att_puri->attachment;
+        attachment = em_part_attachment_get_attachment (empa);
         fi = e_attachment_get_file_info (attachment);
 
         if (e_attachment_get_description (attachment) &&
@@ -276,13 +319,14 @@ efhp_write_inline_attachment (EMFormat *emf,
 
         camel_stream_write_string (stream, name, cancellable, NULL);
         g_free (name);
+	g_object_unref (attachment);
 
-        puri->write_func (emf, puri, stream, info, cancellable);
+	em_part_write (emp, stream, info, cancellable);
 }
 
 static void
 efhp_write_print_layout (EMFormat *emf,
-			 EMFormatPURI *puri,
+			 EMPart *emp,
 			 CamelStream *stream,
 			 EMFormatWriterInfo *info,
 			 GCancellable *cancellable)
@@ -305,46 +349,58 @@ efhp_write_print_layout (EMFormat *emf,
 
 	for (iter = emf->mail_part_list; iter != NULL; iter = iter->next) {
 
-		EMFormatPURI *puri = iter->data;
+		EMPart *p = iter->data;
+		gchar *uri;
 
-		if (g_str_has_suffix (puri->uri, "print_layout"))
+		uri = em_part_get_uri (p);
+		if (g_str_has_suffix (uri, "print_layout")) {
+			g_free (uri);
 			continue;
+		}
 
 		/* To late to change .headers writer_func, do it manually. */
-		if (g_str_has_suffix (puri->uri, ".headers")) {
-			efhp_write_headers (emf, puri, stream, info, cancellable);
+		if (g_str_has_suffix (uri, ".headers")) {
+			efhp_write_headers (emf, emp, stream, info, cancellable);
+			g_free (uri);
 			continue;
 		}
 
-		if (puri->is_attachment || g_str_has_suffix (puri->uri, ".attachment")) {
+		if (em_part_get_is_attachment (p) || g_str_has_suffix (uri, ".attachment")) {
 			const EMFormatHandler *handler;
+			CamelMimePart *part;
+			CamelContentType *ct;
+			gchar *mime_type;
 
-			CamelContentType *ct = camel_mime_part_get_content_type (puri->part);
-			gchar *mime_type = camel_content_type_simple (ct);
+			part = em_part_get_mime_part (p);
+			ct = camel_mime_part_get_content_type (part);
+			mime_type = camel_content_type_simple (ct);			
 
-			handler = em_format_find_handler (puri->emf, mime_type);
-                        g_message ("Handler for PURI %s (%s): %s", puri->uri, mime_type,
+			handler = em_format_find_handler (emf, mime_type);
+                        g_message ("Handler for EMPart %s (%s): %s", uri, mime_type,
                                  handler ? handler->mime_type : "(null)");
                         g_free (mime_type);
 
                         efhp->priv->attachments =
-                                g_list_append (efhp->priv->attachments, puri);
+                                g_list_append (efhp->priv->attachments, emp);
 
 			/* If we can't inline this attachment, skip it */
-			if (handler && puri->write_func) {
-                                efhp_write_inline_attachment (puri->emf, puri,
+			if (handler && em_part_get_write_func (p)) {
+                                efhp_write_inline_attachment (emf, emp,
                                         stream, &print_info, cancellable);
                         }
 
+                        g_free (uri);
                         continue;
 		}
 
+		g_free (uri);
+
 		/* Ignore widget parts and unwritable non-attachment parts */
-                if (puri->write_func == NULL)
+                if (em_part_get_write_func (p) == NULL)
                         continue;
 
                 /* Passed all tests, probably a regular part - display it */
-                puri->write_func(puri->emf, puri, stream, &print_info, cancellable);
+		em_part_write (emp, stream, &print_info, cancellable);
 
         }
 
@@ -364,9 +420,9 @@ efhp_finalize (GObject *object)
 		efhp->priv->original_formatter = NULL;
 	}
 
-	if (efhp->priv->top_level_puri) {
-		em_format_puri_free (efhp->priv->top_level_puri);
-		efhp->priv->top_level_puri = NULL;
+	if (efhp->priv->top_level_part) {
+		g_object_unref (efhp->priv->top_level_part);
+		efhp->priv->top_level_part = NULL;
 	}
 
 	if (efhp->priv->attachments) {
@@ -393,7 +449,7 @@ efhp_set_orig_formatter (EMFormatHTMLPrint *efhp,
 		    	 EMFormat *formatter)
 {
 	EMFormat *emfp, *emfs;
-	EMFormatPURI *puri;
+	EMPart *emp;
 	GHashTableIter iter;
 	gpointer key, value;
 
@@ -404,29 +460,31 @@ efhp_set_orig_formatter (EMFormatHTMLPrint *efhp,
 
 	emfp->mail_part_list = g_list_copy (emfs->mail_part_list);
 
-	/* Make a shallow copy of the table. This table will NOT destroy
-	 * the PURIs when free'd! */
+	/* Make a shallow copy of the table. */
         if (emfp->mail_part_table)
                 g_hash_table_unref (emfp->mail_part_table);
 
-	emfp->mail_part_table = g_hash_table_new (g_str_hash, g_str_equal);
+	emfp->mail_part_table = g_hash_table_new_full 
+		(g_str_hash, g_str_equal, g_free, g_object_unref);
 	g_hash_table_iter_init (&iter, emfs->mail_part_table);
-	while (g_hash_table_iter_next (&iter, &key, &value))
-		g_hash_table_insert (emfp->mail_part_table, key, value);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		GList *item = value;
+		g_hash_table_insert (emfp->mail_part_table, 
+			g_strdup ((gchar *) key), g_object_ref (item->data));
+	}
 
         if (emfs->folder)
 	        emfp->folder = g_object_ref (emfs->folder);
 	emfp->message_uid = g_strdup (emfs->message_uid);
 	emfp->message = g_object_ref (emfs->message);
 
-	/* Add a generic PURI that will write a HTML layout
+	/* Add a generic EMPart that will write a HTML layout
 	   for all the parts */
-	puri = em_format_puri_new (EM_FORMAT (efhp),
-		sizeof (EMFormatPURI), NULL, "print_layout");
-	puri->write_func = efhp_write_print_layout;
-	puri->mime_type = g_strdup ("text/html");
-	em_format_add_puri (EM_FORMAT (efhp), puri);
-	efhp->priv->top_level_puri = puri;
+	emp = em_part_new (emfp, NULL, "print_layout", efhp_write_print_layout);
+	em_part_set_mime_type (emp, "text/html");
+	em_format_add_part_object (emfp, emp);
+
+	efhp->priv->top_level_part = g_object_ref (emp);
 }
 
 static EMFormatHandler type_builtin_table[] = {
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 1ff57a3..034d585 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -66,7 +66,9 @@
 #include "em-format-html.h"
 #include "em-utils.h"
 #include "e-mail-display.h"
+
 #include <em-format/em-inline-filter.h>
+#include <em-format/em-part.h>
 
 #define EM_FORMAT_HTML_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -121,16 +123,16 @@ static void efh_parse_message_external		(EMFormat *emf, CamelMimePart *part, GSt
 static void efh_parse_message_deliverystatus	(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 static void efh_parse_message_rfc822		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 
-static void efh_write_image			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_text_enriched		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_text_plain		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_text_html			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_source			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_headers			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_attachment		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
-static void efh_write_error			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_image			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_text_enriched		(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_text_plain		(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_text_html			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_source			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_headers			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_attachment		(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
+static void efh_write_error			(EMFormat *emf, EMPart *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable);
 
-static GtkWidget* efh_widget_message_rfc822     (EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable);
+static GtkWidget* efh_widget_message_rfc822     (EMFormat *emf, EMPart *emp, GCancellable *cancellable);
 
 static void efh_format_full_headers 		(EMFormatHTML *efh, GString *buffer, CamelMedium *part, gboolean all_headers, gboolean visible, GCancellable *cancellable);
 static void efh_format_short_headers 		(EMFormatHTML *efh, GString *buffer, CamelMedium *part, gboolean visible, GCancellable *cancellable);
@@ -138,14 +140,17 @@ static void efh_format_short_headers 		(EMFormatHTML *efh, GString *buffer, Came
 /*****************************************************************************/
 static GtkWidget*
 efh_widget_message_rfc822 (EMFormat* emf,
-                           EMFormatPURI* puri,
+                           EMPart *emp,
                            GCancellable* cancellable)
 {
         EMailDisplay *display;
         gchar *msg_uri;
+	gchar *uri;
 
+	uri = em_part_get_uri (emp);
         msg_uri = em_format_build_mail_uri (emf->folder, emf->message_uid,
-                "part_id", G_TYPE_STRING, puri->uri, NULL);
+                "part_id", G_TYPE_STRING, uri, NULL);
+	g_free (uri);
 
         display = g_object_new (E_TYPE_MAIL_DISPLAY, NULL);
         e_mail_display_set_formatter (display, EM_FORMAT_HTML (emf));
@@ -165,7 +170,7 @@ efh_parse_image (EMFormat *emf,
 		 EMFormatParserInfo *info,
 		 GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	const gchar *tmp;
 	gchar *cid;
 	gint len;
@@ -176,23 +181,26 @@ efh_parse_image (EMFormat *emf,
 
 	tmp = camel_mime_part_get_content_id (part);
 	if (!tmp) {
-		em_format_parse_part_as (emf, part, part_id, info, "x-evolution/message/attachment", cancellable);
+		em_format_parse_part_as (emf, part, part_id, info,
+                        "x-evolution/message/attachment", cancellable);
 		return;
 	}
 
 	cid = g_strdup_printf ("cid:%s", tmp);
 	len = part_id->len;
 	g_string_append (part_id, ".image");
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->cid = cid;
-	puri->write_func = efh_write_image;
-	puri->mime_type = g_strdup (info->handler->mime_type);
-	puri->is_attachment = TRUE;
-	puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-	puri->validity_type = info->validity_type;
-
-	em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, efh_write_image);
+	em_part_set_cid (emp, cid);
+	em_part_set_mime_type (emp, info->handler->mime_type);
+	em_part_set_is_attachment (emp, TRUE);
+	em_part_set_validity_type (emp, info->validity_type);
+	em_part_set_validity (emp, info->validity);
+
+	em_format_add_part_object (emf, emp);
+
 	g_string_truncate (part_id, len);
+
+	g_free (cid);
 }
 
 static void
@@ -202,7 +210,7 @@ efh_parse_text_enriched (EMFormat *emf,
 			 EMFormatParserInfo *info,
 			 GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	const gchar *tmp;
 	gchar *cid;
 	gint len;
@@ -219,16 +227,18 @@ efh_parse_text_enriched (EMFormat *emf,
 
 	len = part_id->len;
 	g_string_append (part_id, ".text_enriched");
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->cid = cid;
-	puri->mime_type = g_strdup (info->handler->mime_type);
-	puri->write_func = efh_write_text_enriched;
-	puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-	puri->validity_type = info->validity_type;
-        puri->is_attachment = info->is_attachment;
-
-	em_format_add_puri (emf, puri);
+
+	emp = em_part_new (emf, part, part_id->str, efh_write_text_enriched);
+	em_part_set_cid (emp, cid);
+	em_part_set_mime_type (emp, info->handler->mime_type);
+	em_part_set_is_attachment (emp, info->is_attachment);
+	em_part_set_validity_type (emp, info->validity_type);
+	em_part_set_validity (emp, info->validity);
+
+	em_format_add_part_object (emf, emp);
+
 	g_string_truncate (part_id, len);
+	g_free (cid);
 }
 
 static void
@@ -238,7 +248,7 @@ efh_parse_text_plain (EMFormat *emf,
 		      EMFormatParserInfo *info,
 		      GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	CamelStream *filtered_stream, *null;
 	CamelMultipart *mp;
 	CamelDataWrapper *dw;
@@ -317,14 +327,15 @@ efh_parse_text_plain (EMFormat *emf,
 			gint s_len = part_id->len;
 
 			g_string_append (part_id, ".plain_text");
-			puri = em_format_puri_new (emf, sizeof (EMFormatPURI), newpart, part_id->str);
-			puri->write_func = efh_write_text_plain;
-			puri->mime_type = g_strdup ("text/html");
-			puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-			puri->validity_type = info->validity_type;
-                        puri->is_attachment = info->is_attachment;
+
+			emp = em_part_new (emf, newpart, part_id->str, efh_write_text_plain);
+			em_part_set_mime_type (emp, "text/html");
+			em_part_set_is_attachment (emp, info->is_attachment);
+			em_part_set_validity_type (emp, info->validity_type);
+			em_part_set_validity (emp, info->validity);
+
 			g_string_truncate (part_id, s_len);
-			em_format_add_puri (emf, puri);
+			em_format_add_part_object (emf, emp);
 		} else {
 			g_string_append_printf (part_id, ".inline.%d", i);
 			em_format_parse_part (emf, CAMEL_MIME_PART (newpart), part_id, info, cancellable);
@@ -342,7 +353,7 @@ efh_parse_text_html (EMFormat *emf,
 		     EMFormatParserInfo *info,
 		     GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	const gchar *location;
 	gchar *cid = NULL;
 	CamelURL *base;
@@ -372,13 +383,15 @@ efh_parse_text_html (EMFormat *emf,
 
 	len = part_id->len;
 	g_string_append (part_id, ".text_html");
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = efh_write_text_html;
-	puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-	puri->validity_type = info->validity_type;
-        puri->is_attachment = info->is_attachment;
 
-	em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, efh_write_text_html);
+	em_part_set_is_attachment (emp, info->is_attachment);
+	em_part_set_validity_type (emp, info->validity_type);
+	em_part_set_validity (emp, info->validity);
+	em_part_set_cid (emp, cid);
+
+	em_format_add_part_object (emf, emp);
+
 	g_string_truncate (part_id, len);
 
 	if (cid)
@@ -392,7 +405,7 @@ efh_parse_message_external (EMFormat *emf,
 			    EMFormatParserInfo *info,
 			    GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	CamelMimePart *newpart;
 	CamelContentType *type;
 	const gchar *access_type;
@@ -494,11 +507,12 @@ fail:
 addPart:
 	len = part_id->len;
 	g_string_append (part_id, ".msg_external");
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = efh_write_text_html;
-	puri->mime_type = g_strdup ("text/html");
 
-	em_format_add_puri (emf, puri);
+	emp = em_part_new (emf, part, part_id->str, efh_write_text_html);
+	em_part_set_mime_type (emp, "text/html");
+
+	em_format_add_part_object (emf, emp);
+
 	g_string_truncate (part_id, len);
 }
 
@@ -509,7 +523,7 @@ efh_parse_message_deliverystatus (EMFormat *emf,
 				  EMFormatParserInfo *info,
 				  GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
+	EMPart *emp;
 	gint len;
 
 	if (g_cancellable_is_cancelled (cancellable))
@@ -517,14 +531,15 @@ efh_parse_message_deliverystatus (EMFormat *emf,
 
 	len = part_id->len;
 	g_string_append (part_id, ".deliverystatus");
-	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-	puri->write_func = efh_write_source;
-	puri->mime_type = g_strdup ("text/html");
-	puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL;
-	puri->validity_type = info->validity_type;
-        puri->is_attachment = info->is_attachment;
-
-	em_format_add_puri (emf, puri);
+
+	emp = em_part_new (emf, part, part_id->str, efh_write_source);
+	em_part_set_mime_type (emp, "text/html");
+	em_part_set_is_attachment (emp, info->is_attachment);
+	em_part_set_validity_type (emp, info->validity_type);
+	em_part_set_validity (emp, info->validity);
+
+	em_format_add_part_object (emf, emp);
+
 	g_string_truncate (part_id, len);
 }
 
@@ -541,18 +556,21 @@ efh_parse_message_rfc822 (EMFormat *emf,
 	CamelMimeParser *parser;
 	gint len;
 	EMFormatParserInfo oinfo = *info;
-	EMFormatPURI *puri;
+	EMPart *emp;
 
 	len = part_id->len;
 	g_string_append (part_id, ".rfc822");
 
-        /* Create an empty PURI that will represent start of the RFC message */
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str);
-        puri->widget_func = efh_widget_message_rfc822;
-        puri->write_func = info->handler->write_func ? info->handler->write_func : em_format_empty_writer;
-        em_format_add_puri (emf, puri);
+        /* Create an empty EMPart that will represent start of the RFC message */
+	emp = em_part_new (emf, part, part_id->str, NULL);
+        em_part_set_widget_func (emp, efh_widget_message_rfc822);
+	em_part_set_write_func (emp, info->handler->write_func ? 
+		info->handler->write_func : 
+		em_format_empty_writer);
+	
+        em_format_add_part_object (emf, emp);
 
-        /* Now parse the message, creating multiple sub-PURIs */
+        /* Now parse the message, creating multiple sub-EMParts */
 	stream = camel_stream_mem_new ();
 	dw = camel_medium_get_content ((CamelMedium *) part);
 	camel_data_wrapper_write_to_stream_sync (dw, stream, cancellable, NULL);
@@ -567,14 +585,15 @@ efh_parse_message_rfc822 (EMFormat *emf,
 	em_format_parse_part_as (emf, opart, part_id, &oinfo,
 		"x-evolution/message", cancellable);
 
-        /* Add another generic PURI that represents end of the RFC message.
-         * This is required for every PURI that has EMailDisplay widget_func.
-         * The parent EMailDisplay then skips all PURIs between the ".rfc822" PURI
-         * ".rfc822.end" PURI (they were displayed by the child EMailDisplay called
-         * from ".rfc822"'s widget_func) and continues with the following PURI. */
+        /* Add another generic EMPart that represents end of the RFC message.
+         * This is required for every EMPart that has EMailDisplay widget_func.
+         * The parent EMailDisplay then skips all EMParts between the ".rfc822" EMPart
+         * ".rfc822.end" EMPart (they were displayed by the child EMailDisplay called
+         * from ".rfc822"'s widget_func) and continues with the following EMPart. */
         g_string_append (part_id, ".end");
-        puri = em_format_puri_new (emf, sizeof (EMFormatPURI), NULL, part_id->str);
-        em_format_add_puri (emf, puri);
+
+	emp = em_part_new (emf, NULL, part_id->str, NULL);
+	em_format_add_part_object (emf, emp);
 
 	g_string_truncate (part_id, len);
 
@@ -588,7 +607,7 @@ efh_parse_message_rfc822 (EMFormat *emf,
 
 static void
 efh_write_image (EMFormat *emf,
-		 EMFormatPURI *puri,
+		 EMPart *emp,
 		 CamelStream *stream,
  		 EMFormatWriterInfo *info,
 		 GCancellable *cancellable)
@@ -596,11 +615,15 @@ efh_write_image (EMFormat *emf,
 	gchar *content;
 	CamelDataWrapper *dw;
 	GByteArray *ba;
+	CamelMimePart *part;
 
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
+	part = em_part_get_mime_part (emp);
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+	g_object_unref (part);
+
 	g_return_if_fail (dw);
 
 	ba = camel_data_wrapper_get_byte_array (dw);
@@ -615,15 +638,21 @@ efh_write_image (EMFormat *emf,
 	   image. */
 	if (!info->with_html_header) {
 		gchar *buffer;
+		gchar *mime_type;
 
+		mime_type = em_part_get_mime_type (emp);
+                if (!mime_type)
+                        mime_type = g_strdup ("image/*");
 		/* The image is already base64-encrypted so we can directly
 		   paste it to the output */
 		buffer = g_strdup_printf ("<img src=\"data:%s;base64,%s\" style=\"max-width: 100%%;\" />",
-			puri->mime_type, content);
+			mime_type, content);
 
 		camel_stream_write_string (stream, buffer, cancellable, NULL);
 
 		g_free (buffer);
+		if (mime_type)
+			g_free (mime_type);
 
 	} else {
 
@@ -645,7 +674,7 @@ efh_write_image (EMFormat *emf,
 
 static void
 efh_write_text_enriched (EMFormat *emf,
-			 EMFormatPURI *puri,
+			 EMPart *emp,
 			 CamelStream *stream,
 			 EMFormatWriterInfo *info,
 			 GCancellable *cancellable)
@@ -656,12 +685,14 @@ efh_write_text_enriched (EMFormat *emf,
 	guint32 flags = 0;
 	GString *buffer;
 	CamelContentType *ct;
+	CamelMimePart *part;
 	gchar *mime_type = NULL;
 
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	ct = camel_mime_part_get_content_type (puri->part);
+	part = em_part_get_mime_part (emp);
+	ct = camel_mime_part_get_content_type (part);
 	if (ct) {
 		mime_type = camel_content_type_simple (ct);
 	}
@@ -710,24 +741,28 @@ efh_write_text_enriched (EMFormat *emf,
 
 	em_format_format_text (
 		emf, (CamelStream *) filtered_stream,
-		(CamelDataWrapper *) puri->part, cancellable);
+		(CamelDataWrapper *) part, cancellable);
 
 	g_object_unref (filtered_stream);
 	camel_stream_write_string (stream, "</div>", cancellable, NULL);
 
-	if (info->with_html_header)
+	if (info->with_html_header) {
 		camel_stream_write_string (stream, EFH_HTML_FOOTER,
 			cancellable, NULL);
+	}
+
+	g_object_unref (part);
 }
 
 static void
 efh_write_text_plain (EMFormat *emf,
-		      EMFormatPURI *puri,
+		      EMPart *emp,
 		      CamelStream *stream,
  		      EMFormatWriterInfo *info,
 		      GCancellable *cancellable)
 {
 	CamelDataWrapper *dw;
+	CamelMimePart *part;
 	CamelStream *filtered_stream;
 	CamelMimeFilter *html_filter;
 	EMFormatHTML *efh = (EMFormatHTML*) emf;
@@ -741,7 +776,8 @@ efh_write_text_plain (EMFormat *emf,
 
 	flags = efh->text_html_flags;
 
-	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
+	part = em_part_get_mime_part (emp);
+	dw = camel_medium_get_content (CAMEL_MEDIUM (part));
 
 	/* Check for RFC 2646 flowed text. */
 	if (camel_content_type_is(dw->mime_type, "text", "plain")
@@ -768,7 +804,7 @@ efh_write_text_plain (EMFormat *emf,
 			e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]));
 
 	camel_stream_write_string (stream, content, cancellable, NULL);
-	em_format_format_text (emf, filtered_stream, (CamelDataWrapper *) puri->part, cancellable);
+	em_format_format_text (emf, filtered_stream, (CamelDataWrapper *) part, cancellable);
 
 	g_object_unref (filtered_stream);
 	g_free (content);
@@ -777,21 +813,27 @@ efh_write_text_plain (EMFormat *emf,
 
 	if (info->with_html_header)
 		camel_stream_write_string (stream, EFH_HTML_FOOTER, cancellable, NULL);
+
+	g_object_unref (part);
 }
 
 static void
 efh_write_text_html (EMFormat *emf,
-		     EMFormatPURI *puri,
+		     EMPart *emp,
 		     CamelStream *stream,
 		     EMFormatWriterInfo *info,
 		     GCancellable *cancellable)
 {
+	CamelMimePart *part;
+
+	part = em_part_get_mime_part (emp);
+
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
 	if (info->with_html_header) {
 		em_format_format_text (emf, stream,
-			(CamelDataWrapper *) puri->part, cancellable);
+			(CamelDataWrapper *) part, cancellable);
 
 	} else {
 		CamelStream *format_stream;
@@ -801,7 +843,7 @@ efh_write_text_html (EMFormat *emf,
 
 		format_stream = camel_stream_mem_new ();
 		em_format_format_text (
-			emf, format_stream, (CamelDataWrapper *) puri->part, cancellable);
+			emf, format_stream, (CamelDataWrapper *) part, cancellable);
 
 		str  = g_string_new ("");
 		ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (format_stream));
@@ -828,11 +870,13 @@ efh_write_text_html (EMFormat *emf,
 
 		g_string_free (str, TRUE);
 	}
+
+	g_object_unref (part);
 }
 
 static void
 efh_write_source (EMFormat *emf,
-		  EMFormatPURI *puri,
+		  EMPart *emp,
 		  CamelStream *stream,
 		  EMFormatWriterInfo *info,
 		  GCancellable *cancellable)
@@ -841,7 +885,11 @@ efh_write_source (EMFormat *emf,
 	GString *buffer;
 	CamelStream *filtered_stream;
 	CamelMimeFilter *filter;
-	CamelDataWrapper *dw = (CamelDataWrapper *) puri->part;
+	CamelMimePart *part;
+	CamelDataWrapper *dw;
+
+	part = em_part_get_mime_part (emp);
+	dw = (CamelDataWrapper *) part;
 
 	filtered_stream = camel_stream_filter_new (stream);
 
@@ -879,21 +927,25 @@ efh_write_source (EMFormat *emf,
 		camel_stream_write_string (stream, EFH_HTML_FOOTER, cancellable, NULL);
 
 	g_object_unref (filtered_stream);
+	g_object_unref (part);	
 	g_string_free (buffer, TRUE);
 }
 
 static void
 efh_write_headers (EMFormat *emf,
-		   EMFormatPURI *puri,
+		   EMPart *emp,
 		   CamelStream *stream,
 		   EMFormatWriterInfo *info,
 		   GCancellable *cancellable)
 {
 	GString *buffer;
 	EMFormatHTML *efh = (EMFormatHTML *) emf;
+	CamelMimePart *part;
 	gint bg_color;
 
-	if (!puri->part)
+	part = em_part_get_mime_part (emp);
+
+	if (!part)
 		return;
 
 	buffer = g_string_new ("");
@@ -957,12 +1009,12 @@ efh_write_headers (EMFormat *emf,
 			EVOLUTION_IMAGESDIR,
 			(info->headers_collapsed) ? "plus.png" : "minus.png");
 
-		efh_format_short_headers (efh, buffer, (CamelMedium *) puri->part,
+		efh_format_short_headers (efh, buffer, (CamelMedium *) part,
 			info->headers_collapsed,
 			cancellable);
 	}
 
-	efh_format_full_headers (efh, buffer, (CamelMedium *) puri->part,
+	efh_format_full_headers (efh, buffer, (CamelMedium *) part,
 		(info->mode == EM_FORMAT_WRITE_MODE_ALL_HEADERS),
 		!info->headers_collapsed,
 		cancellable);
@@ -975,23 +1027,27 @@ efh_write_headers (EMFormat *emf,
 	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
 
 	g_string_free (buffer, true);
+
+	g_object_unref (part);
 }
 
 static void
 efh_write_error (EMFormat *emf,
-		 EMFormatPURI *puri,
+		 EMPart *emp,
 		 CamelStream *stream,
 		 EMFormatWriterInfo *info,
 		 GCancellable *cancellable)
 {
 	CamelStream *filtered_stream;
 	CamelMimeFilter *filter;
+	CamelMimePart *part;
 	CamelDataWrapper *dw;
 
 	if (info->with_html_header)
 		camel_stream_write_string (stream, EFH_HTML_HEADER, cancellable, NULL);
 
-	dw = camel_medium_get_content ((CamelMedium *) puri->part);
+	part = em_part_get_mime_part (emp);
+	dw = camel_medium_get_content ((CamelMedium *) part);
 
 	camel_stream_write_string (stream, "<em><font color=\"red\">", cancellable, NULL);
 
@@ -1009,6 +1065,8 @@ efh_write_error (EMFormat *emf,
 
 	if (info->with_html_header)
 		camel_stream_write_string (stream, EFH_HTML_FOOTER, cancellable, NULL);
+
+	g_object_unref (part);
 }
 
 /*****************************************************************************/
@@ -1261,18 +1319,21 @@ efh_finalize (GObject *object)
 
 static void
 efh_write_attachment (EMFormat *emf,
-					  EMFormatPURI *puri,
-					  CamelStream *stream,
-					  EMFormatWriterInfo *info,
+		      EMPart *emp,
+		      CamelStream *stream,
+		      EMFormatWriterInfo *info,
                       GCancellable *cancellable)
 {
 	gchar *text, *html;
 	CamelContentType *ct;
+	CamelMimePart *part;
 	gchar *mime_type;
 	const EMFormatHandler *handler;
 
 	/* we display all inlined attachments only */
 
+	part = em_part_get_mime_part (emp);
+
 	/* this could probably be cleaned up ... */
 	camel_stream_write_string (
 		stream,
@@ -1283,11 +1344,11 @@ efh_write_attachment (EMFormat *emf,
 		"<tr><td></td></tr></table></td><td><font size=-1>\n",
 		cancellable, NULL);
 
-	ct = camel_mime_part_get_content_type (puri->part);
+	ct = camel_mime_part_get_content_type (part);
 	mime_type = camel_content_type_simple (ct);
 
 	/* output some info about it */
-	text = em_format_describe_part (puri->part, mime_type);
+	text = em_format_describe_part (part, mime_type);
 	html = camel_text_to_html (
 		text, ((EMFormatHTML *) emf)->text_html_flags &
 		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
@@ -1300,11 +1361,14 @@ efh_write_attachment (EMFormat *emf,
 
 	handler = em_format_find_handler (emf, mime_type);
 	if (handler && handler->write_func && handler->write_func != efh_write_attachment) {
-		if (em_format_is_inline (emf, puri->uri, puri->part, handler))
-			handler->write_func (emf, puri, stream, info, cancellable);
+		gchar *uri = em_part_get_uri (emp);
+		if (em_format_is_inline (emf, uri, part, handler))
+			handler->write_func (emf, emp, stream, info, cancellable);
+		g_free (uri);
 	}
 
 	g_free (mime_type);
+	g_object_unref (part);
 }
 
 static void
@@ -2444,7 +2508,7 @@ efh_format_full_headers (EMFormatHTML *efh,
 		photopart = em_utils_contact_photo (cia, only_local_photo);
 
 		if (photopart) {
-			EMFormatPURI *puri;
+			EMPart *emp;
 			contact_has_photo = TRUE;
 			classid = "icon:///em-format-html/headers/photo";
 			g_string_append_printf (
@@ -2452,10 +2516,9 @@ efh_format_full_headers (EMFormatHTML *efh,
 				"<td align=\"right\" valign=\"top\">"
 				"<img width=64 src=\"%s\"></td>",
 				classid);
-			puri = em_format_puri_new (
-					emf, sizeof (EMFormatPURI), photopart, classid);
-			puri->write_func = efh_write_image;
-			em_format_add_puri (emf, puri);
+
+			emp = em_part_new (emf, photopart, classid, efh_write_image);
+			em_format_add_part_object (emf, emp);
 			g_object_unref (photopart);
 		}
 		g_object_unref (cia);
@@ -2464,7 +2527,7 @@ efh_format_full_headers (EMFormatHTML *efh,
 	if (!contact_has_photo && face_decoded) {
 		const gchar *classid;
 		CamelMimePart *part;
-		EMFormatPURI *puri;
+		EMPart *emp;
 
 		part = camel_mime_part_new ();
 		camel_mime_part_set_content (
@@ -2478,10 +2541,8 @@ efh_format_full_headers (EMFormatHTML *efh,
 			"<img width=48 src=\"%s\"></td>",
 			classid);
 
-		puri = em_format_puri_new (
-			emf, sizeof (EMFormatPURI), part, classid);
-		puri->write_func = efh_write_image;
-		em_format_add_puri (emf, puri);
+		emp = em_part_new (emf, part, classid, efh_write_image);
+		em_format_add_part_object (emf, emp);
 
 		g_object_unref (part);
 		g_free (face_header_value);
@@ -2491,7 +2552,7 @@ efh_format_full_headers (EMFormatHTML *efh,
 		GtkIconInfo *icon_info;
 		const gchar *classid;
 		CamelMimePart *iconpart = NULL;
-		EMFormatPURI *puri;
+		EMPart *emp;
 
 		classid = "icon:///em-format-html/header/icon";
 		g_string_append_printf (
@@ -2510,10 +2571,8 @@ efh_format_full_headers (EMFormatHTML *efh,
 			gtk_icon_info_free (icon_info);
 		}
 		if (iconpart) {
-			puri = em_format_puri_new (
-					emf, sizeof (EMFormatPURI), iconpart, classid);
-			puri->write_func = efh_write_image;
-			em_format_add_puri (emf, puri);
+			emp = em_part_new (emf, iconpart, classid, efh_write_image);
+			em_format_add_part_object (emf, emp);
 			g_object_unref (iconpart);
 		}
 	}
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index 689167f..170b2ae 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -56,7 +56,6 @@ G_BEGIN_DECLS
 typedef struct _EMFormatHTML EMFormatHTML;
 typedef struct _EMFormatHTMLClass EMFormatHTMLClass;
 typedef struct _EMFormatHTMLPrivate EMFormatHTMLPrivate;
-typedef struct _EMFormatWidgetPURI EMFormatWidgetPURI;
 
 enum _em_format_html_header_flags {
 	EM_FORMAT_HTML_HEADER_TO = 1 << 0,
diff --git a/mail/em-utils.c b/mail/em-utils.c
index f019863..b0b4354 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -77,6 +77,7 @@
 #include "em-utils.h"
 #include "e-mail-printer.h"
 #include "em-format/em-format-quote.h"
+#include "em-format/em-part.h"
 
 /* XXX This is a dirty hack on a dirty hack.  We really need
  *     to rework or get rid of the functions that use this. */
@@ -1220,12 +1221,15 @@ em_utils_message_to_html (CamelMimeMessage *message,
 		/* Return all found validities */
 		for (iter = emf->mail_part_list; iter; iter = iter->next) {
 			
-			EMFormatPURI *puri = iter->data;
-			if (!puri)
+			EMPart *emp = iter->data;
+			gint32 validity_type;
+
+			if (!emp)
 				continue;
 
-			if (*validity_found && puri->validity_type)
-				*validity_found |= puri->validity_type;
+			validity_type = em_part_get_validity_type (emp);
+			if (*validity_found && validity_type)
+				*validity_found |= validity_type;
 		}
 
 	}
diff --git a/plugins/audio-inline/Makefile.am b/plugins/audio-inline/Makefile.am
index fc204f9..3e04573 100644
--- a/plugins/audio-inline/Makefile.am
+++ b/plugins/audio-inline/Makefile.am
@@ -20,7 +20,9 @@ liborg_gnome_audio_inline_la_CPPFLAGS =			\
 	$(GSTREAMER_CFLAGS)				\
 	$(GTKHTML_CFLAGS)
 
-liborg_gnome_audio_inline_la_SOURCES = audio-inline.c
+liborg_gnome_audio_inline_la_SOURCES = 			\
+	audio-inline.c					\
+	em-part-audio.c
 
 liborg_gnome_audio_inline_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
 
diff --git a/plugins/audio-inline/audio-inline.c b/plugins/audio-inline/audio-inline.c
index 4942370..7250277 100644
--- a/plugins/audio-inline/audio-inline.c
+++ b/plugins/audio-inline/audio-inline.c
@@ -24,13 +24,14 @@
 #include <config.h>
 #endif
 
+#include "em-part-audio.h"
+
 #include <gtk/gtk.h>
 #include <glib/gstdio.h>
 #include "e-util/e-mktemp.h"
 #include "mail/em-format-hook.h"
 #include "mail/em-format-html.h"
-#include "gtkhtml/gtkhtml-embedded.h"
-#include "gst/gst.h"
+#include <gst/gst.h>
 
 #define d(x)
 
@@ -47,82 +48,31 @@ void org_gnome_audio_inline_format (gpointer ep, EMFormatHookTarget *t);
 
 static volatile gint org_gnome_audio_class_id_counter = 0;
 
-typedef struct _EMFormatInlineAudioPURI EMFormatInlineAudioPURI;
-
-struct _EMFormatInlineAudioPURI {
-	EMFormatPURI puri;
-
-	gchar *filename;
-	GstElement *playbin;
-	gulong      bus_id;
-	GstState    target_state;
-	GtkWidget  *play_button;
-	GtkWidget  *pause_button;
-	GtkWidget  *stop_button;
-};
-
-static void
-org_gnome_audio_inline_pobject_free (EMFormatPURI *o)
-{
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) o;
-
-	d(printf ("audio inline formatter: pobject free\n"));
-
-	if (po->play_button) {
-		g_object_unref (po->play_button);
-		po->play_button = NULL;
-	}
-
-	if (po->pause_button) {
-		g_object_unref (po->pause_button);
-		po->pause_button = NULL;
-	}
-
-	if (po->stop_button) {
-		g_object_unref (po->stop_button);
-		po->stop_button = NULL;
-	}
-
-	if (po->filename) {
-		g_unlink (po->filename);
-		g_free (po->filename);
-		po->filename = NULL;
-	}
-
-	if (po->bus_id) {
-		g_source_remove (po->bus_id);
-		po->bus_id = 0;
-	}
-
-	if (po->playbin) {
-		gst_element_set_state (po->playbin, GST_STATE_NULL);
-		gst_object_unref (po->playbin);
-		po->playbin = NULL;
-	}
-}
 
 static void
 org_gnome_audio_inline_pause_clicked (GtkWidget *button,
-									  EMFormatPURI *puri)
+				      EMPartAudio *empa)
 {
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
+	GstElement *playbin = em_part_audio_get_playbin (empa);
 
-	if (po->playbin) {
+	if (playbin) {
 		/* pause playing */
-		gst_element_set_state (po->playbin, GST_STATE_PAUSED);
+		gst_element_set_state (playbin, GST_STATE_PAUSED);
+		g_object_unref (playbin);
 	}
 }
 
 static void
 org_gnome_audio_inline_stop_clicked (GtkWidget *button,
-									 EMFormatPURI *puri)
+				     EMPartAudio *empa)
 {
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
+	GstElement *playbin = em_part_audio_get_playbin (empa);
 
-	if (po->playbin) {
+	if (playbin) {
 		/* ready to play */
-		gst_element_set_state (po->playbin, GST_STATE_READY);
-		po->target_state = GST_STATE_READY;
+		gst_element_set_state (playbin, GST_STATE_READY);
+		em_part_audio_set_target_state (empa, GST_STATE_READY);
+		g_object_unref (playbin);
 	}
 }
 
@@ -147,39 +97,57 @@ org_gnome_audio_inline_gst_callback (GstBus *bus,
                                      GstMessage *message,
                                      gpointer data)
 {
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) data;
+	EMPartAudio *empa = data;
 	GstMessageType msg_type;
+	GstElement *playbin;
+
+	g_return_val_if_fail (data != NULL, TRUE);
 
-	g_return_val_if_fail (po != NULL, TRUE);
-	g_return_val_if_fail (po->playbin != NULL, TRUE);
+	playbin = em_part_audio_get_playbin (empa);
+	g_return_val_if_fail (playbin != NULL, TRUE);
 
 	msg_type = GST_MESSAGE_TYPE (message);
 
 	switch (msg_type) {
 		case GST_MESSAGE_ERROR:
-			gst_element_set_state (po->playbin, GST_STATE_NULL);
+			gst_element_set_state (playbin, GST_STATE_NULL);
 			break;
 		case GST_MESSAGE_EOS:
-			gst_element_set_state (po->playbin, GST_STATE_READY);
+			gst_element_set_state (playbin, GST_STATE_READY);
 			break;
 		case GST_MESSAGE_STATE_CHANGED:
 			{
-			      GstState old_state, new_state;
-
-			      if (GST_MESSAGE_SRC (message) != GST_OBJECT (po->playbin))
-				      break;
-
-			      gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
-
-			      if (old_state == new_state)
-				      break;
-
-			      if (po->play_button)
-					gtk_widget_set_sensitive (po->play_button, new_state <= GST_STATE_PAUSED);
-			      if (po->pause_button)
-					gtk_widget_set_sensitive (po->pause_button, new_state > GST_STATE_PAUSED);
-			      if (po->stop_button)
-					gtk_widget_set_sensitive (po->stop_button, new_state >= GST_STATE_PAUSED);
+				GstState old_state, new_state;
+				GtkWidget *button;
+
+				if (GST_MESSAGE_SRC (message) != GST_OBJECT (playbin))
+					break;
+
+				gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+
+				if (old_state == new_state)
+					break;
+
+				button = em_part_audio_get_play_button (empa);
+				if (button) {
+					gtk_widget_set_sensitive (button, 
+						new_state <= GST_STATE_PAUSED);
+					g_object_unref (button);
+				}
+
+				button = em_part_audio_get_pause_button (empa);
+				if (button) {
+					gtk_widget_set_sensitive (button, 
+						new_state > GST_STATE_PAUSED);
+					g_object_unref (button);
+				}
+
+				button = em_part_audio_get_stop_button (empa);
+			      	if (button) {
+					gtk_widget_set_sensitive (button,
+						new_state >= GST_STATE_PAUSED);
+					g_object_unref (button);
+				}
 			}
 
 			break;
@@ -187,36 +155,45 @@ org_gnome_audio_inline_gst_callback (GstBus *bus,
 			break;
 	}
 
+	g_object_unref (playbin);
+
 	return TRUE;
 }
 
 static void
 org_gnome_audio_inline_play_clicked (GtkWidget *button,
-									 EMFormatPURI *puri)
+				     EMPartAudio *empa)
 {
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
 	GstState cur_state;
+	GstElement *playbin;
+	gchar *filename;
 
 	d(printf ("audio inline formatter: play\n"));
 
-	if (!po->filename) {
+	filename = em_part_audio_get_filename (empa);
+	if (!filename) {
 		CamelStream *stream;
+		CamelMimePart *part;
 		CamelDataWrapper *data;
 		GError *error = NULL;
 		gint argc = 1;
 		const gchar *argv [] = { "org_gnome_audio_inline", NULL };
 
 		/* FIXME this is ugly, we should stream this directly to gstreamer */
-		po->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX");
+		
+		filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX");
+		em_part_audio_set_filename (empa, filename);
 
-		d(printf ("audio inline formatter: write to temp file %s\n", po->filename));
+		d(printf ("audio inline formatter: write to temp file %s\n", filename));
 
-		stream = camel_stream_fs_new_with_name (po->filename, O_RDWR | O_CREAT | O_TRUNC, 0600, NULL);
-		data = camel_medium_get_content (CAMEL_MEDIUM (po->puri.part));
+		stream = camel_stream_fs_new_with_name (filename, O_RDWR | O_CREAT | O_TRUNC, 0600, NULL);
+		part = em_part_get_mime_part (EM_PART (empa));
+		data = camel_medium_get_content (CAMEL_MEDIUM (part));
 		camel_data_wrapper_decode_to_stream_sync (
 			data, stream, NULL, NULL);
 		camel_stream_flush (stream, NULL, NULL);
 		g_object_unref (stream);
+		g_object_unref (part);
 
 		d(printf ("audio inline formatter: init gst playbin\n"));
 
@@ -225,38 +202,45 @@ org_gnome_audio_inline_play_clicked (GtkWidget *button,
 			GstBus *bus;
 
 			/* create a disk reader */
-			po->playbin = gst_element_factory_make ("playbin", "playbin");
-			if (po->playbin == NULL) {
+			playbin = gst_element_factory_make ("playbin", "playbin");
+			if (playbin == NULL) {
 				g_printerr ("Failed to create gst_element_factory playbin; check your installation\n");
 				return;
 
 			}
+			em_part_audio_set_playbin (empa, playbin);
 
-			uri = g_filename_to_uri (po->filename, NULL, NULL);
-			g_object_set (po->playbin, "uri", uri, NULL);
+			uri = g_filename_to_uri (filename, NULL, NULL);
+			g_object_set (playbin, "uri", uri, NULL);
 			g_free (uri);
-			org_gnome_audio_inline_set_audiosink (po->playbin);
+			org_gnome_audio_inline_set_audiosink (playbin);
+
+			bus = gst_element_get_bus (playbin);
+			em_part_audio_set_bus_id (empa, 
+				gst_bus_add_watch (bus, org_gnome_audio_inline_gst_callback, empa));
 
-			bus = gst_element_get_bus (po->playbin);
-			po->bus_id = gst_bus_add_watch (bus, org_gnome_audio_inline_gst_callback, po);
 			gst_object_unref (bus);
 
 		} else {
 			g_printerr ("GStreamer failed to initialize: %s",error ? error->message : "");
 			g_error_free (error);
 		}
+
+		g_free (filename);
 	}
 
-	gst_element_get_state (po->playbin, &cur_state, NULL, 0);
+	gst_element_get_state (playbin, &cur_state, NULL, 0);
 
 	if (cur_state >= GST_STATE_PAUSED) {
-		gst_element_set_state (po->playbin, GST_STATE_READY);
+		gst_element_set_state (playbin, GST_STATE_READY);
 	}
 
-	if (po->playbin) {
+	if (playbin) {
 		/* start playing */
-		gst_element_set_state (po->playbin, GST_STATE_PLAYING);
+		gst_element_set_state (playbin, GST_STATE_PLAYING);
 	}
+
+	g_object_unref (playbin);
 }
 
 static GtkWidget *
@@ -280,18 +264,26 @@ org_gnome_audio_inline_add_button (GtkWidget *box,
 
 static GtkWidget*
 org_gnome_audio_inline_button_panel (EMFormat *emf,
-									 EMFormatPURI *puri,
-									 GCancellable *cancellable)
+				     EMPartAudio *empa,
+				     GCancellable *cancellable)
 {
 	GtkWidget *box;
-	EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
-
 	/* it is OK to call UI functions here, since we are called from UI thread */
 
 	box = gtk_hbutton_box_new ();
-	po->play_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PLAY, G_CALLBACK (org_gnome_audio_inline_play_clicked), po, TRUE));
-	po->pause_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PAUSE, G_CALLBACK (org_gnome_audio_inline_pause_clicked), po, FALSE));
-	po->stop_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_STOP, G_CALLBACK (org_gnome_audio_inline_stop_clicked), po, FALSE));
+
+        em_part_audio_set_play_button (empa,
+                org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PLAY,
+                        G_CALLBACK (org_gnome_audio_inline_play_clicked),
+                        empa, TRUE));
+        em_part_audio_set_pause_button (empa,
+	        org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PAUSE,
+                        G_CALLBACK (org_gnome_audio_inline_pause_clicked),
+                        empa, FALSE));
+        em_part_audio_set_stop_button (empa,
+                org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_STOP,
+                        G_CALLBACK (org_gnome_audio_inline_stop_clicked),
+                        empa, FALSE));
 
 	gtk_widget_show (box);
 
@@ -302,7 +294,7 @@ void
 org_gnome_audio_inline_format (gpointer ep,
                                EMFormatHookTarget *t)
 {
-	EMFormatInlineAudioPURI *pobj;
+        EMPart *emp;
 	gchar *classid;
 
 	classid = g_strdup_printf (
@@ -313,18 +305,8 @@ org_gnome_audio_inline_format (gpointer ep,
 
 	d(printf ("audio inline formatter: format classid %s\n", classid));
 
-	pobj = (EMFormatInlineAudioPURI *) em_format_puri_new (
-                        t->format, sizeof (EMFormatInlineAudioPURI), t->part, classid);
-	pobj->puri.widget_func = org_gnome_audio_inline_button_panel;
-	pobj->puri.part = g_object_ref (t->part);
-	pobj->filename = NULL;
-	pobj->playbin = NULL;
-	pobj->play_button = NULL;
-	pobj->stop_button = NULL;
-	pobj->pause_button = NULL;
-	pobj->bus_id = 0;
-	pobj->puri.free = org_gnome_audio_inline_pobject_free;
-	pobj->target_state = GST_STATE_NULL;
-
-        em_format_add_puri (t->format, (EMFormatPURI *) pobj);
+        emp = em_part_audio_new (t->format, t->part, t->part_id, NULL);
+        em_part_set_widget_func (emp, org_gnome_audio_inline_button_panel);
+
+        em_format_add_part_object (t->format, emp);
 }
diff --git a/plugins/audio-inline/em-part-audio.c b/plugins/audio-inline/em-part-audio.c
new file mode 100644
index 0000000..749cd83
--- /dev/null
+++ b/plugins/audio-inline/em-part-audio.c
@@ -0,0 +1,346 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "em-part-audio.h"
+
+G_DEFINE_TYPE (EMPartAudio, em_part_audio, EM_TYPE_PART);
+
+struct _EMPartAudioPrivate {
+
+	gchar *filename;
+
+	GstState target_state;
+	GstElement *playbin;
+	gulong bus_id;
+
+
+	GtkWidget *play_button;
+	GtkWidget *pause_button;
+	GtkWidget *stop_button;
+
+	GMutex *mutex;
+};
+
+static void
+em_part_audio_finalize (GObject *object)
+{
+	EMPartAudioPrivate *priv = EM_PART_AUDIO (object)->priv;
+
+	g_mutex_lock (priv->mutex);
+
+	if (priv->filename) {
+		g_free (priv->filename);
+		priv->filename = NULL;
+	}
+
+	if (priv->playbin) {
+		g_object_unref (priv->playbin);
+		priv->playbin = NULL;
+	}
+
+	if (priv->play_button) {
+		g_object_unref (priv->play_button);
+		priv->play_button = NULL;
+	}
+
+	if (priv->pause_button) {
+		g_object_unref (priv->pause_button);
+		priv->pause_button = NULL;
+	}
+
+	if (priv->stop_button) {
+		g_object_unref (priv->stop_button);
+		priv->stop_button = NULL;
+	}
+
+	g_mutex_unlock (priv->mutex);
+	g_mutex_free (priv->mutex);
+}
+
+static void
+em_part_audio_class_init (EMPartAudioClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EMPartAudioPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = em_part_audio_finalize;
+}
+
+static void
+em_part_audio_init (EMPartAudio *empa)
+{
+	empa->priv = G_TYPE_INSTANCE_GET_PRIVATE (empa,
+			EM_TYPE_PART_AUDIO, EMPartAudioPrivate);
+	
+	empa->priv->mutex = g_mutex_new ();
+	empa->priv->filename = NULL;
+	empa->priv->pause_button = NULL;
+	empa->priv->play_button = NULL;
+	empa->priv->stop_button = NULL;
+	empa->priv->playbin = NULL;
+	empa->priv->target_state = GST_STATE_NULL;
+	empa->priv->bus_id = 0;
+}
+
+EMPart *
+em_part_audio_new (EMFormat *emf,
+		   CamelMimePart *part,
+		   const gchar *uri,
+		   EMPartWidgetFunc widget_func)
+{
+	EMPart *emp;
+	
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+	g_return_val_if_fail ((part == NULL) || CAMEL_IS_MIME_PART (part), NULL);
+	g_return_val_if_fail (uri && *uri, NULL);
+	
+	emp = EM_PART (g_object_new (EM_TYPE_PART_AUDIO, NULL));
+	em_part_set_mime_part (emp, part);
+	em_part_set_formatter (emp, emf);
+	em_part_set_uri (emp, uri);
+	
+	if (widget_func)
+		em_part_set_widget_func (emp, widget_func);
+	
+	return emp;
+}
+
+void
+em_part_audio_set_filename (EMPartAudio *empa,
+			    const gchar *filename)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->filename)
+		g_free (empa->priv->filename);
+
+	if (filename)
+		empa->priv->filename = g_strdup (filename);
+	else
+		empa->priv->filename = NULL;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gchar*
+em_part_audio_get_filename (EMPartAudio *empa)
+{
+	gchar *filename = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->filename)
+		filename = g_strdup (empa->priv->filename);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return filename;
+}
+
+void em_part_audio_set_playbin (EMPartAudio *empa,
+				GstElement *playbin)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+	g_return_if_fail (playbin == NULL || GST_IS_ELEMENT (playbin));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (playbin)
+		g_object_ref (playbin);
+
+	if (empa->priv->playbin)
+		g_object_unref (empa->priv->playbin);
+
+	empa->priv->playbin = playbin;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GstElement*
+em_part_audio_get_playbin (EMPartAudio *empa)
+{
+	GstElement *element = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->playbin)
+		element = g_object_ref (empa->priv->playbin);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return element;	
+}
+
+void em_part_audio_set_bus_id (EMPartAudio *empa,
+			       gulong bus_id)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+	empa->priv->bus_id = bus_id;
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+gulong
+em_part_audio_get_bus_id (EMPartAudio *empa)
+{
+	gulong bus_id = 0;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), 0);
+
+	g_mutex_lock (empa->priv->mutex);
+	bus_id = empa->priv->bus_id;
+	g_mutex_unlock (empa->priv->mutex);
+
+	return bus_id;
+}
+
+void
+em_part_audio_set_target_state (EMPartAudio *empa,
+				GstState state)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+
+	g_mutex_lock (empa->priv->mutex);
+	empa->priv->target_state = state;
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GstState
+em_part_audio_get_target_state (EMPartAudio *empa)
+{
+	GstState state;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), GST_STATE_NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	state = empa->priv->target_state;
+	g_mutex_unlock (empa->priv->mutex);
+
+	return state;	
+}
+
+void
+em_part_audio_set_play_button (EMPartAudio *empa,
+			       GtkWidget *button)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+	g_return_if_fail (button == NULL || GTK_IS_WIDGET (button));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (button)
+		g_object_ref (button);
+
+	if (empa->priv->play_button)
+		g_object_unref (empa->priv->play_button);
+
+	empa->priv->play_button = button;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GtkWidget*
+em_part_audio_get_play_button (EMPartAudio *empa)
+{
+	GtkWidget *widget = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->play_button)
+		widget = g_object_ref (empa->priv->play_button);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return widget;
+}
+
+void
+em_part_audio_set_pause_button (EMPartAudio *empa,
+				GtkWidget *button)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+	g_return_if_fail (button == NULL || GTK_IS_WIDGET (button));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (button)
+		g_object_ref (button);
+
+	if (empa->priv->pause_button)
+		g_object_unref (empa->priv->pause_button);
+
+	empa->priv->pause_button = button;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GtkWidget*
+em_part_audio_get_pause_button (EMPartAudio *empa)
+{
+	GtkWidget *widget = NULL;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->pause_button)
+		widget = g_object_ref (empa->priv->pause_button);
+	g_mutex_unlock (empa->priv->mutex);
+
+	return widget;
+}
+
+void
+em_part_audio_set_stop_button (EMPartAudio *empa,
+			       GtkWidget *button)
+{
+	g_return_if_fail (EM_IS_PART_AUDIO (empa));
+	g_return_if_fail (button == NULL || GTK_IS_WIDGET (button));
+
+	g_mutex_lock (empa->priv->mutex);
+
+	if (button)
+		g_object_ref (button);
+
+	if (empa->priv->stop_button)
+		g_object_unref (empa->priv->stop_button);
+
+	empa->priv->stop_button = button;
+
+	g_mutex_unlock (empa->priv->mutex);
+}
+
+GtkWidget*
+em_part_audio_get_stop_button (EMPartAudio *empa)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (EM_IS_PART_AUDIO (empa), NULL);
+
+	g_mutex_lock (empa->priv->mutex);
+	if (empa->priv->stop_button)
+		widget = g_object_ref (empa->priv->stop_button);
+	g_mutex_unlock (empa->priv->stop_button);
+
+	return widget;
+}
diff --git a/plugins/audio-inline/em-part-audio.h b/plugins/audio-inline/em-part-audio.h
new file mode 100644
index 0000000..e8d7853
--- /dev/null
+++ b/plugins/audio-inline/em-part-audio.h
@@ -0,0 +1,112 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EM_PART_AUDIO_H
+#define EM_PART_AUDIO_H
+
+#include <em-format/em-part.h>
+#include <gst/gst.h>
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_PART_AUDIO \
+	(em_part_audio_get_type ())
+#define EM_PART_AUDIO(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), EM_TYPE_PART_AUDIO, EMPartAudio))
+#define EM_PART_AUDIO_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), EM_TYPE_PART_AUDIO, EMPartAudioClass))
+#define EM_IS_PART_AUDIO(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), EM_TYPE_PART_AUDIO))
+#define EM_IS_PART_AUDIO_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), EM_TYPE_PART_AUDIO))
+#define EM_PART_AUDIO_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), EM_TYPE_PART_AUDIO, EMPartAudioClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMPartAudio EMPartAudio;
+typedef struct _EMPartAudioClass EMPartAudioClass;
+typedef struct _EMPartAudioPrivate EMPartAudioPrivate;
+
+
+struct _EMPartAudio {
+	EMPart parent;
+	EMPartAudioPrivate *priv;
+};
+
+struct _EMPartAudioClass {
+	GObjectClass parent_class;
+	
+};
+
+EMPart*			em_part_audio_new      	(EMFormat *emf,
+						 CamelMimePart *part,
+						 const gchar *uri,
+						 EMPartWriteFunc write_func);
+
+GType                   em_part_audio_get_type ();
+
+void			em_part_audio_set_filename
+						(EMPartAudio *empa,
+						 const gchar *filename);
+
+gchar*			em_part_audio_get_filename
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_playbin
+						(EMPartAudio *empa,
+						 GstElement *playbin);
+GstElement*		em_part_audio_get_playbin
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_bus_id
+						(EMPartAudio *empa,
+						 gulong bus_id);
+gulong			em_part_audio_get_bus_id
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_target_state
+						(EMPartAudio *empa,
+						 GstState state);
+GstState		em_part_audio_get_target_state
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_play_button
+						(EMPartAudio *empa,
+						 GtkWidget *button);
+GtkWidget*		em_part_audio_get_play_button
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_pause_button
+						(EMPartAudio *empa,
+						 GtkWidget *button);
+GtkWidget*		em_part_audio_get_pause_button
+						(EMPartAudio *empa);
+
+void			em_part_audio_set_stop_button
+						(EMPartAudio *empa,
+						 GtkWidget *button);
+GtkWidget*		em_part_audio_get_stop_button
+						(EMPartAudio *empa);
+
+G_END_DECLS
+
+#endif /* EM_PART_AUDIO_H */ 
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 4dd58bb..62fb2ca 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -371,24 +371,6 @@ web_view_connect_proxy_cb (EWebView *web_view,
 		G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
 }
 
-static GtkWidget *
-web_view_create_plugin_widget_cb (EWebView *web_view,
-                                  const gchar *mime_type,
-                                  const gchar *uri,
-                                  GHashTable *param)
-{
-	EWebViewClass *class;
-
-	/* XXX WebKitWebView does not provide a class method for
-	 *     this signal, so we do so we can override the default
-	 *     behavior from subclasses for special URI types. */
-
-	class = E_WEB_VIEW_GET_CLASS (web_view);
-	g_return_val_if_fail (class->create_plugin_widget != NULL, NULL);
-
-	return class->create_plugin_widget (web_view, mime_type, uri, param);
-}
-
 static void
 web_view_hovering_over_link_cb (EWebView *web_view,
                                 const gchar *title,
@@ -831,165 +813,6 @@ web_view_scroll_event (GtkWidget *widget,
 	return FALSE;
 }
 
-static void
-web_view_get_preferred_height (GtkWidget *widget,
-			       gint *minimum_height,
-			       gint *natural_height)
-{
-	WebKitWebView *web_view;
-	WebKitDOMDocument *document;
-	WebKitDOMElement *body, *last_el, *style_el;
-	gint doc_height;
-
-	if (!minimum_height && !natural_height)
-		return;
-
-	web_view = WEBKIT_WEB_VIEW (widget);
-	document = webkit_web_view_get_dom_document (web_view);
-	if (!document)
-		return;
-
-	body = WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document));
-	if (!body)
-		return;
-
-	/* Make sure our Evo CSS stylesheet is loaded.
-	 * Note: there's 'user-stylesheet-uri' property of WebKitWebSettings but
-	 * it does not seem to be loaded in webviews with native text/html emails. */
-	style_el = webkit_dom_document_get_element_by_id (document, "_evo_stylesheet");
-	if (!style_el) {
-		WebKitDOMNodeList *list;
-		WebKitDOMNode *head;
-		style_el = webkit_dom_document_create_element (document, "LINK", NULL);
-		webkit_dom_html_link_element_set_rel (
-			WEBKIT_DOM_HTML_LINK_ELEMENT (style_el), "stylesheet");
-		webkit_dom_html_link_element_set_href(
-			WEBKIT_DOM_HTML_LINK_ELEMENT (style_el),
-			"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css");
-		webkit_dom_element_set_attribute (style_el, "type", "text/css", NULL);
-		webkit_dom_html_element_set_id (
-			WEBKIT_DOM_HTML_ELEMENT (style_el), "_evo_stylesheet");
-
-		list = webkit_dom_document_get_elements_by_tag_name (document, "head");
-		/* Broken HTML! Try to add head */
-		if (webkit_dom_node_list_get_length (list) == 0) {
-			WebKitDOMNodeList *body;
-			head = WEBKIT_DOM_NODE (
-				webkit_dom_document_create_element (
-					document, "HEAD", NULL));
-			body = webkit_dom_document_get_elements_by_tag_name (document, "body");
-			if (webkit_dom_node_list_get_length(body) == 0) {
-				/* The document is totally screwed up, there's
-				 * nothing more we can do. */
-				return;
-			}
-
-			webkit_dom_node_insert_before(WEBKIT_DOM_NODE (document),
-				head, webkit_dom_node_list_item (body, 0), NULL);
-
-		} else {
-			head = webkit_dom_node_list_item (list, 0);
-		}
-
-		webkit_dom_node_append_child (head, WEBKIT_DOM_NODE (style_el), NULL);
-	}
-
-	/* Last element in DOM != the undermost element displayed.
-	 * Thus we create our own element which is guaranteed to be displayed
-	 * at the very bottom (via CSS in webview.css) */
-	last_el = webkit_dom_document_get_element_by_id (document, "_evo_bottom_element");
-	if (!last_el) {
-		last_el = webkit_dom_document_create_element (document, "DIV", NULL);
-		webkit_dom_html_element_set_id (WEBKIT_DOM_HTML_ELEMENT (last_el),
-			"_evo_bottom_element");
-		webkit_dom_node_append_child (WEBKIT_DOM_NODE (body),
-			WEBKIT_DOM_NODE (last_el), NULL);
-
-		/* When the _evo_bottom_element is inserted to the DOM, the
-		 * subsequent call of webkit_dom_element_get_offset_top() makes
-		 * WebKit to recalculate layout and invoke content size change
-		 * which results in a recursive call of this function.
-		 * Gtk would prevent the recursion to happen but it would
-		 * throw an ugly warning, therefor we won't be doing any math now.
-		 * When the email is being rendered, the _get_preferred_height()
-		 * gets called multiple times, so we will calculate the actual
-		 * height next time, when WebKit will not be trying to update the
-		 * layout. */
-
-		return;
-	}
-
-	/* The _actual_ height of page content is top + height of the
-	 * very last element in body. The 2px height is hardocded in
-	 * webview.ccs in #_evo_bottom_element */
-	doc_height = webkit_dom_element_get_offset_top (last_el) + 2;
-
-
-	/* Hardcoded padding */
-	doc_height += 18;
-
-	/* When full content zoom is enabled then the elements are not resized
-	 * but rather scaled and thus they still report their original height
-	 * instead of their actual display height. */
-	if (webkit_web_view_get_full_content_zoom (web_view)) {
-		doc_height = ceil((gfloat) doc_height * 
-				webkit_web_view_get_zoom_level (web_view));
-	}
-
-	if (minimum_height)
-		*minimum_height = doc_height;
-
-	if (natural_height)
-		*natural_height = doc_height;
-
-}
-
-static GtkWidget *
-web_view_create_plugin_widget (EWebView *web_view,
-                               const gchar *mime_type,
-                               const gchar *uri,
-                               GHashTable *param)
-{
-	GtkWidget *widget = NULL;
-
-	if (g_strcmp0 (mime_type, "image/x-themed-icon") == 0) {
-		GtkIconTheme *icon_theme;
-		GdkPixbuf *pixbuf;
-		gpointer data;
-		glong size = 0;
-		GError *error = NULL;
-
-		icon_theme = gtk_icon_theme_get_default ();
-
-		if (size == 0) {
-			data = g_hash_table_lookup (param, "width");
-			if (data != NULL)
-				size = MAX (size, strtol (data, NULL, 10));
-		}
-
-		if (size == 0) {
-			data = g_hash_table_lookup (param, "height");
-			if (data != NULL)
-				size = MAX (size, strtol (data, NULL, 10));
-		}
-
-		if (size == 0)
-			size = 32;  /* arbitrary default */
-
-		pixbuf = gtk_icon_theme_load_icon (
-			icon_theme, uri, size, 0, &error);
-		if (pixbuf != NULL) {
-			widget = gtk_image_new_from_pixbuf (pixbuf);
-			g_object_unref (pixbuf);
-		} else if (error != NULL) {
-			g_warning ("%s", error->message);
-			g_error_free (error);
-		}
-	}
-
-	return widget;
-}
-
 static gchar *
 web_view_extract_uri (EWebView *web_view,
                       GdkEventButton *event)
@@ -1422,14 +1245,12 @@ e_web_view_class_init (EWebViewClass *class)
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->button_press_event = web_view_button_press_event;
 	widget_class->scroll_event = web_view_scroll_event;
-	widget_class->get_preferred_height = web_view_get_preferred_height;
 
 #if 0  /* WEBKIT */
 	html_class = GTK_HTML_CLASS (class);
 	html_class->url_requested = web_view_url_requested;
 #endif
 
-	class->create_plugin_widget = web_view_create_plugin_widget;
 	class->extract_uri = web_view_extract_uri;
 	class->hovering_over_link = web_view_hovering_over_link;
 	class->link_clicked = web_view_link_clicked;
@@ -1653,10 +1474,6 @@ e_web_view_init (EWebView *web_view)
 	web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
 
 	g_signal_connect (
-		web_view, "create-plugin-widget",
-		G_CALLBACK (web_view_create_plugin_widget_cb), NULL);
-
-	g_signal_connect (
 		web_view, "hovering-over-link",
 		G_CALLBACK (web_view_hovering_over_link_cb), NULL);
 
@@ -2782,7 +2599,7 @@ e_web_view_get_default_settings(GtkWidget *parent_widget)
                 "default-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
                 "default-monospace-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
                 "enable-frame-flattening", TRUE, 
-                "enable-plugins", FALSE,
+                "enable-plugins", TRUE,
                 "enable-java-applet", FALSE,
                 "enable-html5-database", FALSE,
                 "enable-html5-local-storage", FALSE,
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index 6b32501..656c8b6 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -69,10 +69,6 @@ struct _EWebViewClass {
 	WebKitWebViewClass parent_class;
 
 	/* Methods */
-	GtkWidget *	(*create_plugin_widget)	(EWebView *web_view,
-						 const gchar *mime_type,
-						 const gchar *uri,
-						 GHashTable *param);
 	gchar *		(*extract_uri)		(EWebView *web_view,
 						 GdkEventButton *event);
 	void		(*hovering_over_link)	(EWebView *web_view,



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