aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2011-08-09 16:32:36 +0800
committerMilan Crha <mcrha@redhat.com>2011-08-09 16:32:36 +0800
commit33be6d5da315a0abfd3fb4f74dccc9cc4a249f5e (patch)
tree202750515293b2c08c08f08b6d8ba257abd9a1e2
parent0d4cdfbc9cd14569a3d4c8b75e54e74acca04033 (diff)
downloadgsoc2013-evolution-33be6d5da315a0abfd3fb4f74dccc9cc4a249f5e.tar.gz
gsoc2013-evolution-33be6d5da315a0abfd3fb4f74dccc9cc4a249f5e.tar.zst
gsoc2013-evolution-33be6d5da315a0abfd3fb4f74dccc9cc4a249f5e.zip
Bug #655669 - Can't save inline pictures embedded in HTML Mails
-rw-r--r--mail/em-format-html-display.c162
-rw-r--r--mail/em-format-html.c13
-rw-r--r--mail/em-format-html.h2
-rw-r--r--widgets/misc/e-web-view.c53
-rw-r--r--widgets/misc/e-web-view.h3
5 files changed, 232 insertions, 1 deletions
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index d5e0353bf8..8a4077998d 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -50,6 +50,9 @@
#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"
@@ -59,6 +62,7 @@
#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"
@@ -656,6 +660,145 @@ efhd_format_secure (EMFormat *emf,
}
static void
+attachment_load_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GFile *file)
+{
+ EShell *shell;
+ GtkWindow *parent;
+
+ e_attachment_load_finish (attachment, result, NULL);
+
+ shell = e_shell_get_default ();
+ parent = e_shell_get_active_window (shell);
+
+ e_attachment_save_async (
+ attachment, file, (GAsyncReadyCallback)
+ e_attachment_save_handle_error, parent);
+
+ g_object_unref (file);
+}
+
+static void
+action_image_save_cb (GtkAction *actions, EMFormatHTMLDisplay *efhd)
+{
+ EWebView *web_view;
+ EMFormat *emf;
+ const gchar *image_src;
+ CamelMimePart *part;
+ EAttachment *attachment;
+ GFile *file;
+
+ web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhd));
+ g_return_if_fail (web_view != NULL);
+
+ image_src = e_web_view_get_cursor_image_src (web_view);
+ if (!image_src)
+ return;
+
+ emf = EM_FORMAT (efhd);
+ g_return_if_fail (emf != NULL);
+ g_return_if_fail (emf->message != NULL);
+
+ if (g_str_has_prefix (image_src, "cid:")) {
+ part = camel_mime_message_get_part_by_content_id (emf->message, image_src + 4);
+ g_return_if_fail (part != NULL);
+
+ g_object_ref (part);
+ } else {
+ CamelStream *image_stream;
+ CamelDataWrapper *dw;
+ const gchar *filename;
+
+ image_stream = em_format_html_get_cached_image (EM_FORMAT_HTML (efhd), image_src);
+ if (!image_stream)
+ return;
+
+ filename = strrchr (image_src, '/');
+ if (filename && strchr (filename, '?'))
+ filename = NULL;
+ else if (filename)
+ filename = filename + 1;
+
+ part = camel_mime_part_new ();
+ if (filename)
+ camel_mime_part_set_filename (part, filename);
+
+ dw = camel_data_wrapper_new ();
+ camel_data_wrapper_set_mime_type (dw, "application/octet-stream");
+ camel_data_wrapper_construct_from_stream_sync (dw, image_stream, NULL, NULL);
+ camel_medium_set_content (CAMEL_MEDIUM (part), dw);
+ g_object_unref (dw);
+
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+
+ g_object_unref (image_stream);
+ }
+
+ file = e_shell_run_save_dialog (
+ e_shell_get_default (),
+ _("Save Image"), camel_mime_part_get_filename (part),
+ NULL, NULL, NULL);
+ if (file == NULL) {
+ g_object_unref (part);
+ return;
+ }
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, part);
+
+ e_attachment_load_async (
+ attachment, (GAsyncReadyCallback)
+ attachment_load_finish, file);
+
+ g_object_unref (part);
+}
+
+static void
+efhd_web_view_update_actions_cb (EWebView *web_view, EMFormatHTMLDisplay *efhd)
+{
+ const gchar *image_src;
+ gboolean visible;
+ GtkAction *action;
+
+ g_return_if_fail (web_view != NULL);
+
+ image_src = e_web_view_get_cursor_image_src (web_view);
+ visible = image_src && g_str_has_prefix (image_src, "cid:");
+ if (!visible && image_src) {
+ CamelStream *image_stream;
+
+ image_stream = em_format_html_get_cached_image (EM_FORMAT_HTML (efhd), image_src);
+ visible = image_stream != NULL;
+
+ if (image_stream)
+ g_object_unref (image_stream);
+ }
+
+ action = e_web_view_get_action (web_view, "efhd-image-save");
+ if (action)
+ gtk_action_set_visible (action, visible);
+}
+
+static GtkActionEntry image_entries[] = {
+ { "efhd-image-save",
+ GTK_STOCK_SAVE,
+ N_("Save _Image..."),
+ NULL,
+ N_("Save the image to a file"),
+ G_CALLBACK (action_image_save_cb) }
+};
+
+static const gchar *image_ui =
+ "<ui>"
+ " <popup name='context'>"
+ " <placeholder name='custom-actions-2'>"
+ " <menuitem action='efhd-image-save'/>"
+ " </placeholder>"
+ " </popup>"
+ "</ui>";
+
+static void
efhd_finalize (GObject *object)
{
EMFormatHTMLDisplay *efhd;
@@ -701,6 +844,9 @@ static void
efhd_init (EMFormatHTMLDisplay *efhd)
{
EWebView *web_view;
+ GtkActionGroup *image_actions;
+ GtkUIManager *ui_manager;
+ GError *error = NULL;
web_view = em_format_html_get_web_view (EM_FORMAT_HTML (efhd));
@@ -716,6 +862,22 @@ efhd_init (EMFormatHTMLDisplay *efhd)
EM_FORMAT_HTML (efhd)->text_html_flags |=
CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+
+ image_actions = e_web_view_get_action_group (web_view, "image");
+ g_return_if_fail (image_actions != NULL);
+
+ gtk_action_group_add_actions (
+ image_actions, image_entries,
+ G_N_ELEMENTS (image_entries), efhd);
+
+ ui_manager = e_web_view_get_ui_manager (web_view);
+ gtk_ui_manager_add_ui_from_string (ui_manager, image_ui, -1, &error);
+
+ if (error)
+ g_debug ("%s: Failed to add image_ui: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+
+ g_signal_connect (web_view, "update-actions", G_CALLBACK (efhd_web_view_update_actions_cb), efhd);
}
GType
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index d79fa450bc..745c275d8b 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -3328,3 +3328,16 @@ em_format_html_format_cert_infos (CamelCipherCertInfo *first_cinfo)
return g_string_free (res, FALSE);
}
+
+/* unref returned pointer with g_object_unref(), if not NULL */
+CamelStream *
+em_format_html_get_cached_image (EMFormatHTML *efh, const gchar *image_uri)
+{
+ g_return_val_if_fail (efh != NULL, NULL);
+ g_return_val_if_fail (image_uri != NULL, NULL);
+
+ if (!emfh_http_cache)
+ return NULL;
+
+ return camel_data_cache_get (emfh_http_cache, EMFH_HTTP_CACHE_PATH, image_uri, NULL);
+}
diff --git a/mail/em-format-html.h b/mail/em-format-html.h
index 68b5b438eb..7704cb640a 100644
--- a/mail/em-format-html.h
+++ b/mail/em-format-html.h
@@ -311,6 +311,8 @@ void em_format_html_set_headers_collapsable
gchar * em_format_html_format_cert_infos
(CamelCipherCertInfo *first_cinfo);
+CamelStream * em_format_html_get_cached_image (EMFormatHTML *efh,
+ const gchar *image_uri);
G_END_DECLS
#endif /* EM_FORMAT_HTML_H */
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 0c027431e7..f0eb3a64ba 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -47,6 +47,7 @@ struct _EWebViewPrivate {
GtkUIManager *ui_manager;
gchar *selected_uri;
GdkPixbufAnimation *cursor_image;
+ gchar *cursor_image_src;
GtkAction *open_proxy;
GtkAction *print_proxy;
@@ -85,7 +86,8 @@ enum {
PROP_PRINT_PROXY,
PROP_SAVE_AS_PROXY,
PROP_SELECTED_URI,
- PROP_CURSOR_IMAGE
+ PROP_CURSOR_IMAGE,
+ PROP_CURSOR_IMAGE_SRC
};
enum {
@@ -478,6 +480,7 @@ web_view_button_press_event_cb (EWebView *web_view,
if (event) {
GdkPixbufAnimation *anim;
+ gchar *image_src;
if (frame == NULL)
frame = GTK_HTML (web_view);
@@ -486,6 +489,10 @@ web_view_button_press_event_cb (EWebView *web_view,
e_web_view_set_cursor_image (web_view, anim);
if (anim != NULL)
g_object_unref (anim);
+
+ image_src = gtk_html_get_image_src_at (frame, event->x, event->y);
+ e_web_view_set_cursor_image_src (web_view, image_src);
+ g_free (image_src);
}
if (event != NULL && event->button != 3)
@@ -635,6 +642,11 @@ web_view_set_property (GObject *object,
E_WEB_VIEW (object),
g_value_get_object (value));
return;
+ case PROP_CURSOR_IMAGE_SRC:
+ e_web_view_set_cursor_image_src (
+ E_WEB_VIEW (object),
+ g_value_get_string (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -736,6 +748,11 @@ web_view_get_property (GObject *object,
value, e_web_view_get_cursor_image (
E_WEB_VIEW (object)));
return;
+ case PROP_CURSOR_IMAGE_SRC:
+ g_value_set_string (
+ value, e_web_view_get_cursor_image_src (
+ E_WEB_VIEW (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -783,6 +800,11 @@ web_view_dispose (GObject *object)
priv->cursor_image = NULL;
}
+ if (priv->cursor_image_src != NULL) {
+ g_free (priv->cursor_image_src);
+ priv->cursor_image_src = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -1500,6 +1522,16 @@ e_web_view_class_init (EWebViewClass *class)
GDK_TYPE_PIXBUF_ANIMATION,
G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class,
+ PROP_CURSOR_IMAGE_SRC,
+ g_param_spec_string (
+ "cursor-image-src",
+ "Image source uri at the mouse cursor",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
signals[COPY_CLIPBOARD] = g_signal_new (
"copy-clipboard",
G_TYPE_FROM_CLASS (class),
@@ -2004,6 +2036,25 @@ e_web_view_set_cursor_image (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "cursor-image");
}
+const gchar *
+e_web_view_get_cursor_image_src (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->cursor_image_src;
+}
+
+void
+e_web_view_set_cursor_image_src (EWebView *web_view, const gchar *src_uri)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = g_strdup (src_uri);
+
+ g_object_notify (G_OBJECT (web_view), "cursor-image-src");
+}
+
GtkAction *
e_web_view_get_open_proxy (EWebView *web_view)
{
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index b5f368f622..1ca9915d5e 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -128,6 +128,9 @@ GdkPixbufAnimation *
e_web_view_get_cursor_image (EWebView *web_view);
void e_web_view_set_cursor_image (EWebView *web_view,
GdkPixbufAnimation *animation);
+const gchar * e_web_view_get_cursor_image_src (EWebView *web_view);
+void e_web_view_set_cursor_image_src (EWebView *web_view,
+ const gchar *src_uri);
GtkAction * e_web_view_get_open_proxy (EWebView *web_view);
void e_web_view_set_open_proxy (EWebView *web_view,
GtkAction *open_proxy);