[evolution/webkit: 20/134] Use custom protocol handler to provide data for mail preview
- From: Dan VrÃtil <dvratil src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit: 20/134] Use custom protocol handler to provide data for mail preview
- Date: Wed, 14 Dec 2011 15:33:55 +0000 (UTC)
commit 4d3ba0980e91445678f4c80b92fd4a80a1442639
Author: Dan VrÃtil <dvratil redhat com>
Date: Fri Aug 5 12:42:24 2011 +0200
Use custom protocol handler to provide data for mail preview
Use SoupRequest-based class to handle our own protocol mail://.
To display a mail, or a mimepart, WebKit is given URL
mail://account_url/folder_name/message_id?[part_id=PARTID&]formatter=FORMATTER
(where FORMATTER is a pointer to EMFormat object to be used to format
the given message/part. This way WebKit can request for any part of
a mail and everything is completely asynchronous.
data/webview.css | 5 -
em-format/em-format.c | 97 ++--
em-format/em-format.h | 9 +-
mail/Makefile.am | 9 +-
mail/e-mail-browser.c | 2 +-
mail/e-mail-display.c | 132 +++++-
mail/e-mail-display.h | 4 +-
mail/e-mail-paned-view.c | 2 +-
mail/e-mail-reader-utils.c | 7 +-
mail/e-mail-reader.c | 32 +-
mail/e-mail-request.c | 235 +++++++++
mail/e-mail-request.h | 38 ++
mail/em-format-html.c | 819 +++----------------------------
mail/em-format-html.h | 73 +---
mail/em-utils.c | 4 +-
plugins/itip-formatter/itip-formatter.c | 12 +-
widgets/misc/e-web-view.c | 174 +------
widgets/misc/e-web-view.h | 1 +
18 files changed, 587 insertions(+), 1068 deletions(-)
---
diff --git a/data/webview.css b/data/webview.css
index 704c745..74578af 100644
--- a/data/webview.css
+++ b/data/webview.css
@@ -1,7 +1,3 @@
-body, td, th {
- font-size: 0.8em;
-}
-
h1, h2, h3 {
color: #7f7f7f;
}
@@ -19,7 +15,6 @@ th {
.pre {
font-family: monospace;
- font-size: 0.8em;
}
span.navigable, div.navigable, p.navigable {
diff --git a/em-format/em-format.c b/em-format/em-format.c
index 40f9baa..979d15f 100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@ -40,10 +40,6 @@
typedef struct _EMFormatCache EMFormatCache;
-struct _EMFormatPrivate {
- guint redraw_idle_id;
-};
-
/* Used to cache various data/info for redraws
* The validity stuff could be cached at a higher level but this is easier
* This absolutely relies on the partid being _globally unique_
@@ -137,15 +133,15 @@ emf_finalize (GObject *object)
{
EMFormat *emf = EM_FORMAT (object);
- if (emf->priv->redraw_idle_id > 0)
- g_source_remove (emf->priv->redraw_idle_id);
-
if (emf->session)
g_object_unref (emf->session);
if (emf->message)
g_object_unref (emf->message);
+ if (emf->folder)
+ g_object_unref (emf->folder);
+
g_hash_table_destroy (emf->inline_table);
em_format_clear_headers (emf);
@@ -190,12 +186,6 @@ emf_format_clone (EMFormat *emf,
EMFormat *emfsource,
GCancellable *cancellable)
{
- /* Cancel any pending redraws. */
- if (emf->priv->redraw_idle_id > 0) {
- g_source_remove (emf->priv->redraw_idle_id);
- emf->priv->redraw_idle_id = 0;
- }
-
em_format_clear_puri_tree (emf);
if (emf != emfsource) {
@@ -248,7 +238,6 @@ emf_format_clone (EMFormat *emf,
emf->current_message_part_id = g_strdup ("root-message");
g_string_truncate (emf->part_id, 0);
if (folder != NULL)
- /* TODO build some string based on the folder name/location? */
g_string_append_printf(emf->part_id, ".%p", (gpointer) folder);
if (uid != NULL)
g_string_append_printf(emf->part_id, ".%s", uid);
@@ -333,7 +322,6 @@ emf_class_init (EMFormatClass *class)
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
- g_type_class_add_private (class, sizeof (EMFormatPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->finalize = emf_finalize;
@@ -360,9 +348,6 @@ emf_init (EMFormat *emf)
EShell *shell;
EShellSettings *shell_settings;
- emf->priv = G_TYPE_INSTANCE_GET_PRIVATE (
- emf, EM_TYPE_FORMAT, EMFormatPrivate);
-
emf->inline_table = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) NULL,
@@ -375,6 +360,10 @@ emf_init (EMFormat *emf)
emf->current_message_part_id = NULL;
emf->validity_found = 0;
+ emf->message = NULL;
+ emf->folder = NULL;
+ emf->uid = NULL;
+
shell = e_shell_get_default ();
shell_settings = e_shell_get_shell_settings (shell);
@@ -940,28 +929,6 @@ em_format_format (EMFormat *emf,
em_format_format_clone (emf, folder, uid, message, NULL, cancellable);
}
-static gboolean
-format_redraw_idle_cb (EMFormat *emf)
-{
- emf->priv->redraw_idle_id = 0;
-
- /* FIXME Not passing a GCancellable here. */
- em_format_format_clone (
- emf, emf->folder, emf->uid, emf->message, emf, NULL);
-
- return FALSE;
-}
-
-void
-em_format_queue_redraw (EMFormat *emf)
-{
- g_return_if_fail (EM_IS_FORMAT (emf));
-
- if (emf->priv->redraw_idle_id == 0)
- emf->priv->redraw_idle_id = g_idle_add (
- (GSourceFunc) format_redraw_idle_cb, emf);
-}
-
/**
* em_format_set_mode:
* @emf:
@@ -980,10 +947,6 @@ em_format_set_mode (EMFormat *emf,
return;
emf->mode = mode;
-
- /* force redraw if type changed afterwards */
- if (emf->message != NULL)
- em_format_queue_redraw (emf);
}
/**
@@ -1005,9 +968,6 @@ em_format_set_charset (EMFormat *emf,
g_free (emf->charset);
emf->charset = g_strdup (charset);
-
- if (emf->message)
- em_format_queue_redraw (emf);
}
/**
@@ -1031,9 +991,6 @@ em_format_set_default_charset (EMFormat *emf,
g_free (emf->default_charset);
emf->default_charset = g_strdup (charset);
-
- if (emf->message && emf->charset == NULL)
- em_format_queue_redraw (emf);
}
/**
@@ -1218,9 +1175,6 @@ em_format_set_inline (EMFormat *emf,
return;
emfc->state = state ? INLINE_ON : INLINE_OFF;
-
- if (emf->message)
- em_format_queue_redraw (emf);
}
void
@@ -1633,7 +1587,7 @@ emf_multipart_appledouble (EMFormat *emf,
}
-/* RFC ??? */
+/* RFC 2046 */
static void
emf_multipart_mixed (EMFormat *emf,
CamelStream *stream,
@@ -1652,6 +1606,9 @@ emf_multipart_mixed (EMFormat *emf,
return;
}
+ em_format_push_level (emf);
+
+
len = emf->part_id->len;
nparts = camel_multipart_get_number (mp);
for (i = 0; i < nparts; i++) {
@@ -1686,6 +1643,8 @@ emf_multipart_alternative (EMFormat *emf,
return;
}
+ em_format_push_level (emf);
+
/* as per rfc, find the last part we know how to display */
nparts = camel_multipart_get_number (mp);
for (i = 0; i < nparts; i++) {
@@ -2490,3 +2449,33 @@ em_format_snoop_type (CamelMimePart *part)
/* We used to load parts to check their type, we dont anymore,
* see bug #11778 for some discussion */
}
+
+gchar*
+em_format_build_mail_uri (CamelFolder *folder,
+ const gchar *message_uid,
+ const gchar *part_uid,
+ EMFormat *emf)
+{
+ CamelStore *store;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ g_return_val_if_fail (message_uid && *message_uid, NULL);
+ g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+
+ store = camel_folder_get_parent_store (folder);
+
+ if (part_uid) {
+ return g_strdup_printf ("mail://%s/%s/%s?part_id=%s&formatter=%d",
+ camel_service_get_uid (CAMEL_SERVICE (store)),
+ camel_folder_get_full_name (folder),
+ message_uid,
+ part_uid,
+ GPOINTER_TO_INT (emf));
+ }
+
+ return g_strdup_printf ("mail://%s/%s/%s?formatter=%d",
+ camel_service_get_uid (CAMEL_SERVICE (store)),
+ camel_folder_get_full_name (folder),
+ message_uid,
+ GPOINTER_TO_INT (emf));
+}
diff --git a/em-format/em-format.h b/em-format/em-format.h
index cf214d8..8ebd0b6 100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@ -53,7 +53,6 @@ G_BEGIN_DECLS
typedef struct _EMFormat EMFormat;
typedef struct _EMFormatClass EMFormatClass;
-typedef struct _EMFormatPrivate EMFormatPrivate;
typedef struct _EMFormatHandler EMFormatHandler;
typedef struct _EMFormatHeader EMFormatHeader;
@@ -187,7 +186,6 @@ struct _EMFormatHeader {
**/
struct _EMFormat {
GObject parent;
- EMFormatPrivate *priv;
/* The current message */
CamelMimeMessage *message;
@@ -336,6 +334,7 @@ void em_format_set_inline (EMFormat *emf,
gchar * em_format_describe_part (CamelMimePart *part,
const gchar *mime_type);
+
/* for implementers */
GType em_format_get_type (void);
@@ -378,7 +377,6 @@ void em_format_format (EMFormat *emf,
const gchar *uid,
CamelMimeMessage *message,
GCancellable *cancellable);
-void em_format_queue_redraw (EMFormat *emf);
void em_format_format_attachment (EMFormat *emf,
CamelStream *stream,
CamelMimePart *mime_part,
@@ -427,6 +425,11 @@ void em_format_merge_handler (EMFormat *new,
const gchar * em_format_snoop_type (CamelMimePart *part);
+gchar * em_format_build_mail_uri (CamelFolder *folder,
+ const gchar *message_uid,
+ const gchar *part_uid,
+ EMFormat *emf);
+
G_END_DECLS
#endif /* EM_FORMAT_H */
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 9515feb..954ace7 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -30,7 +30,7 @@ libevolution_mail_la_CPPFLAGS = \
$(CERT_UI_CFLAGS) \
$(CANBERRA_CFLAGS) \
$(CLUTTER_CFLAGS) \
- $(GTKHTML_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
-DEVOLUTION_DATADIR=\""$(datadir)"\" \
-DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \
-DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \
@@ -69,6 +69,7 @@ mailinclude_HEADERS = \
e-mail-migrate.h \
e-mail-reader.h \
e-mail-reader-utils.h \
+ e-mail-request.h \
e-mail-session.h \
e-mail-session-utils.h \
e-mail-sidebar.h \
@@ -142,6 +143,7 @@ libevolution_mail_la_SOURCES = \
e-mail-migrate.c \
e-mail-reader.c \
e-mail-reader-utils.c \
+ e-mail-request.c \
e-mail-session.c \
e-mail-session-utils.c \
e-mail-sidebar.c \
@@ -216,7 +218,10 @@ libevolution_mail_la_LIBADD = \
$(CANBERRA_LIBS) \
$(CLUTTER_LIBS) \
$(GTKHTML_LIBS) \
- $(SMIME_LIBS)
+ $(E_WIDGETS_LIBS) \
+ $(SMIME_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(GNOME_PLATFORM_LIBS)
libevolution_mail_la_LDFLAGS = $(NO_UNDEFINED)
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index 95084c6..5c3d69c 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -707,7 +707,7 @@ mail_browser_constructed (GObject *object)
g_signal_connect_swapped (
search_bar, "changed",
- G_CALLBACK (em_format_queue_redraw), priv->formatter);
+ G_CALLBACK (e_web_view_reload), web_view);
/* Bind GObject properties to GConf keys. */
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 7ccc78d..f0b3980 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -23,6 +23,8 @@
#include <config.h>
#endif
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
#include "e-mail-display.h"
#include <glib/gi18n.h>
@@ -31,6 +33,10 @@
#include "e-util/e-plugin-ui.h"
#include "mail/em-composer-utils.h"
#include "mail/em-utils.h"
+#include "mail/e-mail-request.h"
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-requester.h>
struct _EMailDisplayPrivate {
EMFormatHTML *formatter;
@@ -86,7 +92,7 @@ static GtkActionEntry mailto_entries[] = {
NULL,
N_("Send _Reply To..."),
NULL,
- N_("Send a reply message to this address"),
+ N_("Send a reply message to this address"),
NULL /* Handled by EMailReader */ },
/*** Menus ***/
@@ -203,24 +209,12 @@ static void
mail_display_style_set (GtkWidget *widget,
GtkStyle *previous_style)
{
- EMailDisplayPrivate *priv;
-
- priv = E_MAIL_DISPLAY (widget)->priv;
-
/* Chain up to parent's style_set() method. */
GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
- em_format_queue_redraw (EM_FORMAT (priv->formatter));
-}
-static void
-mail_display_url_requested (GtkHTML *html,
- const gchar *uri,
- GtkHTMLStream *stream)
-{
- /* XXX Sadly, we must block the default method
- * until EMFormatHTML is made asynchronous. */
+ e_web_view_reload (E_WEB_VIEW (widget));
}
static gboolean
@@ -291,6 +285,93 @@ mail_display_link_clicked (WebKitWebView *web_view,
}
static void
+mail_display_resource_requested (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitWebResource *resource,
+ WebKitNetworkRequest *request,
+ WebKitNetworkResponse *response,
+ gpointer user_data)
+{
+ EMFormatHTML *formatter = E_MAIL_DISPLAY (web_view)->priv->formatter;
+ const gchar *uri = webkit_network_request_get_uri (request);
+
+ /* Redirect cid:part_id to mail://mail_id/cid:part_id */
+ if (g_str_has_prefix (uri, "cid:")) {
+ gchar *new_uri = em_format_build_mail_uri (EM_FORMAT (formatter)->folder,
+ EM_FORMAT (formatter)->uid, uri, EM_FORMAT (formatter));
+
+ webkit_network_request_set_uri (request, new_uri);
+
+ g_free (new_uri);
+
+ /* WebKit won't allow to load a local file when displaing "remote" mail://,
+ protocol, so we need to handle this manually */
+ } else if (g_str_has_prefix (uri, "file:")) {
+ gchar *data = NULL;
+ gsize length = 0;
+ gboolean status;
+ gchar *path;
+
+ path = g_filename_from_uri (uri, NULL, NULL);
+ if (!path)
+ return;
+
+ status = g_file_get_contents (path, &data, &length, NULL);
+ if (status) {
+ gchar *b64, *new_uri;
+ gchar *ct;
+
+ b64 = g_base64_encode ((guchar*) data, length);
+ ct = g_content_type_guess (path, NULL, 0, NULL);
+
+ new_uri = g_strdup_printf ("data:%s;base64,%s", ct, b64);
+ webkit_network_request_set_uri (request, new_uri);
+
+ g_free (b64);
+ g_free (new_uri);
+ g_free (ct);
+ }
+ g_free (data);
+ g_free (path);
+ }
+
+ g_signal_stop_emission_by_name (web_view, "resource-request-starting");
+}
+
+static void
+mail_display_headers_collapsed_state_changed (EWebView *web_view,
+ size_t arg_count,
+ const JSValueRef args[],
+ gpointer user_data)
+{
+ EMFormatHTML *formatter = E_MAIL_DISPLAY (web_view)->priv->formatter;
+ JSGlobalContextRef ctx = e_web_view_get_global_context (web_view);
+
+ gboolean collapsed = JSValueToBoolean (ctx, args[0]);
+
+ if (collapsed) {
+ em_format_html_set_headers_state (formatter, EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED);
+ } else {
+ em_format_html_set_headers_state (formatter, EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
+ }
+}
+
+static void
+mail_display_install_js_callbacks (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ gpointer context,
+ gpointer window_object,
+ gpointer user_data)
+{
+ if (frame != webkit_web_view_get_main_frame (web_view))
+ return;
+
+ e_web_view_install_js_callback (E_WEB_VIEW (web_view), "headers_collapsed",
+ (EWebViewJSFunctionCallback) mail_display_headers_collapsed_state_changed, user_data);
+}
+
+
+static void
mail_display_class_init (EMailDisplayClass *class)
{
GObjectClass *object_class;
@@ -326,18 +407,25 @@ mail_display_class_init (EMailDisplayClass *class)
static void
mail_display_init (EMailDisplay *display)
{
- EWebView *web_view;
GtkUIManager *ui_manager;
GtkActionGroup *action_group;
GError *error = NULL;
+ EWebView *web_view;
+ SoupSession *session;
+ SoupSessionFeature *feature;
web_view = E_WEB_VIEW (display);
- g_signal_connect (web_view, "navigation-policy-decision-requested",
- G_CALLBACK (mail_display_link_clicked), display);
display->priv = G_TYPE_INSTANCE_GET_PRIVATE (
display, E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate);
+ g_signal_connect (web_view, "navigation-policy-decision-requested",
+ G_CALLBACK (mail_display_link_clicked), display);
+ g_signal_connect (web_view, "resource-request-starting",
+ G_CALLBACK (mail_display_resource_requested), display);
+ g_signal_connect (web_view, "window-object-cleared",
+ G_CALLBACK (mail_display_install_js_callbacks), display);
+
/* EWebView's action groups are added during its instance
* initialization function (like what we're in now), so it
* is safe to fetch them this early in construction. */
@@ -356,6 +444,14 @@ mail_display_init (EMailDisplay *display)
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
if (error != NULL)
g_error ("%s", error->message);
+
+
+ /* Register our own handler for mail:// protocol */
+ session = webkit_get_default_session ();
+ feature = SOUP_SESSION_FEATURE (soup_requester_new ());
+ soup_session_feature_add_feature (feature, E_TYPE_MAIL_REQUEST);
+ soup_session_add_feature (session, feature);
+ g_object_unref (feature);
}
GType
@@ -404,5 +500,7 @@ e_mail_display_set_formatter (EMailDisplay *display,
display->priv->formatter = g_object_ref (formatter);
+ mail_display_update_formatter_colors (display);
+
g_object_notify (G_OBJECT (display), "formatter");
}
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 1b71a9d..fb3f29d 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -22,8 +22,8 @@
#ifndef E_MAIL_DISPLAY_H
#define E_MAIL_DISPLAY_H
-#include <mail/em-format-html.h>
-#include <misc/e-web-view.h>
+#include <widgets/misc/e-web-view.h>
+#include "em-format-html.h"
/* Standard GObject macros */
#define E_TYPE_MAIL_DISPLAY \
diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c
index 0eda997..2208238 100644
--- a/mail/e-mail-paned-view.c
+++ b/mail/e-mail-paned-view.c
@@ -687,7 +687,7 @@ mail_paned_view_constructed (GObject *object)
g_signal_connect_swapped (
search_bar, "changed",
- G_CALLBACK (em_format_queue_redraw), priv->formatter);
+ G_CALLBACK (e_web_view_reload), web_view);
/* Load the view instance. */
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 725a0c6..845ff21 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1422,6 +1422,7 @@ headers_changed_cb (GConfClient *client,
EMailReader *reader)
{
EMFormatHTML *formatter;
+ EWebView *web_view;
GSList *header_config_list, *p;
g_return_if_fail (client != NULL);
@@ -1453,8 +1454,10 @@ headers_changed_cb (GConfClient *client,
g_slist_free (header_config_list);
/* force a redraw */
- if (EM_FORMAT (formatter)->message)
- em_format_queue_redraw (EM_FORMAT (formatter));
+ if (EM_FORMAT (formatter)->message) {
+ web_view = em_format_html_get_web_view (formatter);
+ e_web_view_reload (web_view);
+ }
}
static void
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index b067c6a..f78d716 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -433,18 +433,20 @@ action_mail_flag_clear_cb (GtkAction *action,
EMailReader *reader)
{
EMFormatHTML *formatter;
+ EWebView *web_view;
CamelFolder *folder;
GtkWindow *window;
GPtrArray *uids;
folder = e_mail_reader_get_folder (reader);
formatter = e_mail_reader_get_formatter (reader);
+ web_view = em_format_html_get_web_view (formatter);
uids = e_mail_reader_get_selected_uids (reader);
window = e_mail_reader_get_window (reader);
em_utils_flag_for_followup_clear (window, folder, uids);
- em_format_queue_redraw (EM_FORMAT (formatter));
+ e_web_view_reload (web_view);
}
static void
@@ -452,18 +454,20 @@ action_mail_flag_completed_cb (GtkAction *action,
EMailReader *reader)
{
EMFormatHTML *formatter;
+ EWebView *web_view;
CamelFolder *folder;
GtkWindow *window;
GPtrArray *uids;
folder = e_mail_reader_get_folder (reader);
formatter = e_mail_reader_get_formatter (reader);
+ web_view = em_format_html_get_web_view (formatter);
uids = e_mail_reader_get_selected_uids (reader);
window = e_mail_reader_get_window (reader);
em_utils_flag_for_followup_completed (window, folder, uids);
- em_format_queue_redraw (EM_FORMAT (formatter));
+ e_web_view_reload (web_view);
}
static void
@@ -2515,6 +2519,7 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
EMEvent *event;
EMEventTargetMessage *target;
const gchar *message_uid;
+ gchar *mail_uri;
gboolean schedule_timeout;
gint timeout_interval;
GError *error = NULL;
@@ -2543,6 +2548,7 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
backend = e_mail_reader_get_backend (reader);
formatter = e_mail_reader_get_formatter (reader);
+ web_view = em_format_html_get_web_view (formatter);
message_list = e_mail_reader_get_message_list (reader);
if (!message_list) {
@@ -2570,10 +2576,14 @@ mail_reader_message_loaded_cb (CamelFolder *folder,
(EEvent *) event, "message.reading",
(EEventTarget *) target);
- /* FIXME Need to pass a GCancellable. */
- em_format_format (
- EM_FORMAT (formatter), folder,
- message_uid, message, NULL);
+
+ /* Initialize formatter */
+ em_format_format_clone (EM_FORMAT (formatter), folder, message_uid, message, NULL, NULL);
+
+ /* Start formatting */
+ mail_uri = em_format_build_mail_uri (folder, message_uid, NULL, EM_FORMAT (formatter));
+ e_web_view_load_uri (web_view, mail_uri);
+ g_free (mail_uri);
/* Reset the shell view icon. */
e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
@@ -2700,9 +2710,8 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader)
priv->retrieving_message = g_object_ref (cancellable);
}
} else {
- /* FIXME Need to pass a GCancellable. */
- em_format_format (
- EM_FORMAT (formatter), NULL, NULL, NULL, NULL);
+ e_web_view_load_string (web_view, "");
+
priv->restoring_message_selection = FALSE;
}
@@ -2793,6 +2802,7 @@ mail_reader_set_folder (EMailReader *reader,
{
EMailReaderPrivate *priv;
EMFormatHTML *formatter;
+ EWebView *web_view;
CamelFolder *previous_folder;
GtkWidget *message_list;
EMailBackend *backend;
@@ -2803,6 +2813,7 @@ mail_reader_set_folder (EMailReader *reader,
backend = e_mail_reader_get_backend (reader);
formatter = e_mail_reader_get_formatter (reader);
+ web_view = em_format_html_get_web_view (formatter);
message_list = e_mail_reader_get_message_list (reader);
previous_folder = e_mail_reader_get_folder (reader);
@@ -2822,8 +2833,7 @@ mail_reader_set_folder (EMailReader *reader,
em_utils_folder_is_outbox (folder) ||
em_utils_folder_is_sent (folder));
- /* FIXME Need to pass a GCancellable. */
- em_format_format (EM_FORMAT (formatter), NULL, NULL, NULL, NULL);
+ e_web_view_load_string (web_view, "");
priv->folder_was_just_selected = (folder != NULL);
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
new file mode 100644
index 0000000..eb7c694
--- /dev/null
+++ b/mail/e-mail-request.c
@@ -0,0 +1,235 @@
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
+#include "e-mail-request.h"
+#include <libsoup/soup.h>
+#include <glib/gi18n.h>
+#include <camel/camel.h>
+
+#include "em-format-html.h"
+
+
+G_DEFINE_TYPE (EMailRequest, e_mail_request, SOUP_TYPE_REQUEST)
+
+struct _EMailRequestPrivate {
+ EMFormatHTML *efh;
+ CamelMimePart *part;
+
+ CamelStream *output_stream;
+
+ gchar *content_type;
+
+ GHashTable *uri_query;
+};
+
+
+static void
+start_mail_formatting (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ EMailRequest *request = E_MAIL_REQUEST (object);
+ EMFormatHTML *efh = request->priv->efh;
+ EMFormat *emf = EM_FORMAT (efh);
+ GInputStream *stream;
+ GByteArray *ba;
+ gchar *part_id;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ if (request->priv->output_stream != NULL)
+ g_object_unref (request->priv->output_stream);
+
+ request->priv->output_stream = camel_stream_mem_new ();
+
+ part_id = g_hash_table_lookup (request->priv->uri_query, "part_id");
+
+ if (part_id) {
+ CamelContentType *ct;
+ EMFormatPURI *puri;
+
+ puri = em_format_find_puri (emf, part_id);
+ if (puri) {
+ request->priv->part = puri->part;
+ ct = camel_mime_part_get_content_type (request->priv->part);
+ if (ct) {
+ request->priv->content_type = camel_content_type_format (ct);
+ camel_content_type_unref (ct);
+ } else {
+ request->priv->content_type = g_strdup ("text/html");
+ }
+ em_format_html_format_message_part (efh, part_id, request->priv->output_stream, cancellable);
+ }
+ } else {
+ request->priv->content_type = g_strdup ("text/html");
+ request->priv->part = g_object_ref (CAMEL_MIME_PART (emf->message));
+ em_format_html_format_message (efh, request->priv->output_stream, cancellable);
+ }
+
+ /* Convert the GString to GInputStream and send it back to WebKit */
+ ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (request->priv->output_stream));
+
+ if (!ba->data) {
+ gchar *data = g_strdup_printf(_("Failed to load part '%s'"), part_id);
+ g_byte_array_append (ba, (guchar*) data, strlen (data));
+ g_free (data);
+ }
+
+ stream = g_memory_input_stream_new_from_data ((gchar*) ba->data, ba->len, NULL);
+ g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+}
+
+static void
+get_image_content (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ EMailRequest *request = E_MAIL_REQUEST (object);
+ SoupURI *uri;
+ GInputStream *stream;
+ gchar *contents;
+ gsize length;
+
+ if (g_cancellable_is_cancelled (cancellable))
+ return;
+
+ uri = soup_request_get_uri (SOUP_REQUEST (request));
+
+ if (g_file_get_contents (uri->path, &contents, &length, NULL)) {
+ request->priv->content_type = g_content_type_guess (uri->path, NULL, 0, NULL);
+ stream = g_memory_input_stream_new_from_data (contents, length, NULL);
+ g_simple_async_result_set_op_res_gpointer (res, stream, NULL);
+ }
+}
+
+static void
+e_mail_request_init (EMailRequest *request)
+{
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ request, E_TYPE_MAIL_REQUEST, EMailRequestPrivate);
+
+ request->priv->efh = NULL;
+ request->priv->part = NULL;
+ request->priv->output_stream = NULL;
+ request->priv->uri_query = NULL;
+}
+
+static void
+mail_request_finalize (GObject *object)
+{
+ EMailRequest *request = E_MAIL_REQUEST (object);
+
+ if (request->priv->output_stream) {
+ g_object_unref (request->priv->output_stream);
+ request->priv->output_stream = NULL;
+ }
+
+ if (request->priv->content_type) {
+ g_free (request->priv->content_type);
+ request->priv->content_type = NULL;
+ }
+
+ if (request->priv->uri_query) {
+ g_hash_table_destroy (request->priv->uri_query);
+ request->priv->uri_query = NULL;
+ }
+
+ G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
+}
+
+static gboolean
+mail_request_check_uri(SoupRequest *request,
+ SoupURI *uri,
+ GError **error)
+{
+ return ((strcmp (uri->scheme, "mail") == 0) ||
+ (strcmp (uri->scheme, "evo-file") == 0));
+}
+
+static void
+mail_request_send_async (SoupRequest *request,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EMailRequest *emr = E_MAIL_REQUEST (request);
+ GSimpleAsyncResult *result;
+ SoupURI *uri;
+
+ uri = soup_request_get_uri (request);
+
+ if (g_strcmp0 (uri->scheme, "mail") == 0) {
+ gchar *formatter;
+ emr->priv->uri_query = soup_form_decode (uri->query);
+
+ formatter = g_hash_table_lookup (emr->priv->uri_query, "formatter");
+
+ emr->priv->efh = GINT_TO_POINTER (atoi (formatter));
+ g_return_if_fail (EM_IS_FORMAT (emr->priv->efh));
+
+ result = g_simple_async_result_new (G_OBJECT (request), callback, user_data, mail_request_send_async);
+ g_simple_async_result_run_in_thread (result, start_mail_formatting, G_PRIORITY_DEFAULT, cancellable);
+ } else if (g_strcmp0 (uri->scheme, "evo-file") == 0) {
+ /* WebKit won't allow us to load data through local file:// protocol, when using "remote" mail://
+ protocol. evo-file:// behaves as file:// */
+ result = g_simple_async_result_new (G_OBJECT (request), callback, user_data, mail_request_send_async);
+ g_simple_async_result_run_in_thread (result, get_image_content, G_PRIORITY_DEFAULT, cancellable);
+ }
+}
+
+static GInputStream*
+mail_request_send_finish (SoupRequest *request,
+ GAsyncResult *result,
+ GError **error)
+{
+ GInputStream *stream;
+
+ stream = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+ g_object_unref (result);
+
+ return stream;
+}
+
+static goffset
+mail_request_get_content_length (SoupRequest *request)
+{
+ EMailRequest *emr = E_MAIL_REQUEST (request);
+ GByteArray *ba;
+
+ if (emr->priv->output_stream) {
+ ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (emr->priv->output_stream));
+ if (ba) {
+ return ba->len;
+ }
+ }
+
+ return 0;
+}
+
+static const gchar*
+mail_request_get_content_type (SoupRequest *request)
+{
+ EMailRequest *emr = E_MAIL_REQUEST (request);
+
+ return emr->priv->content_type;
+}
+
+static const char *data_schemes[] = { "mail", "evo-file", NULL };
+
+static void
+e_mail_request_class_init (EMailRequestClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ SoupRequestClass *request_class = SOUP_REQUEST_CLASS (class);
+
+ g_type_class_add_private (class, sizeof (EMailRequestPrivate));
+
+ object_class->finalize = mail_request_finalize;
+
+ request_class->schemes = data_schemes;
+ request_class->send_async = mail_request_send_async;
+ request_class->send_finish = mail_request_send_finish;
+ request_class->get_content_type = mail_request_get_content_type;
+ request_class->get_content_length = mail_request_get_content_length;
+ request_class->check_uri = mail_request_check_uri;
+}
diff --git a/mail/e-mail-request.h b/mail/e-mail-request.h
new file mode 100644
index 0000000..8d2b298
--- /dev/null
+++ b/mail/e-mail-request.h
@@ -0,0 +1,38 @@
+#ifndef E_MAIL_REQUEST_H
+#define E_MAIL_REQUEST_H
+
+#ifdef LIBSOUP_USE_UNSTABLE_REQUEST_API
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-request.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_MAIL_REQUEST (e_mail_request_get_type ())
+#define E_MAIL_REQUEST(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), E_TYPE_MAIL_REQUEST, EMailRequest))
+#define E_MAIL_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_MAIL_REQUEST, EMailRequestClass))
+#define E_IS_MAIL_REQUEST(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), E_TYPE_MAIL_REQUEST))
+#define E_IS_MAIL_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_MAIL_REQUEST))
+#define E_MAIL_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_MAIL_REQUEST, EMailRequestClass))
+
+typedef struct _EMailRequest EMailRequest;
+typedef struct _EMailRequestClass EMailRequestClass;
+typedef struct _EMailRequestPrivate EMailRequestPrivate;
+
+struct _EMailRequest {
+ SoupRequest parent;
+
+ EMailRequestPrivate *priv;
+};
+
+struct _EMailRequestClass {
+ SoupRequestClass parent;
+};
+
+GType e_mail_request_get_type (void);
+
+G_END_DECLS
+
+#endif /* LIBSOUP_USE_UNSTABLE_REQUEST_API */
+
+#endif /* E_MAIL_REQUEST_H */
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index f17f286..84585cb 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -76,17 +76,9 @@ struct _EMFormatHTMLCache {
struct _EMFormatHTMLPrivate {
EWebView *web_view;
- CamelMimeMessage *last_part; /* not reffed, DO NOT dereference */
- volatile gint format_id; /* format thread id */
- guint format_timeout_id;
- struct _format_msg *format_timeout_msg;
-
/* Table that re-maps text parts into a mutlipart/mixed, EMFormatHTMLCache * */
GHashTable *text_inline_parts;
- GQueue pending_jobs;
- GMutex *lock;
-
GdkColor colors[EM_FORMAT_HTML_NUM_COLOR_TYPES];
EMailImageLoadingPolicy image_loading_policy;
@@ -118,30 +110,6 @@ enum {
};
-static void emfh_format_email (struct _EMFormatHTMLJob *job,
- GCancellable *cancellable);
-
-static gboolean efh_display_formatted_data (gpointer data);
-
-static GtkWidget* efh_create_plugin_widget (WebKitWebView *web_view,
- gchar *mime_type,
- gchar *uri,
- GHashTable *param,
- gpointer user_data);
-static void efh_webview_frame_created (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- gpointer user_data);
-static void efh_resource_requested (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- WebKitWebResource *resource,
- WebKitNetworkRequest *request,
- WebKitNetworkResponse *reponse,
- gpointer user_data);
-static void efh_install_js_callbacks (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- gpointer context,
- gpointer window_object,
- gpointer user_data);
static void efh_format_message (EMFormat *emf,
CamelStream *stream,
CamelMimePart *part,
@@ -167,223 +135,6 @@ static CamelDataCache *emfh_http_cache;
#define EMFH_HTTP_CACHE_PATH "http"
-/* Sigh, this is so we have a cancellable, async rendering thread */
-struct _format_msg {
- MailMsg base;
-
- EMFormatHTML *format;
- EMFormat *format_source;
- CamelFolder *folder;
- gchar *uid;
- CamelMimeMessage *message;
- gboolean cancelled;
-};
-
-static gchar *
-efh_format_desc (struct _format_msg *m)
-{
- return g_strdup(_("Formatting message"));
-}
-
-static void
-efh_format_exec (struct _format_msg *m,
- GCancellable *cancellable,
- GError **error)
-{
- EMFormat *format;
- struct _EMFormatHTMLJob *job;
- GNode *puri_level;
- CamelURL *base;
-
- if (m->format->priv->web_view == NULL) {
- m->cancelled = TRUE;
- return;
- }
-
- format = EM_FORMAT (m->format);
-
- puri_level = format->pending_uri_level;
- base = format->base;
-
- do {
- d(printf("processing job\n"));
-
- g_mutex_lock (m->format->priv->lock);
- while ((job = g_queue_pop_head (&m->format->priv->pending_jobs))) {
-
- g_mutex_unlock (m->format->priv->lock);
-
- /* This is an implicit check to see if the webview has been destroyed */
- if (m->format->priv->web_view == NULL)
- g_cancellable_cancel (cancellable);
-
- /* call jobs even if cancelled, so they can clean up resources */
- format->pending_uri_level = job->puri_level;
- if (job->base)
- format->base = job->base;
- /* Call the job's callback, usually a parser */
- job->callback (job, cancellable);
- format->base = base;
-
- /* Display stream created by the callback and free
- the job struct */
- g_idle_add(efh_display_formatted_data, job);
-
- g_mutex_lock (m->format->priv->lock);
- }
- g_mutex_unlock (m->format->priv->lock);
-
- } while (!g_queue_is_empty (&m->format->priv->pending_jobs));
-
- d(printf("out of jobs, done\n"));
-
- format->pending_uri_level = puri_level;
-
- m->cancelled = m->cancelled || g_cancellable_is_cancelled (cancellable);
-
- m->format->priv->format_id = -1;
-}
-
-static void
-efh_format_done (struct _format_msg *m)
-{
- d(printf("formatting finished\n"));
-
- m->format->priv->format_id = -1;
- m->format->priv->load_images_now = FALSE;
- m->format->state = EM_FORMAT_HTML_STATE_NONE;
- g_signal_emit_by_name(m->format, "complete");
-}
-
-static void
-efh_format_free (struct _format_msg *m)
-{
- d(printf("formatter freed\n"));
- g_object_unref (m->format);
- if (m->folder)
- g_object_unref (m->folder);
- g_free (m->uid);
- if (m->message)
- g_object_unref (m->message);
- if (m->format_source)
- g_object_unref (m->format_source);
-}
-
-static MailMsgInfo efh_format_info = {
- sizeof (struct _format_msg),
- (MailMsgDescFunc) efh_format_desc,
- (MailMsgExecFunc) efh_format_exec,
- (MailMsgDoneFunc) efh_format_done,
- (MailMsgFreeFunc) efh_format_free
-};
-
-static gboolean
-efh_display_formatted_data (gpointer data)
-{
- /* This is an idle callback */
-
- struct _EMFormatHTMLJob *job = data;
- EWebView *web_view = job->format->priv->web_view;
- GByteArray *ba;
- gchar *content;
-
- if (web_view == NULL)
- goto cleanup;
-
- d(printf("displaying messsage\n"));
-
- ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (job->stream));
-
- content = g_strndup ((gchar*) ba->data, ba->len);
- e_web_view_load_string (web_view, content);
-
- g_free (content);
-
-cleanup:
- /* Clean up the job */
- g_object_unref (job->stream);
- if (job->base)
- camel_url_free (job->base);
- g_free (job);
-
- return FALSE;
-}
-
-static gboolean
-efh_format_timeout (struct _format_msg *m)
-{
- EMFormatHTML *efh = m->format;
- EMFormat *emf = EM_FORMAT (efh);
- struct _EMFormatHTMLPrivate *p = efh->priv;
- EWebView *web_view;
-
- web_view = em_format_html_get_web_view (efh);
-
- if (web_view == NULL) {
- mail_msg_unref (m);
- return FALSE;
- }
-
- d(printf("timeout called ...\n"));
- if (p->format_id != -1) {
- d(printf(" still waiting for cancellation to take effect, waiting ...\n"));
- return TRUE;
- }
-
- g_return_val_if_fail (g_queue_is_empty (&p->pending_jobs), FALSE);
-
- /* call super-class to kick it off */
- /* FIXME Not passing a GCancellable here. */
- EM_FORMAT_CLASS (parent_class)->format_clone (
- emf, m->folder, m->uid,
- m->message, m->format_source, NULL);
- em_format_html_clear_pobject (efh);
-
- /* FIXME: method off EMFormat? */
- if (emf->valid) {
- camel_cipher_validity_free (emf->valid);
- emf->valid = NULL;
- emf->valid_parent = NULL;
- }
-
- if (m->message == NULL) {
- mail_msg_unref (m);
- p->last_part = NULL;
- } else {
- struct _EMFormatHTMLJob *job;
-
- /* Queue a job for parsing the email main content */
- job = em_format_html_job_new (efh, emfh_format_email, m->message);
- job->stream = camel_stream_mem_new ();
- em_format_html_job_queue (efh, job);
-
- efh->state = EM_FORMAT_HTML_STATE_RENDERING;
-#if HAVE_CLUTTER
- if (p->last_part != m->message && !e_shell_get_express_mode (e_shell_get_default ())) {
-#else
- if (p->last_part != m->message) {
-#endif
- gchar *str = g_strdup_printf ("<html><head></head><body>"
- "<table width=\"100%%\" height=\"100%%\"><tr>"
- "<td valign=\"middle\" align=\"center\"><h5>%s</h5></td>"
- "</tr></table>"
- "</body></html>", _("Formatting Message..."));
- e_web_view_load_string (web_view, str);
- g_free (str);
-
- g_hash_table_remove_all (p->text_inline_parts);
-
- p->last_part = m->message;
- }
-
- mail_msg_unordered_push (m);
- }
-
- p->format_timeout_id = 0;
- p->format_timeout_msg = NULL;
-
- return FALSE;
-}
static void
efh_free_cache (struct _EMFormatHTMLCache *efhc)
@@ -613,17 +364,6 @@ efh_finalize (GObject *object)
em_format_html_clear_pobject (efh);
- if (priv->format_timeout_id != 0) {
- g_source_remove (priv->format_timeout_id);
- priv->format_timeout_id = 0;
- mail_msg_unref (priv->format_timeout_msg);
- priv->format_timeout_msg = NULL;
- }
-
- /* This probably works ... */
- if (priv->format_id != -1)
- mail_msg_cancel (priv->format_id);
-
if (priv->web_view != NULL) {
g_object_unref (priv->web_view);
efh->priv->web_view = NULL;
@@ -631,66 +371,11 @@ efh_finalize (GObject *object)
g_hash_table_destroy (priv->text_inline_parts);
- g_mutex_free (priv->lock);
-
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
-efh_format_clone (EMFormat *emf,
- CamelFolder *folder,
- const gchar *uid,
- CamelMimeMessage *msg,
- EMFormat *emfsource,
- GCancellable *cancellable)
-{
- EMFormatHTML *efh = EM_FORMAT_HTML (emf);
- struct _format_msg *m;
-
- /* No webview, no need to format anything */
- if (efh->priv->web_view == NULL)
- return;
-
- d(printf("efh_format called\n"));
- if (efh->priv->format_timeout_id != 0) {
- d(printf(" timeout for last still active, removing ...\n"));
- g_source_remove (efh->priv->format_timeout_id);
- efh->priv->format_timeout_id = 0;
- mail_msg_unref (efh->priv->format_timeout_msg);
- efh->priv->format_timeout_msg = NULL;
- }
-
- if (emfsource != NULL)
- g_object_ref (emfsource);
-
- if (folder != NULL)
- g_object_ref (folder);
-
- if (msg != NULL)
- g_object_ref (msg);
-
- m = mail_msg_new (&efh_format_info);
- m->format = g_object_ref (emf);
- m->format_source = emfsource;
- m->folder = folder;
- m->uid = g_strdup (uid);
- m->message = msg;
-
- if (efh->priv->format_id == -1) {
- d(printf(" idle, forcing format\n"));
- efh_format_timeout (m);
- } else {
- d(printf(" still busy, cancelling and queuing wait\n"));
- /* cancel and poll for completion */
- mail_msg_cancel (efh->priv->format_id);
- efh->priv->format_timeout_msg = m;
- efh->priv->format_timeout_id = g_timeout_add (
- 100, (GSourceFunc) efh_format_timeout, m);
- }
-}
-
-static void
efh_format_error (EMFormat *emf,
CamelStream *stream,
const gchar *txt)
@@ -780,15 +465,6 @@ efh_format_attachment (EMFormat *emf,
handle->handler (emf, stream, part, handle, cancellable, FALSE);
}
-static gboolean
-efh_busy (EMFormat *emf)
-{
- EMFormatHTMLPrivate *priv;
-
- priv = EM_FORMAT_HTML (emf)->priv;
-
- return (priv->format_id != -1);
-}
static void
efh_base_init (EMFormatHTMLClass *class)
{
@@ -811,12 +487,10 @@ efh_class_init (EMFormatHTMLClass *class)
object_class->finalize = efh_finalize;
format_class = EM_FORMAT_CLASS (class);
- format_class->format_clone = efh_format_clone;
format_class->format_error = efh_format_error;
format_class->format_source = efh_format_source;
format_class->format_attachment = efh_format_attachment;
format_class->format_secure = efh_format_secure;
- format_class->busy = efh_busy;
class->html_widget_type = E_TYPE_WEB_VIEW;
@@ -986,10 +660,6 @@ efh_init (EMFormatHTML *efh,
efh->priv = G_TYPE_INSTANCE_GET_PRIVATE (
efh, EM_TYPE_FORMAT_HTML, EMFormatHTMLPrivate);
- g_queue_init (&efh->pending_object_list);
- g_queue_init (&efh->priv->pending_jobs);
- efh->priv->lock = g_mutex_new ();
- efh->priv->format_id = -1;
efh->priv->text_inline_parts = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) NULL,
@@ -998,18 +668,7 @@ efh_init (EMFormatHTML *efh,
web_view = g_object_new (class->html_widget_type, NULL);
efh->priv->web_view = g_object_ref_sink (web_view);
- g_signal_connect (
- web_view, "resource-request-starting",
- G_CALLBACK (efh_resource_requested), efh);
- g_signal_connect (
- web_view, "create-plugin-widget",
- G_CALLBACK (efh_create_plugin_widget), efh);
- g_signal_connect (
- web_view, "frame-created",
- G_CALLBACK (efh_webview_frame_created), efh);
- g_signal_connect (
- web_view, "window-object-cleared",
- G_CALLBACK (efh_install_js_callbacks), efh);
+ g_queue_init (&efh->pending_object_list);
color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY];
gdk_color_parse ("#eeeeee", color);
@@ -1035,7 +694,7 @@ efh_init (EMFormatHTML *efh,
g_signal_connect_swapped (
efh, "notify::mark-citations",
- G_CALLBACK (em_format_queue_redraw), NULL);
+ G_CALLBACK (e_web_view_reload), web_view);
e_extensible_load_extensions (E_EXTENSIBLE (efh));
}
@@ -1095,7 +754,7 @@ em_format_html_load_images (EMFormatHTML *efh)
/* This will remain set while we're still
* rendering the same message, then it wont be. */
efh->priv->load_images_now = TRUE;
- em_format_queue_redraw (EM_FORMAT (efh));
+ e_web_view_reload (efh->priv->web_view);
}
void
@@ -1444,416 +1103,72 @@ em_format_html_clear_pobject (EMFormatHTML *efh)
}
}
-struct _EMFormatHTMLJob *
-em_format_html_job_new (EMFormatHTML *efh,
- void (*callback) (struct _EMFormatHTMLJob *job,
- GCancellable *cancellable),
- gpointer data)
-{
- EMFormat *emf = EM_FORMAT (efh);
- struct _EMFormatHTMLJob *job = g_malloc0 (sizeof (*job));
-
- job->format = efh;
- job->puri_level = emf->pending_uri_level;
- job->callback = callback;
- job->u.data = data;
-
- if (emf->base)
- job->base = camel_url_copy (emf->base);
-
- return job;
-}
-
void
-em_format_html_job_queue (EMFormatHTML *efh,
- struct _EMFormatHTMLJob *job)
+em_format_html_format_message (EMFormatHTML *efh,
+ CamelStream *stream,
+ GCancellable *cancellable)
{
- g_mutex_lock (efh->priv->lock);
- g_queue_push_tail (&efh->priv->pending_jobs, job);
- g_mutex_unlock (efh->priv->lock);
-
- /* If no formatting thread is running, then start one */
- if (efh->priv->format_id == -1) {
- struct _format_msg *m;
-
- d(printf("job queued, launching a new formatter thread\n"));
-
- m = mail_msg_new (&efh_format_info);
- m->format = g_object_ref (efh);
-
- mail_msg_unordered_push (m);
- } else {
- d(printf("job queued, a formatter thread already running\n"));
- }
-}
-
-/* ********************************************************************** */
-
-static void
-emfh_format_email (struct _EMFormatHTMLJob *job,
- GCancellable *cancellable)
-{
- EMFormat *format;
+ EMFormat *emf;
d(printf(" running format_email task\n"));
+
if (g_cancellable_is_cancelled (cancellable))
return;
- format = EM_FORMAT (job->format);
- if (format->mode == EM_FORMAT_MODE_SOURCE) {
+ emf = EM_FORMAT (efh);
+ em_format_html_clear_pobject(efh);
+ g_hash_table_remove_all (efh->priv->text_inline_parts);
+
+ if (emf->mode == EM_FORMAT_MODE_SOURCE) {
em_format_format_source (
- format, job->stream,
- CAMEL_MIME_PART (job->u.msg), cancellable);
+ emf, stream,
+ CAMEL_MIME_PART (emf->message), cancellable);
} else {
const EMFormatHandler *handle;
const gchar *mime_type;
mime_type = "x-evolution/message/prefix";
- handle = em_format_find_handler (format, mime_type);
+ handle = em_format_find_handler (emf, mime_type);
if (handle != NULL)
handle->handler (
- format, job->stream,
- CAMEL_MIME_PART (job->u.msg), handle,
+ emf, stream,
+ CAMEL_MIME_PART (emf->message), handle,
cancellable, FALSE);
mime_type = "x-evolution/message/rfc822";
- handle = em_format_find_handler (format, mime_type);
+ handle = em_format_find_handler (emf, mime_type);
if (handle != NULL)
handle->handler (
- format, job->stream,
- CAMEL_MIME_PART (job->u.msg), handle,
+ emf, stream,
+ CAMEL_MIME_PART (emf->message), handle,
cancellable, FALSE);
}
}
-#if 0 /* WEBKIT */
-
-static void
-emfh_getpuri (struct _EMFormatHTMLJob *job,
- GCancellable *cancellable)
-{
- d(printf(" running getpuri task\n"));
- if (!g_cancellable_is_cancelled (cancellable))
- job->u.puri->func (
- EM_FORMAT (job->format), job->stream,
- job->u.puri, cancellable);
-}
-
-static void
-emfh_gethttp (struct _EMFormatHTMLJob *job,
- GCancellable *cancellable)
-{
- CamelStream *cistream = NULL, *costream = NULL, *instream = NULL;
- CamelURL *url;
- CamelContentType *content_type;
- CamelHttpStream *tmp_stream;
- gssize n, total = 0, pc_complete = 0, nread = 0;
- gchar buffer[1500];
- const gchar *length;
-
- if (g_cancellable_is_cancelled (cancellable)
- || (url = camel_url_new (job->u.uri, NULL)) == NULL)
- goto badurl;
-
- d(printf(" running load uri task: %s\n", job->u.uri));
-
- if (emfh_http_cache)
- instream = cistream = camel_data_cache_get (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
- if (instream == NULL) {
- EMailImageLoadingPolicy policy;
- gchar *proxy;
-
- policy = em_format_html_get_image_loading_policy (job->format);
-
- if (!(job->format->priv->load_images_now
- || policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS
- || (policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES
- && em_utils_in_addressbook ((CamelInternetAddress *) camel_mime_message_get_from (job->format->parent.message), FALSE)))) {
- /* TODO: Ideally we would put the http requests into another queue and only send them out
- if the user selects 'load images', when they do. The problem is how to maintain this
- state with multiple renderings, and how to adjust the thread dispatch/setup routine to handle it */
- camel_url_free (url);
- goto done;
- }
-
- instream = camel_http_stream_new (CAMEL_HTTP_METHOD_GET, ((EMFormat *) job->format)->session, url);
- camel_http_stream_set_user_agent((CamelHttpStream *)instream, "CamelHttpStream/1.0 Evolution/" VERSION);
- proxy = em_utils_get_proxy_uri (job->u.uri);
- if (proxy) {
- camel_http_stream_set_proxy ((CamelHttpStream *) instream, proxy);
- g_free (proxy);
- }
- camel_operation_push_message (
- cancellable, _("Retrieving '%s'"), job->u.uri);
- tmp_stream = (CamelHttpStream *) instream;
- content_type = camel_http_stream_get_content_type (tmp_stream);
- length = camel_header_raw_find(&tmp_stream->headers, "Content-Length", NULL);
- d(printf(" Content-Length: %s\n", length));
- if (length != NULL)
- total = atoi (length);
- camel_content_type_unref (content_type);
- } else
- camel_operation_push_message (
- cancellable, _("Retrieving '%s'"), job->u.uri);
-
- camel_url_free (url);
-
- if (instream == NULL)
- goto done;
-
- if (emfh_http_cache != NULL && cistream == NULL)
- costream = camel_data_cache_add (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
-
- do {
- if (camel_operation_cancel_check (CAMEL_OPERATION (cancellable))) {
- n = -1;
- break;
- }
- /* FIXME: progress reporting in percentage, can we get the length always? do we care? */
- n = camel_stream_read (instream, buffer, sizeof (buffer), cancellable, NULL);
- if (n > 0) {
- nread += n;
- /* If we didn't get a valid Content-Length header, do not try to calculate percentage */
- if (total != 0) {
- pc_complete = ((nread * 100) / total);
- camel_operation_progress (cancellable, pc_complete);
- }
- d(printf(" read %d bytes\n", (int)n));
- if (costream && camel_stream_write (costream, buffer, n, cancellable, NULL) == -1) {
- n = -1;
- break;
- }
-
- camel_stream_write (job->stream, buffer, n, cancellable, NULL);
- }
- } while (n>0);
-
- /* indicates success */
- if (n == 0)
- camel_stream_close (job->stream, cancellable, NULL);
-
- if (costream) {
- /* do not store broken files in a cache */
- if (n != 0)
- camel_data_cache_remove (emfh_http_cache, EMFH_HTTP_CACHE_PATH, job->u.uri, NULL);
- g_object_unref (costream);
- }
-
- g_object_unref (instream);
-done:
- camel_operation_pop_message (cancellable);
-badurl:
- g_free (job->u.uri);
-}
-
-#endif /* WEBKIT */
-
-/* ********************************************************************** */
-static void
-efh_resource_requested (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebResource *resource,
- WebKitNetworkRequest *request, WebKitNetworkResponse *response, gpointer user_data)
+void
+em_format_html_format_message_part (EMFormatHTML *efh,
+ const gchar *part_id,
+ CamelStream *stream,
+ GCancellable *cancellable)
{
- EMFormatHTML *efh = user_data;
EMFormatPURI *puri;
- const gchar *p_uri = webkit_network_request_get_uri (request);
- const gchar *uri;
-
- d(printf("URI requested '%s'\n", p_uri));
-
- if (g_str_has_prefix (p_uri, "puri:")) {
- uri = &p_uri[5];
- } else {
- uri = p_uri;
- }
-
- puri = em_format_find_puri (EM_FORMAT (efh), uri);
- if (puri) {
- CamelDataWrapper *dw;
- CamelContentType *ct;
-
- dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part));
- if (!dw) {
- d(printf("PURI does not contain valid mimepart, skipping\n"));
- return;
- }
-
- ct = camel_data_wrapper_get_mime_type_field (dw);
-
- if (ct && (camel_content_type_is (ct, "text", "*")
- || camel_content_type_is (ct, "image", "*")
- || camel_content_type_is (ct, "application", "octet-stream"))) {
-
- gchar *data, *b64;
- gchar *cts = camel_data_wrapper_get_mime_type (dw);
- CamelStream *stream;
- GByteArray *ba;
-
- puri->use_count++;
-
- stream = camel_stream_mem_new ();
-
- camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
- ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
- b64 = g_base64_encode ((guchar*) ba->data, ba->len);
- if (camel_content_type_is (ct, "text", "*")) {
- const gchar *charset = camel_content_type_param (ct, "charset");
- data = g_strdup_printf ("data:%s;charset=%s;base64,%s", cts,
- charset ? charset : "utf-8", b64);
- } else {
- data = g_strdup_printf ("data:%s;base64,%s", cts, b64);
- }
-
- webkit_network_request_set_uri (request, data);
- g_free (b64);
- g_free (data);
- g_free (cts);
- g_object_unref (stream);
-
- } else {
- d(printf(" part is unknown type '%s', not using\n", ct ? camel_content_type_format(ct) : "<unset>"));
- }
- } else if (g_str_has_prefix(uri, "http:") || g_str_has_prefix (uri, "https:")) {
- d(printf(" Remote URI requetsed, webkit handling it\n"));
- } else if (g_str_has_prefix (uri, "file:")) {
- gchar *data = NULL;
- gsize length = 0;
- gboolean status;
- gchar *path;
- path = g_filename_from_uri (uri, NULL, NULL);
- if (!path)
- return;
-
- d(printf(" Local URI requested, loading file '%s'\n", path));
-
- status = g_file_get_contents (path, &data, &length, NULL);
- if (status) {
- gchar *b64, *new_uri;
- gchar *ct;
-
- b64 = g_base64_encode ((guchar*) data, length);
- ct = g_content_type_guess (path, NULL, 0, NULL);
-
- new_uri = g_strdup_printf ("data:%s;base64,%s", ct, b64);
- webkit_network_request_set_uri (request, new_uri);
-
- g_free (b64);
- g_free (new_uri);
- g_free (ct);
- }
- g_free (data);
- g_free (path);
- } else {
- d(printf("HTML Includes reference to unknown uri '%s'\n", uri));
- }
-
- g_signal_stop_emission_by_name (web_view, "resource-request-starting");
-}
-
-static GtkWidget*
-efh_create_plugin_widget (WebKitWebView *web_view,
- gchar *mime_type,
- gchar *uri,
- GHashTable *param,
- gpointer user_data)
-{
- EMFormatHTML *efh = user_data;
- EMFormatHTMLPObject *pobject;
- const gchar *classid;
-
- classid = g_hash_table_lookup (param, "data");
- if (!classid) {
- d(printf("Object does not have class-id, bailing.\n"));
- return NULL;
- }
-
- pobject = em_format_html_find_pobject (efh, classid);
- if (pobject) {
- GtkWidget *widget;
-
- d(printf("Creating widget for object '%s\n'", classid));
-
- /* This stops recursion of the part */
- g_queue_remove (&efh->pending_object_list, pobject);
- widget = pobject->func (efh, pobject);
- g_queue_push_head (&efh->pending_object_list, pobject);
-
- return widget;
- } else {
- d(printf("HTML includes reference to unknown object '%s'\n", uri));
- return NULL;
- }
-}
-
-static void
-efh_webview_frame_loaded (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- WebKitWebFrame *frame = WEBKIT_WEB_FRAME (object);
- WebKitWebView *web_view;
- const gchar *frame_name;
- gchar *script;
- GValue val = {0};
-
- /* Don't do anything until all content of the frame is loaded*/
- if (webkit_web_frame_get_load_status (frame) != WEBKIT_LOAD_FINISHED)
+ if (g_cancellable_is_cancelled (cancellable))
return;
- web_view = webkit_web_frame_get_web_view (frame);
- frame_name = webkit_web_frame_get_name (frame);
-
- /* Get total height of the document inside the frame */
- e_web_view_frame_exec_script (E_WEB_VIEW (web_view), frame_name, "document.body.scrollHeight;", &val);
+ em_format_push_level (EM_FORMAT (efh));
- /* Change height of the frame so that entire content is visible */
- script = g_strdup_printf ("window.document.getElementById(\"%s\").height=%d;", frame_name, (int)(g_value_get_double (&val) + 10));
- e_web_view_exec_script (E_WEB_VIEW (web_view), script, NULL);
- g_free (script);
-}
-
-
-static void
-efh_webview_frame_created (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- gpointer user_data)
-{
- if (frame != webkit_web_view_get_main_frame (web_view)) {
-
- /* Get notified when all content of frame is loaded */
- g_signal_connect (frame, "notify::load-status",
- G_CALLBACK (efh_webview_frame_loaded), NULL);
- }
-}
-
-static void
-efh_headers_collapsed_state_changed (EWebView *web_view, size_t arg_count, const JSValueRef args[], gpointer user_data)
-{
- EMFormatHTML *efh = user_data;
- JSGlobalContextRef ctx = e_web_view_get_global_context (web_view);
-
- gboolean collapsed = JSValueToBoolean (ctx, args[0]);
-
- if (collapsed) {
- em_format_html_set_headers_state (efh, EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED);
- } else {
- em_format_html_set_headers_state (efh, EM_FORMAT_HTML_HEADERS_STATE_EXPANDED);
+ puri = em_format_find_puri (EM_FORMAT (efh), part_id);
+ if (!puri) {
+ d(printf("Can't find PURI %s", part_id));
+ return;
}
+ puri->func (EM_FORMAT (efh), stream, puri, cancellable);
}
-static void
-efh_install_js_callbacks (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer context, gpointer window_object, gpointer user_data)
-{
- if (frame != webkit_web_view_get_main_frame (web_view))
- return;
-
- e_web_view_install_js_callback (E_WEB_VIEW (web_view), "headers_collapsed",
- (EWebViewJSFunctionCallback) efh_headers_collapsed_state_changed, user_data);
-}
/* ********************************************************************** */
#include "em-format/em-inline-filter.h"
@@ -2209,6 +1524,7 @@ efh_text_html (EMFormat *emf,
const gchar *location;
gchar *cid = NULL;
gchar *content;
+ gchar *mail_uri;
content = g_strdup_printf (
"<div style=\"border: solid #%06x 1px; "
@@ -2253,12 +1569,16 @@ efh_text_html (EMFormat *emf,
emf, sizeof (EMFormatPURI), cid,
part, efh_write_text_html);
d(printf("adding iframe, location %s\n", cid));
+
+ mail_uri = em_format_build_mail_uri (emf->folder, emf->uid, cid, emf);
+
content = g_strdup_printf (
- "<iframe name=\"html-frame-%s\" id=\"html-frame-%s\" src=\"puri:%s\" frameborder=0 scrolling=no width=\"100%%\" >" \
- "Could not get %s</iframe>\n</div>\n", cid, cid, cid, cid);
+ "<iframe name=\"html-frame-%s\" id=\"html-frame-%s\" src=\"%s\" frameborder=0 scrolling=no width=\"100%%\" >" \
+ "Could not get %s</iframe>\n</div>\n", cid, cid, mail_uri, cid);
camel_stream_write_string (stream, content, cancellable, NULL);
g_free (content);
g_free (cid);
+ g_free (mail_uri);
}
/* This is a lot of code for something useless ... */
@@ -2432,25 +1752,23 @@ emfh_write_related (EMFormat *emf,
}
static void
-emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
+emfh_multipart_related_check (EMFormat *emf,
+ CamelStream *stream,
GCancellable *cancellable)
{
- EMFormat *format;
GList *link;
gchar *oldpartid;
if (g_cancellable_is_cancelled (cancellable))
return;
- format = EM_FORMAT (job->format);
-
d(printf(" running multipart/related check task\n"));
- oldpartid = g_strdup (format->part_id->str);
+ oldpartid = g_strdup (emf->part_id->str);
- link = g_queue_peek_head_link (job->puri_level->data);
+ link = g_queue_peek_head_link (emf->pending_uri_level->data);
if (!link) {
- g_string_printf (format->part_id, "%s", oldpartid);
+ g_string_printf (emf->part_id, "%s", oldpartid);
g_free (oldpartid);
return;
}
@@ -2459,11 +1777,11 @@ emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
EMFormatPURI *puri = link->data;
if (puri->use_count == 0) {
- d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
+ d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"<no uri>", puri->cid, puri->use_count));
if (puri->func == emfh_write_related) {
- g_string_printf (format->part_id, "%s", puri->part_id);
+ g_string_printf (emf->part_id, "%s", puri->part_id);
em_format_part (
- format, CAMEL_STREAM (job->stream),
+ emf, CAMEL_STREAM (stream),
puri->part, cancellable);
}
/* else it was probably added by a previous format this loop */
@@ -2472,7 +1790,7 @@ emfh_multipart_related_check (struct _EMFormatHTMLJob *job,
link = g_list_next (link);
}
- g_string_printf (format->part_id, "%s", oldpartid);
+ g_string_printf (emf->part_id, "%s", oldpartid);
g_free (oldpartid);
}
@@ -2490,7 +1808,6 @@ efh_multipart_related (EMFormat *emf,
CamelContentType *content_type;
const gchar *start;
gint i, nparts, partidlen, displayid = 0;
- struct _EMFormatHTMLJob *job;
if (!CAMEL_IS_MULTIPART (mp)) {
em_format_format_source (emf, stream, part, cancellable);
@@ -2549,12 +1866,7 @@ efh_multipart_related (EMFormat *emf,
g_string_truncate (emf->part_id, partidlen);
camel_stream_flush (stream, cancellable, NULL);
- /* queue a job to check for un-referenced parts to add as attachments */
- job = em_format_html_job_new (
- EM_FORMAT_HTML (emf), emfh_multipart_related_check, NULL);
- job->stream = stream;
- g_object_ref (stream);
- em_format_html_job_queue ((EMFormatHTML *) emf, job);
+ emfh_multipart_related_check (emf, stream, cancellable);
em_format_pull_level (emf);
}
@@ -2783,7 +2095,6 @@ efh_format_address (EMFormatHTML *efh,
/* Let us add a '...' if we have more addresses */
if (limit > 0 && (i == limit - 1)) {
- gchar *evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
const gchar *id = NULL;
if (strcmp (field, _("To")) == 0) {
@@ -2796,11 +2107,9 @@ efh_format_address (EMFormatHTML *efh,
if (id) {
g_string_append_printf (out, "<span id=\"moreaddr-%s\" style=\"display: none;\">", id);
- str = g_strdup_printf ("<img src=\"%s/plus.png\" onClick=\"collapse_addresses('%s');\" id=\"moreaddr-img-%s\" class=\"navigable\"> ",
- evolution_imagesdir, id, id);
+ str = g_strdup_printf ("<img src=\"evo-file://%s/plus.png\" onClick=\"collapse_addresses('%s');\" id=\"moreaddr-img-%s\" class=\"navigable\"> ",
+ EVOLUTION_IMAGESDIR, id, id);
}
-
- g_free (evolution_imagesdir);
}
}
@@ -3358,18 +2667,14 @@ efh_format_full_headers (EMFormatHTML *efh,
static void
efh_format_headers (EMFormatHTML *efh,
- GString *buffer,
- CamelMedium *part,
+ GString *buffer,
+ CamelMedium *part,
GCancellable *cancellable)
{
- gchar *evolution_imagesdir;
if (!part)
return;
-
- evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
-
g_string_append_printf (
buffer, "<font color=\"#%06x\">\n"
"<table border=\"0\" width=\"100%%\">"
@@ -3380,8 +2685,8 @@ efh_format_headers (EMFormatHTML *efh,
if (efh->priv->headers_collapsable) {
g_string_append_printf (buffer,
- "<img src=\"%s/%s\" onClick=\"collapse_headers();\" class=\"navigable\" id=\"collapse-headers-img\" /></td><td>",
- evolution_imagesdir,
+ "<img src=\"evo-file://%s/%s\" onClick=\"collapse_headers();\" class=\"navigable\" id=\"collapse-headers-img\" /></td><td>",
+ EVOLUTION_IMAGESDIR,
(efh->priv->headers_state == EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED) ? "plus.png" : "minus.png");
efh_format_short_headers (efh, buffer, part,
@@ -3394,8 +2699,6 @@ efh_format_headers (EMFormatHTML *efh,
cancellable);
g_string_append (buffer, "</td></tr></table></font>");
-
- g_free (evolution_imagesdir);
}
static void
@@ -3420,7 +2723,7 @@ efh_format_message (EMFormat *emf,
g_string_append_printf (buffer,
"<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n" \
"<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\">\n" \
- "<link type=\"text/css\" rel=\"stylesheet\" href=\"file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
+ "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
"<style type=\"text/css\">\n" \
" table th { color: #000; font-weight: bold; }\n" \
"</style>\n" \
@@ -3457,7 +2760,7 @@ efh_format_message (EMFormat *emf,
if (!efh->hide_headers)
efh_format_headers (
- efh, buffer, CAMEL_MEDIUM (part), cancellable);
+ efh, buffer, CAMEL_MEDIUM (emf->message), cancellable);
camel_stream_write (
stream, buffer->str, buffer->len, cancellable, NULL);
@@ -3467,17 +2770,17 @@ efh_format_message (EMFormat *emf,
handle = em_format_find_handler(emf, "x-evolution/message/post-header");
if (handle)
handle->handler (
- emf, stream, part, handle, cancellable, FALSE);
+ emf, stream, CAMEL_MIME_PART (emf->message), handle, cancellable, FALSE);
camel_stream_write_string (
stream, EM_FORMAT_HTML_VPAD, cancellable, NULL);
- em_format_part (emf, stream, part, cancellable);
+ em_format_part (emf, stream, CAMEL_MIME_PART (emf->message), cancellable);
if (emf->message != (CamelMimeMessage *) part)
camel_stream_write_string (
stream, "</blockquote>\n", cancellable, NULL);
- camel_stream_write_string (stream, "</body></html", cancellable, NULL);
+ camel_stream_write_string (stream, "</body></html>", cancellable, NULL);
camel_cipher_validity_free (emf->valid);
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index 0485ba2..19ded94 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -83,55 +83,6 @@ typedef enum {
EM_FORMAT_HTML_NUM_COLOR_TYPES
} EMFormatHTMLColorType;
-/* A HTMLJob will be executed in another thread, in sequence.
- * It's job is to write to its stream, close it if successful,
- * then exit. */
-
-typedef struct _EMFormatHTMLJob EMFormatHTMLJob;
-
-typedef void (*EMFormatHTMLJobCallback) (EMFormatHTMLJob *job,
- GCancellable *cancellable);
-
-/**
- * struct _EMFormatHTMLJob - A formatting job.
- *
- * @format: Set by allocation function.
- * @stream: Free for use by caller.
- * @puri_level: Set by allocation function.
- * @base: Set by allocation function, used to save state.
- * @callback: This callback will always be invoked, only once, even if the user
- * cancelled the display. So the callback should free any extra data
- * it allocated every time it is called.
- * @u: Union data, free for caller to use.
- *
- * This object is used to queue a long-running-task which cannot be
- * processed in the primary thread. When its turn comes, the job will
- * be de-queued and the @callback invoked to perform its processing,
- * restoring various state to match the original state. This is used
- * for image loading and other internal tasks.
- *
- * This object is struct-subclassable. Only em_format_html_job_new()
- * may be used to allocate these.
- **/
-struct _EMFormatHTMLJob {
- EMFormatHTML *format;
- CamelStream *stream;
-
- /* We need to track the state of the visibility tree at
- * the point this uri was generated */
- GNode *puri_level;
- CamelURL *base;
-
- EMFormatHTMLJobCallback callback;
- union {
- gchar *uri;
- CamelMedium *msg;
- EMFormatPURI *puri;
- GNode *puri_level;
- gpointer data;
- } u;
-};
-
/* Pending object (classid: url) */
typedef struct _EMFormatHTMLPObject EMFormatHTMLPObject;
@@ -281,12 +232,7 @@ EMFormatHTMLPObject *
void em_format_html_remove_pobject (EMFormatHTML *efh,
EMFormatHTMLPObject *pobject);
void em_format_html_clear_pobject (EMFormatHTML *efh);
-EMFormatHTMLJob *
- em_format_html_job_new (EMFormatHTML *efh,
- EMFormatHTMLJobCallback callback,
- gpointer data);
-void em_format_html_job_queue (EMFormatHTML *efh,
- EMFormatHTMLJob *job);
+
gboolean em_format_html_get_show_real_date
(EMFormatHTML *efh);
void em_format_html_set_show_real_date
@@ -307,8 +253,23 @@ void em_format_html_set_headers_collapsable
gchar * em_format_html_format_cert_infos
(CamelCipherCertInfo *first_cinfo);
-CamelStream * em_format_html_get_cached_image (EMFormatHTML *efh,
+CamelStream *
+ em_format_html_get_cached_image (EMFormatHTML *efh,
const gchar *image_uri);
+
+void em_format_html_format_message (EMFormatHTML *efh,
+ CamelStream *stream,
+ GCancellable *cancellable);
+
+void em_format_html_format_message_part (EMFormatHTML *efh,
+ const gchar *part_id,
+ CamelStream *stream,
+ GCancellable *cancellable);
+void em_format_html_format_headers (EMFormatHTML *efh,
+ CamelStream *stream,
+ CamelMedium *part,
+ GCancellable *cancellable);
+
G_END_DECLS
#endif /* EM_FORMAT_HTML_H */
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 6797888..3d968be 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -398,6 +398,7 @@ em_utils_flag_for_followup (EMailReader *reader,
EShellSettings *shell_settings;
EShellBackend *shell_backend;
EMFormatHTML *formatter;
+ EWebView *web_view;
GtkWidget *editor;
GtkWindow *window;
CamelTag *tags;
@@ -488,7 +489,8 @@ em_utils_flag_for_followup (EMailReader *reader,
camel_tag_list_free (&tags);
formatter = e_mail_reader_get_formatter (reader);
- em_format_queue_redraw (EM_FORMAT (formatter));
+ web_view = em_format_html_get_web_view (formatter);
+ e_web_view_reload (web_view);
exit:
/* XXX We shouldn't be freeing this. */
diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c
index 9ab5895..b1c4438 100644
--- a/plugins/itip-formatter/itip-formatter.c
+++ b/plugins/itip-formatter/itip-formatter.c
@@ -2509,10 +2509,9 @@ in_proper_folder (CamelFolder *folder)
return res;
}
-static gboolean
+static GtkWidget*
format_itip_object (EMFormatHTML *efh,
- GtkHTMLEmbedded *eb,
- EMFormatHTMLPObject *pobject)
+ EMFormatHTMLPObject *pobject)
{
EShell *shell;
EShellSettings *shell_settings;
@@ -2548,11 +2547,12 @@ format_itip_object (EMFormatHTML *efh,
}
/* FIXME Handle multiple VEVENTS with the same UID, ie detached instances */
+#if 0 /* WEBKIT - FIXME!! */
if (!extract_itip_data (info, GTK_CONTAINER (eb), &have_alarms))
return TRUE;
+#endif
info->view = itip_view_new ();
- gtk_container_add (GTK_CONTAINER (eb), info->view);
gtk_widget_show (info->view);
response_enabled = in_proper_folder (((EMFormat *) efh)->folder);
@@ -2603,7 +2603,7 @@ format_itip_object (EMFormatHTML *efh,
itip_view_set_mode (ITIP_VIEW (info->view), ITIP_VIEW_MODE_REQUEST);
break;
default:
- return FALSE;
+ return NULL;
}
}
@@ -2830,7 +2830,7 @@ format_itip_object (EMFormatHTML *efh,
}
}
- return TRUE;
+ return info->view;
}
static void
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 640066f..0da46f7 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -35,6 +35,8 @@
#include <e-util/e-alert-sink.h>
#include <e-util/e-plugin-ui.h>
+#include <mail/e-mail-request.h>
+
#include "e-popup-action.h"
#include "e-selectable.h"
@@ -142,134 +144,6 @@ G_DEFINE_TYPE_WITH_CODE (
E_TYPE_SELECTABLE,
e_web_view_selectable_init))
-static EWebViewRequest *
-web_view_request_new (EWebView *web_view,
- const gchar *uri)
-{
- EWebViewRequest *request;
- GList *list;
-
- request = g_slice_new (EWebViewRequest);
-
- /* Try to detect file paths posing as URIs. */
- if (*uri == '/')
- request->file = g_file_new_for_path (uri);
- else
- request->file = g_file_new_for_uri (uri);
-
- request->web_view = g_object_ref (web_view);
- request->cancellable = g_cancellable_new ();
- request->input_stream = NULL;
- request->output_buffer = g_string_sized_new (4096);
-
- list = request->web_view->priv->requests;
- list = g_list_prepend (list, request);
- request->web_view->priv->requests = list;
-
- return request;
-}
-
-static void
-web_view_request_free (EWebViewRequest *request)
-{
- GList *list;
-
- list = request->web_view->priv->requests;
- list = g_list_remove (list, request);
- request->web_view->priv->requests = list;
-
- g_object_unref (request->file);
- g_object_unref (request->web_view);
- g_object_unref (request->cancellable);
-
- if (request->input_stream != NULL)
- g_object_unref (request->input_stream);
-
- g_string_free (request->output_buffer, TRUE);
-
- g_slice_free (EWebViewRequest, request);
-}
-
-static void
-web_view_request_cancel (EWebViewRequest *request)
-{
- g_cancellable_cancel (request->cancellable);
-}
-
-static gboolean
-web_view_request_check_for_error (EWebViewRequest *request,
- GError *error)
-{
- if (error == NULL)
- return FALSE;
-
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
- /* use this error, but do not close the stream */
- g_error_free (error);
- return TRUE;
- }
-
- /* XXX Should we log errors that are not cancellations? */
-
- web_view_request_free (request);
- g_error_free (error);
-
- return TRUE;
-}
-
-static void
-web_view_request_stream_read_cb (GInputStream *input_stream,
- GAsyncResult *result,
- EWebViewRequest *request)
-{
- gssize bytes_read;
- GError *error = NULL;
-
- bytes_read = g_input_stream_read_finish (input_stream, result, &error);
-
- if (web_view_request_check_for_error (request, error))
- return;
-
- if (bytes_read == 0) {
- e_web_view_load_string (
- request->web_view,
- request->output_buffer->str);
- web_view_request_free (request);
- return;
- }
-
- g_string_append_len (
- request->output_buffer, request->buffer, bytes_read);
-
- g_input_stream_read_async (
- request->input_stream, request->buffer,
- sizeof (request->buffer), G_PRIORITY_DEFAULT,
- request->cancellable, (GAsyncReadyCallback)
- web_view_request_stream_read_cb, request);
-}
-
-static void
-web_view_request_read_cb (GFile *file,
- GAsyncResult *result,
- EWebViewRequest *request)
-{
- GFileInputStream *input_stream;
- GError *error = NULL;
-
- /* Input stream might be NULL, so don't use cast macro. */
- input_stream = g_file_read_finish (file, result, &error);
- request->input_stream = (GInputStream *) input_stream;
-
- if (web_view_request_check_for_error (request, error))
- return;
-
- g_input_stream_read_async (
- request->input_stream, request->buffer,
- sizeof (request->buffer), G_PRIORITY_DEFAULT,
- request->cancellable, (GAsyncReadyCallback)
- web_view_request_stream_read_cb, request);
-}
-
static void
action_copy_clipboard_cb (GtkAction *action,
EWebView *web_view)
@@ -915,23 +789,6 @@ web_view_scroll_event (GtkWidget *widget,
return FALSE;
}
-#if 0 /* WEBKIT */
-static void
-web_view_url_requested (GtkHTML *html,
- const gchar *uri,
- GtkHTMLStream *stream)
-{
- EWebViewRequest *request;
-
- request = web_view_request_new (E_WEB_VIEW (html), uri, stream);
-
- g_file_read_async (
- request->file, G_PRIORITY_DEFAULT,
- request->cancellable, (GAsyncReadyCallback)
- web_view_request_read_cb, request);
-}
-#endif
-
static GtkWidget *
web_view_create_plugin_widget (EWebView *web_view,
const gchar *mime_type,
@@ -1139,10 +996,6 @@ web_view_popup_event (EWebView *web_view,
static void
web_view_stop_loading (EWebView *web_view)
{
- g_list_foreach (
- web_view->priv->requests, (GFunc)
- web_view_request_cancel, NULL);
-
webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
}
@@ -1645,6 +1498,8 @@ e_web_view_init (EWebView *web_view)
WebKitWebSettings *web_settings;
const gchar *domain = GETTEXT_PACKAGE;
const gchar *id;
+ GtkStyleContext *context;
+ const PangoFontDescription *font;
GError *error = NULL;
web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
@@ -1679,6 +1534,18 @@ e_web_view_init (EWebView *web_view)
web_settings = webkit_web_view_get_settings (
WEBKIT_WEB_VIEW (web_view));
+ /* Use same font-size as rest of Evolution */
+ context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
+ font = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL);
+ g_object_set (G_OBJECT (web_settings),
+ "default-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+ "default-monospace-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+ NULL);
+
+ /* Force frames to be as high as their content (e.g. no scrolling) */
+ g_object_set (G_OBJECT (web_settings), "enable-frame-flattening",
+ TRUE, NULL);
+
g_object_bind_property (
web_view, "caret-mode",
web_settings, "enable-caret-browsing",
@@ -1793,6 +1660,7 @@ e_web_view_init (EWebView *web_view)
e_plugin_ui_enable_manager (ui_manager, id);
e_extensible_load_extensions (E_EXTENSIBLE (web_view));
+
}
GtkWidget *
@@ -1837,6 +1705,14 @@ e_web_view_load_uri (EWebView *web_view,
class->load_uri (web_view, uri);
}
+void
+e_web_view_reload (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
+}
+
const gchar*
e_web_view_get_uri (EWebView *web_view)
{
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index d43b3eb..34bf415 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -110,6 +110,7 @@ void e_web_view_load_string (EWebView *web_view,
void e_web_view_load_uri (EWebView *web_view,
const gchar *uri);
const gchar* e_web_view_get_uri (EWebView *web_view);
+void e_web_view_reload (EWebView *web_view);
void e_web_view_frame_load_string (EWebView *web_view,
const gchar *frame_name,
const gchar *string);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]