[evolution/gnome-3-30] "Save Image..." fails on shown attached image in message preview
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/gnome-3-30] "Save Image..." fails on shown attached image in message preview
- Date: Mon, 10 Dec 2018 15:32:41 +0000 (UTC)
commit 671c98eb4d8ac1f67c1600171c5099432941b208
Author: Milan Crha <mcrha redhat com>
Date: Mon Dec 10 16:21:39 2018 +0100
"Save Image..." fails on shown attached image in message preview
The image had been stored as "data:image/...;base64;<data>", which
the context menu Save Image and Copy Image could not handle. This
resulted in a lengthy error message, which could cause a crash.
This commit fixes several things:
a) replace "data:" URI-s with "mail://" URI-s, which means less resources
are needed; it also fixes the Save/Copy Image actions as a side effect;
b) fix memory leak for tiff images;
c) let to Save/Copy Image handle base64-encoded "data:" URI-s (as
the source HTML message can still contain them);
d) shorten the URI in the error message when it's too long;
e) pass also "filename" into the URI, thus the Save Image has prefilled it,
the same as attachment's "Save as" action.
Reported downstream at:
https://bugzilla.redhat.com/show_bug.cgi?id=1657361
src/e-util/e-web-view.c | 59 ++++++++++++++++++++++++-
src/em-format/e-mail-formatter-image.c | 78 +++++++++++++---------------------
src/mail/e-mail-display.c | 24 +++++++++++
3 files changed, 110 insertions(+), 51 deletions(-)
---
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index 78b7ebc9af..6f88d30761 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -4247,6 +4247,7 @@ e_web_view_request (EWebView *web_view,
AsyncContext *async_context;
GSList *link;
GTask *task;
+ gboolean is_processed = FALSE;
g_return_if_fail (E_IS_WEB_VIEW (web_view));
g_return_if_fail (uri != NULL);
@@ -4272,9 +4273,63 @@ e_web_view_request (EWebView *web_view,
if (content_request) {
async_context->content_request = g_object_ref (content_request);
g_task_run_in_thread (task, web_view_request_process_thread);
- } else {
+ is_processed = TRUE;
+
+ /* Handle base64-encoded "data:" URIs manually */
+ } else if (g_ascii_strncasecmp (uri, "data:", 5) == 0) {
+ /* data:[<mime type>][;charset=<charset>][;base64],<encoded data> */
+ const gchar *ptr, *from;
+ gboolean is_base64 = FALSE;
+
+ ptr = uri + 5;
+ from = ptr;
+ while (*ptr && *ptr != ',') {
+ ptr++;
+
+ if (*ptr == ',' || *ptr == ';') {
+ if (g_ascii_strncasecmp (from, "base64", ptr - from) == 0)
+ is_base64 = TRUE;
+
+ from = ptr + 1;
+ }
+ }
+
+ if (is_base64 && *ptr == ',') {
+ guchar *data;
+ gsize len = 0;
+
+ data = g_base64_decode (ptr + 1, &len);
+
+ if (data && len > 0) {
+ async_context->input_stream = g_memory_input_stream_new_from_data (data, len,
g_free);
+ g_task_return_boolean (task, TRUE);
+ is_processed = TRUE;
+ } else {
+ g_free (data);
+ }
+ }
+ }
+
+ if (!is_processed) {
+ GString *shorten_uri = NULL;
+ gint len;
+
+ len = g_utf8_strlen (uri, -1);
+
+ /* The "data:" URIs can be quite long */
+ if (len > 512) {
+ const gchar *ptr = g_utf8_offset_to_pointer (uri, 512);
+
+ shorten_uri = g_string_sized_new (ptr - uri + 16);
+ g_string_append_len (shorten_uri, uri, ptr - uri);
+ g_string_append (shorten_uri, "…");
+ }
+
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Cannot get URI “%s”, do not know how to download it."), uri);
+ _("Cannot get URI “%s”, do not know how to download it."), shorten_uri ?
shorten_uri->str : uri);
+
+ if (shorten_uri)
+ g_string_free (shorten_uri, TRUE);
}
g_object_unref (task);
diff --git a/src/em-format/e-mail-formatter-image.c b/src/em-format/e-mail-formatter-image.c
index 9f837d8a0a..d763c41829 100644
--- a/src/em-format/e-mail-formatter-image.c
+++ b/src/em-format/e-mail-formatter-image.c
@@ -65,12 +65,8 @@ emfe_image_format (EMailFormatterExtension *extension,
GOutputStream *stream,
GCancellable *cancellable)
{
- gchar *content;
CamelMimePart *mime_part;
CamelContentType *content_type;
- CamelDataWrapper *dw;
- GBytes *bytes;
- GOutputStream *raw_content;
if (g_cancellable_is_cancelled (cancellable))
return FALSE;
@@ -82,24 +78,28 @@ emfe_image_format (EMailFormatterExtension *extension,
/* Skip TIFF images, which cannot be shown inline */
if (content_type && (
camel_content_type_is (content_type, "image", "tiff") ||
- camel_content_type_is (content_type, "image", "tif")))
+ camel_content_type_is (content_type, "image", "tif"))) {
+ g_clear_object (&mime_part);
return FALSE;
+ }
- dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
- g_return_val_if_fail (dw, FALSE);
+ if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+ CamelDataWrapper *dw;
+ GBytes *bytes;
+ GOutputStream *raw_content;
- raw_content = g_memory_output_stream_new_resizable ();
- camel_data_wrapper_decode_to_output_stream_sync (
- dw, raw_content, cancellable, NULL);
- g_output_stream_close (raw_content, NULL, NULL);
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+ g_return_val_if_fail (dw, FALSE);
- bytes = g_memory_output_stream_steal_as_bytes (
- G_MEMORY_OUTPUT_STREAM (raw_content));
+ raw_content = g_memory_output_stream_new_resizable ();
+ camel_data_wrapper_decode_to_output_stream_sync (
+ dw, raw_content, cancellable, NULL);
+ g_output_stream_close (raw_content, NULL, NULL);
- if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
+ bytes = g_memory_output_stream_steal_as_bytes (
+ G_MEMORY_OUTPUT_STREAM (raw_content));
if (!e_mail_formatter_get_animate_images (formatter)) {
-
gchar *buff;
gsize len;
@@ -121,52 +121,32 @@ emfe_image_format (EMailFormatterExtension *extension,
stream, data, size, NULL, cancellable, NULL);
}
+ g_bytes_unref (bytes);
+ g_object_unref (raw_content);
} else {
- gchar *buffer;
- const gchar *mime_type;
-
- if (!e_mail_formatter_get_animate_images (formatter)) {
-
- gchar *buff;
- gsize len;
-
- e_mail_part_animation_extract_frame (
- bytes, &buff, &len);
+ gchar *buffer, *uri;
+ const gchar *filename;
- content = g_base64_encode ((guchar *) buff, len);
- g_free (buff);
+ filename = camel_mime_part_get_filename (mime_part);
- } else {
- gconstpointer data;
- gsize size;
+ uri = e_mail_part_build_uri (
+ e_mail_part_list_get_folder (context->part_list),
+ e_mail_part_list_get_message_uid (context->part_list),
+ "part_id", G_TYPE_STRING, e_mail_part_get_id (part),
+ "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW,
+ "filename", G_TYPE_STRING, filename ? filename : "",
+ NULL);
- data = g_bytes_get_data (bytes, &size);
- content = g_base64_encode (data, size);
- }
-
- mime_type = e_mail_part_get_mime_type (part);
- if (mime_type == NULL)
- mime_type = "image/*";
-
- /* 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%%;\" />",
- mime_type, content);
+ buffer = g_strdup_printf ("<img src=\"%s\" style=\"max-width:100%%;\" />", uri);
g_output_stream_write_all (
stream, buffer, strlen (buffer),
NULL, cancellable, NULL);
g_free (buffer);
- g_free (content);
+ g_free (uri);
}
- g_bytes_unref (bytes);
-
- g_object_unref (raw_content);
-
g_object_unref (mime_part);
return TRUE;
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index 458e9731d0..4004d85194 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -1837,6 +1837,7 @@ mail_display_suggest_filename (EWebView *web_view,
{
EMailDisplay *display;
CamelMimePart *mime_part;
+ SoupURI *suri;
/* Note, this assumes the URI comes
* from the currently loaded message. */
@@ -1847,6 +1848,29 @@ mail_display_suggest_filename (EWebView *web_view,
if (mime_part)
return g_strdup (camel_mime_part_get_filename (mime_part));
+ suri = soup_uri_new (uri);
+ if (suri) {
+ gchar *filename = NULL;
+
+ if (suri->query) {
+ GHashTable *uri_query;
+
+ uri_query = soup_form_decode (suri->query);
+ if (uri_query && g_hash_table_contains (uri_query, "filename"))
+ filename = g_strdup (g_hash_table_lookup (uri_query, "filename"));
+
+ if (uri_query)
+ g_hash_table_destroy (uri_query);
+ }
+
+ soup_uri_free (suri);
+
+ if (filename && *filename)
+ return filename;
+
+ g_free (filename);
+ }
+
/* Chain up to parent's suggest_filename() method. */
return E_WEB_VIEW_CLASS (e_mail_display_parent_class)->
suggest_filename (web_view, uri);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]