diff options
author | Dan Vrátil <dvratil@redhat.com> | 2012-06-06 21:27:19 +0800 |
---|---|---|
committer | Dan Vrátil <dvratil@redhat.com> | 2012-06-06 21:27:19 +0800 |
commit | 5b8340563c271fb684a88c6e5bb6dd3bfb629058 (patch) | |
tree | c1c7d606fb4ce9fd2fe459a9226bfb9125423991 /mail | |
parent | 26a4f24188fd89dbabaff192bec9c54af8fe5a80 (diff) | |
download | gsoc2013-evolution-5b8340563c271fb684a88c6e5bb6dd3bfb629058.tar.gz gsoc2013-evolution-5b8340563c271fb684a88c6e5bb6dd3bfb629058.tar.zst gsoc2013-evolution-5b8340563c271fb684a88c6e5bb6dd3bfb629058.zip |
Mail formatter rewrite
All mail-parsing and formatting code has been moved to em-format.
Parsing is handeled by EMailParser class, formatting by EMailFormatter.
Both classes have registry which hold extensions - simple classes
that do actual parsing and formatting. Each supported mime-type
has it's own parser and formatter extension class.
Diffstat (limited to 'mail')
30 files changed, 1143 insertions, 7109 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am index da2c0eb692..7fa3dbab9c 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -44,7 +44,6 @@ mailinclude_HEADERS = \ e-mail-account-manager.h \ e-mail-account-store.h \ e-mail-account-tree-view.h \ - e-mail-attachment-bar.h \ e-mail-autoconfig.h \ e-mail-backend.h \ e-mail-browser.h \ @@ -101,10 +100,6 @@ mailinclude_HEADERS = \ em-folder-tree-model.h \ em-folder-tree.h \ em-folder-utils.h \ - em-format-hook.h \ - em-format-html-display.h \ - em-format-html-print.h \ - em-format-html.h \ em-search-context.h \ em-subscription-editor.h \ em-utils.h \ @@ -128,7 +123,6 @@ libevolution_mail_la_SOURCES = \ e-mail-account-manager.c \ e-mail-account-store.c \ e-mail-account-tree-view.c \ - e-mail-attachment-bar.c \ e-mail-autoconfig.c \ e-mail-backend.c \ e-mail-browser.c \ @@ -185,10 +179,6 @@ libevolution_mail_la_SOURCES = \ em-folder-tree-model.c \ em-folder-tree.c \ em-folder-utils.c \ - em-format-hook.c \ - em-format-html-display.c \ - em-format-html-print.c \ - em-format-html.c \ em-search-context.c \ em-subscription-editor.c \ em-utils.c \ diff --git a/mail/e-http-request.c b/mail/e-http-request.c index a9415b248a..95a97e62f6 100644 --- a/mail/e-http-request.c +++ b/mail/e-http-request.c @@ -26,10 +26,13 @@ #include <webkit/webkit.h> #include <e-util/e-util.h> +#include <mail/em-utils.h> +#include <libemail-engine/e-mail-enumtypes.h> #include <string.h> -#include "em-format-html.h" +#include <em-format/e-mail-formatter.h> +#include <shell/e-shell.h> #define d(x) @@ -41,7 +44,7 @@ struct _EHTTPRequestPrivate { gchar *content_type; gint content_length; - EMFormatHTML *efh; + EMailPartList *parts_list; }; G_DEFINE_TYPE (EHTTPRequest, e_http_request, SOUP_TYPE_REQUEST) @@ -208,9 +211,12 @@ handle_http_request (GSimpleAsyncResult *res, EHTTPRequest *request = E_HTTP_REQUEST (object); SoupURI *soup_uri; gchar *evo_uri, *uri; + gchar *mail_uri; GInputStream *stream; gboolean force_load_images = FALSE; + EMailImageLoadingPolicy image_policy; gchar *uri_md5; + EMailFormatter *formatter; const gchar *user_cache_dir; CamelDataCache *cache; @@ -222,9 +228,15 @@ handle_http_request (GSimpleAsyncResult *res, return; } + formatter = e_mail_formatter_new (); + /* Remove the __evo-mail query */ soup_uri = soup_request_get_uri (SOUP_REQUEST (request)); query = soup_form_decode (soup_uri->query); + mail_uri = g_hash_table_lookup (query, "__evo-mail"); + if (mail_uri) + mail_uri = g_strdup (mail_uri); + g_hash_table_remove (query, "__evo-mail"); /* Remove __evo-load-images if present (and in such case set @@ -306,7 +318,36 @@ handle_http_request (GSimpleAsyncResult *res, /* Item not found in cache, but image loading policy allows us to fetch * it from the interwebs */ - if (force_load_images || em_format_html_can_load_images (request->priv->efh)) { + image_policy = e_mail_formatter_get_image_loading_policy (formatter); + if (!force_load_images && mail_uri && + (image_policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES)) { + SoupSession *session; + GHashTable *parts; + gchar *decoded_uri; + EMailPartList *part_list; + + session = webkit_get_default_session (); + parts = g_object_get_data (G_OBJECT (session), "mails"); + decoded_uri = soup_uri_decode (mail_uri); + + part_list = g_hash_table_lookup (parts, decoded_uri); + if (part_list) { + EShell *shell; + ESourceRegistry *registry; + CamelInternetAddress *addr; + + shell = e_shell_get_default (); + registry = e_shell_get_registry (shell); + addr = camel_mime_message_get_from (part_list->message); + force_load_images = em_utils_in_addressbook ( + registry, addr, FALSE); + } + + g_free (decoded_uri); + } + + if ((image_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS) || + force_load_images) { SoupRequester *requester; SoupRequest *http_request; @@ -393,6 +434,8 @@ handle_http_request (GSimpleAsyncResult *res, cleanup: g_free (uri); g_free (uri_md5); + if (mail_uri) + g_free (mail_uri); } static void @@ -405,9 +448,9 @@ http_request_finalize (GObject *object) request->priv->content_type = NULL; } - if (request->priv->efh) { - g_object_unref (request->priv->efh); - request->priv->efh = NULL; + if (request->priv->parts_list) { + g_object_unref (request->priv->parts_list); + request->priv->parts_list = NULL; } G_OBJECT_CLASS (e_http_request_parent_class)->finalize (object); @@ -434,7 +477,7 @@ http_request_send_async (SoupRequest *request, SoupURI *uri; const gchar *enc; SoupSession *session; - GHashTable *formatters, *query; + GHashTable *mails, *query; ehr = E_HTTP_REQUEST (request); uri = soup_request_get_uri (request); @@ -452,16 +495,16 @@ http_request_send_async (SoupRequest *request, mail_uri = soup_uri_decode (enc); session = webkit_get_default_session (); - formatters = g_object_get_data (G_OBJECT (session), "formatters"); - g_return_if_fail (formatters != NULL); + mails = g_object_get_data (G_OBJECT (session), "mails"); + g_return_if_fail (mails != NULL); - ehr->priv->efh = g_hash_table_lookup (formatters, mail_uri); + ehr->priv->parts_list = g_hash_table_lookup (mails, mail_uri); g_free (mail_uri); - g_return_if_fail (ehr->priv->efh); + g_return_if_fail (ehr->priv->parts_list); /* Make sure the formatter lives until we are finished here */ - g_object_ref (ehr->priv->efh); + g_object_ref (ehr->priv->parts_list); simple = g_simple_async_result_new ( G_OBJECT (request), callback, diff --git a/mail/e-mail-attachment-bar.c b/mail/e-mail-attachment-bar.c deleted file mode 100644 index 495e327a3e..0000000000 --- a/mail/e-mail-attachment-bar.c +++ /dev/null @@ -1,771 +0,0 @@ -/* - * e-mail-attachment-bar.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) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-mail-attachment-bar.h" - -#include <glib/gi18n.h> - -#include "e-attachment-store.h" -#include "e-attachment-icon-view.h" -#include "e-attachment-tree-view.h" - -#define E_MAIL_ATTACHMENT_BAR_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarPrivate)) - -#define NUM_VIEWS 2 - -struct _EMailAttachmentBarPrivate { - GtkTreeModel *model; - GtkWidget *vbox; - GtkWidget *expander; - GtkWidget *combo_box; - GtkWidget *icon_view; - GtkWidget *tree_view; - GtkWidget *icon_frame; - GtkWidget *tree_frame; - GtkWidget *status_icon; - GtkWidget *status_label; - GtkWidget *save_all_button; - GtkWidget *save_one_button; - - gint active_view; - guint expanded : 1; -}; - -enum { - PROP_0, - PROP_ACTIVE_VIEW, - PROP_DRAGGING, - PROP_EDITABLE, - PROP_EXPANDED, - PROP_STORE -}; - -/* Forward Declarations */ -static void e_mail_attachment_bar_interface_init - (EAttachmentViewInterface *interface); - -G_DEFINE_TYPE_WITH_CODE ( - EMailAttachmentBar, - e_mail_attachment_bar, - GTK_TYPE_VBOX, - G_IMPLEMENT_INTERFACE ( - E_TYPE_ATTACHMENT_VIEW, - e_mail_attachment_bar_interface_init)) - -static void -mail_attachment_bar_update_status (EMailAttachmentBar *bar) -{ - EAttachmentStore *store; - GtkActivatable *activatable; - GtkAction *action; - GtkLabel *label; - gint num_attachments; - guint64 total_size; - gchar *display_size; - gchar *markup; - - store = E_ATTACHMENT_STORE (bar->priv->model); - label = GTK_LABEL (bar->priv->status_label); - - num_attachments = e_attachment_store_get_num_attachments (store); - total_size = e_attachment_store_get_total_size (store); - display_size = g_format_size_for_display (total_size); - - if (total_size > 0) - markup = g_strdup_printf ( - "<b>%d</b> %s (%s)", num_attachments, ngettext ( - "Attachment", "Attachments", num_attachments), - display_size); - else - markup = g_strdup_printf ( - "<b>%d</b> %s", num_attachments, ngettext ( - "Attachment", "Attachments", num_attachments)); - gtk_label_set_markup (label, markup); - g_free (markup); - - activatable = GTK_ACTIVATABLE (bar->priv->save_all_button); - action = gtk_activatable_get_related_action (activatable); - gtk_action_set_visible (action, (num_attachments > 1)); - - activatable = GTK_ACTIVATABLE (bar->priv->save_one_button); - action = gtk_activatable_get_related_action (activatable); - gtk_action_set_visible (action, (num_attachments == 1)); - - g_free (display_size); -} - -static void -mail_attachment_bar_set_store (EMailAttachmentBar *bar, - EAttachmentStore *store) -{ - g_return_if_fail (E_IS_ATTACHMENT_STORE (store)); - - bar->priv->model = g_object_ref (store); - - gtk_icon_view_set_model (GTK_ICON_VIEW (bar->priv->icon_view), - bar->priv->model); - gtk_tree_view_set_model (GTK_TREE_VIEW (bar->priv->tree_view), - bar->priv->model); - - g_signal_connect_swapped ( - bar->priv->model, "notify::num-attachments", - G_CALLBACK (mail_attachment_bar_update_status), bar); - - g_signal_connect_swapped ( - bar->priv->model, "notify::total-size", - G_CALLBACK (mail_attachment_bar_update_status), bar); - - /* Initialize */ - mail_attachment_bar_update_status (bar); -} - -static void -mail_attachment_bar_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACTIVE_VIEW: - e_mail_attachment_bar_set_active_view ( - E_MAIL_ATTACHMENT_BAR (object), - g_value_get_int (value)); - return; - - case PROP_DRAGGING: - e_attachment_view_set_dragging ( - E_ATTACHMENT_VIEW (object), - g_value_get_boolean (value)); - return; - - case PROP_EDITABLE: - e_attachment_view_set_editable ( - E_ATTACHMENT_VIEW (object), - g_value_get_boolean (value)); - return; - - case PROP_EXPANDED: - e_mail_attachment_bar_set_expanded ( - E_MAIL_ATTACHMENT_BAR (object), - g_value_get_boolean (value)); - return; - case PROP_STORE: - mail_attachment_bar_set_store ( - E_MAIL_ATTACHMENT_BAR (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_attachment_bar_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACTIVE_VIEW: - g_value_set_int ( - value, - e_mail_attachment_bar_get_active_view ( - E_MAIL_ATTACHMENT_BAR (object))); - return; - - case PROP_DRAGGING: - g_value_set_boolean ( - value, - e_attachment_view_get_dragging ( - E_ATTACHMENT_VIEW (object))); - return; - - case PROP_EDITABLE: - g_value_set_boolean ( - value, - e_attachment_view_get_editable ( - E_ATTACHMENT_VIEW (object))); - return; - - case PROP_EXPANDED: - g_value_set_boolean ( - value, - e_mail_attachment_bar_get_expanded ( - E_MAIL_ATTACHMENT_BAR (object))); - return; - case PROP_STORE: - g_value_set_object ( - value, - e_mail_attachment_bar_get_store ( - E_MAIL_ATTACHMENT_BAR (object))); - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_attachment_bar_dispose (GObject *object) -{ - EMailAttachmentBarPrivate *priv; - - priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object); - - if (priv->model != NULL) { - g_object_unref (priv->model); - priv->model = NULL; - } - - if (priv->vbox != NULL) { - g_object_unref (priv->vbox); - priv->vbox = NULL; - } - - if (priv->expander != NULL) { - g_object_unref (priv->expander); - priv->expander = NULL; - } - - if (priv->combo_box != NULL) { - g_object_unref (priv->combo_box); - priv->combo_box = NULL; - } - - if (priv->icon_view != NULL) { - g_object_unref (priv->icon_view); - priv->icon_view = NULL; - } - - if (priv->tree_view != NULL) { - g_object_unref (priv->tree_view); - priv->tree_view = NULL; - } - - if (priv->icon_frame != NULL) { - g_object_unref (priv->icon_frame); - priv->icon_frame = NULL; - } - - if (priv->tree_frame != NULL) { - g_object_unref (priv->tree_frame); - priv->tree_frame = NULL; - } - - if (priv->status_icon != NULL) { - g_object_unref (priv->status_icon); - priv->status_icon = NULL; - } - - if (priv->status_label != NULL) { - g_object_unref (priv->status_label); - priv->status_label = NULL; - } - - if (priv->save_all_button != NULL) { - g_object_unref (priv->save_all_button); - priv->save_all_button = NULL; - } - - if (priv->save_one_button != NULL) { - g_object_unref (priv->save_one_button); - priv->save_one_button = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_mail_attachment_bar_parent_class)->dispose (object); -} - -static void -mail_attachment_bar_constructed (GObject *object) -{ - EMailAttachmentBarPrivate *priv; - GSettings *settings; - - priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object); - - /* Set up property-to-property bindings. */ - - g_object_bind_property ( - object, "active-view", - priv->combo_box, "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "dragging", - priv->icon_view, "dragging", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "dragging", - priv->tree_view, "dragging", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "editable", - priv->icon_view, "editable", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "editable", - priv->tree_view, "editable", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "expanded", - priv->expander, "expanded", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "expanded", - priv->combo_box, "visible", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - object, "expanded", - priv->vbox, "visible", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - /* Set up property-to-GSettings bindings. */ - settings = g_settings_new ("org.gnome.evolution.shell"); - g_settings_bind ( - settings, "attachment-view", - object, "active-view", - G_SETTINGS_BIND_DEFAULT); - g_object_unref (settings); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_mail_attachment_bar_parent_class)->constructed (object); -} - -static EAttachmentViewPrivate * -mail_attachment_bar_get_private (EAttachmentView *view) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - return e_attachment_view_get_private (view); -} - -static GtkTreePath * -mail_attachment_bar_get_path_at_pos (EAttachmentView *view, - gint x, - gint y) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - return e_attachment_view_get_path_at_pos (view, x, y); -} - -static EAttachmentStore * -mail_attachment_bar_get_store (EAttachmentView *view) -{ - return e_mail_attachment_bar_get_store (E_MAIL_ATTACHMENT_BAR (view)); -} - -static GList * -mail_attachment_bar_get_selected_paths (EAttachmentView *view) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - return e_attachment_view_get_selected_paths (view); -} - -static gboolean -mail_attachment_bar_path_is_selected (EAttachmentView *view, - GtkTreePath *path) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - return e_attachment_view_path_is_selected (view, path); -} - -static void -mail_attachment_bar_select_path (EAttachmentView *view, - GtkTreePath *path) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - e_attachment_view_select_path (view, path); -} - -static void -mail_attachment_bar_unselect_path (EAttachmentView *view, - GtkTreePath *path) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - e_attachment_view_unselect_path (view, path); -} - -static void -mail_attachment_bar_select_all (EAttachmentView *view) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - e_attachment_view_select_all (view); -} - -static void -mail_attachment_bar_unselect_all (EAttachmentView *view) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - e_attachment_view_unselect_all (view); -} - -static void -mail_attachment_bar_update_actions (EAttachmentView *view) -{ - EMailAttachmentBar *bar; - - bar = E_MAIL_ATTACHMENT_BAR (view); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - - e_attachment_view_update_actions (view); -} - -static void -e_mail_attachment_bar_class_init (EMailAttachmentBarClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (EMailAttachmentBarPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_attachment_bar_set_property; - object_class->get_property = mail_attachment_bar_get_property; - object_class->dispose = mail_attachment_bar_dispose; - object_class->constructed = mail_attachment_bar_constructed; - - g_object_class_install_property ( - object_class, - PROP_ACTIVE_VIEW, - g_param_spec_int ( - "active-view", - "Active View", - NULL, - 0, - NUM_VIEWS, - 0, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_EXPANDED, - g_param_spec_boolean ( - "expanded", - "Expanded", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_STORE, - g_param_spec_object ( - "store", - "Attachment Store", - NULL, - E_TYPE_ATTACHMENT_STORE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_override_property ( - object_class, PROP_DRAGGING, "dragging"); - - g_object_class_override_property ( - object_class, PROP_EDITABLE, "editable"); -} - -static void -e_mail_attachment_bar_interface_init (EAttachmentViewInterface *interface) -{ - interface->get_private = mail_attachment_bar_get_private; - interface->get_store = mail_attachment_bar_get_store; - interface->get_path_at_pos = mail_attachment_bar_get_path_at_pos; - interface->get_selected_paths = mail_attachment_bar_get_selected_paths; - interface->path_is_selected = mail_attachment_bar_path_is_selected; - interface->select_path = mail_attachment_bar_select_path; - interface->unselect_path = mail_attachment_bar_unselect_path; - interface->select_all = mail_attachment_bar_select_all; - interface->unselect_all = mail_attachment_bar_unselect_all; - interface->update_actions = mail_attachment_bar_update_actions; -} - -static void -e_mail_attachment_bar_init (EMailAttachmentBar *bar) -{ - EAttachmentView *view; - GtkSizeGroup *size_group; - GtkWidget *container; - GtkWidget *widget; - GtkAction *action; - - bar->priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (bar); - - gtk_box_set_spacing (GTK_BOX (bar), 6); - - /* Keep the expander label and save button the same height. */ - size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); - - /* Construct the Attachment Views */ - - container = GTK_WIDGET (bar); - - widget = gtk_vbox_new (FALSE, 0); - gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->vbox = g_object_ref (widget); - gtk_widget_show (widget); - - container = bar->priv->vbox; - - widget = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - bar->priv->icon_frame = g_object_ref (widget); - gtk_widget_show (widget); - - container = widget; - - widget = e_attachment_icon_view_new (); - gtk_widget_set_can_focus (widget, TRUE); - gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model); - gtk_container_add (GTK_CONTAINER (container), widget); - bar->priv->icon_view = g_object_ref (widget); - gtk_widget_show (widget); - - container = bar->priv->vbox; - - widget = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - bar->priv->tree_frame = g_object_ref (widget); - gtk_widget_hide (widget); - - container = widget; - - widget = e_attachment_tree_view_new (); - gtk_widget_set_can_focus (widget, TRUE); - gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model); - gtk_container_add (GTK_CONTAINER (container), widget); - bar->priv->tree_view = g_object_ref (widget); - gtk_widget_show (widget); - - /* Construct the Controls */ - - container = GTK_WIDGET (bar); - - widget = gtk_hbox_new (FALSE, 12); - gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_expander_new (NULL); - gtk_expander_set_spacing (GTK_EXPANDER (widget), 0); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->expander = g_object_ref (widget); - gtk_widget_show (widget); - - /* The "Save All" button proxies the "save-all" action from - * one of the two attachment views. Doesn't matter which. */ - widget = gtk_button_new (); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - action = e_attachment_view_get_action (view, "save-all"); - gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->save_all_button = g_object_ref (widget); - gtk_widget_show (widget); - - /* Same deal with the "Save" button. */ - widget = gtk_button_new (); - view = E_ATTACHMENT_VIEW (bar->priv->icon_view); - action = e_attachment_view_get_action (view, "save-one"); - gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->save_one_button = g_object_ref (widget); - gtk_widget_show (widget); - - widget = gtk_alignment_new (1.0, 0.5, 0.0, 0.0); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_combo_box_text_new (); - gtk_size_group_add_widget (size_group, widget); - gtk_combo_box_text_append_text ( - GTK_COMBO_BOX_TEXT (widget), _("Icon View")); - gtk_combo_box_text_append_text ( - GTK_COMBO_BOX_TEXT (widget), _("List View")); - gtk_container_add (GTK_CONTAINER (container), widget); - bar->priv->combo_box = g_object_ref (widget); - gtk_widget_show (widget); - - container = bar->priv->expander; - - widget = gtk_hbox_new (FALSE, 6); - gtk_size_group_add_widget (size_group, widget); - gtk_expander_set_label_widget (GTK_EXPANDER (container), widget); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_image_new_from_icon_name ( - "mail-attachment", GTK_ICON_SIZE_MENU); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->status_icon = g_object_ref (widget); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - bar->priv->status_label = g_object_ref (widget); - gtk_widget_show (widget); - - g_object_unref (size_group); -} - -GtkWidget * -e_mail_attachment_bar_new (EAttachmentStore *store) -{ - g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL); - - return g_object_new ( - E_TYPE_MAIL_ATTACHMENT_BAR, - "editable", FALSE, - "store", store, NULL); -} - -gint -e_mail_attachment_bar_get_active_view (EMailAttachmentBar *bar) -{ - g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), 0); - - return bar->priv->active_view; -} - -void -e_mail_attachment_bar_set_active_view (EMailAttachmentBar *bar, - gint active_view) -{ - EAttachmentView *source; - EAttachmentView *target; - - g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar)); - g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS); - - if (active_view == bar->priv->active_view) - return; - - bar->priv->active_view = active_view; - - if (active_view == 0) { - gtk_widget_show (bar->priv->icon_frame); - gtk_widget_hide (bar->priv->tree_frame); - } else { - gtk_widget_hide (bar->priv->icon_frame); - gtk_widget_show (bar->priv->tree_frame); - } - - /* Synchronize the item selection of the view we're - * switching TO with the view we're switching FROM. */ - if (active_view == 0) { - /* from tree view to icon view */ - source = E_ATTACHMENT_VIEW (bar->priv->tree_view); - target = E_ATTACHMENT_VIEW (bar->priv->icon_view); - } else { - /* from icon view to tree view */ - source = E_ATTACHMENT_VIEW (bar->priv->icon_view); - target = E_ATTACHMENT_VIEW (bar->priv->tree_view); - } - - e_attachment_view_sync_selection (source, target); - - g_object_notify (G_OBJECT (bar), "active-view"); -} - -gboolean -e_mail_attachment_bar_get_expanded (EMailAttachmentBar *bar) -{ - g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), FALSE); - - return bar->priv->expanded; -} - -void -e_mail_attachment_bar_set_expanded (EMailAttachmentBar *bar, - gboolean expanded) -{ - g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar)); - - bar->priv->expanded = expanded; - - g_object_notify (G_OBJECT (bar), "expanded"); -} - -EAttachmentStore * -e_mail_attachment_bar_get_store (EMailAttachmentBar *bar) -{ - g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), NULL); - - return E_ATTACHMENT_STORE (bar->priv->model); -} diff --git a/mail/e-mail-attachment-bar.h b/mail/e-mail-attachment-bar.h deleted file mode 100644 index b83d9733e0..0000000000 --- a/mail/e-mail-attachment-bar.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * e-mail-attachment-bar.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_ATTACHMENT_BAR_H -#define E_MAIL_ATTACHMENT_BAR_H - -#include <gtk/gtk.h> -#include <misc/e-attachment-view.h> - -/* Standard GObject macros */ -#define E_TYPE_MAIL_ATTACHMENT_BAR \ - (e_mail_attachment_bar_get_type ()) -#define E_MAIL_ATTACHMENT_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBar)) -#define E_MAIL_ATTACHMENT_BAR_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarClass)) -#define E_IS_MAIL_ATTACHMENT_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MAIL_ATTACHMENT_BAR)) -#define E_IS_MAIL_ATTACHMENT_BAR_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MAIL_ATTACHMENT_BAR)) -#define E_MAIL_ATTACHMENT_BAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarClass)) - -G_BEGIN_DECLS - -typedef struct _EMailAttachmentBar EMailAttachmentBar; -typedef struct _EMailAttachmentBarClass EMailAttachmentBarClass; -typedef struct _EMailAttachmentBarPrivate EMailAttachmentBarPrivate; - -struct _EMailAttachmentBar { - GtkVBox parent; - EMailAttachmentBarPrivate *priv; -}; - -struct _EMailAttachmentBarClass { - GtkVBoxClass parent_class; -}; - -GType e_mail_attachment_bar_get_type (void); -GtkWidget * e_mail_attachment_bar_new (EAttachmentStore *store); -gint e_mail_attachment_bar_get_active_view - (EMailAttachmentBar *bar); -void e_mail_attachment_bar_set_active_view - (EMailAttachmentBar *bar, - gint active_view); -gboolean e_mail_attachment_bar_get_expanded - (EMailAttachmentBar *bar); -void e_mail_attachment_bar_set_expanded - (EMailAttachmentBar *bar, - gboolean expanded); -EAttachmentStore * - e_mail_attachment_bar_get_store (EMailAttachmentBar *bar); - -G_END_DECLS - -#endif /* E_MAIL_ATTACHMENT_BAR_H */ diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c index 806980d602..eda9d6cbc3 100644 --- a/mail/e-mail-browser.c +++ b/mail/e-mail-browser.c @@ -39,7 +39,6 @@ #include "mail/e-mail-reader.h" #include "mail/e-mail-reader-utils.h" #include "mail/em-folder-tree-model.h" -#include "mail/em-format-html-display.h" #include "mail/message-list.h" #define E_MAIL_BROWSER_GET_PRIVATE(obj) \ @@ -56,7 +55,7 @@ struct _EMailBrowserPrivate { GtkUIManager *ui_manager; EFocusTracker *focus_tracker; - EMFormatWriteMode mode; + EMailFormatterMode mode; GtkWidget *main_menu; GtkWidget *main_toolbar; @@ -915,7 +914,7 @@ e_mail_browser_class_init (EMailBrowserClass *class) NULL, 0, G_MAXINT, - EM_FORMAT_WRITE_MODE_NORMAL, + E_MAIL_FORMATTER_MODE_NORMAL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } @@ -951,7 +950,7 @@ GtkWidget * e_mail_browser_new (EMailBackend *backend, CamelFolder *folder, const gchar *msg_uid, - EMFormatWriteMode mode) + EMailFormatterMode mode) { GtkWidget *widget; diff --git a/mail/e-mail-browser.h b/mail/e-mail-browser.h index 88f8174a9d..849daebce4 100644 --- a/mail/e-mail-browser.h +++ b/mail/e-mail-browser.h @@ -64,7 +64,7 @@ GType e_mail_browser_get_type (void); GtkWidget * e_mail_browser_new (EMailBackend *backend, CamelFolder *folder, const gchar *message_uid, - EMFormatWriteMode mode); + EMailFormatterMode mode); void e_mail_browser_close (EMailBrowser *browser); gboolean e_mail_browser_get_show_deleted (EMailBrowser *browser); void e_mail_browser_set_show_deleted (EMailBrowser *browser, diff --git a/mail/e-mail-config-lookup-page.c b/mail/e-mail-config-lookup-page.c index 0154a053b1..d200c3cba0 100644 --- a/mail/e-mail-config-lookup-page.c +++ b/mail/e-mail-config-lookup-page.c @@ -29,7 +29,7 @@ G_DEFINE_TYPE_WITH_CODE ( EMailConfigLookupPage, e_mail_config_lookup_page, GTK_TYPE_BOX, - G_IMPLEMENT_INTERFACE( + G_IMPLEMENT_INTERFACE ( E_TYPE_MAIL_CONFIG_PAGE, e_mail_config_lookup_page_interface_init)) diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c index ca807a6899..4f72e843f6 100644 --- a/mail/e-mail-display.c +++ b/mail/e-mail-display.c @@ -28,6 +28,12 @@ #include <glib/gi18n.h> #include <gdk/gdk.h> +#include <em-format/e-mail-part-utils.h> +#include <em-format/e-mail-formatter-extension.h> +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-part-attachment.h> +#include <em-format/e-mail-formatter-print.h> + #include "e-util/e-marshal.h" #include "e-util/e-util.h" #include "e-util/e-plugin-ui.h" @@ -37,8 +43,7 @@ #include "mail/em-utils.h" #include "mail/e-mail-request.h" #include "mail/e-http-request.h" -#include "mail/em-format-html-display.h" -#include "mail/e-mail-attachment-bar.h" +#include "widgets/misc/e-attachment-bar.h" #include "widgets/misc/e-attachment-button.h" #include <camel/camel.h> @@ -54,9 +59,10 @@ G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW) ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate)) struct _EMailDisplayPrivate { - EMFormatHTML *formatter; + EMailPartList *part_list; + EMailFormatterMode mode; + EMailFormatter *formatter; - EMFormatWriteMode mode; gboolean headers_collapsable; gboolean headers_collapsed; @@ -66,12 +72,14 @@ struct _EMailDisplayPrivate { gint force_image_load: 1; GSettings *settings; + + GHashTable *widgets; }; enum { PROP_0, - PROP_FORMATTER, PROP_MODE, + PROP_PART_LIST, PROP_HEADERS_COLLAPSABLE, PROP_HEADERS_COLLAPSED, }; @@ -197,45 +205,15 @@ formatter_image_loading_policy_changed_cb (GObject *object, static void mail_display_update_formatter_colors (EMailDisplay *display) { - EMFormatHTMLColorType type; - EMFormatHTML *formatter; - GdkColor *color; - GtkStateType state; GtkStyle *style; - - state = gtk_widget_get_state (GTK_WIDGET (display)); - formatter = display->priv->formatter; + GtkStateType state; if (!display->priv->formatter) return; 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)); + state = gtk_widget_get_state (GTK_WIDGET (display)); + e_mail_formatter_set_style (display->priv->formatter, style, state); } static void @@ -245,10 +223,10 @@ mail_display_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_FORMATTER: - e_mail_display_set_formatter ( + case PROP_PART_LIST: + e_mail_display_set_parts_list ( E_MAIL_DISPLAY (object), - g_value_get_object (value)); + g_value_get_pointer (value)); return; case PROP_MODE: e_mail_display_set_mode ( @@ -277,9 +255,9 @@ mail_display_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_FORMATTER: - g_value_set_object ( - value, e_mail_display_get_formatter ( + case PROP_PART_LIST: + g_value_set_pointer ( + value, e_mail_display_get_parts_list ( E_MAIL_DISPLAY (object))); return; case PROP_MODE: @@ -309,9 +287,9 @@ mail_display_dispose (GObject *object) priv = E_MAIL_DISPLAY_GET_PRIVATE (object); - if (priv->formatter) { - g_object_unref (priv->formatter); - priv->formatter = NULL; + if (priv->part_list) { + g_object_unref (priv->part_list); + priv->part_list = NULL; } if (priv->settings) { @@ -319,6 +297,11 @@ mail_display_dispose (GObject *object) priv->settings = NULL; } + if (priv->widgets) { + g_hash_table_destroy (priv->widgets); + priv->widgets = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -353,18 +336,14 @@ mail_display_process_mailto (EWebView *web_view, g_return_val_if_fail (mailto_uri != NULL, FALSE); if (g_ascii_strncasecmp (mailto_uri, "mailto:", 7) == 0) { - EMFormat *format; - CamelFolder *folder = NULL; EShell *shell; + EMailPartList *part_list; - format = (EMFormat *) E_MAIL_DISPLAY (web_view)->priv->formatter; - - if (format != NULL && format->folder != NULL) - folder = format->folder; + part_list = E_MAIL_DISPLAY (web_view)->priv->part_list; shell = e_shell_get_default (); em_utils_compose_new_message_with_mailto ( - shell, mailto_uri, folder); + shell, mailto_uri, part_list->folder); return TRUE; } @@ -380,7 +359,6 @@ mail_display_link_clicked (WebKitWebView *web_view, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { - EMailDisplay *display; const gchar *uri = webkit_network_request_get_uri (request); if (g_str_has_prefix (uri, "file://")) { @@ -397,10 +375,6 @@ mail_display_link_clicked (WebKitWebView *web_view, g_free (filename); } - display = E_MAIL_DISPLAY (web_view); - if (display->priv->formatter == NULL) - return FALSE; - if (mail_display_process_mailto (E_WEB_VIEW (web_view), uri, NULL)) { /* do nothing, function handled the "mailto:" uri already */ webkit_web_policy_decision_ignore (policy_decision); @@ -457,10 +431,11 @@ mail_display_resource_requested (WebKitWebView *web_view, gpointer user_data) { EMailDisplay *display = E_MAIL_DISPLAY (web_view); - EMFormat *formatter = EM_FORMAT (display->priv->formatter); + EMailPartList *part_list; const gchar *uri = webkit_network_request_get_uri (request); - if (!formatter) { + part_list = display->priv->part_list; + if (!part_list) { return; } @@ -468,10 +443,10 @@ mail_display_resource_requested (WebKitWebView *web_view, if (g_str_has_prefix (uri, "cid:")) { /* Always write raw content of CID object */ - gchar *new_uri = em_format_build_mail_uri (formatter->folder, - formatter->message_uid, + gchar *new_uri = e_mail_part_build_uri ( + part_list->folder, part_list->message_uid, "part_id", G_TYPE_STRING, uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, NULL); + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL); webkit_network_request_set_uri (request, new_uri); @@ -499,6 +474,7 @@ mail_display_resource_requested (WebKitWebView *web_view, GHashTable *query; gchar *uri_md5; CamelStream *stream; + EMailImageLoadingPolicy image_policy; /* Open Evolution's cache */ uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1); @@ -509,15 +485,17 @@ mail_display_resource_requested (WebKitWebView *web_view, /* If the URI is not cached and we are not allowed to load it * then redirect to invalid URI, so that webkit would display * a native placeholder for it. */ + image_policy = e_mail_formatter_get_image_loading_policy ( + display->priv->formatter); if (!stream && !display->priv->force_image_load && - !em_format_html_can_load_images (display->priv->formatter)) { + (image_policy == E_MAIL_IMAGE_LOADING_POLICY_NEVER)) { webkit_network_request_set_uri (request, "about:blank"); return; } new_uri = g_strconcat ("evo-", uri, NULL); - mail_uri = em_format_build_mail_uri (formatter->folder, - formatter->message_uid, NULL, NULL); + mail_uri = e_mail_part_build_uri (part_list->folder, + part_list->message_uid, NULL, NULL); soup_uri = soup_uri_new (new_uri); if (soup_uri->query) { @@ -557,6 +535,9 @@ find_element_by_id (WebKitDOMDocument *document, WebKitDOMElement *element; gulong i, length; + if (!WEBKIT_DOM_IS_DOCUMENT (document)) + return NULL; + /* Try to look up the element in this DOM document */ element = webkit_dom_document_get_element_by_id (document, id); if (element) @@ -595,7 +576,6 @@ mail_display_plugin_widget_resize (GObject *object, gint height; widget = GTK_WIDGET (object); - gtk_widget_get_preferred_height (widget, &height, NULL); parent_element = g_object_get_data (object, "parent_element"); if (!parent_element || !WEBKIT_DOM_IS_ELEMENT (parent_element)) { @@ -604,6 +584,14 @@ mail_display_plugin_widget_resize (GObject *object, return; } + /* For attachment bar, we need to ask for height it's parent, + * GtkBox, because EAttachmentBar itself lies about it's real height. */ + if (E_IS_ATTACHMENT_BAR (widget)) { + widget = gtk_widget_get_parent (widget); + } + + gtk_widget_get_preferred_height (widget, &height, NULL); + /* Int -> Str */ dim = g_strdup_printf ("%d", height); @@ -618,6 +606,31 @@ static void mail_display_plugin_widget_realize_cb (GtkWidget *widget, gpointer user_data) { + WebKitDOMHTMLElement *el; + + if (GTK_IS_BOX (widget)) { + GList *children; + + children = gtk_container_get_children (GTK_CONTAINER (widget)); + if (children && children->data && + E_IS_ATTACHMENT_BAR (children->data)) { + widget = children->data; + } + + g_list_free (children); + } + + /* First check if we are actually supposed to be visible */ + el = g_object_get_data (G_OBJECT (widget), "parent_element"); + if (!el || !WEBKIT_DOM_IS_HTML_ELEMENT (el)) { + g_warning ("UAAAAA"); + } else { + if (webkit_dom_html_element_get_hidden (el)) { + gtk_widget_hide (widget); + return; + } + } + /* Initial resize of the <object> element when the widget * is displayed for the first time. */ mail_display_plugin_widget_resize (G_OBJECT (widget), NULL, user_data); @@ -647,166 +660,184 @@ plugin_widget_set_parent_element (GtkWidget *widget, * and the GtkWidget to "widget" data of the DOM Element */ g_object_set_data (G_OBJECT (widget), "parent_element", element); g_object_set_data (G_OBJECT (element), "widget", widget); + + g_object_bind_property ( + element, "hidden", + widget, "visible", + G_BINDING_SYNC_CREATE | + G_BINDING_INVERT_BOOLEAN); } static void -attachment_button_expanded (GObject *object, - GParamSpec *pspec, - gpointer user_data) +toggle_widget_visibility (EAttachmentButton *button, + EMailDisplay *display, + WebKitDOMElement *element) { - EAttachmentButton *button = E_ATTACHMENT_BUTTON (object); - WebKitDOMElement *attachment = user_data; - WebKitDOMCSSStyleDeclaration *css; - gboolean expanded; + gchar *id; + GtkWidget *widget; - d(printf("Attachment button %s (%p) expansion state toggled!\n", - (gchar *) g_object_get_data (object, "uri"), object)); + id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (element)); + if (!id || !*id) { + return; + } - expanded = e_attachment_button_get_expanded (button) && - gtk_widget_get_visible (GTK_WIDGET (button)); + if (!display->priv->widgets) { + g_free (id); + return; + } - if (!WEBKIT_DOM_IS_ELEMENT (attachment)) { - d(printf("%s: Parent element for button %s does not exist!\n", - G_STRFUNC, (gchar *) g_object_get_data (object, "uri"))); + widget = g_hash_table_lookup (display->priv->widgets, id); + g_free (id); + if (!widget) { return; } - /* Show or hide the DIV which contains the attachment (iframe, image...) */ - css = webkit_dom_element_get_style (attachment); - webkit_dom_css_style_declaration_set_property ( - css, "display", expanded ? "block" : "none", "", NULL); -} + /* If the widget encapsulates EAttachmentBar then check, whether + * the attachment bar is not empty. We want to display it only + * when there's at least one attachment */ + if (GTK_IS_BOX (widget)) { + GList *children; -static void -constraint_widget_visibility (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - GtkWidget *widget = GTK_WIDGET (object); - EAttachmentButton *button = user_data; + children = gtk_container_get_children (GTK_CONTAINER (widget)); + if (children && children->data && E_IS_ATTACHMENT_BAR (children->data)) { + EAttachmentStore *store; - gboolean can_show = e_attachment_button_get_expanded (button); - gboolean is_visible = gtk_widget_get_visible (widget); + store = e_attachment_bar_get_store ( + E_ATTACHMENT_BAR (children->data)); - if (is_visible && !can_show) - gtk_widget_hide (widget); - else if (!is_visible && can_show) - gtk_widget_show (widget); + g_list_free (children); + + /* Don't allow to display such attachment bar, + * but always allow to hide it */ + if (e_attachment_button_get_expanded (button) && + (e_attachment_store_get_num_attachments (store) == 0)) { + return; + } + } + } - /* Otherwise it's OK */ + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (element), + !e_attachment_button_get_expanded (button)); + + if (e_attachment_button_get_expanded (button)) { + gtk_widget_show (widget); + } else { + gtk_widget_hide (widget); + } } +/** + * @button: An #EAttachmentButton + * @iframe: An iframe element containing document with an attachment + * represented by the @button + */ static void -bind_iframe_content_visibility (EAttachmentButton *button, - WebKitDOMElement *iframe) +bind_iframe_content_visibility (WebKitDOMElement *iframe, + EMailDisplay *display, + EAttachmentButton *button) { WebKitDOMDocument *document; WebKitDOMNodeList *nodes; gulong i, length; - if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe)) + if (!iframe || !WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe)) return; document = webkit_dom_html_iframe_element_get_content_document ( WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)); + if (!WEBKIT_DOM_IS_DOCUMENT (document)) + return; + nodes = webkit_dom_document_get_elements_by_tag_name (document, "object"); length = webkit_dom_node_list_get_length (nodes); - d(printf("Found %ld objects within iframe %s\n", length, - webkit_dom_html_iframe_element_get_name ( - WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)))); + d ({ + gchar *name = webkit_dom_html_iframe_element_get_name ( + WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)); + printf("Found %ld objects within iframe %s\n", length, name); + g_free (name); + }); /* Iterate through all <object>s and bind visibility of their widget * with expanded-state of related attachment button */ for (i = 0; i < length; i++) { WebKitDOMNode *node = webkit_dom_node_list_item (nodes, i); - GtkWidget *widget; - - widget = g_object_get_data (G_OBJECT (node), "widget"); - if (!widget) - continue; - - d(printf("Binding visibility of widget %s (%p) with button %s (%p)\n", - (gchar *) g_object_get_data (G_OBJECT (widget), "uri"), widget, - (gchar *) g_object_get_data (G_OBJECT (button), "uri"), button)); - - g_object_bind_property ( - button, "expanded", - widget, "visible", - G_BINDING_SYNC_CREATE); - /* Ensure that someone won't attempt to _show() the widget when - * it is supposed to be hidden and vice versa. */ - g_signal_connect (widget, "notify::visible", - G_CALLBACK (constraint_widget_visibility), button); + /* Initial sync */ + toggle_widget_visibility (button, display, WEBKIT_DOM_ELEMENT (node)); } } static void -bind_attachment_iframe_visibility (GObject *object, - GParamSpec *pspec, - gpointer user_data) +attachment_button_expanded (GObject *object, + GParamSpec *pspec, + gpointer user_data) { - WebKitWebFrame *webframe; - const gchar *frame_name; - gchar *button_uri; + EAttachmentButton *button = E_ATTACHMENT_BUTTON (object); + EMailDisplay *display = user_data; WebKitDOMDocument *document; - WebKitDOMElement *attachment; - WebKitDOMElement *button_element; - WebKitDOMNodeList *nodes; - gulong i, length; - GtkWidget *button; - - /* Whenever an <iframe> is loaded, bind visibility of all GtkWidgets - * the document within the <iframe> contains with "expanded" property - * of the EAttachmentButton */ + WebKitDOMElement *element; + WebKitDOMCSSStyleDeclaration *css; + gboolean expanded; + gchar *id; - webframe = WEBKIT_WEB_FRAME (object); - if (webkit_web_frame_get_load_status (webframe) != WEBKIT_LOAD_FINISHED) - return; + d(printf("Attachment button %s has been %s!\n", + (gchar *) g_object_get_data (object, "uri"), + (e_attachment_button_get_expanded (button) ? "expanded" : "collapsed"))); - frame_name = webkit_web_frame_get_name (webframe); + expanded = e_attachment_button_get_expanded (button) && + gtk_widget_get_visible (GTK_WIDGET (button)); - d(printf("Rebinding visibility of frame %s because it's URL changed\n", - frame_name)); + document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display)); + element = find_element_by_id (document, g_object_get_data (object, "attachment_id")); - /* Get DOMDocument of the main document */ - document = webkit_web_view_get_dom_document ( - webkit_web_frame_get_web_view (webframe)); - if (!document) + if (!WEBKIT_DOM_IS_ELEMENT (element)) { + d(printf("%s: Content <div> of attachment %s does not exist!!\n", + G_STRFUNC, (gchar *) g_object_get_data (object, "uri"))); return; + } - /* Find the <DIV> containing the <iframe> and related EAttachmentButton - * within the DOM */ - attachment = find_element_by_id (document, frame_name); - if (!attachment) - return; + /* Show or hide the DIV which contains the attachment (iframe, image...) */ + css = webkit_dom_element_get_style (element); + webkit_dom_css_style_declaration_set_property ( + css, "display", expanded ? "block" : "none", "", NULL); + + id = g_strconcat (g_object_get_data (object, "attachment_id"), ".iframe", NULL); + element = find_element_by_id (document, id); + g_free (id); - button_uri = g_strconcat (frame_name, ".attachment_button", NULL); - button_element = find_element_by_id (document, button_uri); - g_free (button_uri); - if (!button_element) + if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) { + d(printf("%s: No <iframe> found\n", + (gchar *) g_object_get_data (object, "attachment_id"))); return; + } + bind_iframe_content_visibility (element, display, button); +} - button = g_object_get_data (G_OBJECT (button_element), "widget"); +static void +mail_display_attachment_count_changed (EAttachmentStore *store, + GParamSpec *pspec, + GtkWidget *box) +{ + WebKitDOMHTMLElement *element; + GList *children; - /* Get <iframe> representing the attachment content */ - nodes = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe"); - length = webkit_dom_node_list_get_length (nodes); - for (i = 0; i < length; i++) { + children = gtk_container_get_children (GTK_CONTAINER (box)); + g_return_if_fail (children && children->data); - WebKitDOMNode *node = - webkit_dom_node_list_item (nodes, i); + element = g_object_get_data (children->data, "parent_element"); + g_list_free (children); - if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) - continue; + g_return_if_fail (WEBKIT_DOM_IS_HTML_ELEMENT (element)); - /* Bind visibility of all GtkWidget within the - * iframe with "expanded" property of the button */ - bind_iframe_content_visibility ( - E_ATTACHMENT_BUTTON (button), - WEBKIT_DOM_ELEMENT (node)); + if (e_attachment_store_get_num_attachments (store) == 0) { + gtk_widget_hide (box); + webkit_dom_html_element_set_hidden (element, TRUE); + } else { + gtk_widget_show (box); + webkit_dom_html_element_set_hidden (element, FALSE); } } @@ -817,44 +848,91 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view, GHashTable *param, gpointer user_data) { - EMFormat *emf; EMailDisplay *display; - EMFormatPURI *puri; + EMailExtensionRegistry *reg; + EMailFormatterExtension *extension; + GQueue *extensions; + GList *iter; + EMailPart *part; GtkWidget *widget; - gchar *puri_uri; + gchar *part_id, *type, *object_uri; - puri_uri = g_hash_table_lookup (param, "data"); - if (!puri_uri || !g_str_has_prefix (uri, "mail://")) + part_id = g_hash_table_lookup (param, "data"); + if (!part_id || !g_str_has_prefix (uri, "mail://")) + return NULL; + + type = g_hash_table_lookup (param, "type"); + if (!type) return NULL; display = E_MAIL_DISPLAY (web_view); - emf = (EMFormat *) display->priv->formatter; - puri = em_format_find_puri (emf, puri_uri); - if (!puri) { + if ((widget = g_hash_table_lookup (display->priv->widgets, part_id)) != NULL) { + d(printf("Handeled %s widget request from cache\n", part_id)); + return widget; + } + + /* Findt EMailPart representing requested widget */ + part = e_mail_part_list_find_part (display->priv->part_list, part_id); + if (!part) { return NULL; } - if (puri->widget_func) - widget = puri->widget_func (emf, puri, NULL); - else - widget = NULL; + reg = e_mail_formatter_get_extension_registry (display->priv->formatter); + extensions = e_mail_extension_registry_get_for_mime_type (reg, type); + if (!extensions) + return NULL; + + extension = NULL; + for (iter = g_queue_peek_head_link (extensions); iter; iter = iter->next) { + + extension = iter->data; + if (!extension) + continue; + if (e_mail_formatter_extension_has_widget (extension)) + break; + } + + if (!extension) + return NULL; + + /* Get the widget from formatter */ + widget = e_mail_formatter_extension_get_widget ( + extension, display->priv->part_list, part, param); + d(printf("Created widget %s (%p) for part %s\n", + G_OBJECT_TYPE_NAME (widget), widget, part_id)); + + /* Should not happen! WebKit will display an ugly 'Plug-in not available' + * placeholder instead of hiding the <object> element */ if (!widget) return NULL; + /* Attachment button has URI different then the actual PURI because + * that URI identifies the attachment itself */ if (E_IS_ATTACHMENT_BUTTON (widget)) { - /* Attachment button has URI different then the actual PURI because - * that URI identifies the attachment itself */ - gchar *button_uri = g_strconcat (puri_uri, ".attachment_button", NULL); - g_object_set_data_full (G_OBJECT (widget), "uri", - button_uri, (GDestroyNotify) g_free); + EMailPartAttachment *empa = (EMailPartAttachment *) part; + gchar *attachment_part_id; + + if (empa->attachment_view_part_id) + attachment_part_id = empa->attachment_view_part_id; + else + attachment_part_id = part_id; + + object_uri = g_strconcat (attachment_part_id, ".attachment_button", NULL); + g_object_set_data_full (G_OBJECT (widget), "attachment_id", + g_strdup (attachment_part_id), (GDestroyNotify) g_free); } else { - g_object_set_data_full (G_OBJECT (widget), "uri", - g_strdup (puri_uri), (GDestroyNotify) g_free); + object_uri = g_strdup (part_id); } - /* Set widget's <object> container as GObject data "parent_element" */ + /* Store the uri as data of the widget */ + g_object_set_data_full (G_OBJECT (widget), "uri", + object_uri, (GDestroyNotify) g_free); + + /* Set pointer to the <object> element as GObject data "parent_element" + * and set pointer to the widget as GObject data "widget" to the <object> + * element */ plugin_widget_set_parent_element (widget, display); /* Resizing a GtkWidget requires changing size of parent @@ -864,26 +942,32 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view, g_signal_connect (widget, "size-allocate", G_CALLBACK (mail_display_plugin_widget_resize), display); - /* Embed the attachment bar into the GtkBox before we do anything - * further with the widget. */ - if (E_IS_MAIL_ATTACHMENT_BAR (widget)) { - - /* When EMailAttachmentBar is expanded/collapsed it does not - * emit size-allocate signal despite it changes it's height. */ + if (E_IS_ATTACHMENT_BAR (widget)) { GtkWidget *box = NULL; + EAttachmentStore *store; - /* Only when packed in box, EMailAttachmentBar reports correct - * height */ - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0); + /* Only when packed in box (grid does not work), + * EAttachmentBar reports correct height */ + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0); + /* When EAttachmentBar is expanded/collapsed it does not + * emit size-allocate signal despite it changes it's height. */ g_signal_connect (widget, "notify::expanded", G_CALLBACK (mail_display_plugin_widget_resize), display); g_signal_connect (widget, "notify::active-view", G_CALLBACK (mail_display_plugin_widget_resize), display); - /* Show the EAttachmentBar but not the containing layout */ + /* Always hide an attachment bar without attachments */ + store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (widget)); + g_signal_connect (store, "notify::num-attachments", + G_CALLBACK (mail_display_attachment_count_changed), box); + gtk_widget_show (widget); + gtk_widget_show (box); + + /* Initial sync */ + mail_display_attachment_count_changed (store, NULL, box); widget = box; @@ -894,61 +978,63 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view, * attachment button. */ WebKitDOMElement *attachment; WebKitDOMDocument *document; + EMailPartAttachment *empa = (EMailPartAttachment *) part; + gchar *attachment_part_id; + + if (empa->attachment_view_part_id) + attachment_part_id = empa->attachment_view_part_id; + else + attachment_part_id = part_id; + /* Find attachment-wrapper div which contains the content of the + * attachment (iframe) */ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display)); - attachment = find_element_by_id (document, puri_uri); + attachment = find_element_by_id (document, attachment_part_id); + + /* None found? Attachment cannot be expanded */ if (!attachment) { e_attachment_button_set_expandable ( E_ATTACHMENT_BUTTON (widget), FALSE); } else { const CamelContentDisposition *disposition; - WebKitDOMNodeList *nodes; - gulong i, length; - - /* Show/hide the attachment when the EAttachmentButton - * is expanded/collapsed or shown/hidden */ - g_signal_connect_data (widget, "notify::expanded", - G_CALLBACK (attachment_button_expanded), - g_object_ref (attachment), (GClosureNotify) g_object_unref, 0); - g_signal_connect_data (widget, "notify::visible", - G_CALLBACK (attachment_button_expanded), - g_object_ref (attachment), (GClosureNotify) g_object_unref, 0); - /* Initial synchronization */ - attachment_button_expanded (G_OBJECT (widget), - NULL, attachment); - - /* Find all <iframes> within the attachment and bind - * it's visiblity to expanded state of the attachment btn */ - nodes = webkit_dom_element_get_elements_by_tag_name ( - attachment, "iframe"); - length = webkit_dom_node_list_get_length (nodes); - for (i = 0; i < length; i++) { - - WebKitDOMNode *node = - webkit_dom_node_list_item (nodes, i); - - if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) - continue; - - bind_iframe_content_visibility ( - E_ATTACHMENT_BUTTON (widget), - WEBKIT_DOM_ELEMENT (node)); - } - /* Expand inlined attachments */ + e_attachment_button_set_expandable ( + E_ATTACHMENT_BUTTON (widget), TRUE); + + /* Show/hide the attachment when the EAttachmentButton + * * is expanded/collapsed or shown/hidden */ + g_signal_connect (widget, "notify::expanded", + G_CALLBACK (attachment_button_expanded), display); + g_signal_connect (widget, "notify::visible", + G_CALLBACK (attachment_button_expanded), display); + + /* Automatically expand attachments that have inline + * disposition or the EMailParts have specific force_inline + * flag set */ disposition = - camel_mime_part_get_content_disposition (puri->part); - if (disposition && - g_ascii_strncasecmp ( - disposition->disposition, "inline", 6) == 0) { + camel_mime_part_get_content_disposition (part->part); + if (!part->force_collapse && + (part->force_inline || + (g_strcmp0 (empa->snoop_mime_type, "message/rfc822") == 0) || + (disposition && disposition->disposition && + g_ascii_strncasecmp ( + disposition->disposition, "inline", 6) == 0))) { e_attachment_button_set_expanded ( E_ATTACHMENT_BUTTON (widget), TRUE); + } else { + e_attachment_button_set_expanded ( + E_ATTACHMENT_BUTTON (widget), FALSE); + attachment_button_expanded ( + G_OBJECT (widget), NULL, display); } } } - d(printf("Created widget %s (%p)\n", puri_uri, widget)); + g_hash_table_insert ( + display->priv->widgets, + g_strdup (object_uri), g_object_ref (widget)); + return widget; } @@ -1123,18 +1209,17 @@ setup_DOM_bindings (GObject *object, } static void -puri_bind_dom (GObject *object, - GParamSpec *pspec, - gpointer user_data) +mail_parts_bind_dom (GObject *object, + GParamSpec *pspec, + gpointer user_data) { WebKitWebFrame *frame; WebKitLoadStatus load_status; WebKitWebView *web_view; WebKitDOMDocument *document; EMailDisplay *display; - GList *iter; - EMFormat *emf; - const gchar *frame_puri; + GSList *iter; + const gchar *frame_name; frame = WEBKIT_WEB_FRAME (object); load_status = webkit_web_frame_get_load_status (frame); @@ -1142,36 +1227,40 @@ puri_bind_dom (GObject *object, if (load_status != WEBKIT_LOAD_FINISHED) return; - frame_puri = webkit_web_frame_get_name (frame); web_view = webkit_web_frame_get_web_view (frame); display = E_MAIL_DISPLAY (web_view); - - emf = EM_FORMAT (display->priv->formatter); - if (!emf) + if (display->priv->part_list == NULL) return; - iter = g_hash_table_lookup ( - emf->mail_part_table, - webkit_web_frame_get_name (frame)); + frame_name = webkit_web_frame_get_name (frame); + for (iter = display->priv->part_list->list; iter; iter = iter->next) { + + EMailPart *part = iter->data; + if (!part) + continue; - document = webkit_web_view_get_dom_document (web_view); + if (g_strcmp0 (part->id, frame_name) == 0) + break; + } + document = webkit_web_view_get_dom_document (web_view); while (iter) { - EMFormatPURI *puri = iter->data; - - if (!puri) + EMailPart *part = iter->data; + if (!part) { + iter = iter->next; continue; + } - /* Iterate only the PURI rendered in the frame and all it's "subPURIs" */ - if (!g_str_has_prefix (puri->uri, frame_puri)) + /* Iterate only the parts rendered in the frame and all it's subparts */ + if (!g_str_has_prefix (part->id, frame_name)) break; - if (puri->bind_func) { - WebKitDOMElement *el = find_element_by_id (document, puri->uri); + if (part->bind_func) { + WebKitDOMElement *el = find_element_by_id (document, part->id); if (el) { - d(printf("bind_func for %s\n", puri->uri)); - puri->bind_func (el, puri); + d(printf("/*bind_func*/ for %s\n", part->id)); + part->bind_func (part, el); } } @@ -1186,15 +1275,25 @@ mail_display_frame_created (WebKitWebView *web_view, { d(printf("Frame %s created!\n", webkit_web_frame_get_name (frame))); - /* Re-bind visibility of this newly created <iframe> with - * related EAttachmentButton whenever content of this <iframe> is - * (re)loaded */ + /* Call bind_func of all parts written in this frame */ g_signal_connect (frame, "notify::load-status", - G_CALLBACK (bind_attachment_iframe_visibility), NULL); + G_CALLBACK (mail_parts_bind_dom), NULL); +} - /* Call bind_func of all PURIs written in this frame */ - g_signal_connect (frame, "notify::load-status", - G_CALLBACK (puri_bind_dom), NULL); +static void +mail_display_uri_changed (EMailDisplay *display, + GParamSpec *pspec, + gpointer dummy) +{ + d(printf("EMailDisplay URI changed, recreating widgets hashtable\n")); + + if (display->priv->widgets) + g_hash_table_destroy (display->priv->widgets); + + display->priv->widgets = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); } static void @@ -1253,12 +1352,11 @@ e_mail_display_class_init (EMailDisplayClass *class) g_object_class_install_property ( object_class, - PROP_FORMATTER, - g_param_spec_object ( - "formatter", - "HTML Formatter", + PROP_PART_LIST, + g_param_spec_pointer ( + "part-list", + "Part List", NULL, - EM_TYPE_FORMAT_HTML, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -1268,9 +1366,9 @@ e_mail_display_class_init (EMailDisplayClass *class) "mode", "Display Mode", NULL, - 0, + E_MAIL_FORMATTER_MODE_INVALID, G_MAXINT, - EM_FORMAT_WRITE_MODE_NORMAL, + E_MAIL_FORMATTER_MODE_NORMAL, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -1305,6 +1403,10 @@ e_mail_display_init (EMailDisplay *display) display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display); + /* Set invalid mode so that MODE property initialization is run + * completely (see e_mail_display_set_mode) */ + display->priv->mode = E_MAIL_FORMATTER_MODE_INVALID; + e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_NORMAL); display->priv->force_image_load = FALSE; display->priv->mailto_actions = gtk_action_group_new ("mailto"); gtk_action_group_add_actions (display->priv->mailto_actions, mailto_entries, @@ -1331,6 +1433,8 @@ e_mail_display_init (EMailDisplay *display) G_CALLBACK (mail_display_plugin_widget_requested), NULL); g_signal_connect (display, "frame-created", G_CALLBACK (mail_display_frame_created), NULL); + g_signal_connect (display, "notify::uri", + G_CALLBACK (mail_display_uri_changed), NULL); display->priv->settings = g_settings_new ("org.gnome.evolution.mail"); g_signal_connect_swapped ( @@ -1350,7 +1454,7 @@ e_mail_display_init (EMailDisplay *display) G_CALLBACK (setup_DOM_bindings), NULL); main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display)); g_signal_connect (main_frame, "notify::load-status", - G_CALLBACK (puri_bind_dom), NULL); + G_CALLBACK (mail_parts_bind_dom), NULL); /* Because we are loading from a hard-coded string, there is * no chance of I/O errors. Failure here implies a malformed @@ -1387,75 +1491,99 @@ e_mail_display_init (EMailDisplay *display) } } -EMFormatHTML * -e_mail_display_get_formatter (EMailDisplay *display) +EMailFormatterMode +e_mail_display_get_mode (EMailDisplay *display) { - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), + E_MAIL_FORMATTER_MODE_NORMAL); - return display->priv->formatter; + return display->priv->mode; } void -e_mail_display_set_formatter (EMailDisplay *display, - EMFormatHTML *formatter) +e_mail_display_set_mode (EMailDisplay *display, + EMailFormatterMode mode) { + EMailFormatter *formatter; g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - if (formatter) { - g_return_if_fail (EM_IS_FORMAT_HTML (formatter)); - g_object_ref (formatter); - } - - if (display->priv->formatter != NULL) { - /* The formatter might still exist after unrefing it, so - * we need to stop listening to it's request for redrawing */ - g_signal_handlers_disconnect_by_func ( - display->priv->formatter, e_mail_display_reload, display); - g_object_unref (display->priv->formatter); - } + if (display->priv->mode == mode) + return; - display->priv->formatter = formatter; + display->priv->mode = mode; - if (!formatter) { - e_web_view_clear (E_WEB_VIEW (display)); - return; + if (display->priv->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + formatter = e_mail_formatter_print_new (); + } else { + formatter = e_mail_formatter_new (); } + g_clear_object (&display->priv->formatter); + display->priv->formatter = formatter; mail_display_update_formatter_colors (display); g_signal_connect (formatter, "notify::image-loading-policy", G_CALLBACK (formatter_image_loading_policy_changed_cb), display); - g_signal_connect_swapped (formatter, "redraw-requested", - G_CALLBACK (e_mail_display_reload), display); - g_signal_connect_swapped (formatter, "notify::charset", - G_CALLBACK (e_mail_display_reload), display); - g_object_notify (G_OBJECT (display), "formatter"); + g_object_connect (formatter, + "swapped-signal::notify::charset", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::image-loading-policy", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::mark-citations", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::only-local-photos", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::show-sender-photo", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::show-real-date", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::animate-images", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::text-color", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::body-color", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::citation-color", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::content-color", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::frame-color", + G_CALLBACK (e_mail_display_reload), display, + "swapped-signal::notify::header-color", + G_CALLBACK (e_mail_display_reload), display, + NULL); + + e_mail_display_reload (display); + + g_object_notify (G_OBJECT (display), "mode"); } -EMFormatWriteMode -e_mail_display_get_mode (EMailDisplay *display) +EMailPartList * +e_mail_display_get_parts_list (EMailDisplay *display) { - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), - EM_FORMAT_WRITE_MODE_NORMAL); + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - return display->priv->mode; + return display->priv->part_list; } void -e_mail_display_set_mode (EMailDisplay *display, - EMFormatWriteMode mode) +e_mail_display_set_parts_list (EMailDisplay *display, + EMailPartList *part_list) { g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - if (display->priv->mode == mode) - return; + if (part_list) { + g_return_if_fail (E_IS_MAIL_PART_LIST (part_list)); + g_object_ref (part_list); + } - display->priv->mode = mode; + if (display->priv->part_list) + g_object_unref (display->priv->part_list); - e_mail_display_reload (display); + display->priv->part_list = part_list; - g_object_notify (G_OBJECT (display), "mode"); + g_object_notify (G_OBJECT (display), "part-list"); } gboolean @@ -1510,16 +1638,21 @@ void e_mail_display_load (EMailDisplay *display, const gchar *msg_uri) { - EMFormat *emf; gchar *uri; + EMailPartList *part_list; g_return_if_fail (E_IS_MAIL_DISPLAY (display)); display->priv->force_image_load = FALSE; - emf = EM_FORMAT (display->priv->formatter); + part_list = display->priv->part_list; + if (!part_list) { + e_web_view_clear (E_WEB_VIEW (display)); + return; + } - uri = em_format_build_mail_uri (emf->folder, emf->message_uid, + uri = e_mail_part_build_uri ( + part_list->folder, part_list->message_uid, "mode", G_TYPE_INT, display->priv->mode, "headers_collapsable", G_TYPE_BOOLEAN, display->priv->headers_collapsable, "headers_collapsed", G_TYPE_BOOLEAN, display->priv->headers_collapsed, diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h index 9865a3ee37..e19895623a 100644 --- a/mail/e-mail-display.h +++ b/mail/e-mail-display.h @@ -24,7 +24,8 @@ #include <misc/e-web-view.h> #include <misc/e-search-bar.h> -#include "em-format-html.h" + +#include <em-format/e-mail-formatter.h> /* Standard GObject macros */ #define E_TYPE_MAIL_DISPLAY \ @@ -62,13 +63,16 @@ struct _EMailDisplayClass { }; GType e_mail_display_get_type (void); -EMFormatHTML * e_mail_display_get_formatter (EMailDisplay *display); -void e_mail_display_set_formatter (EMailDisplay *display, - EMFormatHTML *formatter); void e_mail_display_set_mode (EMailDisplay *display, - EMFormatWriteMode mode); -EMFormatWriteMode e_mail_display_get_mode (EMailDisplay *display); + EMailFormatterMode mode); +EMailFormatterMode e_mail_display_get_mode (EMailDisplay *display); + +EMailPartList * e_mail_display_get_parts_list (EMailDisplay *display); + +void e_mail_display_set_parts_list (EMailDisplay *display, + EMailPartList *parts_list); + void e_mail_display_set_headers_collapsable (EMailDisplay *display, gboolean collapsable); diff --git a/mail/e-mail-folder-pane.c b/mail/e-mail-folder-pane.c index 03168cec18..e6c0e9213b 100644 --- a/mail/e-mail-folder-pane.c +++ b/mail/e-mail-folder-pane.c @@ -43,7 +43,6 @@ #include "mail/e-mail-reader.h" #include "mail/e-mail-reader-utils.h" #include "mail/em-folder-tree-model.h" -#include "mail/em-format-html-display.h" #include "mail/em-composer-utils.h" #include "mail/em-utils.h" #include "mail/message-list.h" diff --git a/mail/e-mail-paned-view.h b/mail/e-mail-paned-view.h index 5e6879ae94..dbea57b99f 100644 --- a/mail/e-mail-paned-view.h +++ b/mail/e-mail-paned-view.h @@ -28,8 +28,6 @@ #include <shell/e-shell-searchbar.h> #include <shell/e-shell-view.h> -#include <mail/em-format-html-display.h> - /* Standard GObject macros */ #define E_TYPE_MAIL_PANED_VIEW \ (e_mail_paned_view_get_type ()) diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c index 0a52a0a5b2..f90414f02d 100644 --- a/mail/e-mail-printer.c +++ b/mail/e-mail-printer.c @@ -24,13 +24,15 @@ #include <glib/gi18n.h> #include <gtk/gtk.h> +#include <em-format/e-mail-formatter-print.h> +#include <em-format/e-mail-part-utils.h> + #include <e-util/e-print.h> #include <e-util/e-marshal.h> #include <webkit/webkitdom.h> #include "e-mail-printer.h" -#include "em-format-html-print.h" #include "e-mail-display.h" static gpointer parent_class = NULL; @@ -48,9 +50,11 @@ enum { #define w(x) struct _EMailPrinterPrivate { - EMFormatHTMLPrint *efhp; + EMailFormatterPrint *formatter; + EMailPartList *parts_list; gboolean export_mode; + gchar *export_filename; GtkListStore *headers; @@ -69,7 +73,7 @@ G_DEFINE_TYPE ( enum { PROP_0, - PROP_PRINT_FORMATTER + PROP_PART_LIST }; enum { @@ -88,8 +92,8 @@ enum { static guint signals[LAST_SIGNAL]; static gint -emp_header_name_equal (const EMFormatHeader *h1, - const EMFormatHeader *h2) +emp_header_name_equal (const EMailFormatterHeader *h1, + const EMailFormatterHeader *h2) { if ((h2->value == NULL) || (h1->value == NULL)) { return g_strcmp0 (h1->name, h2->name); @@ -169,8 +173,7 @@ emp_start_printing (GObject *object, if (emp->priv->export_mode) { gtk_print_operation_set_export_filename ( - emp->priv->operation, - emp->priv->efhp->export_filename); + emp->priv->operation, emp->priv->export_filename); webkit_web_frame_print_full ( frame, emp->priv->operation, GTK_PRINT_OPERATION_ACTION_EXPORT, NULL); @@ -185,32 +188,23 @@ emp_start_printing (GObject *object, static void emp_run_print_operation (EMailPrinter *emp) { - EMFormat *emf; - SoupSession *session; - GHashTable *formatters; gchar *mail_uri; - emf = EM_FORMAT (emp->priv->efhp); - mail_uri = em_format_build_mail_uri (emf->folder, emf->message_uid, NULL, NULL); - - /* It's safe to assume that session exists and contains formatters table, - * because at least the message we are about to print now must be already - * there */ - session = webkit_get_default_session (); - formatters = g_object_get_data (G_OBJECT (session), "formatters"); - g_hash_table_insert (formatters, g_strdup (mail_uri), emp->priv->efhp); + mail_uri = e_mail_part_build_uri (emp->priv->parts_list->folder, + emp->priv->parts_list->message_uid, + "__evo-load-image", G_TYPE_BOOLEAN, TRUE, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_PRINTING, + NULL); /* Print_layout is a special EMPart created by EMFormatHTMLPrint */ - if (emp->priv->uri) - g_free (emp->priv->uri); - - emp->priv->uri = g_strconcat (mail_uri, "?part_id=print_layout&__evo-load-images=1", NULL); - if (emp->priv->webview == NULL) { - emp->priv->webview = g_object_new (E_TYPE_MAIL_DISPLAY, NULL); + emp->priv->webview = g_object_new ( + E_TYPE_MAIL_DISPLAY, + "mode", E_MAIL_FORMATTER_MODE_PRINTING, NULL); e_web_view_set_enable_frame_flattening (E_WEB_VIEW (emp->priv->webview), FALSE); e_mail_display_set_force_load_images ( - E_MAIL_DISPLAY (emp->priv->webview), TRUE); + E_MAIL_DISPLAY (emp->priv->webview), TRUE); + g_object_ref_sink (emp->priv->webview); g_signal_connect (emp->priv->webview, "notify::load-status", G_CALLBACK (emp_start_printing), emp); @@ -224,18 +218,16 @@ emp_run_print_operation (EMailPrinter *emp) gtk_widget_show_all (window); }); } - - e_mail_display_set_formatter (E_MAIL_DISPLAY (emp->priv->webview), - (EMFormatHTML *) emp->priv->efhp); - - webkit_web_view_load_uri (emp->priv->webview, emp->priv->uri); + e_mail_display_set_parts_list ( + E_MAIL_DISPLAY (emp->priv->webview), emp->priv->parts_list); + webkit_web_view_load_uri (emp->priv->webview, mail_uri); g_free (mail_uri); } static void set_header_visible (EMailPrinter *emp, - EMFormatHeader *header, + EMailFormatterHeader *header, gint index, gboolean visible) { @@ -263,7 +255,7 @@ header_active_renderer_toggled_cb (GtkCellRendererToggle *renderer, GtkTreeIter iter; GtkTreePath *p; gboolean active; - EMFormatHeader *header; + EMailFormatterHeader *header; gint *indices; gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (emp->priv->headers), @@ -301,7 +293,7 @@ emp_headers_tab_toggle_selection (GtkWidget *button, return; do { - EMFormatHeader *header; + EMailFormatterHeader *header; GtkTreePath *path; gint *indices; @@ -594,47 +586,44 @@ emp_create_headers_tab (GtkPrintOperation *operation, } static void -emp_set_formatter (EMailPrinter *emp, - EMFormatHTMLPrint *formatter) +emp_set_parts_list (EMailPrinter *emp, + EMailPartList *parts_list) { - EMFormat *emf = (EMFormat *) formatter; CamelMediumHeader *header; GArray *headers; gint i; GtkTreeIter last_known; - g_return_if_fail (EM_IS_FORMAT_HTML_PRINT (formatter)); - - g_object_ref (formatter); + g_return_if_fail (parts_list); - if (emp->priv->efhp) - g_object_unref (emp->priv->efhp); - - emp->priv->efhp = formatter; + emp->priv->parts_list = g_object_ref (parts_list); if (emp->priv->headers) g_object_unref (emp->priv->headers); emp->priv->headers = gtk_list_store_new (5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT); - headers = camel_medium_get_headers (CAMEL_MEDIUM (emf->message)); + headers = camel_medium_get_headers (CAMEL_MEDIUM (parts_list->message)); if (!headers) return; for (i = 0; i < headers->len; i++) { GtkTreeIter iter; GList *found_header; - EMFormatHeader *emfh; + EMailFormatterHeader *emfh; header = &g_array_index (headers, CamelMediumHeader, i); - emfh = em_format_header_new (header->name, header->value); + emfh = e_mail_formatter_header_new (header->name, header->value); - found_header = g_queue_find_custom (&EM_FORMAT (formatter)->header_list, + found_header = g_queue_find_custom ( + (GQueue *) e_mail_formatter_get_headers ( + E_MAIL_FORMATTER (emp->priv->formatter)), emfh, (GCompareFunc) emp_header_name_equal); if (!found_header) { - emfh->flags |= EM_FORMAT_HTML_HEADER_HIDDEN; - em_format_add_header_struct (EM_FORMAT (formatter), emfh); + emfh->flags |= E_MAIL_FORMATTER_HEADER_FLAG_HIDDEN; + e_mail_formatter_add_header_struct ( + E_MAIL_FORMATTER (emp->priv->formatter), emfh); gtk_list_store_append (emp->priv->headers, &iter); } else { if (gtk_list_store_iter_is_valid (emp->priv->headers, &last_known)) @@ -652,7 +641,7 @@ emp_set_formatter (EMailPrinter *emp, COLUMN_HEADER_STRUCT, emfh, -1); } - camel_medium_free_headers (CAMEL_MEDIUM (emf->message), headers); + camel_medium_free_headers (CAMEL_MEDIUM (parts_list->message), headers); } static void @@ -665,8 +654,8 @@ emp_set_property (GObject *object, switch (property_id) { - case PROP_PRINT_FORMATTER: - emp_set_formatter (emp, g_value_get_object (value)); + case PROP_PART_LIST: + emp_set_parts_list (emp, g_value_get_pointer (value)); return; } @@ -683,9 +672,9 @@ emp_get_property (GObject *object, switch (property_id) { - case PROP_PRINT_FORMATTER: - g_value_set_object (value, - e_mail_printer_get_print_formatter (emp)); + case PROP_PART_LIST: + g_value_set_pointer (value, + emp->priv->parts_list); return; } @@ -697,9 +686,9 @@ emp_finalize (GObject *object) { EMailPrinterPrivate *priv = E_MAIL_PRINTER (object)->priv; - if (priv->efhp) { - g_object_unref (priv->efhp); - priv->efhp = NULL; + if (priv->formatter) { + g_object_unref (priv->formatter); + priv->formatter = NULL; } if (priv->headers) { @@ -707,10 +696,10 @@ emp_finalize (GObject *object) if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->headers), &iter)) { do { - EMFormatHeader *header = NULL; + EMailFormatterHeader *header = NULL; gtk_tree_model_get (GTK_TREE_MODEL (priv->headers), &iter, COLUMN_HEADER_STRUCT, &header, -1); - em_format_header_free (header); + e_mail_formatter_header_free (header); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->headers), &iter)); } g_object_unref (priv->headers); @@ -732,6 +721,11 @@ emp_finalize (GObject *object) priv->operation = NULL; } + if (priv->parts_list) { + g_object_unref (priv->parts_list); + priv->parts_list = NULL; + } + /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -751,13 +745,13 @@ e_mail_printer_class_init (EMailPrinterClass *klass) g_object_class_install_property ( object_class, - PROP_PRINT_FORMATTER, - g_param_spec_object ( - "print-formatter", - NULL, + PROP_PART_LIST, + g_param_spec_pointer ( + "parts-list", + "Parts List", NULL, - EM_TYPE_FORMAT_HTML_PRINT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); signals[SIGNAL_DONE] = g_signal_new ("done", G_TYPE_FROM_CLASS (klass), @@ -775,23 +769,18 @@ e_mail_printer_init (EMailPrinter *emp) emp->priv = G_TYPE_INSTANCE_GET_PRIVATE ( emp, E_TYPE_MAIL_PRINTER, EMailPrinterPrivate); - emp->priv->efhp = NULL; + emp->priv->formatter = (EMailFormatterPrint *) e_mail_formatter_print_new (); emp->priv->headers = NULL; emp->priv->webview = NULL; } EMailPrinter * -e_mail_printer_new (EMFormatHTML *source) +e_mail_printer_new (EMailPartList *source) { EMailPrinter *emp; - EMFormatHTMLPrint *efhp; - - efhp = em_format_html_print_new (source); emp = g_object_new (E_TYPE_MAIL_PRINTER, - "print-formatter", efhp, NULL); - - g_object_unref (efhp); + "parts-list", source, NULL); return emp; } @@ -830,10 +819,7 @@ e_mail_printer_get_export_filename (EMailPrinter *printer) { g_return_val_if_fail (E_IS_MAIL_PRINTER (printer), NULL); - if (!printer->priv->efhp) - return NULL; - - return printer->priv->efhp->export_filename; + return printer->priv->export_filename; } void @@ -841,19 +827,9 @@ e_mail_printer_set_export_filename (EMailPrinter *printer, const gchar *filename) { g_return_if_fail (E_IS_MAIL_PRINTER (printer)); - g_return_if_fail (printer->priv->efhp != NULL); - if (printer->priv->efhp->export_filename && *printer->priv->efhp->export_filename) - g_free (printer->priv->efhp->export_filename); + if (printer->priv->export_filename) + g_free (printer->priv->export_filename); - printer->priv->efhp->export_filename = g_strdup (filename); + printer->priv->export_filename = g_strdup (filename); } - -EMFormatHTMLPrint * -e_mail_printer_get_print_formatter (EMailPrinter *emp) -{ - g_return_val_if_fail (E_IS_MAIL_PRINTER (emp), NULL); - - return emp->priv->efhp; -} - diff --git a/mail/e-mail-printer.h b/mail/e-mail-printer.h index fcd163ec78..a0721ea9d4 100644 --- a/mail/e-mail-printer.h +++ b/mail/e-mail-printer.h @@ -20,7 +20,7 @@ #ifndef E_MAIL_PRINTER_H #define E_MAIL_PRINTER_H -#include "mail/em-format-html-print.h" +#include <em-format/e-mail-part-list.h> /* Standard GObject macros */ #define E_TYPE_MAIL_PRINTER \ @@ -63,7 +63,7 @@ struct _EMailPrinterClass { GType e_mail_printer_get_type (void); -EMailPrinter * e_mail_printer_new (EMFormatHTML *source); +EMailPrinter * e_mail_printer_new (EMailPartList *source); void e_mail_printer_print (EMailPrinter *printer, gboolean export, @@ -76,10 +76,6 @@ void e_mail_printer_set_export_filename const gchar * e_mail_printer_get_export_filename (EMailPrinter *printer); -EMFormatHTMLPrint * - e_mail_printer_get_print_formatter - (EMailPrinter *printer); - G_END_DECLS #endif /* E_MAIL_PRINTER_H */ diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index 2240523beb..f56b094e14 100644 --- a/mail/e-mail-reader-utils.c +++ b/mail/e-mail-reader-utils.c @@ -46,13 +46,20 @@ #include "mail/e-mail-backend.h" #include "mail/e-mail-browser.h" #include "mail/e-mail-printer.h" +#include "mail/e-mail-display.h" #include "mail/em-composer-utils.h" -#include "mail/em-format-html-print.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" #include "mail/mail-vfolder-ui.h" #include "mail/message-list.h" +#include <em-format/e-mail-parser.h> +#include <em-format/e-mail-part-utils.h> + +#define d(x) + +static GHashTable * mail_reader_get_mail_register (void); + typedef struct _AsyncContext AsyncContext; struct _AsyncContext { @@ -434,7 +441,7 @@ e_mail_reader_open_selected (EMailReader *reader) MessageList *ml; browser = e_mail_browser_new (backend, folder, uid, - EM_FORMAT_WRITE_MODE_NORMAL); + E_MAIL_FORMATTER_MODE_NORMAL); e_mail_reader_set_folder (E_MAIL_READER (browser), folder); e_mail_reader_set_message (E_MAIL_READER (browser), uid); @@ -508,30 +515,109 @@ printing_done_cb (EMailPrinter *printer, (GSourceFunc) destroy_printing_activity, activity, NULL); } -void -e_mail_reader_print (EMailReader *reader, - GtkPrintOperationAction action) -{ - EMailDisplay *display; - EMailPrinter *printer; - EMFormatHTML *formatter; +struct _MessagePrintingContext { + EMailReader *reader; + CamelFolder *folder; + gchar *message_uid; + EActivity *activity; - GCancellable *cancellable; +}; - g_return_if_fail (E_IS_MAIL_READER (reader)); +static void +free_message_printing_context (struct _MessagePrintingContext *context) +{ + g_return_if_fail (context != NULL); - display = e_mail_reader_get_mail_display (reader); - formatter = e_mail_display_get_formatter (display); + g_clear_object (&context->reader); + g_clear_object (&context->folder); + g_clear_object (&context->activity); - activity = e_mail_reader_new_activity (reader); + if (context->message_uid) + g_free (context->message_uid); + + g_free (context); +} + +static void +mail_reader_do_print_message (EMailPartList *part_list, + gpointer user_data) +{ + EActivity *activity; + GCancellable *cancellable; + EMailPrinter *printer; + struct _MessagePrintingContext *context = user_data; + + activity = e_mail_reader_new_activity (context->reader); e_activity_set_text (activity, _("Printing")); e_activity_set_state (activity, E_ACTIVITY_RUNNING); cancellable = e_activity_get_cancellable (activity); - printer = e_mail_printer_new (formatter); + printer = e_mail_printer_new (part_list); g_signal_connect (printer, "done", G_CALLBACK (printing_done_cb), activity); e_mail_printer_print (printer, FALSE, cancellable); + + free_message_printing_context (context); +} + +static void +mail_reader_get_message_to_print_ready_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + CamelMimeMessage *message; + struct _MessagePrintingContext *context = user_data; + + message = camel_folder_get_message_finish (CAMEL_FOLDER (object), result, NULL); + if (!CAMEL_IS_MIME_MESSAGE (message)) { + free_message_printing_context (context); + return; + } + + /* "Retrieving message" activity (or NULL) */ + g_clear_object (&context->activity); + + e_mail_reader_parse_message ( + context->reader, context->folder, context->message_uid, + message, (GFunc) mail_reader_do_print_message, context); +} + +void +e_mail_reader_print (EMailReader *reader, + GtkPrintOperationAction action) +{ + EMailPartList *parts; + struct _MessagePrintingContext *context; + MessageList *message_list; + gchar *uri; + + context = g_new0 (struct _MessagePrintingContext, 1); + + message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader)); + context->reader = g_object_ref (reader); + context->message_uid = g_strdup (message_list->cursor_uid); + context->folder = g_object_ref (e_mail_reader_get_folder (reader)); + + g_return_if_fail (E_IS_MAIL_READER (reader)); + + uri = e_mail_part_build_uri ( + context->folder, context->message_uid, NULL, NULL); + parts = e_mail_reader_lookup_part_list (reader, uri); + if (!parts) { + GCancellable *cancellable; + + context->activity = e_mail_reader_new_activity (reader); + cancellable = e_activity_get_cancellable (context->activity); + + camel_folder_get_message ( + context->folder, context->message_uid, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) mail_reader_get_message_to_print_ready_cb, + context); + + } else { + mail_reader_do_print_message (parts, context); + } } static void @@ -770,15 +856,31 @@ html_contains_nonwhitespace (const gchar *html, } static void +mail_reader_reply_message_parsed (EMailPartList *part_list, + gpointer user_data) +{ + EShell *shell; + EMailBackend *backend; + AsyncContext *context = user_data; + + backend = e_mail_reader_get_backend (context->reader); + shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend)); + + em_utils_reply_to_message ( + shell, part_list->message, + context->folder, context->message_uid, + context->reply_type, context->reply_style, + part_list, context->address); + + async_context_free (context); +} + +static void mail_reader_get_message_ready_cb (CamelFolder *folder, GAsyncResult *result, AsyncContext *context) { - EShell *shell; - EMailBackend *backend; EAlertSink *alert_sink; - EMFormatHTML *formatter; - EMailDisplay *display; CamelMimeMessage *message; GError *error = NULL; @@ -804,22 +906,10 @@ mail_reader_get_message_ready_cb (CamelFolder *folder, g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - backend = e_mail_reader_get_backend (context->reader); - shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend)); - display = e_mail_reader_get_mail_display (context->reader); - formatter = e_mail_display_get_formatter (display); - - em_utils_reply_to_message ( - shell, message, - context->folder, context->message_uid, - context->reply_type, context->reply_style, - EM_FORMAT (formatter), context->address); - - g_object_unref (message); - - e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED); - - async_context_free (context); + e_mail_reader_parse_message (context->reader, context->folder, + context->message_uid, message, + (GFunc) mail_reader_reply_message_parsed, + context); } void @@ -831,7 +921,7 @@ e_mail_reader_reply_to_message (EMailReader *reader, EMailBackend *backend; EShellBackend *shell_backend; EMailDisplay *display; - EMFormatHTML *formatter; + EMailPartList *part_list; GtkWidget *message_list; CamelMimeMessage *new_message; CamelInternetAddress *address = NULL; @@ -842,6 +932,8 @@ e_mail_reader_reply_to_message (EMailReader *reader, const gchar *uid; gchar *selection = NULL; gint length; + gchar *mail_uri; + GHashTable *mail_register; /* This handles quoting only selected text in the reply. If * nothing is selected or only whitespace is selected, fall @@ -852,7 +944,6 @@ e_mail_reader_reply_to_message (EMailReader *reader, backend = e_mail_reader_get_backend (reader); folder = e_mail_reader_get_folder (reader); display = e_mail_reader_get_mail_display (reader); - formatter = e_mail_display_get_formatter (display); message_list = e_mail_reader_get_message_list (reader); reply_style = e_mail_reader_get_reply_style (reader); @@ -889,11 +980,19 @@ e_mail_reader_reply_to_message (EMailReader *reader, uid = MESSAGE_LIST (message_list)->cursor_uid; g_return_if_fail (uid != NULL); - if (!gtk_widget_get_mapped (GTK_WIDGET (web_view))) + if (!gtk_widget_get_visible (GTK_WIDGET (web_view))) + goto whole_message; + + mail_register = mail_reader_get_mail_register (); + mail_uri = e_mail_part_build_uri (folder, uid, NULL, NULL); + part_list = g_hash_table_lookup (mail_register, mail_uri); + g_free (mail_uri); + + if (!part_list) goto whole_message; if (src_message == NULL) { - src_message = EM_FORMAT (formatter)->message; + src_message = part_list->message; if (src_message != NULL) g_object_ref (src_message); @@ -976,7 +1075,7 @@ whole_message: em_utils_reply_to_message ( shell, src_message, folder, uid, - reply_type, reply_style, EM_FORMAT (formatter), address); + reply_type, reply_style, part_list, address); if (address) g_object_unref (address); @@ -1419,43 +1518,58 @@ e_mail_reader_header_free (EMailReaderHeader *header) g_free (header); } +struct headers_changed_closure { + EMailFormatter *formatter; + EMailDisplay *display; +}; + +static void +free_headers_changed_closure (struct headers_changed_closure *closure) +{ + g_clear_object (&closure->formatter); + g_clear_object (&closure->display); + + g_free (closure); +} + static void headers_changed_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, - EMFormat *emf) + struct headers_changed_closure *closure) { GSList *header_config_list, *p; g_return_if_fail (client != NULL); - g_return_if_fail (EM_IS_FORMAT (emf)); header_config_list = gconf_client_get_list ( client, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, NULL); - em_format_clear_headers (emf); + e_mail_formatter_clear_headers (closure->formatter); for (p = header_config_list; p; p = g_slist_next (p)) { EMailReaderHeader *h; gchar *xml = (gchar *) p->data; h = e_mail_reader_header_from_xml (xml); if (h && h->enabled) - em_format_add_header ( - emf, h->name, NULL, EM_FORMAT_HEADER_BOLD); + e_mail_formatter_add_header ( + closure->formatter, h->name, NULL, + E_MAIL_FORMATTER_HEADER_FLAG_BOLD); e_mail_reader_header_free (h); } if (!header_config_list) - em_format_default_headers (emf); + e_mail_formatter_set_default_headers (closure->formatter); g_slist_foreach (header_config_list, (GFunc) g_free, NULL); g_slist_free (header_config_list); /* force a redraw */ - if (emf->message) - em_format_redraw (emf); + if (closure->display) { + e_mail_display_reload (closure->display); + } } static void @@ -1482,26 +1596,159 @@ remove_header_notify_cb (gpointer data) **/ void e_mail_reader_connect_headers (EMailReader *reader, - EMFormat *emf) + EMailFormatter *formatter) { GConfClient *client; guint notify_id; + struct headers_changed_closure *closure; client = gconf_client_get_default (); + closure = g_new0 (struct headers_changed_closure, 1); + closure->display = g_object_ref (e_mail_reader_get_mail_display (reader)); + closure->formatter = g_object_ref (formatter); + gconf_client_add_dir ( client, "/apps/evolution/mail/display", GCONF_CLIENT_PRELOAD_NONE, NULL); notify_id = gconf_client_notify_add ( client, "/apps/evolution/mail/display/headers", (GConfClientNotifyFunc) headers_changed_cb, - emf, NULL, NULL); + closure, (GFreeFunc) free_headers_changed_closure, NULL); g_object_set_data_full ( - G_OBJECT (emf), "reader-header-notify-id", + G_OBJECT (formatter), "reader-header-notify-id", GINT_TO_POINTER (notify_id), remove_header_notify_cb); - headers_changed_cb (client, 0, NULL, emf); + headers_changed_cb (client, 0, NULL, closure); g_object_unref (client); } + +static GHashTable * +mail_reader_get_mail_register (void) +{ + SoupSession *session; + GHashTable *mails; + + session = webkit_get_default_session (); + mails = g_object_get_data (G_OBJECT (session), "mails"); + if (!mails) { + mails = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); + g_object_set_data_full ( + G_OBJECT (session), "mails", mails, + (GDestroyNotify) g_hash_table_destroy); + } + + return mails; +} + +EMailPartList * +e_mail_reader_lookup_part_list (EMailReader *reader, + const gchar *uri) +{ + GHashTable *mails; + + g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); + g_return_val_if_fail (uri && *uri, NULL); + + mails = mail_reader_get_mail_register (); + return g_hash_table_lookup (mails, uri); +} + +struct _formatter_weak_ref_closure { + GHashTable *part_lists; + gchar *mail_uri; +}; + +static void +part_list_weak_ref_cb (gchar *mail_uri, + EMailPartList *part_list) +{ + GHashTable *mails; + + mails = mail_reader_get_mail_register (); + + /* When this callback is called, the partslist is being finalized + * so we only remove it from the parts list table. */ + g_hash_table_remove (mails, mail_uri); + + d(printf("Destroying parts list %p (%s)\n", part_list, mail_uri)); + + g_free (mail_uri); +} + +struct format_parser_async_closure_ { + EActivity *activity; + gchar *mail_uri; + + GFunc user_callback; + gpointer user_data; +}; + +static void +format_parser_async_done_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + EMailParser *parser = E_MAIL_PARSER (source); + EMailPartList *part_list; + GHashTable *mails; + struct format_parser_async_closure_ *closure = user_data; + + part_list = e_mail_parser_parse_finish (parser, result, NULL); + + /* When no EMailDisplay holds reference to the part list, then + * the list can be destroyed. */ + g_object_weak_ref (G_OBJECT (part_list), + (GWeakNotify) part_list_weak_ref_cb, g_strdup (closure->mail_uri)); + + mails = mail_reader_get_mail_register (); + g_hash_table_insert (mails, g_strdup (closure->mail_uri), part_list); + d(printf("Registered EMailPartList %s\n", closure->mail_uri)); + + if (closure->user_callback) + closure->user_callback (part_list, closure->user_data); + + g_object_unref (closure->activity); + g_free (closure->mail_uri); + g_free (closure); + + g_object_unref (result); + g_object_unref (parser); +} + +void +e_mail_reader_parse_message (EMailReader *reader, + CamelFolder *folder, + const gchar *message_uid, + CamelMimeMessage *message, + GFunc ready_callback, + gpointer user_data) +{ + EMailParser *parser; + EMailBackend *mail_backend; + EMailSession *mail_session; + gchar *mail_uri; + struct format_parser_async_closure_ *closure; + + mail_uri = e_mail_part_build_uri (folder, message_uid, NULL, NULL); + + mail_backend = e_mail_reader_get_backend (reader); + mail_session = e_mail_backend_get_session (mail_backend); + + closure = g_new0 (struct format_parser_async_closure_, 1); + parser = e_mail_parser_new (CAMEL_SESSION (mail_session)); + + closure->activity = e_mail_reader_new_activity (reader); + e_activity_set_text (closure->activity, _("Parsing message")); + closure->mail_uri = mail_uri; + closure->user_callback = ready_callback; + closure->user_data = user_data; + + e_mail_parser_parse (parser, folder, message_uid, + message, format_parser_async_done_cb, + e_activity_get_cancellable (closure->activity), + closure); +} diff --git a/mail/e-mail-reader-utils.h b/mail/e-mail-reader-utils.h index 6913d0964c..887e399451 100644 --- a/mail/e-mail-reader-utils.h +++ b/mail/e-mail-reader-utils.h @@ -68,7 +68,22 @@ gchar * e_mail_reader_header_to_xml (EMailReaderHeader *header); void e_mail_reader_header_free (EMailReaderHeader *header); void e_mail_reader_connect_headers (EMailReader *reader, - EMFormat *emf); + EMailFormatter *formatter); + +EMailPartList * e_mail_reader_lookup_part_list (EMailReader *reader, + const gchar *uri); + +void e_mail_reader_store_part_list (EMailReader *reader, + const gchar *uri, + EMailPartList *part_list); + +void e_mail_reader_parse_message + (EMailReader *reader, + CamelFolder *folder, + const gchar *message_uid, + CamelMimeMessage *message, + GFunc ready_callback, + gpointer user_data); G_END_DECLS diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c index af8a0eea94..3d0911b1fc 100644 --- a/mail/e-mail-reader.c +++ b/mail/e-mail-reader.c @@ -53,12 +53,15 @@ #include "mail/em-event.h" #include "mail/em-folder-selector.h" #include "mail/em-folder-tree.h" -#include "mail/em-format-html-display.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" #include "mail/mail-vfolder-ui.h" #include "mail/message-list.h" +#include <em-format/e-mail-formatter.h> +#include <em-format/e-mail-parser.h> +#include <em-format/e-mail-part-utils.h> + #if HAVE_CLUTTER #include <clutter/clutter.h> #include <mx/mx.h> @@ -69,7 +72,7 @@ ((EMailReaderPrivate *) g_object_get_qdata \ (G_OBJECT (obj), quark_private)) -#define d(x) +#define d(x) x typedef struct _EMailReaderClosure EMailReaderClosure; typedef struct _EMailReaderPrivate EMailReaderPrivate; @@ -85,6 +88,8 @@ struct _EMailReaderPrivate { EMailForwardStyle forward_style; EMailReplyStyle reply_style; + EMailFormatter *formatter; + /* This timer runs when the user selects a single message. */ guint message_selected_timeout_id; @@ -280,7 +285,7 @@ action_mail_image_save_cb (GtkAction *action, { EMailDisplay *display; EWebView *web_view; - EMFormat *emf; + EMailPartList *parts; const gchar *image_src; CamelMimePart *part; EAttachment *attachment; @@ -296,13 +301,13 @@ action_mail_image_save_cb (GtkAction *action, if (!image_src) return; - emf = EM_FORMAT (e_mail_display_get_formatter (display)); - g_return_if_fail (emf != NULL); - g_return_if_fail (emf->message != NULL); + parts = e_mail_display_get_parts_list (display); + g_return_if_fail (parts != NULL); + g_return_if_fail (parts->message != NULL); if (g_str_has_prefix (image_src, "cid:")) { part = camel_mime_message_get_part_by_content_id ( - emf->message, image_src + 4); + parts->message, image_src + 4); g_return_if_fail (part != NULL); g_object_ref (part); @@ -371,20 +376,18 @@ action_mail_charset_cb (GtkRadioAction *action, GtkRadioAction *current, EMailReader *reader) { - EMailDisplay *display; - EMFormatHTML *formatter; + EMailFormatter *formatter; const gchar *charset; if (action != current) return; - display = e_mail_reader_get_mail_display (reader); - formatter = e_mail_display_get_formatter (display); + formatter = e_mail_reader_get_formatter (reader); charset = g_object_get_data (G_OBJECT (action), "charset"); /* Charset for "Default" action will be NULL. */ if (formatter) - em_format_set_charset (EM_FORMAT (formatter), charset); + e_mail_formatter_set_charset (formatter, charset); } static void @@ -1711,9 +1714,9 @@ action_mail_show_all_headers_cb (GtkToggleAction *action, display = e_mail_reader_get_mail_display (reader); if (gtk_toggle_action_get_active (action)) - e_mail_display_set_mode (display, EM_FORMAT_WRITE_MODE_ALL_HEADERS); + e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_ALL_HEADERS); else - e_mail_display_set_mode (display, EM_FORMAT_WRITE_MODE_NORMAL); + e_mail_display_set_mode (display, E_MAIL_FORMATTER_MODE_NORMAL); } struct _source_retrieval_closure { @@ -1782,13 +1785,13 @@ action_mail_show_source_cb (GtkAction *action, g_return_if_fail (uids != NULL && uids->len == 1); message_uid = g_ptr_array_index (uids, 0); - browser = e_mail_browser_new (backend, NULL, NULL, EM_FORMAT_WRITE_MODE_SOURCE); + browser = e_mail_browser_new (backend, NULL, NULL, E_MAIL_FORMATTER_MODE_SOURCE); e_mail_reader_set_folder (E_MAIL_READER (browser), folder); e_mail_reader_set_message (E_MAIL_READER (browser), message_uid); display = e_mail_reader_get_mail_display (E_MAIL_READER (browser)); string = g_strdup_printf (_("Retrieving message '%s'"), message_uid); - e_mail_display_set_formatter (display, NULL); + e_mail_display_set_parts_list (display, NULL); e_mail_display_set_status (display, string); gtk_widget_show (browser); @@ -2664,7 +2667,7 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure) { EMailReader *reader; GtkWidget *message_list; - EMFormatHTML *formatter; + EMailPartList *parts; EMailDisplay *display; CamelMimeMessage *message; const gchar *current_uid; @@ -2675,7 +2678,7 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure) message_uid = closure->message_uid; display = e_mail_reader_get_mail_display (reader); - formatter = e_mail_display_get_formatter (display); + parts = e_mail_display_get_parts_list (display); message_list = e_mail_reader_get_message_list (reader); if (e_tree_is_dragging (E_TREE (message_list))) @@ -2684,8 +2687,8 @@ mail_reader_message_seen_cb (EMailReaderClosure *closure) current_uid = MESSAGE_LIST (message_list)->cursor_uid; uid_is_current &= (g_strcmp0 (current_uid, message_uid) == 0); - if (formatter) - message = EM_FORMAT (formatter)->message; + if (parts) + message = parts->message; else message = NULL; @@ -2846,7 +2849,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader) CamelFolder *folder; const gchar *cursor_uid; const gchar *format_uid; - EMFormat *formatter; + EMailPartList *parts; priv = E_MAIL_READER_GET_PRIVATE (reader); @@ -2854,10 +2857,10 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader) message_list = e_mail_reader_get_message_list (reader); display = e_mail_reader_get_mail_display (reader); - formatter = EM_FORMAT (e_mail_display_get_formatter (display)); + parts = e_mail_display_get_parts_list (display); cursor_uid = MESSAGE_LIST (message_list)->cursor_uid; - format_uid = formatter ? formatter->message_uid : NULL; + format_uid = parts ? parts->message_uid : NULL; if (MESSAGE_LIST (message_list)->last_sel_single) { GtkWidget *widget; @@ -2877,7 +2880,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader) gchar *string; string = g_strdup_printf (_("Retrieving message '%s'"), cursor_uid); - e_mail_display_set_formatter (display, NULL); + e_mail_display_set_parts_list (display, NULL); e_mail_display_set_status (display, string); g_free (string); @@ -2900,7 +2903,7 @@ mail_reader_message_selected_timeout_cb (EMailReader *reader) priv->retrieving_message = g_object_ref (cancellable); } } else { - e_mail_display_set_formatter (display, NULL); + e_mail_display_set_parts_list (display, NULL); priv->restoring_message_selection = FALSE; } @@ -3100,52 +3103,25 @@ mail_reader_folder_loaded (EMailReader *reader) e_mail_reader_update_actions (reader, state); } -struct _formatter_weak_ref_closure { - GHashTable *formatters; - gchar *mail_uri; -}; - -static void -formatter_weak_ref_cb (struct _formatter_weak_ref_closure *data, - EMFormat *formatter) -{ - /* When this callback is called, the formatter is being finalized - * so we only remove it from the formatters table. */ - g_hash_table_remove (data->formatters, - data->mail_uri); - - d(printf("Destroying formatter %p (%s)\n", formatter, data->mail_uri)); - - /* Destroying the formatter will prevent this callback - * being called, so we can remove the closure data as well */ - g_hash_table_unref (data->formatters); - g_free (data->mail_uri); - g_free (data); -} - struct format_parser_async_closure_ { + struct _formatter_weak_ref_closure *weak_ref_closure; EMailDisplay *display; EActivity *activity; }; static void -format_parser_async_done_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +set_mail_display_part_list (EMailPartList *part_list, + gpointer user_data) { - EMFormat *emf = EM_FORMAT (source); - struct format_parser_async_closure_ *closure = user_data; - - e_mail_display_set_formatter (closure->display, EM_FORMAT_HTML (emf)); - e_mail_display_load (closure->display, emf->uri_base); + EMailDisplay *display = user_data; - g_object_unref (closure->activity); - g_object_unref (closure->display); - g_free (closure); + e_mail_display_set_parts_list (display, part_list); + e_mail_display_load (display, NULL); - /* Remove the reference added when formatter was created, + g_object_unref (display); + /* Remove the reference added when parts list was created, * so that only owners are EMailDisplays */ - g_object_unref (emf); + g_object_unref (part_list); } static void @@ -3155,67 +3131,23 @@ mail_reader_set_display_formatter_for_message (EMailReader *reader, CamelMimeMessage *message, CamelFolder *folder) { - SoupSession *session; - GHashTable *formatters; - EMFormat *formatter; + EMailPartList *parts; gchar *mail_uri; - mail_uri = em_format_build_mail_uri (folder, message_uid, NULL, NULL); + mail_uri = e_mail_part_build_uri (folder, message_uid, NULL, NULL); + parts = e_mail_reader_lookup_part_list (reader, mail_uri); + g_free (mail_uri); - session = webkit_get_default_session (); - formatters = g_object_get_data (G_OBJECT (session), "formatters"); - if (!formatters) { - formatters = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, NULL); - g_object_set_data_full ( - G_OBJECT (session), "formatters", formatters, - (GDestroyNotify) g_hash_table_destroy); - } - - if ((formatter = g_hash_table_lookup (formatters, mail_uri)) == NULL) { - EMailBackend *mail_backend; - EMailSession *mail_session; - struct _formatter_weak_ref_closure *formatter_data = - g_new0 (struct _formatter_weak_ref_closure, 1); - - struct format_parser_async_closure_ *closure; - - formatter_data->formatters = g_hash_table_ref (formatters); - formatter_data->mail_uri = g_strdup (mail_uri); - - mail_backend = e_mail_reader_get_backend (reader); - mail_session = e_mail_backend_get_session (mail_backend); - - formatter = EM_FORMAT ( - em_format_html_display_new ( - CAMEL_SESSION (mail_session))); - - /* When no EMailDisplay holds reference to the formatter, then - * the formatter can be destroyed. */ - g_object_weak_ref (G_OBJECT (formatter), - (GWeakNotify) formatter_weak_ref_cb, formatter_data); - - formatter->message_uid = g_strdup (message_uid); - formatter->uri_base = g_strdup (mail_uri); - - e_mail_reader_connect_headers (reader, formatter); + if (parts == NULL) { - closure = g_new0 (struct format_parser_async_closure_, 1); - closure->activity = e_mail_reader_new_activity (reader); - e_activity_set_text (closure->activity, _("Parsing message")); - closure->display = g_object_ref (display); + e_mail_reader_parse_message ( + reader, folder, message_uid, message, + (GFunc) set_mail_display_part_list, + g_object_ref (display)); - em_format_parse_async (formatter, message, folder, - e_activity_get_cancellable (closure->activity), - format_parser_async_done_cb, closure); - - /* Don't free the mail_uri!! */ - g_hash_table_insert (formatters, mail_uri, formatter); } else { - e_mail_display_set_formatter (display, EM_FORMAT_HTML (formatter)); - e_mail_display_load (display, formatter->uri_base); - - g_free (mail_uri); + e_mail_display_set_parts_list (display, parts); + e_mail_display_load (display, NULL); } } @@ -3895,6 +3827,12 @@ e_mail_reader_init (EMailReader *reader, message_list = e_mail_reader_get_message_list (reader); display = e_mail_reader_get_mail_display (reader); + /* Initialize a private struct. */ + g_object_set_qdata_full ( + G_OBJECT (reader), quark_private, + g_slice_new0 (EMailReaderPrivate), + (GDestroyNotify) mail_reader_private_free); + if (!init_actions) goto connect_signals; @@ -4114,7 +4052,7 @@ e_mail_reader_init (EMailReader *reader, connect_signals: if (!connect_signals) - goto init_private; + return; /* Connect signals. */ g_signal_connect_swapped ( @@ -4158,15 +4096,6 @@ connect_signals: g_signal_connect_swapped ( message_list, "selection-change", G_CALLBACK (e_mail_reader_changed), reader); - -init_private: - - /* Initialize a private struct. */ - - g_object_set_qdata_full ( - G_OBJECT (reader), quark_private, - g_slice_new0 (EMailReaderPrivate), - (GDestroyNotify) mail_reader_private_free); } void @@ -4805,3 +4734,39 @@ e_mail_reader_avoid_next_mark_as_seen (EMailReader *reader) priv->avoid_next_mark_as_seen = TRUE; } + +EMailFormatter * +e_mail_reader_get_formatter (EMailReader *reader) +{ + EMailReaderPrivate *priv; + + g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); + + priv = E_MAIL_READER_GET_PRIVATE (reader); + g_return_val_if_fail (priv != NULL, NULL); + + return priv->formatter; +} + +void +e_mail_reader_set_formatter (EMailReader *reader, + EMailFormatter *formatter) +{ + EMailReaderPrivate *priv; + + g_return_if_fail (E_IS_MAIL_READER (reader)); + g_return_if_fail (E_IS_MAIL_FORMATTER (formatter)); + + priv = E_MAIL_READER_GET_PRIVATE (reader); + g_return_if_fail (priv != NULL); + + g_object_ref (formatter); + + if (priv->formatter) { + g_object_unref (priv->formatter); + } + + priv->formatter = formatter; + + e_mail_reader_connect_headers (reader, formatter); +} diff --git a/mail/e-mail-reader.h b/mail/e-mail-reader.h index 6f03fc0cfe..b33aee7554 100644 --- a/mail/e-mail-reader.h +++ b/mail/e-mail-reader.h @@ -179,6 +179,10 @@ void e_mail_reader_enable_show_folder void e_mail_reader_avoid_next_mark_as_seen (EMailReader *reader); +EMailFormatter * e_mail_reader_get_formatter (EMailReader *reader); +void e_mail_reader_set_formatter (EMailReader *reader, + EMailFormatter *formatter); + G_END_DECLS #endif /* E_MAIL_READER_H */ diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c index 7522bc5e7e..01c114405d 100644 --- a/mail/e-mail-request.c +++ b/mail/e-mail-request.c @@ -24,10 +24,14 @@ #include <libsoup/soup-requester.h> #include <libsoup/soup-request-http.h> +#include <webkit/webkit.h> + #include <glib/gi18n.h> #include <camel/camel.h> -#include "em-format-html.h" +#include <em-format/e-mail-formatter.h> +#include <em-format/e-mail-formatter-utils.h> +#include <em-format/e-mail-formatter-print.h> #include <e-util/e-icon-factory.h> #include <e-util/e-util.h> @@ -40,15 +44,13 @@ ((obj), E_TYPE_MAIL_REQUEST, EMailRequestPrivate)) struct _EMailRequestPrivate { - EMFormatHTML *efh; - CamelStream *output_stream; - EMFormatPURI *puri; gchar *mime_type; gint content_length; GHashTable *uri_query; + gchar *uri_base; gchar *ret_mime_type; }; @@ -61,14 +63,17 @@ handle_mail_request (GSimpleAsyncResult *res, GCancellable *cancellable) { EMailRequest *request = E_MAIL_REQUEST (object); - EMFormatHTML *efh = request->priv->efh; - EMFormat *emf = EM_FORMAT (efh); GInputStream *stream; + EMailFormatter *formatter; + EMailPartList *part_list; + SoupSession *session; + GHashTable *mails; GByteArray *ba; gchar *part_id; - EMFormatWriterInfo info = {0}; gchar *val; + EMailFormatterContext context = { 0 }; + if (g_cancellable_is_cancelled (cancellable)) return; @@ -76,39 +81,67 @@ handle_mail_request (GSimpleAsyncResult *res, g_object_unref (request->priv->output_stream); } + session = webkit_get_default_session (); + mails = g_object_get_data (G_OBJECT (session), "mails"); + part_list = g_hash_table_lookup (mails, request->priv->uri_base); + g_return_if_fail (part_list != NULL); + request->priv->output_stream = camel_stream_mem_new (); val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsed"); - if (val) - info.headers_collapsed = atoi (val); + if (val && atoi (val) == 1) + context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED; val = g_hash_table_lookup (request->priv->uri_query, "headers_collapsable"); - if (val) - info.headers_collapsable = atoi (val); + if (val && atoi (val) == 1) + context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE; val = g_hash_table_lookup (request->priv->uri_query, "mode"); if (val) - info.mode = atoi (val); + context.mode = atoi (val); + + context.message = part_list->message; + context.message_uid = part_list->message_uid; + context.folder = part_list->folder; + context.parts = part_list->list; + + if (context.mode == E_MAIL_FORMATTER_MODE_PRINTING) + formatter = e_mail_formatter_print_new (); + else + formatter = e_mail_formatter_new (); part_id = g_hash_table_lookup (request->priv->uri_query, "part_id"); if (part_id) { + EMailPart *part; + const gchar *mime_type; /* original part_id is owned by the GHashTable */ part_id = soup_uri_decode (part_id); - request->priv->puri = em_format_find_puri (emf, part_id); + part = e_mail_part_list_find_part (part_list, part_id); - if (request->priv->puri) { - em_format_puri_write (request->priv->puri, - request->priv->output_stream, &info, cancellable); + val = g_hash_table_lookup (request->priv->uri_query, "mime_type"); + if (val) { + mime_type = val; + } else { + mime_type = NULL; + } + + if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE) { + mime_type = "application/vnd.evolution.source"; + } + + if (part) { + e_mail_formatter_format_as ( + formatter, &context, part, request->priv->output_stream, + mime_type ? mime_type : part->mime_type, cancellable); } else { g_warning ("Failed to lookup requested part '%s' - this should not happen!", part_id); } g_free (part_id); } else { - if (info.mode == 0) - info.mode = EM_FORMAT_WRITE_MODE_NORMAL; - - em_format_write (emf, request->priv->output_stream, &info, cancellable); + e_mail_formatter_format_sync ( + formatter, part_list, request->priv->output_stream, + context.flags, context.mode, cancellable); } /* Convert the GString to GInputStream and send it back to WebKit */ @@ -136,10 +169,7 @@ 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; - } + g_clear_object (&request->priv->output_stream); if (request->priv->mime_type) { g_free (request->priv->mime_type); @@ -156,9 +186,9 @@ mail_request_finalize (GObject *object) request->priv->ret_mime_type = NULL; } - if (request->priv->efh) { - g_object_unref (request->priv->efh); - request->priv->efh = NULL; + if (request->priv->uri_base) { + g_free (request->priv->uri_base); + request->priv->uri_base = NULL; } G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object); @@ -178,14 +208,11 @@ mail_request_send_async (SoupRequest *request, GAsyncReadyCallback callback, gpointer user_data) { - SoupSession *session; EMailRequest *emr = E_MAIL_REQUEST (request); GSimpleAsyncResult *simple; SoupURI *uri; - GHashTable *formatters; gchar *uri_str; - session = soup_request_get_session (request); uri = soup_request_get_uri (request); d(printf("received request for %s\n", soup_uri_to_string (uri, FALSE))); @@ -196,18 +223,9 @@ mail_request_send_async (SoupRequest *request, emr->priv->uri_query = NULL; } - formatters = g_object_get_data (G_OBJECT (session), "formatters"); - g_return_if_fail (formatters != NULL); - uri_str = g_strdup_printf ( "%s://%s%s", uri->scheme, uri->host, uri->path); - emr->priv->efh = g_hash_table_lookup (formatters, uri_str); - g_free (uri_str); - - g_return_if_fail (emr->priv->efh); - - /* Make sure the formatter lives until we are finished here */ - g_object_ref (emr->priv->efh); + emr->priv->uri_base = uri_str; simple = g_simple_async_result_new ( G_OBJECT (request), callback, @@ -229,10 +247,11 @@ mail_request_send_finish (SoupRequest *request, { GInputStream *stream; - stream = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); + stream = g_simple_async_result_get_op_res_gpointer ( + G_SIMPLE_ASYNC_RESULT (result)); /* Reset the stream before passing it back to webkit */ - if (stream && G_IS_SEEKABLE (stream)) + if (G_IS_INPUT_STREAM (stream) && G_IS_SEEKABLE (stream)) g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL); if (!stream) /* We must always return something */ @@ -269,13 +288,8 @@ mail_request_get_content_type (SoupRequest *request) if (emr->priv->mime_type) { mime_type = g_strdup (emr->priv->mime_type); - } else if (!emr->priv->puri) { - mime_type = g_strdup ("text/html"); - } else if (!emr->priv->puri->mime_type) { - CamelContentType *ct = camel_mime_part_get_content_type (emr->priv->puri->part); - mime_type = camel_content_type_simple (ct); } else { - mime_type = g_strdup (emr->priv->puri->mime_type); + mime_type = g_strdup ("text/html"); } if (g_strcmp0 (mime_type, "text/html") == 0) { diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index 4fe141447a..71754a6d0d 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -43,6 +43,9 @@ #include <libemail-engine/mail-ops.h> #include <libemail-engine/mail-tools.h> +#include <em-format/e-mail-parser.h> +#include <em-format/e-mail-formatter-quote.h> + #include <shell/e-shell.h> #include <composer/e-msg-composer.h> @@ -54,10 +57,6 @@ #include "em-composer-utils.h" #include "em-folder-selector.h" #include "em-folder-tree.h" -#include "em-format-html.h" -#include "em-format-html-print.h" -#include "em-format-html-display.h" -#include "em-format-quote.h" #include "em-event.h" #include "mail-send-recv.h" @@ -958,8 +957,6 @@ composer_print_done_cb (EMailPrinter *emp, GtkPrintOperationResult result, gpointer user_data) { - EMFormat *emf = user_data; - g_object_unref (emf); g_object_unref (emp); } @@ -971,23 +968,23 @@ em_utils_composer_print_cb (EMsgComposer *composer, EMailSession *session) { EMailPrinter *emp; - EMFormatHTMLDisplay *efhd; + EMailParser *parser; + EMailPartList *parts; const gchar *message_id; - efhd = em_format_html_display_new (CAMEL_SESSION (session)); + parser = e_mail_parser_new (CAMEL_SESSION (session)); message_id = camel_mime_message_get_message_id (message); - ((EMFormat *) efhd)->message_uid = g_strdup (message_id); - - /* Parse the message */ - em_format_parse ((EMFormat *) efhd, message, NULL, NULL); + parts = e_mail_parser_parse_sync (parser, NULL, g_strdup (message_id), message, NULL); /* Use EMailPrinter and WebKit to print the message */ - emp = e_mail_printer_new ((EMFormatHTML *) efhd); + emp = e_mail_printer_new (parts); g_signal_connect (emp, "done", - G_CALLBACK (composer_print_done_cb), efhd); + G_CALLBACK (composer_print_done_cb), NULL); e_mail_printer_print (emp, FALSE, NULL); + + g_object_unref (parts); } /* Composing messages... */ @@ -1543,13 +1540,13 @@ emu_update_composers_security (EMsgComposer *composer, shell_settings = e_shell_get_shell_settings (shell); sign_by_default = - (validity_found & EM_FORMAT_VALIDITY_FOUND_SIGNED) != 0 && + (validity_found & E_MAIL_PART_VALIDITY_SIGNED) != 0 && e_shell_settings_get_boolean ( shell_settings, "composer-sign-reply-if-signed"); /* Pre-set only for encrypted messages, not for signed */ if (sign_by_default) { - if (validity_found & EM_FORMAT_VALIDITY_FOUND_SMIME) + if (validity_found & E_MAIL_PART_VALIDITY_SMIME) action = E_COMPOSER_ACTION_SMIME_SIGN (composer); else action = E_COMPOSER_ACTION_PGP_SIGN (composer); @@ -1558,8 +1555,8 @@ emu_update_composers_security (EMsgComposer *composer, GTK_TOGGLE_ACTION (action), TRUE); } - if (validity_found & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED) { - if (validity_found & EM_FORMAT_VALIDITY_FOUND_SMIME) + if (validity_found & E_MAIL_PART_VALIDITY_ENCRYPTED) { + if (validity_found & E_MAIL_PART_VALIDITY_SMIME) action = E_COMPOSER_ACTION_SMIME_ENCRYPT (composer); else action = E_COMPOSER_ACTION_PGP_ENCRYPT (composer); @@ -1703,9 +1700,9 @@ forward_non_attached (EShell *shell, guint32 validity_found = 0; guint32 flags; - flags = EM_FORMAT_QUOTE_HEADERS | EM_FORMAT_QUOTE_KEEP_SIG; + flags = E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS | E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG; if (style == E_MAIL_FORWARD_STYLE_QUOTED) - flags |= EM_FORMAT_QUOTE_CITE; + flags |= E_MAIL_FORMATTER_QUOTE_FLAG_CITE; forward = quoting_text (QUOTING_FORWARD); text = em_utils_message_to_html ( @@ -2760,7 +2757,7 @@ static void composer_set_body (EMsgComposer *composer, CamelMimeMessage *message, EMailReplyStyle style, - EMFormat *source) + EMailPartList *parts_list) { gchar *text, *credits, *original; CamelMimePart *part; @@ -2788,8 +2785,8 @@ composer_set_body (EMsgComposer *composer, case E_MAIL_REPLY_STYLE_OUTLOOK: original = quoting_text (QUOTING_ORIGINAL); text = em_utils_message_to_html ( - session, message, original, EM_FORMAT_QUOTE_HEADERS, - source, start_bottom ? "<BR>" : NULL, &validity_found); + session, message, original, E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS, + parts_list, start_bottom ? "<BR>" : NULL, &validity_found); e_msg_composer_set_body_text (composer, text, TRUE); has_body_text = text && *text; g_free (text); @@ -2802,8 +2799,8 @@ composer_set_body (EMsgComposer *composer, /* do what any sane user would want when replying... */ credits = attribution_format (message); text = em_utils_message_to_html ( - session, message, credits, EM_FORMAT_QUOTE_CITE, - source, start_bottom ? "<BR>" : NULL, &validity_found); + session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE, + parts_list, start_bottom ? "<BR>" : NULL, &validity_found); g_free (credits); e_msg_composer_set_body_text (composer, text, TRUE); has_body_text = text && *text; @@ -2842,7 +2839,7 @@ composer_set_body (EMsgComposer *composer, gchar * em_utils_construct_composer_text (CamelSession *session, CamelMimeMessage *message, - EMFormat *source) + EMailPartList *parts_list) { gchar *text, *credits; gboolean start_bottom = 0; @@ -2851,8 +2848,8 @@ em_utils_construct_composer_text (CamelSession *session, credits = attribution_format (message); text = em_utils_message_to_html ( - session, message, credits, EM_FORMAT_QUOTE_CITE, - source, start_bottom ? "<BR>" : NULL, NULL); + session, message, credits, E_MAIL_FORMATTER_QUOTE_FLAG_CITE, + parts_list, start_bottom ? "<BR>" : NULL, NULL); g_free (credits); return text; @@ -2881,7 +2878,7 @@ em_utils_reply_to_message (EShell *shell, const gchar *message_uid, EMailReplyType type, EMailReplyStyle style, - EMFormat *source_formatter, + EMailPartList *parts_list, CamelInternetAddress *address) { ESourceRegistry *registry; @@ -2956,7 +2953,7 @@ em_utils_reply_to_message (EShell *shell, g_object_unref (to); g_object_unref (cc); - composer_set_body (composer, message, style, source_formatter); + composer_set_body (composer, message, style, parts_list); if (folder != NULL) { gchar *folder_uri; diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h index a525cec2a2..93d87bfb2e 100644 --- a/mail/em-composer-utils.h +++ b/mail/em-composer-utils.h @@ -24,7 +24,7 @@ #ifndef EM_COMPOSER_UTILS_H #define EM_COMPOSER_UTILS_H -#include <em-format/em-format.h> +#include <em-format/e-mail-part.h> #include <mail/e-mail-backend.h> #include <mail/e-mail-reader.h> #include <composer/e-msg-composer.h> @@ -62,7 +62,7 @@ void em_utils_redirect_message (EShell *shell, gchar * em_utils_construct_composer_text (CamelSession *session, CamelMimeMessage *message, - EMFormat *source_formatter); + EMailPartList *source_formatter); gboolean em_utils_is_munged_list_message (CamelMimeMessage *message); void em_utils_get_reply_sender (CamelMimeMessage *message, CamelInternetAddress *to, @@ -78,7 +78,7 @@ EMsgComposer * em_utils_reply_to_message (EShell *shell, const gchar *message_uid, EMailReplyType type, EMailReplyStyle style, - EMFormat *source, + EMailPartList *source, CamelInternetAddress *address); EDestination ** em_utils_camel_address_to_destination (CamelInternetAddress *iaddr); diff --git a/mail/em-format-hook.c b/mail/em-format-hook.c deleted file mode 100644 index 7ceeb20e4d..0000000000 --- a/mail/em-format-hook.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include "em-format-hook.h" - -#include <glib/gi18n.h> - -/* class name -> class map for EMFormat and subclasses */ -static GHashTable *emfh_types; - -/* ********************************************************************** */ - -/* Mail formatter handler plugin */ - -/* - * <hook class="org.gnome.evolution.mail.format:1.0"> - * <group id="EMFormatHTML"> - * <item flags="inline,inline_disposition" - * mime_type="text/vcard" - * format="format_vcard"/> - * </group> - * </hook> - */ - -#define emfh ((EMFormatHook *)eph) - -#define d(x) - -static const EPluginHookTargetKey emfh_flag_map[] = { - { "inline", EM_FORMAT_HANDLER_INLINE }, - { "inline_disposition", EM_FORMAT_HANDLER_INLINE_DISPOSITION }, - { NULL } -}; - -G_DEFINE_TYPE (EMFormatHook, em_format_hook, E_TYPE_PLUGIN_HOOK) - -static void -emfh_parse_part (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - struct _EMFormatHookItem *item = (EMFormatHookItem *) info->handler; - - if (item->hook->hook.plugin->enabled) { - EMFormatHookTarget target = { - emf, part, part_id, info - }; - - e_plugin_invoke (item->hook->hook.plugin, item->format, &target); - } else if (info->handler->old) { - info->handler->old->parse_func ( - emf, part, part_id, info, cancellable); - } -} - -static void -emfh_free_item (struct _EMFormatHookItem *item) -{ - /* FIXME: remove from formatter class */ - - g_free (item->handler.mime_type); - g_free (item->format); - g_free (item); -} - -static void -emfh_free_group (struct _EMFormatHookGroup *group) -{ - g_slist_foreach (group->items, (GFunc) emfh_free_item, NULL); - g_slist_free (group->items); - - g_free (group->id); - g_free (group); -} - -static struct _EMFormatHookItem * -emfh_construct_item (EPluginHook *eph, - EMFormatHookGroup *group, - xmlNodePtr root) -{ - struct _EMFormatHookItem *item; - - d(printf(" loading group item\n")); - item = g_malloc0 (sizeof (*item)); - - item->handler.mime_type = e_plugin_xml_prop(root, "mime_type"); - item->handler.flags = e_plugin_hook_mask(root, emfh_flag_map, "flags"); - item->format = e_plugin_xml_prop(root, "format"); - - item->handler.parse_func = emfh_parse_part; - item->hook = emfh; - - if (item->handler.mime_type == NULL || item->format == NULL) - goto error; - - d(printf(" type='%s' format='%s'\n", item->handler.mime_type, item->format)); - - return item; -error: - d(printf("error!\n")); - emfh_free_item (item); - return NULL; -} - -static struct _EMFormatHookGroup * -emfh_construct_group (EPluginHook *eph, - xmlNodePtr root) -{ - struct _EMFormatHookGroup *group; - xmlNodePtr node; - - d(printf(" loading group\n")); - group = g_malloc0 (sizeof (*group)); - - group->id = e_plugin_xml_prop(root, "id"); - if (group->id == NULL) - goto error; - - node = root->children; - while (node) { - if (0 == strcmp((gchar *)node->name, "item")) { - struct _EMFormatHookItem *item; - - item = emfh_construct_item (eph, group, node); - if (item) - group->items = g_slist_append (group->items, item); - } - node = node->next; - } - - return group; -error: - emfh_free_group (group); - return NULL; -} - -static gint -emfh_construct (EPluginHook *eph, - EPlugin *ep, - xmlNodePtr root) -{ - xmlNodePtr node; - - d(printf("loading format hook\n")); - - if (((EPluginHookClass *) em_format_hook_parent_class)-> - construct (eph, ep, root) == -1) - return -1; - - node = root->children; - while (node) { - if (strcmp((gchar *)node->name, "group") == 0) { - struct _EMFormatHookGroup *group; - - group = emfh_construct_group (eph, node); - if (group) { - EMFormatClass *class; - - if (emfh_types - && (class = g_hash_table_lookup (emfh_types, group->id))) { - GSList *l = group->items; - - for (; l; l = g_slist_next (l)) { - EMFormatHookItem *item = l->data; - /* TODO: only add handlers if enabled? */ - /* Well, disabling is handled by the callback, - * if we leave as is, then we can enable the - * plugin after startup and it will start - * working automagically */ - em_format_class_add_handler (class, &item->handler); - } - } - /* We don't actually need to keep this - * around once its set on the class. */ - emfh->groups = g_slist_append (emfh->groups, group); - } - } - node = node->next; - } - - eph->plugin = ep; - - /* Load the plugin as it does a few thing in the formatter thread. */ - ((EPluginClass *) G_OBJECT_GET_CLASS (ep))->enable (ep, 1); - return 0; -} - -static void -emfh_enable (EPluginHook *eph, - gint state) -{ - GSList *g, *l; - EMFormatClass *class; - - g = emfh->groups; - if (emfh_types == NULL) - return; - - for (; g; g = g_slist_next (g)) { - struct _EMFormatHookGroup *group = g->data; - - class = g_hash_table_lookup (emfh_types, group->id); - for (l = group->items; l; l = g_slist_next (l)) { - EMFormatHookItem *item = l->data; - - if (state) - em_format_class_add_handler (class, &item->handler); - else - em_format_class_remove_handler (class, &item->handler); - } - } -} - -static void -format_hook_finalize (GObject *object) -{ - EPluginHook *eph = (EPluginHook *) object; - - g_slist_foreach (emfh->groups, (GFunc) emfh_free_group, NULL); - g_slist_free (emfh->groups); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (em_format_hook_parent_class)->finalize (object); -} - -static void -em_format_hook_class_init (EMFormatHookClass *class) -{ - GObjectClass *object_class; - EPluginHookClass *hook_class; - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = format_hook_finalize; - - hook_class = E_PLUGIN_HOOK_CLASS (class); - hook_class->construct = emfh_construct; - hook_class->enable = emfh_enable; - hook_class->id = "org.gnome.evolution.mail.format:1.0"; -} - -static void -em_format_hook_init (EMFormatHook *hook) -{ -} - -void -em_format_hook_register_type (GType type) -{ - EMFormatClass *class; - - if (emfh_types == NULL) - emfh_types = g_hash_table_new (g_str_hash, g_str_equal); - - d(printf("registering formatter type '%s'\n", g_type_name(type))); - - class = g_type_class_ref (type); - g_hash_table_insert (emfh_types, (gpointer) g_type_name (type), class); -} diff --git a/mail/em-format-hook.h b/mail/em-format-hook.h deleted file mode 100644 index 09076c2f48..0000000000 --- a/mail/em-format-hook.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * 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/> - * - * - * Authors: - * Michel Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __EM_FORMAT_HOOK_H__ -#define __EM_FORMAT_HOOK_H__ - -#include <e-util/e-plugin.h> -#include <em-format/em-format.h> - -G_BEGIN_DECLS - -typedef struct _EMFormatHookItem EMFormatHookItem; -typedef struct _EMFormatHookGroup EMFormatHookGroup; -typedef struct _EMFormatHook EMFormatHook; -typedef struct _EMFormatHookClass EMFormatHookClass; - -typedef struct _EMFormatHookTarget EMFormatHookTarget; - -typedef void (*EMFormatHookFunc)(struct _EPlugin *plugin, EMFormatHookTarget *data); - -struct _EMFormatHookTarget { - struct _EMFormat *format; - CamelMimePart *part; - GString *part_id; - EMFormatParserInfo *info; -}; - -struct _EMFormatHookItem { - EMFormatHandler handler; - - struct _EMFormatHook *hook; /* parent pointer */ - gchar *format; /* format handler */ -}; - -struct _EMFormatHookGroup { - struct _EMFormatHook *hook; /* parent pointer */ - gchar *id; /* target formatter id */ - GSList *items; /* items to consider */ -}; - -/** - * struct _EMFormatHook - Mail formatter hook. - * - * @hook: - * @groups: - * - * The Mail formatter hook links all of the plugin formatter hooks - * into the relevent formatter classes. - **/ -struct _EMFormatHook { - EPluginHook hook; - - GSList *groups; -}; - -struct _EMFormatHookClass { - EPluginHookClass hook_class; - - /* which class to add matching items to */ - GHashTable *format_classes; -}; - -GType em_format_hook_get_type (void); - -/* register a type as a possible formatter hook point */ -void em_format_hook_register_type (GType type); - -G_END_DECLS - -#endif /* __EM_FORMAT_HOOK_H__ */ diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c deleted file mode 100644 index efa5881542..0000000000 --- a/mail/em-format-html-display.c +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * 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/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> - -#include <gtk/gtk.h> -#include <glib/gstdio.h> -#include <gdk/gdkkeysyms.h> - -#ifdef G_OS_WIN32 -/* Work around 'DATADIR' and 'interface' lossage in <windows.h> */ -#define DATADIR crap_DATADIR -#include <windows.h> -#undef DATADIR -#undef interface -#endif - -#include <glib/gi18n.h> - -#include <e-util/e-util.h> -#include <e-util/e-util-private.h> - -#include "e-util/e-datetime-format.h" -#include <e-util/e-dialog-utils.h> -#include <e-util/e-icon-factory.h> - -#include <shell/e-shell.h> -#include <shell/e-shell-utils.h> - -#if defined (HAVE_NSS) && defined (ENABLE_SMIME) -#include "certificate-viewer.h" -#include "e-cert-db.h" -#endif - -#include "e-mail-display.h" -#include "e-mail-attachment-bar.h" -#include "em-format-html-display.h" -#include "em-utils.h" -#include "widgets/misc/e-attachment.h" -#include "widgets/misc/e-attachment-button.h" -#include "widgets/misc/e-attachment-view.h" -#include "shell/e-shell.h" -#include "shell/e-shell-window.h" - -#define EM_FORMAT_HTML_DISPLAY_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayPrivate)) - -#define d(x) - -#define EM_FORMAT_HTML_DISPLAY_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayPrivate)) - -struct _EMFormatHTMLDisplayPrivate { - - EAttachmentView *last_view; - -}; - -/* TODO: move the dialogue elsehwere */ -/* FIXME: also in em-format-html.c */ -static const struct { - const gchar *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 gchar *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 GdkRGBA smime_sign_colour[5] = { - { 0 }, { 0.53, 0.73, 0.53, 1 }, { 0.73, 0.53, 0.53, 1 }, { 0.91, 0.82, 0.13, 1 }, { 0 }, -}; - -static void efhd_message_prefix (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efhd_message_add_bar (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efhd_parse_attachment (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efhd_parse_secure (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); - -static GtkWidget * efhd_attachment_bar (EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable); -static GtkWidget * efhd_attachment_button (EMFormat *emf, EMFormatPURI *puri, GCancellable *cancellable); - -static void efhd_write_attachment_bar (EMFormat *emf, EMFormatPURI *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efhd_write_attachment (EMFormat *emf, EMFormatPURI *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efhd_write_secure_button (EMFormat *emf, EMFormatPURI *emp, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); - -static void efhd_free_attach_puri_data (EMFormatPURI *puri); - -static void efhd_builtin_init (EMFormatHTMLDisplayClass *efhc); - -static gpointer parent_class; - -static EAttachmentStore * -find_parent_attachment_store (EMFormatHTMLDisplay *efhd, - const gchar *part_id) -{ - EMFormat *emf = (EMFormat *) efhd; - EMFormatAttachmentBarPURI *abp; - gchar *tmp, *pos; - GList *item; - - tmp = g_strdup (part_id); - - do { - gchar *id; - - pos = g_strrstr (tmp, "."); - if (!pos) - break; - - g_free (tmp); - tmp = g_strndup (part_id, pos - tmp); - id = g_strdup_printf ("%s.attachment-bar", tmp); - - item = g_hash_table_lookup (emf->mail_part_table, id); - - g_free (id); - - } while (pos && !item); - - g_free (tmp); - - abp = (EMFormatAttachmentBarPURI *) item->data; - - if (abp) - return abp->store; - else - return NULL; -} - -static void -efhd_attachment_bar_puri_free (EMFormatPURI *puri) -{ - EMFormatAttachmentBarPURI *abp; - - abp = (EMFormatAttachmentBarPURI *) puri; - - if (abp->store) { - g_object_unref (abp->store); - abp->store = NULL; - } -} - -static void -efhd_xpkcs7mime_free (EMFormatPURI *puri) -{ - EMFormatSMIMEPURI *sp = (EMFormatSMIMEPURI *) puri; - - if (sp->widget) - gtk_widget_destroy (sp->widget); - - if (sp->description) - g_free (sp->description); - - if (sp->valid) - camel_cipher_validity_free (sp->valid); -} - -static void -efhd_xpkcs7mime_info_response (GtkWidget *widget, - guint button, - EMFormatSMIMEPURI *po) -{ - gtk_widget_destroy (widget); - po->widget = NULL; -} - -#if defined (HAVE_NSS) && defined (ENABLE_SMIME) -static void -efhd_xpkcs7mime_viewcert_clicked (GtkWidget *button, - EMFormatSMIMEPURI *po) -{ - CamelCipherCertInfo *info = g_object_get_data((GObject *)button, "e-cert-info"); - ECert *ec = NULL; - - if (info->cert_data) - ec = e_cert_new (CERT_DupCertificate (info->cert_data)); - - 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 (gtk_widget_destroy), NULL); - - 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 *grid, - GQueue *certlist, - EMFormatSMIMEPURI *po) -{ - GList *head, *link; - GtkTable *table; - gint n = 0; - - table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE); - - head = g_queue_peek_head_link (certlist); - - for (link = head; link != NULL; link = g_list_next (link)) { - CamelCipherCertInfo *info = link->data; - gchar *la = NULL; - const gchar *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) && defined (ENABLE_SMIME) - 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) && defined (ENABLE_SMIME) - 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->cert_data) - ec = e_cert_new (CERT_DupCertificate (info->cert_data)); - - 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++; - } - } - - gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table)); -} - -static void -efhd_xpkcs7mime_validity_clicked (GtkWidget *button, - EMFormatPURI *puri) -{ - EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri; - GtkBuilder *builder; - GtkWidget *grid, *w; - - if (po->widget) - /* FIXME: window raise? */ - return; - - builder = gtk_builder_new (); - e_load_ui_builder_definition (builder, "mail-dialogs.ui"); - - po->widget = e_builder_get_widget(builder, "message_security_dialog"); - - grid = e_builder_get_widget(builder, "signature_grid"); - 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_container_add (GTK_CONTAINER (grid), w); - if (po->valid->sign.description) { - GtkTextBuffer *buffer; - - 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, - "expand", TRUE, - "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_container_add (GTK_CONTAINER (grid), w); - } - - if (!g_queue_is_empty (&po->valid->sign.signers)) - efhd_xpkcs7mime_add_cert_table (grid, &po->valid->sign.signers, po); - - gtk_widget_show_all (grid); - - grid = e_builder_get_widget(builder, "encryption_grid"); - 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_container_add (GTK_CONTAINER (grid), w); - 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, - "expand", TRUE, - "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_container_add (GTK_CONTAINER (grid), w); - } - - if (!g_queue_is_empty (&po->valid->encrypt.encrypters)) - efhd_xpkcs7mime_add_cert_table (grid, &po->valid->encrypt.encrypters, po); - - gtk_widget_show_all (grid); - - g_object_unref (builder); - - g_signal_connect ( - po->widget, "response", - G_CALLBACK (efhd_xpkcs7mime_info_response), po); - - gtk_widget_show (po->widget); -} - -static GtkWidget * -efhd_xpkcs7mime_button (EMFormat *emf, - EMFormatPURI *puri, - GCancellable *cancellable) -{ - GtkWidget *box, *button, *layout, *widget; - EMFormatSMIMEPURI *po = (EMFormatSMIMEPURI *) puri; - const gchar *icon_name; - - /* 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; - - box = gtk_event_box_new (); - if (po->valid->sign.status != 0) - gtk_widget_override_background_color (box, GTK_STATE_FLAG_NORMAL, - &smime_sign_colour[po->valid->sign.status]); - - layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); - gtk_container_add (GTK_CONTAINER (box), layout); - - button = gtk_button_new (); - gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0); - g_signal_connect (button, "clicked", - G_CALLBACK (efhd_xpkcs7mime_validity_clicked), puri); - - widget = gtk_image_new_from_icon_name ( - icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_button_set_image (GTK_BUTTON (button), widget); - - widget = gtk_label_new (po->description); - gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0); - - gtk_widget_show_all (box); - - return box; -} - -struct attachment_load_data { - EAttachment *attachment; - EFlag *flag; -}; - -static void -attachment_loaded (EAttachment *attachment, - GAsyncResult *res, - gpointer user_data) -{ - struct attachment_load_data *data = user_data; - EShell *shell; - GtkWindow *window; - - shell = e_shell_get_default (); - window = e_shell_get_active_window (shell); - - e_attachment_load_handle_error (data->attachment, res, window); - - e_flag_set (data->flag); -} - -/* Idle callback */ -static gboolean -load_attachment_idle (struct attachment_load_data *data) -{ - e_attachment_load_async (data->attachment, - (GAsyncReadyCallback) attachment_loaded, data); - - return FALSE; -} - -static void -efhd_parse_attachment (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - gchar *text, *html; - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; - EMFormatAttachmentPURI *puri; - EAttachmentStore *store; - const EMFormatHandler *handler; - CamelContentType *ct; - gchar *mime_type; - gint len; - const gchar *cid; - guint32 size; - struct attachment_load_data *load_data; - gboolean can_show = FALSE; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - len = part_id->len; - g_string_append (part_id, ".attachment"); - - /* Try to find handler for the mime part */ - ct = camel_mime_part_get_content_type (part); - if (ct) { - mime_type = camel_content_type_simple (ct); - handler = em_format_find_handler (emf, mime_type); - } - - /* 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); - g_free (text); - g_free (mime_type); - - puri = (EMFormatAttachmentPURI *) em_format_puri_new ( - emf, sizeof (EMFormatAttachmentPURI), part, part_id->str); - puri->puri.free = efhd_free_attach_puri_data; - puri->puri.write_func = efhd_write_attachment; - puri->puri.widget_func = efhd_attachment_button; - puri->shown = (handler && em_format_is_inline (emf, part_id->str, part, handler)); - puri->snoop_mime_type = em_format_snoop_type (part); - puri->attachment = e_attachment_new (); - puri->attachment_view_part_id = NULL; - puri->description = html; - puri->handle = handler; - if (info->validity) - puri->puri.validity = camel_cipher_validity_clone (info->validity); - - cid = camel_mime_part_get_content_id (part); - if (cid) - puri->puri.cid = g_strdup_printf ("cid:%s", cid); - - if (handler) { - CamelContentType *ct; - - /* This mime_type is important for WebKit to determine content type. - * We have converted text/ * to text/html, other (binary) formats remained - * untouched. */ - ct = camel_content_type_decode (handler->mime_type); - if (g_strcmp0 (ct->type, "text") == 0) - puri->puri.mime_type = g_strdup ("text/html"); - else - puri->puri.mime_type = camel_content_type_simple (ct); - camel_content_type_unref (ct); - } - - em_format_add_puri (emf, (EMFormatPURI *) puri); - - /* Though it is an attachment, we still might be able to parse it and - * so discover some parts that we might be even able to display. */ - if (handler && handler->parse_func && (handler->parse_func != efhd_parse_attachment) && - ((handler->flags & EM_FORMAT_HANDLER_COMPOUND_TYPE) || - (handler->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION))) { - GList *i; - EMFormatParserInfo attachment_info = { .handler = handler, - .is_attachment = TRUE }; - handler->parse_func (emf, puri->puri.part, part_id, &attachment_info, cancellable); - - i = g_hash_table_lookup (emf->mail_part_table, part_id->str); - if (i->next && i->next->data) { - EMFormatPURI *p = i->next->data; - puri->attachment_view_part_id = g_strdup (p->uri); - can_show = TRUE; - } - } - - e_attachment_set_mime_part (puri->attachment, part); - e_attachment_set_shown (puri->attachment, puri->shown); - if (puri->puri.validity) { - e_attachment_set_signed (puri->attachment, puri->puri.validity->sign.status); - e_attachment_set_encrypted (puri->attachment, puri->puri.validity->encrypt.status); - } - e_attachment_set_can_show (puri->attachment, - can_show || (puri->handle && puri->handle->write_func)); - - store = find_parent_attachment_store (efhd, part_id->str); - e_attachment_store_add_attachment (store, puri->attachment); - - if (emf->folder && emf->folder->summary && emf->message_uid) { - CamelDataWrapper *dw = camel_medium_get_content (CAMEL_MEDIUM (puri->puri.part)); - GByteArray *ba; - ba = camel_data_wrapper_get_byte_array (dw); - if (ba) { - size = ba->len; - - if (camel_mime_part_get_encoding (puri->puri.part) == CAMEL_TRANSFER_ENCODING_BASE64) - size = size / 1.37; - } - } - - load_data = g_new0 (struct attachment_load_data, 1); - load_data->attachment = g_object_ref (puri->attachment); - load_data->flag = e_flag_new (); - - e_flag_clear (load_data->flag); - - /* e_attachment_load_async must be called from main thread */ - g_idle_add ((GSourceFunc) load_attachment_idle, load_data); - - e_flag_wait (load_data->flag); - - e_flag_free (load_data->flag); - g_object_unref (load_data->attachment); - g_free (load_data); - - if (size != 0) { - GFileInfo *fileinfo; - - fileinfo = e_attachment_get_file_info (puri->attachment); - g_file_info_set_size (fileinfo, size); - e_attachment_set_file_info (puri->attachment, fileinfo); - } - - g_string_truncate (part_id, len); -} - -static void -efhd_parse_secure (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - if (info->validity - && (info->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE - || info->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)) { - GString *buffer; - EMFormatSMIMEPURI *pobj; - - pobj = (EMFormatSMIMEPURI *) em_format_puri_new ( - emf, sizeof (EMFormatSMIMEPURI), part, part_id->str); - pobj->puri.free = efhd_xpkcs7mime_free; - pobj->valid = camel_cipher_validity_clone (info->validity); - pobj->puri.widget_func = efhd_xpkcs7mime_button; - pobj->puri.write_func = efhd_write_secure_button; - - em_format_add_puri (emf, (EMFormatPURI *) pobj); - - buffer = g_string_new (""); - - if (info->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) { - const gchar *desc; - gint status; - - status = info->validity->sign.status; - desc = smime_sign_table[status].shortdesc; - - g_string_append (buffer, gettext (desc)); - - em_format_html_format_cert_infos ( - &info->validity->sign.signers, buffer); - } - - if (info->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) { - const gchar *desc; - gint status; - - if (info->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) - g_string_append (buffer, "\n"); - - status = info->validity->encrypt.status; - desc = smime_encrypt_table[status].shortdesc; - g_string_append (buffer, gettext (desc)); - } - - pobj->description = g_string_free (buffer, FALSE); - } -} - -/******************************************************************************/ -static void -efhd_write_attachment_bar (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatAttachmentBarPURI *efab = (EMFormatAttachmentBarPURI *) puri; - gchar *str; - - if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) - return; - - if (e_attachment_store_get_num_attachments (efab->store) == 0) - return; - - str = g_strdup_printf ( - "<object type=\"application/x-attachment-bar\" " - "height=\"20\" width=\"100%%\" " - "id=\"%s\"data=\"%s\"></object>", puri->uri, puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); -} - -static void -efhd_write_attachment (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *str, *desc; - const gchar *mime_type; - gchar *button_id; - - EMFormatAttachmentPURI *efa = (EMFormatAttachmentPURI *) puri; - - /* If the attachment is requested as RAW, then call the handler directly - * and do not append any other code. */ - if ((info->mode == EM_FORMAT_WRITE_MODE_RAW) && - efa->handle && efa->handle->write_func) { - - efa->handle->write_func (emf, puri, stream, info, cancellable); - return; - } - - if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) { - - if (efa->handle && efa->handle->write_func) - efa->handle->write_func (emf, puri, stream, info, cancellable); - - return; - } - - if (efa->handle) - mime_type = efa->handle->mime_type; - else - mime_type = efa->snoop_mime_type; - - button_id = g_strconcat (puri->uri, ".attachment_button", NULL); - - desc = em_format_describe_part (puri->part, mime_type); - str = g_strdup_printf ( - "<div class=\"attachment\">" - "<table width=\"100%%\" border=\"0\">" - "<tr valign=\"middle\">" - "<td align=\"left\" width=\"100\">" - "<object type=\"application/x-attachment-button\" " - "height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>" - "</td>" - "<td align=\"left\">%s</td>" - "</tr>", puri->uri, button_id, desc); - - camel_stream_write_string (stream, str, cancellable, NULL); - g_free (desc); - g_free (button_id); - g_free (str); - - /* If we know how to write the attachment, then do it */ - if ((efa->handle && efa->handle->write_func) || - (efa->attachment_view_part_id)) { - - str = g_strdup_printf ( - "<tr><td colspan=\"2\">" - "<div class=\"attachment-wrapper\" id=\"%s\">", - puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - g_free (str); - - if (efa->handle->write_func) { - efa->handle->write_func ( - emf, puri, stream, info, cancellable); - } else if (efa->attachment_view_part_id) { - EMFormatPURI *p; - - p = em_format_find_puri ( - emf, efa->attachment_view_part_id); - if (p && p->write_func) - p->write_func (emf, p, stream, info, cancellable); - } - - camel_stream_write_string (stream, "</div></td></tr>", cancellable, NULL); - } - - camel_stream_write_string (stream, "</table></div>", cancellable, NULL); -} - -static void -efhd_write_secure_button (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *str; - - if ((info->mode != EM_FORMAT_WRITE_MODE_NORMAL) && - (info->mode != EM_FORMAT_WRITE_MODE_RAW)) - return; - - str = g_strdup_printf ( - "<object type=\"application/x-secure-button\" " - "height=\"20\" width=\"100%%\" " - "data=\"%s\" id=\"%s\"></object>", puri->uri, puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); -} - -static void -efhd_finalize (GObject *object) -{ - EMFormatHTMLDisplay *efhd; - - efhd = EM_FORMAT_HTML_DISPLAY (object); - g_return_if_fail (efhd != NULL); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -efhd_preparse (EMFormat *emf) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; - - efhd->priv->last_view = NULL; -} - -static void -efhd_class_init (EMFormatHTMLDisplayClass *class) -{ - GObjectClass *object_class; - EMFormatHTMLClass *format_html_class; - EMFormatClass *format_class; - - 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; - - format_html_class = EM_FORMAT_HTML_CLASS (class); - format_html_class->html_widget_type = E_TYPE_MAIL_DISPLAY; - - format_class = EM_FORMAT_CLASS (class); - format_class->preparse = efhd_preparse; - - efhd_builtin_init (class); -} - -static void -efhd_init (EMFormatHTMLDisplay *efhd) -{ - efhd->priv = EM_FORMAT_HTML_DISPLAY_GET_PRIVATE (efhd); - - /* 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; - -} - -GType -em_format_html_display_get_type (void) -{ - static GType type = 0; - - 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 */ - }; - - type = g_type_register_static ( - EM_TYPE_FORMAT_HTML, "EMFormatHTMLDisplay", - &type_info, 0); - } - - return type; -} - -EMFormatHTMLDisplay * -em_format_html_display_new (CamelSession *session) -{ - g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL); - - return g_object_new ( - EM_TYPE_FORMAT_HTML_DISPLAY, - "session", session, NULL); -} - -/* ********************************************************************** */ - -static EMFormatHandler type_builtin_table[] = { - { (gchar *) "x-evolution/message/prefix", efhd_message_prefix, }, - { (gchar *) "x-evolution/message/attachment-bar", (EMFormatParseFunc) efhd_message_add_bar, efhd_write_attachment_bar, }, - { (gchar *) "x-evolution/message/attachment", efhd_parse_attachment, efhd_write_attachment, }, - { (gchar *) "x-evolution/message/x-secure-button", efhd_parse_secure, efhd_write_secure_button, }, -}; - -static void -efhd_builtin_init (EMFormatHTMLDisplayClass *efhc) -{ - gint i; - - EMFormatClass *emfc = (EMFormatClass *) efhc; - - for (i = 0; i < G_N_ELEMENTS (type_builtin_table); i++) - em_format_class_add_handler (emfc, &type_builtin_table[i]); -} - -static void -efhd_message_prefix (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - const gchar *flag, *comp, *due; - time_t date; - gchar *iconpath, *due_date_str; - GString *buffer; - EMFormatAttachmentPURI *puri; - - if (emf->folder == NULL || emf->message_uid == NULL - || (flag = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "follow-up")) == NULL - || flag[0] == 0) - return; - - puri = (EMFormatAttachmentPURI *) em_format_puri_new ( - emf, sizeof (EMFormatAttachmentPURI), part, ".message_prefix"); - - puri->attachment_view_part_id = g_strdup (part_id->str); - - comp = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "completed-on"); - iconpath = e_icon_factory_get_icon_filename (comp && comp[0] ? "stock_mail-flag-for-followup-done" : "stock_mail-flag-for-followup", GTK_ICON_SIZE_MENU); - if (iconpath) { - gchar *classid; - - classid = g_strdup_printf ( - "icon:///em-format-html-display/%s/%s", - part_id->str, - comp && comp[0] ? "comp" : "uncomp"); - - puri->puri.uri = classid; - - g_free (classid); - } - - buffer = g_string_new (""); - - if (comp && comp[0]) { - date = camel_header_decode_date (comp, NULL); - due_date_str = e_datetime_format_format ( - "mail", "header", DTFormatKindDateTime, date); - g_string_append_printf ( - buffer, "%s, %s %s", - flag, _("Completed on"), - due_date_str ? due_date_str : "???"); - g_free (due_date_str); - } else if ((due = camel_folder_get_message_user_tag(emf->folder, emf->message_uid, "due-by")) != NULL && due[0]) { - time_t now; - - date = camel_header_decode_date (due, NULL); - now = time (NULL); - if (now > date) - g_string_append_printf ( - buffer, - "<b>%s</b> ", - _("Overdue:")); - - due_date_str = e_datetime_format_format ( - "mail", "header", DTFormatKindDateTime, date); - /* Translators: the "by" is part of the string, - * like "Follow-up by Tuesday, January 13, 2009" */ - g_string_append_printf ( - buffer, "%s %s %s", - flag, _("by"), - due_date_str ? due_date_str : "???"); - g_free (due_date_str); - } else { - g_string_append (buffer, flag); - } - - puri->description = g_string_free (buffer, FALSE); -} - -/* ********************************************************************** */ - -/* attachment button callback */ -static GtkWidget * -efhd_attachment_button (EMFormat *emf, - EMFormatPURI *puri, - GCancellable *cancellable) -{ - EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri; - GtkWidget *widget; - - /* FIXME: handle default shown case */ - d(printf("adding attachment button/content\n")); - - if (g_cancellable_is_cancelled (cancellable)) - return NULL; - - if (!info || info->forward) { - g_warning ("unable to expand the attachment\n"); - return NULL; - } - - widget = e_attachment_button_new (); - g_object_set_data (G_OBJECT (widget), "uri", puri->uri); - e_attachment_button_set_attachment ( - E_ATTACHMENT_BUTTON (widget), info->attachment); - e_attachment_button_set_view ( - E_ATTACHMENT_BUTTON (widget), - EM_FORMAT_HTML_DISPLAY (emf)->priv->last_view); - - gtk_widget_set_can_focus (widget, TRUE); - gtk_widget_show (widget); - - return widget; -} - -static GtkWidget * -efhd_attachment_bar (EMFormat *emf, - EMFormatPURI *puri, - GCancellable *cancellable) -{ - EMFormatAttachmentBarPURI *abp = (EMFormatAttachmentBarPURI *) puri; - GtkWidget *widget; - - widget = e_mail_attachment_bar_new (abp->store); - EM_FORMAT_HTML_DISPLAY (emf)->priv->last_view = (EAttachmentView *) widget; - - return widget; -} - -static void -efhd_message_add_bar (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatAttachmentBarPURI *puri; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - len = part_id->len; - g_string_append (part_id, ".attachment-bar"); - puri = (EMFormatAttachmentBarPURI *) em_format_puri_new ( - emf, sizeof (EMFormatAttachmentBarPURI), part, part_id->str); - puri->puri.write_func = efhd_write_attachment_bar; - puri->puri.widget_func = efhd_attachment_bar; - puri->puri.free = efhd_attachment_bar_puri_free; - puri->store = E_ATTACHMENT_STORE (e_attachment_store_new ()); - - em_format_add_puri (emf, (EMFormatPURI *) puri); - - g_string_truncate (part_id, len); -} - -static void -efhd_free_attach_puri_data (EMFormatPURI *puri) -{ - EMFormatAttachmentPURI *info = (EMFormatAttachmentPURI *) puri; - - g_return_if_fail (puri != NULL); - - if (info->attachment) { - g_object_unref (info->attachment); - info->attachment = NULL; - } - - if (info->description) { - g_free (info->description); - info->description = NULL; - } - - if (info->attachment_view_part_id) { - g_free (info->attachment_view_part_id); - info->attachment_view_part_id = NULL; - } - - if (info->mstream) { - g_object_unref (info->mstream); - info->mstream = NULL; - } -} diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h deleted file mode 100644 index 7c0d7a9fd5..0000000000 --- a/mail/em-format-html-display.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * - * 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) - * - */ - -/* - Concrete class for formatting mails to displayed html -*/ - -#ifndef EM_FORMAT_HTML_DISPLAY_H -#define EM_FORMAT_HTML_DISPLAY_H - -#include <mail/em-format-html.h> -#include <misc/e-attachment-view.h> - -/* Standard GObject macros */ -#define EM_TYPE_FORMAT_HTML_DISPLAY \ - (em_format_html_display_get_type ()) -#define EM_FORMAT_HTML_DISPLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplay)) -#define EM_FORMAT_HTML_DISPLAY_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayClass)) -#define EM_IS_FORMAT_HTML_DISPLAY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), EM_TYPE_FORMAT_HTML_DISPLAY)) -#define EM_IS_FORMAT_HTML_DISPLAY_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), EM_TYPE_FORMAT_HTML_DISPLAY)) -#define EM_FORMAT_HTML_DISPLAY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), EM_TYPE_FORMAT_HTML_DISPLAY, EMFormatHTMLDisplayClass)) - -G_BEGIN_DECLS - -typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay; -typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass; -typedef struct _EMFormatHTMLDisplayPrivate EMFormatHTMLDisplayPrivate; -typedef struct _EMFormatAttachmentBarPURI EMFormatAttachmentBarPURI; -typedef struct _EMFormatAttachmentPURI EMFormatAttachmentPURI; -typedef struct _EMFormatSMIMEPURI EMFormatSMIMEPURI; - -struct _EMFormatAttachmentBarPURI { - EMFormatPURI puri; - - EAttachmentStore *store; -}; - -struct _EMFormatAttachmentPURI { - EMFormatPURI puri; - - const EMFormatHandler *handle; - - const gchar *snoop_mime_type; - - /* for the > and V buttons */ - GtkWidget *forward, *down; - guint shown : 1; - - /* Attachment */ - EAttachment *attachment; - gchar *attachment_view_part_id; - gchar *description; - - /* image stuff */ - gint fit_width; - gint fit_height; - GtkImage *image; - GtkWidget *event_box; - - /* Optional Text Mem Stream */ - CamelStreamMem *mstream; -}; - -struct _EMFormatSMIMEPURI { - EMFormatPURI puri; - - gchar *description; - - gint signature; - CamelCipherValidity *valid; - GtkWidget *widget; -}; - -struct _EMFormatHTMLDisplay { - EMFormatHTML parent; - EMFormatHTMLDisplayPrivate *priv; - - struct _ESearchingTokenizer *search_tok; -}; - -struct _EMFormatHTMLDisplayClass { - EMFormatHTMLClass parent_class; -}; - -GType em_format_html_display_get_type (void); -EMFormatHTMLDisplay * - em_format_html_display_new (CamelSession *session); -G_END_DECLS - -#endif /* EM_FORMAT_HTML_DISPLAY_H */ diff --git a/mail/em-format-html-print.c b/mail/em-format-html-print.c deleted file mode 100644 index 150c16dbf5..0000000000 --- a/mail/em-format-html-print.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * - * 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/> - * - * - * Authors: - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include "em-format-html-print.h" -#include "em-format-html-display.h" -#include "e-mail-attachment-bar.h" -#include <e-util/e-print.h> -#include <e-util/e-util.h> -#include <widgets/misc/e-attachment-store.h> -#include <libemail-engine/mail-ops.h> - -#include "em-format-html-print.h" - -#define d(x) - -static gpointer parent_class = NULL; - -struct _EMFormatHTMLPrintPrivate { - - EMFormatHTML *original_formatter; - EMFormatPURI *top_level_puri; - - /* List of attachment PURIs */ - GList *attachments; - -}; - -enum { - PROP_0, - PROP_ORIGINAL_FORMATTER -}; - -static void efhp_write_print_layout (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efhp_write_headers (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efhp_write_inline_attachment (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); - -static void -efhp_write_attachments_list (EMFormatHTMLPrint *efhp, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GString *str; - GList *iter; - - if (!efhp->priv->attachments) - return; - - str = g_string_new ( - "<table border=\"0\" cellspacing=\"5\" cellpadding=\"0\" " - "class=\"attachments-list\" >\n"); - g_string_append_printf (str, - "<tr><th colspan=\"2\"><h1>%s</h1></td></tr>\n" - "<tr><th>%s</th><th>%s</th></tr>\n", - _("Attachments"), _("Name"), _("Size")); - - for (iter = efhp->priv->attachments; iter; iter = iter->next) { - EMFormatPURI *puri = iter->data; - EAttachment *attachment; - GFileInfo *fi; - gchar *name, *size; - GByteArray *ba; - CamelDataWrapper *dw; - - attachment = ((EMFormatAttachmentPURI *) puri)->attachment; - fi = e_attachment_get_file_info (attachment); - if (!fi) - continue; - - if (e_attachment_get_description (attachment) && - *e_attachment_get_description (attachment)) { - name = g_strdup_printf ("%s (%s)", - e_attachment_get_description (attachment), - g_file_info_get_display_name (fi)); - } else { - name = g_strdup (g_file_info_get_display_name (fi)); - } - - dw = camel_medium_get_content ((CamelMedium *) puri->part); - ba = camel_data_wrapper_get_byte_array (dw); - size = g_format_size (ba->len); - - g_string_append_printf (str, "<tr><td>%s</td><td>%s</td></tr>\n", - name, size); - - g_free (name); - g_free (size); - } - - g_string_append (str, "</table>\n"); - - camel_stream_write_string (stream, str->str, cancellable, NULL); - g_string_free (str, TRUE); -} - -static void -efhp_write_headers (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - struct _camel_header_raw raw_header; - GString *str, *tmp; - gchar *subject; - const gchar *buf; - EMFormatPURI *p; - GList *iter; - gint attachments_count; - gchar *puri_prefix; - - buf = camel_medium_get_header (CAMEL_MEDIUM (puri->part), "subject"); - subject = camel_header_decode_string (buf, "UTF-8"); - str = g_string_new ("<table border=\"0\" cellspacing=\"5\" " \ - "cellpadding=\"0\" class=\"printing-header\">\n"); - g_string_append_printf ( - str, - "<tr class=\"header-item\">" - "<td colspan=\"2\"><h1>%s</h1></td>" - "</tr>\n", - subject); - g_free (subject); - - for (iter = g_queue_peek_head_link (&emf->header_list); iter; iter = iter->next) { - - EMFormatHeader *header = iter->data; - raw_header.name = header->name; - - /* Skip 'Subject' header, it's already displayed. */ - if (g_ascii_strncasecmp (header->name, "Subject", 7) == 0) - continue; - - if (header->value && *header->value) { - raw_header.value = header->value; - em_format_html_format_header (emf, str, - CAMEL_MEDIUM (puri->part), &raw_header, - header->flags | EM_FORMAT_HTML_HEADER_NOLINKS, - "UTF-8"); - } else { - raw_header.value = g_strdup (camel_medium_get_header ( - CAMEL_MEDIUM (emf->message), header->name)); - - if (raw_header.value && *raw_header.value) { - em_format_html_format_header (emf, str, - CAMEL_MEDIUM (puri->part), &raw_header, - header->flags | EM_FORMAT_HTML_HEADER_NOLINKS, - "UTF-8"); - } - - if (raw_header.value) - g_free (raw_header.value); - } - } - - /* Get prefix of this PURI */ - puri_prefix = g_strndup (puri->uri, g_strrstr (puri->uri, ".") - puri->uri); - - /* Add encryption/signature header */ - raw_header.name = _("Security"); - tmp = g_string_new (""); - /* Find first secured part. */ - for (iter = emf->mail_part_list, puri; iter; iter = iter->next) { - - p = iter->data; - - if (p->validity_type == 0) - continue; - - if (!g_str_has_prefix (p->uri, puri_prefix)) - continue; - - if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) && - (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) { - g_string_append (tmp, _("GPG signed")); - } - if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_PGP) && - (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) { - if (tmp->len > 0) g_string_append (tmp, ", "); - g_string_append (tmp, _("GPG encrpyted")); - } - if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) && - (p->validity_type & EM_FORMAT_VALIDITY_FOUND_SIGNED)) { - - if (tmp->len > 0) g_string_append (tmp, ", "); - g_string_append (tmp, _("S/MIME signed")); - } - if ((p->validity_type & EM_FORMAT_VALIDITY_FOUND_SMIME) && - (p->validity_type & EM_FORMAT_VALIDITY_FOUND_ENCRYPTED)) { - - if (tmp->len > 0) g_string_append (tmp, ", "); - g_string_append (tmp, _("S/MIME encrpyted")); - } - - break; - } - - if (tmp->len > 0) { - raw_header.value = tmp->str; - em_format_html_format_header (emf, str, CAMEL_MEDIUM (p->part), - &raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); - } - g_string_free (tmp, TRUE); - - /* Count attachments and display the number as a header */ - attachments_count = 0; - - for (iter = emf->mail_part_list; iter; iter = iter ? iter->next : iter) { - - p = iter->data; - - if (!g_str_has_prefix (p->uri, puri_prefix)) - continue; - - if ((p->is_attachment || g_str_has_suffix(p->uri, ".attachment")) && - (!p->cid)) { - attachments_count++; - /* EFHD sometimes creates two PURIs per attachment! */ - if (iter->next && iter->next->data) { - EMFormatPURI *p2 = iter->next->data; - if (g_str_has_prefix (p2->uri, p->uri)) - iter = iter->next; - } - } - } - if (attachments_count > 0) { - raw_header.name = _("Attachments"); - raw_header.value = g_strdup_printf ("%d", attachments_count); - em_format_html_format_header (emf, str, CAMEL_MEDIUM (puri->part), - &raw_header, EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_NOLINKS, "UTF-8"); - g_free (raw_header.value); - } - - g_string_append (str, "</table>"); - - camel_stream_write_string (stream, str->str, cancellable, NULL); - g_string_free (str, TRUE); - g_free (puri_prefix); -} - -static void -efhp_write_inline_attachment (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *name; - EMFormatAttachmentPURI *att_puri = (EMFormatAttachmentPURI *) puri; - EAttachment *attachment; - GFileInfo *fi; - - attachment = att_puri->attachment; - fi = e_attachment_get_file_info (attachment); - - if (e_attachment_get_description (attachment) && - *e_attachment_get_description (attachment)) { - name = g_strdup_printf ("<h2>Attachment: %s (%s)</h2>\n", - e_attachment_get_description (attachment), - g_file_info_get_display_name (fi)); - } else { - name = g_strdup_printf ("<h2>Attachment: %s</h2>\n", - g_file_info_get_display_name (fi)); - } - - camel_stream_write_string (stream, name, cancellable, NULL); - g_free (name); -} - -static void -efhp_write_print_layout (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GList *iter; - EMFormatWriterInfo print_info = { - EM_FORMAT_WRITE_MODE_PRINTING, FALSE, FALSE }; - EMFormatHTMLPrint *efhp = EM_FORMAT_HTML_PRINT (emf); - - g_list_free (efhp->priv->attachments); - efhp->priv->attachments = NULL; - - camel_stream_write_string (stream, - "<!DOCTYPE HTML>\n<html>\n" - "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n" - "<title>Evolution Mail Display</title>\n" - "<link type=\"text/css\" rel=\"stylesheet\" media=\"print\" " - "href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview-print.css\" />\n" - "</head>\n" - "<body style=\"background: #FFF; color: #000;\">", - cancellable, NULL); - - for (iter = emf->mail_part_list; iter != NULL; iter = iter ? iter->next : iter) { - - EMFormatPURI *puri = iter->data; - - if (g_str_has_suffix (puri->uri, "print_layout")) - continue; - - /* To late to change .headers writer_func, do it manually. */ - if (g_str_has_suffix (puri->uri, ".headers")) { - efhp_write_headers (emf, puri, stream, &print_info, cancellable); - continue; - } - - if (g_str_has_suffix (puri->uri, ".rfc822")) { - - puri->write_func (emf, puri, stream, &print_info, cancellable); - - while (iter && !g_str_has_suffix (puri->uri, ".rfc822.end")) { - - iter = iter->next; - if (iter) - puri = iter->data; - } - - if (!iter) - break; - - continue; - - } - - if (puri->is_attachment || g_str_has_suffix (puri->uri, ".attachment")) { - const EMFormatHandler *handler; - CamelContentType *ct; - gchar *mime_type; - - if (puri->cid && g_ascii_strncasecmp (puri->cid, "cid:", 4) == 0) - continue; - - ct = camel_mime_part_get_content_type (puri->part); - mime_type = camel_content_type_simple (ct); - - handler = em_format_find_handler (puri->emf, mime_type); - d(printf("Handler for PURI %s (%s): %s\n", puri->uri, mime_type, - handler ? handler->mime_type : "(null)")); - g_free (mime_type); - - efhp->priv->attachments = - g_list_append (efhp->priv->attachments, puri); - - /* If we can't inline this attachment, skip it */ - if (handler && puri->write_func) { - efhp_write_inline_attachment (puri->emf, puri, - stream, &print_info, cancellable); - - if (iter->next && iter->next->data) { - EMFormatPURI *p; - p = iter->next->data; - - /* Has the next PURI the same prefix? */ - if (p->write_func && - g_str_has_prefix (p->uri, puri->uri)) { - p->write_func (emf, p, stream, - &print_info, cancellable); - iter = iter->next; - } else { - if (puri->write_func) { - puri->write_func (emf, puri, - stream, &print_info, - cancellable); - } - } - } - } - - continue; - } - - /* Ignore widget parts and unwritable non-attachment parts */ - if (puri->write_func == NULL) - continue; - - /* Passed all tests, probably a regular part - display it */ - puri->write_func (puri->emf, puri, stream, &print_info, cancellable); - - } - - efhp_write_attachments_list (efhp, stream, &print_info, cancellable); - - camel_stream_write_string (stream, "</body></html>", cancellable, NULL); -} - -static void -efhp_finalize (GObject *object) -{ - EMFormatHTMLPrint *efhp = EM_FORMAT_HTML_PRINT (object); - - if (efhp->priv->original_formatter) { - g_object_unref (efhp->priv->original_formatter); - efhp->priv->original_formatter = NULL; - } - - if (efhp->priv->top_level_puri) { - em_format_puri_free (efhp->priv->top_level_puri); - efhp->priv->top_level_puri = NULL; - } - - if (efhp->priv->attachments) { - g_list_free (efhp->priv->attachments); - efhp->priv->attachments = NULL; - } - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -efhp_is_inline (EMFormat *emf, - const gchar *part_id, - CamelMimePart *mime_part, - const EMFormatHandler *handle) -{ - /* When printing, inline any part that has a handler. */ - return (handle != NULL); -} - -static void -efhp_set_orig_formatter (EMFormatHTMLPrint *efhp, - EMFormat *formatter) -{ - EMFormat *emfp, *emfs; - EMFormatPURI *puri; - GHashTableIter iter; - gpointer key, value; - - efhp->priv->original_formatter = g_object_ref (formatter); - - emfp = EM_FORMAT (efhp); - emfs = EM_FORMAT (formatter); - - emfp->mail_part_list = g_list_copy (emfs->mail_part_list); - - /* Make a shallow copy of the table. This table will NOT destroy - * the PURIs when free'd! */ - if (emfp->mail_part_table) - g_hash_table_unref (emfp->mail_part_table); - - emfp->mail_part_table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_iter_init (&iter, emfs->mail_part_table); - while (g_hash_table_iter_next (&iter, &key, &value)) - g_hash_table_insert (emfp->mail_part_table, key, value); - - if (emfs->folder) - emfp->folder = g_object_ref (emfs->folder); - emfp->message_uid = g_strdup (emfs->message_uid); - emfp->message = g_object_ref (emfs->message); - - /* Add a generic PURI that will write a HTML layout - * for all the parts */ - puri = em_format_puri_new (EM_FORMAT (efhp), - sizeof (EMFormatPURI), NULL, "print_layout"); - puri->write_func = efhp_write_print_layout; - puri->mime_type = g_strdup ("text/html"); - em_format_add_puri (EM_FORMAT (efhp), puri); - efhp->priv->top_level_puri = puri; -} - -static EMFormatHandler type_builtin_table[] = { - { (gchar *) "x-evolution/message/headers", 0, efhp_write_headers, }, -}; - -static void -efhp_builtin_init (EMFormatHTMLPrintClass *efhc) -{ - EMFormatClass *emfc; - gint ii; - - emfc = (EMFormatClass *) efhc; - - for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++) - em_format_class_add_handler ( - emfc, &type_builtin_table[ii]); -} - -static void -efhp_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - - case PROP_ORIGINAL_FORMATTER: - efhp_set_orig_formatter ( - EM_FORMAT_HTML_PRINT (object), - (EMFormat *) g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -} - -static void -efhp_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EMFormatHTMLPrintPrivate *priv; - - priv = EM_FORMAT_HTML_PRINT (object)->priv; - - switch (prop_id) { - - case PROP_ORIGINAL_FORMATTER: - g_value_set_pointer (value, - priv->original_formatter); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -} - -static void -em_format_html_print_base_init (EMFormatHTMLPrintClass *klass) -{ - efhp_builtin_init (klass); -} - -static void -em_format_html_print_class_init (EMFormatHTMLPrintClass *klass) -{ - GObjectClass *object_class; - EMFormatClass *format_class; - - parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (EMFormatHTMLPrintPrivate)); - - object_class = G_OBJECT_CLASS (klass); - object_class->finalize = efhp_finalize; - object_class->set_property = efhp_set_property; - object_class->get_property = efhp_get_property; - - format_class = EM_FORMAT_CLASS (klass); - format_class->is_inline = efhp_is_inline; - - g_object_class_install_property ( - object_class, - PROP_ORIGINAL_FORMATTER, - g_param_spec_object ( - "original-formatter", - NULL, - NULL, - EM_TYPE_FORMAT, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY)); -} - -static void -em_format_html_print_init (EMFormatHTMLPrint *efhp) -{ - efhp->priv = G_TYPE_INSTANCE_GET_PRIVATE ( - efhp, EM_TYPE_FORMAT_HTML_PRINT, EMFormatHTMLPrintPrivate); - - efhp->priv->attachments = NULL; - efhp->export_filename = NULL; -} - -GType -em_format_html_print_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EMFormatHTMLPrintClass), - (GBaseInitFunc) em_format_html_print_base_init, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) em_format_html_print_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EMFormatHTMLPrint), - 0, /* n_preallocs */ - (GInstanceInitFunc) em_format_html_print_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - em_format_html_get_type(), "EMFormatHTMLPrint", - &type_info, 0); - } - - return type; -} - -EMFormatHTMLPrint * -em_format_html_print_new (EMFormatHTML *source) -{ - EMFormatHTMLPrint *efhp; - CamelSession *session; - - g_return_val_if_fail (EM_IS_FORMAT_HTML (source), NULL); - - session = em_format_get_session (EM_FORMAT (source)); - - efhp = g_object_new ( - EM_TYPE_FORMAT_HTML_PRINT, - "session", session, - "original-formatter", source, - NULL); - - return efhp; -} diff --git a/mail/em-format-html-print.h b/mail/em-format-html-print.h deleted file mode 100644 index d9fe1ff6d4..0000000000 --- a/mail/em-format-html-print.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Concrete class for formatting mails to displayed html - * - * 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 EM_FORMAT_HTML_PRINT_H -#define EM_FORMAT_HTML_PRINT_H - -#include "mail/em-format-html.h" - -/* Standard GObject macros */ -#define EM_TYPE_FORMAT_HTML_PRINT \ - (em_format_html_print_get_type ()) -#define EM_FORMAT_HTML_PRINT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), EM_TYPE_FORMAT_HTML_PRINT, EMFormatHTMLPrint)) -#define EM_FORMAT_HTML_PRINT_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), EM_TYPE_FORMAT_HTML_PRINT, EMFormatHTMLPrintClass)) -#define EM_IS_FORMAT_HTML_PRINT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), EM_TYPE_FORMAT_HTML_PRINT)) -#define EM_IS_FORMAT_HTML_PRINT_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), EM_TYPE_FORMAT_HTML_PRINT)) -#define EM_FORMAT_HTML_PRINT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), EM_TYPE_FORMAT_HTML_PRINT, EMFormatHTMLPrintClass)) - -G_BEGIN_DECLS - -typedef struct _EMFormatHTMLPrint EMFormatHTMLPrint; -typedef struct _EMFormatHTMLPrintClass EMFormatHTMLPrintClass; -typedef struct _EMFormatHTMLPrintPrivate EMFormatHTMLPrintPrivate; - -struct _EMFormatHTMLPrint { - EMFormatHTML parent; - EMFormatHTMLPrintPrivate *priv; - gchar *export_filename; -}; - -struct _EMFormatHTMLPrintClass { - EMFormatHTMLClass parent_class; -}; - -GType em_format_html_print_get_type (void); -EMFormatHTMLPrint * - em_format_html_print_new (EMFormatHTML *source); - -G_END_DECLS - -#endif /* EM_FORMAT_HTML_PRINT_H */ diff --git a/mail/em-format-html.c b/mail/em-format-html.c deleted file mode 100644 index bb80d3957b..0000000000 --- a/mail/em-format-html.c +++ /dev/null @@ -1,3011 +0,0 @@ -/* - * 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/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#define _GNU_SOURCE /* Enable strcasestr in string.h */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <ctype.h> - -#include <gtk/gtk.h> -#ifdef G_OS_WIN32 -/* Work around 'DATADIR' and 'interface' lossage in <windows.h> */ -#define DATADIR crap_DATADIR -#include <windows.h> -#undef DATADIR -#undef interface -#endif - -#include <libebackend/libebackend.h> - -#include "e-util/e-datetime-format.h" -#include "e-util/e-icon-factory.h" -#include "e-util/e-util-private.h" -#include "e-util/e-util.h" -#include "misc/e-web-view.h" - -#include <shell/e-shell.h> - -#include <glib/gi18n.h> - -#include <JavaScriptCore/JavaScript.h> -#include <webkit/webkit.h> - -#include <libemail-utils/mail-mt.h> -#include <libemail-engine/e-mail-enumtypes.h> -#include <libemail-engine/e-mail-utils.h> -#include <libemail-engine/mail-config.h> - -#include "em-format-html.h" -#include "em-utils.h" -#include "e-mail-display.h" -#include <em-format/em-inline-filter.h> - -#define EM_FORMAT_HTML_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), EM_TYPE_FORMAT_HTML, EMFormatHTMLPrivate)) - -#define d(x) - -struct _EMFormatHTMLPrivate { - GdkColor colors[EM_FORMAT_HTML_NUM_COLOR_TYPES]; - EMailImageLoadingPolicy image_loading_policy; - - guint can_load_images : 1; - guint only_local_photos : 1; - guint show_sender_photo : 1; - guint show_real_date : 1; - guint animate_images : 1; -}; - -static gpointer parent_class; - -enum { - PROP_0, - PROP_BODY_COLOR, - PROP_CITATION_COLOR, - PROP_CONTENT_COLOR, - PROP_FRAME_COLOR, - PROP_HEADER_COLOR, - PROP_IMAGE_LOADING_POLICY, - PROP_MARK_CITATIONS, - PROP_ONLY_LOCAL_PHOTOS, - PROP_SHOW_SENDER_PHOTO, - PROP_SHOW_REAL_DATE, - PROP_TEXT_COLOR, - PROP_ANIMATE_IMAGES -}; - -#define EFM_MESSAGE_START_ANAME "evolution_message_start" -#define EFH_MESSAGE_START "<A name=\"" EFM_MESSAGE_START_ANAME "\"></A>" - -static void efh_parse_image (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_text_enriched (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_text_plain (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_text_html (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_message_external (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_message_deliverystatus (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void efh_parse_message_rfc822 (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); - -static void efh_write_image (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_text_enriched (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_text_plain (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_text_html (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_source (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_headers (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_attachment (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_error (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void efh_write_message_rfc822 (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); - -static void efh_format_full_headers (EMFormatHTML *efh, GString *buffer, CamelMedium *part, gboolean all_headers, gboolean visible, GCancellable *cancellable); -static void efh_format_short_headers (EMFormatHTML *efh, GString *buffer, CamelMedium *part, gboolean visible, GCancellable *cancellable); - -static void efh_write_message (EMFormat *emf, GList *puris, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); - -/*****************************************************************************/ -static void -efh_parse_image (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - const gchar *tmp; - gchar *cid; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - tmp = camel_mime_part_get_content_id (part); - if (!tmp) { - em_format_parse_part_as (emf, part, part_id, info, - "x-evolution/message/attachment", cancellable); - return; - } - - cid = g_strdup_printf ("cid:%s", tmp); - len = part_id->len; - g_string_append (part_id, ".image"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->cid = cid; - puri->write_func = efh_write_image; - puri->mime_type = g_strdup (info->handler->mime_type); - puri->is_attachment = TRUE; - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - - em_format_add_puri (emf, puri); - g_string_truncate (part_id, len); -} - -static void -efh_parse_text_enriched (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - const gchar *tmp; - gchar *cid; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - tmp = camel_mime_part_get_content_id (part); - if (!tmp) { - cid = g_strdup_printf ("em-no-cid:%s", part_id->str); - } else { - cid = g_strdup_printf ("cid:%s", tmp); - } - - len = part_id->len; - g_string_append (part_id, ".text_enriched"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->cid = cid; - puri->mime_type = g_strdup (info->handler->mime_type); - puri->write_func = efh_write_text_enriched; - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - puri->is_attachment = info->is_attachment; - - em_format_add_puri (emf, puri); - g_string_truncate (part_id, len); -} - -static void -efh_parse_text_plain (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - CamelStream *filtered_stream, *null; - CamelMultipart *mp; - CamelDataWrapper *dw; - CamelContentType *type; - gint i, count, len; - EMInlineFilter *inline_filter; - gboolean charset_added = FALSE; - const gchar *snoop_type = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - dw = camel_medium_get_content ((CamelMedium *) part); - if (!dw) - return; - - /* This scans the text part for inline-encoded data, creates - * a multipart of all the parts inside it. */ - - /* FIXME: We should discard this multipart if it only contains - * the original text, but it makes this hash lookup more complex */ - - /* TODO: We could probably put this in the superclass, since - * no knowledge of html is required - but this messes with - * filters a bit. Perhaps the superclass should just deal with - * html anyway and be done with it ... */ - - if (!dw->mime_type) - snoop_type = em_format_snoop_type (part); - - /* if we had to snoop the part type to get here, then - * use that as the base type, yuck */ - if (snoop_type == NULL - || (type = camel_content_type_decode (snoop_type)) == NULL) { - type = dw->mime_type; - camel_content_type_ref (type); - } - - if (dw->mime_type && type != dw->mime_type && camel_content_type_param (dw->mime_type, "charset")) { - camel_content_type_set_param (type, "charset", camel_content_type_param (dw->mime_type, "charset")); - charset_added = TRUE; - } - - null = camel_stream_null_new (); - filtered_stream = camel_stream_filter_new (null); - g_object_unref (null); - inline_filter = em_inline_filter_new (camel_mime_part_get_encoding (part), type); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), - CAMEL_MIME_FILTER (inline_filter)); - camel_data_wrapper_decode_to_stream_sync ( - dw, (CamelStream *) filtered_stream, cancellable, NULL); - camel_stream_close ((CamelStream *) filtered_stream, cancellable, NULL); - g_object_unref (filtered_stream); - - mp = em_inline_filter_get_multipart (inline_filter); - - if (charset_added) { - camel_content_type_set_param (type, "charset", NULL); - } - - g_object_unref (inline_filter); - camel_content_type_unref (type); - - /* We handle our made-up multipart here, so we don't recursively call ourselves */ - len = part_id->len; - count = camel_multipart_get_number (mp); - for (i = 0; i < count; i++) { - CamelMimePart *newpart = camel_multipart_get_part (mp, i); - - if (!newpart) - continue; - - type = camel_mime_part_get_content_type (newpart); - if (camel_content_type_is (type, "text", "*") && (!camel_content_type_is (type, "text", "calendar"))) { - gint s_len = part_id->len; - - g_string_append (part_id, ".plain_text"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), newpart, part_id->str); - puri->write_func = efh_write_text_plain; - puri->mime_type = g_strdup ("text/html"); - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - puri->is_attachment = info->is_attachment; - g_string_truncate (part_id, s_len); - em_format_add_puri (emf, puri); - } else { - g_string_append_printf (part_id, ".inline.%d", i); - em_format_parse_part (emf, CAMEL_MIME_PART (newpart), part_id, info, cancellable); - g_string_truncate (part_id, len); - } - } - - g_object_unref (mp); -} - -static void -efh_parse_text_html (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - const gchar *location; - gchar *cid = NULL; - CamelURL *base; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - base = em_format_get_base_url (emf); - location = camel_mime_part_get_content_location (part); - if (location == NULL) { - if (base) - cid = camel_url_to_string (base, 0); - else - cid = g_strdup (part_id->str); - } else { - if (strchr (location, ':') == NULL && base != NULL) { - CamelURL *uri; - - uri = camel_url_new_with_base (base, location); - cid = camel_url_to_string (uri, 0); - camel_url_free (uri); - } else { - cid = g_strdup (location); - } - } - - len = part_id->len; - g_string_append (part_id, ".text_html"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = efh_write_text_html; - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - puri->is_attachment = info->is_attachment; - - em_format_add_puri (emf, puri); - g_string_truncate (part_id, len); - - if (cid) - g_free (cid); -} - -static void -efh_parse_message_external (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - CamelMimePart *newpart; - CamelContentType *type; - const gchar *access_type; - gchar *url = NULL, *desc = NULL; - gchar *content; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - newpart = camel_mime_part_new (); - - /* needs to be cleaner */ - type = camel_mime_part_get_content_type (part); - access_type = camel_content_type_param (type, "access-type"); - if (!access_type) { - const gchar *msg = _("Malformed external-body part"); - camel_mime_part_set_content (newpart, msg, strlen (msg), - "text/plain"); - goto addPart; - } - - if (!g_ascii_strcasecmp(access_type, "ftp") || - !g_ascii_strcasecmp(access_type, "anon-ftp")) { - const gchar *name, *site, *dir, *mode; - gchar *path; - gchar ftype[16]; - - name = camel_content_type_param (type, "name"); - site = camel_content_type_param (type, "site"); - dir = camel_content_type_param (type, "directory"); - mode = camel_content_type_param (type, "mode"); - if (name == NULL || site == NULL) - goto fail; - - /* Generate the path. */ - if (dir) - path = g_strdup_printf("/%s/%s", *dir=='/'?dir+1:dir, name); - else - path = g_strdup_printf("/%s", *name=='/'?name+1:name); - - if (mode && *mode) - sprintf(ftype, ";type=%c", *mode); - else - ftype[0] = 0; - - url = g_strdup_printf ("ftp://%s%s%s", site, path, ftype); - g_free (path); - desc = g_strdup_printf (_("Pointer to FTP site (%s)"), url); - } else if (!g_ascii_strcasecmp (access_type, "local-file")) { - const gchar *name, *site; - - name = camel_content_type_param (type, "name"); - site = camel_content_type_param (type, "site"); - if (name == NULL) - goto fail; - - url = g_filename_to_uri (name, NULL, NULL); - if (site) - desc = g_strdup_printf(_("Pointer to local file (%s) valid at site \"%s\""), name, site); - else - desc = g_strdup_printf(_("Pointer to local file (%s)"), name); - } else if (!g_ascii_strcasecmp (access_type, "URL")) { - const gchar *urlparam; - gchar *s, *d; - - /* RFC 2017 */ - urlparam = camel_content_type_param (type, "url"); - if (urlparam == NULL) - goto fail; - - /* For obscure MIMEy reasons, the URL may be split into words */ - url = g_strdup (urlparam); - s = d = url; - while (*s) { - if (!isspace ((guchar) * s)) - *d++ = *s; - s++; - } - *d = 0; - desc = g_strdup_printf (_("Pointer to remote data (%s)"), url); - } else - goto fail; - - content = g_strdup_printf ("<a href=\"%s\">%s</a>", url, desc); - camel_mime_part_set_content (newpart, content, strlen (content), "text/html"); - g_free (content); - - g_free (url); - g_free (desc); - -fail: - content = g_strdup_printf ( - _("Pointer to unknown external data (\"%s\" type)"), - access_type); - camel_mime_part_set_content (newpart, content, strlen (content), "text/plain"); - g_free (content); - -addPart: - len = part_id->len; - g_string_append (part_id, ".msg_external"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = efh_write_text_html; - puri->mime_type = g_strdup ("text/html"); - - em_format_add_puri (emf, puri); - g_string_truncate (part_id, len); -} - -static void -efh_parse_message_deliverystatus (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - len = part_id->len; - g_string_append (part_id, ".deliverystatus"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = efh_write_source; - puri->mime_type = g_strdup ("text/html"); - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - puri->is_attachment = info->is_attachment; - - em_format_add_puri (emf, puri); - g_string_truncate (part_id, len); -} - -static void -efh_parse_message_rfc822 (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelDataWrapper *dw; - CamelMimePart *opart; - CamelStream *stream; - CamelMimeParser *parser; - gint len; - EMFormatParserInfo oinfo = *info; - EMFormatPURI *puri; - - len = part_id->len; - g_string_append (part_id, ".rfc822"); - - /* Create an empty PURI that will represent start of the RFC message */ - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = efh_write_message_rfc822; - puri->mime_type = g_strdup ("text/html"); - puri->is_attachment = info->is_attachment; - em_format_add_puri (emf, puri); - - /* Now parse the message, creating multiple sub-PURIs */ - stream = camel_stream_mem_new (); - dw = camel_medium_get_content ((CamelMedium *) part); - camel_data_wrapper_write_to_stream_sync (dw, stream, cancellable, NULL); - g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, NULL); - - parser = camel_mime_parser_new (); - camel_mime_parser_init_with_stream (parser, stream, NULL); - - opart = camel_mime_part_new (); - camel_mime_part_construct_from_parser_sync (opart, parser, cancellable, NULL); - - em_format_parse_part_as (emf, opart, part_id, &oinfo, - "x-evolution/message", cancellable); - - /* Add another generic PURI that represents end of the RFC message. - * The em_format_write() function will skip all PURIs between the ".rfc822" - * PURI and ".rfc822.end" PURI as they will be rendered in an <iframe> */ - g_string_append (part_id, ".end"); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), NULL, part_id->str); - em_format_add_puri (emf, puri); - - g_string_truncate (part_id, len); - - g_object_unref (opart); - g_object_unref (parser); - g_object_unref (stream); -} - -/*****************************************************************************/ - -static void -efh_write_image (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *content; - EMFormatHTML *efh; - CamelDataWrapper *dw; - GByteArray *ba; - CamelStream *raw_content; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - efh = (EMFormatHTML *) emf; - - dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part)); - g_return_if_fail (dw); - - raw_content = camel_stream_mem_new (); - camel_data_wrapper_decode_to_stream_sync (dw, raw_content, cancellable, NULL); - ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (raw_content)); - - if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - - if (!efh->priv->animate_images) { - - gchar *buff; - gsize len; - - em_format_html_animation_extract_frame (ba, &buff, &len); - - camel_stream_write (stream, buff, len, cancellable, NULL); - - g_free (buff); - - } else { - - camel_stream_write_to_stream (raw_content, stream, cancellable, NULL); - } - - } else { - - gchar *buffer; - - if (!efh->priv->animate_images) { - - gchar *buff; - gsize len; - - em_format_html_animation_extract_frame (ba, &buff, &len); - - content = g_base64_encode ((guchar *) buff, len); - g_free (buff); - - } else { - content = g_base64_encode ((guchar *) ba->data, ba->len); - } - - /* The image is already base64-encrypted so we can directly - * paste it to the output */ - buffer = g_strdup_printf ( - "<img src=\"data:%s;base64,%s\" style=\"max-width: 100%%;\" />", - puri->mime_type ? puri->mime_type : "image/*", content); - - camel_stream_write_string (stream, buffer, cancellable, NULL); - g_free (buffer); - g_free (content); - } - - g_object_unref (raw_content); -} - -static void -efh_write_text_enriched (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatHTML *efh = EM_FORMAT_HTML (emf); - CamelStream *filtered_stream; - CamelMimeFilter *enriched; - guint32 flags = 0; - GString *buffer; - CamelContentType *ct; - gchar *mime_type = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - ct = camel_mime_part_get_content_type (puri->part); - if (ct) { - mime_type = camel_content_type_simple (ct); - } - - if (!g_strcmp0(mime_type, "text/richtext")) { - flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT; - camel_stream_write_string ( - stream, "\n<!-- text/richtext -->\n", - cancellable, NULL); - } else { - camel_stream_write_string ( - stream, "\n<!-- text/enriched -->\n", - cancellable, NULL); - } - - if (mime_type) - g_free (mime_type); - - enriched = camel_mime_filter_enriched_new (flags); - filtered_stream = camel_stream_filter_new (stream); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), enriched); - g_object_unref (enriched); - - buffer = g_string_new (""); - - g_string_append_printf (buffer, - "<div class=\"part-container\" style=\"border-color: #%06x; " - "background-color: #%06x; color: #%06x;\">" - "<div class=\"part-container-inner-margin\">\n", - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_CONTENT]), - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_TEXT])); - - camel_stream_write_string (stream, buffer->str, cancellable, NULL); - g_string_free (buffer, TRUE); - - em_format_format_text ( - emf, (CamelStream *) filtered_stream, - (CamelDataWrapper *) puri->part, cancellable); - - g_object_unref (filtered_stream); - camel_stream_write_string (stream, "</div></div>", cancellable, NULL); -} - -static void -efh_write_text_plain (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - CamelDataWrapper *dw; - CamelStream *filtered_stream; - CamelMimeFilter *html_filter; - EMFormatHTML *efh = (EMFormatHTML *) emf; - gchar *content; - const gchar *format; - guint32 flags; - guint32 rgb; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - flags = efh->text_html_flags; - - dw = camel_medium_get_content (CAMEL_MEDIUM (puri->part)); - - /* Check for RFC 2646 flowed text. */ - if (camel_content_type_is(dw->mime_type, "text", "plain") - && (format = camel_content_type_param(dw->mime_type, "format")) - && !g_ascii_strcasecmp(format, "flowed")) - flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED; - - rgb = e_color_to_value ( - &efh->priv->colors[EM_FORMAT_HTML_COLOR_CITATION]); - filtered_stream = camel_stream_filter_new (stream); - html_filter = camel_mime_filter_tohtml_new (flags, rgb); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), html_filter); - g_object_unref (html_filter); - - content = g_strdup_printf ( - "<div class=\"part-container\" style=\"border-color: #%06x; " - "background-color: #%06x; color: #%06x;\">" - "<div class=\"part-container-inner-margin pre\">\n", - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_CONTENT]), - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_TEXT])); - - camel_stream_write_string (stream, content, cancellable, NULL); - em_format_format_text (emf, filtered_stream, (CamelDataWrapper *) puri->part, cancellable); - camel_stream_flush (filtered_stream, cancellable, NULL); - - g_object_unref (filtered_stream); - g_free (content); - - camel_stream_write_string (stream, "</div></div>\n", cancellable, NULL); -} - -static gchar * -get_tag (const gchar *tag_name, - gchar *opening, - gchar *closing) -{ - gchar *t; - gboolean has_end; - - for (t = closing - 1; t != opening; t--) { - if (*t != ' ') - break; - } - - /* Not a pair tag */ - if (*t == '/') - return g_strndup (opening, closing - opening + 1); - - for (t = closing; t && *t; t++) { - if (*t == '<') - break; - } - - do { - if (*t == '/') { - has_end = TRUE; - break; - } - - if (*t == '>') { - has_end = FALSE; - break; - } - - t++; - - } while (t && *t); - - /* Broken HTML? */ - if (!has_end) - return g_strndup (opening, closing - opening + 1); - - do { - if ((*t != ' ') && (*t != '/')) - break; - - t++; - } while (t && *t); - - if (g_strncasecmp (t, tag_name, strlen (tag_name)) == 0) { - - closing = strstr (t, ">"); - - return g_strndup (opening, closing - opening + strlen (tag_name)); - } - - /* Broken HTML? */ - return g_strndup (opening, closing - opening + 1); -} - -static void -efh_write_text_html (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatHTML *efh = (EMFormatHTML *) emf; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - em_format_format_text (emf, stream, - (CamelDataWrapper *) puri->part, cancellable); - - } else if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) { - GString *string; - GByteArray *ba; - gchar *pos; - GList *tags, *iter; - gboolean valid; - gchar *tag; - const gchar *document_end; - gint length; - gint i; - CamelStream *decoded_stream; - - decoded_stream = camel_stream_mem_new (); - em_format_format_text (emf, decoded_stream, - (CamelDataWrapper *) puri->part, cancellable); - g_seekable_seek (G_SEEKABLE (decoded_stream), 0, G_SEEK_SET, cancellable, NULL); - - ba = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (decoded_stream)); - string = g_string_new_len ((gchar *) ba->data, ba->len); - - g_object_unref (decoded_stream); - - tags = NULL; - pos = string->str; - valid = FALSE; - do { - gchar *closing; - gchar *opening; - - pos = strstr (pos + 1, "<"); - if (!pos) - break; - - opening = pos; - closing = strstr (pos, ">"); - - /* Find where the actual tag name begins */ - for (tag = pos + 1; tag && *tag; tag++) { - if (*tag != ' ') - break; - } - - if (g_ascii_strncasecmp (tag, "style", 5) == 0) { - tags = g_list_append ( - tags, - get_tag ("style", opening, closing)); - } else if (g_ascii_strncasecmp (tag, "script", 6) == 0) { - tags = g_list_append ( - tags, - get_tag ("script", opening, closing)); - } else if (g_ascii_strncasecmp (tag, "link", 4) == 0) { - tags = g_list_append ( - tags, - get_tag ("link", opening, closing)); - } else if (g_ascii_strncasecmp (tag, "body", 4) == 0) { - valid = TRUE; - break; - } - - } while (TRUE); - - /* Something's wrong, let's write the entire HTML and hope - * that WebKit can handle it */ - if (!valid) { - EMFormatWriterInfo i = *info; - i.mode = EM_FORMAT_WRITE_MODE_RAW; - efh_write_text_html (emf, puri, stream, &i, cancellable); - return; - } - - /* include the "body" as well -----v */ - g_string_erase (string, 0, tag - string->str + 4); - g_string_prepend (string, "<div "); - - for (iter = tags; iter; iter = iter->next) { - g_string_prepend (string, iter->data); - } - - g_list_free_full (tags, g_free); - - /* that's reversed </body></html>... */ - document_end = ">lmth/<>ydob/<"; - length = strlen (document_end); - tag = string->str + string->len - 1; - i = 0; - valid = FALSE; - while (i < length - 1) { - gchar c; - - if (g_ascii_isspace (*tag)) { - tag--; - continue; - } - - if ((*tag >= 'A') && (*tag <= 'Z')) - c = *tag + 32; - else - c = *tag; - - if (c == document_end[i]) { - tag--; - i++; - valid = TRUE; - continue; - } - - valid = FALSE; - } - - if (valid) - g_string_truncate (string, tag - string->str); - - camel_stream_write_string (stream, string->str, cancellable, NULL); - - g_string_free (string, TRUE); - } else { - gchar *str; - gchar *uri; - - uri = em_format_build_mail_uri ( - emf->folder, emf->message_uid, - "part_id", G_TYPE_STRING, puri->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, - NULL); - - str = g_strdup_printf ( - "<div class=\"part-container-nostyle\">" - "<iframe width=\"100%%\" height=\"auto\"" - " frameborder=\"0\" src=\"%s\" " - " style=\"border: 1px solid #%06x; background-color: #%06x;\">" - "</iframe>" - "</div>", - uri, - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT])); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - g_free (uri); - } -} - -static void -efh_write_source (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatHTML *efh = (EMFormatHTML *) emf; - GString *buffer; - CamelStream *filtered_stream; - CamelMimeFilter *filter; - CamelDataWrapper *dw = (CamelDataWrapper *) puri->part; - - filtered_stream = camel_stream_filter_new (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 ( - CAMEL_STREAM_FILTER (filtered_stream), filter); - g_object_unref (filter); - - buffer = g_string_new (""); - - g_string_append_printf ( - buffer, "<div class=\"part-container\" style=\"border: 0; background: #%06x; color: #%06x;\" >", - e_color_to_value ( - &efh->priv->colors[ - EM_FORMAT_HTML_COLOR_BODY]), - e_color_to_value ( - &efh->priv->colors[ - EM_FORMAT_HTML_COLOR_TEXT])); - - camel_stream_write_string ( - stream, buffer->str, cancellable, NULL); - camel_stream_write_string ( - stream, "<code class=\"pre\">", cancellable, NULL); - camel_data_wrapper_write_to_stream_sync (dw, filtered_stream, - cancellable, NULL); - camel_stream_write_string ( - stream, "</code>", cancellable, NULL); - - g_object_unref (filtered_stream); - g_string_free (buffer, TRUE); -} - -static void -efh_write_headers (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GString *buffer; - EMFormatHTML *efh = (EMFormatHTML *) emf; - gint bg_color; - - if (!puri->part) - return; - - buffer = g_string_new (""); - - if (info->mode & EM_FORMAT_WRITE_MODE_PRINTING) { - GdkColor white = { 0, G_MAXUINT16, G_MAXUINT16, G_MAXUINT16 }; - bg_color = e_color_to_value (&white); - } else { - bg_color = e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY]); - } - - g_string_append_printf ( - buffer, - "<div class=\"headers\" style=\"background: #%06x;\">" - "<table border=\"0\" width=\"100%%\" style=\"color: #%06x;\">\n" - "<tr><td valign=\"top\" width=\"16\">\n", - bg_color, - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER])); - - if (info->headers_collapsable) { - g_string_append_printf (buffer, - "<img src=\"evo-file://%s/%s\" class=\"navigable\" " - "id=\"__evo-collapse-headers-img\" />" - "</td><td>", - EVOLUTION_IMAGESDIR, - (info->headers_collapsed) ? "plus.png" : "minus.png"); - - efh_format_short_headers (efh, buffer, (CamelMedium *) puri->part, - info->headers_collapsed, - cancellable); - } - - efh_format_full_headers (efh, buffer, (CamelMedium *) puri->part, - (info->mode == EM_FORMAT_WRITE_MODE_ALL_HEADERS), - !info->headers_collapsed, - cancellable); - - g_string_append (buffer, "</td></tr></table></div>"); - - camel_stream_write_string (stream, buffer->str, cancellable, NULL); - - g_string_free (buffer, true); -} - -static void -efh_write_error (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - CamelStream *filtered_stream; - CamelMimeFilter *filter; - CamelDataWrapper *dw; - - dw = camel_medium_get_content ((CamelMedium *) puri->part); - - camel_stream_write_string (stream, "<em><font color=\"red\">", cancellable, NULL); - - filtered_stream = camel_stream_filter_new (stream); - filter = camel_mime_filter_tohtml_new (CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered_stream), filter); - g_object_unref (filter); - - camel_data_wrapper_decode_to_stream_sync (dw, filtered_stream, cancellable, NULL); - - g_object_unref (filtered_stream); - - camel_stream_write_string (stream, "</font></em><br>", cancellable, NULL); -} - -static void -efh_write_message_rfc822 (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - - GList *puris; - GList *iter; - EMFormatWriterInfo msgInfo = *info; - msgInfo.mode = EM_FORMAT_WRITE_MODE_NORMAL; - - /* Create a new fake list of PURIs which will contain only - * PURIs from this message. */ - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - iter = iter->next; - puris = NULL; - while (iter) { - - EMFormatPURI *p; - p = iter->data; - - if (g_str_has_suffix (p->uri, ".rfc822.end")) - break; - - puris = g_list_append (puris, p); - iter = iter->next; - - }; - - efh_write_message (emf, puris, stream, &msgInfo, cancellable); - - g_list_free (puris); - - } else if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) { - - GList *iter; - gboolean can_write = FALSE; - - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - /* Skip everything before attachment bar, inclusive */\ - iter = iter->next; - while (iter) { - - EMFormatPURI *p = iter->data; - - /* EMFormatHTMLPrint has registered a special writer - * for headers, try to find it and use it. */ - if (g_str_has_suffix (p->uri, ".headers")) { - - const EMFormatHandler *handler; - - handler = em_format_find_handler ( - emf, "x-evolution/message/headers"); - if (handler && handler->write_func) - handler->write_func (emf, p, stream, info, cancellable); - - iter = iter->next; - continue; - } - - if (g_str_has_suffix (p->uri, ".rfc822.end")) - break; - - if (g_str_has_suffix (p->uri, ".attachment-bar")) - can_write = TRUE; - - if (can_write && p->write_func) { - p->write_func ( - emf, p, stream, info, cancellable); - } - - iter = iter->next; - } - - } else { - gchar *str; - gchar *uri; - - EMFormatHTML *efh = (EMFormatHTML *) emf; - EMFormatPURI *p; - GList *iter; - - iter = g_hash_table_lookup (emf->mail_part_table, puri->uri); - if (!iter || !iter->next) - return; - - iter = iter->next; - p = iter->data; - - uri = em_format_build_mail_uri (emf->folder, emf->message_uid, - "part_id", G_TYPE_STRING, p->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, - NULL); - - str = g_strdup_printf ( - "<div class=\"part-container\" style=\"border-color: #%06x; " - "background-color: #%06x;\">" - "<div class=\"part-container-inner-margin\">\n" - "<iframe width=\"100%%\" height=\"auto\"" - " frameborder=\"0\" src=\"%s\" name=\"%s\"></iframe>" - "</div></div>", - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]), - e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]), - uri, puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - g_free (uri); - } - -} - -/*****************************************************************************/ - -/* Notes: - * - * image/tiff is omitted because it's a multi-page image format, but - * gdk-pixbuf unconditionally renders the first page only, and doesn't - * even indicate through meta-data whether multiple pages are present - * (see bug 335959). Therefore, make no attempt to render TIFF images - * inline and defer to an application that can handle multi-page TIFF - * files properly like Evince or Gimp. Once the referenced bug is - * fixed we can reevaluate this policy. - */ -static EMFormatHandler type_builtin_table[] = { - { (gchar *) "image/gif", efh_parse_image, efh_write_image, }, - { (gchar *) "image/jpeg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/png", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-png", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-bmp", efh_parse_image, efh_write_image, }, - { (gchar *) "image/bmp", efh_parse_image, efh_write_image, }, - { (gchar *) "image/svg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-cmu-raster", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-ico", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-anymap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-bitmap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-graymap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-portable-pixmap", efh_parse_image, efh_write_image, }, - { (gchar *) "image/x-xpixmap", efh_parse_image, efh_write_image, }, - { (gchar *) "text/enriched", efh_parse_text_enriched, efh_write_text_enriched, }, - { (gchar *) "text/plain", efh_parse_text_plain, efh_write_text_plain, }, - { (gchar *) "text/html", efh_parse_text_html, efh_write_text_html, }, - { (gchar *) "text/richtext", efh_parse_text_enriched, efh_write_text_enriched, }, - { (gchar *) "text/*", efh_parse_text_plain, efh_write_text_plain, }, - { (gchar *) "message/rfc822", efh_parse_message_rfc822, efh_write_message_rfc822, EM_FORMAT_HANDLER_INLINE | EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "message/news", efh_parse_message_rfc822, 0, EM_FORMAT_HANDLER_INLINE | EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "message/delivery-status", efh_parse_message_deliverystatus, efh_write_text_plain, }, - { (gchar *) "message/external-body", efh_parse_message_external, efh_write_text_plain, }, - { (gchar *) "message/*", efh_parse_message_rfc822, 0, EM_FORMAT_HANDLER_INLINE }, - - /* 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. */ - { (gchar *) "image/jpg", efh_parse_image, efh_write_image, }, - { (gchar *) "image/pjpeg", efh_parse_image, efh_write_image, }, - - /* special internal types */ - { (gchar *) "x-evolution/message/rfc822", 0, efh_write_text_plain, }, - { (gchar *) "x-evolution/message/headers", 0, efh_write_headers, }, - { (gchar *) "x-evolution/message/source", 0, efh_write_source, }, - { (gchar *) "x-evolution/message/attachment", 0, efh_write_attachment, }, - { (gchar *) "x-evolution/message/error", 0, efh_write_error, }, -}; - -static void -efh_builtin_init (EMFormatHTMLClass *efhc) -{ - EMFormatClass *emfc; - gint ii; - - emfc = (EMFormatClass *) efhc; - - for (ii = 0; ii < G_N_ELEMENTS (type_builtin_table); ii++) - em_format_class_add_handler ( - emfc, &type_builtin_table[ii]); -} - -static void -efh_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_BODY_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_BODY, - g_value_get_boxed (value)); - return; - - case PROP_CITATION_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CITATION, - g_value_get_boxed (value)); - return; - - case PROP_CONTENT_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CONTENT, - g_value_get_boxed (value)); - return; - - case PROP_FRAME_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_FRAME, - g_value_get_boxed (value)); - return; - - case PROP_HEADER_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_HEADER, - g_value_get_boxed (value)); - return; - - case PROP_IMAGE_LOADING_POLICY: - em_format_html_set_image_loading_policy ( - EM_FORMAT_HTML (object), - g_value_get_enum (value)); - return; - - case PROP_MARK_CITATIONS: - em_format_html_set_mark_citations ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_ONLY_LOCAL_PHOTOS: - em_format_html_set_only_local_photos ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_SHOW_SENDER_PHOTO: - em_format_html_set_show_sender_photo ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_SHOW_REAL_DATE: - em_format_html_set_show_real_date ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - - case PROP_TEXT_COLOR: - em_format_html_set_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_TEXT, - g_value_get_boxed (value)); - return; - - case PROP_ANIMATE_IMAGES: - em_format_html_set_animate_images ( - EM_FORMAT_HTML (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -efh_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GdkColor color; - - switch (property_id) { - case PROP_BODY_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_BODY, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_CITATION_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CITATION, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_CONTENT_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_CONTENT, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_FRAME_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_FRAME, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_HEADER_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_HEADER, - &color); - g_value_set_boxed (value, &color); - return; - - case PROP_IMAGE_LOADING_POLICY: - g_value_set_enum ( - value, - em_format_html_get_image_loading_policy ( - EM_FORMAT_HTML (object))); - return; - - case PROP_MARK_CITATIONS: - g_value_set_boolean ( - value, em_format_html_get_mark_citations ( - EM_FORMAT_HTML (object))); - return; - - case PROP_ONLY_LOCAL_PHOTOS: - g_value_set_boolean ( - value, em_format_html_get_only_local_photos ( - EM_FORMAT_HTML (object))); - return; - - case PROP_SHOW_SENDER_PHOTO: - g_value_set_boolean ( - value, em_format_html_get_show_sender_photo ( - EM_FORMAT_HTML (object))); - return; - - case PROP_SHOW_REAL_DATE: - g_value_set_boolean ( - value, em_format_html_get_show_real_date ( - EM_FORMAT_HTML (object))); - return; - - case PROP_TEXT_COLOR: - em_format_html_get_color ( - EM_FORMAT_HTML (object), - EM_FORMAT_HTML_COLOR_TEXT, - &color); - g_value_set_boxed (value, &color); - return; - case PROP_ANIMATE_IMAGES: - g_value_set_boolean ( - value, em_format_html_get_animate_images ( - EM_FORMAT_HTML (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -efh_finalize (GObject *object) -{ - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -efh_constructed (GObject *object) -{ - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (parent_class)->constructed (object); - - e_extensible_load_extensions (E_EXTENSIBLE (object)); -} - -static void -efh_write_attachment (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *text, *html; - CamelContentType *ct; - gchar *mime_type; - const EMFormatHandler *handler; - - /* we display all inlined attachments only */ - - /* this could probably be cleaned up ... */ - camel_stream_write_string ( - stream, - "<table border=1 cellspacing=0 cellpadding=0><tr><td>" - "<table width=10 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td>" - "<td><table width=3 cellspacing=0 cellpadding=0>" - "<tr><td></td></tr></table></td><td><font size=-1>\n", - cancellable, NULL); - - ct = camel_mime_part_get_content_type (puri->part); - mime_type = camel_content_type_simple (ct); - - /* output some info about it */ - text = em_format_describe_part (puri->part, mime_type); - html = camel_text_to_html ( - text, ((EMFormatHTML *) emf)->text_html_flags & - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_write_string (stream, html, cancellable, NULL); - g_free (html); - g_free (text); - - camel_stream_write_string ( - stream, "</font></td></tr><tr></table>", cancellable, NULL); - - handler = em_format_find_handler (emf, mime_type); - if (handler && handler->write_func && handler->write_func != efh_write_attachment) { - if (em_format_is_inline (emf, puri->uri, puri->part, handler)) - handler->write_func (emf, puri, stream, info, cancellable); - } - - g_free (mime_type); -} - -static void -efh_preparse (EMFormat *emf) -{ - EMFormatHTML *efh = EM_FORMAT_HTML (emf); - CamelInternetAddress *addr; - CamelSession *session; - ESourceRegistry *registry; - - if (!emf->message) { - efh->priv->can_load_images = FALSE; - return; - } - - session = em_format_get_session (emf); - registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); - - addr = camel_mime_message_get_from (emf->message); - efh->priv->can_load_images = em_utils_in_addressbook ( - registry, addr, FALSE); -} - -static void -efh_write_message (EMFormat *emf, - GList *puris, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GList *iter; - EMFormatHTML *efh; - gchar *header; - - efh = (EMFormatHTML *) emf; - - header = g_strdup_printf ( - "<!DOCTYPE HTML>\n<html>\n" - "<head>\n<meta name=\"generator\" content=\"Evolution Mail Component\" />\n" - "<title>Evolution Mail Display</title>\n" - "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n" - "<style type=\"text/css\">\n" - " table th { color: #000; font-weight: bold; }\n" - "</style>\n" - "</head><body bgcolor=\"#%06x\">", - e_color_to_value (&efh->priv->colors[ - EM_FORMAT_HTML_COLOR_BODY])); - - camel_stream_write_string (stream, header, cancellable, NULL); - g_free (header); - - if (info->mode == EM_FORMAT_WRITE_MODE_SOURCE) { - - efh_write_source (emf, emf->mail_part_list->data, - stream, info, cancellable); - - camel_stream_write_string (stream, "</body></html>", cancellable, NULL); - return; - } - - for (iter = puris; iter; iter = iter->next) { - - EMFormatPURI *puri = iter->data; - - if (!puri) - continue; - - /* If current PURI has suffix .rfc822 then iterate through all - * subsequent PURIs until PURI with suffix .rfc822.end is found. - * These skipped PURIs contain entire RFC message which will - * be written in <iframe> as attachment. - */ - if (g_str_has_suffix (puri->uri, ".rfc822")) { - - /* If the PURI is not an attachment, then we must - * inline it here otherwise it would not be displayed. */ - if (!puri->is_attachment && puri->write_func) { - /* efh_write_message_rfc822 starts parsing _after_ - * the passed PURI, so we must give it previous PURI here */ - EMFormatPURI *p; - if (!iter->prev) - continue; - - p = iter->prev->data; - puri->write_func (emf, p, stream, info, cancellable); - } - - while (iter && !g_str_has_suffix (puri->uri, ".rfc822.end")) { - - iter = iter->next; - if (iter) - puri = iter->data; - - d(printf(".rfc822 - skipping %s\n", puri->uri)); - } - - /* Skip the .rfc822.end PURI as well. */ - if (!iter) - break; - - continue; - } - - if (puri->write_func && !puri->is_attachment) { - puri->write_func (emf, puri, stream, info, cancellable); - d(printf("Writing PURI %s\n", puri->uri)); - } else { - d(printf("Skipping PURI %s\n", puri->uri)); - } - } - - camel_stream_write_string (stream, "</body></html>", cancellable, NULL); -} - -static void -efh_write (EMFormat *emf, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - efh_write_message (emf, emf->mail_part_list, stream, info, cancellable); -} - -static void -efh_base_init (EMFormatHTMLClass *klass) -{ - efh_builtin_init (klass); -} - -static void -efh_class_init (EMFormatHTMLClass *klass) -{ - GObjectClass *object_class; - EMFormatClass *emf_class; - - parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (EMFormatHTMLPrivate)); - - emf_class = EM_FORMAT_CLASS (klass); - emf_class->preparse = efh_preparse; - emf_class->write = efh_write; - - object_class = G_OBJECT_CLASS (klass); - object_class->constructed = efh_constructed; - object_class->set_property = efh_set_property; - object_class->get_property = efh_get_property; - object_class->finalize = efh_finalize; - - g_object_class_install_property ( - object_class, - PROP_BODY_COLOR, - g_param_spec_boxed ( - "body-color", - "Body Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CITATION_COLOR, - g_param_spec_boxed ( - "citation-color", - "Citation Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CONTENT_COLOR, - g_param_spec_boxed ( - "content-color", - "Content Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_FRAME_COLOR, - g_param_spec_boxed ( - "frame-color", - "Frame Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_HEADER_COLOR, - g_param_spec_boxed ( - "header-color", - "Header Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - /* FIXME Make this a proper enum property. */ - g_object_class_install_property ( - object_class, - PROP_IMAGE_LOADING_POLICY, - g_param_spec_enum ( - "image-loading-policy", - "Image Loading Policy", - NULL, - E_TYPE_MAIL_IMAGE_LOADING_POLICY, - E_MAIL_IMAGE_LOADING_POLICY_ALWAYS, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_MARK_CITATIONS, - g_param_spec_boolean ( - "mark-citations", - "Mark Citations", - NULL, - TRUE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_ONLY_LOCAL_PHOTOS, - g_param_spec_boolean ( - "only-local-photos", - "Only Local Photos", - NULL, - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_SHOW_SENDER_PHOTO, - g_param_spec_boolean ( - "show-sender-photo", - "Show Sender Photo", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_SHOW_REAL_DATE, - g_param_spec_boolean ( - "show-real-date", - "Show real Date header value", - NULL, - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_TEXT_COLOR, - g_param_spec_boxed ( - "text-color", - "Text Color", - NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_ANIMATE_IMAGES, - g_param_spec_boolean ( - "animate-images", - "Animate images", - NULL, - FALSE, - G_PARAM_READWRITE)); -} - -static void -efh_init (EMFormatHTML *efh, - EMFormatHTMLClass *klass) -{ - GdkColor *color; - - efh->priv = EM_FORMAT_HTML_GET_PRIVATE (efh); - - g_queue_init (&efh->pending_object_list); - - color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_BODY]; - gdk_color_parse ("#eeeeee", color); - - color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]; - gdk_color_parse ("#ffffff", color); - - color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]; - gdk_color_parse ("#3f3f3f", color); - - color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_HEADER]; - gdk_color_parse ("#eeeeee", color); - - color = &efh->priv->colors[EM_FORMAT_HTML_COLOR_TEXT]; - gdk_color_parse ("#000000", color); - - efh->text_html_flags = - CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | - CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES | - CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; - efh->show_icon = TRUE; -} - -GType -em_format_html_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EMFormatHTMLClass), - (GBaseInitFunc) efh_base_init, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) efh_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EMFormatHTML), - 0, /* n_preallocs */ - (GInstanceInitFunc) efh_init, - NULL /* value_table */ - }; - - static const GInterfaceInfo extensible_info = { - (GInterfaceInitFunc) NULL, - (GInterfaceFinalizeFunc) NULL, - NULL /* interface_data */ - }; - - type = g_type_register_static ( - em_format_get_type(), "EMFormatHTML", - &type_info, G_TYPE_FLAG_ABSTRACT); - - g_type_add_interface_static ( - type, E_TYPE_EXTENSIBLE, &extensible_info); - } - - return type; -} - -/*****************************************************************************/ -void -em_format_html_get_color (EMFormatHTML *efh, - EMFormatHTMLColorType type, - GdkColor *color) -{ - GdkColor *format_color; - - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES); - g_return_if_fail (color != NULL); - - format_color = &efh->priv->colors[type]; - - color->red = format_color->red; - color->green = format_color->green; - color->blue = format_color->blue; -} - -void -em_format_html_set_color (EMFormatHTML *efh, - EMFormatHTMLColorType type, - const GdkColor *color) -{ - GdkColor *format_color; - const gchar *property_name; - - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES); - g_return_if_fail (color != NULL); - - format_color = &efh->priv->colors[type]; - - if (gdk_color_equal (color, format_color)) - return; - - format_color->red = color->red; - format_color->green = color->green; - format_color->blue = color->blue; - - switch (type) { - case EM_FORMAT_HTML_COLOR_BODY: - property_name = "body-color"; - break; - case EM_FORMAT_HTML_COLOR_CITATION: - property_name = "citation-color"; - break; - case EM_FORMAT_HTML_COLOR_CONTENT: - property_name = "content-color"; - break; - case EM_FORMAT_HTML_COLOR_FRAME: - property_name = "frame-color"; - break; - case EM_FORMAT_HTML_COLOR_HEADER: - property_name = "header-color"; - break; - case EM_FORMAT_HTML_COLOR_TEXT: - property_name = "text-color"; - break; - default: - g_return_if_reached (); - } - - g_object_notify (G_OBJECT (efh), property_name); -} - -EMailImageLoadingPolicy -em_format_html_get_image_loading_policy (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0); - - return efh->priv->image_loading_policy; -} - -void -em_format_html_set_image_loading_policy (EMFormatHTML *efh, - EMailImageLoadingPolicy policy) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - if (policy == efh->priv->image_loading_policy) - return; - - efh->priv->image_loading_policy = policy; - - g_object_notify (G_OBJECT (efh), "image-loading-policy"); -} - -gboolean -em_format_html_get_mark_citations (EMFormatHTML *efh) -{ - guint32 flags; - - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - flags = efh->text_html_flags; - - return ((flags & CAMEL_MIME_FILTER_TOHTML_MARK_CITATION) != 0); -} - -void -em_format_html_set_mark_citations (EMFormatHTML *efh, - gboolean mark_citations) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - if (mark_citations) - efh->text_html_flags |= - CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; - else - efh->text_html_flags &= - ~CAMEL_MIME_FILTER_TOHTML_MARK_CITATION; - - g_object_notify (G_OBJECT (efh), "mark-citations"); -} - -gboolean -em_format_html_get_only_local_photos (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - return efh->priv->only_local_photos; -} - -void -em_format_html_set_only_local_photos (EMFormatHTML *efh, - gboolean only_local_photos) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - efh->priv->only_local_photos = only_local_photos; - - g_object_notify (G_OBJECT (efh), "only-local-photos"); -} - -gboolean -em_format_html_get_show_sender_photo (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - return efh->priv->show_sender_photo; -} - -void -em_format_html_set_show_sender_photo (EMFormatHTML *efh, - gboolean show_sender_photo) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - efh->priv->show_sender_photo = show_sender_photo; - - g_object_notify (G_OBJECT (efh), "show-sender-photo"); -} - -gboolean -em_format_html_get_show_real_date (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - return efh->priv->show_real_date; -} - -void -em_format_html_set_show_real_date (EMFormatHTML *efh, - gboolean show_real_date) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - efh->priv->show_real_date = show_real_date; - - g_object_notify (G_OBJECT (efh), "show-real-date"); -} - -gboolean -em_format_html_get_animate_images (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - return efh->priv->animate_images; -} - -void -em_format_html_set_animate_images (EMFormatHTML *efh, - gboolean animate_images) -{ - g_return_if_fail (EM_IS_FORMAT_HTML (efh)); - - efh->priv->animate_images = animate_images; - - g_object_notify (G_OBJECT (efh), "animate-images"); -} - -CamelMimePart * -em_format_html_file_part (EMFormatHTML *efh, - const gchar *mime_type, - const gchar *filename, - GCancellable *cancellable) -{ - CamelMimePart *part; - CamelStream *stream; - CamelDataWrapper *dw; - gchar *basename; - - stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL); - if (stream == NULL) - return NULL; - - dw = camel_data_wrapper_new (); - camel_data_wrapper_construct_from_stream_sync ( - dw, stream, cancellable, NULL); - g_object_unref (stream); - if (mime_type) - camel_data_wrapper_set_mime_type (dw, mime_type); - part = camel_mime_part_new (); - camel_medium_set_content ((CamelMedium *) part, dw); - g_object_unref (dw); - basename = g_path_get_basename (filename); - camel_mime_part_set_filename (part, basename); - g_free (basename); - - return part; -} - -void -em_format_html_format_cert_infos (GQueue *cert_infos, - GString *output_buffer) -{ - GQueue valid = G_QUEUE_INIT; - GList *head, *link; - - g_return_if_fail (cert_infos != NULL); - g_return_if_fail (output_buffer != NULL); - - head = g_queue_peek_head_link (cert_infos); - - /* Make sure we have a valid CamelCipherCertInfo before - * appending anything to the output buffer, so we don't - * end up with "()". */ - for (link = head; link != NULL; link = g_list_next (link)) { - CamelCipherCertInfo *cinfo = link->data; - - if ((cinfo->name != NULL && *cinfo->name != '\0') || - (cinfo->email != NULL && *cinfo->email != '\0')) { - g_queue_push_tail (&valid, cinfo); - } - } - - if (g_queue_is_empty (&valid)) - return; - - g_string_append (output_buffer, " ("); - - while (!g_queue_is_empty (&valid)) { - CamelCipherCertInfo *cinfo; - - cinfo = g_queue_pop_head (&valid); - - if (cinfo->name != NULL && *cinfo->name != '\0') { - g_string_append (output_buffer, cinfo->name); - - if (cinfo->email != NULL && *cinfo->email != '\0') { - g_string_append (output_buffer, " <"); - g_string_append (output_buffer, cinfo->email); - g_string_append (output_buffer, ">"); - } - - } else if (cinfo->email != NULL && *cinfo->email != '\0') { - g_string_append (output_buffer, cinfo->email); - } - - if (!g_queue_is_empty (&valid)) - g_string_append (output_buffer, ", "); - } - - g_string_append_c (output_buffer, ')'); -} - -static void -efh_format_text_header (EMFormatHTML *emfh, - GString *buffer, - const gchar *label, - const gchar *value, - guint32 flags) -{ - const gchar *fmt, *html; - gchar *mhtml = NULL; - gboolean is_rtl; - - if (value == NULL) - return; - - while (*value == ' ') - value++; - - if (!(flags & EM_FORMAT_HTML_HEADER_HTML)) - html = mhtml = camel_text_to_html (value, emfh->text_html_flags, 0); - else - html = value; - - is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL; - - if (flags & EM_FORMAT_HTML_HEADER_NOCOLUMNS) { - if (flags & EM_FORMAT_HEADER_BOLD) { - fmt = "<tr class=\"header-item\" style=\"display: %s\"><td><b>%s:</b> %s</td></tr>"; - } else { - fmt = "<tr class=\"header-item\" style=\"display: %s\"><td>%s: %s</td></tr>"; - } - } else if (flags & EM_FORMAT_HTML_HEADER_NODEC) { - if (is_rtl) - fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th valign=top align=\"left\" nowrap>%1$s<b> </b></th></tr>"; - else - fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s<b> </b></th><td valign=top>%s</td></tr>"; - } else { - if (flags & EM_FORMAT_HEADER_BOLD) { - if (is_rtl) - fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%%\">%2$s</td><th align=\"left\" nowrap>%1$s:<b> </b></th></tr>"; - else - fmt = "<tr class=\"header-item\" style=\"display: %s\"><th align=\"right\" valign=\"top\" nowrap>%s:<b> </b></th><td>%s</td></tr>"; - } else { - if (is_rtl) - fmt = "<tr class=\"header-item rtl\" style=\"display: %s\"><td align=\"right\" valign=\"top\" width=\"100%\">%2$s</td><td align=\"left\" nowrap>%1$s:<b> </b></td></tr>"; - else - fmt = "<tr class=\"header-item\" style=\"display: %s\"><td align=\"right\" valign=\"top\" nowrap>%s:<b> </b></td><td>%s</td></tr>"; - } - } - - g_string_append_printf (buffer, fmt, - (flags & EM_FORMAT_HTML_HEADER_HIDDEN ? "none" : "table-row"), label, html); - - g_free (mhtml); -} - -static const gchar *addrspec_hdrs[] = { - "Sender", "From", "Reply-To", "To", "Cc", "Bcc", - "Resent-Sender", "Resent-From", "Resent-Reply-To", - "Resent-To", "Resent-Cc", "Resent-Bcc", NULL -}; - -static gchar * -efh_format_address (EMFormatHTML *efh, - GString *out, - struct _camel_header_address *a, - gchar *field, - gboolean no_links) -{ - guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; - gchar *name, *mailto, *addr; - gint i = 0; - gchar *str = NULL; - gint limit = mail_config_get_address_count (); - - while (a) { - if (a->name) - name = camel_text_to_html (a->name, flags, 0); - else - name = NULL; - - switch (a->type) { - case CAMEL_HEADER_ADDRESS_NAME: - if (name && *name) { - gchar *real, *mailaddr; - - if (strchr (a->name, ',') || strchr (a->name, ';')) - g_string_append_printf (out, ""%s"", name); - else - g_string_append (out, name); - - g_string_append (out, " <"); - - /* rfc2368 for mailto syntax and url encoding extras */ - if ((real = camel_header_encode_phrase ((guchar *) a->name))) { - mailaddr = g_strdup_printf("%s <%s>", real, a->v.addr); - g_free (real); - mailto = camel_url_encode (mailaddr, "?=&()"); - g_free (mailaddr); - } else { - mailto = camel_url_encode (a->v.addr, "?=&()"); - } - } else { - mailto = camel_url_encode (a->v.addr, "?=&()"); - } - addr = camel_text_to_html (a->v.addr, flags, 0); - if (no_links) - g_string_append_printf (out, "%s", addr); - else - g_string_append_printf (out, "<a href=\"mailto:%s\">%s</a>", mailto, addr); - g_free (mailto); - g_free (addr); - - if (name && *name) - g_string_append (out, ">"); - break; - case CAMEL_HEADER_ADDRESS_GROUP: - g_string_append_printf (out, "%s: ", name); - efh_format_address (efh, out, a->v.members, field, no_links); - g_string_append_printf (out, ";"); - break; - default: - g_warning ("Invalid address type"); - break; - } - - g_free (name); - - i++; - a = a->next; - if (a) - g_string_append (out, ", "); - - /* Let us add a '...' if we have more addresses */ - if (limit > 0 && (i == limit - 1)) { - const gchar *id = NULL; - - if (strcmp (field, _("To")) == 0) { - id = "to"; - } else if (strcmp (field, _("Cc")) == 0) { - id = "cc"; - } else if (strcmp (field, _("Bcc")) == 0) { - id = "bcc"; - } - - if (id) { - g_string_append_printf (out, - "<span id=\"__evo-moreaddr-%s\" " - "style=\"display: none;\">", id); - str = g_strdup_printf ( - "<img src=\"evo-file://%s/plus.png\" " - "id=\"__evo-moreaddr-img-%s\" class=\"navigable\">", - EVOLUTION_IMAGESDIR, id); - } - } - } - - if (str) { - const gchar *id = NULL; - - if (strcmp (field, _("To")) == 0) { - id = "to"; - } else if (strcmp (field, _("Cc")) == 0) { - id = "cc"; - } else if (strcmp (field, _("Bcc")) == 0) { - id = "bcc"; - } - - if (id) { - g_string_append_printf (out, - "</span>" - "<span class=\"navigable\" " - "id=\"__evo-moreaddr-ellipsis-%s\" " - "style=\"display: inline;\">...</span>", - id); - } - } - - return str; -} - -static void -canon_header_name (gchar *name) -{ - gchar *inptr = name; - - /* canonicalise the header name... first letter is - * capitalised and any letter following a '-' also gets - * capitalised */ - - if (*inptr >= 'a' && *inptr <= 'z') - *inptr -= 0x20; - - inptr++; - - while (*inptr) { - if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z') - *inptr -= 0x20; - else if (*inptr >= 'A' && *inptr <= 'Z') - *inptr += 0x20; - - inptr++; - } -} - -void -em_format_html_format_header (EMFormat *emf, - GString *buffer, - CamelMedium *part, - struct _camel_header_raw *header, - guint32 flags, - const gchar *charset) -{ - EMFormatHTML *efh = EM_FORMAT_HTML (emf); - gchar *name, *buf, *value = NULL; - const gchar *label, *txt; - gboolean addrspec = FALSE; - gchar *str_field = NULL; - gint i; - - name = g_alloca (strlen (header->name) + 1); - strcpy (name, header->name); - canon_header_name (name); - - for (i = 0; addrspec_hdrs[i]; i++) { - if (!strcmp (name, addrspec_hdrs[i])) { - addrspec = TRUE; - break; - } - } - - label = _(name); - - if (addrspec) { - struct _camel_header_address *addrs; - GString *html; - gchar *img; - const gchar *charset = em_format_get_charset (emf) ? - em_format_get_charset (emf) : em_format_get_default_charset (emf); - - buf = camel_header_unfold (header->value); - if (!(addrs = camel_header_address_decode (buf, charset))) { - g_free (buf); - return; - } - - g_free (buf); - - html = g_string_new(""); - img = efh_format_address (efh, html, addrs, (gchar *) label, - (flags & EM_FORMAT_HTML_HEADER_NOLINKS)); - - if (img) { - str_field = g_strdup_printf ("%s%s:", img, label); - label = str_field; - flags |= EM_FORMAT_HTML_HEADER_NODEC; - g_free (img); - } - - camel_header_address_list_clear (&addrs); - txt = value = html->str; - g_string_free (html, FALSE); - - flags |= EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_HTML; - } else if (!strcmp (name, "Subject")) { - buf = camel_header_unfold (header->value); - txt = value = camel_header_decode_string (buf, charset); - g_free (buf); - - flags |= EM_FORMAT_HEADER_BOLD; - } else if (!strcmp(name, "X-evolution-mailer")) { - /* pseudo-header */ - label = _("Mailer"); - txt = value = camel_header_format_ctext (header->value, charset); - flags |= EM_FORMAT_HEADER_BOLD; - } else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) { - gint msg_offset, local_tz; - time_t msg_date; - struct tm local; - gchar *html; - gboolean hide_real_date; - - hide_real_date = !em_format_html_get_show_real_date (efh); - - txt = header->value; - while (*txt == ' ' || *txt == '\t') - txt++; - - html = camel_text_to_html (txt, efh->text_html_flags, 0); - - msg_date = camel_header_decode_date (txt, &msg_offset); - e_localtime_with_offset (msg_date, &local, &local_tz); - - /* Convert message offset to minutes (e.g. -0400 --> -240) */ - msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100); - /* Turn into offset from localtime, not UTC */ - msg_offset -= local_tz / 60; - - /* value will be freed at the end */ - if (!hide_real_date && !msg_offset) { - /* No timezone difference; just show the real Date: header */ - txt = value = html; - } else { - gchar *date_str; - - date_str = e_datetime_format_format ("mail", "header", - DTFormatKindDateTime, msg_date); - - if (hide_real_date) { - /* Show only the local-formatted date, losing all timezone - * information like Outlook does. Should we attempt to show - * it somehow? */ - txt = value = date_str; - } else { - txt = value = g_strdup_printf ("%s (<I>%s</I>)", html, date_str); - g_free (date_str); - } - g_free (html); - } - flags |= EM_FORMAT_HTML_HEADER_HTML | EM_FORMAT_HEADER_BOLD; - } else if (!strcmp(name, "Newsgroups")) { - struct _camel_header_newsgroup *ng, *scan; - GString *html; - - buf = camel_header_unfold (header->value); - - if (!(ng = camel_header_newsgroups_decode (buf))) { - g_free (buf); - return; - } - - g_free (buf); - - html = g_string_new(""); - scan = ng; - while (scan) { - if (flags & EM_FORMAT_HTML_HEADER_NOLINKS) - g_string_append_printf (html, "%s", scan->newsgroup); - else - g_string_append_printf(html, "<a href=\"news:%s\">%s</a>", - scan->newsgroup, scan->newsgroup); - scan = scan->next; - if (scan) - g_string_append_printf(html, ", "); - } - - camel_header_newsgroups_free (ng); - - txt = html->str; - g_string_free (html, FALSE); - flags |= EM_FORMAT_HEADER_BOLD | EM_FORMAT_HTML_HEADER_HTML; - } else if (!strcmp (name, "Received") || !strncmp (name, "X-", 2)) { - /* don't unfold Received nor extension headers */ - txt = value = camel_header_decode_string (header->value, charset); - } else { - /* don't unfold Received nor extension headers */ - buf = camel_header_unfold (header->value); - txt = value = camel_header_decode_string (buf, charset); - g_free (buf); - } - - efh_format_text_header (efh, buffer, label, txt, flags); - - g_free (value); - g_free (str_field); -} - -static void -efh_format_short_headers (EMFormatHTML *efh, - GString *buffer, - CamelMedium *part, - gboolean visible, - GCancellable *cancellable) -{ - EMFormat *emf = EM_FORMAT (efh); - const gchar *charset; - CamelContentType *ct; - const gchar *hdr_charset; - gchar *evolution_imagesdir; - gchar *subject = NULL; - struct _camel_header_address *addrs = NULL; - struct _camel_header_raw *header; - GString *from; - gboolean is_rtl; - - if (cancellable && g_cancellable_is_cancelled (cancellable)) - return; - - ct = camel_mime_part_get_content_type ((CamelMimePart *) part); - charset = camel_content_type_param (ct, "charset"); - charset = camel_iconv_charset_name (charset); - hdr_charset = em_format_get_charset (emf) ? - em_format_get_charset (emf) : em_format_get_default_charset (emf); - - evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); - from = g_string_new (""); - - g_string_append_printf (buffer, - "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" " - "id=\"__evo-short-headers\" style=\"display: %s\">", - visible ? "block" : "none"); - - header = ((CamelMimePart *) part)->headers; - while (header) { - if (!g_ascii_strcasecmp (header->name, "From")) { - GString *tmp; - if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) { - header = header->next; - continue; - } - tmp = g_string_new (""); - efh_format_address (efh, tmp, addrs, header->name, FALSE); - - if (tmp->len) - g_string_printf (from, _("From: %s"), tmp->str); - g_string_free (tmp, TRUE); - - } else if (!g_ascii_strcasecmp (header->name, "Subject")) { - gchar *buf = NULL; - subject = camel_header_unfold (header->value); - buf = camel_header_decode_string (subject, hdr_charset); - g_free (subject); - subject = camel_text_to_html (buf, CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT, 0); - g_free (buf); - } - header = header->next; - } - - is_rtl = gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL; - if (is_rtl) { - g_string_append_printf ( - buffer, - "<tr><td width=\"100%%\" align=\"right\">%s%s%s <strong>%s</strong></td></tr>", - from->len ? "(" : "", from->str, from->len ? ")" : "", - subject ? subject : _("(no subject)")); - } else { - g_string_append_printf ( - buffer, - "<tr><td><strong>%s</strong> %s%s%s</td></tr>", - subject ? subject : _("(no subject)"), - from->len ? "(" : "", from->str, from->len ? ")" : ""); - } - - g_string_append (buffer, "</table>"); - - g_free (subject); - if (addrs) - camel_header_address_list_clear (&addrs); - - g_string_free (from, TRUE); - g_free (evolution_imagesdir); -} - -static void -write_contact_picture (CamelMimePart *part, - gint size, - GString *buffer) -{ - gchar *b64, *content_type; - CamelDataWrapper *dw; - CamelContentType *ct; - GByteArray *ba; - - ba = NULL; - dw = camel_medium_get_content (CAMEL_MEDIUM (part)); - if (dw) { - ba = camel_data_wrapper_get_byte_array (dw); - } - - if (!ba || ba->len == 0) { - - if (camel_mime_part_get_filename (part)) { - - if (size >= 0) { - g_string_append_printf ( - buffer, - "<img width=\"%d\" src=\"evo-file://%s\" />", - size, camel_mime_part_get_filename (part)); - } else { - g_string_append_printf ( - buffer, - "<img src=\"evo-file://%s\" />", - camel_mime_part_get_filename (part)); - } - } - - return; - } - - b64 = g_base64_encode (ba->data, ba->len); - ct = camel_mime_part_get_content_type (part); - content_type = camel_content_type_simple (ct); - - if (size >= 0) { - g_string_append_printf ( - buffer, - "<img width=\"%d\" src=\"data:%s;base64,%s\">", - size, content_type, b64); - } else { - g_string_append_printf ( - buffer, - "<img src=\"data:%s;base64,%s\">", - content_type, b64); - } - - g_free (b64); - g_free (content_type); -} - -static void -efh_format_full_headers (EMFormatHTML *efh, - GString *buffer, - CamelMedium *part, - gboolean all_headers, - gboolean visible, - GCancellable *cancellable) -{ - EMFormat *emf = EM_FORMAT (efh); - const gchar *charset; - CamelContentType *ct; - struct _camel_header_raw *header; - gboolean have_icon = FALSE; - const gchar *photo_name = NULL; - CamelInternetAddress *cia = NULL; - CamelSession *session; - ESourceRegistry *registry; - gboolean face_decoded = FALSE, contact_has_photo = FALSE; - guchar *face_header_value = NULL; - gsize face_header_len = 0; - gchar *header_sender = NULL, *header_from = NULL, *name; - gboolean mail_from_delegate = FALSE; - const gchar *hdr_charset; - gchar *evolution_imagesdir; - - if (cancellable && g_cancellable_is_cancelled (cancellable)) - return; - - session = em_format_get_session (emf); - registry = e_mail_session_get_registry (E_MAIL_SESSION (session)); - - ct = camel_mime_part_get_content_type ((CamelMimePart *) part); - charset = camel_content_type_param (ct, "charset"); - charset = camel_iconv_charset_name (charset); - hdr_charset = em_format_get_charset (emf) ? - em_format_get_charset (emf) : em_format_get_default_charset (emf); - - evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL); - - g_string_append_printf (buffer, - "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" " - "id=\"__evo-full-headers\" style=\"display: %s\" width=\"100%%\">", - visible ? "block" : "none"); - - header = ((CamelMimePart *) part)->headers; - while (header) { - if (!g_ascii_strcasecmp (header->name, "Sender")) { - struct _camel_header_address *addrs; - GString *html; - - if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) - break; - - html = g_string_new(""); - name = efh_format_address (efh, html, addrs, header->name, FALSE); - - header_sender = html->str; - camel_header_address_list_clear (&addrs); - - g_string_free (html, FALSE); - g_free (name); - } else if (!g_ascii_strcasecmp (header->name, "From")) { - struct _camel_header_address *addrs; - GString *html; - - if (!(addrs = camel_header_address_decode (header->value, hdr_charset))) - break; - - html = g_string_new(""); - name = efh_format_address (efh, html, addrs, header->name, FALSE); - - header_from = html->str; - camel_header_address_list_clear (&addrs); - - g_string_free (html, FALSE); - g_free (name); - } else if (!g_ascii_strcasecmp (header->name, "X-Evolution-Mail-From-Delegate")) { - mail_from_delegate = TRUE; - } - - header = header->next; - } - - if (header_sender && header_from && mail_from_delegate) { - gchar *bold_sender, *bold_from; - - g_string_append ( - buffer, - "<tr><td><table border=1 width=\"100%%\" " - "cellspacing=2 cellpadding=2><tr>"); - if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) - g_string_append ( - buffer, "<td align=\"right\" width=\"100%%\">"); - else - g_string_append ( - buffer, "<td align=\"left\" width=\"100%%\">"); - bold_sender = g_strconcat ("<b>", header_sender, "</b>", NULL); - bold_from = g_strconcat ("<b>", header_from, "</b>", NULL); - /* Translators: This message suggests to the receipients - * that the sender of the mail is different from the one - * listed in From field. */ - g_string_append_printf ( - buffer, - _("This message was sent by %s on behalf of %s"), - bold_sender, bold_from); - g_string_append (buffer, "</td></tr></table></td></tr>"); - g_free (bold_sender); - g_free (bold_from); - } - - g_free (header_sender); - g_free (header_from); - - g_string_append (buffer, "<tr><td width=\"100%%\"><table border=0 cellpadding=\"0\">\n"); - - g_free (evolution_imagesdir); - - /* dump selected headers */ - if (all_headers) { - header = ((CamelMimePart *) part)->headers; - while (header) { - em_format_html_format_header ( - emf, buffer, part, header, - EM_FORMAT_HTML_HEADER_NOCOLUMNS, charset); - header = header->next; - } - } else { - GList *link; - gint mailer_shown = FALSE; - - link = g_queue_peek_head_link (&emf->header_list); - - while (link != NULL) { - EMFormatHeader *h = link->data; - gint mailer, face; - - header = ((CamelMimePart *) part)->headers; - mailer = !g_ascii_strcasecmp (h->name, "X-Evolution-Mailer"); - face = !g_ascii_strcasecmp (h->name, "Face"); - - while (header) { - if (em_format_html_get_show_sender_photo (efh) && - !photo_name && !g_ascii_strcasecmp (header->name, "From")) - photo_name = header->value; - - if (!mailer_shown && mailer && ( - !g_ascii_strcasecmp (header->name, "X-Mailer") || - !g_ascii_strcasecmp (header->name, "User-Agent") || - !g_ascii_strcasecmp (header->name, "X-Newsreader") || - !g_ascii_strcasecmp (header->name, "X-MimeOLE"))) { - struct _camel_header_raw xmailer, *use_header = NULL; - - if (!g_ascii_strcasecmp (header->name, "X-MimeOLE")) { - for (use_header = header->next; use_header; use_header = use_header->next) { - if (!g_ascii_strcasecmp (use_header->name, "X-Mailer") || - !g_ascii_strcasecmp (use_header->name, "User-Agent") || - !g_ascii_strcasecmp (use_header->name, "X-Newsreader")) { - /* even we have X-MimeOLE, then use rather the standard one, when available */ - break; - } - } - } - - if (!use_header) - use_header = header; - - xmailer.name = (gchar *) "X-Evolution-Mailer"; - xmailer.value = use_header->value; - mailer_shown = TRUE; - - em_format_html_format_header ( - emf, buffer, part, - &xmailer, h->flags, charset); - if (strstr(use_header->value, "Evolution")) - have_icon = TRUE; - } else if (!face_decoded && face && !g_ascii_strcasecmp (header->name, "Face")) { - gchar *cp = header->value; - - /* Skip over spaces */ - while (*cp == ' ') - cp++; - - face_header_value = g_base64_decode ( - cp, &face_header_len); - face_header_value = g_realloc ( - face_header_value, - face_header_len + 1); - face_header_value[face_header_len] = 0; - face_decoded = TRUE; - /* Showing an encoded "Face" header makes little sense */ - } else if (!g_ascii_strcasecmp (header->name, h->name) && !face) { - em_format_html_format_header ( - emf, buffer, part, - header, h->flags, charset); - } - - header = header->next; - } - - link = g_list_next (link); - } - } - - g_string_append (buffer, "</table></td>"); - - if (photo_name) { - CamelMimePart *photopart; - gboolean only_local_photo; - - cia = camel_internet_address_new (); - camel_address_decode ((CamelAddress *) cia, (const gchar *) photo_name); - only_local_photo = - em_format_html_get_only_local_photos (efh); - photopart = em_utils_contact_photo ( - registry, cia, only_local_photo); - - if (photopart) { - g_string_append (buffer, "<td align=\"right\" valign=\"top\">"); - write_contact_picture (photopart, -1, buffer); - g_string_append (buffer, "</td>"); - g_object_unref (photopart); - } - g_object_unref (cia); - } - - if (!contact_has_photo && face_decoded) { - CamelMimePart *part; - - part = camel_mime_part_new (); - camel_mime_part_set_content ( - (CamelMimePart *) part, - (const gchar *) face_header_value, - face_header_len, "image/png"); - - g_string_append (buffer, "<td align=\"right\" valign=\"top\">"); - write_contact_picture (part, 48, buffer); - g_string_append (buffer, "</td>"); - - g_object_unref (part); - g_free (face_header_value); - } - - if (have_icon && efh->show_icon) { - GtkIconInfo *icon_info; - CamelMimePart *iconpart = NULL; - - icon_info = gtk_icon_theme_lookup_icon ( - gtk_icon_theme_get_default (), - "evolution", 16, GTK_ICON_LOOKUP_NO_SVG); - if (icon_info != NULL) { - iconpart = em_format_html_file_part ( - (EMFormatHTML *) emf, "image/png", - gtk_icon_info_get_filename (icon_info), - cancellable); - gtk_icon_info_free (icon_info); - } - if (iconpart) { - g_string_append (buffer, "<td align=\"right\" valign=\"top\">"); - write_contact_picture (iconpart, 16, buffer); - g_string_append (buffer, "</td>"); - - g_object_unref (iconpart); - } - } - - g_string_append (buffer, "</tr></table>"); -} - -gboolean -em_format_html_can_load_images (EMFormatHTML *efh) -{ - g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), FALSE); - - return ((efh->priv->image_loading_policy == E_MAIL_IMAGE_LOADING_POLICY_ALWAYS) || - ((efh->priv->image_loading_policy == E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES) && - efh->priv->can_load_images)); -} - -void -em_format_html_animation_extract_frame (const GByteArray *anim, - gchar **frame, - gsize *len) -{ - GdkPixbufLoader *loader; - GdkPixbufAnimation *animation; - GdkPixbuf *frame_buf; - - /* GIF89a (GIF image signature) */ - const gchar GIF_HEADER[] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; - const gint GIF_HEADER_LEN = sizeof (GIF_HEADER); - - /* NETSCAPE2.0 (extension describing animated GIF, starts on 0x310) */ - const gchar GIF_APPEXT[] = { 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, - 0x50, 0x45, 0x32, 0x2E, 0x30 }; - const gint GIF_APPEXT_LEN = sizeof (GIF_APPEXT); - - if ((anim == NULL) || (anim->data == NULL)) { - *frame = NULL; - *len = 0; - return; - } - - /* Check if the image is an animated GIF. We don't care about any - * other animated formats (APNG or MNG) as WebKit does not support them - * and displays only the first frame. */ - if ((anim->len < 0x331) - || (memcmp (anim->data, GIF_HEADER, GIF_HEADER_LEN) != 0) - || (memcmp (&anim->data[0x310], GIF_APPEXT, GIF_APPEXT_LEN) != 0)) { - - *frame = g_memdup (anim->data, anim->len); - *len = anim->len; - return; - } - - loader = gdk_pixbuf_loader_new (); - gdk_pixbuf_loader_write (loader, (guchar *) anim->data, anim->len, NULL); - gdk_pixbuf_loader_close (loader, NULL); - animation = gdk_pixbuf_loader_get_animation (loader); - if (!animation) { - - *frame = g_memdup (anim->data, anim->len); - *len = anim->len; - g_object_unref (loader); - return; - } - - /* Extract first frame */ - frame_buf = gdk_pixbuf_animation_get_static_image (animation); - if (!frame_buf) { - *frame = g_memdup (anim->data, anim->len); - *len = anim->len; - g_object_unref (loader); - g_object_unref (animation); - return; - } - - /* Unforunatelly, GdkPixbuf cannot save to GIF, but WebKit does not - * have any trouble displaying PNG image despite the part having - * image/gif mime-type */ - gdk_pixbuf_save_to_buffer (frame_buf, frame, len, "png", NULL, NULL); - - g_object_unref (loader); -} diff --git a/mail/em-format-html.h b/mail/em-format-html.h deleted file mode 100644 index 9749c37f31..0000000000 --- a/mail/em-format-html.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * - * 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/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* - Abstract class for formatting mails to html -*/ - -#ifndef EM_FORMAT_HTML_H -#define EM_FORMAT_HTML_H - -#include <em-format/em-format.h> -#include <misc/e-web-view.h> -#include <libemail-engine/e-mail-enums.h> - -/* Standard GObject macros */ -#define EM_TYPE_FORMAT_HTML \ - (em_format_html_get_type ()) -#define EM_FORMAT_HTML(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), EM_TYPE_FORMAT_HTML, EMFormatHTML)) -#define EM_FORMAT_HTML_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), EM_TYPE_FORMAT_HTML, EMFormatHTMLClass)) -#define EM_IS_FORMAT_HTML(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), EM_TYPE_FORMAT_HTML)) -#define EM_IS_FORMAT_HTML_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), EM_TYPE_FORMAT_HTML)) -#define EM_FORMAT_HTML_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), EM_TYPE_FORMAT_HTML, EMFormatHTMLClass)) - -G_BEGIN_DECLS - -typedef struct _EMFormatHTML EMFormatHTML; -typedef struct _EMFormatHTMLClass EMFormatHTMLClass; -typedef struct _EMFormatHTMLPrivate EMFormatHTMLPrivate; -typedef struct _EMFormatWidgetPURI EMFormatWidgetPURI; - -enum _em_format_html_header_flags { - EM_FORMAT_HTML_HEADER_TO = 1 << 0, - EM_FORMAT_HTML_HEADER_CC = 1 << 1, - EM_FORMAT_HTML_HEADER_BCC = 1 << 2 -}; - -typedef enum { - EM_FORMAT_HTML_COLOR_BODY, /* header area background */ - EM_FORMAT_HTML_COLOR_CITATION, /* citation font color */ - EM_FORMAT_HTML_COLOR_CONTENT, /* message area background */ - EM_FORMAT_HTML_COLOR_FRAME, /* frame around message area */ - EM_FORMAT_HTML_COLOR_HEADER, /* header font color */ - EM_FORMAT_HTML_COLOR_TEXT, /* message font color */ - EM_FORMAT_HTML_NUM_COLOR_TYPES -} EMFormatHTMLColorType; - -#define EM_FORMAT_HTML_HEADER_NOCOLUMNS (EM_FORMAT_HEADER_LAST) - -/* header already in html format */ -#define EM_FORMAT_HTML_HEADER_HTML (EM_FORMAT_HEADER_LAST<<1) -#define EM_FORMAT_HTML_HEADER_NODEC (EM_FORMAT_HEADER_LAST<<2) -#define EM_FORMAT_HTML_HEADER_NOLINKS (EM_FORMAT_HEADER_LAST<<3) -#define EM_FORMAT_HTML_HEADER_HIDDEN (EM_FORMAT_HEADER_LAST<<4) - -#define EM_FORMAT_HTML_HEADER_LAST (EM_FORMAT_HEADER_LAST<<8) - -#define EM_FORMAT_HTML_VPAD \ - "<table cellspacing=0 cellpadding=3><tr><td>" \ - "<a name=\"padding\"></a></td></tr></table>\n" - -/** - * struct _EMFormatHTML - HTML formatter object. - * - * @format: - * @priv: - * @html: - * @pending_object_list: - * @headers: - * @text_html_flags: - * @body_colour: - * @header_colour: - * @text_colour: - * @frame_colour: - * @content_colour: - * @citation_color: - * @load_http:2: - * @load_http_now:1: - * @mark_citations:1: - * @hide_headers:1: - * @show_icon:1: - * - * Most of these fields are private or read-only. - * - * The base HTML formatter object. This object drives HTML generation - * into a WebKit parser. It also handles text to HTML conversion, - * multipart/related objects and inline images. - **/ -struct _EMFormatHTML { - EMFormat parent; - EMFormatHTMLPrivate *priv; - - GQueue pending_object_list; - - GSList *headers; - - guint32 text_html_flags; /* default flags for text to html conversion */ - guint hide_headers:1; /* no headers at all */ - guint show_icon:1; /* show an icon when the sender used Evo */ - guint32 header_wrap_flags; -}; - -struct _EMFormatHTMLClass { - EMFormatClass parent_class; - - GType html_widget_type; -}; - -GType em_format_html_get_type (void); -void em_format_html_get_color (EMFormatHTML *efh, - EMFormatHTMLColorType type, - GdkColor *color); -void em_format_html_set_color (EMFormatHTML *efh, - EMFormatHTMLColorType type, - const GdkColor *color); -EMailImageLoadingPolicy - em_format_html_get_image_loading_policy - (EMFormatHTML *efh); -void em_format_html_set_image_loading_policy - (EMFormatHTML *efh, - EMailImageLoadingPolicy policy); -gboolean em_format_html_get_mark_citations - (EMFormatHTML *efh); -void em_format_html_set_mark_citations - (EMFormatHTML *efh, - gboolean mark_citations); -gboolean em_format_html_get_only_local_photos - (EMFormatHTML *efh); -void em_format_html_set_only_local_photos - (EMFormatHTML *efh, - gboolean only_local_photos); -gboolean em_format_html_get_show_sender_photo - (EMFormatHTML *efh); -void em_format_html_set_show_sender_photo - (EMFormatHTML *efh, - gboolean show_sender_photo); -gboolean em_format_html_get_animate_images - (EMFormatHTML *efh); -void em_format_html_set_animate_images - (EMFormatHTML *efh, - gboolean animate_images); -void em_format_html_clone_sync (CamelFolder *folder, - const gchar *message_uid, - CamelMimeMessage *message, - EMFormatHTML *efh, - EMFormat *source); -gboolean em_format_html_get_show_real_date - (EMFormatHTML *efh); -void em_format_html_set_show_real_date - (EMFormatHTML *efh, - gboolean show_real_date); - -/* retrieves a pseudo-part icon wrapper for a file */ -CamelMimePart * em_format_html_file_part (EMFormatHTML *efh, - const gchar *mime_type, - const gchar *filename, - GCancellable *cancellable); - -void em_format_html_format_cert_infos - (GQueue *cert_infos, - GString *output_buffer); - -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, - gboolean all_headers, - GCancellable *cancellable); -void em_format_html_format_header (EMFormat *emf, - GString *buffer, - CamelMedium *part, - struct _camel_header_raw *header, - guint32 flags, - const gchar *charset); - -gboolean em_format_html_can_load_images (EMFormatHTML *efh); - -void em_format_html_animation_extract_frame - (const GByteArray *anim, - gchar **frame, - gsize *len); - -G_END_DECLS - -#endif /* EM_FORMAT_HTML_H */ diff --git a/mail/em-utils.c b/mail/em-utils.c index bf75253d34..9be80fbf79 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -56,6 +56,9 @@ #include <shell/e-shell.h> #include <widgets/misc/e-attachment.h> +#include <em-format/e-mail-parser.h> +#include <em-format/e-mail-formatter-quote.h> + #include <libemail-utils/mail-mt.h> #include <libemail-engine/e-mail-folder-utils.h> @@ -65,13 +68,11 @@ #include "e-mail-tag-editor.h" #include "em-composer-utils.h" -#include "em-format-html-display.h" -#include "em-format-html-print.h" #include "em-utils.h" #include "e-mail-printer.h" -#include "em-format/em-format-quote.h" /* XXX This is a dirty hack on a dirty hack. We really need +#include <em-format/e-mail-print-formatter.h> * to rework or get rid of the functions that use this. */ extern const gchar *shell_builtin_backend; @@ -616,20 +617,22 @@ do_print_msg_to_file (GObject *source, GAsyncResult *result, gpointer user_data) { - - EMFormatHTML *efh = EM_FORMAT_HTML (source); + EMailParser *parser; + EMailPartList *parts_list; gchar *filename = user_data; - EMailPrinter *printer; - printer = e_mail_printer_new (efh); + parser = E_MAIL_PARSER (source); + parts_list = e_mail_parser_parse_finish (parser, result, NULL); + + printer = e_mail_printer_new (parts_list); e_mail_printer_set_export_filename (printer, filename); g_signal_connect_swapped (printer, "done", G_CALLBACK (g_object_unref), printer); e_mail_printer_print (printer, TRUE, NULL); - g_object_unref (efh); + g_object_unref (parser); } static gboolean @@ -637,7 +640,7 @@ em_utils_print_messages_to_file (CamelFolder *folder, const gchar *uid, const gchar *filename) { - EMFormatHTMLDisplay *efhd; + EMailParser *parser; CamelMimeMessage *message; CamelStore *parent_store; CamelSession *session; @@ -649,11 +652,10 @@ em_utils_print_messages_to_file (CamelFolder *folder, parent_store = camel_folder_get_parent_store (folder); session = camel_service_get_session (CAMEL_SERVICE (parent_store)); - efhd = em_format_html_display_new (session); - ((EMFormat *) efhd)->message_uid = g_strdup (uid); + parser = e_mail_parser_new (session); - em_format_parse_async ((EMFormat *) efhd, message, folder, NULL, - (GAsyncReadyCallback) do_print_msg_to_file, g_strdup (filename)); + e_mail_parser_parse (parser, folder, uid, message, + (GAsyncReadyCallback) do_print_msg_to_file, NULL, g_strdup (filename)); return TRUE; } @@ -1180,13 +1182,19 @@ em_utils_message_to_html (CamelSession *session, CamelMimeMessage *message, const gchar *credits, guint32 flags, - EMFormat *source, + EMailPartList *parts_list, const gchar *append, guint32 *validity_found) { - EMFormatQuote *emfq; + EMailFormatter *formatter; + EMailParser *parser; CamelStream *mem; GByteArray *buf; + EShell *shell; + GtkWindow *window; + + shell = e_shell_get_default (); + window = e_shell_get_active_window (shell); g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL); @@ -1194,10 +1202,12 @@ em_utils_message_to_html (CamelSession *session, mem = camel_stream_mem_new (); camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (mem), buf); - emfq = em_format_quote_new (session, credits, mem, flags); - em_format_set_composer ((EMFormat *) emfq, TRUE); + formatter = e_mail_formatter_quote_new (credits, flags); + e_mail_formatter_set_style (formatter, + gtk_widget_get_style (GTK_WIDGET (window)), + gtk_widget_get_state (GTK_WIDGET (window))); - if (!source) { + if (!parts_list) { GSettings *settings; gchar *charset; @@ -1205,37 +1215,38 @@ em_utils_message_to_html (CamelSession *session, * current view, not the global setting. */ settings = g_settings_new ("org.gnome.evolution.mail"); charset = g_settings_get_string (settings, "charset"); - em_format_set_default_charset ((EMFormat *) emfq, charset); + if (charset && *charset) + e_mail_formatter_set_default_charset (formatter, charset); g_object_unref (settings); g_free (charset); - } - /* FIXME Not passing a GCancellable here. */ - em_format_parse (EM_FORMAT (emfq), message, NULL, NULL); + parser = e_mail_parser_new (session); + parts_list = e_mail_parser_parse_sync (parser, NULL, NULL, message, NULL); + } if (validity_found) { - GList *iter; - EMFormat *emf = (EMFormat *) emfq; + GSList *iter; if (validity_found) *validity_found = 0; /* Return all found validities */ - for (iter = emf->mail_part_list; iter; iter = iter->next) { + for (iter = parts_list->list; iter; iter = iter->next) { - EMFormatPURI *puri = iter->data; - if (!puri) + EMailPart *part = iter->data; + if (!part) continue; - if (*validity_found && puri->validity_type) - *validity_found |= puri->validity_type; + if (*validity_found && part->validity_type) + *validity_found |= part->validity_type; } } - em_format_quote_write (emfq, mem, NULL); - - g_object_unref (emfq); + e_mail_formatter_format_sync ( + formatter, parts_list, mem, 0, + E_MAIL_FORMATTER_MODE_PRINTING, NULL); + g_object_unref (formatter); if (append && *append) camel_stream_write_string (mem, append, NULL, NULL); diff --git a/mail/em-utils.h b/mail/em-utils.h index 092b75933c..db286eb55b 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -35,7 +35,7 @@ G_BEGIN_DECLS -struct _EMFormat; +struct _EMailPartList; struct _EShell; gboolean em_utils_ask_open_many (GtkWindow *parent, gint how_many); @@ -66,7 +66,7 @@ void em_utils_selection_get_urilist (GtkSelectionData *data, CamelFolder *folder EProxy * em_utils_get_proxy (void); /* FIXME: should this have an override charset? */ -gchar *em_utils_message_to_html (CamelSession *session, CamelMimeMessage *msg, const gchar *credits, guint32 flags, struct _EMFormat *source, const gchar *append, guint32 *validity_found); +gchar *em_utils_message_to_html (CamelSession *session, CamelMimeMessage *msg, const gchar *credits, guint32 flags, struct _EMailPartList *parts_list, const gchar *append, guint32 *validity_found); void em_utils_empty_trash (GtkWidget *parent, EMailSession *session); |