[evolution/webkit] Use custom protocol handler to provide data for mail preview



commit f364d553d8d012e62f5cccf17ffb1ca03bbe153b
Author: Dan VrÃtil <dvratil redhat com>
Date:   Fri Aug 5 12:42:24 2011 +0200

    Use custom protocol handler to provide data for mail preview
    
    Use SoupRequest-based class to handle our own protocol mail://.
    To display a mail, or a mimepart, WebKit is given URL
    mail://account_url/folder_name/message_id?[part_id=PARTID&]formatter=FORMATTER
    (where FORMATTER is a pointer to EMFormat object to be used to format
    the given message/part. This way WebKit can request for any part of
    a mail and everything is completely asynchronous.

 data/webview.css                        |    5 -
 em-format/em-format.c                   |   97 ++--
 em-format/em-format.h                   |    9 +-
 mail/Makefile.am                        |    4 +
 mail/e-mail-browser.c                   |    2 +-
 mail/e-mail-display.c                   |  132 +++++-
 mail/e-mail-display.h                   |    4 +-
 mail/e-mail-paned-view.c                |    2 +-
 mail/e-mail-reader-utils.c              |    7 +-
 mail/e-mail-reader.c                    |   32 +-
 mail/e-mail-request.c                   |  235 +++++++++
 mail/e-mail-request.h                   |   38 ++
 mail/em-format-html.c                   |  799 +++----------------------------
 mail/em-format-html.h                   |   69 +---
 mail/em-utils.c                         |    4 +-
 plugins/itip-formatter/itip-formatter.c |   11 +-
 widgets/misc/e-web-view.c               |  174 +------
 widgets/misc/e-web-view.h               |    1 +
 18 files changed, 576 insertions(+), 1049 deletions(-)
---
diff --git a/data/webview.css b/data/webview.css
index 704c745..74578af 100644
--- a/data/webview.css
+++ b/data/webview.css
@@ -1,7 +1,3 @@
-body, td, th {
-  font-size: 0.8em;
-}
-
 h1, h2, h3 {
   color: #7f7f7f;
 }
@@ -19,7 +15,6 @@ th {
 
 .pre {
   font-family: monospace;
-  font-size: 0.8em;
 }
 
 span.navigable, div.navigable, p.navigable {
diff --git a/em-format/em-format.c b/em-format/em-format.c
index 1c2624f..0a10c73 100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@ -40,10 +40,6 @@
 
 typedef struct _EMFormatCache EMFormatCache;
 
-struct _EMFormatPrivate {
-	guint redraw_idle_id;
-};
-
 /* Used to cache various data/info for redraws
    The validity stuff could be cached at a higher level but this is easier
    This absolutely relies on the partid being _globally unique_
@@ -134,15 +130,15 @@ emf_finalize (GObject *object)
 {
 	EMFormat *emf = EM_FORMAT (object);
 
-	if (emf->priv->redraw_idle_id > 0)
-		g_source_remove (emf->priv->redraw_idle_id);
-
 	if (emf->session)
 		g_object_unref (emf->session);
 
 	if (emf->message)
 		g_object_unref (emf->message);
 
+	if (emf->folder)
+		g_object_unref (emf->folder);
+
 	g_hash_table_destroy (emf->inline_table);
 
 	em_format_clear_headers (emf);
@@ -187,12 +183,6 @@ emf_format_clone (EMFormat *emf,
                   EMFormat *emfsource,
                   GCancellable *cancellable)
 {
-	/* Cancel any pending redraws. */
-	if (emf->priv->redraw_idle_id > 0) {
-		g_source_remove (emf->priv->redraw_idle_id);
-		emf->priv->redraw_idle_id = 0;
-	}
-
 	em_format_clear_puri_tree (emf);
 
 	if (emf != emfsource) {
@@ -245,7 +235,6 @@ emf_format_clone (EMFormat *emf,
 	emf->current_message_part_id = g_strdup ("root-message");
 	g_string_truncate (emf->part_id, 0);
 	if (folder != NULL)
-		/* TODO build some string based on the folder name/location? */
 		g_string_append_printf(emf->part_id, ".%p", (gpointer) folder);
 	if (uid != NULL)
 		g_string_append_printf(emf->part_id, ".%s", uid);
@@ -330,7 +319,6 @@ emf_class_init (EMFormatClass *class)
 	GObjectClass *object_class;
 
 	parent_class = g_type_class_peek_parent (class);
-	g_type_class_add_private (class, sizeof (EMFormatPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->finalize = emf_finalize;
@@ -357,9 +345,6 @@ emf_init (EMFormat *emf)
 	EShell *shell;
 	EShellSettings *shell_settings;
 
-	emf->priv = G_TYPE_INSTANCE_GET_PRIVATE (
-		emf, EM_TYPE_FORMAT, EMFormatPrivate);
-
 	emf->inline_table = g_hash_table_new_full (
 		g_str_hash, g_str_equal,
 		(GDestroyNotify) NULL,
@@ -372,6 +357,10 @@ emf_init (EMFormat *emf)
 	emf->current_message_part_id = NULL;
 	emf->validity_found = 0;
 
+	emf->message = NULL;
+	emf->folder = NULL;
+	emf->uid = NULL;
+
 	shell = e_shell_get_default ();
 	shell_settings = e_shell_get_shell_settings (shell);
 
@@ -934,28 +923,6 @@ em_format_format (EMFormat *emf,
 	em_format_format_clone (emf, folder, uid, message, NULL, cancellable);
 }
 
-static gboolean
-format_redraw_idle_cb (EMFormat *emf)
-{
-	emf->priv->redraw_idle_id = 0;
-
-	/* FIXME Not passing a GCancellable here. */
-	em_format_format_clone (
-		emf, emf->folder, emf->uid, emf->message, emf, NULL);
-
-	return FALSE;
-}
-
-void
-em_format_queue_redraw (EMFormat *emf)
-{
-	g_return_if_fail (EM_IS_FORMAT (emf));
-
-	if (emf->priv->redraw_idle_id == 0)
-		emf->priv->redraw_idle_id = g_idle_add (
-			(GSourceFunc) format_redraw_idle_cb, emf);
-}
-
 /**
  * em_format_set_mode:
  * @emf:
@@ -974,10 +941,6 @@ em_format_set_mode (EMFormat *emf,
 		return;
 
 	emf->mode = mode;
-
-	/* force redraw if type changed afterwards */
-	if (emf->message != NULL)
-		em_format_queue_redraw (emf);
 }
 
 /**
@@ -999,9 +962,6 @@ em_format_set_charset (EMFormat *emf,
 
 	g_free (emf->charset);
 	emf->charset = g_strdup (charset);
-
-	if (emf->message)
-		em_format_queue_redraw (emf);
 }
 
 /**
@@ -1025,9 +985,6 @@ em_format_set_default_charset (EMFormat *emf,
 
 	g_free (emf->default_charset);
 	emf->default_charset = g_strdup (charset);
-
-	if (emf->message && emf->charset == NULL)
-		em_format_queue_redraw (emf);
 }
 
 /**
@@ -1212,9 +1169,6 @@ em_format_set_inline (EMFormat *emf,
 		return;
 
 	emfc->state = state?INLINE_ON:INLINE_OFF;
-
-	if (emf->message)
-		em_format_queue_redraw (emf);
 }
 
 void
@@ -1627,7 +1581,7 @@ emf_multipart_appledouble (EMFormat *emf,
 
 }
 
-/* RFC ??? */
+/* RFC 2046 */
 static void
 emf_multipart_mixed (EMFormat *emf,
                      CamelStream *stream,
@@ -1646,6 +1600,9 @@ emf_multipart_mixed (EMFormat *emf,
 		return;
 	}
 
+	em_format_push_level (emf);
+
+
 	len = emf->part_id->len;
 	nparts = camel_multipart_get_number (mp);
 	for (i = 0; i < nparts; i++) {
@@ -1678,6 +1635,8 @@ emf_multipart_alternative (EMFormat *emf,
 		return;
 	}
 
+	em_format_push_level (emf);
+
 	/* as per rfc, find the last part we know how to display */
 	nparts = camel_multipart_get_number (mp);
 	for (i = 0; i < nparts; i++) {
@@ -2480,3 +2439,33 @@ em_format_snoop_type (CamelMimePart *part)
 	/* We used to load parts to check their type, we dont anymore,
 	   see bug #11778 for some discussion */
 }
+
+gchar*
+em_format_build_mail_uri (CamelFolder *folder,
+			  const gchar *message_uid,
+			  const gchar *part_uid,
+			  EMFormat *emf)
+{
+	CamelStore *store;
+
+	g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+	g_return_val_if_fail (message_uid && *message_uid, NULL);
+	g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+
+	store = camel_folder_get_parent_store (folder);
+
+	if (part_uid) {
+		return g_strdup_printf ("mail://%s/%s/%s?part_id=%s&formatter=%d",
+			camel_service_get_uid (CAMEL_SERVICE (store)),
+			camel_folder_get_full_name (folder),
+			message_uid,
+			part_uid,
+			GPOINTER_TO_INT (emf));
+	}
+
+	return g_strdup_printf ("mail://%s/%s/%s?formatter=%d",
+		camel_service_get_uid (CAMEL_SERVICE (store)),
+		camel_folder_get_full_name (folder),
+		message_uid,
+		GPOINTER_TO_INT (emf));
+}
diff --git a/em-format/em-format.h b/em-format/em-format.h
index d78cfee..cd51369 100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@ -53,7 +53,6 @@ G_BEGIN_DECLS
 
 typedef struct _EMFormat EMFormat;
 typedef struct _EMFormatClass EMFormatClass;
-typedef struct _EMFormatPrivate EMFormatPrivate;
 
 typedef struct _EMFormatHandler EMFormatHandler;
 typedef struct _EMFormatHeader EMFormatHeader;
@@ -187,7 +186,6 @@ struct _EMFormatHeader {
  **/
 struct _EMFormat {
 	GObject parent;
-	EMFormatPrivate *priv;
 
 	/* The current message */
 	CamelMimeMessage *message;
@@ -336,6 +334,7 @@ void		em_format_set_inline		(EMFormat *emf,
 gchar *		em_format_describe_part		(CamelMimePart *part,
 						 const gchar *mime_type);
 
+
 /* for implementers */
 GType		em_format_get_type		(void);
 
@@ -378,7 +377,6 @@ void		em_format_format		(EMFormat *emf,
 						 const gchar *uid,
 						 CamelMimeMessage *message,
 						 GCancellable *cancellable);
-void		em_format_queue_redraw		(EMFormat *emf);
 void		em_format_format_attachment	(EMFormat *emf,
 						 CamelStream *stream,
 						 CamelMimePart *mime_part,
@@ -427,6 +425,11 @@ void		em_format_merge_handler		(EMFormat *new,
 
 const gchar *	em_format_snoop_type		(CamelMimePart *part);
 
+gchar *		em_format_build_mail_uri	(CamelFolder *folder,
+						 const gchar *message_uid,
+						 const gchar *part_uid,
+						 EMFormat *emf);
+
 G_END_DECLS
 
 #endif /* EM_FORMAT_H */
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 5fec4da..0c42883 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -29,6 +29,7 @@ libevolution_mail_la_CPPFLAGS =				\
 	$(CERT_UI_CFLAGS)				\
 	$(CANBERRA_CFLAGS)				\
 	$(CLUTTER_CFLAGS)				\
+	$(LIBSOUP_CFLAGS)				\
 	-DEVOLUTION_DATADIR=\""$(datadir)"\"		\
 	-DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\"	\
 	-DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\"	\
@@ -65,6 +66,7 @@ mailinclude_HEADERS =					\
 	e-mail-migrate.h				\
 	e-mail-reader.h					\
 	e-mail-reader-utils.h				\
+	e-mail-request.h				\
 	e-mail-session.h				\
 	e-mail-session-utils.h				\
 	e-mail-sidebar.h				\
@@ -136,6 +138,7 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-migrate.c				\
 	e-mail-reader.c					\
 	e-mail-reader-utils.c				\
+	e-mail-request.c				\
 	e-mail-session.c				\
 	e-mail-session-utils.c				\
 	e-mail-sidebar.c				\
@@ -211,6 +214,7 @@ libevolution_mail_la_LIBADD =				\
 	$(GTKHTML_LIBS)					\
 	$(E_WIDGETS_LIBS)				\
 	$(SMIME_LIBS)					\
+	$(LIBSOUP_LIBS)					\
 	$(GNOME_PLATFORM_LIBS)
 
 libevolution_mail_la_LDFLAGS = $(NO_UNDEFINED)
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index db5150b..e4799bf 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -704,7 +704,7 @@ mail_browser_constructed (GObject *object)
 
 	g_signal_connect_swapped (
 		search_bar, "changed",
-		G_CALLBACK (em_format_queue_redraw), priv->formatter);
+		G_CALLBACK (e_web_view_reload), web_view);
 
 	/* Bind GObject properties to GConf keys. */
 
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 7ccc78d..f0b3980 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
 #include "e-mail-display.h"
 
 #include <glib/gi18n.h>
@@ -31,6 +33,10 @@
 #include "e-util/e-plugin-ui.h"
 #include "mail/em-composer-utils.h"
 #include "mail/em-utils.h"
+#include "mail/e-mail-request.h"
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-requester.h>
 
 struct _EMailDisplayPrivate {
 	EMFormatHTML *formatter;
@@ -86,7 +92,7 @@ static GtkActionEntry mailto_entries[] = {
 	  NULL,
 	  N_("Send _Reply To..."),
 	  NULL,
-	  N_("Send a reply message to this address"),  
+	  N_("Send a reply message to this address"),
 	  NULL   /* Handled by EMailReader */ },
 
 	/*** Menus ***/
@@ -203,24 +209,12 @@ static void
 mail_display_style_set (GtkWidget *widget,
                         GtkStyle *previous_style)
 {
-	EMailDisplayPrivate *priv;
-
-	priv = E_MAIL_DISPLAY (widget)->priv;
-
 	/* Chain up to parent's style_set() method. */
 	GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
 
 	mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
-	em_format_queue_redraw (EM_FORMAT (priv->formatter));
-}
 
-static void
-mail_display_url_requested (GtkHTML *html,
-                            const gchar *uri,
-                            GtkHTMLStream *stream)
-{
-	/* XXX Sadly, we must block the default method
-	 *     until EMFormatHTML is made asynchronous. */
+	e_web_view_reload (E_WEB_VIEW (widget));
 }
 
 static gboolean
@@ -291,6 +285,93 @@ mail_display_link_clicked (WebKitWebView *web_view,
 }
 
 static void
+mail_display_resource_requested (WebKitWebView *web_view,
+				 WebKitWebFrame *frame,
+				 WebKitWebResource *resource,
+                        	 WebKitNetworkRequest *request,
+                        	 WebKitNetworkResponse *response,
+                        	 gpointer user_data)
+{
+	EMFormatHTML *formatter = E_MAIL_DISPLAY (web_view)->priv->formatter;
+	const gchar *uri = webkit_network_request_get_uri (request);
+
+        /* Redirect cid:part_id to mail://mail_id/cid:part_id */
+        if (g_str_has_prefix (uri, "cid:")) {
+		gchar *new_uri = em_format_build_mail_uri (EM_FORMAT (formatter)->folder,
+			EM_FORMAT (formatter)->uid, uri, EM_FORMAT (formatter));
+
+                webkit_network_request_set_uri (request, new_uri);
+
+                g_free (new_uri);
+
+        /* WebKit won't allow to load a local file when displaing "remote" mail://,
+           protocol, so we need to handle this manually */
+        } else if (g_str_has_prefix (uri, "file:")) {
+                gchar *data = NULL;
+                gsize length = 0;
+                gboolean status;
+                gchar *path;
+
+                path = g_filename_from_uri (uri, NULL, NULL);
+                if (!path)
+                        return;
+
+		status = g_file_get_contents (path, &data, &length, NULL);
+                if (status) {
+                        gchar *b64, *new_uri;
+                        gchar *ct;
+
+                        b64 = g_base64_encode ((guchar*) data, length);
+                        ct = g_content_type_guess (path, NULL, 0, NULL);
+
+                        new_uri =  g_strdup_printf ("data:%s;base64,%s", ct, b64);
+                        webkit_network_request_set_uri (request, new_uri);
+
+                        g_free (b64);
+                        g_free (new_uri);
+                        g_free (ct);
+                }
+                g_free (data);
+                g_free (path);
+        }
+
+       	g_signal_stop_emission_by_name (web_view, "resource-request-starting");
+}
+
+static void
+mail_display_headers_collapsed_state_changed (EWebView *web_view,
+					      size_t arg_count,
+					      const JSValueRef args[],
+					      gpointer user_data)
+{
+	EMFormatHTML *formatter = E_MAIL_DISPLAY (web_view)->priv->formatter;
+	JSGlobalContextRef ctx = e_web_view_get_global_context (web_view);
+
+	gboolean collapsed = JSValueToBoolean (ctx, args[0]);
+
+	if (collapsed) {
+		em_format_html_set_headers_state (formatter, EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED);
+	} else {
+		em_format_html_set_headers_state (formatter, EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
+	}
+}
+
+static void
+mail_display_install_js_callbacks (WebKitWebView *web_view,
+				   WebKitWebFrame *frame,
+				   gpointer context,
+				   gpointer window_object,
+				   gpointer user_data)
+{
+	if (frame != webkit_web_view_get_main_frame (web_view))
+		return;
+
+	e_web_view_install_js_callback (E_WEB_VIEW (web_view), "headers_collapsed",
+		(EWebViewJSFunctionCallback) mail_display_headers_collapsed_state_changed, user_data);
+}
+
+
+static void
 mail_display_class_init (EMailDisplayClass *class)
 {
 	GObjectClass *object_class;
@@ -326,18 +407,25 @@ mail_display_class_init (EMailDisplayClass *class)
 static void
 mail_display_init (EMailDisplay *display)
 {
-	EWebView *web_view;
 	GtkUIManager *ui_manager;
 	GtkActionGroup *action_group;
 	GError *error = NULL;
+	EWebView *web_view;
+	SoupSession *session;
+	SoupSessionFeature *feature;
 
 	web_view = E_WEB_VIEW (display);
-	g_signal_connect (web_view, "navigation-policy-decision-requested",
-		G_CALLBACK (mail_display_link_clicked), display);
 
 	display->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		display, E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate);
 
+	g_signal_connect (web_view, "navigation-policy-decision-requested",
+		G_CALLBACK (mail_display_link_clicked), display);
+	g_signal_connect (web_view, "resource-request-starting",
+		G_CALLBACK (mail_display_resource_requested), display);
+	g_signal_connect (web_view, "window-object-cleared",
+		G_CALLBACK (mail_display_install_js_callbacks), display);
+
 	/* EWebView's action groups are added during its instance
 	 * initialization function (like what we're in now), so it
 	 * is safe to fetch them this early in construction. */
@@ -356,6 +444,14 @@ mail_display_init (EMailDisplay *display)
 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
 	if (error != NULL)
 		g_error ("%s", error->message);
+
+
+	/* Register our own handler for mail:// protocol */
+	session = webkit_get_default_session ();
+	feature = SOUP_SESSION_FEATURE (soup_requester_new ());
+	soup_session_feature_add_feature (feature, E_TYPE_MAIL_REQUEST);
+	soup_session_add_feature (session, feature);
+	g_object_unref (feature);
 }
 
 GType
@@ -404,5 +500,7 @@ e_mail_display_set_formatter (EMailDisplay *display,
 
 	display->priv->formatter = g_object_ref (formatter);
 
+	mail_display_update_formatter_colors (display);
+
 	g_object_notify (G_OBJECT (display), "formatter");
 }
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 1b71a9d..fb3f29d 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -22,8 +22,8 @@
 #ifndef E_MAIL_DISPLAY_H
 #define E_MAIL_DISPLAY_H
 
-#include <mail/em-format-html.h>
-#include <misc/e-web-view.h>
+#include <widgets/misc/e-web-view.h>
+#include "em-format-html.h"
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_DISPLAY \
diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c
index 7c0ee88..32c7996 100644
--- a/mail/e-mail-paned-view.c
+++ b/mail/e-mail-paned-view.c
@@ -687,7 +687,7 @@ mail_paned_view_constructed (GObject *object)
 
 	g_signal_connect_swapped (
 		search_bar, "changed",
-		G_CALLBACK (em_format_queue_redraw), priv->formatter);
+		G_CALLBACK (e_web_view_reload), web_view);
 
 	/* Load the view instance. */
 
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index fe4e406..0e14e64 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1338,6 +1338,7 @@ headers_changed_cb (GConfClient *client,
                     EMailReader *reader)
 {
 	EMFormatHTML *formatter;
+	EWebView *web_view;
 	GSList *header_config_list, *p;
 
 	g_return_if_fail (client != NULL);
@@ -1369,8 +1370,10 @@ headers_changed_cb (GConfClient *client,
 	g_slist_free (header_config_list);
 
 	/* force a redraw */
-	if (EM_FORMAT (formatter)->message)
-		em_format_queue_redraw (EM_FORMAT (formatter));
+	if (EM_FORMAT (formatter)->message) {
+		web_view = em_format_html_get_web_view (formatter);
+		e_web_view_reload (web_view);
+	}
 }
 
 static void
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index c14cf8e..d185e1f 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -429,18 +429,20 @@ action_mail_flag_clear_cb (GtkAction *action,
                            EMailReader *reader)
 {
 	EMFormatHTML *formatter;
+	EWebView *web_view;
 	CamelFolder *folder;
 	GtkWindow *window;
 	GPtrArray *uids;
 
 	folder = e_mail_reader_get_folder (reader);
 	formatter = e_mail_reader_get_formatter (reader);
+	web_view = em_format_html_get_web_view (formatter);
 	uids = e_mail_reader_get_selected_uids (reader);
 	window = e_mail_reader_get_window (reader);
 
 	em_utils_flag_for_followup_clear (window, folder, uids);
 
-	em_format_queue_redraw (EM_FORMAT (formatter));
+	e_web_view_reload (web_view);
 }
 
 static void
@@ -448,18 +450,20 @@ action_mail_flag_completed_cb (GtkAction *action,
                                EMailReader *reader)
 {
 	EMFormatHTML *formatter;
+	EWebView *web_view;
 	CamelFolder *folder;
 	GtkWindow *window;
 	GPtrArray *uids;
 
 	folder = e_mail_reader_get_folder (reader);
 	formatter = e_mail_reader_get_formatter (reader);
+	web_view = em_format_html_get_web_view (formatter);
 	uids = e_mail_reader_get_selected_uids (reader);
 	window = e_mail_reader_get_window (reader);
 
 	em_utils_flag_for_followup_completed (window, folder, uids);
 
-	em_format_queue_redraw (EM_FORMAT (formatter));
+	e_web_view_reload (web_view);
 }
 
 static void
@@ -2498,6 +2502,7 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
 	EMEvent *event;
 	EMEventTargetMessage *target;
 	const gchar *message_uid;
+	gchar *mail_uri;
 	gboolean schedule_timeout;
 	gint timeout_interval;
 	GError *error = NULL;
@@ -2526,6 +2531,7 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
 
 	backend = e_mail_reader_get_backend (reader);
 	formatter = e_mail_reader_get_formatter (reader);
+	web_view = em_format_html_get_web_view (formatter);
 	message_list = e_mail_reader_get_message_list (reader);
 
 	if (!message_list) {
@@ -2553,10 +2559,14 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
 		(EEvent *) event, "message.reading",
 		(EEventTarget *) target);
 
-	/* FIXME Need to pass a GCancellable. */
-	em_format_format (
-		EM_FORMAT (formatter), folder,
-		message_uid, message, NULL);
+
+	/* Initialize formatter */
+	em_format_format_clone (EM_FORMAT (formatter), folder, message_uid, message, NULL, NULL);
+
+	/* Start formatting */
+	mail_uri = em_format_build_mail_uri (folder, message_uid, NULL, EM_FORMAT (formatter));
+	e_web_view_load_uri (web_view, mail_uri);
+	g_free (mail_uri);
 
 	/* Reset the shell view icon. */
 	e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
@@ -2683,9 +2693,8 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
 			priv->retrieving_message = g_object_ref (cancellable);
 		}
 	} else {
-		/* FIXME Need to pass a GCancellable. */
-		em_format_format (
-			EM_FORMAT (formatter), NULL, NULL, NULL, NULL);
+		e_web_view_load_string (web_view, "");
+
 		priv->restoring_message_selection = FALSE;
 	}
 
@@ -2776,6 +2785,7 @@ mail_reader_set_folder (EMailReader *reader,
 {
 	EMailReaderPrivate *priv;
 	EMFormatHTML *formatter;
+	EWebView *web_view;
 	CamelFolder *previous_folder;
 	GtkWidget *message_list;
 	EMailBackend *backend;
@@ -2786,6 +2796,7 @@ mail_reader_set_folder (EMailReader *reader,
 
 	backend = e_mail_reader_get_backend (reader);
 	formatter = e_mail_reader_get_formatter (reader);
+	web_view = em_format_html_get_web_view (formatter);
 	message_list = e_mail_reader_get_message_list (reader);
 
 	previous_folder = e_mail_reader_get_folder (reader);
@@ -2805,8 +2816,7 @@ mail_reader_set_folder (EMailReader *reader,
 		em_utils_folder_is_outbox (folder) ||
 		em_utils_folder_is_sent (folder));
 
-	/* FIXME Need to pass a GCancellable. */
-	em_format_format (EM_FORMAT (formatter), NULL, NULL, NULL, NULL);
+	e_web_view_load_string (web_view, "");
 
 	priv->folder_was_just_selected = (folder != NULL);
 
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
new file mode 100644
index 0000000..eb7c694
--- /dev/null
+++ b/mail/e-mail-request.c
@@ -0,0 +1,235 @@
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
+#include "e-mail-request.h"
+#include <libsoup/soup.h>
+#include <glib/gi18n.h>
+#include <camel/camel.h>
+
+#include "em-format-html.h"
+
+
+G_DEFINE_TYPE (EMailRequest, e_mail_request, SOUP_TYPE_REQUEST)
+
+struct _EMailRequestPrivate {
+	EMFormatHTML *efh;
+	CamelMimePart *part;
+
+	CamelStream *output_stream;
+
+	gchar *content_type;
+
+	GHashTable *uri_query;
+};
+
+
+static void
+start_mail_formatting (GSimpleAsyncResult *res,
+		       GObject *object,
+		       GCancellable *cancellable)
+{
+	EMailRequest *request = E_MAIL_REQUEST (object);
+	EMFormatHTML *efh = request->priv->efh;
+	EMFormat *emf = EM_FORMAT (efh);
+	GInputStream *stream;
+	GByteArray *ba;
+	gchar *part_id;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	if (request->priv->output_stream != NULL)
+		g_object_unref (request->priv->output_stream);
+
+	request->priv->output_stream = camel_stream_mem_new ();
+
+	part_id = g_hash_table_lookup (request->priv->uri_query, "part_id");
+
+	if (part_id) {
+		CamelContentType *ct;
+		EMFormatPURI *puri;
+
+		puri = em_format_find_puri (emf, part_id);
+		if (puri) {
+			request->priv->part = puri->part;
+			ct = camel_mime_part_get_content_type (request->priv->part);
+			if (ct) {
+				request->priv->content_type = camel_content_type_format (ct);
+			camel_content_type_unref (ct);
+			} else {
+				request->priv->content_type = g_strdup ("text/html");
+			}
+			em_format_html_format_message_part (efh, part_id, request->priv->output_stream, cancellable);
+		}
+	} else {
+		request->priv->content_type = g_strdup ("text/html");
+		request->priv->part = g_object_ref (CAMEL_MIME_PART (emf->message));
+		em_format_html_format_message (efh, request->priv->output_stream, cancellable);
+	}
+
+	/* Convert the GString to GInputStream and send it back to WebKit */
+	ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (request->priv->output_stream));
+
+	if (!ba->data) {
+		gchar *data = g_strdup_printf(_("Failed to load part '%s'"), part_id);
+		g_byte_array_append (ba, (guchar*) data, strlen (data));
+		g_free (data);
+	}
+
+	stream = g_memory_input_stream_new_from_data ((gchar*) ba->data, ba->len, NULL);
+	g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+}
+
+static void
+get_image_content (GSimpleAsyncResult *res,
+	       	   GObject *object,
+		   GCancellable *cancellable)
+{
+	EMailRequest *request = E_MAIL_REQUEST (object);
+	SoupURI *uri;
+	GInputStream *stream;
+	gchar *contents;
+	gsize length;
+
+	if (g_cancellable_is_cancelled (cancellable))
+		return;
+
+	uri = soup_request_get_uri (SOUP_REQUEST (request));
+
+	if (g_file_get_contents (uri->path, &contents, &length, NULL)) {
+		request->priv->content_type = g_content_type_guess (uri->path, NULL, 0, NULL);
+		stream = g_memory_input_stream_new_from_data (contents, length, NULL);
+		g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+	}
+}
+
+static void
+e_mail_request_init (EMailRequest *request)
+{
+	request->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+		request, E_TYPE_MAIL_REQUEST, EMailRequestPrivate);
+
+	request->priv->efh = NULL;
+	request->priv->part = NULL;
+	request->priv->output_stream = NULL;
+	request->priv->uri_query = NULL;
+}
+
+static void
+mail_request_finalize (GObject *object)
+{
+	EMailRequest *request = E_MAIL_REQUEST (object);
+
+	if (request->priv->output_stream) {
+		g_object_unref (request->priv->output_stream);
+		request->priv->output_stream = NULL;
+	}
+
+	if (request->priv->content_type) {
+		g_free (request->priv->content_type);
+		request->priv->content_type = NULL;
+	}
+
+	if (request->priv->uri_query) {
+		g_hash_table_destroy (request->priv->uri_query);
+		request->priv->uri_query = NULL;
+	}
+
+	G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
+}
+
+static gboolean
+mail_request_check_uri(SoupRequest *request,
+		       SoupURI *uri,
+		       GError **error)
+{
+	return ((strcmp (uri->scheme, "mail") == 0) ||
+		(strcmp (uri->scheme, "evo-file") == 0));
+}
+
+static void
+mail_request_send_async (SoupRequest *request,
+			 GCancellable *cancellable,
+			 GAsyncReadyCallback callback,
+			 gpointer	user_data)
+{
+	EMailRequest *emr = E_MAIL_REQUEST (request);
+	GSimpleAsyncResult *result;
+	SoupURI *uri;
+
+	uri = soup_request_get_uri (request);
+
+	if (g_strcmp0 (uri->scheme, "mail") == 0) {
+		gchar *formatter;
+		emr->priv->uri_query = soup_form_decode (uri->query);
+
+		formatter = g_hash_table_lookup (emr->priv->uri_query, "formatter");
+
+		emr->priv->efh = GINT_TO_POINTER (atoi (formatter));
+		g_return_if_fail (EM_IS_FORMAT (emr->priv->efh));
+
+		result = g_simple_async_result_new (G_OBJECT (request), callback, user_data, mail_request_send_async);
+		g_simple_async_result_run_in_thread (result, start_mail_formatting, G_PRIORITY_DEFAULT, cancellable);
+	} else if (g_strcmp0 (uri->scheme, "evo-file") == 0) {
+		/* WebKit won't allow us to load data through local file:// protocol, when using "remote" mail://
+		   protocol. evo-file:// behaves as file:// */
+		result = g_simple_async_result_new (G_OBJECT (request), callback, user_data, mail_request_send_async);
+		g_simple_async_result_run_in_thread (result, get_image_content, G_PRIORITY_DEFAULT, cancellable);
+	}
+}
+
+static GInputStream*
+mail_request_send_finish (SoupRequest *request,
+			  GAsyncResult *result,
+			  GError **error)
+{
+	GInputStream *stream;
+
+	stream = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	g_object_unref (result);
+
+	return stream;
+}
+
+static goffset
+mail_request_get_content_length (SoupRequest *request)
+{
+	EMailRequest *emr = E_MAIL_REQUEST (request);
+	GByteArray *ba;
+
+	if (emr->priv->output_stream) {
+		ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (emr->priv->output_stream));
+		if (ba) {
+			return ba->len;
+		}
+	}
+
+	return 0;
+}
+
+static const gchar*
+mail_request_get_content_type (SoupRequest *request)
+{
+	EMailRequest *emr = E_MAIL_REQUEST (request);
+
+	return emr->priv->content_type;
+}
+
+static const char *data_schemes[] = { "mail", "evo-file", NULL };
+
+static void
+e_mail_request_class_init (EMailRequestClass *class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	SoupRequestClass *request_class = SOUP_REQUEST_CLASS (class);
+
+	g_type_class_add_private (class, sizeof (EMailRequestPrivate));
+
+	object_class->finalize = mail_request_finalize;
+
+	request_class->schemes = data_schemes;
+	request_class->send_async = mail_request_send_async;
+	request_class->send_finish = mail_request_send_finish;
+	request_class->get_content_type = mail_request_get_content_type;
+	request_class->get_content_length = mail_request_get_content_length;
+	request_class->check_uri = mail_request_check_uri;
+}
diff --git a/mail/e-mail-request.h b/mail/e-mail-request.h
new file mode 100644
index 0000000..8d2b298
--- /dev/null
+++ b/mail/e-mail-request.h
@@ -0,0 +1,38 @@
+#ifndef E_MAIL_REQUEST_H
+#define E_MAIL_REQUEST_H
+
+#ifdef LIBSOUP_USE_UNSTABLE_REQUEST_API
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-request.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_MAIL_REQUEST            (e_mail_request_get_type ())
+#define E_MAIL_REQUEST(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), E_TYPE_MAIL_REQUEST, EMailRequest))
+#define E_MAIL_REQUEST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_MAIL_REQUEST, EMailRequestClass))
+#define E_IS_MAIL_REQUEST(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), E_TYPE_MAIL_REQUEST))
+#define E_IS_MAIL_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_MAIL_REQUEST))
+#define E_MAIL_REQUEST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_MAIL_REQUEST, EMailRequestClass))
+
+typedef struct _EMailRequest EMailRequest;
+typedef struct _EMailRequestClass EMailRequestClass;
+typedef struct _EMailRequestPrivate EMailRequestPrivate;
+
+struct _EMailRequest {
+	SoupRequest parent;
+
+	EMailRequestPrivate *priv;
+};
+
+struct _EMailRequestClass {
+	SoupRequestClass parent;
+};
+
+GType e_mail_request_get_type (void);
+
+G_END_DECLS
+
+#endif /* LIBSOUP_USE_UNSTABLE_REQUEST_API */
+
+#endif /* E_MAIL_REQUEST_H */
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index af5b960..33343c2 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -74,17 +74,9 @@ struct _EMFormatHTMLCache {
 struct _EMFormatHTMLPrivate {
 	EWebView *web_view;
 
-	CamelMimeMessage *last_part;	/* not reffed, DO NOT dereference */
-	volatile gint format_id;		/* format thread id */
-	guint format_timeout_id;
-	struct _format_msg *format_timeout_msg;
-
 	/* Table that re-maps text parts into a mutlipart/mixed, EMFormatHTMLCache * */
 	GHashTable *text_inline_parts;
 
-	GQueue pending_jobs;
-	GMutex *lock;
-
 	GdkColor colors[EM_FORMAT_HTML_NUM_COLOR_TYPES];
 	EMailImageLoadingPolicy image_loading_policy;
 
@@ -116,30 +108,6 @@ enum {
 };
 
 
-static void	emfh_format_email		(struct _EMFormatHTMLJob *job,
-	       	   				 GCancellable *cancellable);
-
-static gboolean	efh_display_formatted_data	(gpointer data);
-
-static GtkWidget* efh_create_plugin_widget	(WebKitWebView *web_view,
-						 gchar *mime_type,
-						 gchar *uri,
-						 GHashTable *param,
-						 gpointer user_data);
-static void	efh_webview_frame_created	(WebKitWebView *web_view,
-						 WebKitWebFrame *frame,
-						 gpointer user_data);
-static void	efh_resource_requested		(WebKitWebView *web_view,
-						 WebKitWebFrame *frame,
-						 WebKitWebResource *resource,
-						 WebKitNetworkRequest *request,
-						 WebKitNetworkResponse *reponse,
-						 gpointer user_data);
-static void	efh_install_js_callbacks	(WebKitWebView *web_view,
-						 WebKitWebFrame *frame,
-						 gpointer context,
-						 gpointer window_object,
-						 gpointer user_data);
 static void	efh_format_message		(EMFormat *emf,
 						 CamelStream *stream,
 						 CamelMimePart *part,
@@ -165,218 +133,6 @@ static CamelDataCache *emfh_http_cache;
 
 #define EMFH_HTTP_CACHE_PATH "http"
 
-/* Sigh, this is so we have a cancellable, async rendering thread */
-struct _format_msg {
-	MailMsg base;
-
-	EMFormatHTML *format;
-	EMFormat *format_source;
-	CamelFolder *folder;
-	gchar *uid;
-	CamelMimeMessage *message;
-};
-
-static gchar *
-efh_format_desc (struct _format_msg *m)
-{
-	return g_strdup(_("Formatting message"));
-}
-
-static void
-efh_format_exec (struct _format_msg *m,
-                 GCancellable *cancellable,
-                 GError **error)
-{
-	EMFormat *format;
-	struct _EMFormatHTMLJob *job;
-	GNode *puri_level;
-	CamelURL *base;
-
-	if (m->format->priv->web_view == NULL)
-		return;
-
-	format = EM_FORMAT (m->format);
-
-	puri_level = format->pending_uri_level;
-	base = format->base;
-
-	do {
-		d(printf("processing job\n"));
-
-		g_mutex_lock (m->format->priv->lock);
-		while ((job = g_queue_pop_head (&m->format->priv->pending_jobs))) {
-
-			g_mutex_unlock (m->format->priv->lock);
-
-			/* This is an implicit check to see if the webview has been destroyed */
-			if (m->format->priv->web_view == NULL)
-				g_cancellable_cancel (cancellable);
-
-			/* call jobs even if cancelled, so they can clean up resources */
-			format->pending_uri_level = job->puri_level;
-			if (job->base)
-				format->base = job->base;
-			/* Call the job's callback, usually a parser */
-			job->callback (job, cancellable);
-			format->base = base;
-
-			/* Display stream created by the callback and free
-			   the job struct */
-			g_idle_add(efh_display_formatted_data, job);
-
-			g_mutex_lock (m->format->priv->lock);
-		}
-		g_mutex_unlock (m->format->priv->lock);
-
-	} while (!g_queue_is_empty (&m->format->priv->pending_jobs));
-
-	d(printf("out of jobs, done\n"));
-
-	format->pending_uri_level = puri_level;
-
-	m->format->priv->format_id = -1;
-}
-
-static void
-efh_format_done (struct _format_msg *m)
-{
-	d(printf("formatting finished\n"));
-
-	m->format->priv->format_id = -1;
-	m->format->priv->load_images_now = FALSE;
-	m->format->state = EM_FORMAT_HTML_STATE_NONE;
-	g_signal_emit_by_name(m->format, "complete");
-}
-
-static void
-efh_format_free (struct _format_msg *m)
-{
-	d(printf("formatter freed\n"));
-	g_object_unref (m->format);
-	if (m->folder)
-		g_object_unref (m->folder);
-	g_free (m->uid);
-	if (m->message)
-		g_object_unref (m->message);
-	if (m->format_source)
-		g_object_unref (m->format_source);
-}
-
-static MailMsgInfo efh_format_info = {
-	sizeof (struct _format_msg),
-	(MailMsgDescFunc) efh_format_desc,
-	(MailMsgExecFunc) efh_format_exec,
-	(MailMsgDoneFunc) efh_format_done,
-	(MailMsgFreeFunc) efh_format_free
-};
-
-static gboolean
-efh_display_formatted_data (gpointer data)
-{
-	/* This is an idle callback */
-
-	struct _EMFormatHTMLJob *job = data;
-	EWebView *web_view = job->format->priv->web_view;
-	GByteArray *ba;
-	gchar *content;
-
-	if (web_view == NULL)
-		goto cleanup;
-
-	d(printf("displaying messsage\n"));
-
-	ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (job->stream));
-
-	content = g_strndup ((gchar*) ba->data, ba->len);
-	e_web_view_load_string (web_view, content);
-
-	g_free (content);
-
-cleanup:
-	/* Clean up the job */
-	g_object_unref (job->stream);
-	if (job->base)
-		camel_url_free (job->base);
-	g_free (job);
-
-	return FALSE;
-}
-
-static gboolean
-efh_format_timeout (struct _format_msg *m)
-{
-	EMFormatHTML *efh = m->format;
-	EMFormat *emf = EM_FORMAT (efh);
-	struct _EMFormatHTMLPrivate *p = efh->priv;
-	EWebView *web_view;
-
-	web_view = em_format_html_get_web_view (efh);
-
-	if (web_view == NULL) {
-		mail_msg_unref (m);
-		return FALSE;
-	}
-
-	d(printf("timeout called ...\n"));
-	if (p->format_id != -1) {
-		d(printf(" still waiting for cancellation to take effect, waiting ...\n"));
-		return TRUE;
-	}
-
-	g_return_val_if_fail (g_queue_is_empty (&p->pending_jobs), FALSE);
-
-	/* call super-class to kick it off */
-	/* FIXME Not passing a GCancellable here. */
-	EM_FORMAT_CLASS (parent_class)->format_clone (
-		emf, m->folder, m->uid,
-		m->message, m->format_source, NULL);
-	em_format_html_clear_pobject (efh);
-
-	/* FIXME: method off EMFormat? */
-	if (emf->valid) {
-		camel_cipher_validity_free (emf->valid);
-		emf->valid = NULL;
-		emf->valid_parent = NULL;
-	}
-
-	if (m->message == NULL) {
-		mail_msg_unref (m);
-		p->last_part = NULL;
-	} else {
-		struct _EMFormatHTMLJob *job;
-
-		/* Queue a job for parsing the email main content */
-		job = em_format_html_job_new (efh, emfh_format_email, m->message);
-		job->stream = camel_stream_mem_new ();
-		em_format_html_job_queue (efh, job);
-
-		efh->state = EM_FORMAT_HTML_STATE_RENDERING;
-#if HAVE_CLUTTER
-		if (p->last_part != m->message && !e_shell_get_express_mode (e_shell_get_default ())) {
-#else
-		if (p->last_part != m->message) {
-#endif
-			gchar *str = g_strdup_printf ("<html><head></head><body>"
-						      "<table width=\"100%%\" height=\"100%%\"><tr>"
-						      "<td valign=\"middle\" align=\"center\"><h5>%s</h5></td>"
-						      "</tr></table>"
-						      "</body></html>", _("Formatting Message..."));
-			e_web_view_load_string (web_view, str);
-			g_free (str);
-
-			g_hash_table_remove_all (p->text_inline_parts);
-
-			p->last_part = m->message;
-		}
-
-		mail_msg_unordered_push (m);
-	}
-
-	p->format_timeout_id = 0;
-	p->format_timeout_msg = NULL;
-
-	return FALSE;
-}
 
 static void
 efh_free_cache (struct _EMFormatHTMLCache *efhc)
@@ -605,17 +361,6 @@ efh_finalize (GObject *object)
 
 	em_format_html_clear_pobject (efh);
 
-	if (priv->format_timeout_id != 0) {
-		g_source_remove (priv->format_timeout_id);
-		priv->format_timeout_id = 0;
-		mail_msg_unref (priv->format_timeout_msg);
-		priv->format_timeout_msg = NULL;
-	}
-
-	/* This probably works ... */
-	if (priv->format_id != -1)
-		mail_msg_cancel (priv->format_id);
-
 	if (priv->web_view != NULL) {
 		g_object_unref (priv->web_view);
 		efh->priv->web_view = NULL;
@@ -623,66 +368,11 @@ efh_finalize (GObject *object)
 
 	g_hash_table_destroy (priv->text_inline_parts);
 
-	g_mutex_free (priv->lock);
-
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static void
-efh_format_clone (EMFormat *emf,
-                  CamelFolder *folder,
-                  const gchar *uid,
-                  CamelMimeMessage *msg,
-                  EMFormat *emfsource,
-                  GCancellable *cancellable)
-{
-	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
-	struct _format_msg *m;
-
-	/* No webview, no need to format anything */
-	if (efh->priv->web_view == NULL)
-		return;
-
-	d(printf("efh_format called\n"));
-	if (efh->priv->format_timeout_id != 0) {
-		d(printf(" timeout for last still active, removing ...\n"));
-		g_source_remove (efh->priv->format_timeout_id);
-		efh->priv->format_timeout_id = 0;
-		mail_msg_unref (efh->priv->format_timeout_msg);
-		efh->priv->format_timeout_msg = NULL;
-	}
-
-	if (emfsource != NULL)
-		g_object_ref (emfsource);
-
-	if (folder != NULL)
-		g_object_ref (folder);
-
-	if (msg != NULL)
-		g_object_ref (msg);
-
-	m = mail_msg_new (&efh_format_info);
-	m->format = g_object_ref (emf);
-	m->format_source = emfsource;
-	m->folder = folder;
-	m->uid = g_strdup (uid);
-	m->message = msg;
-
-	if (efh->priv->format_id == -1) {
-		d(printf(" idle, forcing format\n"));
-		efh_format_timeout (m);
-	} else {
-		d(printf(" still busy, cancelling and queuing wait\n"));
-		/* cancel and poll for completion */
-		mail_msg_cancel (efh->priv->format_id);
-		efh->priv->format_timeout_msg = m;
-		efh->priv->format_timeout_id = g_timeout_add (
-			100, (GSourceFunc) efh_format_timeout, m);
-	}
-}
-
-static void
 efh_format_error (EMFormat *emf,
                   CamelStream *stream,
                   const gchar *txt)
@@ -772,15 +462,6 @@ efh_format_attachment (EMFormat *emf,
 		handle->handler (emf, stream, part, handle, cancellable, FALSE);
 }
 
-static gboolean
-efh_busy (EMFormat *emf)
-{
-	EMFormatHTMLPrivate *priv;
-
-	priv = EM_FORMAT_HTML (emf)->priv;
-
-	return (priv->format_id != -1);
-}
 static void
 efh_base_init (EMFormatHTMLClass *class)
 {
@@ -803,12 +484,10 @@ efh_class_init (EMFormatHTMLClass *class)
 	object_class->finalize = efh_finalize;
 
 	format_class = EM_FORMAT_CLASS (class);
-	format_class->format_clone = efh_format_clone;
 	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;
-	format_class->busy = efh_busy;
 
 	class->html_widget_type = E_TYPE_WEB_VIEW;
 
@@ -978,10 +657,6 @@ efh_init (EMFormatHTML *efh,
 	efh->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		efh, EM_TYPE_FORMAT_HTML, EMFormatHTMLPrivate);
 
-	g_queue_init (&efh->pending_object_list);
-	g_queue_init (&efh->priv->pending_jobs);
-	efh->priv->lock = g_mutex_new ();
-	efh->priv->format_id = -1;
 	efh->priv->text_inline_parts = g_hash_table_new_full (
 		g_str_hash, g_str_equal,
 		(GDestroyNotify) NULL,
@@ -990,18 +665,7 @@ efh_init (EMFormatHTML *efh,
 	web_view = g_object_new (class->html_widget_type, NULL);
 	efh->priv->web_view = g_object_ref_sink (web_view);
 
-	g_signal_connect (
-		web_view, "resource-request-starting",
-		G_CALLBACK (efh_resource_requested), efh);
-	g_signal_connect (
-		web_view, "create-plugin-widget",
-		G_CALLBACK (efh_create_plugin_widget), efh);
-	g_signal_connect (
-		web_view, "frame-created",
-		G_CALLBACK (efh_webview_frame_created), efh);
-	g_signal_connect (
-		web_view, "window-object-cleared",
-		G_CALLBACK (efh_install_js_callbacks), efh);
+	g_queue_init (&efh->pending_object_list);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
 	gdk_color_parse ("#eeeeee", color);
@@ -1027,7 +691,7 @@ efh_init (EMFormatHTML *efh,
 
 	g_signal_connect_swapped (
 		efh, "notify::mark-citations",
-		G_CALLBACK (em_format_queue_redraw), NULL);
+		G_CALLBACK (e_web_view_reload), web_view);
 
 	e_extensible_load_extensions (E_EXTENSIBLE (efh));
 }
@@ -1087,7 +751,7 @@ em_format_html_load_images (EMFormatHTML *efh)
 	/* This will remain set while we're still
 	 * rendering the same message, then it wont be. */
 	efh->priv->load_images_now = TRUE;
-	em_format_queue_redraw (EM_FORMAT (efh));
+	e_web_view_reload (efh->priv->web_view);
 }
 
 void
@@ -1432,406 +1096,67 @@ em_format_html_clear_pobject (EMFormatHTML *efh)
 	}
 }
 
-struct _EMFormatHTMLJob *
-em_format_html_job_new (EMFormatHTML *efh,
-                        void (*callback) (struct _EMFormatHTMLJob *job, GCancellable *cancellable),
-                        gpointer data)
-{
-	EMFormat *emf = EM_FORMAT (efh);
-	struct _EMFormatHTMLJob *job = g_malloc0 (sizeof (*job));
-
-	job->format = efh;
-	job->puri_level = emf->pending_uri_level;
-	job->callback = callback;
-	job->u.data = data;
-
-	if (emf->base)
-		job->base = camel_url_copy (emf->base);
-
-	return job;
-}
-
 void
-em_format_html_job_queue (EMFormatHTML *efh, struct _EMFormatHTMLJob *job)
-{
-	g_mutex_lock (efh->priv->lock);
-	g_queue_push_tail (&efh->priv->pending_jobs, job);
-	g_mutex_unlock (efh->priv->lock);
-
-	/* If no formatting thread is running, then start one */
-	if (efh->priv->format_id == -1) {
-		struct _format_msg *m;
-
-		d(printf("job queued, launching a new formatter thread\n"));
-
-		m = mail_msg_new (&efh_format_info);
-		m->format = g_object_ref (efh);
-
-		mail_msg_unordered_push (m);
-	} else {
-		d(printf("job queued, a formatter thread already running\n"));
-	}
-}
-
-/* ********************************************************************** */
-
-static void
-emfh_format_email (struct _EMFormatHTMLJob *job,
-	       	   GCancellable *cancellable)
+em_format_html_format_message (EMFormatHTML *efh, CamelStream *stream, GCancellable *cancellable)
 {
-	EMFormat *format;
+	EMFormat *emf;
 
 	d(printf(" running format_email task\n"));
+
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	format = EM_FORMAT (job->format);
 
-	if (format->mode == EM_FORMAT_MODE_SOURCE) {
+	emf = EM_FORMAT (efh);
+	em_format_html_clear_pobject(efh);
+	g_hash_table_remove_all (efh->priv->text_inline_parts);
+
+	if (emf->mode == EM_FORMAT_MODE_SOURCE) {
 		em_format_format_source (
-			format, job->stream,
-			CAMEL_MIME_PART (job->u.msg), cancellable);
+			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 (format, mime_type);
+		handle = em_format_find_handler (emf, mime_type);
 
 		if (handle != NULL)
 			handle->handler (
-				format, job->stream,
-				CAMEL_MIME_PART (job->u.msg), handle,
+				emf, stream,
+				CAMEL_MIME_PART (emf->message), handle,
 				cancellable, FALSE);
 
 		mime_type = "x-evolution/message/rfc822";
-		handle = em_format_find_handler (format, mime_type);
+		handle = em_format_find_handler (emf, mime_type);
 
 		if (handle != NULL)
 			handle->handler (
-				format, job->stream,
-				CAMEL_MIME_PART (job->u.msg), handle,
+				emf, stream,
+				CAMEL_MIME_PART (emf->message), handle,
 				cancellable, FALSE);
 	}
 }
 
-#if 0 /* WEBKIT */
-
-static void
-emfh_getpuri (struct _EMFormatHTMLJob *job,
-              GCancellable *cancellable)
-{
-	d(printf(" running getpuri task\n"));
-	if (!g_cancellable_is_cancelled (cancellable))
-		job->u.puri->func (
-			EM_FORMAT (job->format), job->stream,
-			job->u.puri, cancellable);
-}
-
-static void
-emfh_gethttp (struct _EMFormatHTMLJob *job,
-              GCancellable *cancellable)
-{
-	CamelStream *cistream = NULL, *costream = NULL, *instream = NULL;
-	CamelURL *url;
-	CamelContentType *content_type;
-	CamelHttpStream *tmp_stream;
-	gssize n, total = 0, pc_complete = 0, nread = 0;
-	gchar buffer[1500];
-	const gchar *length;
-
-	if (g_cancellable_is_cancelled (cancellable)
-	    || (url = camel_url_new (job->u.uri, NULL)) == NULL)
-		goto badurl;
-
-	d(printf(" running load uri task: %s\n", job->u.uri));
-
-	if (emfh_http_cache)
-		instream = cistream = camel_data_cache_get (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
-	if (instream == NULL) {
-		EMailImageLoadingPolicy policy;
-		gchar *proxy;
-
-		policy = em_format_html_get_image_loading_policy (job->format);
-
-		if (!(job->format->priv->load_images_now
-		      || policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS
-		      || (policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES
-			  && em_utils_in_addressbook ((CamelInternetAddress *) camel_mime_message_get_from (job->format->parent.message), FALSE)))) {
-			/* TODO: Ideally we would put the http requests into another queue and only send them out
-			   if the user selects 'load images', when they do.  The problem is how to maintain this
-			   state with multiple renderings, and how to adjust the thread dispatch/setup routine to handle it */
-			camel_url_free (url);
-			goto done;
-		}
-
-		instream = camel_http_stream_new (CAMEL_HTTP_METHOD_GET, ((EMFormat *) job->format)->session, url);
-		camel_http_stream_set_user_agent((CamelHttpStream *)instream, "CamelHttpStream/1.0 Evolution/" VERSION);
-		proxy = em_utils_get_proxy_uri (job->u.uri);
-		if (proxy) {
-			camel_http_stream_set_proxy ((CamelHttpStream *) instream, proxy);
-			g_free (proxy);
-		}
-		camel_operation_push_message (
-			cancellable, _("Retrieving '%s'"), job->u.uri);
-		tmp_stream = (CamelHttpStream *) instream;
-		content_type = camel_http_stream_get_content_type (tmp_stream);
-		length = camel_header_raw_find(&tmp_stream->headers, "Content-Length", NULL);
-		d(printf("  Content-Length: %s\n", length));
-		if (length != NULL)
-			total = atoi (length);
-		camel_content_type_unref (content_type);
-	} else
-		camel_operation_push_message (
-			cancellable, _("Retrieving '%s'"), job->u.uri);
-
-	camel_url_free (url);
-
-	if (instream == NULL)
-		goto done;
-
-	if (emfh_http_cache != NULL && cistream == NULL)
-		costream = camel_data_cache_add (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
-	do {
-		if (camel_operation_cancel_check (CAMEL_OPERATION (cancellable))) {
-			n = -1;
-			break;
-		}
-		/* FIXME: progress reporting in percentage, can we get the length always?  do we care? */
-		n = camel_stream_read (instream, buffer, sizeof (buffer), cancellable, NULL);
-		if (n > 0) {
-			nread += n;
-			/* If we didn't get a valid Content-Length header, do not try to calculate percentage */
-			if (total != 0) {
-				pc_complete = ((nread * 100) / total);
-				camel_operation_progress (cancellable, pc_complete);
-			}
-			d(printf("  read %d bytes\n", (int)n));
-			if (costream && camel_stream_write (costream, buffer, n, cancellable, NULL) == -1) {
-				n = -1;
-				break;
-			}
-
-			camel_stream_write (job->stream, buffer, n, cancellable, NULL);
-		}
-	} while (n>0);
-
-	/* indicates success */
-	if (n == 0)
-		camel_stream_close (job->stream, cancellable, NULL);
-
-	if (costream) {
-		/* do not store broken files in a cache */
-		if (n != 0)
-			camel_data_cache_remove (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-		g_object_unref (costream);
-	}
-
-	g_object_unref (instream);
-done:
-	camel_operation_pop_message (cancellable);
-badurl:
-	g_free (job->u.uri);
-}
-
-#endif /* WEBKIT */
-
-/* ********************************************************************** */
-static void
-efh_resource_requested (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebResource *resource,
-			WebKitNetworkRequest *request, WebKitNetworkResponse *response, gpointer user_data)
+void
+em_format_html_format_message_part (EMFormatHTML *efh, const gchar *part_id, CamelStream *stream, GCancellable *cancellable)
 {
-	EMFormatHTML *efh = user_data;
 	EMFormatPURI *puri;
-	const gchar *p_uri = webkit_network_request_get_uri (request);
-	const gchar *uri;
-
-	d(printf("URI requested '%s'\n", p_uri));
-
-	if (g_str_has_prefix (p_uri, "puri:")) {
-		uri = &p_uri[5];
-	} else {
-		uri = p_uri;
-	}
-
-	puri = em_format_find_puri (EM_FORMAT (efh), uri);
-	if (puri) {
-		CamelDataWrapper *dw;
-		CamelContentType *ct;
-
-		dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
-		if (!dw) {
-			d(printf("PURI does not contain valid mimepart, skipping\n"));
-			return;
-		}
-
-		ct = camel_data_wrapper_get_mime_type_field (dw);
-
-		if (ct && (camel_content_type_is (ct, "text", "*")
-			   || camel_content_type_is (ct, "image", "*")
-			   || camel_content_type_is (ct, "application", "octet-stream"))) {
-
-			gchar *data, *b64;
-			gchar *cts = camel_data_wrapper_get_mime_type (dw);
-			CamelStream *stream;
-			GByteArray *ba;
 
-			puri->use_count++;
-
-			stream = camel_stream_mem_new ();
-
-			camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
-			ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
-			b64 = g_base64_encode ((guchar*) ba->data, ba->len);
-			if (camel_content_type_is (ct, "text", "*")) {
-				const gchar *charset = camel_content_type_param (ct, "charset");
-				data = g_strdup_printf ("data:%s;charset=%s;base64,%s", cts,
-					charset ? charset : "utf-8", b64);
-			} else {
-				data = g_strdup_printf ("data:%s;base64,%s", cts, b64);
-			}
-
-			webkit_network_request_set_uri (request, data);
-			g_free (b64);
-			g_free (data);
-			g_free (cts);
-			g_object_unref (stream);
-
-		} else {
-			d(printf(" part is unknown type '%s', not using\n", ct ? camel_content_type_format(ct) : "<unset>"));
-		}
-	} else if (g_str_has_prefix(uri, "http:") || g_str_has_prefix (uri, "https:")) {
-		d(printf(" Remote URI requetsed, webkit handling it\n"));
-	} else if  (g_str_has_prefix (uri, "file:")) {
-		gchar *data = NULL;
-		gsize length = 0;
-		gboolean status;
-		gchar *path;
-
-		path = g_filename_from_uri (uri, NULL, NULL);
-		if (!path)
-			return;
-
-		d(printf(" Local URI requested, loading file '%s'\n", path));
-
-		status = g_file_get_contents (path, &data, &length, NULL);
-		if (status) {
-			gchar *b64, *new_uri;
-			gchar *ct;
-
-			b64 = g_base64_encode ((guchar*) data, length);
-			ct = g_content_type_guess (path, NULL, 0, NULL);
-
-			new_uri =  g_strdup_printf ("data:%s;base64,%s", ct, b64);
-			webkit_network_request_set_uri (request, new_uri);
-
-			g_free (b64);
-			g_free (new_uri);
-			g_free (ct);
-		}
-		g_free (data);
-		g_free (path);
-	} else {
-		d(printf("HTML Includes reference to unknown uri '%s'\n", uri));
-	}
-
-	g_signal_stop_emission_by_name (web_view, "resource-request-starting");
-}
-
-static GtkWidget*
-efh_create_plugin_widget (WebKitWebView *web_view, gchar *mime_type, gchar *uri, GHashTable *param, gpointer user_data)
-{
-	EMFormatHTML *efh = user_data;
-	EMFormatHTMLPObject *pobject;
-	const gchar *classid;
-
-	classid = g_hash_table_lookup (param, "data");
-	if (!classid) {
-		d(printf("Object does not have class-id, bailing.\n"));
-		return NULL;
-	}
-
-	pobject = em_format_html_find_pobject (efh, classid);
-	if (pobject) {
-		GtkWidget *widget;
-
-		d(printf("Creating widget for object '%s\n'", classid));
-
-		/* This stops recursion of the part */
-		g_queue_remove (&efh->pending_object_list, pobject);
-		widget = pobject->func (efh, pobject);
-		g_queue_push_head (&efh->pending_object_list, pobject);
-
-		return widget;
-	} else {
-		d(printf("HTML includes reference to unknown object '%s'\n", uri));
-		return NULL;
-	}
-}
-
-static void
-efh_webview_frame_loaded (GObject *object, GParamSpec *pspec, gpointer user_data)
-{
-	WebKitWebFrame *frame = WEBKIT_WEB_FRAME (object);
-	WebKitWebView *web_view;
-	const gchar *frame_name;
-	gchar *script;
-	GValue val = {0};
-
-	/* Don't do anything until all content of the frame is loaded*/
-	if (webkit_web_frame_get_load_status (frame) != WEBKIT_LOAD_FINISHED)
+	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	web_view = webkit_web_frame_get_web_view (frame);
-	frame_name = webkit_web_frame_get_name (frame);
-
-	/* Get total height of the document inside the frame */
-	e_web_view_frame_exec_script (E_WEB_VIEW (web_view), frame_name, "document.body.scrollHeight;", &val);
+	em_format_push_level (EM_FORMAT (efh));
 
-	/* Change height of the frame so that entire content is visible */
-	script = g_strdup_printf ("window.document.getElementById(\"%s\").height=%d;", frame_name, (int)(g_value_get_double (&val) + 10));
-	e_web_view_exec_script (E_WEB_VIEW (web_view), script, NULL);
-	g_free (script);
-}
-
-
-static void
-efh_webview_frame_created (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data)
-{
-	if (frame != webkit_web_view_get_main_frame (web_view)) {
-
-		/* Get notified when all content of frame is loaded */
-		g_signal_connect (frame,  "notify::load-status",
-			G_CALLBACK (efh_webview_frame_loaded), NULL);
+	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);
 }
 
-static void
-efh_headers_collapsed_state_changed (EWebView *web_view, size_t arg_count, const JSValueRef args[], gpointer user_data)
-{
-	EMFormatHTML *efh = user_data;
-	JSGlobalContextRef ctx = e_web_view_get_global_context (web_view);
-
-	gboolean collapsed = JSValueToBoolean (ctx, args[0]);
-
-	if (collapsed) {
-		em_format_html_set_headers_state (efh, EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED);
-	} else {
-		em_format_html_set_headers_state (efh, EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
-	}
-}
-
-static void
-efh_install_js_callbacks (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer context, gpointer window_object, gpointer user_data)
-{
-	if (frame != webkit_web_view_get_main_frame (web_view))
-		return;
-
-	e_web_view_install_js_callback (E_WEB_VIEW (web_view), "headers_collapsed",
-		(EWebViewJSFunctionCallback) efh_headers_collapsed_state_changed, user_data);
-}
 
 /* ********************************************************************** */
 #include "em-format/em-inline-filter.h"
@@ -2187,6 +1512,7 @@ efh_text_html (EMFormat *emf,
 	const gchar *location;
 	gchar *cid = NULL;
 	gchar *content;
+	gchar *mail_uri;
 
 	content = g_strdup_printf (
 		"<div style=\"border: solid #%06x 1px; "
@@ -2231,12 +1557,16 @@ efh_text_html (EMFormat *emf,
 		emf, sizeof (EMFormatPURI), cid,
 		part, efh_write_text_html);
 	d(printf("adding iframe, location %s\n", cid));
+
+	mail_uri = em_format_build_mail_uri (emf->folder, emf->uid, cid, emf);
+
 	content = g_strdup_printf (
-		"<iframe name=\"html-frame-%s\" id=\"html-frame-%s\" src=\"puri:%s\" frameborder=0 scrolling=no width=\"100%%\" >" \
-		"Could not get %s</iframe>\n</div>\n", cid, cid, cid, cid);
+		"<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);
 }
 
 /* This is a lot of code for something useless ... */
@@ -2410,25 +1740,23 @@ emfh_write_related (EMFormat *emf,
 }
 
 static void
-emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
+emfh_multipart_related_check (EMFormat *emf,
+			      CamelStream *stream,
                               GCancellable *cancellable)
 {
-	EMFormat *format;
 	GList *link;
 	gchar *oldpartid;
 
 	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
-	format = EM_FORMAT (job->format);
-
 	d(printf(" running multipart/related check task\n"));
-	oldpartid = g_strdup (format->part_id->str);
+	oldpartid = g_strdup (emf->part_id->str);
 
-	link = g_queue_peek_head_link (job->puri_level->data);
+	link = g_queue_peek_head_link (emf->pending_uri_level->data);
 
 	if (!link) {
-		g_string_printf (format->part_id, "%s", oldpartid);
+		g_string_printf (emf->part_id, "%s", oldpartid);
 		g_free (oldpartid);
 		return;
 	}
@@ -2437,11 +1765,11 @@ emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
 		EMFormatPURI *puri = link->data;
 
 		if (puri->use_count == 0) {
-			d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
+			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 (format->part_id, "%s", puri->part_id);
+				g_string_printf (emf->part_id, "%s", puri->part_id);
 				em_format_part (
-					format, CAMEL_STREAM (job->stream),
+					emf, CAMEL_STREAM (stream),
 					puri->part, cancellable);
 			}
 			/* else it was probably added by a previous format this loop */
@@ -2450,7 +1778,7 @@ emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
 		link = g_list_next (link);
 	}
 
-	g_string_printf (format->part_id, "%s", oldpartid);
+	g_string_printf (emf->part_id, "%s", oldpartid);
 	g_free (oldpartid);
 }
 
@@ -2468,7 +1796,6 @@ efh_multipart_related (EMFormat *emf,
 	CamelContentType *content_type;
 	const gchar *start;
 	gint i, nparts, partidlen, displayid = 0;
-	struct _EMFormatHTMLJob *job;
 
 	if (!CAMEL_IS_MULTIPART (mp)) {
 		em_format_format_source (emf, stream, part, cancellable);
@@ -2527,12 +1854,7 @@ efh_multipart_related (EMFormat *emf,
 	g_string_truncate (emf->part_id, partidlen);
 	camel_stream_flush (stream, cancellable, NULL);
 
-	/* queue a job to check for un-referenced parts to add as attachments */
-	job = em_format_html_job_new (
-		EM_FORMAT_HTML (emf), emfh_multipart_related_check, NULL);
-	job->stream = stream;
-	g_object_ref (stream);
-	em_format_html_job_queue ((EMFormatHTML *) emf, job);
+	emfh_multipart_related_check (emf, stream, cancellable);
 
 	em_format_pull_level (emf);
 }
@@ -2758,7 +2080,6 @@ efh_format_address (EMFormatHTML *efh, GString *out, struct _camel_header_addres
 
 		/* Let us add a '...' if we have more addresses */
 		if (limit > 0 && (i == limit-1)) {
-			gchar *evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
 			const gchar *id = NULL;
 
 			if (strcmp (field, _("To")) == 0) {
@@ -2771,11 +2092,9 @@ efh_format_address (EMFormatHTML *efh, GString *out, struct _camel_header_addres
 
 			if (id) {
 				g_string_append_printf (out, "<span id=\"moreaddr-%s\" style=\"display: none;\">", id);
-				str = g_strdup_printf ("<img src=\"%s/plus.png\" onClick=\"collapse_addresses('%s');\" id=\"moreaddr-img-%s\" class=\"navigable\">  ",
-					evolution_imagesdir, id, id);
+				str = g_strdup_printf ("<img src=\"evo-file://%s/plus.png\" onClick=\"collapse_addresses('%s');\" id=\"moreaddr-img-%s\" class=\"navigable\">  ",
+					EVOLUTION_IMAGESDIR, id, id);
 			}
-
-			g_free (evolution_imagesdir);
 		}
 	}
 
@@ -3333,18 +2652,14 @@ efh_format_full_headers (EMFormatHTML *efh,
 
 static void
 efh_format_headers (EMFormatHTML *efh,
-                    GString *buffer,
-                    CamelMedium *part,
+		    GString *buffer,
+	            CamelMedium *part,
                     GCancellable *cancellable)
 {
-	gchar *evolution_imagesdir;
 
 	if (!part)
 		return;
 
-
-	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
-
 	g_string_append_printf (
 		buffer, "<font color=\"#%06x\">\n"
 		"<table border=\"0\" width=\"100%%\">"
@@ -3355,8 +2670,8 @@ efh_format_headers (EMFormatHTML *efh,
 
 	if (efh->priv->headers_collapsable) {
 		g_string_append_printf (buffer,
-			"<img src=\"%s/%s\" onClick=\"collapse_headers();\" class=\"navigable\" id=\"collapse-headers-img\" /></td><td>",
-			evolution_imagesdir,
+			"<img src=\"evo-file://%s/%s\" onClick=\"collapse_headers();\" class=\"navigable\" id=\"collapse-headers-img\" /></td><td>",
+			EVOLUTION_IMAGESDIR,
 			(efh->priv->headers_state == EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED) ? "plus.png" : "minus.png");
 
 		efh_format_short_headers (efh, buffer, part,
@@ -3369,8 +2684,6 @@ efh_format_headers (EMFormatHTML *efh,
 		cancellable);
 
 	g_string_append (buffer, "</td></tr></table></font>");
-
-	g_free (evolution_imagesdir);
 }
 
 static void
@@ -3395,7 +2708,7 @@ efh_format_message (EMFormat *emf,
 	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=\"file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\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" \
@@ -3432,7 +2745,7 @@ efh_format_message (EMFormat *emf,
 
 	if (!efh->hide_headers)
 		efh_format_headers (
-			efh, buffer, CAMEL_MEDIUM (part), cancellable);
+			efh, buffer, CAMEL_MEDIUM (emf->message), cancellable);
 
 	camel_stream_write (
 		stream, buffer->str, buffer->len, cancellable, NULL);
@@ -3442,17 +2755,17 @@ efh_format_message (EMFormat *emf,
 	handle = em_format_find_handler(emf, "x-evolution/message/post-header");
 	if (handle)
 		handle->handler (
-			emf, stream, part, handle, cancellable, FALSE);
+			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, part, cancellable);
+	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_stream_write_string (stream, "</body></html>", cancellable, NULL);
 
 	camel_cipher_validity_free (emf->valid);
 
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index 41e4eba..fa87a57 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -83,55 +83,6 @@ typedef enum {
 	EM_FORMAT_HTML_NUM_COLOR_TYPES
 } EMFormatHTMLColorType;
 
-/* A HTMLJob will be executed in another thread, in sequence.
-   It's job is to write to its stream, close it if successful,
-   then exit. */
-
-typedef struct _EMFormatHTMLJob EMFormatHTMLJob;
-
-typedef void	(*EMFormatHTMLJobCallback)	(EMFormatHTMLJob *job,
-						 GCancellable *cancellable);
-
-/**
- * struct _EMFormatHTMLJob - A formatting job.
- *
- * @format: Set by allocation function.
- * @stream: Free for use by caller.
- * @puri_level: Set by allocation function.
- * @base: Set by allocation function, used to save state.
- * @callback: This callback will always be invoked, only once, even if the user
- * cancelled the display.  So the callback should free any extra data
- * it allocated every time it is called.
- * @u: Union data, free for caller to use.
- *
- * This object is used to queue a long-running-task which cannot be
- * processed in the primary thread.  When its turn comes, the job will
- * be de-queued and the @callback invoked to perform its processing,
- * restoring various state to match the original state.  This is used
- * for image loading and other internal tasks.
- *
- * This object is struct-subclassable.  Only em_format_html_job_new()
- * may be used to allocate these.
- **/
-struct _EMFormatHTMLJob {
-	EMFormatHTML *format;
-	CamelStream *stream;
-
-	/* We need to track the state of the visibility tree at
-	   the point this uri was generated */
-	GNode *puri_level;
-	CamelURL *base;
-
-	EMFormatHTMLJobCallback callback;
-	union {
-		gchar *uri;
-		CamelMedium *msg;
-		EMFormatPURI *puri;
-		GNode *puri_level;
-		gpointer data;
-	} u;
-};
-
 /* Pending object (classid: url) */
 typedef struct _EMFormatHTMLPObject EMFormatHTMLPObject;
 
@@ -281,12 +232,7 @@ EMFormatHTMLPObject *
 void		em_format_html_remove_pobject	(EMFormatHTML *efh,
 						 EMFormatHTMLPObject *pobject);
 void		em_format_html_clear_pobject	(EMFormatHTML *efh);
-EMFormatHTMLJob *
-		em_format_html_job_new		(EMFormatHTML *efh,
-						 EMFormatHTMLJobCallback callback,
-						 gpointer data);
-void		em_format_html_job_queue	(EMFormatHTML *efh,
-						 EMFormatHTMLJob *job);
+
 gboolean	em_format_html_get_show_real_date
 						(EMFormatHTML *efh);
 void		em_format_html_set_show_real_date
@@ -307,6 +253,19 @@ void		em_format_html_set_headers_collapsable
 gchar *		em_format_html_format_cert_infos
 						(CamelCipherCertInfo *first_cinfo);
 
+void		em_format_html_format_message (EMFormatHTML *efh,
+					       CamelStream *stream,
+					       GCancellable *cancellable);
+
+void		em_format_html_format_message_part (EMFormatHTML *efh,
+						    const gchar *part_id,
+    						    CamelStream *stream,
+						    GCancellable *cancellable);
+void		em_format_html_format_headers (EMFormatHTML *efh,
+					       CamelStream *stream,
+					       CamelMedium *part,
+					       GCancellable *cancellable);
+
 G_END_DECLS
 
 #endif /* EM_FORMAT_HTML_H */
diff --git a/mail/em-utils.c b/mail/em-utils.c
index a106a0c..98ceea6 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -394,6 +394,7 @@ em_utils_flag_for_followup (EMailReader *reader,
 	EShellSettings *shell_settings;
 	EShellBackend *shell_backend;
 	EMFormatHTML *formatter;
+	EWebView *web_view;
 	GtkWidget *editor;
 	GtkWindow *window;
 	CamelTag *tags;
@@ -484,7 +485,8 @@ em_utils_flag_for_followup (EMailReader *reader,
 	camel_tag_list_free (&tags);
 
 	formatter = e_mail_reader_get_formatter (reader);
-	em_format_queue_redraw (EM_FORMAT (formatter));
+	web_view = em_format_html_get_web_view (formatter);
+	e_web_view_reload (web_view);
 
 exit:
 	/* XXX We shouldn't be freeing this. */
diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c
index f5b2bcd..9296254 100644
--- a/plugins/itip-formatter/itip-formatter.c
+++ b/plugins/itip-formatter/itip-formatter.c
@@ -2431,8 +2431,8 @@ in_proper_folder (CamelFolder *folder)
 	return res;
 }
 
-static gboolean
-format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
+static GtkWidget*
+format_itip_object (EMFormatHTML *efh, EMFormatHTMLPObject *pobject)
 {
 	EShell *shell;
 	EShellSettings *shell_settings;
@@ -2468,11 +2468,12 @@ format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject
 	}
 
 	/* FIXME Handle multiple VEVENTS with the same UID, ie detached instances */
+#if 0  /* WEBKIT - FIXME!! */
 	if (!extract_itip_data (info, GTK_CONTAINER (eb), &have_alarms))
 		return TRUE;
+#endif
 
 	info->view = itip_view_new ();
-	gtk_container_add (GTK_CONTAINER (eb), info->view);
 	gtk_widget_show (info->view);
 
 	response_enabled = in_proper_folder (((EMFormat*) efh)->folder);
@@ -2523,7 +2524,7 @@ format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject
 			itip_view_set_mode (ITIP_VIEW (info->view), ITIP_VIEW_MODE_REQUEST);
 			break;
 		default:
-			return FALSE;
+			return NULL;
 		}
 	}
 
@@ -2750,7 +2751,7 @@ format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject
 		}
 	}
 
-	return TRUE;
+	return info->view;
 }
 
 static void
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index e4958ad..1ace381 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -35,6 +35,8 @@
 #include <e-util/e-extensible.h>
 #include <e-util/e-plugin-ui.h>
 
+#include <mail/e-mail-request.h>
+
 #include "e-popup-action.h"
 #include "e-selectable.h"
 
@@ -140,134 +142,6 @@ G_DEFINE_TYPE_WITH_CODE (
 		E_TYPE_SELECTABLE,
 		e_web_view_selectable_init))
 
-static EWebViewRequest *
-web_view_request_new (EWebView *web_view,
-                      const gchar *uri)
-{
-	EWebViewRequest *request;
-	GList *list;
-
-	request = g_slice_new (EWebViewRequest);
-
-	/* Try to detect file paths posing as URIs. */
-	if (*uri == '/')
-		request->file = g_file_new_for_path (uri);
-	else
-		request->file = g_file_new_for_uri (uri);
-
-	request->web_view = g_object_ref (web_view);
-	request->cancellable = g_cancellable_new ();
-	request->input_stream = NULL;
-	request->output_buffer = g_string_sized_new (4096);
-
-	list = request->web_view->priv->requests;
-	list = g_list_prepend (list, request);
-	request->web_view->priv->requests = list;
-
-	return request;
-}
-
-static void
-web_view_request_free (EWebViewRequest *request)
-{
-	GList *list;
-
-	list = request->web_view->priv->requests;
-	list = g_list_remove (list, request);
-	request->web_view->priv->requests = list;
-
-	g_object_unref (request->file);
-	g_object_unref (request->web_view);
-	g_object_unref (request->cancellable);
-
-	if (request->input_stream != NULL)
-		g_object_unref (request->input_stream);
-
-	g_string_free (request->output_buffer, TRUE);
-
-	g_slice_free (EWebViewRequest, request);
-}
-
-static void
-web_view_request_cancel (EWebViewRequest *request)
-{
-	g_cancellable_cancel (request->cancellable);
-}
-
-static gboolean
-web_view_request_check_for_error (EWebViewRequest *request,
-                                  GError *error)
-{
-	if (error == NULL)
-		return FALSE;
-
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
-		/* use this error, but do not close the stream */
-		g_error_free (error);
-		return TRUE;
-	}
-
-	/* XXX Should we log errors that are not cancellations? */
-
-	web_view_request_free (request);
-	g_error_free (error);
-
-	return TRUE;
-}
-
-static void
-web_view_request_stream_read_cb (GInputStream *input_stream,
-                                 GAsyncResult *result,
-                                 EWebViewRequest *request)
-{
-	gssize bytes_read;
-	GError *error = NULL;
-
-	bytes_read = g_input_stream_read_finish (input_stream, result, &error);
-
-	if (web_view_request_check_for_error (request, error))
-		return;
-
-	if (bytes_read == 0) {
-		e_web_view_load_string (
-			request->web_view,
-			request->output_buffer->str);
-		web_view_request_free (request);
-		return;
-	}
-
-	g_string_append_len (
-		request->output_buffer, request->buffer, bytes_read);
-
-	g_input_stream_read_async (
-		request->input_stream, request->buffer,
-		sizeof (request->buffer), G_PRIORITY_DEFAULT,
-		request->cancellable, (GAsyncReadyCallback)
-		web_view_request_stream_read_cb, request);
-}
-
-static void
-web_view_request_read_cb (GFile *file,
-                          GAsyncResult *result,
-                          EWebViewRequest *request)
-{
-	GFileInputStream *input_stream;
-	GError *error = NULL;
-
-	/* Input stream might be NULL, so don't use cast macro. */
-	input_stream = g_file_read_finish (file, result, &error);
-	request->input_stream = (GInputStream *) input_stream;
-
-	if (web_view_request_check_for_error (request, error))
-		return;
-
-	g_input_stream_read_async (
-		request->input_stream, request->buffer,
-		sizeof (request->buffer), G_PRIORITY_DEFAULT,
-		request->cancellable, (GAsyncReadyCallback)
-		web_view_request_stream_read_cb, request);
-}
-
 static void
 action_copy_clipboard_cb (GtkAction *action,
                           EWebView *web_view)
@@ -941,23 +815,6 @@ web_view_scroll_event (GtkWidget *widget,
 	return FALSE;
 }
 
-#if 0  /* WEBKIT */
-static void
-web_view_url_requested (GtkHTML *html,
-                        const gchar *uri,
-                        GtkHTMLStream *stream)
-{
-	EWebViewRequest *request;
-
-	request = web_view_request_new (E_WEB_VIEW (html), uri, stream);
-
-	g_file_read_async (
-		request->file, G_PRIORITY_DEFAULT,
-		request->cancellable, (GAsyncReadyCallback)
-		web_view_request_read_cb, request);
-}
-#endif
-
 static GtkWidget *
 web_view_create_plugin_widget (EWebView *web_view,
                                const gchar *mime_type,
@@ -1164,10 +1021,6 @@ web_view_popup_event (EWebView *web_view,
 static void
 web_view_stop_loading (EWebView *web_view)
 {
-	g_list_foreach (
-		web_view->priv->requests, (GFunc)
-		web_view_request_cancel, NULL);
-
 	webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
 }
 
@@ -1654,6 +1507,8 @@ e_web_view_init (EWebView *web_view)
 	WebKitWebSettings *web_settings;
 	const gchar *domain = GETTEXT_PACKAGE;
 	const gchar *id;
+	GtkStyleContext *context;
+	const PangoFontDescription *font;
 	GError *error = NULL;
 
 	web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
@@ -1688,6 +1543,18 @@ e_web_view_init (EWebView *web_view)
 	web_settings = webkit_web_view_get_settings (
 		WEBKIT_WEB_VIEW (web_view));
 
+	/* Use same font-size as rest of Evolution */
+	context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
+	font = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL);
+	g_object_set (G_OBJECT (web_settings),
+		"default-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+		"default-monospace-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+		NULL);
+
+	/* Force frames to be as high as their content (e.g. no scrolling) */
+	g_object_set (G_OBJECT (web_settings), "enable-frame-flattening",
+		TRUE, NULL);
+
 	g_object_bind_property (
 		web_view, "caret-mode",
 		web_settings, "enable-caret-browsing",
@@ -1802,6 +1669,7 @@ e_web_view_init (EWebView *web_view)
 	e_plugin_ui_enable_manager (ui_manager, id);
 
 	e_extensible_load_extensions (E_EXTENSIBLE (web_view));
+
 }
 
 GtkWidget *
@@ -1846,6 +1714,14 @@ e_web_view_load_uri (EWebView *web_view,
 	class->load_uri (web_view, uri);
 }
 
+void
+e_web_view_reload (EWebView *web_view)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
+}
+
 const gchar*
 e_web_view_get_uri (EWebView *web_view)
 {
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index e43b15f..98c5821 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -110,6 +110,7 @@ void		e_web_view_load_string		(EWebView *web_view,
 void		e_web_view_load_uri		(EWebView *web_view,
 						 const gchar *uri);
 const gchar*	e_web_view_get_uri		(EWebView *web_view);
+void		e_web_view_reload		(EWebView *web_view);
 void		e_web_view_frame_load_string	(EWebView *web_view,
 						 const gchar *frame_name,
 						 const gchar *string);



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