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



commit d0d7f9b6fc649caa8e678b8f17bcc678d21d4aa0
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 |  560 +++-----
 mail/em-format-html-display.h |   45 +
 mail/em-format-html-print.c   |   15 +-
 mail/em-format-html.c         | 3039 ++++++++++++++++++-----------------------
 mail/em-format-html.h         |   89 +-
 7 files changed, 1575 insertions(+), 2200 deletions(-)
---
diff --git a/mail/em-format-hook.c b/mail/em-format-hook.c
index 51608ca..7f7fc7c 100644
--- a/mail/em-format-hook.c
+++ b/mail/em-format-hook.c
@@ -60,24 +60,23 @@ static const EPluginHookTargetKey emfh_flag_map[] = {
 };
 
 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);
 	}
 }
 
@@ -115,7 +114,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 ad3f162..5423203 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -67,15 +67,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 */
@@ -105,65 +96,36 @@ 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);
 
 static gpointer parent_class;
 
 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;
@@ -172,7 +134,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;
@@ -200,7 +162,7 @@ efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
 static void
 efhd_xpkcs7mime_add_cert_table (GtkWidget *vbox,
                                 CamelDList *certlist,
-                                struct _smime_pobject *po)
+                                EMFormatSMIMEPURI *po)
 {
 	CamelCipherCertInfo *info = (CamelCipherCertInfo *) certlist->head;
 	GtkTable *table = (GtkTable *) gtk_table_new (camel_dlist_length (certlist), 2, FALSE);
@@ -257,9 +219,9 @@ efhd_xpkcs7mime_add_cert_table (GtkWidget *vbox,
 
 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 *vbox, *w;
 
@@ -343,11 +305,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 */
@@ -359,7 +322,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 (
@@ -402,12 +365,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;
 
@@ -417,214 +378,150 @@ 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 (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) {
 			gchar *signers;
 			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));
 
 			signers = em_format_html_format_cert_infos (
-				(CamelCipherCertInfo *) valid->sign.signers.head);
+				(CamelCipherCertInfo *) puri->validity->sign.signers.head);
 			if (signers && *signers) {
 				g_string_append_printf (
 					buffer, " (%s)", signers);
@@ -632,24 +529,19 @@ efhd_format_secure (EMFormat *emf,
 			g_free (signers);
 		}
 
-		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);
 	}
 }
 
@@ -834,7 +726,7 @@ efhd_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;
@@ -848,20 +740,9 @@ efhd_class_init (EMFormatHTMLDisplayClass *class)
 static void
 efhd_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 = G_TYPE_INSTANCE_GET_PRIVATE (
 		efhd, EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayPrivate);
 	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 |=
@@ -924,8 +805,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
@@ -933,8 +814,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
@@ -954,60 +837,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);
@@ -1018,7 +884,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);
@@ -1026,7 +892,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 (
@@ -1042,89 +908,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_uid (emf->folder->summary, emf->uid);
+		mi = camel_folder_summary_uid (emf->folder->summary, emf->message_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? */
@@ -1135,8 +955,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;
@@ -1148,10 +966,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);
@@ -1183,20 +1004,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;
 }
 
@@ -1206,6 +1013,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)
@@ -1214,6 +1024,7 @@ efhd_attachment_frame (EMFormat *emf,
 			info->handle, cancellable, FALSE);
 
 	camel_stream_close (stream, cancellable, NULL);
+	*/
 }
 
 static void
@@ -1236,11 +1047,13 @@ efhd_bar_resize (EMFormatHTML *efh,
 
 	priv = EM_FORMAT_HTML_DISPLAY (efh)->priv;
 
+	/* 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));
@@ -1248,24 +1061,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 (efh)->priv;
 
 	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);
 
@@ -1278,29 +1097,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);
 }
@@ -1328,17 +1149,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;
@@ -1346,11 +1169,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;
@@ -1417,11 +1243,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);
@@ -1435,7 +1263,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 dbfe011..23cba45 100644
--- a/mail/em-format-html-print.c
+++ b/mail/em-format-html-print.c
@@ -81,6 +81,7 @@ efhp_init (GObject *o)
 	EMFormatHTMLPrint *efhp = (EMFormatHTMLPrint *) o;
 	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
@@ -89,7 +90,10 @@ efhp_init (GObject *o)
 	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;
+	*/
 }
 
 GType
@@ -206,10 +210,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
 	gtk_html_print_operation_run (
 		GTK_HTML (web_view),
 		operation, efhp->action, NULL,
@@ -218,7 +220,7 @@ emfhp_complete (EMFormatHTMLPrint *efhp)
 		(GtkHTMLPrintDrawFunc) NULL,
 		(GtkHTMLPrintDrawFunc) efhp_draw_footer,
 		NULL, &error);
-
+*/
 	g_object_unref (operation);
 }
 
@@ -243,8 +245,5 @@ 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 (efhp),
-		folder, message_uid, message,
-		EM_FORMAT (efhp->source), NULL);
+	em_format_parse (EM_FORMAT (efhp), message, folder, NULL);
 }
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 4369d04..3da2a94 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -59,25 +59,11 @@
 #include "em-format-html.h"
 #include "em-utils.h"
 #include "mail-config.h"
-#include "mail-mt.h"
+#include <em-format/em-inline-filter.h>
 
 #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;
 
@@ -90,6 +76,8 @@ struct _EMFormatHTMLPrivate {
 	guint show_real_date	: 1;
 };
 
+static gpointer parent_class;
+
 enum {
 	PROP_0,
 	PROP_BODY_COLOR,
@@ -103,1867 +91,1548 @@ 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));
-
-	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));
-
-	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_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_class_install_property (
-		object_class,
-		PROP_HEADER_COLOR,
-		g_param_spec_boxed (
-			"header-color",
-			"Header Color",
-			NULL,
-			GDK_TYPE_COLOR,
-			G_PARAM_READWRITE));
-
-	/* 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));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_MARK_CITATIONS,
-		g_param_spec_boolean (
-			"mark-citations",
-			"Mark Citations",
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE));
-
-	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));
-
-	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));
-
-	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));
-
-	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_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));
+	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_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));
+	camel_stream_write_string (stream, content, cancellable, NULL);
+	g_free (content);
 
-	g_object_class_install_property (
-		object_class,
-		PROP_HEADERS_COLLAPSABLE,
-		g_param_spec_boolean (
-			"headers-collapsable",
-			NULL,
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE));
+	em_format_format_text (
+		emf, (CamelStream *) filtered_stream,
+		(CamelDataWrapper *) puri->part, cancellable);
 
-	/* 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);
-	}
+	g_object_unref (filtered_stream);
+	camel_stream_write_string (stream, "</div>", cancellable, NULL);
 }
 
 static void
-efh_init (EMFormatHTML *efh,
-          EMFormatHTMLClass *class)
+efh_write_text_plain (EMFormat *emf,
+		      EMFormatPURI *puri,
+		      CamelStream *stream,
+		      GCancellable *cancellable)
 {
-	EWebView *web_view;
-	GdkColor *color;
-
-	efh->priv = G_TYPE_INSTANCE_GET_PRIVATE (
-		efh, EM_TYPE_FORMAT_HTML, EMFormatHTMLPrivate);
-
-	efh->priv->text_inline_parts = g_hash_table_new_full (
-		g_str_hash, g_str_equal,
-		(GDestroyNotify) NULL,
-		(GDestroyNotify) efh_free_cache);
-
-	web_view = g_object_new (class->html_widget_type, NULL);
-	efh->priv->web_view = g_object_ref_sink (web_view);
-
-	g_queue_init (&efh->pending_object_list);
-
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
-	gdk_color_parse ("#eeeeee", color);
-
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT];
-	gdk_color_parse ("#ffffff", color);
-
-	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME];
-	gdk_color_parse ("#3f3f3f", color);
-
-	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);
-
-	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;
-
-	g_signal_connect_swapped (
-		efh, "notify::mark-citations",
-		G_CALLBACK (e_web_view_reload), web_view);
-
-	e_extensible_load_extensions (E_EXTENSIBLE (efh));
-}
-
-GType
-em_format_html_get_type (void)
-{
-	static GType type = 0;
-
-	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);
-
-	return efh->priv->web_view;
-}
-
-void
-em_format_html_load_images (EMFormatHTML *efh)
-{
-	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);
-}
-
-void
-em_format_html_get_color (EMFormatHTML *efh,
-                          EMFormatHTMLColorType type,
-                          GdkColor *color)
-{
-	GdkColor *format_color;
-
-	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);
-
-	format_color = &efh->priv->colors[type];
-
-	color->red   = format_color->red;
-	color->green = format_color->green;
-	color->blue  = format_color->blue;
-}
-
-void
-em_format_html_set_color (EMFormatHTML *efh,
-                          EMFormatHTMLColorType type,
-                          const GdkColor *color)
-{
-	GdkColor *format_color;
-	const gchar *property_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);
-
-	format_color = &efh->priv->colors[type];
-
-	if (gdk_color_equal (color, format_color))
-		return;
-
-	format_color->red   = color->red;
-	format_color->green = color->green;
-	format_color->blue  = color->blue;
-
-	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_object_notify (G_OBJECT (efh), property_name);
-}
-
-EMailImageLoadingPolicy
-em_format_html_get_image_loading_policy (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
-
-	return efh->priv->image_loading_policy;
-}
-
-void
-em_format_html_set_image_loading_policy (EMFormatHTML *efh,
-                                         EMailImageLoadingPolicy policy)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	CamelDataWrapper *dw;
+	CamelStream *filtered_stream;
+	CamelMimeFilter *html_filter;
+	EMFormatHTML *efh = (EMFormatHTML*) emf;
+	gchar *content;
+	const gchar *format;
+	guint32 flags;
+	guint32 rgb;
 
-	if (policy == efh->priv->image_loading_policy)
+	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	efh->priv->image_loading_policy = policy;
+	flags = efh->text_html_flags;
 
-	g_object_notify (G_OBJECT (efh), "image-loading-policy");
-}
+	dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
 
-gboolean
-em_format_html_get_mark_citations (EMFormatHTML *efh)
-{
-	guint32 flags;
+	/* 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_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	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);
 
-	flags = efh->text_html_flags;
+	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]));
 
-	return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
-}
+	camel_stream_write_string (
+			stream, content, cancellable, NULL);
+	g_free (content);
 
-void
-em_format_html_set_mark_citations (EMFormatHTML *efh,
-                                   gboolean mark_citations)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	em_format_format_text (
+			emf, filtered_stream,
+			(CamelDataWrapper *) puri->part,
+			cancellable);
 
-	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_unref (filtered_stream);
 
-	g_object_notify (G_OBJECT (efh), "mark-citations");
+	camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
+	camel_stream_write_string (stream, EFH_HTML_FOOTER, cancellable, NULL);
 }
 
-gboolean
-em_format_html_get_only_local_photos (EMFormatHTML *efh)
+static void
+efh_write_text_html (EMFormat *emf,
+		     EMFormatPURI *puri,
+		     CamelStream *stream,
+		     GCancellable *cancellable)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
 
-	return efh->priv->only_local_photos;
+	em_format_format_text (
+		emf, stream, (CamelDataWrapper *) puri->part, cancellable);
 }
 
-void
-em_format_html_set_only_local_photos (EMFormatHTML *efh,
-                                      gboolean only_local_photos)
+static void
+efh_write_source (EMFormat *emf,
+		  EMFormatPURI *puri,
+		  CamelStream *stream,
+		  GCancellable *cancellable)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) puri->part;
 
-	efh->priv->only_local_photos = only_local_photos;
+	filtered_stream = camel_stream_filter_new (stream);
 
-	g_object_notify (G_OBJECT (efh), "only-local-photos");
-}
+	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);
 
-gboolean
-em_format_html_get_show_sender_photo (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	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);
 
-	return efh->priv->show_sender_photo;
+	g_object_unref (filtered_stream);
 }
 
-void
-em_format_html_set_show_sender_photo (EMFormatHTML *efh,
-                                      gboolean show_sender_photo)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+/*****************************************************************************/
 
-	efh->priv->show_sender_photo = show_sender_photo;
+/* 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 },
 
-	g_object_notify (G_OBJECT (efh), "show-sender-photo");
-}
+	/* 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. */
 
-gboolean
-em_format_html_get_show_real_date (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+	{ (gchar *) "image/jpg", efh_parse_image, efh_write_image, },
+	{ (gchar *) "image/pjpeg", efh_parse_image, efh_write_image, },
 
-	return efh->priv->show_real_date;
-}
+	/* special internal types */
+	{ (gchar *) "x-evolution/message/rfc822", 0, efh_write_text_plain }
+};
 
-void
-em_format_html_set_show_real_date (EMFormatHTML *efh,
-                                   gboolean show_real_date)
+static void
+efh_builtin_init (EMFormatHTMLClass *efhc)
 {
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+	EMFormatClass *emfc;
+	gint ii;
 
-	efh->priv->show_real_date = show_real_date;
+	emfc = (EMFormatClass *) efhc;
 
-	g_object_notify (G_OBJECT (efh), "show-real-date");
+	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
+		em_format_class_add_handler (
+			emfc, &type_builtin_table[ii]);
 }
 
-EMFormatHTMLHeadersState
-em_format_html_get_headers_state (EMFormatHTML *efh)
+static void
+efh_set_property (GObject *object,
+                  guint property_id,
+                  const GValue *value,
+                  GParamSpec *pspec)
 {
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
+	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;
 
-	return efh->priv->headers_state;
-}
+		case PROP_CITATION_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CITATION,
+				g_value_get_boxed (value));
+			return;
 
-void
-em_format_html_set_headers_state (EMFormatHTML *efh,
-                                  EMFormatHTMLHeadersState state)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+		case PROP_CONTENT_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_CONTENT,
+				g_value_get_boxed (value));
+			return;
 
-	efh->priv->headers_state = state;
+		case PROP_FRAME_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_FRAME,
+				g_value_get_boxed (value));
+			return;
 
-	g_object_notify (G_OBJECT (efh), "headers-state");
-}
+		case PROP_HEADER_COLOR:
+			em_format_html_set_color (
+				EM_FORMAT_HTML (object),
+				EM_FORMAT_HTML_COLOR_HEADER,
+				g_value_get_boxed (value));
+			return;
 
-gboolean
-em_format_html_get_headers_collapsable (EMFormatHTML *efh)
-{
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
+		case PROP_IMAGE_LOADING_POLICY:
+			em_format_html_set_image_loading_policy (
+				EM_FORMAT_HTML (object),
+				g_value_get_enum (value));
+			return;
 
-	return efh->priv->headers_collapsable;
-}
+		case PROP_MARK_CITATIONS:
+			em_format_html_set_mark_citations (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-void
-em_format_html_set_headers_collapsable (EMFormatHTML *efh,
-                                        gboolean collapsable)
-{
-	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+		case PROP_ONLY_LOCAL_PHOTOS:
+			em_format_html_set_only_local_photos (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	efh->priv->headers_collapsable = collapsable;
+		case PROP_SHOW_SENDER_PHOTO:
+			em_format_html_set_show_sender_photo (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
 
-	g_object_notify (G_OBJECT (efh), "headers-collapsable");
+		case PROP_SHOW_REAL_DATE:
+			em_format_html_set_show_real_date (
+				EM_FORMAT_HTML (object),
+				g_value_get_boolean (value));
+			return;
+
+		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_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-CamelMimePart *
-em_format_html_file_part (EMFormatHTML *efh,
-                          const gchar *mime_type,
-                          const gchar *filename,
-                          GCancellable *cancellable)
+static void
+efh_get_property (GObject *object,
+                  guint property_id,
+                  GValue *value,
+                  GParamSpec *pspec)
 {
-	CamelMimePart *part;
-	CamelStream *stream;
-	CamelDataWrapper *dw;
-	gchar *basename;
+	GdkColor color;
 
-	stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
-	if (stream == NULL)
-		return NULL;
+	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;
 
-	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);
+		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;
 
-	return part;
-}
+		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;
+
+		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;
+
+		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;
+
+		case PROP_IMAGE_LOADING_POLICY:
+			g_value_set_enum (
+				value,
+				em_format_html_get_image_loading_policy (
+				EM_FORMAT_HTML (object)));
+			return;
 
-/* all this api is a pain in the bum ... */
+		case PROP_MARK_CITATIONS:
+			g_value_set_boolean (
+				value, em_format_html_get_mark_citations (
+				EM_FORMAT_HTML (object)));
+			return;
 
-EMFormatHTMLPObject *
-em_format_html_add_pobject (EMFormatHTML *efh,
-                            gsize size,
-                            const gchar *classid,
-                            CamelMimePart *part,
-                            EMFormatHTMLPObjectFunc func)
-{
-	EMFormatHTMLPObject *pobj;
+		case PROP_ONLY_LOCAL_PHOTOS:
+			g_value_set_boolean (
+				value, em_format_html_get_only_local_photos (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	if (size < sizeof (EMFormatHTMLPObject)) {
-		g_warning ("size is less than the size of EMFormatHTMLPObject\n");
-		size = sizeof (EMFormatHTMLPObject);
-	}
+		case PROP_SHOW_SENDER_PHOTO:
+			g_value_set_boolean (
+				value, em_format_html_get_show_sender_photo (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	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);
+		case PROP_SHOW_REAL_DATE:
+			g_value_set_boolean (
+				value, em_format_html_get_show_real_date (
+				EM_FORMAT_HTML (object)));
+			return;
 
-	pobj->format = efh;
-	pobj->func = func;
-	pobj->part = part;
+		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;
 
-	g_queue_push_tail (&efh->pending_object_list, pobj);
+		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)));
+	}
 
-	return pobj;
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-EMFormatHTMLPObject *
-em_format_html_find_pobject (EMFormatHTML *efh,
-                             const gchar *classid)
+static void
+efh_finalize (GObject *object)
 {
-	GList *link;
-
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
-	g_return_val_if_fail (classid != NULL, NULL);
-
-	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);
-	}
+	EMFormatHTML *efh = EM_FORMAT_HTML (object);
+	EMFormatHTMLPrivate *priv = efh->priv;
 
-	return NULL;
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-EMFormatHTMLPObject *
-em_format_html_find_pobject_func (EMFormatHTML *efh,
-                                  CamelMimePart *part,
-                                  EMFormatHTMLPObjectFunc func)
+static void
+efh_format_error (EMFormat *emf,
+                  const gchar *message)
 {
-	GList *link;
+	EMFormatPURI *puri;
+	CamelMimePart *part;
+	GString *buffer;
+	gchar *html;
+
+	buffer = g_string_new ("<em><font color=\"red\">");
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), NULL);
+	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);
 
-	link = g_queue_peek_head_link (&efh->pending_object_list);
+	g_string_append (buffer, "</font></em><br>");
 
-	while (link != NULL) {
-		EMFormatHTMLPObject *pw = link->data;
+	part = camel_mime_part_new ();
+	camel_mime_part_set_content (part, buffer->str, buffer->len, "text/html");
 
-		if (pw->func == func && pw->part == part)
-			return pw;
+	puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, ".error");
+	puri->write_func = efh_write_text_html;
 
-		link = g_list_next (link);
-	}
+	em_format_add_puri (emf, puri);
 
-	return NULL;
+	g_string_free (buffer, TRUE);
 }
 
-void
-em_format_html_remove_pobject (EMFormatHTML *efh,
-                               EMFormatHTMLPObject *pobject)
+static void
+efh_format_source (EMFormat *emf,
+		   CamelStream *stream,
+		   CamelMimePart *part,
+		   GCancellable *cancellable)
 {
-	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);
+	CamelStream *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) part;
 
-	g_free (pobject->classid);
-	g_free (pobject);
-}
+	filtered_stream = camel_stream_filter_new (stream);
 
-void
-em_format_html_clear_pobject (EMFormatHTML *efh)
-{
-	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);
 
-	while (!g_queue_is_empty (&efh->pending_object_list)) {
-		EMFormatHTMLPObject *pobj;
+	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);
 
-		pobj = g_queue_pop_head (&efh->pending_object_list);
-		em_format_html_remove_pobject (efh, pobj);
-	}
+	g_object_unref (filtered_stream);
 }
 
-void
-em_format_html_format_message (EMFormatHTML *efh,
-							   CamelStream *stream,
-							   GCancellable *cancellable)
+/* 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)
 {
-	EMFormat *emf;
-
-	d(printf(" running format_email task\n"));
+	gchar *text, *html;
 
-	if (g_cancellable_is_cancelled (cancellable))
-		return;
+	/* 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);
 
-	emf = EM_FORMAT (efh);
-	em_format_html_clear_pobject(efh);
-	g_hash_table_remove_all (efh->priv->text_inline_parts);
+	/* 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);
 
-	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);
-	}
+	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);
+*/
 }
 
-void
-em_format_html_format_message_part (EMFormatHTML *efh,
-									const gchar *part_id,
-									CamelStream *stream,
-									GCancellable *cancellable)
+static void
+efh_base_init (EMFormatHTMLClass *class)
 {
-	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);
+	efh_builtin_init (class);
 }
 
-
-/* ********************************************************************** */
-#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)
+efh_class_init (EMFormatHTMLClass *class)
 {
+	GObjectClass *object_class;
 	EMFormatClass *format_class;
+	const gchar *user_cache_dir;
 
-	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);
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMFormatHTMLPrivate));
 
-	/* 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;
+	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;
 
-		buffer = g_string_sized_new (1024);
+	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));
 
-		g_string_append_printf (
-			buffer,
-			"<table border=0 width=\"100%%\" "
-			"cellpadding=3 cellspacing=0%s><tr>",
-			smime_sign_colour[valid->sign.status]);
+	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));
 
-		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_CONTENT_COLOR,
+		g_param_spec_boxed (
+			"content-color",
+			"Content Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			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_FRAME_COLOR,
+		g_param_spec_boxed (
+			"frame-color",
+			"Frame Color",
+			NULL,
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	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));
+
+	/* 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));
+
+	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 != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
-			gchar *signers;
+	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));
 
-			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));
 
-			signers = em_format_html_format_cert_infos (
-				(CamelCipherCertInfo *) valid->sign.signers.head);
-			if (signers && *signers) {
-				g_string_append_printf (
-					buffer, " (%s)", signers);
-			}
-			g_free (signers);
-		}
+	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;
-		}
+	GdkColor *color;
 
-		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);
+	efh->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+		efh, EM_TYPE_FORMAT_HTML, EMFormatHTMLPrivate);
 
-		mp = em_inline_filter_get_multipart (inline_filter);
-		if (efhc == NULL)
-			efhc = efh_insert_cache (efh, emf->part_id->str);
-		efhc->textmp = mp;
+	/* FIXME WEBKIT
+	efh->priv->text_inline_parts = g_hash_table_new_full (
+		g_str_hash, g_str_equal,
+		(GDestroyNotify) NULL,
+		(GDestroyNotify) efh_free_cache);
+	*/
 
-		if (charset_added) {
-			camel_content_type_set_param (ct, "charset", NULL);
-		}
+	g_queue_init (&efh->pending_object_list);
 
-		g_object_unref (inline_filter);
-		camel_content_type_unref (ct);
-	}
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
+	gdk_color_parse ("#eeeeee", color);
 
-	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);
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT];
+	gdk_color_parse ("#ffffff", color);
 
-	/* We handle our made-up multipart here, so we don't recursively call ourselves */
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME];
+	gdk_color_parse ("#3f3f3f", color);
 
-	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);
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER];
+	gdk_color_parse ("#eeeeee", color);
 
-		if (!newpart)
-			continue;
+	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT];
+	gdk_color_parse ("#000000", 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->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;
 
-	g_object_unref (filtered_stream);
+	/* 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_enriched (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);
-	CamelStream *filtered_stream;
-	CamelMimeFilter *enriched;
-	guint32 flags = 0;
-	gchar *content;
+	static GType type = 0;
 
-	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);
-	}
+	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 */
+		};
 
-	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);
+		static const GInterfaceInfo extensible_info = {
+			(GInterfaceInitFunc) NULL,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
 
-	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);
+		type = g_type_register_static (
+			em_format_get_type(), "EMFormatHTML",
+			&type_info, G_TYPE_FLAG_ABSTRACT);
 
-	em_format_format_text (
-		emf, (CamelStream *) filtered_stream,
-		(CamelDataWrapper *) part, cancellable);
+		g_type_add_interface_static (
+			type, E_TYPE_EXTENSIBLE, &extensible_info);
+	}
 
-	g_object_unref (filtered_stream);
-	camel_stream_write_string (stream, "</div>", cancellable, NULL);
+	return type;
 }
 
-static void
-efh_write_text_html (EMFormat *emf,
-                     CamelStream *stream,
-                     EMFormatPURI *puri,
-                     GCancellable *cancellable)
-{
-#if d(!)0
-	CamelStream *out;
-	gint fd;
-	CamelDataWrapper *dw;
-
-	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);
-}
+/*****************************************************************************/
 
-static void
-efh_text_html (EMFormat *emf,
-               CamelStream *stream,
-               CamelMimePart *part,
-               const EMFormatHandler *info,
-               GCancellable *cancellable,
-               gboolean is_fallback)
+/* FIXME: This goes to EMailDisplay! */
+void
+em_format_html_load_images (EMFormatHTML *efh)
 {
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	const gchar *location;
-	gchar *cid = NULL;
-	gchar *content;
-	gchar *mail_uri;
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	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);
+	if (efh->priv->image_loading_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS)
+		return;
 
-	/* 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;
+	/* This will remain set while we're still
+	 * rendering the same message, then it wont be. */
+	efh->priv->load_images_now = TRUE;
+}
 
-			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);
-		}
-	}
+void
+em_format_html_get_color (EMFormatHTML *efh,
+                          EMFormatHTMLColorType type,
+                          GdkColor *color)
+{
+	GdkColor *format_color;
 
-	em_format_add_puri (
-		emf, sizeof (EMFormatPURI), cid,
-		part, efh_write_text_html);
-	d(printf("adding iframe, location %s\n", cid));
+	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);
 
-	mail_uri = em_format_build_mail_uri (emf->folder, emf->uid, cid, emf);
+	format_color = &efh->priv->colors[type];
 
-	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);
+	color->red   = format_color->red;
+	color->green = format_color->green;
+	color->blue  = format_color->blue;
 }
 
-/* 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)
+void
+em_format_html_set_color (EMFormatHTML *efh,
+                          EMFormatHTMLColorType type,
+                          const GdkColor *color)
 {
-	CamelContentType *type;
-	const gchar *access_type;
-	gchar *url = NULL, *desc = NULL;
-	gchar *content;
+	GdkColor *format_color;
+	const gchar *property_name;
 
-	if (!part) {
-		camel_stream_write_string (
-			stream, _("Unknown external-body part."),
-			cancellable, NULL);
-		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);
 
-	/* 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);
-		return;
-	}
+	format_color = &efh->priv->colors[type];
 
-	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];
+	if (gdk_color_equal (color, format_color))
+		return;
 
-		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;
+	format_color->red   = color->red;
+	format_color->green = color->green;
+	format_color->blue  = color->blue;
 
-		/* 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);
+	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 ();
+	}
 
-		if (mode && *mode)
-			sprintf(ftype, ";type=%c",  *mode);
-		else
-			ftype[0] = 0;
+	g_object_notify (G_OBJECT (efh), property_name);
+}
 
-		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;
+EMailImageLoadingPolicy
+em_format_html_get_image_loading_policy (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
 
-		name = camel_content_type_param (type, "name");
-		site = camel_content_type_param (type, "site");
-		if (name == NULL)
-			goto fail;
+	return efh->priv->image_loading_policy;
+}
 
-		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;
+void
+em_format_html_set_image_loading_policy (EMFormatHTML *efh,
+                                         EMailImageLoadingPolicy policy)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-		/* RFC 2017 */
+	if (policy == efh->priv->image_loading_policy)
+		return;
 
-		urlparam = camel_content_type_param (type, "url");
-		if (urlparam == NULL)
-			goto fail;
+	efh->priv->image_loading_policy = policy;
 
-		/* 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;
+	g_object_notify (G_OBJECT (efh), "image-loading-policy");
+}
 
-	content = g_strdup_printf ("<a href=\"%s\">%s</a>", url, desc);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
+gboolean
+em_format_html_get_mark_citations (EMFormatHTML *efh)
+{
+	guint32 flags;
 
-	g_free (url);
-	g_free (desc);
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	return;
+	flags = efh->text_html_flags;
 
-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 ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0);
 }
 
-static void
-efh_message_deliverystatus (EMFormat *emf,
-                            CamelStream *stream,
-                            CamelMimePart *part,
-                            const EMFormatHandler *info,
-                            GCancellable *cancellable,
-                            gboolean is_fallback)
+void
+em_format_html_set_mark_citations (EMFormatHTML *efh,
+                                   gboolean mark_citations)
 {
-	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);
+	/* 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;
 
-	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);
+	g_object_notify (G_OBJECT (efh), "mark-citations");
+}
 
-	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);
+gboolean
+em_format_html_get_only_local_photos (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	camel_stream_write_string (stream, "</div>", cancellable, NULL);
+	return efh->priv->only_local_photos;
 }
 
-static void
-emfh_write_related (EMFormat *emf,
-                    CamelStream *stream,
-                    EMFormatPURI *puri,
-                    GCancellable *cancellable)
+void
+em_format_html_set_only_local_photos (EMFormatHTML *efh,
+                                      gboolean only_local_photos)
 {
-	em_format_format_content (emf, stream, puri->part, cancellable);
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
+
+	efh->priv->only_local_photos = only_local_photos;
 
-	camel_stream_close (stream, cancellable, NULL);
+	g_object_notify (G_OBJECT (efh), "only-local-photos");
 }
 
-static void
-emfh_multipart_related_check (EMFormat *emf,
-			      CamelStream *stream,
-                              GCancellable *cancellable)
+gboolean
+em_format_html_get_show_sender_photo (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->show_sender_photo;
+}
+
+void
+em_format_html_set_show_sender_photo (EMFormatHTML *efh,
+                                      gboolean show_sender_photo)
+{
+	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->show_sender_photo = show_sender_photo;
 
-	link = g_queue_peek_head_link (emf->pending_uri_level->data);
+	g_object_notify (G_OBJECT (efh), "show-sender-photo");
+}
 
-	if (!link) {
-		g_string_printf (emf->part_id, "%s", oldpartid);
-		g_free (oldpartid);
-		return;
-	}
+gboolean
+em_format_html_get_show_real_date (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	while (link != NULL) {
-		EMFormatPURI *puri = link->data;
+	return efh->priv->show_real_date;
+}
 
-		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_real_date (EMFormatHTML *efh,
+                                   gboolean show_real_date)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-		link = g_list_next (link);
-	}
+	efh->priv->show_real_date =	show_real_date;
 
-	g_string_printf (emf->part_id, "%s", oldpartid);
-	g_free (oldpartid);
+	g_object_notify (G_OBJECT (efh), "show-real-date");
 }
 
-/* RFC 2387 */
-static void
-efh_multipart_related (EMFormat *emf,
-                       CamelStream *stream,
-                       CamelMimePart *part,
-                       const EMFormatHandler *info,
-                       GCancellable *cancellable,
-                       gboolean is_fallback)
+EMFormatHTMLHeadersState
+em_format_html_get_headers_state (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;
-	}
-
-	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;
-
-		/* strip <>'s */
-		len = strlen (start) - 2;
-		start++;
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
 
-		for (i = 0; i < nparts; i++) {
-			body_part = camel_multipart_get_part (mp, i);
-			cid = camel_mime_part_get_content_id (body_part);
+	return efh->priv->headers_state;
+}
 
-			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);
-	}
+void
+em_format_html_set_headers_state (EMFormatHTML *efh,
+				  EMFormatHTMLHeadersState state)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	if (display_part == NULL) {
-		em_format_part_as (
-			emf, stream, part,
-			"multipart/mixed", cancellable);
-		return;
-	}
+	efh->priv->headers_state = state;
 
-	em_format_push_level (emf);
+	g_object_notify (G_OBJECT (efh), "headers-state");
+}
 
-	partidlen = emf->part_id->len;
+gboolean
+em_format_html_get_headers_collapsable (EMFormatHTML *efh)
+{
+	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE);
 
-	/* 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)));
-		}
-	}
+	return efh->priv->headers_collapsable;
+}
 
-	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);
+void
+em_format_html_set_headers_collapsable (EMFormatHTML *efh,
+					gboolean collapsable)
+{
+	g_return_if_fail (EM_IS_FORMAT_HTML (efh));
 
-	emfh_multipart_related_check (emf, stream, cancellable);
+	efh->priv->headers_collapsable = collapsable;
 
-	em_format_pull_level (emf);
+	g_object_notify (G_OBJECT (efh), "headers-collapsable");
 }
 
-static void
-efh_write_image (EMFormat *emf,
-                 CamelStream *stream,
-                 EMFormatPURI *puri,
-                 GCancellable *cancellable)
+CamelMimePart *
+em_format_html_file_part (EMFormatHTML *efh,
+                          const gchar *mime_type,
+                          const gchar *filename,
+                          GCancellable *cancellable)
 {
-	CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) puri->part);
+	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;
 
-	d(printf("writing image '%s'\n", puri->cid));
-	camel_data_wrapper_decode_to_stream_sync (
+	dw = camel_data_wrapper_new ();
+	camel_data_wrapper_construct_from_stream_sync (
 		dw, stream, cancellable, NULL);
-	camel_stream_close (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;
 }
 
-static void
-efh_image (EMFormat *emf,
-           CamelStream *stream,
-           CamelMimePart *part,
-           const EMFormatHandler *info,
-           GCancellable *cancellable,
-           gboolean is_fallback)
+gchar *
+em_format_html_format_cert_infos (CamelCipherCertInfo *first_cinfo)
 {
-	EMFormatPURI *puri;
-	gchar *content;
-
-	puri = em_format_add_puri (
-		emf, sizeof (EMFormatPURI), NULL, part, efh_write_image);
+	GString *res = NULL;
+	CamelCipherCertInfo *cinfo;
 
-	content = g_strdup_printf (
-		"<img hspace=10 vspace=10 src=\"%s\">", puri->cid);
-	camel_stream_write_string (stream, content, cancellable, NULL);
-	g_free (content);
-}
+	if (!first_cinfo)
+		return NULL;
 
-/* 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 },
+	#define append(x) G_STMT_START {		\
+		if (!res) {				\
+			res = g_string_new (x);		\
+		} else {				\
+			g_string_append (res, x);	\
+		}					\
+	} G_STMT_END
 
-	/* 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. */
+	for (cinfo = first_cinfo; cinfo && cinfo->next; cinfo = cinfo->next) {
+		if (!cinfo->name && !cinfo->email)
+			continue;
 
-	{ (gchar *) "image/jpg", efh_image },
-	{ (gchar *) "image/pjpeg", efh_image },
+		if (res)
+			append (", ");
 
-	/* special internal types */
+		if (cinfo->name && *cinfo->name) {
+			append (cinfo->name);
 
-	{ (gchar *) "x-evolution/message/rfc822", efh_format_message }
-};
+			if (cinfo->email && *cinfo->email) {
+				append (" &lt;");
+				append (cinfo->email);
+				append ("&gt;");
+			}
+		} else if (cinfo->email && *cinfo->email) {
+			append (cinfo->email);
+		}
+	}
 
-static void
-efh_builtin_init (EMFormatHTMLClass *efhc)
-{
-	EMFormatClass *efc;
-	gint ii;
+	#undef append
 
-	efc = (EMFormatClass *) efhc;
+	if (!res)
+		return NULL;
 
-	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
-		em_format_class_add_handler (
-			efc, &type_builtin_table[ii]);
+	return g_string_free (res, FALSE);
 }
 
-/* ********************************************************************** */
+
+
 
 static void
 efh_format_text_header (EMFormatHTML *emfh,
@@ -2189,9 +1858,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;
 		}
@@ -2335,7 +2006,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 ("");
@@ -2388,6 +2060,7 @@ static void
 efh_format_full_headers (EMFormatHTML *efh,
 			 GString *buffer,
 			 CamelMedium *part,
+			 gboolean all_headers,
 			 gboolean visible,
 			 GCancellable *cancellable)
 {
@@ -2412,7 +2085,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);
 
@@ -2493,7 +2167,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 (
@@ -2577,7 +2251,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;
 
@@ -2587,56 +2261,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\">"
@@ -2653,31 +2327,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]));
@@ -2693,143 +2372,15 @@ 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;
-}
-
-gchar *
-em_format_html_format_cert_infos (CamelCipherCertInfo *first_cinfo)
-{
-	GString *res = NULL;
-	CamelCipherCertInfo *cinfo;
-
-	if (!first_cinfo)
-		return NULL;
-
-	#define append(x) G_STMT_START {		\
-		if (!res) {				\
-			res = g_string_new (x);		\
-		} else {				\
-			g_string_append (res, x);	\
-		}					\
-	} G_STMT_END
-
-	for (cinfo = first_cinfo; cinfo && cinfo->next; cinfo = cinfo->next) {
-		if (!cinfo->name && !cinfo->email)
-			continue;
-
-		if (res)
-			append (", ");
-
-		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);
-		}
-	}
-
-	#undef append
+	g_string_append (buffer, "</td></tr></table>" EFH_HTML_FOOTER);
 
-	if (!res)
-		return NULL;
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
 
-	return g_string_free (res, FALSE);
+	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 19ded94..fc3f794 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,
@@ -207,32 +174,6 @@ gboolean	em_format_html_get_show_sender_photo
 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);
-
 gboolean	em_format_html_get_show_real_date
 						(EMFormatHTML *efh);
 void		em_format_html_set_show_real_date
@@ -250,6 +191,12 @@ void		em_format_html_set_headers_collapsable
 						(EMFormatHTML *efh,
 						 gboolean collapsable);
 
+/* 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);
 
@@ -258,17 +205,23 @@ CamelStream *
 						 const gchar *image_uri);
 
 void		em_format_html_format_message (EMFormatHTML *efh,
-					       CamelStream *stream,
-					       GCancellable *cancellable);
+					      CamelStream *stream,
+					      GCancellable *cancellable);
 
 void		em_format_html_format_message_part (EMFormatHTML *efh,
-						    const gchar *part_id,
-    						    CamelStream *stream,
-						    GCancellable *cancellable);
+						  const gchar *part_id,
+    					  CamelStream *stream,
+						  GCancellable *cancellable);
 void		em_format_html_format_headers (EMFormatHTML *efh,
-					       CamelStream *stream,
-					       CamelMedium *part,
-					       GCancellable *cancellable);
+					      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]