[evolution/webkit: 14/154] Adapt EMFormat subclasses to the new EMFormat API



commit 59af609acda0054c2cdcb2a78a03c4792c7ef711
Author: Dan VrÃtil <dvratil redhat com>
Date:   Fri Aug 26 16:07:05 2011 +0200

    Adapt EMFormat subclasses to the new EMFormat API
    
    The EMFormat subclasses now work the same way EMFormat does -
    providing EMFormatParseFunc for parsing the mail and EMFormatWriteFunc
    for converting parts to displayable HTML code.
    
    EMFormatHTML is almost entirely ported. Parsing and formatting
    email as source code and analyzing and displaying attachments is
    not working yet. All the headers-related code will be most probably
    moved to EMFormatHMTLHeaders, as it is more then 600 lines of completely
    independent code.
    
    EMFormatHTMLDisplay is ported to the new API and partially works, but
    attachments are not displayed and the functions need renaming to
    conform better with the new functionality of EMFormat.
    
    EMFormatHook is now adapted to the new API as well, but still needs
    some more work.
    
    The EMFormatHTMLPrint is only ported to compile against the new API,
    but does not work yet.

 mail/em-format-hook.c         |   23 +-
 mail/em-format-hook.h         |    4 +-
 mail/em-format-html-display.c |  558 +++-----
 mail/em-format-html-display.h |   45 +
 mail/em-format-html-print.c   |   12 +-
 mail/em-format-html.c         | 3034 ++++++++++++++++++-----------------------
 mail/em-format-html.h         |  102 +-
 7 files changed, 1583 insertions(+), 2195 deletions(-)
---
diff --git a/mail/em-format-hook.c b/mail/em-format-hook.c
index 7777914..80774bf 100644
--- a/mail/em-format-hook.c
+++ b/mail/em-format-hook.c
@@ -61,24 +61,23 @@ static const EPluginHookTargetKey emfh_flag_map[] = {
 G_DEFINE_TYPE (EMFormatHook, em_format_hook, E_TYPE_PLUGIN_HOOK)
 
 static void
-emfh_format_format (EMFormat *md,
-                    CamelStream *stream,
-                    CamelMimePart *part,
-                    const EMFormatHandler *info,
-                    GCancellable *cancellable,
-                    gboolean is_fallback)
+emfh_parse_part (EMFormat *emf,
+		 CamelMimePart *part,
+		 GString *part_id,
+		 EMFormatParserInfo *info,
+		 GCancellable *cancellable)
 {
-	struct _EMFormatHookItem *item = (EMFormatHookItem *) info;
+	struct _EMFormatHookItem *item = (EMFormatHookItem *) info->handler;
 
 	if (item->hook->hook.plugin->enabled) {
 		EMFormatHookTarget target = {
-			md, stream, part, item
+			emf, part, part_id, info
 		};
 
 		e_plugin_invoke (item->hook->hook.plugin, item->format, &target);
-	} else if (info->old) {
-		info->old->handler (
-			md, stream, part, info->old, cancellable, FALSE);
+	} else if (info->handler->old) {
+		info->handler->old->parse_func (
+			emf, part, part_id, info, cancellable);
 	}
 }
 
@@ -116,7 +115,7 @@ emfh_construct_item (EPluginHook *eph,
 	item->handler.flags = e_plugin_hook_mask(root, emfh_flag_map, "flags");
 	item->format = e_plugin_xml_prop(root, "format");
 
-	item->handler.handler = emfh_format_format;
+	item->handler.parse_func = emfh_parse_part;
 	item->hook = emfh;
 
 	if (item->handler.mime_type == NULL || item->format == NULL)
diff --git a/mail/em-format-hook.h b/mail/em-format-hook.h
index ad0745b..09076c2 100644
--- a/mail/em-format-hook.h
+++ b/mail/em-format-hook.h
@@ -40,9 +40,9 @@ typedef void (*EMFormatHookFunc)(struct _EPlugin *plugin, EMFormatHookTarget *da
 
 struct _EMFormatHookTarget {
 	struct _EMFormat *format;
-	CamelStream *stream;
 	CamelMimePart *part;
-	struct _EMFormatHookItem *item;
+	GString *part_id;
+	EMFormatParserInfo *info;
 };
 
 struct _EMFormatHookItem {
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index b87991f..3b08898 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -71,15 +71,6 @@
 
 struct _EMFormatHTMLDisplayPrivate {
 	GHashTable *attachment_views;  /* weak reference; message_part_id->EAttachmentView */
-	gboolean attachment_expanded;
-};
-
-struct _smime_pobject {
-	EMFormatHTMLPObject object;
-
-	gint signature;
-	CamelCipherValidity *valid;
-	GtkWidget *widget;
 };
 
 /* TODO: move the dialogue elsehwere */
@@ -109,46 +100,13 @@ static const gchar *smime_sign_colour[5] = {
 };
 
 static void efhd_attachment_frame (EMFormat *emf, CamelStream *stream, EMFormatPURI *puri, GCancellable *cancellable);
-static void efhd_message_add_bar (EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
-static GtkWidget* efhd_attachment_button (EMFormatHTML *efh, EMFormatHTMLPObject *pobject);
-static GtkWidget* efhd_attachment_optional (EMFormatHTML *efh, EMFormatHTMLPObject *object);
+static void efhd_message_add_bar (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, 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 void efhd_free_attach_puri_data (EMFormatPURI *puri);
 
-struct _attach_puri {
-	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;
-
-	/* image stuff */
-	gint fit_width;
-	gint fit_height;
-	GtkImage *image;
-	GtkWidget *event_box;
-
-	/* Optional Text Mem Stream */
-	CamelStreamMem *mstream;
-
-	/* Signed / Encrypted */
-        camel_cipher_validity_sign_t sign;
-        camel_cipher_validity_encrypt_t encrypt;
-};
-
-static void	efhd_message_prefix		(EMFormat *emf,
-						 CamelStream *stream,
-						 CamelMimePart *part,
-						 const EMFormatHandler *info,
-						 GCancellable *cancellable,
-						 gboolean is_fallback);
+static void efhd_message_prefix (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
 
 static void efhd_builtin_init (EMFormatHTMLDisplayClass *efhc);
 
@@ -158,19 +116,23 @@ G_DEFINE_TYPE (
 	EM_TYPE_FORMAT_HTML)
 
 static void
-efhd_xpkcs7mime_free (EMFormatHTMLPObject *o)
+efhd_xpkcs7mime_free (EMFormatPURI *puri)
 {
-	struct _smime_pobject *po = (struct _smime_pobject *) o;
+	EMFormatSMIMEPURI *sp = (EMFormatSMIMEPURI *) puri;
 
-	if (po->widget)
-		gtk_widget_destroy (po->widget);
-	camel_cipher_validity_free (po->valid);
+	if (sp->widget)
+		gtk_widget_destroy (sp->widget);
+
+	if (sp->description)
+		g_free (sp->description);
+
+	camel_cipher_validity_free (sp->valid);
 }
 
 static void
 efhd_xpkcs7mime_info_response (GtkWidget *widget,
                                guint button,
-                               struct _smime_pobject *po)
+                               EMFormatSMIMEPURI *po)
 {
 	gtk_widget_destroy (widget);
 	po->widget = NULL;
@@ -179,7 +141,7 @@ efhd_xpkcs7mime_info_response (GtkWidget *widget,
 #if defined (HAVE_NSS) && defined (ENABLE_SMIME)
 static void
 efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
-                                  struct _smime_pobject *po)
+                                  EMFormatSMIMEPURI *po)
 {
 	CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info");
 	ECert *ec = NULL;
@@ -207,7 +169,7 @@ efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
 static void
 efhd_xpkcs7mime_add_cert_table (GtkWidget *grid,
                                 GQueue *certlist,
-                                struct _smime_pobject *po)
+                                EMFormatSMIMEPURI *po)
 {
 	GList *head, *link;
 	GtkTable *table;
@@ -267,9 +229,9 @@ efhd_xpkcs7mime_add_cert_table (GtkWidget *grid,
 
 static void
 efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
-                                  EMFormatHTMLPObject *pobject)
+                                  EMFormatPURI *puri)
 {
-	struct _smime_pobject *po = (struct _smime_pobject *) pobject;
+	EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri;
 	GtkBuilder *builder;
 	GtkWidget *grid, *w;
 
@@ -355,11 +317,12 @@ efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
 }
 
 static GtkWidget*
-efhd_xpkcs7mime_button (EMFormatHTML *efh,
-                        EMFormatHTMLPObject *pobject)
+efhd_xpkcs7mime_button (EMFormat *emf,
+                        EMFormatPURI *puri,
+                        GCancellable *cancellable)
 {
 	GtkWidget *widget;
-	struct _smime_pobject *po = (struct _smime_pobject *) pobject;
+	EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri;
 	const gchar *icon_name;
 
 	/* FIXME: need to have it based on encryption and signing too */
@@ -371,7 +334,7 @@ efhd_xpkcs7mime_button (EMFormatHTML *efh,
 	widget = gtk_button_new ();
 	g_signal_connect (
 		widget, "clicked",
-		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), pobject);
+		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), puri);
 	gtk_widget_show (widget);
 
 	widget = gtk_image_new_from_icon_name (
@@ -414,12 +377,10 @@ weak_unref_attachment_view_cb (gpointer message_part_id,
 }
 
 static void
-efhd_format_clone (EMFormat *emf,
-                   CamelFolder *folder,
-                   const gchar *uid,
-                   CamelMimeMessage *msg,
-                   EMFormat *src,
-                   GCancellable *cancellable)
+efhd_parse (EMFormat *emf,
+	    CamelMimeMessage *msg,
+	    CamelFolder *folder,
+	    Cancellable *cancellable)
 {
 	EMFormatHTMLDisplay *efhd;
 
@@ -429,233 +390,164 @@ efhd_format_clone (EMFormat *emf,
 	g_hash_table_foreach (efhd->priv->attachment_views, weak_unref_attachment_view_cb, efhd);
 	g_hash_table_remove_all (efhd->priv->attachment_views);
 
+	/* FIXME WEBKIT Duh?
 	if (emf != src)
 		EM_FORMAT_HTML (emf)->header_wrap_flags = 0;
+	 */
 
 	/* Chain up to parent's format_clone() method. */
 	EM_FORMAT_CLASS (em_format_html_display_parent_class)->
-		format_clone (emf, folder, uid, msg, src, cancellable);
+		parse (emf, msg, folder, cancellable);
 }
 
 static void
 efhd_format_attachment (EMFormat *emf,
-                        CamelStream *stream,
-                        CamelMimePart *part,
-                        const gchar *mime_type,
-                        const EMFormatHandler *handle,
+                        EMFormatPURI *puri,
                         GCancellable *cancellable)
 {
-	GString *buffer;
 	gchar *classid, *text, *html;
-	struct _attach_puri *info;
+	EMFormatAttachmentPURI *info;
+	const EMFormatHandler *handler;
+	CamelContentType *ct;
+	gchar *mime_type;
 
-	classid = g_strdup_printf ("attachment%s", emf->part_id->str);
-	info = (struct _attach_puri *) em_format_add_puri (
-		emf, sizeof (*info), classid, part, efhd_attachment_frame);
-	info->puri.free = efhd_free_attach_puri_data;
-	info->attachment_view_part_id = g_strdup (emf->current_message_part_id);
-	em_format_html_add_pobject (
-		EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject),
-		classid, part, efhd_attachment_button);
-	info->handle = handle;
-	info->shown = em_format_is_inline (
-		emf, info->puri.part_id, info->puri.part, handle);
-	info->snoop_mime_type = emf->snoop_mime_type;
-	info->attachment = e_attachment_new ();
-	e_attachment_set_mime_part (info->attachment, info->puri.part);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	classid = g_strdup_printf ("attachment.%s", puri->uri);
 
-	if (emf->valid) {
-		info->sign = emf->valid->sign.status;
-		info->encrypt = emf->valid->encrypt.status;
+	ct = camel_mime_part_get_content_type (puri->part);
+	if (ct) {
+		mime_type = camel_content_type_simple (ct);
+
+		handler = em_format_find_handler (emf, mime_type);
 	}
 
-	buffer = g_string_sized_new (1024);
-
-	g_string_append_printf (
-		buffer, EM_FORMAT_HTML_VPAD
-		"<table cellspacing=0 cellpadding=0>"
-		"<tr><td>"
-		"<table width=10 cellspacing=0 cellpadding=0>"
-		"<tr><td></td><tr>"
-		"</table>"
-		"</td>"
-		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object></td>"
-		"<td><table width=3 cellspacing=0 cellpadding=0>"
-		"<tr><td></td></tr>"
-		"</table></td>"
-		"<td><font size=-1>",
-		classid);
-
-	/* output some info about it */
 	/* FIXME: should we look up mime_type from object again? */
-	text = em_format_describe_part (part, mime_type);
+	text = em_format_describe_part (puri->part, mime_type);
 	html = camel_text_to_html (
 		text, EM_FORMAT_HTML (emf)->text_html_flags &
 		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	g_string_append (buffer, html);
-	g_free (html);
 	g_free (text);
+	g_free (mime_type);
+
+	info = (EMFormatAttachmentPURI*) em_format_puri_new (
+			emf, sizeof (EMFormatAttachmentPURI), puri->part, classid);
+	info->puri.free = efhd_free_attach_puri_data;
+	/* FIXME WEBKIT HEEEEEEELP, this func is killing me
+	info->widget_func = efhd_attachment_frame;
+	*/
+	info->shown = em_format_is_inline (
+		emf, info->puri.uri, info->puri.part, handler);
+	info->snoop_mime_type = em_format_snoop_type (puri->part);
+	info->attachment = e_attachment_new ();
+	info->attachment_view_part_id = g_strdup (puri->uri);
+	info->description = html;
 
-	g_string_append (
-		buffer,
-		"</font></td>"
-		"</tr><tr></table>\n"
-		EM_FORMAT_HTML_VPAD);
+	if (handler)
+		info->puri.write_func = handler->write_func;
 
-	camel_stream_write (
-		stream, buffer->str, buffer->len, cancellable, NULL);
+	em_format_add_puri (emf, (EMFormatPURI *) info);
 
-	g_string_free (buffer, TRUE);
+	e_attachment_set_mime_part (info->attachment, info->puri.part);
 
-	if (handle && info->shown)
-		handle->handler (
-			emf, stream, part, handle, cancellable, FALSE);
+	if (puri->validity) {
+		info->sign = puri->validity->sign.status;
+		info->encrypt = puri->validity->encrypt.status;
+	}
 
 	g_free (classid);
 }
 
 static void
 efhd_format_optional (EMFormat *emf,
-                      CamelStream *fstream,
-                      CamelMimePart *part,
+                      EMFormatPURI *puri,
                       CamelStream *mstream,
                       GCancellable *cancellable)
 {
-	gchar *classid, *html;
-	struct _attach_puri *info;
-	CamelStream *stream = NULL;
-	GString *buffer;
+	gchar *classid;
+	EMFormatAttachmentPURI *info;
 
-	if (CAMEL_IS_STREAM_FILTER (fstream))
-		stream = camel_stream_filter_get_source (
-			CAMEL_STREAM_FILTER (fstream));
-	if (stream == NULL)
-		stream = fstream;
+	classid = g_strdup_printf ("optional%s", puri->uri);
 
-	classid = g_strdup_printf ("optional%s", emf->part_id->str);
-	info = (struct _attach_puri *) em_format_add_puri (
-		emf, sizeof (*info), classid, part, efhd_attachment_frame);
+	info = (EMFormatAttachmentPURI *) em_format_puri_new (
+			emf, sizeof (EMFormatAttachmentPURI), puri->part, classid);
 	info->puri.free = efhd_free_attach_puri_data;
-	info->attachment_view_part_id = g_strdup (emf->current_message_part_id);
-	em_format_html_add_pobject (
-		EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject),
-		classid, part, efhd_attachment_optional);
+	info->attachment_view_part_id = g_strdup (puri->uri);
 	info->handle = em_format_find_handler (emf, "text/plain");
 	info->shown = FALSE;
 	info->snoop_mime_type = "text/plain";
 	info->attachment = e_attachment_new ();
 	e_attachment_set_mime_part (info->attachment, info->puri.part);
-	info->mstream = (CamelStreamMem *) g_object_ref (mstream);
-	if (emf->valid) {
-		info->sign = emf->valid->sign.status;
-		info->encrypt = emf->valid->encrypt.status;
-	}
-
-	buffer = g_string_sized_new (1024);
-
-	g_string_append (
-		buffer, EM_FORMAT_HTML_VPAD
-		"<table cellspacing=0 cellpadding=0><tr><td>"
-		"<h3><font size=-1 color=red>");
-
-	html = camel_text_to_html (
-		_("Evolution cannot render this email as it is too "
-		  "large to process. You can view it unformatted or "
-		  "with an external text editor."),
-		EM_FORMAT_HTML (emf)->text_html_flags &
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	g_string_append (buffer, html);
-	g_free (html);
+	info->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."));
 
-	g_string_append_printf (
-		buffer,
-		"</font></h3></td></tr></table>\n"
-		"<table cellspacing=0 cellpadding=0><tr>"
-		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object>"
-		"</td></tr></table>" EM_FORMAT_HTML_VPAD,
-		classid);
+	/* MStream holds content of the 'attachment' to be displayed */
+	info->mstream = (CamelStreamMem *) g_object_ref (mstream);
 
-	camel_stream_write (
-		stream, buffer->str, buffer->len, cancellable, NULL);
+	if (puri->validity) {
+		info->sign = puri->validity->sign.status;
+		info->encrypt = puri->validity->encrypt.status;
+	}
 
-	g_string_free (buffer, TRUE);
+	em_format_add_puri (emf, (EMFormatPURI *) info);
 
 	g_free (classid);
 }
 
 static void
 efhd_format_secure (EMFormat *emf,
-                    CamelStream *stream,
-                    CamelMimePart *part,
-                    CamelCipherValidity *valid,
-                    GCancellable *cancellable)
+		    EMFormatPURI *puri,
+		    GCancellable *cancellable)
 {
 	EMFormatClass *format_class;
 
 	format_class = g_type_class_peek (EM_TYPE_FORMAT);
-	format_class->format_secure (emf, stream, part, valid, cancellable);
+	format_class->format_secure (emf, puri, cancellable);
 
-	if (emf->valid == valid
-	    && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
-		|| valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
+	if (puri->validity
+	    && (puri->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
+		|| puri->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
 		GString *buffer;
-		gchar *classid;
-		struct _smime_pobject *pobj;
+		EMFormatSMIMEPURI *pobj;
 
-		buffer = g_string_sized_new (1024);
+		pobj = (EMFormatSMIMEPURI *) em_format_puri_new (
+				emf, sizeof (EMFormatSMIMEPURI), puri->part, puri->uri);
+		pobj->puri.free = efhd_xpkcs7mime_free;
+		pobj->valid = camel_cipher_validity_clone (puri->validity);
+		pobj->widget_func = efhd_xpkcs7mime_button;
 
-		g_string_append_printf (
-			buffer,
-			"<table border=0 width=\"100%%\" "
-			"cellpadding=3 cellspacing=0%s><tr>",
-			smime_sign_colour[valid->sign.status]);
+		em_format_add_puri (emf, (EMFormatPURI*) pobj);
 
-		classid = g_strdup_printf (
-			"smime:///em-format-html/%s/icon/signed",
-			emf->part_id->str);
-		pobj = (struct _smime_pobject *) em_format_html_add_pobject (
-			EM_FORMAT_HTML (emf), sizeof (*pobj),
-			classid, part, efhd_xpkcs7mime_button);
-		pobj->valid = camel_cipher_validity_clone (valid);
-		pobj->object.free = efhd_xpkcs7mime_free;
-		g_string_append_printf (
-			buffer,
-			"<td valign=center><object data=\"%s\" type=\"application/x-gtk-widget\">"
-			"</object></td><td width=100%% valign=center>",
-			classid);
-		g_free (classid);
+		buffer = g_string_new ("");
 
-		if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+		if (puri->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
 			const gchar *desc;
 			gint status;
 
-			status = valid->sign.status;
+			status = puri->validity->sign.status;
 			desc = smime_sign_table[status].shortdesc;
 
 			g_string_append (buffer, gettext (desc));
 
 			em_format_html_format_cert_infos (
-				&valid->sign.signers, buffer);
+				(CamelCipherCertInfo *) puri->validity->sign.signers.head);
 		}
 
-		if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+		if (puri->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
 			const gchar *desc;
 			gint status;
 
-			if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
-				g_string_append (buffer, "<br>");
+			if (puri->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
+				g_string_append (buffer, "\n");
 
-			status = valid->encrypt.status;
+			status = puri->validity->encrypt.status;
 			desc = smime_encrypt_table[status].shortdesc;
 			g_string_append (buffer, gettext (desc));
 		}
 
-		g_string_append (buffer, "</td></tr></table>");
-
-		camel_stream_write (
-			stream, buffer->str, buffer->len, cancellable, NULL);
-
-		g_string_free (buffer, TRUE);
+		pobj->description = g_string_free (buffer, FALSE);
 	}
 }
 
@@ -840,7 +732,7 @@ em_format_html_display_class_init (EMFormatHTMLDisplayClass *class)
 	object_class->finalize = efhd_finalize;
 
 	format_class = EM_FORMAT_CLASS (class);
-	format_class->format_clone = efhd_format_clone;
+	format_class->parse = efhd_parse;
 	format_class->format_attachment = efhd_format_attachment;
 	format_class->format_optional = efhd_format_optional;
 	format_class->format_secure = efhd_format_secure;
@@ -854,20 +746,9 @@ em_format_html_display_class_init (EMFormatHTMLDisplayClass *class)
 static void
 em_format_html_display_init (EMFormatHTMLDisplay *efhd)
 {
-	EWebView *web_view;
-	GtkActionGroup *image_actions;
-	GtkUIManager *ui_manager;
-	GError *error = NULL;
-
-	web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhd));
-
 	efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efhd);
 	efhd->priv->attachment_views = g_hash_table_new_full (
 		g_str_hash, g_str_equal, g_free, NULL);
-	efhd->priv->attachment_expanded = FALSE;
-
-	e_mail_display_set_formatter (
-		E_MAIL_DISPLAY (web_view), EM_FORMAT_HTML (efhd));
 
 	/* we want to convert url's etc */
 	EM_FORMAT_HTML (efhd)->text_html_flags |=
@@ -903,8 +784,8 @@ em_format_html_display_new (void)
 /* ********************************************************************** */
 
 static EMFormatHandler type_builtin_table[] = {
-	{ (gchar *) "x-evolution/message/prefix", efhd_message_prefix },
-	{ (gchar *) "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar }
+	{ (gchar *) "x-evolution/message/prefix", efhd_message_prefix, },
+	{ (gchar *) "x-evolution/message/post-header", (EMFormatParseFunc) efhd_message_add_bar, }
 };
 
 static void
@@ -912,8 +793,10 @@ efhd_builtin_init (EMFormatHTMLDisplayClass *efhc)
 {
 	gint i;
 
+	EMFormatClass *emfc = (EMFormatClass *) efhc;
+
 	for (i = 0; i < G_N_ELEMENTS (type_builtin_table); i++)
-		em_format_class_add_handler ((EMFormatClass *) efhc, &type_builtin_table[i]);
+		em_format_class_add_handler (emfc, &type_builtin_table[i]);
 }
 
 static void
@@ -933,60 +816,43 @@ efhd_write_image (EMFormat *emf,
 
 static void
 efhd_message_prefix (EMFormat *emf,
-                     CamelStream *stream,
                      CamelMimePart *part,
-                     const EMFormatHandler *info,
-                     GCancellable *cancellable,
-                     gboolean is_fallback)
+                     GString *part_id,
+                     EMFormatParserInfo *info,
+                     GCancellable *cancellable)
 {
 	const gchar *flag, *comp, *due;
 	time_t date;
 	gchar *iconpath, *due_date_str;
 	GString *buffer;
+	EMFormatAttachmentPURI *puri;
 
-	if (emf->folder == NULL || emf->uid == NULL
-	    || (flag = camel_folder_get_message_user_tag(emf->folder, emf->uid, "follow-up")) == NULL
+	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;
 
-	buffer = g_string_sized_new (1024);
+	puri = (EMFormatAttachmentPURI *) em_format_puri_new (
+			emf, sizeof (EMFormatAttachmentPURI), part, ".message_prefix");
 
-	/* header displayed for message-flags in mail display */
-	g_string_append (
-		buffer,
-		"<table border=1 width=\"100%%\" "
-		"cellspacing=2 cellpadding=2><tr>");
+	puri->attachment_view_part_id = g_strdup (part_id->str);
 
-	comp = camel_folder_get_message_user_tag(emf->folder, emf->uid, "completed-on");
+	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);
 	if (iconpath) {
-		CamelMimePart *iconpart;
-
-		iconpart = em_format_html_file_part (
-			(EMFormatHTML *)emf, "image/png",
-			iconpath, cancellable);
-		g_free (iconpath);
-		if (iconpart) {
-			gchar *classid;
-
-			classid = g_strdup_printf (
-				"icon:///em-format-html-display/%s/%s",
-				emf->part_id->str,
-				comp && comp[0] ? "comp" : "uncomp");
-			g_string_append_printf (
-				buffer,
-				"<td align=\"left\">"
-				"<img src=\"%s\"></td>",
-				classid);
-			(void) em_format_add_puri (
-				emf, sizeof (EMFormatPURI),
-				classid, iconpart, efhd_write_image);
-			g_free (classid);
-			g_object_unref (iconpart);
-		}
+		gchar *classid;
+
+		classid = g_strdup_printf (
+			"icon:///em-format-html-display/%s/%s",
+			part_id->str,
+			comp && comp[0] ? "comp" : "uncomp");
+
+		puri->puri.uri = classid;
+
+		g_free (classid);
 	}
 
-	g_string_append (buffer, "<td align=\"left\" width=\"100%%\">");
+	buffer = g_string_new ("");
 
 	if (comp && comp[0]) {
 		date = camel_header_decode_date (comp, NULL);
@@ -997,7 +863,7 @@ 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->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);
@@ -1005,7 +871,7 @@ efhd_message_prefix (EMFormat *emf,
 		if (now > date)
 			g_string_append_printf (
 				buffer,
-				"<b>%s</b>&nbsp;",
+				"<b>%s</b> ",
 				_("Overdue:"));
 
 		due_date_str = e_datetime_format_format (
@@ -1021,89 +887,43 @@ efhd_message_prefix (EMFormat *emf,
 		g_string_append (buffer, flag);
 	}
 
-	g_string_append (buffer, "</td></tr></table>");
-
-	camel_stream_write (
-		stream, buffer->str, buffer->len, cancellable, NULL);
-
-	g_string_free (buffer, TRUE);
-}
-
-/* ********************************************************************** */
-
-static void
-efhd_attachment_button_expanded (EAttachmentButton *button,
-                                 GParamSpec *pspec,
-                                 struct _attach_puri *info)
-{
-	EMFormatHTML *efh;
-	EMFormatHTMLDisplay *efhd;
-
-	/* FIXME The PURI struct seems to have some lifecycle issues,
-	 *       because casting info->puri.format to an EMFormatHTML
-	 *       can lead to crashes.  So we hack around it. */
-	efh = g_object_get_data (G_OBJECT (button), "efh");
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-
-	if (efh->state == EM_FORMAT_HTML_STATE_RENDERING)
-		return;
-
-	info->shown = e_attachment_button_get_expanded (button);
-
-	em_format_set_inline (
-		info->puri.format, info->puri.part_id, info->shown);
-
-	efhd = (EMFormatHTMLDisplay *) efh;
-	g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd));
-
-	efhd->priv->attachment_expanded = TRUE;
-}
-
-/* ********************************************************************** */
-
-static void
-attachment_button_realized (GtkWidget *widget)
-{
-	EMFormatHTML *efh = g_object_get_data (G_OBJECT (widget), "efh");
-	EMFormatHTMLDisplay *efhd;
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-
-	efhd = (EMFormatHTMLDisplay *) efh;
-	g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd));
-
-	gtk_widget_grab_focus (widget);
-	efhd->priv->attachment_expanded = FALSE;
+	puri->description = g_string_free (buffer, FALSE);
 }
 
 /* ********************************************************************** */
 
 /* attachment button callback */
 static GtkWidget*
-efhd_attachment_button (EMFormatHTML *efh,
-						EMFormatHTMLPObject *pobject)
+efhd_attachment_button (EMFormat *emf,
+						EMFormatPURI *puri,
+						GCancellable *cancellable)
 {
+	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
+	EMFormatHTML *efh = (EMFormatHTML *) emf;
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh;
-	struct _attach_puri *info;
 	EAttachmentView *view;
 	EAttachmentStore *store;
 	EAttachment *attachment;
-	EWebView *web_view;
+	//EWebView *web_view;
 	GtkWidget *widget;
 	gpointer parent;
-	EMFormat *emf = (EMFormat *) efh;
 	guint32 size = 0;
 
 	/* FIXME: handle default shown case */
 	d(printf("adding attachment button/content\n"));
 
-	if (emf->folder && emf->folder->summary && emf->uid) {
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
+	if (emf->folder && emf->folder->summary && emf->message_uid) {
 		CamelMessageInfo *mi;
 
 		mi = camel_folder_summary_get (emf->folder->summary, emf->uid);
 		if (mi) {
 			const CamelMessageContentInfo *ci;
 
-			ci = camel_folder_summary_guess_content_info (mi, camel_mime_part_get_content_type (pobject->part));
+			ci = camel_folder_summary_guess_content_info (mi,
+					camel_mime_part_get_content_type (info->puri.part));
 			if (ci) {
 				size = ci->size;
 				/* what if its not encoded in base64 ? is it a case to consider? */
@@ -1114,8 +934,6 @@ efhd_attachment_button (EMFormatHTML *efh,
 		}
 	}
 
-	info = (struct _attach_puri *) em_format_find_puri ((EMFormat *) efh, pobject->classid);
-
 	if (!info || info->forward) {
 		g_warning ("unable to expand the attachment\n");
 		return NULL;
@@ -1127,10 +945,13 @@ efhd_attachment_button (EMFormatHTML *efh,
 	e_attachment_set_encrypted (attachment, info->encrypt);
 	e_attachment_set_can_show (attachment, info->handle != NULL);
 
+	/* FIXME WEBKIT: We need some root-element
 	web_view = em_format_html_get_web_view (efh);
 	g_return_val_if_fail (web_view != NULL, TRUE);
 	parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+	*/
+	parent = NULL;
 
 	view = em_format_html_display_get_attachment_view (efhd, info->attachment_view_part_id);
 	g_return_val_if_fail (view != NULL, TRUE);
@@ -1162,20 +983,6 @@ efhd_attachment_button (EMFormatHTML *efh,
 	 *       a reference count? */
 	g_object_set_data (G_OBJECT (widget), "efh", efh);
 
-	g_signal_connect (
-		widget, "notify::expanded",
-		G_CALLBACK (efhd_attachment_button_expanded), info);
-
-	/* If the button is created, then give it focus after
-	 * it is realized, so that user can use arrow keys to scroll
-	 * message */
-	 /* WEBKIT: Is this still needed? */
-	if (efhd->priv->attachment_expanded || e_attachment_button_get_expanded (E_ATTACHMENT_BUTTON (widget))) {
-		g_signal_connect (
-			widget, "realize",
-			G_CALLBACK (attachment_button_realized), NULL);
-	}
-
 	return widget;
 }
 
@@ -1185,6 +992,9 @@ efhd_attachment_frame (EMFormat *emf,
                        EMFormatPURI *puri,
                        GCancellable *cancellable)
 {
+	/* FIXME WEBKIT Heeeelp, I can't force Evo to call this function
+	 * so I don't know what it actually does :(
+
 	struct _attach_puri *info = (struct _attach_puri *) puri;
 
 	if (info->shown)
@@ -1193,6 +1003,7 @@ efhd_attachment_frame (EMFormat *emf,
 			info->handle, cancellable, FALSE);
 
 	camel_stream_close (stream, cancellable, NULL);
+	*/
 }
 
 static void
@@ -1215,11 +1026,13 @@ efhd_bar_resize (EMFormatHTML *efh,
 
 	priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efh);
 
+	/* FIXME WEBKIT: Ehm :)
 	web_view = em_format_html_get_web_view (efh);
 
 	widget = GTK_WIDGET (web_view);
 	gtk_widget_get_allocation (widget, &allocation);
 	width = allocation.width - 12;
+	*/
 
 	if (width > 0) {
 		g_hash_table_foreach (priv->attachment_views, set_size_request_cb, GINT_TO_POINTER (width));
@@ -1227,24 +1040,30 @@ efhd_bar_resize (EMFormatHTML *efh,
 }
 
 static GtkWidget*
-efhd_add_bar (EMFormatHTML *efh,
-              EMFormatHTMLPObject *pobject)
+efhd_add_bar (EMFormat *emf,
+			  EMFormatPURI *puri,
+              GCancellable *cancellable)
 {
+    EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
+    EMFormatHTML *efh = (EMFormatHTML *) emf;
 	EMFormatHTMLDisplayPrivate *priv;
 	GtkWidget *widget;
 
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
+
 	/* XXX See note in efhd_message_add_bar(). */
 	if (!EM_IS_FORMAT_HTML_DISPLAY (efh))
 		return FALSE;
 
-	g_return_val_if_fail (pobject != NULL && pobject->classid != NULL, FALSE);
-	g_return_val_if_fail (g_str_has_prefix (pobject->classid, "attachment-bar:"), FALSE);
+	g_return_val_if_fail (info != NULL, FALSE);
+	g_return_val_if_fail (g_str_has_prefix (info->puri.uri, "attachment-bar:"), FALSE);
 
 	priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efh);
 
 	widget = e_mail_attachment_bar_new ();
 
-	g_hash_table_insert (priv->attachment_views, g_strdup (strchr (pobject->classid, ':') + 1), widget);
+	g_hash_table_insert (priv->attachment_views, g_strdup (strchr (info->puri.uri, ':') + 1), widget);
 	g_object_weak_ref (G_OBJECT (widget), efhd_attachment_view_gone_cb, efh);
 	gtk_widget_hide (widget);
 
@@ -1257,29 +1076,31 @@ efhd_add_bar (EMFormatHTML *efh,
 
 static void
 efhd_message_add_bar (EMFormat *emf,
-                      CamelStream *stream,
                       CamelMimePart *part,
-                      const EMFormatHandler *info)
+                      GString *part_id,
+                      EMFormatParserInfo *info,
+                      GCancellable *cancellable)
 {
 	gchar *classid;
 	gchar *content;
+	EMFormatAttachmentPURI *puri;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
 	classid = g_strdup_printf (
-		"attachment-bar:%s", emf->current_message_part_id);
+		"attachment-bar:%s", part_id->str);
 
 	/* XXX Apparently this installs the callback for -all-
 	 *     EMFormatHTML subclasses, not just this subclass.
 	 *     Bad idea.  So we have to filter out other types
 	 *     in the callback. */
-	em_format_html_add_pobject (
-		EM_FORMAT_HTML (emf),
-		sizeof (EMFormatHTMLPObject),
-		classid, part, efhd_add_bar);
+	/* FIXME WEBKIT: oh, rly? ^^^ */
+	puri = (EMFormatAttachmentPURI *) em_format_puri_new (
+			emf, sizeof (EMFormatAttachmentPURI), part, classid);
+	puri->puri.widget_func = efhd_add_bar;
+	em_format_add_puri (emf, (EMFormatPURI*) puri);
 
-	content = g_strdup_printf (
-		"<td><object data=\"%s\" type=\"application/x-gtk-widget\"></object></td>", classid);
-	camel_stream_write_string (stream, content, NULL, NULL);
-	g_free (content);
 
 	g_free (classid);
 }
@@ -1307,17 +1128,19 @@ efhd_resize (GtkWidget *w,
 	EWebView *web_view;
 	GtkAllocation allocation;
 
+	/* FIXME WEBKIT: Emh...
 	web_view = em_format_html_get_web_view (efh);
 	gtk_widget_get_allocation (GTK_WIDGET (web_view), &allocation);
 	gtk_widget_set_size_request (w, allocation.width - 48, 250);
+	*/
 }
 
 /* optional render attachment button callback */
 static GtkWidget*
-efhd_attachment_optional (EMFormatHTML *efh,
-						  EMFormatHTMLPObject *pobject)
+efhd_attachment_optional (EMFormat *efh,
+						  EMFormatPURI *puri,
+						  GCancellable *cancellable)
 {
-	struct _attach_puri *info;
 	GtkWidget *hbox, *vbox, *button, *mainbox, *scroll, *label, *img;
 	AtkObject *a11y;
 	GtkWidget *view;
@@ -1325,11 +1148,14 @@ efhd_attachment_optional (EMFormatHTML *efh,
 	GtkTextBuffer *buffer;
 	GByteArray *byte_array;
 	EWebView *web_view;
+	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return NULL;
 
 	/* FIXME: handle default shown case */
 	d(printf("adding attachment button/content for optional rendering\n"));
 
-	info = (struct _attach_puri *) em_format_find_puri ((EMFormat *) efh, pobject->classid);
 	if (!info || info->forward) {
 		g_warning ("unable to expand the attachment\n");
 		return NULL;
@@ -1396,11 +1222,13 @@ efhd_attachment_optional (EMFormatHTML *efh,
 	gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 6);
 	gtk_widget_show (GTK_WIDGET (view));
 
+	/* FIXME WEBKIT hmm, what to do?
 	web_view = em_format_html_get_web_view (efh);
 	gtk_widget_get_allocation (GTK_WIDGET (web_view), &allocation);
 	gtk_widget_set_size_request (scroll, allocation.width - 48, 250);
 	g_signal_connect (scroll, "size_allocate", G_CALLBACK(efhd_resize), efh);
 	gtk_widget_show (scroll);
+	*/
 
 	if (!info->shown)
 		gtk_widget_hide (scroll);
@@ -1414,7 +1242,7 @@ efhd_attachment_optional (EMFormatHTML *efh,
 static void
 efhd_free_attach_puri_data (EMFormatPURI *puri)
 {
-	struct _attach_puri *info = (struct _attach_puri *) puri;
+	EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri;
 
 	g_return_if_fail (puri != NULL);
 
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index ec29698..fae5a96 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -52,6 +52,51 @@ G_BEGIN_DECLS
 typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay;
 typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass;
 typedef struct _EMFormatHTMLDisplayPrivate EMFormatHTMLDisplayPrivate;
+typedef struct _EMFormatAttachmentPURI EMFormatAttachmentPURI;
+typedef struct _EMFormatSMIMEPURI EMFormatSMIMEPURI;
+
+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;
+
+	/* Signed / Encrypted */
+	camel_cipher_validity_sign_t sign;
+	camel_cipher_validity_encrypt_t encrypt;
+};
+
+struct _EMFormatSMIMEPURI {
+	EMFormatPURI puri;
+
+	EMFormatWidgetFunc widget_func;
+
+	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 e03c9a1..dbfef3c 100644
--- a/mail/em-format-html-print.c
+++ b/mail/em-format-html-print.c
@@ -85,6 +85,7 @@ em_format_html_print_init (EMFormatHTMLPrint *efhp)
 {
 	EWebView *web_view;
 
+	/* FIXME WEBKIT: this ain't gonna work
 	web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhp));
 
 	/* gtk widgets don't like to be realized outside top level widget
@@ -93,7 +94,10 @@ em_format_html_print_init (EMFormatHTMLPrint *efhp)
 	gtk_container_add (GTK_CONTAINER (efhp->window), GTK_WIDGET (web_view));
 	gtk_widget_realize (GTK_WIDGET (web_view));
 	efhp->parent.show_icon = FALSE;
+	*/
+	/* FIXME WEBKIT
 	((EMFormat *) efhp)->print = TRUE;
+	*/
 
 	efhp->export_filename = NULL;
 	efhp->async = TRUE;
@@ -187,10 +191,8 @@ emfhp_complete (EMFormatHTMLPrint *efhp)
 	EWebView *web_view;
 	GError *error = NULL;
 
-	web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhp));
-
 	operation = e_print_operation_new ();
-
+/* FIXME WEBKIT: Port to webkit's API, probably from outside
 	if (efhp->action == GTK_PRINT_OPERATION_ACTION_EXPORT)
 		gtk_print_operation_set_export_filename (operation, efhp->export_filename);
 
@@ -202,7 +204,7 @@ emfhp_complete (EMFormatHTMLPrint *efhp)
 		(GtkHTMLPrintDrawFunc) NULL,
 		(GtkHTMLPrintDrawFunc) efhp_draw_footer,
 		NULL, &error);
-
+*/
 	g_object_unref (operation);
 }
 
@@ -225,7 +227,7 @@ em_format_html_print_message (EMFormatHTMLPrint *efhp,
 		efhp, "complete", G_CALLBACK (emfhp_complete), efhp);
 
 	/* FIXME Not passing a GCancellable here. */
-	em_format_format_clone (
+	em_format_parse (EM_FORMAT (efhp), message, folder, NULL);
 		(EMFormat *) efhp,
 		folder, message_uid, message,
 		(EMFormat *) efhp->source, NULL);
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 465a4b2..2e37527 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -63,6 +63,7 @@
 
 #include "em-format-html.h"
 #include "em-utils.h"
+#include <em-format/em-inline-filter.h>
 
 #define EM_FORMAT_HTML_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -70,21 +71,7 @@
 
 #define d(x)
 
-#define EFM_MESSAGE_START_ANAME "evolution_message_start"
-#define EFH_MESSAGE_START "<A name=\"" EFM_MESSAGE_START_ANAME "\"></A>"
-
-struct _EMFormatHTMLCache {
-	CamelMultipart *textmp;
-
-	gchar partid[1];
-};
-
 struct _EMFormatHTMLPrivate {
-	EWebView *web_view;
-
-	/* Table that re-maps text parts into a mutlipart/mixed, EMFormatHTMLCache * */
-	GHashTable *text_inline_parts;
-
 	GdkColor colors[EM_FORMAT_HTML_NUM_COLOR_TYPES];
 	EMailImageLoadingPolicy image_loading_policy;
 
@@ -97,6 +84,8 @@ struct _EMFormatHTMLPrivate {
 	guint show_real_date	: 1;
 };
 
+static gpointer parent_class;
+
 enum {
 	PROP_0,
 	PROP_BODY_COLOR,
@@ -110,1859 +99,1547 @@ enum {
 	PROP_SHOW_SENDER_PHOTO,
 	PROP_SHOW_REAL_DATE,
 	PROP_TEXT_COLOR,
-	PROP_WEB_VIEW,
 	PROP_HEADERS_STATE,
 	PROP_HEADERS_COLLAPSABLE
 };
 
+#define EFM_MESSAGE_START_ANAME "evolution_message_start"
+#define EFH_MESSAGE_START "<A name=\"" EFM_MESSAGE_START_ANAME "\"></A>"
+#define EFH_HTML_HEADER "<!DOCTYPE HTML>\n<html>\n"  \
+		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n" \
+		"<title>Evolution Mail Display</title>\n" \
+		"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n" \
+		"<style type=\"text/css\">\n" \
+		"  table th { color: #000; font-weight: bold; }\n" \
+		"</style>\n" \
+		"<script type=\"text/javascript\">\n" \
+		"function body_loaded() { window.location.hash='" EFM_MESSAGE_START_ANAME "'; }\n" \
+		"function collapse_addresses(field) {\n" \
+		"  var e=window.document.getElementById(\"moreaddr-\"+field).style;\n" \
+		"  var f=window.document.getElementById(\"moreaddr-ellipsis-\"+field).style;\n" \
+		"  var g=window.document.getElementById(\"moreaddr-img-\"+field);\n" \
+		"  if (e.display==\"inline\") { e.display=\"none\"; f.display=\"inline\"; g.src=g.src.substr(0,g.src.lastIndexOf(\"/\"))+\"/plus.png\"; }\n" \
+		"  else { e.display=\"inline\"; f.display=\"none\"; g.src=g.src.substr(0,g.src.lastIndexOf(\"/\"))+\"/minus.png\"; }\n" \
+		"}\n" \
+		"function collapse_headers() {\n" \
+		"  var f=window.document.getElementById(\"full-headers\").style;\n" \
+		"  var s=window.document.getElementById(\"short-headers\").style;\n" \
+		"  var i=window.document.getElementById(\"collapse-headers-img\");\n" \
+		"  if (f.display==\"block\") { f.display=\"none\"; s.display=\"block\";\n" \
+		"	i.src=i.src.substr(0,i.src.lastIndexOf(\"/\"))+\"/plus.png\"; window.headers_collapsed(true, window.em_format_html); }\n" \
+		"  else { f.display=\"block\"; s.display=\"none\";\n" \
+		"	 i.src=i.src.substr(0,i.src.lastIndexOf(\"/\"))+\"/minus.png\"; window.headers_collapsed(false, window.em_format_html); }\n" \
+		"}\n" \
+		"</script>\n" \
+		"</head>\n" \
+		"<body style=\"background: #%06x; color: #%06x;\" onLoad=\"body_loaded();\">"
+#define EFH_HTML_FOOTER "</body></html>"
+
+static void efh_parse_image			(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
+static void efh_parse_text_enriched		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
+static void efh_parse_text_plain		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
+static void efh_parse_text_html			(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
+static void efh_parse_message_external		(EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable);
+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, GCancellable *cancellable);
+static void efh_write_text_enriched		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, GCancellable *cancellable);
+static void efh_write_text_plain		(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, GCancellable *cancellable);
+static void efh_write_text_html			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, GCancellable *cancellable);
+static void efh_write_source			(EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, GCancellable *cancellable);
+/*****************************************************************************/
+static void
+efh_parse_image (EMFormat *emf,
+		 CamelMimePart *part,
+		 GString *part_id,
+		 EMFormatParserInfo *info,
+		 GCancellable *cancellable)
+{
+	EMFormatPURI *puri;
+	const gchar *tmp;
+	gchar *cid;
+	gint len;
 
-static void	efh_format_message		(EMFormat *emf,
-						 CamelStream *stream,
-						 CamelMimePart *part,
-						 const EMFormatHandler *info,
-						 GCancellable *cancellable,
-						 gboolean is_fallback);
-
-static void	efh_format_secure		(EMFormat *emf,
-						 CamelStream *stream,
-						 CamelMimePart *part,
-						 CamelCipherValidity *valid,
-						 GCancellable *cancellable);
-
-static void	efh_builtin_init		(EMFormatHTMLClass *efhc);
-
-static void	efh_write_image			(EMFormat *emf,
-						 CamelStream *stream,
-						 EMFormatPURI *puri,
-						 GCancellable *cancellable);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-static gpointer parent_class;
-static CamelDataCache *emfh_http_cache;
+	tmp = camel_mime_part_get_content_id (part);
+	if (!tmp) {
+		cid = g_strdup_printf ("em-no-cid:%s", part_id->str);
+	} else {
+		cid = g_strdup_printf ("cid:%s", tmp);
+	}
 
-#define EMFH_HTTP_CACHE_PATH "http"
+	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;
 
+	em_format_add_puri (emf, puri);
+	g_string_truncate (part_id, len);
+}
 
 static void
-efh_free_cache (struct _EMFormatHTMLCache *efhc)
+efh_parse_text_enriched (EMFormat *emf,
+			 CamelMimePart *part,
+			 GString *part_id,
+			 EMFormatParserInfo *info,
+			 GCancellable *cancellable)
 {
-	if (efhc->textmp)
-		g_object_unref (efhc->textmp);
-	g_free (efhc);
-}
+	EMFormatPURI *puri;
+	const gchar *tmp;
+	gchar *cid;
+	gint len;
 
-static struct _EMFormatHTMLCache *
-efh_insert_cache (EMFormatHTML *efh,
-                  const gchar *partid)
-{
-	struct _EMFormatHTMLCache *efhc;
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	tmp = camel_mime_part_get_content_id (part);
+	if (!tmp) {
+		cid = g_strdup_printf ("em-no-cid:%s", part_id->str);
+	} else {
+		cid = g_strdup_printf ("cid:%s", tmp);
+	}
 
-	efhc = g_malloc0 (sizeof (*efh) + strlen (partid));
-	strcpy (efhc->partid, partid);
-	g_hash_table_insert (efh->priv->text_inline_parts, efhc->partid, efhc);
+	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->write_func = efh_write_text_enriched;
 
-	return efhc;
+	em_format_add_puri (emf, puri);
+	g_string_truncate (part_id, len);
 }
 
 static void
-efh_set_property (GObject *object,
-                  guint property_id,
-                  const GValue *value,
-                  GParamSpec *pspec)
+efh_parse_text_plain (EMFormat *emf,
+		      CamelMimePart *part,
+		      GString *part_id,
+		      EMFormatParserInfo *info,
+		      GCancellable *cancellable)
 {
-	switch (property_id) {
-		case PROP_BODY_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_BODY,
-				g_value_get_boxed (value));
-			return;
+	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
+	CamelStream *filtered_stream;
+	CamelMultipart *mp;
+	CamelDataWrapper *dw;
+	CamelContentType *type;
+	gint i, count, len;
 
-		case PROP_CITATION_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_CITATION,
-				g_value_get_boxed (value));
-			return;
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-		case PROP_CONTENT_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_CONTENT,
-				g_value_get_boxed (value));
-			return;
+	dw = camel_medium_get_content ((CamelMedium *) part);
+	if (!dw)
+		return;
 
-		case PROP_FRAME_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_FRAME,
-				g_value_get_boxed (value));
-			return;
+	/* This scans the text part for inline-encoded data, creates
+	   a multipart of all the parts inside it. */
 
-		case PROP_HEADER_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_HEADER,
-				g_value_get_boxed (value));
-			return;
+	/* FIXME: We should discard this multipart if it only contains
+	   the original text, but it makes this hash lookup more complex */
 
-		case PROP_IMAGE_LOADING_POLICY:
-			em_format_html_set_image_loading_policy (
-				EM_FORMAT_HTML (object),
-				g_value_get_enum (value));
-			return;
+	/* TODO: We could probably put this in the superclass, since
+	   no knowledge of html is required - but this messes with
+	   filters a bit.  Perhaps the superclass should just deal with
+	   html anyway and be done with it ... */
 
-		case PROP_MARK_CITATIONS:
-			em_format_html_set_mark_citations (
-				EM_FORMAT_HTML (object),
-				g_value_get_boolean (value));
-			return;
+	/* FIXME WEBKIT no cache
+	efhc = g_hash_table_lookup (
+		efh->priv->text_inline_parts,
+		emf->part_id->str);
 
-		case PROP_ONLY_LOCAL_PHOTOS:
-			em_format_html_set_only_local_photos (
-				EM_FORMAT_HTML (object),
-				g_value_get_boolean (value));
-			return;
+	if (efhc == NULL || (mp = efhc->textmp) == NULL) {
+	*/
+	if (TRUE) {
+		EMInlineFilter *inline_filter;
+		CamelStream *null;
+		CamelContentType *ct;
+		gboolean charset_added = FALSE;
+		const gchar *snoop_type;
 
-		case PROP_SHOW_SENDER_PHOTO:
-			em_format_html_set_show_sender_photo (
-				EM_FORMAT_HTML (object),
-				g_value_get_boolean (value));
-			return;
+		snoop_type = em_format_snoop_type (part);
 
-		case PROP_SHOW_REAL_DATE:
-			em_format_html_set_show_real_date (
-				EM_FORMAT_HTML (object),
-				g_value_get_boolean (value));
-			return;
+		/* if we had to snoop the part type to get here, then
+		 * use that as the base type, yuck */
+		if (snoop_type == NULL
+		    || (ct = camel_content_type_decode (snoop_type)) == NULL) {
+			ct = dw->mime_type;
+			camel_content_type_ref (ct);
+		}
 
-		case PROP_TEXT_COLOR:
-			em_format_html_set_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_TEXT,
-				g_value_get_boxed (value));
-			return;
-		case PROP_HEADERS_STATE:
-			em_format_html_set_headers_state (
-				EM_FORMAT_HTML (object),
-				g_value_get_int (value));
-			return;
-		case PROP_HEADERS_COLLAPSABLE:
-			em_format_html_set_headers_collapsable (
-				EM_FORMAT_HTML (object),
-				g_value_get_boolean (value));
+		if (dw->mime_type && ct != dw->mime_type && camel_content_type_param (dw->mime_type, "charset")) {
+			camel_content_type_set_param (ct, "charset", camel_content_type_param (dw->mime_type, "charset"));
+			charset_added = TRUE;
+		}
+
+		null = camel_stream_null_new ();
+		filtered_stream = camel_stream_filter_new (null);
+		g_object_unref (null);
+		inline_filter = em_inline_filter_new (camel_mime_part_get_encoding (part), ct);
+		camel_stream_filter_add (
+			CAMEL_STREAM_FILTER (filtered_stream),
+			CAMEL_MIME_FILTER (inline_filter));
+		camel_data_wrapper_decode_to_stream_sync (
+			dw, (CamelStream *) filtered_stream, cancellable, NULL);
+		camel_stream_close ((CamelStream *) filtered_stream, cancellable, NULL);
+		g_object_unref (filtered_stream);
+
+		mp = em_inline_filter_get_multipart (inline_filter);
+		/* FIXME WEBKIT
+		if (efhc == NULL)
+			efhc = efh_insert_cache (efh, emf->part_id->str);
+		efhc->textmp = mp;
+		*/
+
+		if (charset_added) {
+			camel_content_type_set_param (ct, "charset", NULL);
+		}
+
+		g_object_unref (inline_filter);
+		camel_content_type_unref (ct);
 	}
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	/* We handle our made-up multipart here, so we don't recursively call ourselves */
+	len = part_id->len;
+	count = camel_multipart_get_number (mp);
+	for (i=0;i<count;i++) {
+		CamelMimePart *newpart = camel_multipart_get_part (mp, i);
+
+		if (!newpart)
+			continue;
+
+		type = camel_mime_part_get_content_type (newpart);
+		if (camel_content_type_is (type, "text", "*") && (!camel_content_type_is (type, "text", "calendar"))) {
+			EMFormatPURI *puri;
+			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;
+			g_string_truncate (part_id, s_len);
+			em_format_add_puri (emf, puri);
+		} else {
+			g_string_append_printf (part_id, ".inline.%d", i);
+			em_format_parse_part (emf, CAMEL_MIME_PART (newpart), part_id, info, cancellable);
+			g_string_truncate (part_id, len);
+		}
+	}
+
+	g_object_unref (mp);
 }
 
 static void
-efh_get_property (GObject *object,
-                  guint property_id,
-                  GValue *value,
-                  GParamSpec *pspec)
+efh_parse_text_html (EMFormat *emf,
+		     CamelMimePart *part,
+		     GString *part_id,
+		     EMFormatParserInfo *info,
+		     GCancellable *cancellable)
 {
-	GdkColor color;
+	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
+	EMFormatPURI *puri;
+	const gchar *location;
+	gchar *cid = NULL;
+	CamelURL *base;
+	gint len;
 
-	switch (property_id) {
-		case PROP_BODY_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_BODY,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-		case PROP_CITATION_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_CITATION,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+	base = em_format_get_base_url (emf);
+	location = camel_mime_part_get_content_location (part);
+	if (location == NULL) {
+		if (base)
+			cid = camel_url_to_string (base, 0);
+		else
+			cid = g_strdup (part_id->str);
+	} else {
+		if (strchr (location, ':') == NULL && base != NULL) {
+			CamelURL *uri;
 
-		case PROP_CONTENT_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_CONTENT,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+			uri = camel_url_new_with_base (base, location);
+			cid = camel_url_to_string (uri, 0);
+			camel_url_free (uri);
+		} else {
+			cid = g_strdup (location);
+		}
+	}
 
-		case PROP_FRAME_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_FRAME,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+	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;
 
-		case PROP_HEADER_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_HEADER,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+	em_format_add_puri (emf, puri);
+	g_string_truncate (part_id, len);
+}
 
-		case PROP_IMAGE_LOADING_POLICY:
-			g_value_set_enum (
-				value,
-				em_format_html_get_image_loading_policy (
-				EM_FORMAT_HTML (object)));
-			return;
-
-		case PROP_MARK_CITATIONS:
-			g_value_set_boolean (
-				value, em_format_html_get_mark_citations (
-				EM_FORMAT_HTML (object)));
-			return;
+static void
+efh_parse_message_external (EMFormat *emf,
+			    CamelMimePart *part,
+			    GString *part_id,
+			    EMFormatParserInfo *info,
+			    GCancellable *cancellable)
+{
+	EMFormatPURI *puri;
+	CamelMimePart *newpart;
+	CamelContentType *type;
+	const gchar *access_type;
+	gchar *url = NULL, *desc = NULL;
+	gchar *content;
+	gint len;
 
-		case PROP_ONLY_LOCAL_PHOTOS:
-			g_value_set_boolean (
-				value, em_format_html_get_only_local_photos (
-				EM_FORMAT_HTML (object)));
-			return;
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-		case PROP_SHOW_SENDER_PHOTO:
-			g_value_set_boolean (
-				value, em_format_html_get_show_sender_photo (
-				EM_FORMAT_HTML (object)));
-			return;
+	newpart = camel_mime_part_new ();
 
-		case PROP_SHOW_REAL_DATE:
-			g_value_set_boolean (
-				value, em_format_html_get_show_real_date (
-				EM_FORMAT_HTML (object)));
-			return;
+	/* needs to be cleaner */
+	type = camel_mime_part_get_content_type (part);
+	access_type = camel_content_type_param (type, "access-type");
+	if (!access_type) {
+		const gchar *msg = _("Malformed external-body part");
+		camel_mime_part_set_content (newpart, msg, strlen (msg),
+				"text/plain");
+		goto addPart;
+	}
 
-		case PROP_TEXT_COLOR:
-			em_format_html_get_color (
-				EM_FORMAT_HTML (object),
-				EM_FORMAT_HTML_COLOR_TEXT,
-				&color);
-			g_value_set_boxed (value, &color);
-			return;
+	if (!g_ascii_strcasecmp(access_type, "ftp") ||
+	    !g_ascii_strcasecmp(access_type, "anon-ftp")) {
+		const gchar *name, *site, *dir, *mode;
+		gchar *path;
+		gchar ftype[16];
 
-		case PROP_WEB_VIEW:
-			g_value_set_object (
-				value, em_format_html_get_web_view (
-				EM_FORMAT_HTML (object)));
-			return;
-		case PROP_HEADERS_STATE:
-			g_value_set_int (
-				value, em_format_html_get_headers_state (
-				EM_FORMAT_HTML (object)));
-			return;
-		case PROP_HEADERS_COLLAPSABLE:
-			g_value_set_boolean (
-				value, em_format_html_get_headers_collapsable (
-				EM_FORMAT_HTML (object)));
-	}
+		name = camel_content_type_param (type, "name");
+		site = camel_content_type_param (type, "site");
+		dir = camel_content_type_param (type, "directory");
+		mode = camel_content_type_param (type, "mode");
+		if (name == NULL || site == NULL)
+			goto fail;
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-}
+		/* Generate the path. */
+		if (dir)
+			path = g_strdup_printf("/%s/%s", *dir=='/'?dir+1:dir, name);
+		else
+			path = g_strdup_printf("/%s", *name=='/'?name+1:name);
 
-static void
-efh_finalize (GObject *object)
-{
-	EMFormatHTML *efh = EM_FORMAT_HTML (object);
-	EMFormatHTMLPrivate *priv = efh->priv;
+		if (mode && *mode)
+			sprintf(ftype, ";type=%c",  *mode);
+		else
+			ftype[0] = 0;
 
-	em_format_html_clear_pobject (efh);
+		url = g_strdup_printf ("ftp://%s%s%s";, site, path, ftype);
+		g_free (path);
+		desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url);
+	} else if (!g_ascii_strcasecmp (access_type, "local-file")) {
+		const gchar *name, *site;
 
-	if (priv->web_view != NULL) {
-		g_object_unref (priv->web_view);
-		efh->priv->web_view = NULL;
-	}
+		name = camel_content_type_param (type, "name");
+		site = camel_content_type_param (type, "site");
+		if (name == NULL)
+			goto fail;
 
-	g_hash_table_destroy (priv->text_inline_parts);
+		url = g_filename_to_uri (name, NULL, NULL);
+		if (site)
+			desc = g_strdup_printf(_("Pointer to local file (%s) valid at site \"%s\""), name, site);
+		else
+			desc = g_strdup_printf(_("Pointer to local file (%s)"), name);
+	} else if (!g_ascii_strcasecmp (access_type, "URL")) {
+		const gchar *urlparam;
+		gchar *s, *d;
 
-	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
+		/* RFC 2017 */
+		urlparam = camel_content_type_param (type, "url");
+		if (urlparam == NULL)
+			goto fail;
 
-static void
-efh_format_error (EMFormat *emf,
-                  CamelStream *stream,
-                  const gchar *txt)
-{
-	GString *buffer;
-	gchar *html;
+		/* For obscure MIMEy reasons, the URL may be split into words */
+		url = g_strdup (urlparam);
+		s = d = url;
+		while (*s) {
+			if (!isspace ((guchar)*s))
+				*d++ = *s;
+			s++;
+		}
+		*d = 0;
+		desc = g_strdup_printf (_("Pointer to remote data (%s)"), url);
+	} else
+		goto fail;
 
-	buffer = g_string_new ("<em><font color=\"red\">");
+	content = g_strdup_printf ("<a href=\"%s\">%s</a>", url, desc);
+	camel_mime_part_set_content (newpart, content, strlen (content), "text/html");
+	g_free (content);
 
-	html = camel_text_to_html (
-		txt, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	g_string_append (buffer, html);
-	g_free (html);
+	g_free (url);
+	g_free (desc);
 
-	g_string_append (buffer, "</font></em><br>");
+fail:
+	content = g_strdup_printf (
+		_("Pointer to unknown external data (\"%s\" type)"),
+		access_type);
+	camel_mime_part_set_content (newpart, content, strlen (content), "text/plain");
+	g_free (content);
 
-	camel_stream_write (stream, buffer->str, buffer->len, NULL, NULL);
+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;
 
-	g_string_free (buffer, TRUE);
+	em_format_add_puri (emf, puri);
+	g_string_truncate (part_id, len);
 }
 
 static void
-efh_format_source (EMFormat *emf,
-		   CamelStream *stream,
-		   CamelMimePart *part,
-                   GCancellable *cancellable)
+efh_parse_message_deliverystatus (EMFormat *emf,
+				  CamelMimePart *part,
+				  GString *part_id,
+				  EMFormatParserInfo *info,
+				  GCancellable *cancellable)
 {
-	CamelStream *filtered_stream;
-	CamelMimeFilter *filter;
-	CamelDataWrapper *dw = (CamelDataWrapper *) part;
-
-	filtered_stream = camel_stream_filter_new (stream);
+	EMFormatPURI *puri;
+	gint len;
 
-	filter = camel_mime_filter_tohtml_new (
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
-		CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
-	camel_stream_filter_add (
-		CAMEL_STREAM_FILTER (filtered_stream), filter);
-	g_object_unref (filter);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	camel_stream_write_string (
-		stream, "<code class=\"pre\">", cancellable, NULL);
-	em_format_format_text (emf, filtered_stream, dw, cancellable);
-	camel_stream_write_string (
-		stream, "</code>", cancellable, NULL);
+	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;
 
-	g_object_unref (filtered_stream);
+	em_format_add_puri (emf, puri);
+	g_string_truncate (part_id, len);
 }
 
-static void
-efh_format_attachment (EMFormat *emf,
-                       CamelStream *stream,
-                       CamelMimePart *part,
-                       const gchar *mime_type,
-                       const EMFormatHandler *handle,
-                       GCancellable *cancellable)
-{
-	gchar *text, *html;
 
-	/* we display all inlined attachments only */
+/*****************************************************************************/
 
-	/* this could probably be cleaned up ... */
-	camel_stream_write_string (
-		stream,
-		"<table border=1 cellspacing=0 cellpadding=0><tr><td>"
-		"<table width=10 cellspacing=0 cellpadding=0>"
-		"<tr><td></td></tr></table></td>"
-		"<td><table width=3 cellspacing=0 cellpadding=0>"
-		"<tr><td></td></tr></table></td><td><font size=-1>\n",
-		cancellable, NULL);
 
-	/* output some info about it */
-	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);
-	camel_stream_write_string (stream, html, cancellable, NULL);
-	g_free (html);
-	g_free (text);
+static void
+efh_write_image (EMFormat *emf,
+		 EMFormatPURI *puri,
+		 CamelStream *stream,
+		 GCancellable *cancellable)
+{
+	GByteArray *ba;
+	CamelDataWrapper *dw;
+	gchar *content;
 
-	camel_stream_write_string (
-		stream, "</font></td></tr><tr></table>", cancellable, NULL);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	if (handle && em_format_is_inline (emf, emf->part_id->str, part, handle))
-		handle->handler (emf, stream, part, handle, cancellable, FALSE);
+	/* FIXME: What about some error string when dw == NULL? */
+	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
+	if (dw) {
+		ba = camel_data_wrapper_get_byte_array (dw);
+		content = g_strndup ((gchar *) ba->data, ba->len);
+		camel_stream_write_string (stream, content, cancellable, NULL);
+		g_free (content);
+	}
 }
 
 static void
-efh_base_init (EMFormatHTMLClass *class)
+efh_write_text_enriched (EMFormat *emf,
+			 EMFormatPURI *puri,
+			 CamelStream *stream,
+			 GCancellable *cancellable)
 {
-	efh_builtin_init (class);
-}
+	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
+	CamelStream *filtered_stream;
+	CamelMimeFilter *enriched;
+	guint32 flags = 0;
+	gchar *content;
+	CamelContentType *ct;
+	gchar *mime_type = NULL;
 
-static void
-efh_class_init (EMFormatHTMLClass *class)
-{
-	GObjectClass *object_class;
-	EMFormatClass *format_class;
-	const gchar *user_cache_dir;
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	parent_class = g_type_class_peek_parent (class);
-	g_type_class_add_private (class, sizeof (EMFormatHTMLPrivate));
+	ct = camel_mime_part_get_content_type (puri->part);
+	if (ct) {
+		mime_type = camel_content_type_simple (ct);
+	}
 
-	object_class = G_OBJECT_CLASS (class);
-	object_class->set_property = efh_set_property;
-	object_class->get_property = efh_get_property;
-	object_class->finalize = efh_finalize;
+	if (!g_strcmp0(mime_type, "text/richtext")) {
+		flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+		camel_stream_write_string (
+			stream, "\n<!-- text/richtext -->\n",
+			cancellable, NULL);
+	} else {
+		camel_stream_write_string (
+			stream, "\n<!-- text/enriched -->\n",
+			cancellable, NULL);
+	}
 
-	format_class = EM_FORMAT_CLASS (class);
-	format_class->format_error = efh_format_error;
-	format_class->format_source = efh_format_source;
-	format_class->format_attachment = efh_format_attachment;
-	format_class->format_secure = efh_format_secure;
+	if (mime_type)
+		g_free (mime_type);
 
-	class->html_widget_type = E_TYPE_WEB_VIEW;
+	enriched = camel_mime_filter_enriched_new (flags);
+	filtered_stream = camel_stream_filter_new (stream);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), enriched);
+	g_object_unref (enriched);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_BODY_COLOR,
-		g_param_spec_boxed (
-			"body-color",
-			"Body Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+	content = g_strdup_printf (
+		"<div style=\"border: solid #%06x 1px; "
+		"background-color: #%06x; padding: 10px; "
+		"color: #%06x;\">\n" EFH_MESSAGE_START,
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_FRAME]),
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_CONTENT]),
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_TEXT]));
 
-	g_object_class_install_property (
-		object_class,
-		PROP_CITATION_COLOR,
-		g_param_spec_boxed (
-			"citation-color",
-			"Citation Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+	camel_stream_write_string (stream, content, cancellable, NULL);
+	g_free (content);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_CONTENT_COLOR,
-		g_param_spec_boxed (
-			"content-color",
-			"Content Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+	em_format_format_text (
+		emf, (CamelStream *) filtered_stream,
+		(CamelDataWrapper *) puri->part, cancellable);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_FRAME_COLOR,
-		g_param_spec_boxed (
-			"frame-color",
-			"Frame Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+	g_object_unref (filtered_stream);
+	camel_stream_write_string (stream, "</div>", cancellable, NULL);
+}
 
-	g_object_class_install_property (
-		object_class,
-		PROP_HEADER_COLOR,
-		g_param_spec_boxed (
-			"header-color",
-			"Header Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+static void
+efh_write_text_plain (EMFormat *emf,
+		      EMFormatPURI *puri,
+		      CamelStream *stream,
+		      GCancellable *cancellable)
+{
+	CamelDataWrapper *dw;
+	CamelStream *filtered_stream;
+	CamelMimeFilter *html_filter;
+	EMFormatHTML *efh = (EMFormatHTML*) emf;
+	gchar *content;
+	const gchar *format;
+	guint32 flags;
+	guint32 rgb;
 
-	/* FIXME Make this a proper enum property. */
-	g_object_class_install_property (
-		object_class,
-		PROP_IMAGE_LOADING_POLICY,
-		g_param_spec_enum (
-			"image-loading-policy",
-			"Image Loading Policy",
-			NULL,
-			E_TYPE_MAIL_IMAGE_LOADING_POLICY,
-			E_MAIL_IMAGE_LOADING_POLICY_ALWAYS,
-			G_PARAM_READWRITE));
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	g_object_class_install_property (
-		object_class,
-		PROP_MARK_CITATIONS,
-		g_param_spec_boolean (
-			"mark-citations",
-			"Mark Citations",
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE));
+	flags = efh->text_html_flags;
 
-	g_object_class_install_property (
-		object_class,
-		PROP_ONLY_LOCAL_PHOTOS,
-		g_param_spec_boolean (
-			"only-local-photos",
-			"Only Local Photos",
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
+	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
 
-	g_object_class_install_property (
-		object_class,
-		PROP_SHOW_SENDER_PHOTO,
-		g_param_spec_boolean (
-			"show-sender-photo",
-			"Show Sender Photo",
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
+	/* Check for RFC 2646 flowed text. */
+	if (camel_content_type_is(dw->mime_type, "text", "plain")
+	    && (format = camel_content_type_param(dw->mime_type, "format"))
+	    && !g_ascii_strcasecmp(format, "flowed"))
+		flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
 
-	g_object_class_install_property (
-		object_class,
-		PROP_SHOW_REAL_DATE,
-		g_param_spec_boolean (
-			"show-real-date",
-			"Show real Date header value",
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
+	rgb = e_color_to_value (
+		&efh->priv->colors[EM_FORMAT_HTML_COLOR_CITATION]);
+	filtered_stream = camel_stream_filter_new (stream);
+	html_filter = camel_mime_filter_tohtml_new (flags, rgb);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), html_filter);
+	g_object_unref (html_filter);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_TEXT_COLOR,
-		g_param_spec_boxed (
-			"text-color",
-			"Text Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
+	content = g_strdup_printf (
+			EFH_HTML_HEADER	"<div id=\"pre\" style=\"background: #%06x; padding: 10px;\">\n",
+			e_color_to_value (
+				&efh->priv->colors[
+				EM_FORMAT_HTML_COLOR_BODY]),
+			e_color_to_value (
+				&efh->priv->colors[
+				EM_FORMAT_HTML_COLOR_HEADER]),
+			e_color_to_value (
+				&efh->priv->colors[
+				EM_FORMAT_HTML_COLOR_CONTENT]));
 
-	g_object_class_install_property (
-		object_class,
-		PROP_WEB_VIEW,
-		g_param_spec_object (
-			"web-view",
-			"Web View",
-			NULL,
-			E_TYPE_WEB_VIEW,
-			G_PARAM_READABLE));
+	camel_stream_write_string (
+			stream, content, cancellable, NULL);
+	g_free (content);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_HEADERS_STATE,
-		g_param_spec_int (
-			"headers-state",
-			"Headers state",
-			NULL,
-			EM_FORMAT_HTML_HEADERS_STATE_EXPANDED,
-			EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED,
-			EM_FORMAT_HTML_HEADERS_STATE_EXPANDED,
-			G_PARAM_READWRITE));
+	em_format_format_text (
+			emf, filtered_stream,
+			(CamelDataWrapper *) puri->part,
+			cancellable);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_HEADERS_COLLAPSABLE,
-		g_param_spec_boolean (
-			"headers-collapsable",
-			NULL,
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE));
+	g_object_unref (filtered_stream);
 
-	/* cache expiry - 2 hour access, 1 day max */
-	user_cache_dir = e_get_user_cache_dir ();
-	emfh_http_cache = camel_data_cache_new (user_cache_dir, NULL);
-	if (emfh_http_cache) {
-		camel_data_cache_set_expire_age (emfh_http_cache, 24 *60 *60);
-		camel_data_cache_set_expire_access (emfh_http_cache, 2 *60 *60);
-	}
+	camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
+	camel_stream_write_string (stream, EFH_HTML_FOOTER, cancellable, NULL);
 }
 
 static void
-efh_init (EMFormatHTML *efh,
-          EMFormatHTMLClass *class)
+efh_write_text_html (EMFormat *emf,
+		     EMFormatPURI *puri,
+		     CamelStream *stream,
+		     GCancellable *cancellable)
 {
-	EWebView *web_view;
-	GdkColor *color;
-
-	efh->priv = EM_FORMAT_HTML_GET_PRIVATE (efh);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	efh->priv->text_inline_parts = g_hash_table_new_full (
-		g_str_hash, g_str_equal,
-		(GDestroyNotify) NULL,
-		(GDestroyNotify) efh_free_cache);
+	em_format_format_text (
+		emf, stream, (CamelDataWrapper *) puri->part, cancellable);
+}
 
-	web_view = g_object_new (class->html_widget_type, NULL);
-	efh->priv->web_view = g_object_ref_sink (web_view);
+static void
+efh_write_source (EMFormat *emf,
+		  EMFormatPURI *puri,
+		  CamelStream *stream,
+		  GCancellable *cancellable)
+{
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) puri->part;
 
-	g_queue_init (&efh->pending_object_list);
+	filtered_stream = camel_stream_filter_new (stream);
 
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
-	gdk_color_parse ("#eeeeee", color);
+	filter = camel_mime_filter_tohtml_new (
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+		CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), filter);
+	g_object_unref (filter);
 
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT];
-	gdk_color_parse ("#ffffff", color);
+	camel_stream_write_string (
+		stream, "<code class=\"pre\">", cancellable, NULL);
+	em_format_format_text (emf, filtered_stream, dw, cancellable);
+	camel_stream_write_string (
+		stream, "</code>", cancellable, NULL);
 
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME];
-	gdk_color_parse ("#3f3f3f", color);
+	g_object_unref (filtered_stream);
+}
 
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER];
-	gdk_color_parse ("#eeeeee", color);
+/*****************************************************************************/
 
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT];
-	gdk_color_parse ("#000000", color);
+/* Notes:
+ *
+ * image/tiff is omitted because it's a multi-page image format, but
+ * gdk-pixbuf unconditionally renders the first page only, and doesn't
+ * even indicate through meta-data whether multiple pages are present
+ * (see bug 335959).  Therefore, make no attempt to render TIFF images
+ * inline and defer to an application that can handle multi-page TIFF
+ * files properly like Evince or Gimp.  Once the referenced bug is
+ * fixed we can reevaluate this policy.
+ */
+static EMFormatHandler type_builtin_table[] = {
+	{ (gchar *) "image/gif", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/jpeg", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/png", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-png", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-bmp", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/bmp", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/svg", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-cmu-raster", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-ico", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-portable-anymap", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-portable-bitmap", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-portable-graymap", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-portable-pixmap", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/x-xpixmap", efh_parse_image, efh_write_image, },
+	{ (gchar *) "text/enriched", efh_parse_text_enriched, efh_write_text_enriched, },
+	{ (gchar *) "text/plain", efh_parse_text_plain, efh_write_text_plain, },
+	{ (gchar *) "text/html", efh_parse_text_html, efh_write_text_html, },
+	{ (gchar *) "text/richtext", efh_parse_text_enriched, efh_write_text_enriched, },
+	{ (gchar *) "text/*", efh_parse_text_plain, efh_write_text_plain, },
+	{ (gchar *) "message/external-body", efh_parse_message_external, 0 },
 
-	efh->text_html_flags =
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
-		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
-		CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
-	efh->show_icon = TRUE;
-	efh->state = EM_FORMAT_HTML_STATE_NONE;
+	/* This is where one adds those busted, non-registered types,
+	   that some idiot mailer writers out there decide to pull out
+	   of their proverbials at random. */
 
-	g_signal_connect_swapped (
-		efh, "notify::mark-citations",
-		G_CALLBACK (e_web_view_reload), web_view);
+	{ (gchar *) "image/jpg", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/pjpeg", efh_parse_image, efh_write_image, },
 
-	e_extensible_load_extensions (E_EXTENSIBLE (efh));
-}
+	/* special internal types */
+	{ (gchar *) "x-evolution/message/rfc822", 0, efh_write_text_plain }
+};
 
-GType
-em_format_html_get_type (void)
+static void
+efh_builtin_init (EMFormatHTMLClass *efhc)
 {
-	static GType type = 0;
+	EMFormatClass *emfc;
+	gint ii;
 
-	if (G_UNLIKELY (type == 0)) {
-		static const GTypeInfo type_info = {
-			sizeof (EMFormatHTMLClass),
-			(GBaseInitFunc) efh_base_init,
-			(GBaseFinalizeFunc) NULL,
-			(GClassInitFunc) efh_class_init,
-			(GClassFinalizeFunc) NULL,
-			NULL,  /* class_data */
-			sizeof (EMFormatHTML),
-			0,     /* n_preallocs */
-			(GInstanceInitFunc) efh_init,
-			NULL   /* value_table */
-		};
-
-		static const GInterfaceInfo extensible_info = {
-			(GInterfaceInitFunc) NULL,
-			(GInterfaceFinalizeFunc) NULL,
-			NULL   /* interface_data */
-		};
-
-		type = g_type_register_static (
-			em_format_get_type(), "EMFormatHTML",
-			&type_info, G_TYPE_FLAG_ABSTRACT);
-
-		g_type_add_interface_static (
-			type, E_TYPE_EXTENSIBLE, &extensible_info);
-	}
-
-	return type;
-}
-
-EWebView *
-em_format_html_get_web_view (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
+	emfc = (EMFormatClass *) efhc;
 
-	return efh->priv->web_view;
+	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
+		em_format_class_add_handler (
+			emfc, &type_builtin_table[ii]);
 }
 
-void
-em_format_html_load_images (EMFormatHTML *efh)
+static void
+efh_set_property (GObject *object,
+                  guint property_id,
+                  const GValue *value,
+                  GParamSpec *pspec)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-
-	if (efh->priv->image_loading_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS)
-		return;
-
-	/* This will remain set while we're still
-	 * rendering the same message, then it wont be. */
-	efh->priv->load_images_now = TRUE;
-	e_web_view_reload (efh->priv->web_view);
-}
+	switch (property_id) {
+		case PROP_BODY_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_BODY,
+				g_value_get_boxed (value));
+			return;
 
-void
-em_format_html_get_color (EMFormatHTML *efh,
-                          EMFormatHTMLColorType type,
-                          GdkColor *color)
-{
-	GdkColor *format_color;
+		case PROP_CITATION_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CITATION,
+				g_value_get_boxed (value));
+			return;
 
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
-	g_return_if_fail (color != NULL);
+		case PROP_CONTENT_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CONTENT,
+				g_value_get_boxed (value));
+			return;
 
-	format_color = &efh->priv->colors[type];
+		case PROP_FRAME_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_FRAME,
+				g_value_get_boxed (value));
+			return;
 
-	color->red   = format_color->red;
-	color->green = format_color->green;
-	color->blue  = format_color->blue;
-}
+		case PROP_HEADER_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_HEADER,
+				g_value_get_boxed (value));
+			return;
 
-void
-em_format_html_set_color (EMFormatHTML *efh,
-                          EMFormatHTMLColorType type,
-                          const GdkColor *color)
-{
-	GdkColor *format_color;
-	const gchar *property_name;
+		case PROP_IMAGE_LOADING_POLICY:
+			em_format_html_set_image_loading_policy (
+				EM_FORMAT_HTML (object),
+				g_value_get_enum (value));
+			return;
 
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
-	g_return_if_fail (color != NULL);
+		case PROP_MARK_CITATIONS:
+			em_format_html_set_mark_citations (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	format_color = &efh->priv->colors[type];
+		case PROP_ONLY_LOCAL_PHOTOS:
+			em_format_html_set_only_local_photos (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	if (gdk_color_equal (color, format_color))
-		return;
+		case PROP_SHOW_SENDER_PHOTO:
+			em_format_html_set_show_sender_photo (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	format_color->red   = color->red;
-	format_color->green = color->green;
-	format_color->blue  = color->blue;
+		case PROP_SHOW_REAL_DATE:
+			em_format_html_set_show_real_date (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	switch (type) {
-		case EM_FORMAT_HTML_COLOR_BODY:
-			property_name = "body-color";
-			break;
-		case EM_FORMAT_HTML_COLOR_CITATION:
-			property_name = "citation-color";
-			break;
-		case EM_FORMAT_HTML_COLOR_CONTENT:
-			property_name = "content-color";
-			break;
-		case EM_FORMAT_HTML_COLOR_FRAME:
-			property_name = "frame-color";
-			break;
-		case EM_FORMAT_HTML_COLOR_HEADER:
-			property_name = "header-color";
-			break;
-		case EM_FORMAT_HTML_COLOR_TEXT:
-			property_name = "text-color";
-			break;
-		default:
-			g_return_if_reached ();
+		case PROP_TEXT_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_TEXT,
+				g_value_get_boxed (value));
+			return;
+		case PROP_HEADERS_STATE:
+			em_format_html_set_headers_state (
+				EM_FORMAT_HTML (object),
+				g_value_get_int (value));
+			return;
+		case PROP_HEADERS_COLLAPSABLE:
+			em_format_html_set_headers_collapsable (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
 	}
 
-	g_object_notify (G_OBJECT (efh), property_name);
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-EMailImageLoadingPolicy
-em_format_html_get_image_loading_policy (EMFormatHTML *efh)
+static void
+efh_get_property (GObject *object,
+                  guint property_id,
+                  GValue *value,
+                  GParamSpec *pspec)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
+	GdkColor color;
 
-	return efh->priv->image_loading_policy;
-}
+	switch (property_id) {
+		case PROP_BODY_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_BODY,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-void
-em_format_html_set_image_loading_policy (EMFormatHTML *efh,
-                                         EMailImageLoadingPolicy policy)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+		case PROP_CITATION_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CITATION,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-	if (policy == efh->priv->image_loading_policy)
-		return;
+		case PROP_CONTENT_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CONTENT,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-	efh->priv->image_loading_policy = policy;
+		case PROP_FRAME_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_FRAME,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-	g_object_notify (G_OBJECT (efh), "image-loading-policy");
-}
+		case PROP_HEADER_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_HEADER,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-gboolean
-em_format_html_get_mark_citations (EMFormatHTML *efh)
-{
-	guint32 flags;
+		case PROP_IMAGE_LOADING_POLICY:
+			g_value_set_enum (
+				value,
+				em_format_html_get_image_loading_policy (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+		case PROP_MARK_CITATIONS:
+			g_value_set_boolean (
+				value, em_format_html_get_mark_citations (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	flags = efh->text_html_flags;
+		case PROP_ONLY_LOCAL_PHOTOS:
+			g_value_set_boolean (
+				value, em_format_html_get_only_local_photos (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
-}
+		case PROP_SHOW_SENDER_PHOTO:
+			g_value_set_boolean (
+				value, em_format_html_get_show_sender_photo (
+				EM_FORMAT_HTML (object)));
+			return;
 
-void
-em_format_html_set_mark_citations (EMFormatHTML *efh,
-                                   gboolean mark_citations)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-
-	if (mark_citations)
-		efh->text_html_flags |=
-			CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
-		efh->text_html_flags &=
-			~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
-
-	g_object_notify (G_OBJECT (efh), "mark-citations");
-}
-
-gboolean
-em_format_html_get_only_local_photos (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
-
-	return efh->priv->only_local_photos;
-}
+		case PROP_SHOW_REAL_DATE:
+			g_value_set_boolean (
+				value, em_format_html_get_show_real_date (
+				EM_FORMAT_HTML (object)));
+			return;
 
-void
-em_format_html_set_only_local_photos (EMFormatHTML *efh,
-                                      gboolean only_local_photos)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+		case PROP_TEXT_COLOR:
+			em_format_html_get_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_TEXT,
+				&color);
+			g_value_set_boxed (value, &color);
+			return;
 
-	efh->priv->only_local_photos = only_local_photos;
+		case PROP_HEADERS_STATE:
+			g_value_set_int (
+				value, em_format_html_get_headers_state (
+				EM_FORMAT_HTML (object)));
+			return;
+		case PROP_HEADERS_COLLAPSABLE:
+			g_value_set_boolean (
+				value, em_format_html_get_headers_collapsable (
+				EM_FORMAT_HTML (object)));
+	}
 
-	g_object_notify (G_OBJECT (efh), "only-local-photos");
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-gboolean
-em_format_html_get_show_sender_photo (EMFormatHTML *efh)
+static void
+efh_finalize (GObject *object)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	EMFormatHTML *efh = EM_FORMAT_HTML (object);
+	EMFormatHTMLPrivate *priv = efh->priv;
 
-	return efh->priv->show_sender_photo;
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-void
-em_format_html_set_show_sender_photo (EMFormatHTML *efh,
-                                      gboolean show_sender_photo)
+static void
+efh_format_error (EMFormat *emf,
+                  const gchar *message)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	EMFormatPURI *puri;
+	CamelMimePart *part;
+	GString *buffer;
+	gchar *html;
 
-	efh->priv->show_sender_photo = show_sender_photo;
+	buffer = g_string_new ("<em><font color=\"red\">");
 
-	g_object_notify (G_OBJECT (efh), "show-sender-photo");
-}
+	html = camel_text_to_html (
+		message, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	g_string_append (buffer, html);
+	g_free (html);
 
-gboolean
-em_format_html_get_show_real_date (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	g_string_append (buffer, "</font></em><br>");
 
-	return efh->priv->show_real_date;
-}
+	part = camel_mime_part_new ();
+	camel_mime_part_set_content (part, buffer->str, buffer->len, "text/html");
 
-void
-em_format_html_set_show_real_date (EMFormatHTML *efh,
-                                   gboolean show_real_date)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, ".error");
+	puri->write_func = efh_write_text_html;
 
-	efh->priv->show_real_date = show_real_date;
+	em_format_add_puri (emf, puri);
 
-	g_object_notify (G_OBJECT (efh), "show-real-date");
+	g_string_free (buffer, TRUE);
 }
 
-EMFormatHTMLHeadersState
-em_format_html_get_headers_state (EMFormatHTML *efh)
+static void
+efh_format_source (EMFormat *emf,
+		   CamelStream *stream,
+		   CamelMimePart *part,
+		   GCancellable *cancellable)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) part;
 
-	return efh->priv->headers_state;
-}
+	filtered_stream = camel_stream_filter_new (stream);
 
-void
-em_format_html_set_headers_state (EMFormatHTML *efh,
-                                  EMFormatHTMLHeadersState state)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	filter = camel_mime_filter_tohtml_new (
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+		CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0);
+	camel_stream_filter_add (
+		CAMEL_STREAM_FILTER (filtered_stream), filter);
+	g_object_unref (filter);
 
-	efh->priv->headers_state = state;
+	camel_stream_write_string (
+		stream, "<code class=\"pre\">", cancellable, NULL);
+	em_format_format_text (emf, filtered_stream, dw, cancellable);
+	camel_stream_write_string (
+		stream, "</code>", cancellable, NULL);
 
-	g_object_notify (G_OBJECT (efh), "headers-state");
+	g_object_unref (filtered_stream);
 }
 
-gboolean
-em_format_html_get_headers_collapsable (EMFormatHTML *efh)
+/* FIXME WEBKIT: This should only create EMFormatPURI that will be then
+ * processed to EAttachment (or whatever) widget!
+ */
+static void
+efh_format_attachment (EMFormat *emf,
+                       CamelStream *stream,
+                       CamelMimePart *part,
+                       const gchar *mime_type,
+                       const EMFormatHandler *handle,
+                       GCancellable *cancellable)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	gchar *text, *html;
 
-	return efh->priv->headers_collapsable;
-}
+	/* we display all inlined attachments only */
 
-void
-em_format_html_set_headers_collapsable (EMFormatHTML *efh,
-                                        gboolean collapsable)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	/* this could probably be cleaned up ... */
+	camel_stream_write_string (
+		stream,
+		"<table border=1 cellspacing=0 cellpadding=0><tr><td>"
+		"<table width=10 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td>"
+		"<td><table width=3 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td><td><font size=-1>\n",
+		cancellable, NULL);
 
-	efh->priv->headers_collapsable = collapsable;
+	/* output some info about it */
+	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);
+	camel_stream_write_string (stream, html, cancellable, NULL);
+	g_free (html);
+	g_free (text);
 
-	g_object_notify (G_OBJECT (efh), "headers-collapsable");
+	camel_stream_write_string (
+		stream, "</font></td></tr><tr></table>", cancellable, NULL);
+/*
+	if (handle && em_format_is_inline (emf, part_id->str, part, handle))
+			handle->write_func (emf, part, stream, cancellable);
+*/
 }
 
-CamelMimePart *
-em_format_html_file_part (EMFormatHTML *efh,
-                          const gchar *mime_type,
-                          const gchar *filename,
-                          GCancellable *cancellable)
+static void
+efh_base_init (EMFormatHTMLClass *class)
 {
-	CamelMimePart *part;
-	CamelStream *stream;
-	CamelDataWrapper *dw;
-	gchar *basename;
-
-	stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
-	if (stream == NULL)
-		return NULL;
-
-	dw = camel_data_wrapper_new ();
-	camel_data_wrapper_construct_from_stream_sync (
-		dw, stream, cancellable, NULL);
-	g_object_unref (stream);
-	if (mime_type)
-		camel_data_wrapper_set_mime_type (dw, mime_type);
-	part = camel_mime_part_new ();
-	camel_medium_set_content ((CamelMedium *) part, dw);
-	g_object_unref (dw);
-	basename = g_path_get_basename (filename);
-	camel_mime_part_set_filename (part, basename);
-	g_free (basename);
-
-	return part;
+	efh_builtin_init (class);
 }
 
-/* all this api is a pain in the bum ... */
-
-EMFormatHTMLPObject *
-em_format_html_add_pobject (EMFormatHTML *efh,
-                            gsize size,
-                            const gchar *classid,
-                            CamelMimePart *part,
-                            EMFormatHTMLPObjectFunc func)
+static void
+efh_class_init (EMFormatHTMLClass *class)
 {
-	EMFormatHTMLPObject *pobj;
-
-	if (size < sizeof (EMFormatHTMLPObject)) {
-		g_warning ("size is less than the size of EMFormatHTMLPObject\n");
-		size = sizeof (EMFormatHTMLPObject);
-	}
+	GObjectClass *object_class;
+	EMFormatClass *format_class;
+	const gchar *user_cache_dir;
 
-	pobj = g_malloc0 (size);
-	if (classid)
-		pobj->classid = g_strdup (classid);
-	else
-		pobj->classid = g_strdup_printf("e-object:///%s", ((EMFormat *)efh)->part_id->str);
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMFormatHTMLPrivate));
 
-	pobj->format = efh;
-	pobj->func = func;
-	pobj->part = part;
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = efh_set_property;
+	object_class->get_property = efh_get_property;
+	object_class->finalize = efh_finalize;
 
-	g_queue_push_tail (&efh->pending_object_list, pobj);
+	format_class = EM_FORMAT_CLASS (class);
+	format_class->format_error = efh_format_error;
+	/*format_class->format_source = efh_format_source;
+	format_class->format_attachment = efh_format_attachment;
+	format_class->format_secure = efh_format_secure;
+	*/
+	g_object_class_install_property (
+		object_class,
+		PROP_BODY_COLOR,
+		g_param_spec_boxed (
+			"body-color",
+			"Body Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-	return pobj;
-}
+	g_object_class_install_property (
+		object_class,
+		PROP_CITATION_COLOR,
+		g_param_spec_boxed (
+			"citation-color",
+			"Citation Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-EMFormatHTMLPObject *
-em_format_html_find_pobject (EMFormatHTML *efh,
-                             const gchar *classid)
-{
-	GList *link;
+	g_object_class_install_property (
+		object_class,
+		PROP_CONTENT_COLOR,
+		g_param_spec_boxed (
+			"content-color",
+			"Content Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
-	g_return_val_if_fail (classid != NULL, NULL);
+	g_object_class_install_property (
+		object_class,
+		PROP_FRAME_COLOR,
+		g_param_spec_boxed (
+			"frame-color",
+			"Frame Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-	link = g_queue_peek_head_link (&efh->pending_object_list);
-
-	while (link != NULL) {
-		EMFormatHTMLPObject *pw = link->data;
-
-		if (!strcmp (pw->classid, classid))
-			return pw;
-
-		link = g_list_next (link);
-	}
-
-	return NULL;
-}
-
-EMFormatHTMLPObject *
-em_format_html_find_pobject_func (EMFormatHTML *efh,
-                                  CamelMimePart *part,
-                                  EMFormatHTMLPObjectFunc func)
-{
-	GList *link;
-
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
-
-	link = g_queue_peek_head_link (&efh->pending_object_list);
-
-	while (link != NULL) {
-		EMFormatHTMLPObject *pw = link->data;
-
-		if (pw->func == func && pw->part == part)
-			return pw;
-
-		link = g_list_next (link);
-	}
-
-	return NULL;
-}
-
-void
-em_format_html_remove_pobject (EMFormatHTML *efh,
-                               EMFormatHTMLPObject *pobject)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-	g_return_if_fail (pobject != NULL);
-
-	g_queue_remove (&efh->pending_object_list, pobject);
-
-	if (pobject->free != NULL)
-		pobject->free (pobject);
-
-	g_free (pobject->classid);
-	g_free (pobject);
-}
-
-void
-em_format_html_clear_pobject (EMFormatHTML *efh)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
-
-	while (!g_queue_is_empty (&efh->pending_object_list)) {
-		EMFormatHTMLPObject *pobj;
-
-		pobj = g_queue_pop_head (&efh->pending_object_list);
-		em_format_html_remove_pobject (efh, pobj);
-	}
-}
-
-void
-em_format_html_format_message (EMFormatHTML *efh,
-							   CamelStream *stream,
-							   GCancellable *cancellable)
-{
-	EMFormat *emf;
-
-	d(printf(" running format_email task\n"));
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return;
-
-
-	emf = EM_FORMAT (efh);
-	em_format_html_clear_pobject(efh);
-	g_hash_table_remove_all (efh->priv->text_inline_parts);
-
-	if (emf->mode == EM_FORMAT_MODE_SOURCE) {
-		em_format_format_source (
-			emf, stream,
-			CAMEL_MIME_PART (emf->message), cancellable);
-	} else {
-		const EMFormatHandler *handle;
-		const gchar *mime_type;
-
-		mime_type = "x-evolution/message/prefix";
-		handle = em_format_find_handler (emf, mime_type);
-
-		if (handle != NULL)
-			handle->handler (
-				emf, stream,
-				CAMEL_MIME_PART (emf->message), handle,
-				cancellable, FALSE);
-
-		mime_type = "x-evolution/message/rfc822";
-		handle = em_format_find_handler (emf, mime_type);
-
-		if (handle != NULL)
-			handle->handler (
-				emf, stream,
-				CAMEL_MIME_PART (emf->message), handle,
-				cancellable, FALSE);
-	}
-}
-
-void
-em_format_html_format_message_part (EMFormatHTML *efh,
-									const gchar *part_id,
-									CamelStream *stream,
-									GCancellable *cancellable)
-{
-	EMFormatPURI *puri;
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return;
-
-	em_format_push_level (EM_FORMAT (efh));
-
-	puri = em_format_find_puri (EM_FORMAT (efh), part_id);
-	if (!puri) {
-		d(printf("Can't find PURI %s", part_id));
-		return;
-	}
-	puri->func (EM_FORMAT (efh), stream, puri, cancellable);
-}
-
-
-/* ********************************************************************** */
-#include "em-format/em-inline-filter.h"
-
-/* FIXME: This is duplicated in em-format-html-display, should be exported or in security module */
-static const struct {
-	const gchar *icon, *shortdesc;
-} smime_sign_table[5] = {
-	{ "stock_signature-bad", N_("Unsigned") },
-	{ "stock_signature-ok", N_("Valid signature") },
-	{ "stock_signature-bad", N_("Invalid signature") },
-	{ "stock_signature", N_("Valid signature, but cannot verify sender") },
-	{ "stock_signature-bad", N_("Signature exists, but need public key") },
-};
-
-static const struct {
-	const gchar *icon, *shortdesc;
-} smime_encrypt_table[4] = {
-	{ "stock_lock-broken", N_("Unencrypted") },
-	{ "stock_lock", N_("Encrypted, weak"),},
-	{ "stock_lock-ok", N_("Encrypted") },
-	{ "stock_lock-ok", N_("Encrypted, strong") },
-};
-
-static const gchar *smime_sign_colour[4] = {
-	"", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\""
-};
-
-/* TODO: this could probably be virtual on em-format-html
- * then we only need one version of each type handler */
-static void
-efh_format_secure (EMFormat *emf,
-                   CamelStream *stream,
-                   CamelMimePart *part,
-                   CamelCipherValidity *valid,
-                   GCancellable *cancellable)
-{
-	EMFormatClass *format_class;
-
-	format_class = EM_FORMAT_CLASS (parent_class);
-	g_return_if_fail (format_class->format_secure != NULL);
-	format_class->format_secure (emf, stream, part, valid, cancellable);
-
-	/* To explain, if the validity is the same, then we are the
-	 * base validity and now have a combined sign/encrypt validity
-	 * we can display.  Primarily a new verification context is
-	 * created when we have an embeded message. */
-	if (emf->valid == valid
-	    && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
-		|| valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
-		gchar *classid, *iconpath;
-		const gchar *icon;
-		CamelMimePart *iconpart;
-		GString *buffer;
-
-		buffer = g_string_sized_new (1024);
+	g_object_class_install_property (
+		object_class,
+		PROP_HEADER_COLOR,
+		g_param_spec_boxed (
+			"header-color",
+			"Header Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-		g_string_append_printf (
-			buffer,
-			"<table border=0 width=\"100%%\" "
-			"cellpadding=3 cellspacing=0%s><tr>",
-			smime_sign_colour[valid->sign.status]);
+	/* FIXME Make this a proper enum property. */
+	g_object_class_install_property (
+		object_class,
+		PROP_IMAGE_LOADING_POLICY,
+		g_param_spec_enum (
+			"image-loading-policy",
+			"Image Loading Policy",
+			NULL,
+			E_TYPE_MAIL_IMAGE_LOADING_POLICY,
+			E_MAIL_IMAGE_LOADING_POLICY_ALWAYS,
+			G_PARAM_READWRITE));
 
-		classid = g_strdup_printf (
-			"smime:///em-format-html/%s/icon/signed",
-			emf->part_id->str);
-		g_string_append_printf (
-			buffer,
-			"<td valign=\"top\"><img src=\"%s\"></td>"
-			"<td valign=\"top\" width=\"100%%\">", classid);
+	g_object_class_install_property (
+		object_class,
+		PROP_MARK_CITATIONS,
+		g_param_spec_boolean (
+			"mark-citations",
+			"Mark Citations",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE));
 
-		if (valid->sign.status != 0)
-			icon = smime_sign_table[valid->sign.status].icon;
-		else
-			icon = smime_encrypt_table[valid->encrypt.status].icon;
-		iconpath = e_icon_factory_get_icon_filename (icon, GTK_ICON_SIZE_DIALOG);
-		iconpart = em_format_html_file_part((EMFormatHTML *)emf, "image/png", iconpath, cancellable);
-		if (iconpart) {
-			(void) em_format_add_puri (emf, sizeof (EMFormatPURI), classid, iconpart, efh_write_image);
-			g_object_unref (iconpart);
-		}
-		g_free (iconpath);
-		g_free (classid);
+	g_object_class_install_property (
+		object_class,
+		PROP_ONLY_LOCAL_PHOTOS,
+		g_param_spec_boolean (
+			"only-local-photos",
+			"Only Local Photos",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
 
-		if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
-			g_string_append (
-				buffer, _(smime_sign_table[valid->sign.status].shortdesc));
+	g_object_class_install_property (
+		object_class,
+		PROP_SHOW_SENDER_PHOTO,
+		g_param_spec_boolean (
+			"show-sender-photo",
+			"Show Sender Photo",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
 
-			em_format_html_format_cert_infos (
-				&valid->sign.signers, buffer);
-		}
+	g_object_class_install_property (
+		object_class,
+		PROP_SHOW_REAL_DATE,
+		g_param_spec_boolean (
+			"show-real-date",
+			"Show real Date header value",
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
 
-		if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
-			if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
-				g_string_append (buffer, "<br>");
+	g_object_class_install_property (
+		object_class,
+		PROP_TEXT_COLOR,
+		g_param_spec_boxed (
+			"text-color",
+			"Text Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
 
-			g_string_append (
-				buffer, _(smime_encrypt_table[valid->encrypt.status].shortdesc));
-		}
+	g_object_class_install_property (
+		object_class,
+		PROP_HEADERS_STATE,
+		g_param_spec_int (
+			"headers-state",
+			"Headers state",
+			NULL,
+			EM_FORMAT_HTML_HEADERS_STATE_EXPANDED,
+			EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED,
+			EM_FORMAT_HTML_HEADERS_STATE_EXPANDED,
+			G_PARAM_READWRITE));
 
-		g_string_append (buffer, "</td></tr></table>");
+	g_object_class_install_property (
+		object_class,
+		PROP_HEADERS_COLLAPSABLE,
+		g_param_spec_boolean (
+			"headers-collapsable",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
 
-		camel_stream_write (
-			stream, buffer->str,
-			buffer->len, cancellable, NULL);
+	/* cache expiry - 2 hour access, 1 day max */
 
-		g_string_free (buffer, TRUE);
+	/* FIXME WEBKIT - this emfh_http_cache is not used anywhere - remove?
+	user_cache_dir = e_get_user_cache_dir ();
+	emfh_http_cache = camel_data_cache_new (user_cache_dir, NULL);
+	if (emfh_http_cache) {
+		camel_data_cache_set_expire_age (emfh_http_cache, 24*60*60);
+		camel_data_cache_set_expire_access (emfh_http_cache, 2*60*60);
 	}
+	*/
 }
 
 static void
-efh_text_plain (EMFormat *emf,
-                CamelStream *stream,
-                CamelMimePart *part,
-                const EMFormatHandler *info,
-                GCancellable *cancellable,
-                gboolean is_fallback)
+efh_init (EMFormatHTML *efh,
+	  EMFormatHTMLClass *class)
 {
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	CamelStream *filtered_stream;
-	CamelMimeFilter *html_filter;
-	CamelMultipart *mp;
-	CamelDataWrapper *dw;
-	CamelContentType *type;
-	const gchar *format;
-	guint32 flags;
-	guint32 rgb;
-	gint i, count, len;
-	struct _EMFormatHTMLCache *efhc;
-
-	flags = efh->text_html_flags;
-
-	dw = camel_medium_get_content ((CamelMedium *) part);
-	if (!dw)
-		return;
-
-	/* Check for RFC 2646 flowed text. */
-	if (camel_content_type_is(dw->mime_type, "text", "plain")
-	    && (format = camel_content_type_param(dw->mime_type, "format"))
-	    && !g_ascii_strcasecmp(format, "flowed"))
-		flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
-
-	/* This scans the text part for inline-encoded data, creates
-	 * a multipart of all the parts inside it. */
-
-	/* FIXME: We should discard this multipart if it only contains
-	 * the original text, but it makes this hash lookup more complex */
-
-	/* TODO: We could probably put this in the superclass, since
-	 * no knowledge of html is required - but this messes with
-	 * filters a bit.  Perhaps the superclass should just deal with
-	 * html anyway and be done with it ... */
-
-	efhc = g_hash_table_lookup (
-		efh->priv->text_inline_parts,
-		emf->part_id->str);
-
-	if (efhc == NULL || (mp = efhc->textmp) == NULL) {
-		EMInlineFilter *inline_filter;
-		CamelStream *null;
-		CamelContentType *ct;
-		gboolean charset_added = FALSE;
-
-		/* if we had to snoop the part type to get here, then
-		 * use that as the base type, yuck */
-		if (emf->snoop_mime_type == NULL
-		    || (ct = camel_content_type_decode (emf->snoop_mime_type)) == NULL) {
-			ct = dw->mime_type;
-			camel_content_type_ref (ct);
-		}
-
-		if (dw->mime_type && ct != dw->mime_type && camel_content_type_param (dw->mime_type, "charset")) {
-			camel_content_type_set_param (ct, "charset", camel_content_type_param (dw->mime_type, "charset"));
-			charset_added = TRUE;
-		}
-
-		null = camel_stream_null_new ();
-		filtered_stream = camel_stream_filter_new (null);
-		g_object_unref (null);
-		inline_filter = em_inline_filter_new (camel_mime_part_get_encoding (part), ct);
-		camel_stream_filter_add (
-			CAMEL_STREAM_FILTER (filtered_stream),
-			CAMEL_MIME_FILTER (inline_filter));
-		camel_data_wrapper_decode_to_stream_sync (
-			dw, (CamelStream *) filtered_stream, cancellable, NULL);
-		camel_stream_close ((CamelStream *) filtered_stream, cancellable, NULL);
-		g_object_unref (filtered_stream);
-
-		mp = em_inline_filter_get_multipart (inline_filter);
-		if (efhc == NULL)
-			efhc = efh_insert_cache (efh, emf->part_id->str);
-		efhc->textmp = mp;
-
-		if (charset_added) {
-			camel_content_type_set_param (ct, "charset", NULL);
-		}
-
-		g_object_unref (inline_filter);
-		camel_content_type_unref (ct);
-	}
-
-	rgb = e_color_to_value (
-		&efh->priv->colors[EM_FORMAT_HTML_COLOR_CITATION]);
-	filtered_stream = camel_stream_filter_new (stream);
-	html_filter = camel_mime_filter_tohtml_new (flags, rgb);
-	camel_stream_filter_add (
-		CAMEL_STREAM_FILTER (filtered_stream), html_filter);
-	g_object_unref (html_filter);
-
-	/* We handle our made-up multipart here, so we don't recursively call ourselves */
-
-	len = emf->part_id->len;
-	count = camel_multipart_get_number (mp);
-	for (i = 0; i < count; i++) {
-		CamelMimePart *newpart = camel_multipart_get_part (mp, i);
-
-		if (!newpart)
-			continue;
+	GdkColor *color;
 
-		type = camel_mime_part_get_content_type (newpart);
-		if (camel_content_type_is (type, "text", "*") && (is_fallback || !camel_content_type_is (type, "text", "calendar"))) {
-			gchar *content;
-
-			content = g_strdup_printf (
-				"<div style=\"border: solid #%06x 1px; "
-				"background-color: #%06x; padding: 10px; "
-				"color: #%06x;\">\n<div id=\"pre\">\n" EFH_MESSAGE_START,
-				e_color_to_value (
-					&efh->priv->colors[
-					EM_FORMAT_HTML_COLOR_FRAME]),
-				e_color_to_value (
-					&efh->priv->colors[
-					EM_FORMAT_HTML_COLOR_CONTENT]),
-				e_color_to_value (
-					&efh->priv->colors[
-					EM_FORMAT_HTML_COLOR_TEXT]));
-			camel_stream_write_string (
-				stream, content, cancellable, NULL);
-			g_free (content);
-
-			em_format_format_text (
-				emf, filtered_stream,
-				(CamelDataWrapper *) newpart,
-				cancellable);
-			camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL);
-			camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
-			camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
-		} else {
-			g_string_append_printf (emf->part_id, ".inline.%d", i);
-			em_format_part (
-				emf, stream, newpart, cancellable);
-			g_string_truncate (emf->part_id, len);
-		}
-	}
+	efh->priv = EM_FORMAT_HTML_GET_PRIVATE (efh);
 
-	g_object_unref (filtered_stream);
-}
+	/* FIXME WEBKIT
+	efh->priv->text_inline_parts = g_hash_table_new_full (
+		g_str_hash, g_str_equal,
+		(GDestroyNotify) NULL,
+		(GDestroyNotify) efh_free_cache);
+	*/
 
-static void
-efh_text_enriched (EMFormat *emf,
-                   CamelStream *stream,
-                   CamelMimePart *part,
-                   const EMFormatHandler *info,
-                   GCancellable *cancellable,
-                   gboolean is_fallback)
-{
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	CamelStream *filtered_stream;
-	CamelMimeFilter *enriched;
-	guint32 flags = 0;
-	gchar *content;
+	g_queue_init (&efh->pending_object_list);
 
-	if (!strcmp(info->mime_type, "text/richtext")) {
-		flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
-		camel_stream_write_string (
-			stream, "\n<!-- text/richtext -->\n",
-			cancellable, NULL);
-	} else {
-		camel_stream_write_string (
-			stream, "\n<!-- text/enriched -->\n",
-			cancellable, NULL);
-	}
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
+	gdk_color_parse ("#eeeeee", color);
 
-	enriched = camel_mime_filter_enriched_new (flags);
-	filtered_stream = camel_stream_filter_new (stream);
-	camel_stream_filter_add (
-		CAMEL_STREAM_FILTER (filtered_stream), enriched);
-	g_object_unref (enriched);
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT];
+	gdk_color_parse ("#ffffff", color);
 
-	content = g_strdup_printf (
-		"<div style=\"border: solid #%06x 1px; "
-		"background-color: #%06x; padding: 10px; "
-		"color: #%06x;\">\n" EFH_MESSAGE_START,
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_FRAME]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_CONTENT]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_TEXT]));
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME];
+	gdk_color_parse ("#3f3f3f", color);
 
-	em_format_format_text (
-		emf, (CamelStream *) filtered_stream,
-		(CamelDataWrapper *) part, cancellable);
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER];
+	gdk_color_parse ("#eeeeee", color);
 
-	g_object_unref (filtered_stream);
-	camel_stream_write_string (stream, "</div>", cancellable, NULL);
-}
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT];
+	gdk_color_parse ("#000000", color);
 
-static void
-efh_write_text_html (EMFormat *emf,
-                     CamelStream *stream,
-                     EMFormatPURI *puri,
-                     GCancellable *cancellable)
-{
-#if d(!)0
-	CamelStream *out;
-	gint fd;
-	CamelDataWrapper *dw;
+	efh->text_html_flags =
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+		CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+	efh->show_icon = TRUE;
+	efh->state = EM_FORMAT_HTML_STATE_NONE;
 
-	fd = dup (STDOUT_FILENO);
-	out = camel_stream_fs_new_with_fd (fd);
-	printf("writing text content to frame '%s'\n", puri->cid);
-	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
-	if (dw)
-		camel_data_wrapper_write_to_stream_sync (dw, out, NULL, NULL);
-	g_object_unref (out);
-#endif
-	em_format_format_text (
-		emf, stream, (CamelDataWrapper *) puri->part, cancellable);
+	/* FIXME WEBKIT: emit signal? */
+	/*
+	g_signal_connect_swapped (
+		efh, "notify::mark-citations",
+		G_CALLBACK (e_mail_display_reload), efh->priv->mail_display);
+	 */
+	e_extensible_load_extensions (E_EXTENSIBLE (efh));
 }
 
-static void
-efh_text_html (EMFormat *emf,
-               CamelStream *stream,
-               CamelMimePart *part,
-               const EMFormatHandler *info,
-               GCancellable *cancellable,
-               gboolean is_fallback)
+GType
+em_format_html_get_type (void)
 {
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	const gchar *location;
-	gchar *cid = NULL;
-	gchar *content;
-	gchar *mail_uri;
-
-	content = g_strdup_printf (
-		"<div style=\"border: solid #%06x 1px; "
-		"background-color: #%06x; color: #%06x;\">\n"
-		"<!-- text/html -->\n" EFH_MESSAGE_START,
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_FRAME]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_CONTENT]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_TEXT]));
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	static GType type = 0;
 
-	/* TODO: perhaps we don't need to calculate this anymore now base is handled better */
-	/* calculate our own location string so add_puri doesn't do it
-	 * for us. our iframes are special cases, we need to use the
-	 * proper base url to access them, but other children parts
-	 * shouldn't blindly inherit the container's location. */
-	location = camel_mime_part_get_content_location (part);
-	if (location == NULL) {
-		if (emf->base)
-			cid = camel_url_to_string (emf->base, 0);
-		else
-			cid = g_strdup (emf->part_id->str);
-	} else {
-		if (strchr (location, ':') == NULL && emf->base != NULL) {
-			CamelURL *uri;
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMFormatHTMLClass),
+			(GBaseInitFunc) efh_base_init,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) efh_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMFormatHTML),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) efh_init,
+			NULL   /* value_table */
+		};
 
-			uri = camel_url_new_with_base (emf->base, location);
-			cid = camel_url_to_string (uri, 0);
-			camel_url_free (uri);
-		} else {
-			cid = g_strdup (location);
-		}
-	}
+		static const GInterfaceInfo extensible_info = {
+			(GInterfaceInitFunc) NULL,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
 
-	em_format_add_puri (
-		emf, sizeof (EMFormatPURI), cid,
-		part, efh_write_text_html);
-	d(printf("adding iframe, location %s\n", cid));
+		type = g_type_register_static (
+			em_format_get_type(), "EMFormatHTML",
+			&type_info, G_TYPE_FLAG_ABSTRACT);
 
-	mail_uri = em_format_build_mail_uri (emf->folder, emf->uid, cid, emf);
+		g_type_add_interface_static (
+			type, E_TYPE_EXTENSIBLE, &extensible_info);
+	}
 
-	content = g_strdup_printf (
-		"<iframe name=\"html-frame-%s\" id=\"html-frame-%s\" src=\"%s\" frameborder=0 scrolling=no width=\"100%%\" >" \
-		"Could not get %s</iframe>\n</div>\n", cid, cid, mail_uri, cid);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
-	g_free (cid);
-	g_free (mail_uri);
+	return type;
 }
 
-/* This is a lot of code for something useless ... */
-static void
-efh_message_external (EMFormat *emf,
-                      CamelStream *stream,
-                      CamelMimePart *part,
-                      const EMFormatHandler *info,
-                      GCancellable *cancellable,
-                      gboolean is_fallback)
-{
-	CamelContentType *type;
-	const gchar *access_type;
-	gchar *url = NULL, *desc = NULL;
-	gchar *content;
+/*****************************************************************************/
 
-	if (!part) {
-		camel_stream_write_string (
-			stream, _("Unknown external-body part."),
-			cancellable, NULL);
-		return;
-	}
+/* FIXME: This goes to EMailDisplay! */
+void
+em_format_html_load_images (EMFormatHTML *efh)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	/* needs to be cleaner */
-	type = camel_mime_part_get_content_type (part);
-	access_type = camel_content_type_param (type, "access-type");
-	if (!access_type) {
-		camel_stream_write_string (
-			stream, _("Malformed external-body part."),
-			cancellable, NULL);
+	if (efh->priv->image_loading_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS)
 		return;
-	}
 
-	if (!g_ascii_strcasecmp(access_type, "ftp") ||
-	    !g_ascii_strcasecmp(access_type, "anon-ftp")) {
-		const gchar *name, *site, *dir, *mode;
-		gchar *path;
-		gchar ftype[16];
+	/* This will remain set while we're still
+	 * rendering the same message, then it wont be. */
+	efh->priv->load_images_now = TRUE;
+}
 
-		name = camel_content_type_param (type, "name");
-		site = camel_content_type_param (type, "site");
-		dir = camel_content_type_param (type, "directory");
-		mode = camel_content_type_param (type, "mode");
-		if (name == NULL || site == NULL)
-			goto fail;
+void
+em_format_html_get_color (EMFormatHTML *efh,
+                          EMFormatHTMLColorType type,
+                          GdkColor *color)
+{
+	GdkColor *format_color;
 
-		/* Generate the path. */
-		if (dir)
-			path = g_strdup_printf("/%s/%s", *dir=='/'?dir+1:dir, name);
-		else
-			path = g_strdup_printf("/%s", *name=='/'?name+1:name);
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
+	g_return_if_fail (color != NULL);
 
-		if (mode && *mode)
-			sprintf(ftype, ";type=%c",  *mode);
-		else
-			ftype[0] = 0;
+	format_color = &efh->priv->colors[type];
 
-		url = g_strdup_printf ("ftp://%s%s%s";, site, path, ftype);
-		g_free (path);
-		desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url);
-	} else if (!g_ascii_strcasecmp (access_type, "local-file")) {
-		const gchar *name, *site;
+	color->red   = format_color->red;
+	color->green = format_color->green;
+	color->blue  = format_color->blue;
+}
 
-		name = camel_content_type_param (type, "name");
-		site = camel_content_type_param (type, "site");
-		if (name == NULL)
-			goto fail;
+void
+em_format_html_set_color (EMFormatHTML *efh,
+                          EMFormatHTMLColorType type,
+                          const GdkColor *color)
+{
+	GdkColor *format_color;
+	const gchar *property_name;
 
-		url = g_filename_to_uri (name, NULL, NULL);
-		if (site)
-			desc = g_strdup_printf(_("Pointer to local file (%s) valid at site \"%s\""), name, site);
-		else
-			desc = g_strdup_printf(_("Pointer to local file (%s)"), name);
-	} else if (!g_ascii_strcasecmp (access_type, "URL")) {
-		const gchar *urlparam;
-		gchar *s, *d;
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
+	g_return_if_fail (color != NULL);
 
-		/* RFC 2017 */
+	format_color = &efh->priv->colors[type];
 
-		urlparam = camel_content_type_param (type, "url");
-		if (urlparam == NULL)
-			goto fail;
+	if (gdk_color_equal (color, format_color))
+		return;
 
-		/* For obscure MIMEy reasons, the URL may be split into words */
-		url = g_strdup (urlparam);
-		s = d = url;
-		while (*s) {
-			/* FIXME: use camel_isspace */
-			if (!isspace ((guchar) * s))
-				*d++ = *s;
-			s++;
-		}
-		*d = 0;
-		desc = g_strdup_printf (_("Pointer to remote data (%s)"), url);
-	} else
-		goto fail;
+	format_color->red   = color->red;
+	format_color->green = color->green;
+	format_color->blue  = color->blue;
 
-	content = g_strdup_printf ("<a href=\"%s\">%s</a>", url, desc);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	switch (type) {
+		case EM_FORMAT_HTML_COLOR_BODY:
+			property_name = "body-color";
+			break;
+		case EM_FORMAT_HTML_COLOR_CITATION:
+			property_name = "citation-color";
+			break;
+		case EM_FORMAT_HTML_COLOR_CONTENT:
+			property_name = "content-color";
+			break;
+		case EM_FORMAT_HTML_COLOR_FRAME:
+			property_name = "frame-color";
+			break;
+		case EM_FORMAT_HTML_COLOR_HEADER:
+			property_name = "header-color";
+			break;
+		case EM_FORMAT_HTML_COLOR_TEXT:
+			property_name = "text-color";
+			break;
+		default:
+			g_return_if_reached ();
+	}
 
-	g_free (url);
-	g_free (desc);
+	g_object_notify (G_OBJECT (efh), property_name);
+}
 
-	return;
+EMailImageLoadingPolicy
+em_format_html_get_image_loading_policy (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
 
-fail:
-	content = g_strdup_printf (
-		_("Pointer to unknown external data (\"%s\" type)"),
-		access_type);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	return efh->priv->image_loading_policy;
 }
 
-static void
-efh_message_deliverystatus (EMFormat *emf,
-                            CamelStream *stream,
-                            CamelMimePart *part,
-                            const EMFormatHandler *info,
-                            GCancellable *cancellable,
-                            gboolean is_fallback)
+void
+em_format_html_set_image_loading_policy (EMFormatHTML *efh,
+                                         EMailImageLoadingPolicy policy)
 {
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	CamelStream *filtered_stream;
-	CamelMimeFilter *html_filter;
-	guint32 rgb = 0x737373;
-	gchar *content;
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	/* Yuck, this is copied from efh_text_plain */
-	content = g_strdup_printf (
-		"<div style=\"border: solid #%06x 1px; "
-		"background-color: #%06x; padding: 10px; "
-		"color: #%06x;\">\n",
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_FRAME]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_CONTENT]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_TEXT]));
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	if (policy == efh->priv->image_loading_policy)
+		return;
+
+	efh->priv->image_loading_policy = policy;
+
+	g_object_notify (G_OBJECT (efh), "image-loading-policy");
+}
 
-	filtered_stream = camel_stream_filter_new (stream);
-	html_filter = camel_mime_filter_tohtml_new (efh->text_html_flags, rgb);
-	camel_stream_filter_add (
-		CAMEL_STREAM_FILTER (filtered_stream), html_filter);
-	g_object_unref (html_filter);
+gboolean
+em_format_html_get_mark_citations (EMFormatHTML *efh)
+{
+	guint32 flags;
 
-	camel_stream_write_string (stream, "<div id=\"pre\">\n" EFH_MESSAGE_START, cancellable, NULL);
-	em_format_format_text (
-		emf, filtered_stream,
-		(CamelDataWrapper *) part, cancellable);
-	camel_stream_flush (filtered_stream, cancellable, NULL);
-	camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	camel_stream_write_string (stream, "</div>", cancellable, NULL);
+	flags = efh->text_html_flags;
+
+	return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
 }
 
-static void
-emfh_write_related (EMFormat *emf,
-                    CamelStream *stream,
-                    EMFormatPURI *puri,
-                    GCancellable *cancellable)
+void
+em_format_html_set_mark_citations (EMFormatHTML *efh,
+                                   gboolean mark_citations)
 {
-	em_format_format_content (emf, stream, puri->part, cancellable);
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+
+	/* FIXME WEBKIT: Make this thread safe */
+	if (mark_citations)
+		efh->text_html_flags |=
+			CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+	else
+		efh->text_html_flags &=
+			~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
 
-	camel_stream_close (stream, cancellable, NULL);
+	g_object_notify (G_OBJECT (efh), "mark-citations");
 }
 
-static void
-emfh_multipart_related_check (EMFormat *emf,
-			      CamelStream *stream,
-                              GCancellable *cancellable)
+gboolean
+em_format_html_get_only_local_photos (EMFormatHTML *efh)
 {
-	GList *link;
-	gchar *oldpartid;
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return;
+	return efh->priv->only_local_photos;
+}
+
+void
+em_format_html_set_only_local_photos (EMFormatHTML *efh,
+                                      gboolean only_local_photos)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	d(printf(" running multipart/related check task\n"));
-	oldpartid = g_strdup (emf->part_id->str);
+	efh->priv->only_local_photos = only_local_photos;
 
-	link = g_queue_peek_head_link (emf->pending_uri_level->data);
+	g_object_notify (G_OBJECT (efh), "only-local-photos");
+}
 
-	if (!link) {
-		g_string_printf (emf->part_id, "%s", oldpartid);
-		g_free (oldpartid);
-		return;
-	}
+gboolean
+em_format_html_get_show_sender_photo (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	while (link != NULL) {
-		EMFormatPURI *puri = link->data;
+	return efh->priv->show_sender_photo;
+}
 
-		if (puri->use_count == 0) {
-			d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"<no uri>", puri->cid, puri->use_count));
-			if (puri->func == emfh_write_related) {
-				g_string_printf (emf->part_id, "%s", puri->part_id);
-				em_format_part (
-					emf, CAMEL_STREAM (stream),
-					puri->part, cancellable);
-			}
-			/* else it was probably added by a previous format this loop */
-		}
+void
+em_format_html_set_show_sender_photo (EMFormatHTML *efh,
+                                      gboolean show_sender_photo)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-		link = g_list_next (link);
-	}
+	efh->priv->show_sender_photo = show_sender_photo;
 
-	g_string_printf (emf->part_id, "%s", oldpartid);
-	g_free (oldpartid);
+	g_object_notify (G_OBJECT (efh), "show-sender-photo");
 }
 
-/* RFC 2387 */
-static void
-efh_multipart_related (EMFormat *emf,
-                       CamelStream *stream,
-                       CamelMimePart *part,
-                       const EMFormatHandler *info,
-                       GCancellable *cancellable,
-                       gboolean is_fallback)
+gboolean
+em_format_html_get_show_real_date (EMFormatHTML *efh)
 {
-	CamelMultipart *mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
-	CamelMimePart *body_part, *display_part = NULL;
-	CamelContentType *content_type;
-	const gchar *start;
-	gint i, nparts, partidlen, displayid = 0;
-
-	if (!CAMEL_IS_MULTIPART (mp)) {
-		em_format_format_source (emf, stream, part, cancellable);
-		return;
-	}
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	nparts = camel_multipart_get_number (mp);
-	content_type = camel_mime_part_get_content_type (part);
-	start = camel_content_type_param (content_type, "start");
-	if (start && strlen (start) > 2) {
-		gint len;
-		const gchar *cid;
+	return efh->priv->show_real_date;
+}
 
-		/* strip <>'s */
-		len = strlen (start) - 2;
-		start++;
+void
+em_format_html_set_show_real_date (EMFormatHTML *efh,
+                                   gboolean show_real_date)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-		for (i = 0; i < nparts; i++) {
-			body_part = camel_multipart_get_part (mp, i);
-			cid = camel_mime_part_get_content_id (body_part);
+	efh->priv->show_real_date =	show_real_date;
 
-			if (cid && !strncmp (cid, start, len) && strlen (cid) == len) {
-				display_part = body_part;
-				displayid = i;
-				break;
-			}
-		}
-	} else {
-		display_part = camel_multipart_get_part (mp, 0);
-	}
+	g_object_notify (G_OBJECT (efh), "show-real-date");
+}
 
-	if (display_part == NULL) {
-		em_format_part_as (
-			emf, stream, part,
-			"multipart/mixed", cancellable);
-		return;
-	}
+EMFormatHTMLHeadersState
+em_format_html_get_headers_state (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
 
-	em_format_push_level (emf);
+	return efh->priv->headers_state;
+}
 
-	partidlen = emf->part_id->len;
+void
+em_format_html_set_headers_state (EMFormatHTML *efh,
+				  EMFormatHTMLHeadersState state)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	/* queue up the parts for possible inclusion */
-	for (i = 0; i < nparts; i++) {
-		body_part = camel_multipart_get_part (mp, i);
-		if (body_part != display_part) {
-			g_string_append_printf(emf->part_id, "related.%d", i);
-			em_format_add_puri (emf, sizeof (EMFormatPURI), NULL, body_part, emfh_write_related);
-			g_string_truncate (emf->part_id, partidlen);
-			d(printf(" part '%s' added\n", camel_mime_part_get_content_id (body_part)));
-		}
-	}
+	efh->priv->headers_state = state;
 
-	g_string_append_printf(emf->part_id, "related.%d", displayid);
-	em_format_part (emf, stream, display_part, cancellable);
-	g_string_truncate (emf->part_id, partidlen);
-	camel_stream_flush (stream, cancellable, NULL);
+	g_object_notify (G_OBJECT (efh), "headers-state");
+}
 
-	emfh_multipart_related_check (emf, stream, cancellable);
+gboolean
+em_format_html_get_headers_collapsable (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	em_format_pull_level (emf);
+	return efh->priv->headers_collapsable;
 }
 
-static void
-efh_write_image (EMFormat *emf,
-                 CamelStream *stream,
-                 EMFormatPURI *puri,
-                 GCancellable *cancellable)
+void
+em_format_html_set_headers_collapsable (EMFormatHTML *efh,
+					gboolean collapsable)
 {
-	CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) puri->part);
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	d(printf("writing image '%s'\n", puri->cid));
-	camel_data_wrapper_decode_to_stream_sync (
-		dw, stream, cancellable, NULL);
-	camel_stream_close (stream, cancellable, NULL);
+	efh->priv->headers_collapsable = collapsable;
+
+	g_object_notify (G_OBJECT (efh), "headers-collapsable");
 }
 
-static void
-efh_image (EMFormat *emf,
-           CamelStream *stream,
-           CamelMimePart *part,
-           const EMFormatHandler *info,
-           GCancellable *cancellable,
-           gboolean is_fallback)
+CamelMimePart *
+em_format_html_file_part (EMFormatHTML *efh,
+                          const gchar *mime_type,
+                          const gchar *filename,
+                          GCancellable *cancellable)
 {
-	EMFormatPURI *puri;
-	gchar *content;
+	CamelMimePart *part;
+	CamelStream *stream;
+	CamelDataWrapper *dw;
+	gchar *basename;
 
-	puri = em_format_add_puri (
-		emf, sizeof (EMFormatPURI), NULL, part, efh_write_image);
+	stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
+	if (stream == NULL)
+		return NULL;
 
-	content = g_strdup_printf (
-		"<img hspace=10 vspace=10 src=\"%s\">", puri->cid);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+	dw = camel_data_wrapper_new ();
+	camel_data_wrapper_construct_from_stream_sync (
+		dw, stream, cancellable, NULL);
+	g_object_unref (stream);
+	if (mime_type)
+		camel_data_wrapper_set_mime_type (dw, mime_type);
+	part = camel_mime_part_new ();
+	camel_medium_set_content ((CamelMedium *) part, dw);
+	g_object_unref (dw);
+	basename = g_path_get_basename (filename);
+	camel_mime_part_set_filename (part, basename);
+	g_free (basename);
+
+	return part;
 }
 
-/* Notes:
- *
- * image/tiff is omitted because it's a multi-page image format, but
- * gdk-pixbuf unconditionally renders the first page only, and doesn't
- * even indicate through meta-data whether multiple pages are present
- * (see bug 335959).  Therefore, make no attempt to render TIFF images
- * inline and defer to an application that can handle multi-page TIFF
- * files properly like Evince or Gimp.  Once the referenced bug is
- * fixed we can reevaluate this policy.
- */
-static EMFormatHandler type_builtin_table[] = {
-	{ (gchar *) "image/gif", efh_image },
-	{ (gchar *) "image/jpeg", efh_image },
-	{ (gchar *) "image/png", efh_image },
-	{ (gchar *) "image/x-png", efh_image },
-	{ (gchar *) "image/x-bmp", efh_image },
-	{ (gchar *) "image/bmp", efh_image },
-	{ (gchar *) "image/svg", efh_image },
-	{ (gchar *) "image/x-cmu-raster", efh_image },
-	{ (gchar *) "image/x-ico", efh_image },
-	{ (gchar *) "image/x-portable-anymap", efh_image },
-	{ (gchar *) "image/x-portable-bitmap", efh_image },
-	{ (gchar *) "image/x-portable-graymap", efh_image },
-	{ (gchar *) "image/x-portable-pixmap", efh_image },
-	{ (gchar *) "image/x-xpixmap", efh_image },
-	{ (gchar *) "text/enriched", efh_text_enriched },
-	{ (gchar *) "text/plain", efh_text_plain },
-	{ (gchar *) "text/html", efh_text_html },
-	{ (gchar *) "text/richtext", efh_text_enriched },
-	{ (gchar *) "text/*", efh_text_plain },
-	{ (gchar *) "message/external-body", efh_message_external },
-	{ (gchar *) "message/delivery-status", efh_message_deliverystatus },
-	{ (gchar *) "multipart/related", efh_multipart_related },
+gchar *
+em_format_html_format_cert_infos (CamelCipherCertInfo *first_cinfo)
+{
+	GString *res = NULL;
+	CamelCipherCertInfo *cinfo;
 
-	/* This is where one adds those busted, non-registered types,
-	 * that some idiot mailer writers out there decide to pull out
-	 * of their proverbials at random. */
+	if (!first_cinfo)
+		return NULL;
 
-	{ (gchar *) "image/jpg", efh_image },
-	{ (gchar *) "image/pjpeg", efh_image },
+	#define append(x) G_STMT_START {		\
+		if (!res) {				\
+			res = g_string_new (x);		\
+		} else {				\
+			g_string_append (res, x);	\
+		}					\
+	} G_STMT_END
 
-	/* special internal types */
+	for (cinfo = first_cinfo; cinfo && cinfo->next; cinfo = cinfo->next) {
+		if (!cinfo->name && !cinfo->email)
+			continue;
 
-	{ (gchar *) "x-evolution/message/rfc822", efh_format_message }
-};
+		if (res)
+			append (", ");
 
-static void
-efh_builtin_init (EMFormatHTMLClass *efhc)
-{
-	EMFormatClass *efc;
-	gint ii;
+		if (cinfo->name && *cinfo->name) {
+			append (cinfo->name);
+
+			if (cinfo->email && *cinfo->email) {
+				append (" &lt;");
+				append (cinfo->email);
+				append ("&gt;");
+			}
+		} else if (cinfo->email && *cinfo->email) {
+			append (cinfo->email);
+		}
+	}
 
-	efc = (EMFormatClass *) efhc;
+	#undef append
 
-	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
-		em_format_class_add_handler (
-			efc, &type_builtin_table[ii]);
+	if (!res)
+		return NULL;
+
+	return g_string_free (res, FALSE);
 }
 
-/* ********************************************************************** */
+
+
 
 static void
 efh_format_text_header (EMFormatHTML *emfh,
@@ -2188,9 +1865,11 @@ efh_format_header (EMFormat *emf,
 		struct _camel_header_address *addrs;
 		GString *html;
 		gchar *img;
+		const gchar *charset = em_format_get_charset (emf) ?
+				em_format_get_charset (emf) : em_format_get_default_charset (emf);
 
 		buf = camel_header_unfold (header->value);
-		if (!(addrs = camel_header_address_decode (buf, emf->charset ? emf->charset : emf->default_charset))) {
+ 		if (!(addrs = camel_header_address_decode (buf, charset))) {
 			g_free (buf);
 			return;
 		}
@@ -2334,7 +2013,8 @@ efh_format_short_headers (EMFormatHTML *efh,
 	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
 	charset = camel_content_type_param (ct, "charset");
 	charset = camel_iconv_charset_name (charset);
-	hdr_charset = emf->charset ? emf->charset : emf->default_charset;
+	hdr_charset = em_format_get_charset (emf) ?
+			em_format_get_charset (emf) : em_format_get_default_charset (emf);
 
 	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
 	from = g_string_new ("");
@@ -2387,6 +2067,7 @@ static void
 efh_format_full_headers (EMFormatHTML *efh,
 			 GString *buffer,
 			 CamelMedium *part,
+			 gboolean all_headers,
 			 gboolean visible,
 			 GCancellable *cancellable)
 {
@@ -2411,7 +2092,8 @@ efh_format_full_headers (EMFormatHTML *efh,
 	ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
 	charset = camel_content_type_param (ct, "charset");
 	charset = camel_iconv_charset_name (charset);
-	hdr_charset = emf->charset ? emf->charset : emf->default_charset;
+	hdr_charset = em_format_get_charset (emf) ?
+			em_format_get_charset (emf) : em_format_get_default_charset (emf);
 
 	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
 
@@ -2492,7 +2174,7 @@ efh_format_full_headers (EMFormatHTML *efh,
 	g_free (evolution_imagesdir);
 
 	/* dump selected headers */
-	if (emf->mode == EM_FORMAT_MODE_ALLHEADERS) {
+	if (all_headers) {
 		header = ((CamelMimePart *) part)->headers;
 		while (header) {
 			efh_format_header (
@@ -2576,7 +2258,7 @@ efh_format_full_headers (EMFormatHTML *efh,
 	g_string_append (buffer, "</table></td>");
 
 	if (photo_name) {
-		gchar *classid;
+		const gchar *classid;
 		CamelMimePart *photopart;
 		gboolean only_local_photo;
 
@@ -2586,56 +2268,56 @@ efh_format_full_headers (EMFormatHTML *efh,
 		photopart = em_utils_contact_photo (cia, only_local_photo);
 
 		if (photopart) {
+			EMFormatPURI *puri;
 			contact_has_photo = TRUE;
-			classid = g_strdup_printf (
-				"icon:///em-format-html/%s/photo/header",
-				emf->part_id->str);
+			classid = "icon:///em-format-html/headers/photo";
 			g_string_append_printf (
 				buffer,
 				"<td align=\"right\" valign=\"top\">"
 				"<img width=64 src=\"%s\"></td>",
 				classid);
-			em_format_add_puri (emf, sizeof (EMFormatPURI), classid,
-				photopart, efh_write_image);
+			puri = em_format_puri_new (
+					emf, sizeof (EMFormatPURI), photopart, classid);
+			puri->write_func = efh_write_image;
+			em_format_add_puri (emf, puri);
 			g_object_unref (photopart);
-
-			g_free (classid);
 		}
 		g_object_unref (cia);
 	}
 
 	if (!contact_has_photo && face_decoded) {
-		gchar *classid;
+		const gchar *classid;
 		CamelMimePart *part;
+		EMFormatPURI *puri;
 
 		part = camel_mime_part_new ();
 		camel_mime_part_set_content (
 			(CamelMimePart *) part,
 			(const gchar *) face_header_value,
 			face_header_len, "image/png");
-		classid = g_strdup_printf (
-			"icon:///em-format-html/face/photo/header");
+		classid = "icon:///em-format-html/headers/face/photo";
 		g_string_append_printf (
 			buffer,
 			"<td align=\"right\" valign=\"top\">"
 			"<img width=48 src=\"%s\"></td>",
 			classid);
-		em_format_add_puri (
-			emf, sizeof (EMFormatPURI),
-			classid, part, efh_write_image);
+
+		puri = em_format_puri_new (
+			emf, sizeof (EMFormatPURI), part, classid);
+		puri->write_func = efh_write_image;
+		em_format_add_puri (emf, puri);
+
 		g_object_unref (part);
-		g_free (classid);
 		g_free (face_header_value);
 	}
 
 	if (have_icon && efh->show_icon) {
 		GtkIconInfo *icon_info;
-		gchar *classid;
+		const gchar *classid;
 		CamelMimePart *iconpart = NULL;
+		EMFormatPURI *puri;
 
-		classid = g_strdup_printf (
-			"icon:///em-format-html/%s/icon/header",
-			emf->part_id->str);
+		classid = "icon:///em-format-html/header/icon";
 		g_string_append_printf (
 			buffer,
 			"<td align=\"right\" valign=\"top\">"
@@ -2652,31 +2334,36 @@ efh_format_full_headers (EMFormatHTML *efh,
 			gtk_icon_info_free (icon_info);
 		}
 		if (iconpart) {
-			em_format_add_puri (
-				emf, sizeof (EMFormatPURI),
-				classid, iconpart, efh_write_image);
+			puri = em_format_puri_new (
+					emf, sizeof (EMFormatPURI), iconpart, classid);
+			puri->write_func = efh_write_image;
+			em_format_add_puri (emf, puri);
 			g_object_unref (iconpart);
 		}
-		g_free (classid);
 	}
 
 	g_string_append (buffer, "</tr></table>");
 }
 
-static void
-efh_format_headers (EMFormatHTML *efh,
-		    GString *buffer,
-	            CamelMedium *part,
-                    GCancellable *cancellable)
+void
+em_format_html_format_headers (EMFormatHTML *efh,
+							   CamelStream *stream,
+							   CamelMedium *part,
+							   gboolean all_headers,
+							   GCancellable *cancellable)
 {
+	GString *buffer;
 
 	if (!part)
 		return;
 
+	buffer = g_string_new ("");
+
 	g_string_append_printf (
-		buffer, "<font color=\"#%06x\">\n"
-		"<table border=\"0\" width=\"100%%\">"
-		"<tr><td valign=\"top\" width=\"20\">",
+		buffer, EFH_HTML_HEADER,
+		e_color_to_value (
+			&efh->priv->colors[
+			EM_FORMAT_HTML_COLOR_BODY]),
 		e_color_to_value (
 			&efh->priv->colors[
 			EM_FORMAT_HTML_COLOR_HEADER]));
@@ -2692,151 +2379,28 @@ efh_format_headers (EMFormatHTML *efh,
 			cancellable);
 	}
 
-	efh_format_full_headers (efh, buffer, part,
+	efh_format_full_headers (efh, buffer, part, all_headers,
 		(efh->priv->headers_state == EM_FORMAT_HTML_HEADERS_STATE_EXPANDED),
 		cancellable);
 
-	g_string_append (buffer, "</td></tr></table></font>");
-}
-
-static void
-efh_format_message (EMFormat *emf,
-                    CamelStream *stream,
-                    CamelMimePart *part,
-                    const EMFormatHandler *info,
-                    GCancellable *cancellable,
-                    gboolean is_fallback)
-{
-	const EMFormatHandler *handle;
-	GString *buffer;
-
-	/* TODO: make this validity stuff a method */
-	EMFormatHTML *efh = (EMFormatHTML *) emf;
-	CamelCipherValidity *save = emf->valid, *save_parent = emf->valid_parent;
-
-	emf->valid = NULL;
-	emf->valid_parent = NULL;
-
-	buffer = g_string_sized_new (1024);
-	g_string_append_printf (buffer,
-		"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
-		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n" \
-		"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
-		"<style type=\"text/css\">\n" \
-		"  table th { color: #000; font-weight: bold; }\n" \
-		"</style>\n" \
-		"<script type=\"text/javascript\">\n" \
-		"function body_loaded() { window.location.hash='" EFM_MESSAGE_START_ANAME "'; }\n" \
-		"function collapse_addresses(field) {\n" \
-		"  var e=window.document.getElementById(\"moreaddr-\"+field).style;\n" \
-		"  var f=window.document.getElementById(\"moreaddr-ellipsis-\"+field).style;\n" \
-		"  var g=window.document.getElementById(\"moreaddr-img-\"+field);\n" \
-		"  if (e.display==\"inline\") { e.display=\"none\"; f.display=\"inline\"; g.src=g.src.substr(0,g.src.lastIndexOf(\"/\"))+\"/plus.png\"; }\n" \
-		"  else { e.display=\"inline\"; f.display=\"none\"; g.src=g.src.substr(0,g.src.lastIndexOf(\"/\"))+\"/minus.png\"; }\n" \
-		"}\n" \
-		"function collapse_headers() {\n" \
-		"  var f=window.document.getElementById(\"full-headers\").style;\n" \
-		"  var s=window.document.getElementById(\"short-headers\").style;\n" \
-		"  var i=window.document.getElementById(\"collapse-headers-img\");\n" \
-		"  if (f.display==\"block\") { f.display=\"none\"; s.display=\"block\";" \
-		"	i.src=i.src.substr(0,i.src.lastIndexOf(\"/\"))+\"/plus.png\"; window.headers_collapsed(true, window.em_format_html); }\n" \
-		"  else { f.display=\"block\"; s.display=\"none\";" \
-		"	 i.src=i.src.substr(0,i.src.lastIndexOf(\"/\"))+\"/minus.png\"; window.headers_collapsed(false, window.em_format_html); }\n" \
-		"}\n" \
-		"</script>\n" \
-		"</head>\n" \
-		"<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6 onLoad=\"body_loaded();\">",
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_BODY]),
-		e_color_to_value (
-			&efh->priv->colors[
-			EM_FORMAT_HTML_COLOR_HEADER]));
-
-	if (emf->message != (CamelMimeMessage *) part)
-		g_string_append (buffer, "<blockquote>\n");
-
-	if (!efh->hide_headers)
-		efh_format_headers (
-			efh, buffer, CAMEL_MEDIUM (emf->message), cancellable);
-
-	camel_stream_write (
-		stream, buffer->str, buffer->len, cancellable, NULL);
-
-	g_string_free (buffer, TRUE);
-
-	handle = em_format_find_handler(emf, "x-evolution/message/post-header");
-	if (handle)
-		handle->handler (
-			emf, stream, CAMEL_MIME_PART (emf->message), handle, cancellable, FALSE);
-
-	camel_stream_write_string (
-		stream, EM_FORMAT_HTML_VPAD, cancellable, NULL);
-	em_format_part (emf, stream, CAMEL_MIME_PART (emf->message), cancellable);
-
-	if (emf->message != (CamelMimeMessage *) part)
-		camel_stream_write_string (
-			stream, "</blockquote>\n", cancellable, NULL);
-
-	camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
-
-	camel_cipher_validity_free (emf->valid);
-
-	emf->valid = save;
-	emf->valid_parent = save_parent;
-}
-
-void
-em_format_html_format_cert_infos (GQueue *cert_infos,
-                                  GString *output_buffer)
-{
-	GQueue valid = G_QUEUE_INIT;
-	GList *head, *link;
-
-	g_return_if_fail (cert_infos != NULL);
-	g_return_if_fail (output_buffer != NULL);
-
-	head = g_queue_peek_head_link (cert_infos);
-
-	/* Make sure we have a valid CamelCipherCertInfo before
-	 * appending anything to the output buffer, so we don't
-	 * end up with "()". */
+	g_string_append (buffer, "</td></tr></table>" EFH_HTML_FOOTER);
 	for (link = head; link != NULL; link = g_list_next (link)) {
 		CamelCipherCertInfo *cinfo = link->data;
-
-		if ((cinfo->name != NULL && *cinfo->name != '\0') ||
-		    (cinfo->email != NULL && *cinfo->email != '\0'))
 			g_queue_push_tail (&valid, cinfo);
 	}
-
-	if (g_queue_is_empty (&valid))
-		return;
-
-	g_string_append (output_buffer, " (");
-
-	while (!g_queue_is_empty (&valid)) {
-		CamelCipherCertInfo *cinfo;
-
-		cinfo = g_queue_pop_head (&valid);
-
-		if (cinfo->name != NULL && *cinfo->name != '\0') {
 			g_string_append (output_buffer, cinfo->name);
 
 			if (cinfo->email != NULL && *cinfo->email != '\0') {
 				g_string_append (output_buffer, " &lt;");
 				g_string_append (output_buffer, cinfo->email);
 				g_string_append (output_buffer, "&gt;");
-			}
-
-		} else if (cinfo->email != NULL && *cinfo->email != '\0') {
 			g_string_append (output_buffer, cinfo->email);
 		}
 
-		if (!g_queue_is_empty (&valid))
-			g_string_append (output_buffer, ", ");
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
 	}
 
-	g_string_append_c (output_buffer, ')');
+	g_string_free (buffer, true);
 }
 
 /* unref returned pointer with g_object_unref(), if not NULL */
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index a12f393..0891d54 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -56,6 +56,7 @@ 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,
@@ -83,39 +84,6 @@ typedef enum {
 	EM_FORMAT_HTML_NUM_COLOR_TYPES
 } EMFormatHTMLColorType;
 
-/* Pending object (classid: url) */
-typedef struct _EMFormatHTMLPObject EMFormatHTMLPObject;
-
-typedef GtkWidget*
-		(*EMFormatHTMLPObjectFunc)	(EMFormatHTML *md,
-						 EMFormatHTMLPObject *pobject);
-
-/**
- * struct _EMFormatHTMLPObject - Pending object.
- *
- * @free: Invoked when the object is no longer needed.
- * @format: The parent formatter.
- * @classid: The assigned class id as passed to add_pobject().
- * @func: Callback function.
- * @part: The part as passed to add_pobject().
- *
- * This structure is used to track OBJECT tags which have been
- * inserted into the HTML stream.  When GtkHTML requests them the
- * @func will be invoked to create the embedded widget.
- *
- * This object is struct-subclassable.  Only
- * em_format_html_add_pobject() may be used to allocate these.
- **/
-struct _EMFormatHTMLPObject {
-	void (*free)(EMFormatHTMLPObject *);
-	EMFormatHTML *format;
-
-	gchar *classid;
-
-	EMFormatHTMLPObjectFunc func;
-	CamelMimePart *part;
-};
-
 #define EM_FORMAT_HTML_HEADER_NOCOLUMNS (EM_FORMAT_HEADER_LAST)
 
 /* header already in html format */
@@ -178,7 +146,6 @@ struct _EMFormatHTMLClass {
 };
 
 GType		em_format_html_get_type		(void);
-EWebView *	em_format_html_get_web_view	(EMFormatHTML *efh);
 void		em_format_html_load_images	(EMFormatHTML *efh);
 void		em_format_html_get_color	(EMFormatHTML *efh,
 						 EMFormatHTMLColorType type,
@@ -208,37 +175,11 @@ void		em_format_html_set_show_sender_photo
 						(EMFormatHTML *efh,
 						 gboolean show_sender_photo);
 
-/* retrieves a pseudo-part icon wrapper for a file */
-CamelMimePart *	em_format_html_file_part	(EMFormatHTML *efh,
-						 const gchar *mime_type,
-						 const gchar *filename,
-						 GCancellable *cancellable);
-
-/* for implementers */
-EMFormatHTMLPObject *
-		em_format_html_add_pobject	(EMFormatHTML *efh,
-						 gsize size,
-						 const gchar *classid,
-						 CamelMimePart *part,
-						 EMFormatHTMLPObjectFunc func);
-EMFormatHTMLPObject *
-		em_format_html_find_pobject	(EMFormatHTML *efh,
-						 const gchar *classid);
-EMFormatHTMLPObject *
-		em_format_html_find_pobject_func
-						(EMFormatHTML *efh,
-						 CamelMimePart *part,
-						 EMFormatHTMLPObjectFunc func);
-void		em_format_html_remove_pobject	(EMFormatHTML *efh,
-						 EMFormatHTMLPObject *pobject);
-void		em_format_html_clear_pobject	(EMFormatHTML *efh);
-
 void		em_format_html_clone_sync	(CamelFolder *folder,
 						 const gchar *message_uid,
 						 CamelMimeMessage *message,
 						 EMFormatHTML *efh,
 						 EMFormat *source);
-
 gboolean	em_format_html_get_show_real_date
 						(EMFormatHTML *efh);
 void		em_format_html_set_show_real_date
@@ -255,26 +196,35 @@ gboolean	em_format_html_get_headers_collapsable
 void		em_format_html_set_headers_collapsable
 						(EMFormatHTML *efh,
 						 gboolean collapsable);
-void		em_format_html_format_cert_infos
-						(GQueue *cert_infos,
-						 GString *output_buffer);
 
-CamelStream *	
-			em_format_html_get_cached_image	(EMFormatHTML *efh,
+/* retrieves a pseudo-part icon wrapper for a file */
+CamelMimePart *	em_format_html_file_part	(EMFormatHTML *efh,
+						 const gchar *mime_type,
+						 const gchar *filename,
+						 GCancellable *cancellable);
+
+gchar *		em_format_html_format_cert_infos
+						(CamelCipherCertInfo *first_cinfo);
+
+CamelStream *
+		em_format_html_get_cached_image	(EMFormatHTML *efh,
 						 const gchar *image_uri);
 
-void		em_format_html_format_message (EMFormatHTML *efh,
-					       CamelStream *stream,
-					       GCancellable *cancellable);
+void		em_format_html_format_message	(EMFormatHTML *efh,
+						 CamelStream *stream,
+						 GCancellable *cancellable);
+
+void		em_format_html_format_message_part
+						(EMFormatHTML *efh,
+						 const gchar *part_id,
+    						 CamelStream *stream,
+						 GCancellable *cancellable);
 
-void		em_format_html_format_message_part (EMFormatHTML *efh,
-						    const gchar *part_id,
-    						    CamelStream *stream,
-						    GCancellable *cancellable);
-void		em_format_html_format_headers (EMFormatHTML *efh,
-					       CamelStream *stream,
-					       CamelMedium *part,
-					       GCancellable *cancellable);
+void		em_format_html_format_headers	(EMFormatHTML *efh,
+						 CamelStream *stream,
+						 CamelMedium *part,
+						 gboolean all_headers,
+						 GCancellable *cancellable);
 
 G_END_DECLS
 



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