evolution r37346 - branches/kill-bonobo/mail



Author: mbarnes
Date: Sun Mar  1 13:16:31 2009
New Revision: 37346
URL: http://svn.gnome.org/viewvc/evolution?rev=37346&view=rev

Log:
Split the interactive parts of the message display out of EMFormatHTMLDisplay
to a new GtkHTML subclass named EMailDisplay, and have EMFormatHTML create an
instance of that.  EMailDisplay will handle link clicking, mousing over URIs,
popup menus, and interactive search.  This makes EMFormatHTMLDisplay and
EMailReader more lightweight.

Clean up more of the EMFormat stack.


Added:
   branches/kill-bonobo/mail/e-mail-display.c
   branches/kill-bonobo/mail/e-mail-display.h
Modified:
   branches/kill-bonobo/mail/Makefile.am
   branches/kill-bonobo/mail/e-mail-browser.c
   branches/kill-bonobo/mail/e-mail-reader.c
   branches/kill-bonobo/mail/e-mail-shell-view-private.c
   branches/kill-bonobo/mail/em-folder-view.c
   branches/kill-bonobo/mail/em-format-html-display.c
   branches/kill-bonobo/mail/em-format-html-display.h
   branches/kill-bonobo/mail/em-format-html.c
   branches/kill-bonobo/mail/em-format-html.h
   branches/kill-bonobo/mail/em-html-stream.c
   branches/kill-bonobo/mail/em-html-stream.h

Modified: branches/kill-bonobo/mail/Makefile.am
==============================================================================
--- branches/kill-bonobo/mail/Makefile.am	(original)
+++ branches/kill-bonobo/mail/Makefile.am	Sun Mar  1 13:16:31 2009
@@ -37,6 +37,8 @@
 libevolution_module_mail_la_SOURCES =			\
 	e-mail-browser.c				\
 	e-mail-browser.h				\
+	e-mail-display.c				\
+	e-mail-display.h				\
 	e-mail-label-dialog.c				\
 	e-mail-label-dialog.h				\
 	e-mail-label-list-store.c			\

Modified: branches/kill-bonobo/mail/e-mail-browser.c
==============================================================================
--- branches/kill-bonobo/mail/e-mail-browser.c	(original)
+++ branches/kill-bonobo/mail/e-mail-browser.c	Sun Mar  1 13:16:31 2009
@@ -218,6 +218,23 @@
 }
 
 static void
+mail_browser_status_message_cb (EMailBrowser *browser,
+                                const gchar *status_message)
+{
+	GtkStatusbar *statusbar;
+	guint context_id;
+
+	statusbar = GTK_STATUSBAR (browser->priv->statusbar);
+	context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC);
+
+	/* Always pop first.  This prevents messages from piling up. */
+	gtk_statusbar_pop (statusbar, context_id);
+
+	if (status_message != NULL && *status_message != '\0')
+		gtk_statusbar_push (statusbar, context_id, status_message);
+}
+
+static void
 mail_browser_set_shell_module (EMailBrowser *browser,
                                EShellModule *shell_module)
 {
@@ -320,6 +337,7 @@
 static void
 mail_browser_constructed (GObject *object)
 {
+	EMFormatHTMLDisplay *html_display;
 	EMailBrowserPrivate *priv;
 	EMailReader *reader;
 	EShellModule *shell_module;
@@ -329,6 +347,7 @@
 	GtkUIManager *ui_manager;
 	GtkWidget *container;
 	GtkWidget *widget;
+	GtkHTML *html;
 	const gchar *domain;
 	guint merge_id;
 
@@ -338,10 +357,14 @@
 	ui_manager = priv->ui_manager;
 	domain = GETTEXT_PACKAGE;
 
+	html_display = e_mail_reader_get_html_display (reader);
 	shell_module = e_mail_reader_get_shell_module (reader);
+
 	shell = e_shell_module_get_shell (shell_module);
 	e_shell_watch_window (shell, GTK_WINDOW (object));
 
+	html = EM_FORMAT_HTML (html_display)->html;
+
 	/* The message list is a widget, but it is not shown in the browser.
 	 * Unfortunately, the widget is inseparable from its model, and the
 	 * model is all we need. */
@@ -352,6 +375,10 @@
 		priv->message_list, "message-selected",
 		G_CALLBACK (mail_browser_message_selected_cb), object);
 
+	g_signal_connect_swapped (
+		html, "status-message",
+		G_CALLBACK (mail_browser_status_message_cb), object);
+
 	e_mail_reader_init (reader);
 
 	action_group = priv->action_group;
@@ -409,7 +436,7 @@
 
 	container = widget;
 
-	widget = GTK_WIDGET (((EMFormatHTML *) priv->html_display)->html);
+	widget = GTK_WIDGET (EM_FORMAT_HTML (html_display)->html);
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	gtk_widget_show (widget);
 }

Added: branches/kill-bonobo/mail/e-mail-display.c
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/mail/e-mail-display.c	Sun Mar  1 13:16:31 2009
@@ -0,0 +1,627 @@
+/*
+ * e-mail-display.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-display.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+
+#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
+
+struct _EMailDisplayPrivate {
+	EMFormatHTML *formatter;
+};
+
+enum {
+	PROP_0,
+	PROP_ANIMATE,
+	PROP_CARET_MODE,
+	PROP_FORMATTER
+};
+
+enum {
+	POPUP_EVENT,
+	STATUS_MESSAGE,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static gboolean
+mail_display_emit_popup_event (EMailDisplay *display,
+                               GdkEventButton *event,
+                               const gchar *uri,
+                               EMFormatPURI *puri)
+{
+	CamelMimePart *mime_part;
+	gboolean stop_handlers = FALSE;
+
+	mime_part = (puri != NULL) ? puri->part : NULL;
+
+	g_signal_emit (
+		display, signals[POPUP_EVENT], 0,
+		event, uri, mime_part, &stop_handlers);
+
+	return stop_handlers;
+}
+
+static void
+mail_display_emit_status_message (EMailDisplay *display,
+                                  const gchar *status_message)
+{
+	g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message);
+}
+
+static void
+mail_display_get_uri_puri (EMailDisplay *display,
+                           GdkEventButton *event,
+                           gchar **uri,
+                           EMFormatPURI **puri)
+{
+	EMFormat *formatter;
+	GtkHTML *html;
+	gchar *text_uri;
+	gchar *image_uri;
+	gboolean is_cid;
+
+	html = GTK_HTML (display);
+	formatter = EM_FORMAT (display->priv->formatter);
+
+	if (event != NULL) {
+		text_uri = gtk_html_get_url_at (html, event->x, event->y);
+		image_uri = gtk_html_get_image_src_at (html, event->x, event->y);
+	} else {
+		text_uri = gtk_html_get_cursor_url (html);
+		image_uri = gtk_html_get_cursor_image_src (html);
+	}
+
+	is_cid = (image_uri != NULL) &&
+		(g_ascii_strncasecmp (image_uri, "cid:", 4) == 0);
+
+	if (image_uri != NULL) {
+		if (strstr (image_uri, "://") == NULL && !is_cid) {
+			gchar *temp;
+
+			temp = g_strconcat ("file://", image_uri, NULL);
+			g_free (image_uri);
+			temp = image_uri;
+		}
+	}
+
+	if (puri != NULL) {
+		if (text_uri != NULL)
+			*puri = em_format_find_puri (formatter, text_uri);
+
+		if (*puri == NULL && image_uri != NULL)
+			*puri = em_format_find_puri (formatter, image_uri);
+	}
+
+	if (uri != NULL) {
+		*uri = NULL;
+		if (is_cid) {
+			if (text_uri != NULL)
+				*uri = g_strdup_printf (
+					"%s\n%s", text_uri, image_uri);
+			else {
+				*uri = image_uri;
+				image_uri = NULL;
+			}
+		} else {
+			*uri = text_uri;
+			text_uri = NULL;
+		}
+	}
+
+	g_free (text_uri);
+	g_free (image_uri);
+}
+
+static void
+mail_display_update_formatter_colors (EMailDisplay *display)
+{
+	EMFormatHTMLColorType type;
+	EMFormatHTML *formatter;
+	GdkColor *color;
+	GtkStyle *style;
+	gint state;
+
+	state = GTK_WIDGET_STATE (display);
+	formatter = display->priv->formatter;
+
+	style = gtk_widget_get_style (GTK_WIDGET (display));
+	if (style == NULL)
+		return;
+
+	g_object_freeze_notify (G_OBJECT (formatter));
+
+	color = &style->bg[state];
+	type = EM_FORMAT_HTML_COLOR_BODY;
+	em_format_html_set_color (formatter, type, color);
+
+	color = &style->base[GTK_STATE_NORMAL];
+	type = EM_FORMAT_HTML_COLOR_CONTENT;
+	em_format_html_set_color (formatter, type, color);
+
+	color = &style->dark[state];
+	type = EM_FORMAT_HTML_COLOR_FRAME;
+	em_format_html_set_color (formatter, type, color);
+
+	color = &style->fg[state];
+	type = EM_FORMAT_HTML_COLOR_HEADER;
+	em_format_html_set_color (formatter, type, color);
+
+	color = &style->text[state];
+	type = EM_FORMAT_HTML_COLOR_TEXT;
+	em_format_html_set_color (formatter, type, color);
+
+	g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+mail_display_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ANIMATE:
+			e_mail_display_set_animate (
+				E_MAIL_DISPLAY (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_CARET_MODE:
+			e_mail_display_set_caret_mode (
+				E_MAIL_DISPLAY (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_FORMATTER:
+			e_mail_display_set_formatter (
+				E_MAIL_DISPLAY (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ANIMATE:
+			g_value_set_boolean (
+				value, e_mail_display_get_animate (
+				E_MAIL_DISPLAY (object)));
+			return;
+
+		case PROP_CARET_MODE:
+			g_value_set_boolean (
+				value, e_mail_display_get_caret_mode (
+				E_MAIL_DISPLAY (object)));
+			return;
+
+		case PROP_FORMATTER:
+			g_value_set_object (
+				value, e_mail_display_get_formatter (
+				E_MAIL_DISPLAY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_dispose (GObject *object)
+{
+	EMailDisplayPrivate *priv;
+
+	priv = E_MAIL_DISPLAY_GET_PRIVATE (object);
+
+	if (priv->formatter) {
+		g_object_unref (priv->formatter);
+		priv->formatter = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_display_realize (GtkWidget *widget)
+{
+	/* Chain up to parent's realize() method. */
+	GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+	mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
+}
+
+static void
+mail_display_style_set (GtkWidget *widget,
+                        GtkStyle *previous_style)
+{
+	EMailDisplayPrivate *priv;
+
+	priv = E_MAIL_DISPLAY_GET_PRIVATE (widget);
+
+	/* 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_redraw (EM_FORMAT (priv->formatter));
+}
+
+static gboolean
+mail_display_button_press_event (GtkWidget *widget,
+                                 GdkEventButton *event)
+{
+	if (event->button == 3) {
+		EMailDisplay *display;
+		EMFormatPURI *puri = NULL;
+		gboolean stop_handlers = TRUE;
+		gchar *uri = NULL;
+
+		display = E_MAIL_DISPLAY (widget);
+		mail_display_get_uri_puri (display, event, &uri, &puri);
+
+		if (uri == NULL || !g_str_has_prefix (uri, "##"))
+			stop_handlers = mail_display_emit_popup_event (
+				display, event, uri, puri);
+
+		g_free (uri);
+
+		if (stop_handlers)
+			return TRUE;
+	}
+
+	/* Chain up to parent's button_press_event() method. */
+	return GTK_WIDGET_CLASS (parent_class)->
+		button_press_event (widget, event);
+}
+
+static gboolean
+mail_display_scroll_event (GtkWidget *widget,
+                           GdkEventScroll *event)
+{
+	if (event->state & GDK_CONTROL_MASK) {
+		switch (event->direction) {
+			case GDK_SCROLL_UP:
+				gtk_html_zoom_in (GTK_HTML (widget));
+				return TRUE;
+			case GDK_SCROLL_DOWN:
+				gtk_html_zoom_out (GTK_HTML (widget));
+				return TRUE;
+			default:
+				break;
+		}
+	}
+
+	return FALSE;
+}
+
+static void
+mail_display_link_clicked (GtkHTML *html,
+                           const gchar *uri)
+{
+	EMailDisplayPrivate *priv;
+
+	priv = E_MAIL_DISPLAY_GET_PRIVATE (html);
+	g_return_if_fail (priv->formatter != NULL);
+
+	if (g_str_has_prefix (uri, "##")) {
+		guint32 flags;
+
+		flags = priv->formatter->header_wrap_flags;
+
+		if (strcmp (uri, "##TO##") == 0) {
+			if (!(flags & EM_FORMAT_HTML_HEADER_TO))
+				flags |= EM_FORMAT_HTML_HEADER_TO;
+			else
+				flags &= ~EM_FORMAT_HTML_HEADER_TO;
+		} else if (strcmp (uri, "##CC##") == 0) {
+			if (!(flags & EM_FORMAT_HTML_HEADER_CC))
+				flags |= EM_FORMAT_HTML_HEADER_CC;
+			else
+				flags |= EM_FORMAT_HTML_HEADER_CC;
+		} else if (strcmp (uri, "##BCC##") == 0) {
+			if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
+				flags |= EM_FORMAT_HTML_HEADER_BCC;
+			else
+				flags |= EM_FORMAT_HTML_HEADER_BCC;
+		}
+
+		priv->formatter->header_wrap_flags = flags;
+		em_format_redraw (EM_FORMAT (priv->formatter));
+
+	} else if (*uri == '#')
+		gtk_html_jump_to_anchor (html, uri + 1);
+
+	else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
+		/* ignore */ ;
+
+	else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
+		/* ignore */ ;
+
+	else {
+		gpointer parent;
+
+		parent = gtk_widget_get_toplevel (GTK_WIDGET (html));
+		parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+		e_show_uri (parent, uri);
+	}
+}
+
+static void
+mail_display_on_url (GtkHTML *html,
+                     const gchar *uri)
+{
+	EMailDisplay *display;
+	CamelInternetAddress *address;
+	CamelURL *curl;
+	const gchar *format = NULL;
+	gchar *message = NULL;
+	gchar *who;
+
+	display = E_MAIL_DISPLAY (html);
+
+	if (uri == NULL || *uri == '\0')
+		goto exit;
+
+	if (g_str_has_prefix (uri, "mailto:";))
+		format = _("Click to mail %s");
+	else if (g_str_has_prefix (uri, "callto:"))
+		format = _("Click to call %s");
+	else if (g_str_has_prefix (uri, "h323:"))
+		format = _("Click to call %s");
+	else if (g_str_has_prefix (uri, "sip:"))
+		format = _("Click to call %s");
+	else if (g_str_has_prefix (uri, "##"))
+		message = g_strdup (_("Click to hide/unhide addresses"));
+	else
+		message = g_strdup_printf (_("Click to open %s"), uri);
+
+	if (format == NULL)
+		goto exit;
+
+	curl = camel_url_new (uri, NULL);
+	address = camel_internet_address_new ();
+	camel_address_decode (CAMEL_ADDRESS (address), curl->path);
+	who = camel_address_format (CAMEL_ADDRESS (address));
+	camel_object_unref (address);
+	camel_url_free (curl);
+
+	if (who == NULL)
+		who = g_strdup (strchr (uri, ':') + 1);
+
+	message = g_strdup_printf (format, who);
+
+	g_free (who);
+
+exit:
+	mail_display_emit_status_message (display, message);
+
+	g_free (message);
+}
+
+static void
+mail_display_iframe_created (GtkHTML *html,
+                             GtkHTML *iframe)
+{
+	g_signal_connect_swapped (
+		iframe, "button-press-event",
+		G_CALLBACK (mail_display_button_press_event), html);
+}
+
+static void
+mail_display_class_init (EMailDisplayClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+	GtkHTMLClass *html_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = mail_display_set_property;
+	object_class->get_property = mail_display_get_property;
+	object_class->dispose = mail_display_dispose;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->realize = mail_display_realize;
+	widget_class->style_set = mail_display_style_set;
+	widget_class->button_press_event = mail_display_button_press_event;
+	widget_class->scroll_event = mail_display_scroll_event;
+
+	html_class = GTK_HTML_CLASS (class);
+	html_class->link_clicked = mail_display_link_clicked;
+	html_class->on_url = mail_display_on_url;
+	html_class->iframe_created = mail_display_iframe_created;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ANIMATE,
+		g_param_spec_boolean (
+			"animate",
+			"Animate Images",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CARET_MODE,
+		g_param_spec_boolean (
+			"caret-mode",
+			"Caret Mode",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FORMATTER,
+		g_param_spec_object (
+			"formatter",
+			"HTML Formatter",
+			NULL,
+			EM_TYPE_FORMAT_HTML,
+			G_PARAM_READWRITE));
+
+	signals[POPUP_EVENT] = g_signal_new (
+		"popup-event",
+		G_TYPE_FROM_CLASS (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EMailDisplayClass, popup_event),
+		g_signal_accumulator_true_handled, NULL,
+		e_marshal_BOOLEAN__BOXED_POINTER_POINTER,
+		G_TYPE_BOOLEAN, 3,
+		GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
+		G_TYPE_POINTER,
+		G_TYPE_POINTER);
+
+	signals[STATUS_MESSAGE] = g_signal_new (
+		"status-message",
+		G_TYPE_FROM_CLASS (class),
+		G_SIGNAL_RUN_FIRST,
+		G_STRUCT_OFFSET (EMailDisplayClass, status_message),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1,
+		G_TYPE_STRING);
+}
+
+static void
+mail_display_init (EMailDisplay *display)
+{
+	display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
+}
+
+GType
+e_mail_display_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailDisplayClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) mail_display_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailDisplay),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) mail_display_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_HTML, "EMailDisplay", &type_info, 0);
+	}
+
+	return type;
+}
+
+gboolean
+e_mail_display_get_animate (EMailDisplay *display)
+{
+	/* XXX This is just here to maintain symmetry
+	 *     with e_mail_display_set_animate(). */
+
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+	return gtk_html_get_animate (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_animate (EMailDisplay *display,
+                            gboolean animate)
+{
+	/* XXX GtkHTML does not utilize GObject properties as well
+	 *     as it could.  This just wraps gtk_html_set_animate()
+	 *     so we can get a "notify::animate" signal. */
+
+	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+	gtk_html_set_animate (GTK_HTML (display), animate);
+
+	g_object_notify (G_OBJECT (display), "animate");
+}
+
+gboolean
+e_mail_display_get_caret_mode (EMailDisplay *display)
+{
+	/* XXX This is just here to maintain symmetry
+	 *     with e_mail_display_get_caret_mode(). */
+
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+	return gtk_html_get_caret_mode (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_caret_mode (EMailDisplay *display,
+                               gboolean caret_mode)
+{
+	/* XXX GtkHTML does not utilize GObject properties as well
+	 *     as it could.  This just wraps gtk_html_set_caret_mode()
+	 *     so we can get a "notify::caret-mode" signal. */
+
+	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+	gtk_html_set_caret_mode (GTK_HTML (display), caret_mode);
+
+	g_object_notify (G_OBJECT (display), "caret-mode");
+}
+
+EMFormatHTML *
+e_mail_display_get_formatter (EMailDisplay *display)
+{
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+	return display->priv->formatter;
+}
+
+void
+e_mail_display_set_formatter (EMailDisplay *display,
+                              EMFormatHTML *formatter)
+{
+	g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+	g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
+
+	if (display->priv->formatter != NULL)
+		g_object_unref (display->priv->formatter);
+
+	display->priv->formatter = g_object_ref (formatter);
+
+	g_object_notify (G_OBJECT (display), "formatter");
+}

Added: branches/kill-bonobo/mail/e-mail-display.h
==============================================================================
--- (empty file)
+++ branches/kill-bonobo/mail/e-mail-display.h	Sun Mar  1 13:16:31 2009
@@ -0,0 +1,83 @@
+/*
+ * e-mail-display.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>  
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_DISPLAY_H
+#define E_MAIL_DISPLAY_H
+
+#include <gtkhtml/gtkhtml.h>
+#include <mail/em-format-html.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_DISPLAY \
+	(e_mail_display_get_type ())
+#define E_MAIL_DISPLAY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplay))
+#define E_MAIL_DISPLAY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
+#define E_IS_MAIL_DISPLAY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_DISPLAY))
+#define E_IS_MAIL_DISPLAY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_DISPLAY))
+#define E_MAIL_DISPLAY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailDisplay EMailDisplay;
+typedef struct _EMailDisplayClass EMailDisplayClass;
+typedef struct _EMailDisplayPrivate EMailDisplayPrivate;
+
+struct _EMailDisplay {
+	GtkHTML parent;
+	EMailDisplayPrivate *priv;
+};
+
+struct _EMailDisplayClass {
+	GtkHTMLClass parent_class;
+
+	/* Signals */
+	gboolean	(*popup_event)		(EMailDisplay *display,
+						 GdkEventButton *event,
+						 const gchar *uri,
+						 EMFormatPURI *puri);
+	void		(*status_message)	(EMailDisplay *display,
+						 const gchar *status_message);
+};
+
+GType		e_mail_display_get_type		(void);
+gboolean	e_mail_display_get_animate	(EMailDisplay *display);
+void		e_mail_display_set_animate	(EMailDisplay *display,
+						 gboolean animate);
+gboolean	e_mail_display_get_caret_mode	(EMailDisplay *display);
+void		e_mail_display_set_caret_mode	(EMailDisplay *display,
+						 gboolean caret_mode);
+EMFormatHTML *	e_mail_display_get_formatter	(EMailDisplay *display);
+void		e_mail_display_set_formatter	(EMailDisplay *display,
+						 EMFormatHTML *formatter);
+
+G_END_DECLS
+
+#endif /* E_MAIL_DISPLAY_H */

Modified: branches/kill-bonobo/mail/e-mail-reader.c
==============================================================================
--- branches/kill-bonobo/mail/e-mail-reader.c	(original)
+++ branches/kill-bonobo/mail/e-mail-reader.c	Sun Mar  1 13:16:31 2009
@@ -1620,40 +1620,6 @@
 	  FALSE }
 };
 
-static void
-mail_reader_link_clicked_cb (EMailReader *reader,
-                             const gchar *uri,
-                             EMFormatHTMLDisplay *html_display)
-{
-	GtkHTML *html;
-	GtkWindow *window;
-	MessageList *message_list;
-	const gchar *folder_uri;
-
-	html = EM_FORMAT_HTML (html_display)->html;
-	message_list = e_mail_reader_get_message_list (reader);
-	window = e_mail_reader_get_window (reader);
-	folder_uri = message_list->folder_uri;
-
-	if (g_str_has_prefix (uri, "##"))
-		return;
-
-	if (g_ascii_strncasecmp (uri, "mailto:";, 7) == 0)
-		em_utils_compose_new_message_with_mailto (uri, folder_uri);
-
-	else if (*uri == '#')
-		gtk_html_jump_to_anchor (html, uri + 1);
-
-	else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
-		/* ignore */ ;
-
-	else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
-		/* ignore */ ;
-
-	else
-		e_show_uri (window, uri);
-}
-
 static gboolean
 mail_reader_html_button_release_event_cb (EMailReader *reader,
                                           GdkEventButton *button,
@@ -2057,6 +2023,7 @@
 	MessageList *message_list;
 	GConfBridge *bridge;
 	GtkAction *action;
+	GtkHTML *html;
 	const gchar *action_name;
 	const gchar *key;
 
@@ -2070,6 +2037,8 @@
 	shell = e_shell_module_get_shell (shell_module);
 	shell_settings = e_shell_get_shell_settings (shell);
 
+	html = EM_FORMAT_HTML (html_display)->html;
+
 	gtk_action_group_add_actions (
 		action_group, mail_reader_entries,
 		G_N_ELEMENTS (mail_reader_entries), reader);
@@ -2136,7 +2105,7 @@
 
 	e_binding_new (
 		G_OBJECT (shell_settings), "mail-show-animated-images",
-		G_OBJECT (html_display), "animate");
+		G_OBJECT (html), "animate");
 
 	e_binding_new (
 		G_OBJECT (shell_settings), "mail-show-sender-photo",
@@ -2147,15 +2116,11 @@
 
 	e_mutual_binding_new (
 		G_OBJECT (action), "active",
-		G_OBJECT (html_display), "caret-mode");
+		G_OBJECT (html), "caret-mode");
 
 	/* Connect signals. */
 
 	g_signal_connect_swapped (
-		html_display, "link-clicked",
-		G_CALLBACK (mail_reader_link_clicked_cb), reader);
-
-	g_signal_connect_swapped (
 		EM_FORMAT_HTML (html_display)->html, "button-release-event",
 		G_CALLBACK (mail_reader_html_button_release_event_cb), reader);
 

Modified: branches/kill-bonobo/mail/e-mail-shell-view-private.c
==============================================================================
--- branches/kill-bonobo/mail/e-mail-shell-view-private.c	(original)
+++ branches/kill-bonobo/mail/e-mail-shell-view-private.c	Sun Mar  1 13:16:31 2009
@@ -89,6 +89,19 @@
 }
 
 static void
+mail_shell_view_reader_status_message_cb (EMailShellView *mail_shell_view,
+                                          const gchar *status_message)
+{
+	EShellView *shell_view;
+	EShellTaskbar *shell_taskbar;
+
+	shell_view = E_SHELL_VIEW (mail_shell_view);
+	shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
+
+	e_shell_taskbar_set_message (shell_taskbar, status_message);
+}
+
+static void
 mail_shell_view_load_view_collection (EShellViewClass *shell_view_class)
 {
 	GalViewCollection *collection;
@@ -160,6 +173,7 @@
 	EShellSettings *shell_settings;
 	EShellSidebar *shell_sidebar;
 	EShellWindow *shell_window;
+	EMFormatHTMLDisplay *html_display;
 	EMFolderTreeModel *folder_tree_model;
 	EMFolderTree *folder_tree;
 	RuleContext *context;
@@ -168,6 +182,7 @@
 	GtkUIManager *ui_manager;
 	MessageList *message_list;
 	EMailReader *reader;
+	GtkHTML *html;
 	const gchar *source;
 	guint merge_id;
 	gchar *uri;
@@ -197,11 +212,14 @@
 	priv->mail_shell_sidebar = g_object_ref (shell_sidebar);
 
 	reader = E_MAIL_READER (shell_content);
+	html_display = e_mail_reader_get_html_display (reader);
 	message_list = e_mail_reader_get_message_list (reader);
 
 	mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
 	folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
 
+	html = EM_FORMAT_HTML (html_display)->html;
+
 	g_signal_connect_swapped (
 		folder_tree, "folder-selected",
 		G_CALLBACK (mail_shell_view_folder_tree_selected_cb),
@@ -243,6 +261,11 @@
 		G_CALLBACK (e_mail_shell_view_update_search_filter),
 		mail_shell_view);
 
+	g_signal_connect_swapped (
+		html, "status-message",
+		G_CALLBACK (mail_shell_view_reader_status_message_cb),
+		mail_shell_view);
+
 	e_mail_shell_view_actions_init (mail_shell_view);
 	e_mail_shell_view_update_search_filter (mail_shell_view);
 	e_mail_reader_init (reader);

Modified: branches/kill-bonobo/mail/em-folder-view.c
==============================================================================
--- branches/kill-bonobo/mail/em-folder-view.c	(original)
+++ branches/kill-bonobo/mail/em-folder-view.c	Sun Mar  1 13:16:31 2009
@@ -238,7 +238,7 @@
 //	em_format_set_session ((EMFormat *) emfv->preview, session);
 //	g_signal_connect(emfv->preview, "link_clicked", G_CALLBACK(emfv_format_link_clicked), emfv);
 	g_signal_connect(emfv->preview, "popup_event", G_CALLBACK(emfv_format_popup_event), emfv);
-	g_signal_connect (emfv->preview, "on_url", G_CALLBACK (emfv_on_url_cb), emfv);
+//	g_signal_connect (emfv->preview, "on_url", G_CALLBACK (emfv_on_url_cb), emfv);
 //	g_signal_connect (((EMFormatHTML *)emfv->preview)->html, "button-release-event", G_CALLBACK (emfv_on_html_button_released_cb), emfv);
 //#ifdef ENABLE_PROFILING
 //	g_signal_connect(emfv->preview, "complete", G_CALLBACK (emfv_format_complete), emfv);
@@ -268,7 +268,7 @@
 	((EMFolderViewClass *)klass)->set_message = emfv_set_message;
 	((EMFolderViewClass *)klass)->activate = emfv_activate;
 
-	((EMFolderViewClass *)klass)->on_url = emfv_on_url;
+//	((EMFolderViewClass *)klass)->on_url = emfv_on_url;
 
 	signals[EMFV_ON_URL] = g_signal_new ("on-url",
 					     G_OBJECT_CLASS_TYPE (klass),
@@ -1077,58 +1077,3 @@
 		break; }
 	}
 }
-
-static void
-emfv_on_url (EMFolderView *emfv, const char *uri, const char *nice_uri)
-{
-	if (emfv->statusbar_active) {
-		if (emfv->uic) {
-			bonobo_ui_component_set_status (emfv->uic, nice_uri, NULL);
-			/* Make sure the node keeps existing if nice_url == NULL */
-			if (!nice_uri)
-				bonobo_ui_component_set_translate (
-					emfv->uic, "/", "<status><item name=\"main\"/></status>", NULL);
-		}
-	}
-}
-
-static void
-emfv_on_url_cb (GObject *emitter, const char *url, EMFolderView *emfv)
-{
-	char *nice_url = NULL;
-
-	if (url) {
-		if (strncmp (url, "mailto:";, 7) == 0) {
-			CamelInternetAddress *cia = camel_internet_address_new();
-			CamelURL *curl;
-			char *addr;
-
-			curl = camel_url_new(url, NULL);
-			camel_address_decode((CamelAddress *)cia, curl->path);
-			addr = camel_address_format((CamelAddress *)cia);
-			nice_url = g_strdup_printf (_("Click to mail %s"), addr&&addr[0]?addr:(url + 7));
-			g_free(addr);
-			camel_url_free(curl);
-			camel_object_unref(cia);
-		} else if (strncmp (url, "callto:", 7) == 0 || strncmp (url, "h323:", 5) == 0 || strncmp (url, "sip:", 4) == 0) {
-			CamelInternetAddress *cia = camel_internet_address_new();
-			CamelURL *curl;
-			char *addr;
-
-			curl = camel_url_new(url, NULL);
-			camel_address_decode((CamelAddress *)cia, curl->path);
-			addr = camel_address_format((CamelAddress *)cia);
-			nice_url = g_strdup_printf (_("Click to call %s"), addr&&addr[0]?addr:(url + 7));
-			g_free(addr);
-			camel_url_free(curl);
-			camel_object_unref(cia);
-		} else if (!strncmp (url, "##", 2)) {
-			nice_url = g_strdup (_("Click to hide/unhide addresses"));
-		} else
-			nice_url = g_strdup_printf (_("Click to open %s"), url);
-	}
-
-	g_signal_emit (emfv, signals[EMFV_ON_URL], 0, url, nice_url);
-
-	g_free (nice_url);
-}

Modified: branches/kill-bonobo/mail/em-format-html-display.c
==============================================================================
--- branches/kill-bonobo/mail/em-format-html-display.c	(original)
+++ branches/kill-bonobo/mail/em-format-html-display.c	Sun Mar  1 13:16:31 2009
@@ -75,6 +75,7 @@
 
 #include "mail-config.h"
 
+#include "e-mail-display.h"
 #include "em-format-html-display.h"
 #include "e-searching-tokenizer.h"
 #include "em-icon-stream.h"
@@ -126,20 +127,47 @@
 	gboolean updated;
 };
 
-enum {
-	PROP_0,
-	PROP_ANIMATE,
-	PROP_CARET_MODE
+struct _smime_pobject {
+	EMFormatHTMLPObject object;
+
+	int signature;
+	CamelCipherValidity *valid;
+	GtkWidget *widget;
+};
+
+/* TODO: move the dialogue elsehwere */
+/* FIXME: also in em-format-html.c */
+static const struct {
+	const char *icon, *shortdesc, *description;
+} smime_sign_table[5] = {
+	{ "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") },
+	{ "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") },
+	{ "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") },
+	{ "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") },
+	{ "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") },
+
+};
+
+static const struct {
+	const char *icon, *shortdesc, *description;
+} smime_encrypt_table[4] = {
+	{ "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") },
+	{ "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") },
+	{ "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted.  It would be difficult for an outsider to view the content of this message.") },
+	{ "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") },
 };
 
-static int efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efh);
-static void efhd_html_link_clicked (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd);
-static void efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd);
+static const char *smime_sign_colour[5] = {
+	"", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\"",""
+};
 
 static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri);
 static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
 static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
 static void efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
+static void efhd_attachment_button_show (GtkWidget *w, void *data);
+static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
+static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object);
 static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd);
 
 struct _attach_puri {
@@ -177,151 +205,250 @@
 };
 
 
-static void efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh);
-/*static void efhd_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTMLDisplay *efh);
-  static gboolean efhd_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTMLDisplay *efh);*/
-
 static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info);
 
-static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_type);
-static void efhd_format_clone(EMFormat *, CamelFolder *folder, const char *, CamelMimeMessage *msg, EMFormat *);
-static void efhd_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
-static void efhd_format_source(EMFormat *, CamelStream *, CamelMimePart *);
-static void efhd_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
-static void efhd_format_optional(EMFormat *, CamelStream *, CamelMimePart *, CamelStream *);
-static void efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
 static void efhd_complete(EMFormat *);
 gboolean efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd);
 
 static void efhd_builtin_init(EMFormatHTMLDisplayClass *efhc);
 
-enum {
-	EFHD_LINK_CLICKED,
-	EFHD_POPUP_EVENT,
-	EFHD_ON_URL,
-	EFHD_LAST_SIGNAL,
-};
-
-static guint efhd_signals[EFHD_LAST_SIGNAL] = { 0 };
-
-static EMFormatHTMLClass *efhd_parent;
-static EMFormatClass *efhd_format_class;
+static EMFormatHTMLClass *parent_class;
 
 static void
-efhd_gtkhtml_realize(GtkHTML *html, EMFormatHTMLDisplay *efhd)
+efhd_xpkcs7mime_free (EMFormatHTMLPObject *o)
 {
-	EMFormatHTMLColorType type;
-	EMFormatHTML *efh;
-	GdkColor *color;
-	GtkStyle *style;
-	gint state;
+	struct _smime_pobject *po = (struct _smime_pobject *)o;
 
-	efh = EM_FORMAT_HTML (efhd);
-	state = GTK_WIDGET_STATE (html);
+	if (po->widget)
+		gtk_widget_destroy(po->widget);
+	camel_cipher_validity_free(po->valid);
+}
 
-	style = gtk_widget_get_style (GTK_WIDGET (html));
-	if (style == NULL)
-		return;
+static void
+efhd_xpkcs7mime_info_response (GtkWidget *widget,
+                               guint button,
+                               struct _smime_pobject *po)
+{
+	gtk_widget_destroy (widget);
+	po->widget = NULL;
+}
 
-	g_object_freeze_notify (G_OBJECT (efh));
+#ifdef HAVE_NSS
+static void
+efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button,
+                                  struct _smime_pobject *po)
+{
+	CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info");
+	ECertDB *db = e_cert_db_peek();
+	ECert *ec = NULL;
 
-	color = &style->bg[state];
-	type = EM_FORMAT_HTML_COLOR_BODY;
-	em_format_html_set_color (efh, type, color);
+	if (info->email)
+		ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL);
 
-	color = &style->base[GTK_STATE_NORMAL];
-	type = EM_FORMAT_HTML_COLOR_CONTENT;
-	em_format_html_set_color (efh, type, color);
+	if (ec == NULL && info->name)
+		ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL);
 
-	color = &style->dark[state];
-	type = EM_FORMAT_HTML_COLOR_FRAME;
-	em_format_html_set_color (efh, type, color);
+	if (ec != NULL) {
+		GtkWidget *w = certificate_viewer_show(ec);
 
-	color = &style->fg[state];
-	type = EM_FORMAT_HTML_COLOR_HEADER;
-	em_format_html_set_color (efh, type, color);
+		/* oddly enough certificate_viewer_show doesn't ... */
+		gtk_widget_show(w);
+		g_signal_connect(w, "response", G_CALLBACK(gtk_widget_destroy), NULL);
 
-	color = &style->text[state];
-	type = EM_FORMAT_HTML_COLOR_TEXT;
-	em_format_html_set_color (efh, type, color);
+		if (w && po->widget)
+			gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)po->widget);
 
-	g_object_thaw_notify (G_OBJECT (efh));
+		g_object_unref(ec);
+	} else {
+		g_warning("can't find certificate for %s <%s>", info->name?info->name:"", info->email?info->email:"");
+	}
 }
+#endif
 
 static void
-efhd_gtkhtml_style_set(GtkHTML *html, GtkStyle *old, EMFormatHTMLDisplay *efhd)
+efhd_xpkcs7mime_add_cert_table (GtkWidget *vbox,
+                                CamelDList *certlist,
+                                struct _smime_pobject *po)
 {
-	efhd_gtkhtml_realize(html, efhd);
-	em_format_redraw((EMFormat *)efhd);
+	CamelCipherCertInfo *info = (CamelCipherCertInfo *)certlist->head;
+	GtkTable *table = (GtkTable *)gtk_table_new(camel_dlist_length(certlist), 2, FALSE);
+	int n = 0;
+
+	while (info->next) {
+		char *la = NULL;
+		const char *l = NULL;
+
+		if (info->name) {
+			if (info->email && strcmp(info->name, info->email) != 0)
+				l = la = g_strdup_printf("%s <%s>", info->name, info->email);
+			else
+				l = info->name;
+		} else {
+			if (info->email)
+				l = info->email;
+		}
+
+		if (l) {
+			GtkWidget *w;
+#if defined(HAVE_NSS)
+			ECertDB *db = e_cert_db_peek();
+			ECert *ec = NULL;
+#endif
+			w = gtk_label_new(l);
+			gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
+			g_free(la);
+			gtk_table_attach(table, w, 0, 1, n, n+1, GTK_FILL, GTK_FILL, 3, 3);
+#if defined(HAVE_NSS)
+			w = gtk_button_new_with_mnemonic(_("_View Certificate"));
+			gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3);
+			g_object_set_data((GObject *)w, "e-cert-info", info);
+			g_signal_connect(w, "clicked", G_CALLBACK(efhd_xpkcs7mime_viewcert_clicked), po);
+
+			if (info->email)
+				ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL);
+			if (ec == NULL && info->name)
+				ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL);
+
+			if (ec == NULL)
+				gtk_widget_set_sensitive(w, FALSE);
+			else
+				g_object_unref(ec);
+#else
+			w = gtk_label_new (_("This certificate is not viewable"));
+			gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3);
+#endif
+			n++;
+		}
+
+		info = info->next;
+	}
+
+	gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)table, TRUE, TRUE, 6);
 }
 
 static void
-efhd_init(GObject *o)
+efhd_xpkcs7mime_validity_clicked (GtkWidget *button,
+                                  EMFormatHTMLPObject *pobject)
 {
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)o;
-#define efh ((EMFormatHTML *)efhd)
+	struct _smime_pobject *po = (struct _smime_pobject *)pobject;
+	GladeXML *xml;
+	GtkWidget *vbox, *w;
+	char *gladefile;
+
+	if (po->widget)
+		/* FIXME: window raise? */
+		return;
 
-	efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE(efhd);
+	gladefile = g_build_filename (
+		EVOLUTION_GLADEDIR, "mail-dialogs.glade", NULL);
+	xml = glade_xml_new (gladefile, "message_security_dialog", NULL);
+	g_free (gladefile);
 
-	efhd->search_tok = (ESearchingTokenizer *)e_searching_tokenizer_new();
-	gtk_html_set_tokenizer (efh->html, (HTMLTokenizer *)efhd->search_tok);
+	po->widget = glade_xml_get_widget(xml, "message_security_dialog");
 
-	g_signal_connect(efh->html, "realize", G_CALLBACK(efhd_gtkhtml_realize), o);
-	g_signal_connect(efh->html, "style-set", G_CALLBACK(efhd_gtkhtml_style_set), o);
-	/* we want to convert url's etc */
-	efh->text_html_flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
-#undef efh
+	vbox = glade_xml_get_widget(xml, "signature_vbox");
+	w = gtk_label_new (_(smime_sign_table[po->valid->sign.status].description));
+	gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
+	gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
+	gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
+	if (po->valid->sign.description) {
+		GtkTextBuffer *buffer;
 
-	efhd->nobar = getenv("EVOLUTION_NO_BAR") != NULL;
+		buffer = gtk_text_buffer_new(NULL);
+		gtk_text_buffer_set_text(buffer, po->valid->sign.description, strlen(po->valid->sign.description));
+		w = g_object_new(gtk_scrolled_window_get_type(),
+				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "shadow_type", GTK_SHADOW_IN,
+				 "child", g_object_new(gtk_text_view_get_type(),
+						       "buffer", buffer,
+						       "cursor_visible", FALSE,
+						       "editable", FALSE,
+						       "width_request", 500,
+						       "height_request", 160,
+						       NULL),
+				 NULL);
+		g_object_unref(buffer);
 
-	efhd->priv->show_bar = FALSE;
-	efhd->priv->files = NULL;
-}
+		gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
+	}
 
-static void
-efhd_set_property (GObject *object,
-                   guint property_id,
-                   const GValue *value,
-                   GParamSpec *pspec)
-{
-	switch (property_id) {
-		case PROP_ANIMATE:
-			em_format_html_display_set_animate (
-				EM_FORMAT_HTML_DISPLAY (object),
-				g_value_get_boolean (value));
-			return;
+	if (!camel_dlist_empty(&po->valid->sign.signers))
+		efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->sign.signers, po);
 
-		case PROP_CARET_MODE:
-			em_format_html_display_set_caret_mode (
-				EM_FORMAT_HTML_DISPLAY (object),
-				g_value_get_boolean (value));
-			return;
+	gtk_widget_show_all(vbox);
+
+	vbox = glade_xml_get_widget(xml, "encryption_vbox");
+	w = gtk_label_new(_(smime_encrypt_table[po->valid->encrypt.status].description));
+	gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
+	gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
+	gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
+	if (po->valid->encrypt.description) {
+		GtkTextBuffer *buffer;
+
+		buffer = gtk_text_buffer_new(NULL);
+		gtk_text_buffer_set_text(buffer, po->valid->encrypt.description, strlen(po->valid->encrypt.description));
+		w = g_object_new(gtk_scrolled_window_get_type(),
+				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+				 "shadow_type", GTK_SHADOW_IN,
+				 "child", g_object_new(gtk_text_view_get_type(),
+						       "buffer", buffer,
+						       "cursor_visible", FALSE,
+						       "editable", FALSE,
+						       "width_request", 500,
+						       "height_request", 160,
+						       NULL),
+				 NULL);
+		g_object_unref(buffer);
+
+		gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
 	}
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	if (!camel_dlist_empty(&po->valid->encrypt.encrypters))
+		efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->encrypt.encrypters, po);
+
+	gtk_widget_show_all(vbox);
+
+	g_object_unref(xml);
+
+	g_signal_connect(po->widget, "response", G_CALLBACK(efhd_xpkcs7mime_info_response), po);
+	gtk_widget_show(po->widget);
 }
 
-static void
-efhd_get_property (GObject *object,
-                   guint property_id,
-                   GValue *value,
-                   GParamSpec *pspec)
+static gboolean
+efhd_xpkcs7mime_button (EMFormatHTML *efh,
+                        GtkHTMLEmbedded *eb,
+                        EMFormatHTMLPObject *pobject)
 {
-	switch (property_id) {
-		case PROP_ANIMATE:
-			g_value_set_boolean (
-				value, em_format_html_display_get_animate (
-				EM_FORMAT_HTML_DISPLAY (object)));
-			return;
+	GtkWidget *container;
+	GtkWidget *widget;
+	struct _smime_pobject *po = (struct _smime_pobject *)pobject;
+	const char *icon_name;
 
-		case PROP_CARET_MODE:
-			g_value_set_boolean (
-				value, em_format_html_display_get_caret_mode (
-				EM_FORMAT_HTML_DISPLAY (object)));
-			return;
-	}
+	/* FIXME: need to have it based on encryption and signing too */
+	if (po->valid->sign.status != 0)
+		icon_name = smime_sign_table[po->valid->sign.status].icon;
+	else
+		icon_name = smime_encrypt_table[po->valid->encrypt.status].icon;
+
+	container = GTK_WIDGET (eb);
+
+	widget = gtk_button_new ();
+	g_signal_connect (
+		widget, "clicked",
+		G_CALLBACK (efhd_xpkcs7mime_validity_clicked), pobject);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
 
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	container = widget;
+
+	widget = gtk_image_new_from_icon_name (
+		icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	return TRUE;
 }
 
 static void
@@ -337,206 +464,294 @@
 	g_free (priv->search_text);
 
 	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (efhd_parent)->finalize (object);
+	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static gboolean
-efhd_bool_accumulator(GSignalInvocationHint *ihint, GValue *out, const GValue *in, void *data)
+static void
+efhd_format_clone (EMFormat *emf,
+                   CamelFolder *folder,
+                   const gchar *uid,
+                   CamelMimeMessage *msg,
+                   EMFormat *src)
 {
-	gboolean val = g_value_get_boolean(in);
+	EMFormatHTMLDisplayPrivate *priv;
+
+	priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (emf);
 
-	g_value_set_boolean(out, val);
+	if (emf != src) {
+		priv->show_bar = (src != NULL) ?
+			EM_FORMAT_HTML_DISPLAY (src)->priv->show_bar : FALSE;
+
+		EM_FORMAT_HTML (emf)->header_wrap_flags = 0;
+	}
 
-	return !val;
+	/* Chain up to parent's format_clone() method. */
+	EM_FORMAT_CLASS (parent_class)->
+		format_clone (emf, folder, uid, msg, src);
 }
 
 static void
-efhd_class_init (GObjectClass *class)
+efhd_format_attachment (EMFormat *emf,
+                        CamelStream *stream,
+                        CamelMimePart *part,
+                        const gchar *mime_type,
+                        const EMFormatHandler *handle)
 {
-	GObjectClass *object_class;
-	EMFormatClass *format_class;
+	char *classid, *text, *html;
+	struct _attach_puri *info;
 
-	g_type_class_add_private (class, sizeof (EMFormatHTMLDisplayPrivate));
+	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);
+	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_from_mime_part (info->puri.part);
+	e_attachment_bar_create_attachment_cache (info->attachment);
 
-	object_class = G_OBJECT_CLASS (class);
-	object_class->set_property = efhd_set_property;
-	object_class->get_property = efhd_get_property;
-	object_class->finalize = efhd_finalize;
+	if (emf->valid) {
+		info->sign = emf->valid->sign.status;
+		info->encrypt = emf->valid->encrypt.status;
+	}
 
-	format_class = EM_FORMAT_CLASS (class);
-	format_class->find_handler = efhd_find_handler;
-	format_class->format_clone = efhd_format_clone;
-	format_class->format_error = efhd_format_error;
-	format_class->format_source = efhd_format_source;
-	format_class->format_attachment = efhd_format_attachment;
-	format_class->format_optional = efhd_format_optional;
-	format_class->format_secure = efhd_format_secure;
-	format_class->complete = efhd_complete;
+	camel_stream_write_string(
+		stream, EM_FORMAT_HTML_VPAD
+		"<table cellspacing=0 cellpadding=0><tr><td>"
+		"<table width=10 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td>");
+
+	camel_stream_printf (
+		stream, "<td><object classid=\"%s\"></object></td>", classid);
+
+	camel_stream_write_string (
+		stream, "<td><table width=3 cellspacing=0 cellpadding=0>"
+		"<tr><td></td></tr></table></td><td><font size=-1>");
 
-	g_object_class_install_property (
-		object_class,
-		PROP_ANIMATE,
-		g_param_spec_boolean (
-			"animate",
-			"Animate Images",
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_CARET_MODE,
-		g_param_spec_boolean (
-			"caret-mode",
-			"Caret Mode",
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE));
-
-	efhd_signals[EFHD_LINK_CLICKED] =
-		g_signal_new("link_clicked",
-			     G_TYPE_FROM_CLASS(class),
-			     G_SIGNAL_RUN_LAST,
-			     G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, link_clicked),
-			     NULL, NULL,
-			     g_cclosure_marshal_VOID__POINTER,
-			     G_TYPE_NONE, 1, G_TYPE_POINTER);
-
-	efhd_signals[EFHD_POPUP_EVENT] =
-		g_signal_new("popup_event",
-			     G_TYPE_FROM_CLASS(class),
-			     G_SIGNAL_RUN_LAST,
-			     G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, popup_event),
-			     efhd_bool_accumulator, NULL,
-			     e_marshal_BOOLEAN__BOXED_POINTER_POINTER,
-			     G_TYPE_BOOLEAN, 3,
-			     GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
-			     G_TYPE_POINTER, G_TYPE_POINTER);
-
-	efhd_signals[EFHD_ON_URL] =
-		g_signal_new("on_url",
-			     G_TYPE_FROM_CLASS(class),
-			     G_SIGNAL_RUN_LAST,
-			     G_STRUCT_OFFSET(EMFormatHTMLDisplayClass, on_url),
-			     NULL, NULL,
-			     g_cclosure_marshal_VOID__STRING,
-			     G_TYPE_NONE, 1,
-			     G_TYPE_STRING);
+	/* output some info about it */
+	/* FIXME: should we look up mime_type from object again? */
+	text = em_format_describe_part (part, mime_type);
+	html = camel_text_to_html (
+		text, EM_FORMAT_HTML (emf)->text_html_flags &
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	camel_stream_write_string (stream, html);
+	g_free (html);
+	g_free (text);
+
+	camel_stream_write_string (
+		stream, "</font></td></tr><tr></table>\n"
+		EM_FORMAT_HTML_VPAD);
+
+	if (handle && info->shown)
+		handle->handler (emf, stream, part, handle);
 
-	efhd_builtin_init((EMFormatHTMLDisplayClass *)class);
+	g_free (classid);
 }
 
-GType
-em_format_html_display_get_type (void)
+static void
+efhd_format_optional (EMFormat *emf,
+                      CamelStream *fstream,
+                      CamelMimePart *part,
+                      CamelStream *mstream)
 {
-	static GType type = 0;
+	char *classid, *html;
+	struct _attach_puri *info;
+	CamelStream *stream;
 
-	if (type == 0) {
-		static const GTypeInfo info = {
-			sizeof(EMFormatHTMLDisplayClass),
-			NULL, NULL,
-			(GClassInitFunc)efhd_class_init,
-			NULL, NULL,
-			sizeof(EMFormatHTMLDisplay), 0,
-			(GInstanceInitFunc)efhd_init
-		};
-		efhd_parent = g_type_class_ref(em_format_html_get_type());
-		efhd_format_class = g_type_class_ref(em_format_get_type());
-		type = g_type_register_static(em_format_html_get_type(), "EMFormatHTMLDisplay", &info, 0);
+	if (CAMEL_IS_STREAM_FILTER (fstream) && ((CamelStreamFilter *) fstream)->source)
+		stream = ((CamelStreamFilter *) fstream)->source;
+	else
+		stream = fstream;
+
+	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);
+	em_format_html_add_pobject (
+		EM_FORMAT_HTML (emf), sizeof (EMFormatHTMLPObject),
+		classid, part, efhd_attachment_optional);
+	info->handle = em_format_find_handler (emf, "text/plain");
+	info->shown = FALSE;
+	info->snoop_mime_type = "text/plain";
+	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
+	info->mstream = (CamelStreamMem *) mstream;
+	if (emf->valid) {
+		info->sign = emf->valid->sign.status;
+		info->encrypt = emf->valid->encrypt.status;
 	}
 
-	return type;
-}
+	camel_stream_write_string (
+		stream, 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);
+	camel_stream_write_string (stream, html);
+	camel_stream_write_string (
+		stream, "</font></h3></td></tr></table>\n");
+	camel_stream_write_string (
+		stream, "<table cellspacing=0 cellpadding=0><tr>");
+	camel_stream_printf (
+		stream, "<td><object classid=\"%s\"></object>"
+		"</td></tr></table>", classid);
 
-static gboolean
-efhd_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd)
-{
-	if(event->state & GDK_CONTROL_MASK)
-	{
-		if(event->direction == GDK_SCROLL_UP)
-		{
-			gtk_html_zoom_in (efhd->parent.html);
-		}
-		else if(event->direction == GDK_SCROLL_DOWN)
-		{
-			gtk_html_zoom_out (efhd->parent.html);
-		}
-		return TRUE;
-	}
-	return FALSE;
+	g_free(html);
+
+	camel_stream_write_string (
+		stream, EM_FORMAT_HTML_VPAD);
+
+	g_free (classid);
 }
 
-EMFormatHTMLDisplay *em_format_html_display_new(void)
+static void
+efhd_format_secure (EMFormat *emf,
+                    CamelStream *stream,
+                    CamelMimePart *part,
+                    CamelCipherValidity *valid)
 {
-	EMFormatHTMLDisplay *efhd;
+	EM_FORMAT_CLASS (parent_class)->
+		format_secure (emf, stream, part, valid);
 
-	efhd = g_object_new(em_format_html_display_get_type(), 0);
+	if (emf->valid == valid
+	    && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
+		|| valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
+		char *classid;
+		struct _smime_pobject *pobj;
 
-	g_signal_connect(efhd->parent.html, "iframe_created", G_CALLBACK(efhd_iframe_created), efhd);
-	g_signal_connect(efhd->parent.html, "link_clicked", G_CALLBACK(efhd_html_link_clicked), efhd);
-	g_signal_connect(efhd->parent.html, "on_url", G_CALLBACK(efhd_html_on_url), efhd);
-	g_signal_connect(efhd->parent.html, "button_press_event", G_CALLBACK(efhd_html_button_press_event), efhd);
-	g_signal_connect(efhd->parent.html,"scroll_event", G_CALLBACK(efhd_scroll_event), efhd);
+		camel_stream_printf (
+			stream, "<table border=0 width=\"100%%\" "
+			"cellpadding=3 cellspacing=0%s><tr>",
+			smime_sign_colour[valid->sign.status]);
+
+		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;
+		camel_stream_printf (
+			stream, "<td valign=center><object classid=\"%s\">"
+			"</object></td><td width=100%% valign=center>",
+			classid);
+		g_free (classid);
 
-	return efhd;
-}
+		if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+			const gchar *desc;
+			gint status;
 
-gboolean
-em_format_html_display_get_animate (EMFormatHTMLDisplay *efhd)
-{
-	GtkHTML *html;
+			status = valid->sign.status;
+			desc = smime_sign_table[status].shortdesc;
+			camel_stream_printf (stream, "%s", gettext (desc));
+		}
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd), FALSE);
+		if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
+			const gchar *desc;
+			gint status;
 
-	html = ((EMFormatHTML *) efhd)->html;
+			if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
+				camel_stream_printf (stream, "<br>");
+			}
 
-	return gtk_html_get_animate (html);
+			status = valid->encrypt.status;
+			desc = smime_encrypt_table[status].shortdesc;
+			camel_stream_printf (stream, "%s", gettext (desc));
+		}
+
+		camel_stream_printf(stream, "</td></tr></table>");
+	}
 }
 
-void
-em_format_html_display_set_animate (EMFormatHTMLDisplay *efhd,
-                                    gboolean animate)
+static void
+efhd_class_init (EMFormatHTMLDisplayClass *class)
 {
-	GtkHTML *html;
+	GObjectClass *object_class;
+	EMFormatClass *format_class;
+	EMFormatHTMLClass *format_html_class;
 
-	/* XXX Note this is imperfect.  If animate is set by
-	 *     some other means we won't emit a notification. */
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMFormatHTMLDisplayPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = efhd_finalize;
 
-	g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd));
+	format_class = EM_FORMAT_CLASS (class);
+	format_class->format_clone = efhd_format_clone;
+	format_class->format_attachment = efhd_format_attachment;
+	format_class->format_optional = efhd_format_optional;
+	format_class->format_secure = efhd_format_secure;
+	format_class->complete = efhd_complete;
 
-	html = ((EMFormatHTML *) efhd)->html;
-	gtk_html_set_animate (html, animate);
+	format_html_class = EM_FORMAT_HTML_CLASS (class);
+	format_html_class->html_widget_type = E_TYPE_MAIL_DISPLAY;
 
-	g_object_notify (G_OBJECT (efhd), "animate");
+	efhd_builtin_init (class);
 }
 
-gboolean
-em_format_html_display_get_caret_mode (EMFormatHTMLDisplay *efhd)
+static void
+efhd_init (EMFormatHTMLDisplay *efhd)
 {
 	GtkHTML *html;
 
-	g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd), FALSE);
+	html = EM_FORMAT_HTML (efhd)->html;
+
+	efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efhd);
+
+	e_mail_display_set_formatter (
+		E_MAIL_DISPLAY (html), EM_FORMAT_HTML (efhd));
 
-	html = ((EMFormatHTML *) efhd)->html;
+	efhd->search_tok =
+		(ESearchingTokenizer *) e_searching_tokenizer_new ();
+	gtk_html_set_tokenizer (html, (HTMLTokenizer *) efhd->search_tok);
 
-	return gtk_html_get_caret_mode (html);
+	/* we want to convert url's etc */
+	EM_FORMAT_HTML (efhd)->text_html_flags |=
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+
+	efhd->priv->show_bar = FALSE;
+	efhd->priv->files = NULL;
 }
 
-void
-em_format_html_display_set_caret_mode (EMFormatHTMLDisplay *efhd,
-                                       gboolean caret_mode)
+GType
+em_format_html_display_get_type (void)
 {
-	GtkHTML *html;
+	static GType type = 0;
 
-	/* XXX Note this is imperfect.  If caret mode is set by
-	 *     some other means we won't emit a notification. */
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMFormatHTMLDisplayClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) efhd_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMFormatHTMLDisplay),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) efhd_init,
+			NULL   /* value_table */
+		};
 
-	g_return_if_fail (EM_IS_FORMAT_HTML_DISPLAY (efhd));
+		type = g_type_register_static (
+			EM_TYPE_FORMAT_HTML, "EMFormatHTMLDisplay",
+			&type_info, 0);
+	}
 
-	html = ((EMFormatHTML *) efhd)->html;
-	gtk_html_set_caret_mode (html, caret_mode);
+	return type;
+}
 
-	g_object_notify (G_OBJECT (efhd), "caret-mode");
+EMFormatHTMLDisplay *
+em_format_html_display_new (void)
+{
+	return g_object_new (EM_TYPE_FORMAT_HTML_DISPLAY, NULL);
 }
 
 EAttachmentBar *
@@ -779,579 +994,138 @@
 
 	efhd_update_matches(efhd);
 
-	return (GtkWidget *)p->search_dialog;
-
-}
-
-static void
-set_focus_cb (GtkWidget *window, GtkWidget *widget, EMFormatHTMLDisplay *efhd)
-{
-	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
-	GtkWidget *sbar = GTK_WIDGET (p->search_dialog);
-
-	while (widget != NULL && widget != sbar) {
-		widget = widget->parent;
-    	}
-
-	if (widget != sbar)
-		efhd_search_destroy(widget, efhd);
-}
-
-/**
- * em_format_html_display_search:
- * @efhd:
- *
- * Run an interactive search dialogue.
- **/
-void
-em_format_html_display_search(EMFormatHTMLDisplay *efhd)
-{
-	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
-
-	if (p->search_dialog){
-		GtkWidget *toplevel;
-
-		gtk_widget_show (GTK_WIDGET (p->search_dialog));
-		gtk_widget_grab_focus (p->search_entry);
-		gtk_widget_show (p->search_entry_box);
-
-		p->search_active = TRUE;
-
-		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (p->search_dialog));
-
-		g_signal_connect (toplevel, "set-focus",
-                                 G_CALLBACK (set_focus_cb), efhd);
-	}
-
-}
-/**
- * em_format_html_display_search_with:
- * @efhd:
- *
- * Run an interactive search dialogue.
- **/
-void
-em_format_html_display_search_with (EMFormatHTMLDisplay *efhd, char *word)
-{
-	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
-
-	if (p->search_dialog){
-		gtk_widget_show (GTK_WIDGET (p->search_dialog));
-		p->search_active = TRUE;
-
-		/* Set the query */
-		gtk_entry_set_text (GTK_ENTRY (p->search_entry), word);
-		gtk_widget_hide (p->search_entry_box);
-
-		/* Trigger the search */
-		g_signal_emit_by_name (p->search_entry, "activate", efhd);
-	}
-}
-
-void
-em_format_html_display_search_close (EMFormatHTMLDisplay *efhd)
-{
-	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
-
-	if (p->search_dialog && p->search_active)
-		efhd_search_destroy(GTK_WIDGET (p->search_dialog), efhd);
-}
-
-void
-em_format_html_display_cut (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_cut (((EMFormatHTML *) efhd)->html);
-}
-
-void
-em_format_html_display_copy (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_copy (((EMFormatHTML *) efhd)->html);
-}
-
-void
-em_format_html_display_paste (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_paste (((EMFormatHTML *) efhd)->html, FALSE);
-}
-
-void
-em_format_html_display_zoom_in (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_zoom_in (((EMFormatHTML *) efhd)->html);
-}
-
-void
-em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_zoom_out (((EMFormatHTML *) efhd)->html);
-}
-
-void
-em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd)
-{
-	gtk_html_zoom_reset (((EMFormatHTML *) efhd)->html);
-}
-
-/* ********************************************************************** */
-
-static void
-efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh)
-{
-	d(printf("Iframe created %p ... \n", iframe));
-
-	g_signal_connect(iframe, "button_press_event", G_CALLBACK (efhd_html_button_press_event), efh);
-
-	return;
-}
-
-static void
-efhd_get_uri_puri (GtkWidget *html, GdkEventButton *event, EMFormatHTMLDisplay *efhd, char **uri, EMFormatPURI **puri)
-{
-	char *url, *img_url;
-
-	g_return_if_fail (html != NULL);
-	g_return_if_fail (GTK_IS_HTML (html));
-	g_return_if_fail (efhd != NULL);
-
-	if (event) {
-		url = gtk_html_get_url_at (GTK_HTML (html), event->x, event->y);
-		img_url = gtk_html_get_image_src_at (GTK_HTML (html), event->x, event->y);
-	} else {
-		url = gtk_html_get_cursor_url (GTK_HTML (html));
-		img_url = gtk_html_get_cursor_image_src (GTK_HTML (html));
-	}
-
-	if (img_url) {
-		if (!(strstr (img_url, "://") || g_ascii_strncasecmp (img_url, "cid:", 4) == 0)) {
-			char *u = g_strconcat ("file://", img_url, NULL);
-			g_free (img_url);
-			img_url = u;
-		}
-	}
-
-	if (puri) {
-		if (url)
-			*puri = em_format_find_puri ((EMFormat *)efhd, url);
-
-		if (!*puri && img_url)
-			*puri = em_format_find_puri ((EMFormat *)efhd, img_url);
-	}
-
-	if (uri) {
-		*uri = NULL;
-		if (img_url && g_ascii_strncasecmp (img_url, "cid:", 4) != 0) {
-			if (url)
-				*uri = g_strdup_printf ("%s\n%s", url, img_url);
-			else {
-				*uri = img_url;
-				img_url = NULL;
-			}
-		} else {
-			*uri = url;
-			url = NULL;
-		}
-	}
-
-	g_free (url);
-	g_free (img_url);
-}
-
-static int
-efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efhd)
-{
-	char *uri = NULL;
-	EMFormatPURI *puri = NULL;
-	gboolean res = FALSE;
-
-	if (event->button != 3)
-		return FALSE;
-
-	d(printf("popup button pressed\n"));
-
-	efhd_get_uri_puri (widget, event, efhd, &uri, &puri);
-
-	if (uri && !strncmp (uri, "##", 2)) {
-		g_free (uri);
-		return TRUE;
-	}
-
-	g_signal_emit((GtkObject *)efhd, efhd_signals[EFHD_POPUP_EVENT], 0, event, uri, puri?puri->part:NULL, &res);
-
-	g_free (uri);
-
-	return res;
-}
-
-gboolean
-em_format_html_display_popup_menu (EMFormatHTMLDisplay *efhd)
-{
-	GtkHTML *html;
-	char *uri = NULL;
-	EMFormatPURI *puri = NULL;
-	gboolean res = FALSE;
-
-	html = efhd->parent.html;
-
-	efhd_get_uri_puri (GTK_WIDGET (html), NULL, efhd, &uri, &puri);
-
-	g_signal_emit ((GtkObject *)efhd, efhd_signals[EFHD_POPUP_EVENT], 0, NULL, uri, puri?puri->part:NULL, &res);
-
-	g_free (uri);
-
-	return res;
-}
-
-static void
-efhd_html_link_clicked (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd)
-{
-	d(printf("link clicked event '%s'\n", url));
-	if (url && !strncmp(url, "##", 2)) {
-		if (!strcmp (url, "##TO##"))
-			if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_TO))
-				((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_TO;
-			else
-				((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_TO;
-		else if (!strcmp (url, "##CC##"))
-			if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_CC))
-				((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_CC;
-			else
-				((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_CC;
-		else if (!strcmp (url, "##BCC##")) {
-			if (!(((EMFormatHTML *) efhd)->header_wrap_flags & EM_FORMAT_HTML_HEADER_BCC))
-				((EMFormatHTML *) efhd)->header_wrap_flags |= EM_FORMAT_HTML_HEADER_BCC;
-			else
-				((EMFormatHTML *) efhd)->header_wrap_flags &= ~EM_FORMAT_HTML_HEADER_BCC;
-		}
-		em_format_redraw((EMFormat *)efhd);
-	} else
-	    g_signal_emit((GObject *)efhd, efhd_signals[EFHD_LINK_CLICKED], 0, url);
-}
-
-static void
-efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd)
-{
-	d(printf("on_url event '%s'\n", url));
-
-	g_signal_emit((GObject *)efhd, efhd_signals[EFHD_ON_URL], 0, url);
-}
-
-static void
-efhd_complete(EMFormat *emf)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)emf;
-
-	if (efhd->priv->search_dialog && efhd->priv->search_active)
-		efhd_update_matches(efhd);
-
-	if (efhd->priv->files) {
-		g_hash_table_destroy (efhd->priv->files);
-		efhd->priv->files = NULL;
-	}
-}
-
-/* ********************************************************************** */
-
-/* TODO: move the dialogue elsehwere */
-/* FIXME: also in em-format-html.c */
-static const struct {
-	const char *icon, *shortdesc, *description;
-} smime_sign_table[5] = {
-	{ "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") },
-	{ "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") },
-	{ "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") },
-	{ "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") },
-	{ "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") },
-
-};
-
-static const struct {
-	const char *icon, *shortdesc, *description;
-} smime_encrypt_table[4] = {
-	{ "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") },
-	{ "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") },
-	{ "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted.  It would be difficult for an outsider to view the content of this message.") },
-	{ "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") },
-};
-
-static const char *smime_sign_colour[5] = {
-	"", " bgcolor=\"#88bb88\"", " bgcolor=\"#bb8888\"", " bgcolor=\"#e8d122\"",""
-};
-
-struct _smime_pobject {
-	EMFormatHTMLPObject object;
-
-	int signature;
-	CamelCipherValidity *valid;
-	GtkWidget *widget;
-};
-
-static void
-efhd_xpkcs7mime_free(EMFormatHTMLPObject *o)
-{
-	struct _smime_pobject *po = (struct _smime_pobject *)o;
-
-	if (po->widget)
-		gtk_widget_destroy(po->widget);
-	camel_cipher_validity_free(po->valid);
-}
-
-static void
-efhd_xpkcs7mime_info_response(GtkWidget *w, guint button, struct _smime_pobject *po)
-{
-	gtk_widget_destroy(w);
-	po->widget = NULL;
-}
-
-#ifdef HAVE_NSS
-static void
-efhd_xpkcs7mime_viewcert_foad(GtkWidget *w, guint button, struct _smime_pobject *po)
-{
-	gtk_widget_destroy(w);
-}
-
-static void
-efhd_xpkcs7mime_viewcert_clicked(GtkWidget *button, struct _smime_pobject *po)
-{
-	CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info");
-	ECertDB *db = e_cert_db_peek();
-	ECert *ec = NULL;
-
-	if (info->email)
-		ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL);
-
-	if (ec == NULL && info->name)
-		ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL);
-
-	if (ec != NULL) {
-		GtkWidget *w = certificate_viewer_show(ec);
-
-		/* oddly enough certificate_viewer_show doesn't ... */
-		gtk_widget_show(w);
-		g_signal_connect(w, "response", G_CALLBACK(efhd_xpkcs7mime_viewcert_foad), po);
-
-		if (w && po->widget)
-			gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)po->widget);
-
-		g_object_unref(ec);
-	} else {
-		g_warning("can't find certificate for %s <%s>", info->name?info->name:"", info->email?info->email:"");
-	}
-}
-#endif
-
-static void
-efhd_xpkcs7mime_add_cert_table(GtkWidget *vbox, CamelDList *certlist, struct _smime_pobject *po)
-{
-	CamelCipherCertInfo *info = (CamelCipherCertInfo *)certlist->head;
-	GtkTable *table = (GtkTable *)gtk_table_new(camel_dlist_length(certlist), 2, FALSE);
-	int n = 0;
-
-	while (info->next) {
-		char *la = NULL;
-		const char *l = NULL;
-
-		if (info->name) {
-			if (info->email && strcmp(info->name, info->email) != 0)
-				l = la = g_strdup_printf("%s <%s>", info->name, info->email);
-			else
-				l = info->name;
-		} else {
-			if (info->email)
-				l = info->email;
-		}
-
-		if (l) {
-			GtkWidget *w;
-#if defined(HAVE_NSS)
-			ECertDB *db = e_cert_db_peek();
-			ECert *ec = NULL;
-#endif
-			w = gtk_label_new(l);
-			gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
-			g_free(la);
-			gtk_table_attach(table, w, 0, 1, n, n+1, GTK_FILL, GTK_FILL, 3, 3);
-#if defined(HAVE_NSS)
-			w = gtk_button_new_with_mnemonic(_("_View Certificate"));
-			gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3);
-			g_object_set_data((GObject *)w, "e-cert-info", info);
-			g_signal_connect(w, "clicked", G_CALLBACK(efhd_xpkcs7mime_viewcert_clicked), po);
-
-			if (info->email)
-				ec = e_cert_db_find_cert_by_email_address(db, info->email, NULL);
-			if (ec == NULL && info->name)
-				ec = e_cert_db_find_cert_by_nickname(db, info->name, NULL);
-
-			if (ec == NULL)
-				gtk_widget_set_sensitive(w, FALSE);
-			else
-				g_object_unref(ec);
-#else
-			w = gtk_label_new (_("This certificate is not viewable"));
-			gtk_table_attach(table, w, 1, 2, n, n+1, 0, 0, 3, 3);
-#endif
-			n++;
-		}
-
-		info = info->next;
-	}
-
-	gtk_box_pack_start((GtkBox *)vbox, (GtkWidget *)table, TRUE, TRUE, 6);
-}
-
-static void
-efhd_xpkcs7mime_validity_clicked(GtkWidget *button, EMFormatHTMLPObject *pobject)
-{
-	struct _smime_pobject *po = (struct _smime_pobject *)pobject;
-	GladeXML *xml;
-	GtkWidget *vbox, *w;
-	char *gladefile;
-
-	if (po->widget)
-		/* FIXME: window raise? */
-		return;
-
-	gladefile = g_build_filename (EVOLUTION_GLADEDIR,
-				      "mail-dialogs.glade",
-				      NULL);
-	xml = glade_xml_new(gladefile, "message_security_dialog", NULL);
-	g_free (gladefile);
+	return (GtkWidget *)p->search_dialog;
 
-	po->widget = glade_xml_get_widget(xml, "message_security_dialog");
+}
 
-	vbox = glade_xml_get_widget(xml, "signature_vbox");
-	w = gtk_label_new (_(smime_sign_table[po->valid->sign.status].description));
-	gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
-	gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
-	gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
-	if (po->valid->sign.description) {
-		GtkTextBuffer *buffer;
+static void
+set_focus_cb (GtkWidget *window, GtkWidget *widget, EMFormatHTMLDisplay *efhd)
+{
+	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
+	GtkWidget *sbar = GTK_WIDGET (p->search_dialog);
 
-		buffer = gtk_text_buffer_new(NULL);
-		gtk_text_buffer_set_text(buffer, po->valid->sign.description, strlen(po->valid->sign.description));
-		w = g_object_new(gtk_scrolled_window_get_type(),
-				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
-				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
-				 "shadow_type", GTK_SHADOW_IN,
-				 "child", g_object_new(gtk_text_view_get_type(),
-						       "buffer", buffer,
-						       "cursor_visible", FALSE,
-						       "editable", FALSE,
-						       "width_request", 500,
-						       "height_request", 160,
-						       NULL),
-				 NULL);
-		g_object_unref(buffer);
+	while (widget != NULL && widget != sbar) {
+		widget = widget->parent;
+    	}
 
-		gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
-	}
+	if (widget != sbar)
+		efhd_search_destroy(widget, efhd);
+}
 
-	if (!camel_dlist_empty(&po->valid->sign.signers))
-		efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->sign.signers, po);
+/**
+ * em_format_html_display_search:
+ * @efhd:
+ *
+ * Run an interactive search dialogue.
+ **/
+void
+em_format_html_display_search(EMFormatHTMLDisplay *efhd)
+{
+	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
 
-	gtk_widget_show_all(vbox);
+	if (p->search_dialog){
+		GtkWidget *toplevel;
 
-	vbox = glade_xml_get_widget(xml, "encryption_vbox");
-	w = gtk_label_new(_(smime_encrypt_table[po->valid->encrypt.status].description));
-	gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.5);
-	gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
-	gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
-	if (po->valid->encrypt.description) {
-		GtkTextBuffer *buffer;
+		gtk_widget_show (GTK_WIDGET (p->search_dialog));
+		gtk_widget_grab_focus (p->search_entry);
+		gtk_widget_show (p->search_entry_box);
 
-		buffer = gtk_text_buffer_new(NULL);
-		gtk_text_buffer_set_text(buffer, po->valid->encrypt.description, strlen(po->valid->encrypt.description));
-		w = g_object_new(gtk_scrolled_window_get_type(),
-				 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
-				 "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
-				 "shadow_type", GTK_SHADOW_IN,
-				 "child", g_object_new(gtk_text_view_get_type(),
-						       "buffer", buffer,
-						       "cursor_visible", FALSE,
-						       "editable", FALSE,
-						       "width_request", 500,
-						       "height_request", 160,
-						       NULL),
-				 NULL);
-		g_object_unref(buffer);
+		p->search_active = TRUE;
 
-		gtk_box_pack_start((GtkBox *)vbox, w, TRUE, TRUE, 6);
+		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (p->search_dialog));
+
+		g_signal_connect (toplevel, "set-focus",
+                                 G_CALLBACK (set_focus_cb), efhd);
 	}
 
-	if (!camel_dlist_empty(&po->valid->encrypt.encrypters))
-		efhd_xpkcs7mime_add_cert_table(vbox, &po->valid->encrypt.encrypters, po);
+}
+/**
+ * em_format_html_display_search_with:
+ * @efhd:
+ *
+ * Run an interactive search dialogue.
+ **/
+void
+em_format_html_display_search_with (EMFormatHTMLDisplay *efhd, char *word)
+{
+	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
 
-	gtk_widget_show_all(vbox);
+	if (p->search_dialog){
+		gtk_widget_show (GTK_WIDGET (p->search_dialog));
+		p->search_active = TRUE;
 
-	g_object_unref(xml);
+		/* Set the query */
+		gtk_entry_set_text (GTK_ENTRY (p->search_entry), word);
+		gtk_widget_hide (p->search_entry_box);
 
-	g_signal_connect(po->widget, "response", G_CALLBACK(efhd_xpkcs7mime_info_response), po);
-	gtk_widget_show(po->widget);
+		/* Trigger the search */
+		g_signal_emit_by_name (p->search_entry, "activate", efhd);
+	}
 }
 
-static gboolean
-efhd_xpkcs7mime_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
+void
+em_format_html_display_search_close (EMFormatHTMLDisplay *efhd)
 {
-	GtkWidget *icon, *button;
-	struct _smime_pobject *po = (struct _smime_pobject *)pobject;
-	const char *icon_name;
+	struct _EMFormatHTMLDisplayPrivate *p = efhd->priv;
 
-	/* FIXME: need to have it based on encryption and signing too */
-	if (po->valid->sign.status != 0)
-		icon_name = smime_sign_table[po->valid->sign.status].icon;
-	else
-		icon_name = smime_encrypt_table[po->valid->encrypt.status].icon;
+	if (p->search_dialog && p->search_active)
+		efhd_search_destroy(GTK_WIDGET (p->search_dialog), efhd);
+}
 
-	icon = gtk_image_new_from_icon_name (
-		icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
-	gtk_widget_show(icon);
+void
+em_format_html_display_cut (EMFormatHTMLDisplay *efhd)
+{
+	gtk_html_cut (((EMFormatHTML *) efhd)->html);
+}
 
-	button = gtk_button_new();
-	g_signal_connect(button, "clicked", G_CALLBACK(efhd_xpkcs7mime_validity_clicked), pobject);
+void
+em_format_html_display_copy (EMFormatHTMLDisplay *efhd)
+{
+	gtk_html_copy (((EMFormatHTML *) efhd)->html);
+}
 
-	gtk_container_add((GtkContainer *)button, icon);
-	gtk_widget_show(button);
-	gtk_container_add((GtkContainer *)eb, button);
+void
+em_format_html_display_paste (EMFormatHTMLDisplay *efhd)
+{
+	gtk_html_paste (((EMFormatHTML *) efhd)->html, FALSE);
+}
 
-	return TRUE;
+void
+em_format_html_display_zoom_in (EMFormatHTMLDisplay *efhd)
+{
+	gtk_html_zoom_in (((EMFormatHTML *) efhd)->html);
 }
 
-static void
-efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
+void
+em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd)
 {
-	/* Note: We call EMFormatClass directly, not EMFormatHTML, our parent */
-	efhd_format_class->format_secure(emf, stream, part, valid);
+	gtk_html_zoom_out (((EMFormatHTML *) efhd)->html);
+}
 
-	if (emf->valid == valid
-	    && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
-		|| valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) {
-		char *classid;
-		struct _smime_pobject *pobj;
+void
+em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd)
+{
+	gtk_html_zoom_reset (((EMFormatHTML *) efhd)->html);
+}
 
-		camel_stream_printf (stream, "<table border=0 width=\"100%%\" cellpadding=3 cellspacing=0%s><tr>",
-				     smime_sign_colour[valid->sign.status]);
+/* ********************************************************************** */
 
-		classid = g_strdup_printf("smime:///em-format-html/%s/icon/signed", emf->part_id->str);
-		pobj = (struct _smime_pobject *)em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(*pobj), classid, part, efhd_xpkcs7mime_button);
-		pobj->valid = camel_cipher_validity_clone(valid);
-		pobj->object.free = efhd_xpkcs7mime_free;
-		camel_stream_printf(stream, "<td valign=center><object classid=\"%s\"></object></td><td width=100%% valign=center>", classid);
-		g_free(classid);
-		if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
-			camel_stream_printf (stream, "%s", _(smime_sign_table[valid->sign.status].shortdesc));
-		}
+static void
+efhd_complete(EMFormat *emf)
+{
+	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)emf;
 
-		if (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
-			if (valid->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
-				camel_stream_printf (stream, "<br>");
-			}
-			camel_stream_printf (stream, "%s", _(smime_encrypt_table[valid->encrypt.status].shortdesc));
-		}
+	if (efhd->priv->search_dialog && efhd->priv->search_active)
+		efhd_update_matches(efhd);
 
-		camel_stream_printf(stream, "</td></tr></table>");
+	if (efhd->priv->files) {
+		g_hash_table_destroy (efhd->priv->files);
+		efhd->priv->files = NULL;
 	}
 }
 
+/* ********************************************************************** */
+
 static void
 efhd_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *handle)
 {
@@ -1417,27 +1191,6 @@
 		em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]);
 }
 
-static const EMFormatHandler *
-efhd_find_handler(EMFormat *emf, const char *mime_type)
-{
-	return ((EMFormatClass *) efhd_parent)->find_handler (emf, mime_type);
-}
-
-static void efhd_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src)
-{
-	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
-
-	if (emf != src) {
-		if (src)
-			efhd->priv->show_bar = ((EMFormatHTMLDisplay *)src)->priv->show_bar;
-		else
-			efhd->priv->show_bar = FALSE;
-		((EMFormatHTML *) emf)->header_wrap_flags = 0;
-	}
-
-	((EMFormatClass *)efhd_parent)->format_clone(emf, folder, uid, msg, src);
-}
-
 static void
 efhd_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
 {
@@ -1449,7 +1202,8 @@
 	camel_stream_close(stream);
 }
 
-static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
+static void
+efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 {
 	const char *flag, *comp, *due;
 	time_t date;
@@ -1508,17 +1262,6 @@
 	camel_stream_printf(stream, "</td></tr></table>");
 }
 
-/* TODO: if these aren't going to do anything should remove */
-static void efhd_format_error(EMFormat *emf, CamelStream *stream, const char *txt)
-{
-	((EMFormatClass *)efhd_parent)->format_error(emf, stream, txt);
-}
-
-static void efhd_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
-{
-	((EMFormatClass *)efhd_parent)->format_source(emf, stream, part);
-}
-
 /* ********************************************************************** */
 
 /* Checks on the widget whether it can be processed, based on the state of EMFormatHTML.
@@ -2381,7 +2124,7 @@
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
 	const char *classid = "attachment-bar-refresh";
 
-	if (efhd->nobar || efhd->priv->updated)
+	if (efhd->priv->updated)
 		return;
 
 	efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -2397,7 +2140,7 @@
 	EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf;
 	const char *classid = "attachment-bar";
 
-	if (efhd->nobar || efhd->priv->files)
+	if (efhd->priv->files)
 		return;
 
 	efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
@@ -2408,56 +2151,6 @@
 }
 
 static void
-efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle)
-{
-	char *classid, *text, *html;
-	struct _attach_puri *info;
-
-	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);
-	em_format_html_add_pobject((EMFormatHTML *)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_from_mime_part (info->puri.part);
-	e_attachment_bar_create_attachment_cache (info->attachment);
-
-	if (emf->valid) {
-		info->sign = emf->valid->sign.status;
-		info->encrypt = emf->valid->encrypt.status;
-	}
-
-	camel_stream_write_string(stream,
-				  EM_FORMAT_HTML_VPAD
-				  "<table cellspacing=0 cellpadding=0><tr><td>"
-				  "<table width=10 cellspacing=0 cellpadding=0>"
-				  "<tr><td></td></tr></table></td>");
-
-	camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
-
-	camel_stream_write_string(stream,
-				  "<td><table width=3 cellspacing=0 cellpadding=0>"
-				  "<tr><td></td></tr></table></td><td><font size=-1>");
-
-	/* output some info about it */
-	/* FIXME: should we look up mime_type from object again? */
-	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);
-	g_free(html);
-	g_free(text);
-
-	camel_stream_write_string(stream,
-				  "</font></td></tr><tr></table>\n"
-				  EM_FORMAT_HTML_VPAD);
-
-	if (handle && info->shown)
-		handle->handler(emf, stream, part, handle);
-
-	g_free(classid);
-}
-
-static void
 efhd_optional_button_show (GtkWidget *widget, GtkWidget *w)
 {
 	GtkWidget *label = g_object_get_data (G_OBJECT (widget), "text-label");
@@ -2570,49 +2263,3 @@
 	return TRUE;
 }
 
-static void
-efhd_format_optional(EMFormat *emf, CamelStream *fstream, CamelMimePart *part, CamelStream *mstream)
-{
-	char *classid, *html;
-	struct _attach_puri *info;
-	CamelStream *stream;
-
-	if (CAMEL_IS_STREAM_FILTER (fstream) && ((CamelStreamFilter *) fstream)->source)
-		stream = ((CamelStreamFilter *) fstream)->source;
-	else
-		stream = fstream;
-
-	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);
-	em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_optional);
-	info->handle = em_format_find_handler(emf, "text/plain");
-	info->shown = FALSE;
-	info->snoop_mime_type = "text/plain";
-	info->attachment = e_attachment_new_from_mime_part (info->puri.part);
-	info->mstream = (CamelStreamMem *)mstream;
-	if (emf->valid) {
-		info->sign = emf->valid->sign.status;
-		info->encrypt = emf->valid->encrypt.status;
-	}
-
-	camel_stream_write_string(stream,
-				  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."), ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	camel_stream_write_string(stream, html);
-	camel_stream_write_string(stream,
-				  "</font></h3></td></tr></table>\n");
-	camel_stream_write_string(stream,
-				  "<table cellspacing=0 cellpadding=0>"
-				  "<tr>");
-	camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td></tr></table>", classid);
-
-	g_free(html);
-
-	camel_stream_write_string(stream,
-/* 				  "</font></h2></td></tr></table>\n" */
-				  EM_FORMAT_HTML_VPAD);
-
-	g_free(classid);
-}

Modified: branches/kill-bonobo/mail/em-format-html-display.h
==============================================================================
--- branches/kill-bonobo/mail/em-format-html-display.h	(original)
+++ branches/kill-bonobo/mail/em-format-html-display.h	Sun Mar  1 13:16:31 2009
@@ -25,8 +25,9 @@
 #ifndef EM_FORMAT_HTML_DISPLAY_H
 #define EM_FORMAT_HTML_DISPLAY_H
 
-#include "mail/em-format-html.h"
-#include "widgets/misc/e-attachment-bar.h"
+#include <camel/camel-mime-part.h>
+#include <mail/em-format-html.h>
+#include <widgets/misc/e-attachment-bar.h>
 
 /* Standard GObject macros */
 #define EM_TYPE_FORMAT_HTML_DISPLAY \
@@ -58,41 +59,32 @@
 typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass;
 typedef struct _EMFormatHTMLDisplayPrivate EMFormatHTMLDisplayPrivate;
 
-struct _CamelMimePart;
-
 struct _EMFormatHTMLDisplay {
 	EMFormatHTML parent;
 	EMFormatHTMLDisplayPrivate *priv;
 
 	struct _ESearchingTokenizer *search_tok;
-
-	unsigned int nobar:1;
 };
 
 struct _EMFormatHTMLDisplayClass {
 	EMFormatHTMLClass parent_class;
 
 	/* a link clicked normally */
-	void (*link_clicked)(EMFormatHTMLDisplay *efhd, const char *uri);
+	void		(*link_clicked)		(EMFormatHTMLDisplay *efhd,
+						 const gchar *uri);
 	/* a part or a link button pressed event */
-	int (*popup_event)(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, struct _CamelMimePart *part);
+	gint		(*popup_event)		(EMFormatHTMLDisplay *efhd,
+						 GdkEventButton *event,
+						 const gchar *uri,
+						 CamelMimePart *part);
 	/* the mouse is over a link */
-	void (*on_url)(EMFormatHTMLDisplay *efhd, const char *uri);
+	void		(*on_url)		(EMFormatHTMLDisplay *efhd,
+						 const gchar *uri);
 };
 
 GType		em_format_html_display_get_type	(void);
 EMFormatHTMLDisplay *
 		em_format_html_display_new	(void);
-gboolean	em_format_html_display_get_animate
-						(EMFormatHTMLDisplay *efhd);
-void		em_format_html_display_set_animate
-						(EMFormatHTMLDisplay *efhd,
-						 gboolean animate);
-gboolean	em_format_html_display_get_caret_mode
-						(EMFormatHTMLDisplay *efhd);
-void		em_format_html_display_set_caret_mode
-						(EMFormatHTMLDisplay *efhd,
-						 gboolean caret_mode);
 void		em_format_html_display_set_search
 						(EMFormatHTMLDisplay *efhd,
 						 int type,

Modified: branches/kill-bonobo/mail/em-format-html.c
==============================================================================
--- branches/kill-bonobo/mail/em-format-html.c	(original)
+++ branches/kill-bonobo/mail/em-format-html.c	Sun Mar  1 13:16:31 2009
@@ -135,12 +135,7 @@
 
 static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
 
-static void efh_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource);
-static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
-static void efh_format_source(EMFormat *, CamelStream *, CamelMimePart *);
-static void efh_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
 static void efh_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
-static gboolean efh_busy(EMFormat *);
 
 static void efh_builtin_init(EMFormatHTMLClass *efhc);
 
@@ -151,6 +146,230 @@
 
 #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;
+	EMHTMLStream *estream;
+	CamelFolder *folder;
+	char *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)
+{
+	struct _EMFormatHTMLJob *job;
+	struct _EMFormatPURITree *puri_level;
+	int cancelled = FALSE;
+	CamelURL *base;
+
+	if (m->format->html == NULL)
+		return;
+
+	camel_stream_printf (
+		(CamelStream *)m->estream,
+		"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"
+		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n"
+		"<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6>\n",
+		e_color_to_value (
+			&m->format->priv->colors[
+			EM_FORMAT_HTML_COLOR_BODY]),
+		e_color_to_value (
+			&m->format->priv->colors[
+			EM_FORMAT_HTML_COLOR_HEADER]));
+
+	/* <insert top-header stuff here> */
+
+	if (((EMFormat *)m->format)->mode == EM_FORMAT_SOURCE) {
+		em_format_format_source((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message);
+	} else {
+		const EMFormatHandler *handle;
+
+		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/prefix");
+		if (handle)
+			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
+		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/rfc822");
+		if (handle)
+			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
+		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/post-header-closure");
+		if (handle && !((EMFormat *)m->format)->print)
+			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
+
+	}
+
+	camel_stream_flush((CamelStream *)m->estream);
+
+	puri_level = ((EMFormat *)m->format)->pending_uri_level;
+	base = ((EMFormat *)m->format)->base;
+
+	do {
+		/* now dispatch any added tasks ... */
+		g_mutex_lock(m->format->priv->lock);
+		while ((job = (struct _EMFormatHTMLJob *)e_dlist_remhead(&m->format->priv->pending_jobs))) {
+			g_mutex_unlock(m->format->priv->lock);
+
+			/* This is an implicit check to see if the gtkhtml has been destroyed */
+			if (!cancelled)
+				cancelled = m->format->html == NULL;
+
+			/* Now do an explicit check for user cancellation */
+			if (!cancelled)
+				cancelled = camel_operation_cancel_check(NULL);
+
+			/* call jobs even if cancelled, so they can clean up resources */
+			((EMFormat *)m->format)->pending_uri_level = job->puri_level;
+			if (job->base)
+				((EMFormat *)m->format)->base = job->base;
+			job->callback(job, cancelled);
+			((EMFormat *)m->format)->base = base;
+
+			/* clean up the job */
+			camel_object_unref(job->stream);
+			if (job->base)
+				camel_url_free(job->base);
+			g_free(job);
+
+			g_mutex_lock(m->format->priv->lock);
+		}
+		g_mutex_unlock(m->format->priv->lock);
+
+		if (m->estream) {
+			/* Closing this base stream can queue more jobs, so we need
+			   to check the list again after we've finished */
+			d(printf("out of jobs, closing root stream\n"));
+			camel_stream_write_string((CamelStream *)m->estream, "</body>\n</html>\n");
+			camel_stream_close((CamelStream *)m->estream);
+			camel_object_unref(m->estream);
+			m->estream = NULL;
+		}
+
+		/* e_dlist_empty is atomic and doesn't need locking */
+	} while (!e_dlist_empty(&m->format->priv->pending_jobs));
+
+	d(printf("out of jobs, done\n"));
+
+	((EMFormat *)m->format)->pending_uri_level = puri_level;
+}
+
+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->estream) {
+		camel_stream_close((CamelStream *)m->estream);
+		camel_object_unref(m->estream);
+	}
+	if (m->folder)
+		camel_object_unref(m->folder);
+	g_free(m->uid);
+	if (m->message)
+		camel_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_format_timeout(struct _format_msg *m)
+{
+	GtkHTMLStream *hstream;
+	EMFormatHTML *efh = m->format;
+	struct _EMFormatHTMLPrivate *p = efh->priv;
+
+	if (m->format->html == 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 (e_dlist_empty(&p->pending_jobs), FALSE);
+
+	d(printf(" ready to go, firing off format thread\n"));
+
+	/* call super-class to kick it off */
+	EM_FORMAT_CLASS (parent_class)->format_clone (
+		EM_FORMAT (efh), m->folder, m->uid,
+		m->message, m->format_source);
+	em_format_html_clear_pobject(m->format);
+
+	/* FIXME: method off EMFormat? */
+	if (((EMFormat *)efh)->valid) {
+		camel_cipher_validity_free(((EMFormat *)efh)->valid);
+		((EMFormat *)efh)->valid = NULL;
+		((EMFormat *)efh)->valid_parent = NULL;
+	}
+
+	if (m->message == NULL) {
+		hstream = gtk_html_begin(efh->html);
+		gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
+		mail_msg_unref(m);
+		p->last_part = NULL;
+	} else {
+		efh->state = EM_FORMAT_HTML_STATE_RENDERING;
+
+		if (p->last_part != m->message) {
+			hstream = gtk_html_begin (efh->html);
+			gtk_html_stream_printf (hstream, "<h5>%s</h5>", _("Formatting Message..."));
+			gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK);
+		}
+
+		hstream = NULL;
+		m->estream = (EMHTMLStream *)em_html_stream_new(efh->html, hstream);
+
+		if (p->last_part == m->message) {
+			em_html_stream_set_flags (m->estream,
+						  GTK_HTML_BEGIN_KEEP_SCROLL | GTK_HTML_BEGIN_KEEP_IMAGES
+						  | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES);
+		} else {
+			/* clear cache of inline-scanned text parts */
+			g_hash_table_remove_all(p->text_inline_parts);
+
+			p->last_part = m->message;
+		}
+
+		efh->priv->format_id = m->base.seq;
+		mail_msg_unordered_push (m);
+	}
+
+	efh->priv->format_timeout_id = 0;
+	efh->priv->format_timeout_msg = NULL;
+
+	return FALSE;
+}
+
 static void
 efh_free_cache(struct _EMFormatHTMLCache *efhc)
 {
@@ -371,34 +590,173 @@
 }
 
 static void
-efh_base_init (EMFormatHTMLClass *class)
+efh_format_clone (EMFormat *emf,
+                  CamelFolder *folder,
+                  const gchar *uid,
+                  CamelMimeMessage *msg,
+                  EMFormat *emfsource)
 {
-	efh_builtin_init (class);
-}
+	EMFormatHTML *efh = EM_FORMAT_HTML (emf);
+	struct _format_msg *m;
 
-static void
-efh_class_init (EMFormatHTMLClass *class)
-{
-	GObjectClass *object_class;
-	EMFormatClass *format_class;
-	gchar *pathname;
+	/* How to sub-class ?  Might need to adjust api ... */
 
-	parent_class = g_type_class_peek_parent (class);
-	g_type_class_add_private (class, sizeof (EMFormatHTMLPrivate));
+	if (efh->html == NULL)
+		return;
 
-	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;
+	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;
+	}
 
-	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;
+	if (emfsource != NULL)
+		g_object_ref (emfsource);
+
+	if (folder != NULL)
+		camel_object_ref (folder);
+
+	if (msg != NULL)
+		camel_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)
+{
+	gchar *html;
+
+	html = camel_text_to_html (
+		txt, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
+		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+	camel_stream_printf (
+		stream, "<em><font color=\"red\">%s</font></em><br>", html);
+	g_free (html);
+}
+
+static void
+efh_format_source (EMFormat *emf,
+                   CamelStream *stream,
+                   CamelMimePart *part)
+{
+	CamelStreamFilter *filtered_stream;
+	CamelMimeFilter *filter;
+	CamelDataWrapper *dw = (CamelDataWrapper *) part;
+
+	filtered_stream = camel_stream_filter_new_with_stream (stream);
+
+	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 (filtered_stream, filter);
+	camel_object_unref (filter);
+
+	camel_stream_write_string (stream, "<table><tr><td><tt>");
+	em_format_format_text (emf, (CamelStream *) filtered_stream, dw);
+	camel_object_unref (filtered_stream);
+
+	camel_stream_write_string(stream, "</tt></td></tr></table>");
+}
+
+static void
+efh_format_attachment (EMFormat *emf,
+                       CamelStream *stream,
+                       CamelMimePart *part,
+                       const gchar *mime_type,
+                       const EMFormatHandler *handle)
+{
+	char *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");
+
+	/* 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);
+	g_free (html);
+	g_free (text);
+
+	camel_stream_write_string (stream, "</font></td></tr><tr></table>");
+
+	if (handle && em_format_is_inline (emf, emf->part_id->str, part, handle))
+		handle->handler (emf, stream, part, handle);
+}
+
+static gboolean
+efh_busy (EMFormat *emf)
+{
+	EMFormatHTMLPrivate *priv;
+
+	priv = EM_FORMAT_HTML_GET_PRIVATE (emf);
+
+	return (priv->format_id != -1);
+}
+static void
+efh_base_init (EMFormatHTMLClass *class)
+{
+	efh_builtin_init (class);
+}
+
+static void
+efh_class_init (EMFormatHTMLClass *class)
+{
+	GObjectClass *object_class;
+	EMFormatClass *format_class;
+	gchar *pathname;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMFormatHTMLPrivate));
+
+	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;
+
+	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 = GTK_TYPE_HTML;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_BODY_COLOR,
@@ -516,8 +874,10 @@
 }
 
 static void
-efh_init (EMFormatHTML *efh)
+efh_init (EMFormatHTML *efh,
+          EMFormatHTMLClass *class)
 {
+	GtkHTML *html;
 	GdkColor *color;
 
 	efh->priv = EM_FORMAT_HTML_GET_PRIVATE (efh);
@@ -531,32 +891,35 @@
 		(GDestroyNotify) NULL,
 		(GDestroyNotify) efh_free_cache);
 
-	efh->html = (GtkHTML *) gtk_html_new ();
-	g_object_ref_sink(efh->html);
-
-	gtk_html_set_blocking (efh->html, FALSE);
-	gtk_html_set_caret_first_focus_anchor (efh->html, EFM_MESSAGE_START_ANAME);
+	html = g_object_new (class->html_widget_type, NULL);
+	efh->html = g_object_ref_sink (html);
 
-	gtk_html_set_default_content_type(efh->html, "text/html; charset=utf-8");
-	gtk_html_set_editable(efh->html, FALSE);
-
-	g_signal_connect(efh->html, "url_requested", G_CALLBACK(efh_url_requested), efh);
-	g_signal_connect(efh->html, "object_requested", G_CALLBACK(efh_object_requested), efh);
+	gtk_html_set_blocking (html, FALSE);
+	gtk_html_set_caret_first_focus_anchor (html, EFM_MESSAGE_START_ANAME);
+	gtk_html_set_default_content_type (html, "text/html; charset=utf-8");
+	gtk_html_set_editable (html, FALSE);
+
+	g_signal_connect (
+		html, "url-requested",
+		G_CALLBACK (efh_url_requested), efh);
+	g_signal_connect (
+		html, "object-requested",
+		G_CALLBACK (efh_object_requested), efh);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
-	gdk_color_parse ("0xeeeeee", color);
+	gdk_color_parse ("#eeeeee", color);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT];
-	gdk_color_parse ("0xffffff", color);
+	gdk_color_parse ("#ffffff", color);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME];
-	gdk_color_parse ("0x3f3f3f", color);
+	gdk_color_parse ("#3f3f3f", color);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER];
-	gdk_color_parse ("0xeeeeee", color);
+	gdk_color_parse ("#eeeeee", color);
 
 	color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT];
-	gdk_color_parse ("0x000000", color);
+	gdk_color_parse ("#000000", color);
 
 	efh->text_html_flags =
 		CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
@@ -590,18 +953,13 @@
 		};
 
 		type = g_type_register_static (
-			em_format_get_type(), "EMFormatHTML", &type_info, 0);
+			em_format_get_type(), "EMFormatHTML",
+			&type_info, G_TYPE_FLAG_ABSTRACT);
 	}
 
 	return type;
 }
 
-EMFormatHTML *
-em_format_html_new(void)
-{
-	return g_object_new (EM_TYPE_FORMAT_HTML, NULL);
-}
-
 void
 em_format_html_load_images (EMFormatHTML *efh)
 {
@@ -688,7 +1046,7 @@
 {
 	g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
 
-	return efh->priv->image_loading_policy;;
+	return efh->priv->image_loading_policy;
 }
 
 void
@@ -1548,447 +1906,169 @@
 	while (purin) {
 		if (puri->use_count == 0) {
 			d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
-			if (puri->func == emfh_write_related) {
-				g_string_printf(((EMFormat *)job->format)->part_id, "%s", puri->part_id);
-				em_format_part((EMFormat *)job->format, (CamelStream *)job->stream, puri->part);
-			}
-			/* else it was probably added by a previous format this loop */
-		}
-		puri = purin;
-		purin = purin->next;
-	}
-
-	g_string_printf(((EMFormat *)job->format)->part_id, "%s", oldpartid);
-	g_free(oldpartid);
-}
-
-/* RFC 2387 */
-static void
-efh_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
-{
-	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
-	CamelMimePart *body_part, *display_part = NULL;
-	CamelContentType *content_type;
-	const char *start;
-	int i, nparts, partidlen, displayid = 0;
-	/* puri is set but never used */
-	EMFormatPURI *puri;
-	struct _EMFormatHTMLJob *job;
-
-	if (!CAMEL_IS_MULTIPART(mp)) {
-		em_format_format_source(emf, stream, part);
-		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) {
-		int len;
-		const char *cid;
-
-		/* strip <>'s */
-		len = strlen (start) - 2;
-		start++;
-
-		for (i=0; i<nparts; i++) {
-			body_part = camel_multipart_get_part(mp, i);
-			cid = camel_mime_part_get_content_id(body_part);
-
-			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);
-	}
-
-	if (display_part == NULL) {
-		em_format_part_as(emf, stream, part, "multipart/mixed");
-		return;
-	}
-
-	em_format_push_level(emf);
-
-	partidlen = emf->part_id->len;
-
-	/* 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);
-			puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emfh_write_related);
-			g_string_truncate(emf->part_id, partidlen);
-			d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
-		}
-	}
-
-	g_string_append_printf(emf->part_id, "related.%d", displayid);
-	em_format_part(emf, stream, display_part);
-	g_string_truncate(emf->part_id, partidlen);
-	camel_stream_flush(stream);
-
-	/* queue a job to check for un-referenced parts to add as attachments */
-	job = em_format_html_job_new((EMFormatHTML *)emf, emfh_multipart_related_check, NULL);
-	job->stream = stream;
-	camel_object_ref(stream);
-	em_format_html_job_queue((EMFormatHTML *)emf, job);
-
-	em_format_pull_level(emf);
-}
-
-static void
-efh_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
-{
-	CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)puri->part);
-
-	d(printf("writing image '%s'\n", puri->cid));
-	camel_data_wrapper_decode_to_stream(dw, stream);
-	camel_stream_close(stream);
-}
-
-static void
-efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
-{
-	EMFormatPURI *puri;
-
-	puri = em_format_add_puri((EMFormat *)efh, sizeof(EMFormatPURI), NULL, part, efh_write_image);
-	d(printf("adding image '%s'\n", puri->cid));
-	camel_stream_printf(stream, "<img hspace=10 vspace=10 src=\"%s\">", puri->cid);
-}
-
-static EMFormatHandler type_builtin_table[] = {
-	{ "image/gif", (EMFormatFunc)efh_image },
-	{ "image/jpeg", (EMFormatFunc)efh_image },
-	{ "image/png", (EMFormatFunc)efh_image },
-	{ "image/x-png", (EMFormatFunc)efh_image },
-	{ "image/tiff", (EMFormatFunc)efh_image },
-	{ "image/x-bmp", (EMFormatFunc)efh_image },
-	{ "image/bmp", (EMFormatFunc)efh_image },
-	{ "image/svg", (EMFormatFunc)efh_image },
-	{ "image/x-cmu-raster", (EMFormatFunc)efh_image },
-	{ "image/x-ico", (EMFormatFunc)efh_image },
-	{ "image/x-portable-anymap", (EMFormatFunc)efh_image },
-	{ "image/x-portable-bitmap", (EMFormatFunc)efh_image },
-	{ "image/x-portable-graymap", (EMFormatFunc)efh_image },
-	{ "image/x-portable-pixmap", (EMFormatFunc)efh_image },
-	{ "image/x-xpixmap", (EMFormatFunc)efh_image },
-	{ "text/enriched", (EMFormatFunc)efh_text_enriched },
-	{ "text/plain", (EMFormatFunc)efh_text_plain },
-	{ "text/html", (EMFormatFunc)efh_text_html },
-	{ "text/richtext", (EMFormatFunc)efh_text_enriched },
-	{ "text/*", (EMFormatFunc)efh_text_plain },
-	{ "message/external-body", (EMFormatFunc)efh_message_external },
-	{ "message/delivery-status", (EMFormatFunc)efh_message_deliverystatus },
-	{ "multipart/related", (EMFormatFunc)efh_multipart_related },
-
-	/* 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. */
-
-	{ "image/jpg", (EMFormatFunc)efh_image },
-	{ "image/pjpeg", (EMFormatFunc)efh_image },
-
-	/* special internal types */
-
-	{ "x-evolution/message/rfc822", (EMFormatFunc)efh_format_message }
-};
-
-static void
-efh_builtin_init(EMFormatHTMLClass *efhc)
-{
-	EMFormatClass *efc;
-	gint ii;
-
-	efc = (EMFormatClass *) efhc;
-
-	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
-		em_format_class_add_handler (
-			efc, &type_builtin_table[ii]);
-}
-
-/* ********************************************************************** */
-
-/* Sigh, this is so we have a cancellable, async rendering thread */
-struct _format_msg {
-	MailMsg base;
-
-	EMFormatHTML *format;
-	EMFormat *format_source;
-	EMHTMLStream *estream;
-	CamelFolder *folder;
-	char *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)
-{
-	struct _EMFormatHTMLJob *job;
-	struct _EMFormatPURITree *puri_level;
-	int cancelled = FALSE;
-	CamelURL *base;
-
-	if (m->format->html == NULL)
-		return;
-
-	camel_stream_printf (
-		(CamelStream *)m->estream,
-		"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"
-		"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n</head>\n"
-		"<body bgcolor =\"#%06x\" text=\"#%06x\" marginwidth=6 marginheight=6>\n",
-		e_color_to_value (
-			&m->format->priv->colors[
-			EM_FORMAT_HTML_COLOR_BODY]),
-		e_color_to_value (
-			&m->format->priv->colors[
-			EM_FORMAT_HTML_COLOR_HEADER]));
-
-	/* <insert top-header stuff here> */
-
-	if (((EMFormat *)m->format)->mode == EM_FORMAT_SOURCE) {
-		em_format_format_source((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message);
-	} else {
-		const EMFormatHandler *handle;
-
-		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/prefix");
-		if (handle)
-			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
-		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/rfc822");
-		if (handle)
-			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
-		handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/post-header-closure");
-		if (handle && !((EMFormat *)m->format)->print)
-			handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle);
-
-	}
-
-	camel_stream_flush((CamelStream *)m->estream);
-
-	puri_level = ((EMFormat *)m->format)->pending_uri_level;
-	base = ((EMFormat *)m->format)->base;
-
-	do {
-		/* now dispatch any added tasks ... */
-		g_mutex_lock(m->format->priv->lock);
-		while ((job = (struct _EMFormatHTMLJob *)e_dlist_remhead(&m->format->priv->pending_jobs))) {
-			g_mutex_unlock(m->format->priv->lock);
-
-			/* This is an implicit check to see if the gtkhtml has been destroyed */
-			if (!cancelled)
-				cancelled = m->format->html == NULL;
-
-			/* Now do an explicit check for user cancellation */
-			if (!cancelled)
-				cancelled = camel_operation_cancel_check(NULL);
-
-			/* call jobs even if cancelled, so they can clean up resources */
-			((EMFormat *)m->format)->pending_uri_level = job->puri_level;
-			if (job->base)
-				((EMFormat *)m->format)->base = job->base;
-			job->callback(job, cancelled);
-			((EMFormat *)m->format)->base = base;
-
-			/* clean up the job */
-			camel_object_unref(job->stream);
-			if (job->base)
-				camel_url_free(job->base);
-			g_free(job);
-
-			g_mutex_lock(m->format->priv->lock);
-		}
-		g_mutex_unlock(m->format->priv->lock);
-
-		if (m->estream) {
-			/* Closing this base stream can queue more jobs, so we need
-			   to check the list again after we've finished */
-			d(printf("out of jobs, closing root stream\n"));
-			camel_stream_write_string((CamelStream *)m->estream, "</body>\n</html>\n");
-			camel_stream_close((CamelStream *)m->estream);
-			camel_object_unref(m->estream);
-			m->estream = NULL;
-		}
-
-		/* e_dlist_empty is atomic and doesn't need locking */
-	} while (!e_dlist_empty(&m->format->priv->pending_jobs));
-
-	d(printf("out of jobs, done\n"));
-
-	((EMFormat *)m->format)->pending_uri_level = puri_level;
-}
-
-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->estream) {
-		camel_stream_close((CamelStream *)m->estream);
-		camel_object_unref(m->estream);
+			if (puri->func == emfh_write_related) {
+				g_string_printf(((EMFormat *)job->format)->part_id, "%s", puri->part_id);
+				em_format_part((EMFormat *)job->format, (CamelStream *)job->stream, puri->part);
+			}
+			/* else it was probably added by a previous format this loop */
+		}
+		puri = purin;
+		purin = purin->next;
 	}
-	if (m->folder)
-		camel_object_unref(m->folder);
-	g_free(m->uid);
-	if (m->message)
-		camel_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
-};
+	g_string_printf(((EMFormat *)job->format)->part_id, "%s", oldpartid);
+	g_free(oldpartid);
+}
 
-static gboolean
-efh_format_timeout(struct _format_msg *m)
+/* RFC 2387 */
+static void
+efh_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 {
-	GtkHTMLStream *hstream;
-	EMFormatHTML *efh = m->format;
-	struct _EMFormatHTMLPrivate *p = efh->priv;
+	CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+	CamelMimePart *body_part, *display_part = NULL;
+	CamelContentType *content_type;
+	const char *start;
+	int i, nparts, partidlen, displayid = 0;
+	/* puri is set but never used */
+	EMFormatPURI *puri;
+	struct _EMFormatHTMLJob *job;
 
-	if (m->format->html == NULL) {
-		mail_msg_unref(m);
-		return FALSE;
+	if (!CAMEL_IS_MULTIPART(mp)) {
+		em_format_format_source(emf, stream, part);
+		return;
 	}
 
-	d(printf("timeout called ...\n"));
-	if (p->format_id != -1) {
-		d(printf(" still waiting for cancellation to take effect, waiting ...\n"));
-		return TRUE;
-	}
+	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) {
+		int len;
+		const char *cid;
 
-	g_return_val_if_fail (e_dlist_empty(&p->pending_jobs), FALSE);
+		/* strip <>'s */
+		len = strlen (start) - 2;
+		start++;
 
-	d(printf(" ready to go, firing off format thread\n"));
+		for (i=0; i<nparts; i++) {
+			body_part = camel_multipart_get_part(mp, i);
+			cid = camel_mime_part_get_content_id(body_part);
 
-	/* call super-class to kick it off */
-	EM_FORMAT_CLASS (parent_class)->format_clone (
-		EM_FORMAT (efh), m->folder, m->uid,
-		m->message, m->format_source);
-	em_format_html_clear_pobject(m->format);
+			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);
+	}
 
-	/* FIXME: method off EMFormat? */
-	if (((EMFormat *)efh)->valid) {
-		camel_cipher_validity_free(((EMFormat *)efh)->valid);
-		((EMFormat *)efh)->valid = NULL;
-		((EMFormat *)efh)->valid_parent = NULL;
+	if (display_part == NULL) {
+		em_format_part_as(emf, stream, part, "multipart/mixed");
+		return;
 	}
 
-	if (m->message == NULL) {
-		hstream = gtk_html_begin(efh->html);
-		gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
-		mail_msg_unref(m);
-		p->last_part = NULL;
-	} else {
-		efh->state = EM_FORMAT_HTML_STATE_RENDERING;
+	em_format_push_level(emf);
 
-		if (p->last_part != m->message) {
-			hstream = gtk_html_begin (efh->html);
-			gtk_html_stream_printf (hstream, "<h5>%s</h5>", _("Formatting Message..."));
-			gtk_html_stream_close (hstream, GTK_HTML_STREAM_OK);
-		}
+	partidlen = emf->part_id->len;
 
-		hstream = NULL;
-		m->estream = (EMHTMLStream *)em_html_stream_new(efh->html, hstream);
+	/* 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);
+			puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emfh_write_related);
+			g_string_truncate(emf->part_id, partidlen);
+			d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
+		}
+	}
 
-		if (p->last_part == m->message) {
-			em_html_stream_set_flags (m->estream,
-						  GTK_HTML_BEGIN_KEEP_SCROLL | GTK_HTML_BEGIN_KEEP_IMAGES
-						  | GTK_HTML_BEGIN_BLOCK_UPDATES | GTK_HTML_BEGIN_BLOCK_IMAGES);
-		} else {
-			/* clear cache of inline-scanned text parts */
-			g_hash_table_remove_all(p->text_inline_parts);
+	g_string_append_printf(emf->part_id, "related.%d", displayid);
+	em_format_part(emf, stream, display_part);
+	g_string_truncate(emf->part_id, partidlen);
+	camel_stream_flush(stream);
 
-			p->last_part = m->message;
-		}
+	/* queue a job to check for un-referenced parts to add as attachments */
+	job = em_format_html_job_new((EMFormatHTML *)emf, emfh_multipart_related_check, NULL);
+	job->stream = stream;
+	camel_object_ref(stream);
+	em_format_html_job_queue((EMFormatHTML *)emf, job);
 
-		efh->priv->format_id = m->base.seq;
-		mail_msg_unordered_push (m);
-	}
+	em_format_pull_level(emf);
+}
 
-	efh->priv->format_timeout_id = 0;
-	efh->priv->format_timeout_msg = NULL;
+static void
+efh_write_image(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
+{
+	CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)puri->part);
 
-	return FALSE;
+	d(printf("writing image '%s'\n", puri->cid));
+	camel_data_wrapper_decode_to_stream(dw, stream);
+	camel_stream_close(stream);
 }
 
-static void efh_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource)
+static void
+efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 {
-	EMFormatHTML *efh = (EMFormatHTML *)emf;
-	struct _format_msg *m;
+	EMFormatPURI *puri;
 
-	/* How to sub-class ?  Might need to adjust api ... */
+	puri = em_format_add_puri((EMFormat *)efh, sizeof(EMFormatPURI), NULL, part, efh_write_image);
+	d(printf("adding image '%s'\n", puri->cid));
+	camel_stream_printf(stream, "<img hspace=10 vspace=10 src=\"%s\">", puri->cid);
+}
 
-	if (efh->html == NULL)
-		return;
+static EMFormatHandler type_builtin_table[] = {
+	{ "image/gif", (EMFormatFunc)efh_image },
+	{ "image/jpeg", (EMFormatFunc)efh_image },
+	{ "image/png", (EMFormatFunc)efh_image },
+	{ "image/x-png", (EMFormatFunc)efh_image },
+	{ "image/tiff", (EMFormatFunc)efh_image },
+	{ "image/x-bmp", (EMFormatFunc)efh_image },
+	{ "image/bmp", (EMFormatFunc)efh_image },
+	{ "image/svg", (EMFormatFunc)efh_image },
+	{ "image/x-cmu-raster", (EMFormatFunc)efh_image },
+	{ "image/x-ico", (EMFormatFunc)efh_image },
+	{ "image/x-portable-anymap", (EMFormatFunc)efh_image },
+	{ "image/x-portable-bitmap", (EMFormatFunc)efh_image },
+	{ "image/x-portable-graymap", (EMFormatFunc)efh_image },
+	{ "image/x-portable-pixmap", (EMFormatFunc)efh_image },
+	{ "image/x-xpixmap", (EMFormatFunc)efh_image },
+	{ "text/enriched", (EMFormatFunc)efh_text_enriched },
+	{ "text/plain", (EMFormatFunc)efh_text_plain },
+	{ "text/html", (EMFormatFunc)efh_text_html },
+	{ "text/richtext", (EMFormatFunc)efh_text_enriched },
+	{ "text/*", (EMFormatFunc)efh_text_plain },
+	{ "message/external-body", (EMFormatFunc)efh_message_external },
+	{ "message/delivery-status", (EMFormatFunc)efh_message_deliverystatus },
+	{ "multipart/related", (EMFormatFunc)efh_multipart_related },
 
-	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;
-	}
+	/* 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. */
 
-	m = mail_msg_new(&efh_format_info);
-	m->format = (EMFormatHTML *)emf;
-	g_object_ref(emf);
-	m->format_source = emfsource;
-	if (emfsource)
-		g_object_ref(emfsource);
-	m->folder = folder;
-	if (folder)
-		camel_object_ref(folder);
-	m->uid = g_strdup(uid);
-	m->message = msg;
-	if (msg)
-		camel_object_ref(msg);
+	{ "image/jpg", (EMFormatFunc)efh_image },
+	{ "image/pjpeg", (EMFormatFunc)efh_image },
 
-	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);
-	}
-}
+	/* special internal types */
+
+	{ "x-evolution/message/rfc822", (EMFormatFunc)efh_format_message }
+};
 
-static void efh_format_error(EMFormat *emf, CamelStream *stream, const char *txt)
+static void
+efh_builtin_init(EMFormatHTMLClass *efhc)
 {
-	char *html;
+	EMFormatClass *efc;
+	gint ii;
+
+	efc = (EMFormatClass *) efhc;
 
-	html = camel_text_to_html (txt, CAMEL_MIME_FILTER_TOHTML_CONVERT_NL|CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
-	camel_stream_printf(stream, "<em><font color=\"red\">%s</font></em><br>", html);
-	g_free(html);
+	for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++)
+		em_format_class_add_handler (
+			efc, &type_builtin_table[ii]);
 }
 
+/* ********************************************************************** */
+
 static void
 efh_format_text_header (EMFormatHTML *emfh, CamelStream *stream, const char *label, const char *value, guint32 flags)
 {
@@ -2563,7 +2643,8 @@
 	}
 }
 
-static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+static void
+efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
 {
 	const EMFormatHandler *handle;
 
@@ -2595,57 +2676,3 @@
 	emf->valid = save;
 	emf->valid_parent = save_parent;
 }
-
-static void efh_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
-{
-	CamelStreamFilter *filtered_stream;
-	CamelMimeFilter *html_filter;
-	CamelDataWrapper *dw = (CamelDataWrapper *)part;
-
-	filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
-	html_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(filtered_stream, html_filter);
-	camel_object_unref(html_filter);
-
-	camel_stream_write_string((CamelStream *)stream, "<table><tr><td><tt>");
-	em_format_format_text(emf, (CamelStream *)filtered_stream, dw);
-	camel_object_unref(filtered_stream);
-
-	camel_stream_write_string(stream, "</tt></td></tr></table>");
-}
-
-static void
-efh_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle)
-{
-	char *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");
-
-	/* 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);
-	g_free(html);
-	g_free(text);
-
-	camel_stream_write_string(stream, "</font></td></tr><tr></table>");
-
-	if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle))
-		handle->handler(emf, stream, part, handle);
-}
-
-static gboolean
-efh_busy(EMFormat *emf)
-{
-	return (((EMFormatHTML *)emf)->priv->format_id != -1);
-}

Modified: branches/kill-bonobo/mail/em-format-html.h
==============================================================================
--- branches/kill-bonobo/mail/em-format-html.h	(original)
+++ branches/kill-bonobo/mail/em-format-html.h	Sun Mar  1 13:16:31 2009
@@ -22,7 +22,7 @@
  */
 
 /*
-  Concrete class for formatting mails to html
+  Abstract class for formatting mails to html
 */
 
 #ifndef EM_FORMAT_HTML_H
@@ -226,10 +226,11 @@
 
 struct _EMFormatHTMLClass {
 	EMFormatClass parent_class;
+
+	GType html_widget_type;
 };
 
 GType		em_format_html_get_type		(void);
-EMFormatHTML *	em_format_html_new		(void);
 void		em_format_html_load_images	(EMFormatHTML *efh);
 void		em_format_html_get_color	(EMFormatHTML *efh,
 						 EMFormatHTMLColorType type,

Modified: branches/kill-bonobo/mail/em-html-stream.c
==============================================================================
--- branches/kill-bonobo/mail/em-html-stream.c	(original)
+++ branches/kill-bonobo/mail/em-html-stream.c	Sun Mar  1 13:16:31 2009
@@ -27,84 +27,39 @@
 #endif
 
 #include <stdio.h>
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-stream.h>
 #include <gtk/gtk.h>
 #include "em-html-stream.h"
 
 #define d(x)
 
-static void em_html_stream_class_init (EMHTMLStreamClass *klass);
-static void em_html_stream_init (CamelObject *object);
-static void em_html_stream_finalize (CamelObject *object);
-
-static ssize_t emhs_sync_write(CamelStream *stream, const char *buffer, size_t n);
-static int emhs_sync_close(CamelStream *stream);
-static int emhs_sync_flush(CamelStream *stream);
-
 static EMSyncStreamClass *parent_class = NULL;
 
-CamelType
-em_html_stream_get_type (void)
-{
-	static CamelType type = CAMEL_INVALID_TYPE;
-
-	if (type == CAMEL_INVALID_TYPE) {
-		parent_class = (EMSyncStreamClass *)em_sync_stream_get_type();
-		type = camel_type_register (em_sync_stream_get_type(),
-					    "EMHTMLStream",
-					    sizeof (EMHTMLStream),
-					    sizeof (EMHTMLStreamClass),
-					    (CamelObjectClassInitFunc) em_html_stream_class_init,
-					    NULL,
-					    (CamelObjectInitFunc) em_html_stream_init,
-					    (CamelObjectFinalizeFunc) em_html_stream_finalize);
-	}
-
-	return type;
-}
-
-static void
-em_html_stream_class_init (EMHTMLStreamClass *klass)
-{
-	((EMSyncStreamClass *)klass)->sync_write = emhs_sync_write;
-	((EMSyncStreamClass *)klass)->sync_flush = emhs_sync_flush;
-	((EMSyncStreamClass *)klass)->sync_close = emhs_sync_close;
-}
-
 static void
-em_html_stream_init (CamelObject *object)
-{
-	/*EMHTMLStream *emhs = (EMHTMLStream *)object;*/
-}
-
-static void
-emhs_cleanup(EMHTMLStream *emhs)
+emhs_cleanup (EMHTMLStream *emhs)
 {
 	if (emhs->sync.cancel && emhs->html_stream)
-		gtk_html_stream_close (emhs->html_stream, GTK_HTML_STREAM_ERROR);
+		gtk_html_stream_close (
+			emhs->html_stream, GTK_HTML_STREAM_ERROR);
+
 	emhs->html_stream = NULL;
 	emhs->sync.cancel = TRUE;
-	g_signal_handler_disconnect(emhs->html, emhs->destroy_id);
-	g_object_unref(emhs->html);
+	g_signal_handler_disconnect (emhs->html, emhs->destroy_id);
+	g_object_unref (emhs->html);
 	emhs->html = NULL;
 }
 
 static void
-em_html_stream_finalize (CamelObject *object)
+emhs_gtkhtml_destroy (GtkHTML *html,
+                      EMHTMLStream *emhs)
 {
-	EMHTMLStream *emhs = (EMHTMLStream *)object;
-
-	d(printf("%p: finalising stream\n", object));
-	if (emhs->html_stream) {
-		d(printf("%p: html stream still open - error\n", object));
-		/* set 'in finalise' flag */
-		camel_stream_close((CamelStream *)emhs);
-	}
+	emhs->sync.cancel = TRUE;
+	emhs_cleanup (emhs);
 }
 
 static ssize_t
-emhs_sync_write(CamelStream *stream, const char *buffer, size_t n)
+emhs_sync_write (CamelStream *stream,
+                 const char *buffer,
+                 size_t n)
 {
 	EMHTMLStream *emhs = EM_HTML_STREAM (stream);
 
@@ -112,9 +67,10 @@
 		return -1;
 
 	if (emhs->html_stream == NULL)
-		emhs->html_stream = gtk_html_begin_full (emhs->html, NULL, NULL, emhs->flags);
+		emhs->html_stream = gtk_html_begin_full (
+			emhs->html, NULL, NULL, emhs->flags);
 
-	gtk_html_stream_write(emhs->html_stream, buffer, n);
+	gtk_html_stream_write (emhs->html_stream, buffer, n);
 
 	return (ssize_t) n;
 }
@@ -133,48 +89,93 @@
 }
 
 static int
-emhs_sync_close(CamelStream *stream)
+emhs_sync_close (CamelStream *stream)
 {
 	EMHTMLStream *emhs = (EMHTMLStream *)stream;
 
 	if (emhs->html_stream == NULL)
 		return -1;
 
-	gtk_html_stream_close(emhs->html_stream, GTK_HTML_STREAM_OK);
-	emhs_cleanup(emhs);
+	gtk_html_stream_close (emhs->html_stream, GTK_HTML_STREAM_OK);
+	emhs_cleanup (emhs);
 
 	return 0;
 }
 
 static void
-emhs_gtkhtml_destroy(struct _GtkHTML *html, EMHTMLStream *emhs)
+em_html_stream_class_init (EMHTMLStreamClass *class)
 {
-	d(printf("%p: emhs gtkhtml destroy\n", emhs));
-	emhs->sync.cancel = TRUE;
-	emhs_cleanup(emhs);
+	EMSyncStreamClass *sync_stream_class;
+
+	parent_class = (EMSyncStreamClass *)em_sync_stream_get_type();
+
+	sync_stream_class = EM_SYNC_STREAM_CLASS (class);
+	sync_stream_class->sync_write = emhs_sync_write;
+	sync_stream_class->sync_flush = emhs_sync_flush;
+	sync_stream_class->sync_close = emhs_sync_close;
+}
+
+static void
+em_html_stream_init (EMHTMLStream *emhs)
+{
+}
+
+static void
+em_html_stream_finalize (EMHTMLStream *emhs)
+{
+	if (emhs->html_stream) {
+		/* set 'in finalise' flag */
+		camel_stream_close (CAMEL_STREAM (emhs));
+	}
+}
+
+CamelType
+em_html_stream_get_type (void)
+{
+	static CamelType type = CAMEL_INVALID_TYPE;
+
+	if (G_UNLIKELY (type == CAMEL_INVALID_TYPE)) {
+		type = camel_type_register (
+			em_sync_stream_get_type(),
+			"EMHTMLStream",
+			sizeof (EMHTMLStream),
+			sizeof (EMHTMLStreamClass),
+			(CamelObjectClassInitFunc) em_html_stream_class_init,
+			NULL,
+			(CamelObjectInitFunc) em_html_stream_init,
+			(CamelObjectFinalizeFunc) em_html_stream_finalize);
+	}
+
+	return type;
 }
 
 /* TODO: Could pass NULL for html_stream, and do a gtk_html_begin
    on first data -> less flashing */
 CamelStream *
-em_html_stream_new(struct _GtkHTML *html, struct _GtkHTMLStream *html_stream)
+em_html_stream_new (GtkHTML *html,
+                    GtkHTMLStream *html_stream)
 {
 	EMHTMLStream *new;
 
+	g_return_val_if_fail (GTK_IS_HTML (html), NULL);
+
 	new = EM_HTML_STREAM (camel_object_new (EM_HTML_STREAM_TYPE));
 	new->html_stream = html_stream;
-	new->html = html;
+	new->html = g_object_ref (html);
 	new->flags = 0;
-	g_object_ref(html);
-	new->destroy_id = g_signal_connect(html, "destroy", G_CALLBACK(emhs_gtkhtml_destroy), new);
+	new->destroy_id = g_signal_connect (
+		html, "destroy",
+		G_CALLBACK (emhs_gtkhtml_destroy), new);
 
-	em_sync_stream_set_buffer_size(&new->sync, 8192);
+	em_sync_stream_set_buffer_size (&new->sync, 8192);
 
-	return (CamelStream *)new;
+	return CAMEL_STREAM (new);
 }
 
 void
 em_html_stream_set_flags (EMHTMLStream *emhs, GtkHTMLBeginFlags flags)
 {
+	g_return_if_fail (EM_IS_HTML_STREAM (emhs));
+
 	emhs->flags = flags;
 }

Modified: branches/kill-bonobo/mail/em-html-stream.h
==============================================================================
--- branches/kill-bonobo/mail/em-html-stream.h	(original)
+++ branches/kill-bonobo/mail/em-html-stream.h	Sun Mar  1 13:16:31 2009
@@ -24,44 +24,47 @@
 #ifndef EM_HTML_STREAM_H
 #define EM_HTML_STREAM_H
 
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define EM_HTML_STREAM_TYPE     (em_html_stream_get_type ())
-#define EM_HTML_STREAM(obj)     (CAMEL_CHECK_CAST((obj), EM_HTML_STREAM_TYPE, EMHTMLStream))
-#define EM_HTML_STREAM_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_HTML_STREAM_TYPE, EMHTMLStreamClass))
-#define EM_IS_HTML_STREAM(o)    (CAMEL_CHECK_TYPE((o), EM_HTML_STREAM_TYPE))
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
+#include <mail/em-sync-stream.h>
+
+#define EM_HTML_STREAM_TYPE \
+	(em_html_stream_get_type ())
+#define EM_HTML_STREAM(obj) \
+	(CAMEL_CHECK_CAST \
+	((obj), EM_HTML_STREAM_TYPE, EMHTMLStream))
+#define EM_HTML_STREAM_CLASS(cls) \
+	(CAMEL_CHECK_CLASS_CAST \
+	((cls), EM_HTML_STREAM_TYPE, EMHTMLStreamClass))
+#define EM_IS_HTML_STREAM(obj) \
+	(CAMEL_CHECK_TYPE \
+	((obj), EM_HTML_STREAM_TYPE))
 
-struct _GtkHTML;
-struct _GtkHTMLStream;
+G_BEGIN_DECLS
 
-#include "mail/em-sync-stream.h"
+typedef struct _EMHTMLStream EMHTMLStream;
+typedef struct _EMHTMLStreamClass EMHTMLStreamClass;
 
-typedef struct _EMHTMLStream {
+struct _EMHTMLStream {
 	EMSyncStream sync;
 
 	guint destroy_id;
-	struct _GtkHTML *html;
-	struct _GtkHTMLStream *html_stream;
+	GtkHTML *html;
+	GtkHTMLStream *html_stream;
 	GtkHTMLBeginFlags flags;
-} EMHTMLStream;
+};
 
-typedef struct {
+struct _EMHTMLStreamClass {
 	EMSyncStreamClass parent_class;
 
-} EMHTMLStreamClass;
+};
 
+CamelType	em_html_stream_get_type		(void);
+CamelStream *	em_html_stream_new		(GtkHTML *html,
+						 GtkHTMLStream *html_stream);
+void		em_html_stream_set_flags	(EMHTMLStream *emhs,
+						 GtkHTMLBeginFlags flags);
 
-CamelType    em_html_stream_get_type (void);
-
-/* the html_stream is closed when we are finalised (with an error), or closed (ok) */
-CamelStream *em_html_stream_new(struct _GtkHTML *html, struct _GtkHTMLStream *html_stream);
-void em_html_stream_set_flags (EMHTMLStream *emhs, GtkHTMLBeginFlags flags);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+G_END_DECLS
 
 #endif /* EM_HTML_STREAM_H */



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