[evolution] Bug 743876 - Inline image lost on message send when sending through Outbox



commit f60a5b6b58b3c1bf6982aaa7b0d3d055770674e1
Author: Tomas Popela <tpopela redhat com>
Date:   Wed Feb 4 13:45:28 2015 +0100

    Bug 743876 - Inline image lost on message send when sending through Outbox
    
    The thing is that when we were sending the message through Outbox
    Evolution generates one message that is used for sending and another one
    for saving to Outbox. But while creating the first message the images
    inside the view are processed to cid images, so for the second message
    they were not there. To avoid that we will restore the images in the
    view right after we get the HTML version of view's content.

 composer/e-msg-composer.c        |    3 +-
 e-util/e-html-editor-view.c      |  487 ++++++++++++++++++++++----------------
 e-util/e-html-editor-view.h      |    7 +-
 e-util/e-html-editor.c           |    2 +-
 e-util/e-mail-signature-editor.c |    2 +-
 e-util/test-html-editor.c        |    8 +-
 6 files changed, 295 insertions(+), 214 deletions(-)
---
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 50400f1..1e3d03a 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -1362,10 +1362,9 @@ composer_build_message (EMsgComposer *composer,
 
                editor = e_msg_composer_get_editor (composer);
                view = e_html_editor_get_view (editor);
-               inline_images = e_html_editor_view_get_parts_for_inline_images (view, from_domain);
 
                data = g_byte_array_new ();
-               text = e_html_editor_view_get_text_html (view);
+               text = e_html_editor_view_get_text_html (view, from_domain, &inline_images);
                length = strlen (text);
                g_byte_array_append (data, (guint8 *) text, (guint) length);
                pre_encode = text_requires_quoted_printable (text, length);
diff --git a/e-util/e-html-editor-view.c b/e-util/e-html-editor-view.c
index 30aacb1..3f05e8a 100644
--- a/e-util/e-html-editor-view.c
+++ b/e-util/e-html-editor-view.c
@@ -7752,6 +7752,271 @@ e_html_editor_view_get_spell_checker (EHTMLEditorView *view)
        return E_SPELL_CHECKER (webkit_get_text_checker ());
 }
 
+static CamelMimePart *
+e_html_editor_view_add_inline_image_from_element (EHTMLEditorView *view,
+                                                  WebKitDOMElement *element,
+                                                  const gchar *attribute,
+                                                 const gchar *uid_domain)
+{
+       CamelStream *stream;
+       CamelDataWrapper *wrapper;
+       CamelMimePart *part = NULL;
+       gsize decoded_size;
+       gssize size;
+       gchar *mime_type = NULL;
+       gchar *element_src, *cid, *name;
+       const gchar *base64_encoded_data;
+       guchar *base64_decoded_data = NULL;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element)) {
+               return NULL;
+       }
+
+       element_src = webkit_dom_element_get_attribute (
+               WEBKIT_DOM_ELEMENT (element), attribute);
+
+       base64_encoded_data = strstr (element_src, ";base64,");
+       if (!base64_encoded_data)
+               goto out;
+
+       mime_type = g_strndup (
+               element_src + 5,
+               base64_encoded_data - (strstr (element_src, "data:") + 5));
+
+       /* Move to actual data */
+       base64_encoded_data += 8;
+
+       base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
+
+       stream = camel_stream_mem_new ();
+       size = camel_stream_write (
+               stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
+
+       if (size == -1)
+               goto out;
+
+       wrapper = camel_data_wrapper_new ();
+       camel_data_wrapper_construct_from_stream_sync (
+               wrapper, stream, NULL, NULL);
+       g_object_unref (stream);
+
+       camel_data_wrapper_set_mime_type (wrapper, mime_type);
+
+       part = camel_mime_part_new ();
+       camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
+       g_object_unref (wrapper);
+
+       cid = camel_header_msgid_generate (uid_domain);
+       camel_mime_part_set_content_id (part, cid);
+       g_free (cid);
+       name = webkit_dom_element_get_attribute (element, "data-name");
+       camel_mime_part_set_filename (part, name);
+       g_free (name);
+       camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+out:
+       g_free (mime_type);
+       g_free (element_src);
+       g_free (base64_decoded_data);
+
+       return part;
+}
+
+static GList *
+html_editor_view_get_parts_for_inline_images (EHTMLEditorView *view,
+                                              const gchar *uid_domain,
+                                              GHashTable **inline_images)
+{
+       GList *parts = NULL;
+       gint length, ii;
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+
+       g_return_val_if_fail (E_IS_HTML_EDITOR_VIEW (view), NULL);
+       g_return_val_if_fail (inline_images != NULL, NULL);
+
+       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW  (view));
+       list = webkit_dom_document_query_selector_all (document, "img[data-inline]", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       if (length == 0)
+               goto background;
+
+       *inline_images = g_hash_table_new_full (
+               g_str_hash, g_str_equal, g_free, g_free);
+
+       for (ii = 0; ii < length; ii++) {
+               const gchar *id;
+               gchar *cid;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               gchar *src = webkit_dom_element_get_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "src");
+
+               if ((id = g_hash_table_lookup (*inline_images, src)) != NULL) {
+                       cid = g_strdup_printf ("cid:%s", id);
+                       g_free (src);
+               } else {
+                       CamelMimePart *part;
+
+                       part = e_html_editor_view_add_inline_image_from_element (
+                               view, WEBKIT_DOM_ELEMENT (node), "src", uid_domain);
+                       parts = g_list_append (parts, part);
+
+                       id = camel_mime_part_get_content_id (part);
+                       cid = g_strdup_printf ("cid:%s", id);
+
+                       g_hash_table_insert (*inline_images, src, g_strdup (id));
+               }
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "src", cid, NULL);
+               g_free (cid);
+       }
+       g_object_unref (list);
+
+ background:
+       list = webkit_dom_document_query_selector_all (
+               document, "[data-inline][background]", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       if (length == 0)
+               return parts;
+       if (!*inline_images)
+               *inline_images = g_hash_table_new_full (
+                       g_str_hash, g_str_equal, g_free, g_free);
+
+       for (ii = 0; ii < length; ii++) {
+               CamelMimePart *part;
+               const gchar *id;
+               gchar *cid = NULL;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               gchar *src = webkit_dom_element_get_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "background");
+
+               if ((id = g_hash_table_lookup (*inline_images, src)) != NULL) {
+                       cid = g_strdup_printf ("cid:%s", id);
+                       webkit_dom_element_set_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+                       g_free (src);
+               } else {
+                       part = e_html_editor_view_add_inline_image_from_element (
+                               view, WEBKIT_DOM_ELEMENT (node), "background", uid_domain);
+                       if (part) {
+                               parts = g_list_append (parts, part);
+                               id = camel_mime_part_get_content_id (part);
+                               g_hash_table_insert (*inline_images, src, g_strdup (id));
+                               cid = g_strdup_printf ("cid:%s", id);
+                               webkit_dom_element_set_attribute (
+                                       WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+                       } else
+                               g_free (src);
+               }
+               g_free (cid);
+       }
+
+       g_object_unref (list);
+
+       return parts;
+}
+
+/**
+ * e_html_editor_view_add_inline_image_from_mime_part:
+ * @composer: a composer object
+ * @part: a CamelMimePart containing image data
+ *
+ * This adds the mime part @part to @composer as an inline image.
+ **/
+void
+e_html_editor_view_add_inline_image_from_mime_part (EHTMLEditorView *view,
+                                                    CamelMimePart *part)
+{
+       CamelDataWrapper *dw;
+       CamelStream *stream;
+       GByteArray *byte_array;
+       gchar *src, *base64_encoded, *mime_type, *cid_src;
+       const gchar *cid, *name;
+
+       stream = camel_stream_mem_new ();
+       dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+       g_return_if_fail (dw);
+
+       mime_type = camel_data_wrapper_get_mime_type (dw);
+       camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
+       camel_stream_close (stream, NULL, NULL);
+
+       byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+
+       if (!byte_array->data)
+               return;
+
+       base64_encoded = g_base64_encode ((const guchar *) byte_array->data, byte_array->len);
+
+       name = camel_mime_part_get_filename (part);
+       /* Insert file name before new src */
+       src = g_strconcat (name, ";data:", mime_type, ";base64,", base64_encoded, NULL);
+
+       cid = camel_mime_part_get_content_id (part);
+       if (!cid) {
+               camel_mime_part_set_content_id (part, NULL);
+               cid = camel_mime_part_get_content_id (part);
+       }
+       cid_src = g_strdup_printf ("cid:%s", cid);
+
+       g_hash_table_insert (view->priv->inline_images, cid_src, src);
+
+       g_free (base64_encoded);
+       g_free (mime_type);
+       g_object_unref (stream);
+}
+
+static void
+restore_images (gchar *key,
+                gchar *value,
+                EHTMLEditorView *view)
+{
+       gchar *selector;
+       gint length, ii;
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+
+       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW  (view));
+
+       selector = g_strconcat ("[data-inline][background=\"cid:", value, "\"]", NULL);
+       list = webkit_dom_document_query_selector_all (document, selector, NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_list_item (list, ii));
+
+               webkit_dom_element_set_attribute (element, "background", key, NULL);
+       }
+       g_free (selector);
+       g_object_unref (list);
+
+       selector = g_strconcat ("[data-inline][src=\"cid:", value, "\"]", NULL);
+       list = webkit_dom_document_query_selector_all (document, selector, NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_list_item (list, ii));
+
+               webkit_dom_element_set_attribute (element, "src", key, NULL);
+       }
+       g_free (selector);
+       g_object_unref (list);
+}
+
+static void
+html_editor_view_restore_images (EHTMLEditorView *view,
+                                 GHashTable **inline_images)
+{
+       g_return_if_fail (E_IS_HTML_EDITOR_VIEW (view));
+
+       g_hash_table_foreach (*inline_images, (GHFunc) restore_images, view);
+
+       /* Remove all hashed images as user can modify them. */
+       g_hash_table_remove_all (*inline_images);
+       g_hash_table_destroy (*inline_images);
+}
+
 /**
  * e_html_editor_view_get_text_html:
  * @view: an #EHTMLEditorView:
@@ -7762,9 +8027,25 @@ e_html_editor_view_get_spell_checker (EHTMLEditorView *view)
  * Returns: A newly allocated string
  */
 gchar *
-e_html_editor_view_get_text_html (EHTMLEditorView *view)
+e_html_editor_view_get_text_html (EHTMLEditorView *view,
+                                  const gchar *from_domain,
+                                  GList **inline_images)
 {
-       return process_content_for_html (view);
+       gchar *html = NULL;
+       GHashTable *inline_images_to_restore = NULL;
+
+       g_return_val_if_fail (E_IS_HTML_EDITOR_VIEW (view), NULL);
+
+       if (inline_images && from_domain)
+               *inline_images = html_editor_view_get_parts_for_inline_images (
+                       view, from_domain, &inline_images_to_restore);
+
+       html = process_content_for_html (view);
+
+       if (inline_images && from_domain && inline_images_to_restore)
+               html_editor_view_restore_images (view, &inline_images_to_restore);
+
+       return html;
 }
 
 /**
@@ -8370,208 +8651,6 @@ e_html_editor_view_check_magic_links (EHTMLEditorView *view,
        html_editor_view_check_magic_links (view, range, include_space);
 }
 
-static CamelMimePart *
-e_html_editor_view_add_inline_image_from_element (EHTMLEditorView *view,
-                                                  WebKitDOMElement *element,
-                                                  const gchar *attribute,
-                                                 const gchar *uid_domain)
-{
-       CamelStream *stream;
-       CamelDataWrapper *wrapper;
-       CamelMimePart *part = NULL;
-       gsize decoded_size;
-       gssize size;
-       gchar *mime_type = NULL;
-       gchar *element_src, *cid, *name;
-       const gchar *base64_encoded_data;
-       guchar *base64_decoded_data = NULL;
-
-       if (!WEBKIT_DOM_IS_ELEMENT (element)) {
-               return NULL;
-       }
-
-       element_src = webkit_dom_element_get_attribute (
-               WEBKIT_DOM_ELEMENT (element), attribute);
-
-       base64_encoded_data = strstr (element_src, ";base64,");
-       if (!base64_encoded_data)
-               goto out;
-
-       mime_type = g_strndup (
-               element_src + 5,
-               base64_encoded_data - (strstr (element_src, "data:") + 5));
-
-       /* Move to actual data */
-       base64_encoded_data += 8;
-
-       base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
-
-       stream = camel_stream_mem_new ();
-       size = camel_stream_write (
-               stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
-
-       if (size == -1)
-               goto out;
-
-       wrapper = camel_data_wrapper_new ();
-       camel_data_wrapper_construct_from_stream_sync (
-               wrapper, stream, NULL, NULL);
-       g_object_unref (stream);
-
-       camel_data_wrapper_set_mime_type (wrapper, mime_type);
-
-       part = camel_mime_part_new ();
-       camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
-       g_object_unref (wrapper);
-
-       cid = camel_header_msgid_generate (uid_domain);
-       camel_mime_part_set_content_id (part, cid);
-       g_free (cid);
-       name = webkit_dom_element_get_attribute (element, "data-name");
-       camel_mime_part_set_filename (part, name);
-       g_free (name);
-       camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
-out:
-       g_free (mime_type);
-       g_free (element_src);
-       g_free (base64_decoded_data);
-
-       return part;
-}
-
-GList *
-e_html_editor_view_get_parts_for_inline_images (EHTMLEditorView *view,
-                                               const gchar *uid_domain)
-{
-       GHashTable *added;
-       GList *parts = NULL;
-       gint length, ii;
-       WebKitDOMDocument *document;
-       WebKitDOMNodeList *list;
-
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW  (view));
-       list = webkit_dom_document_query_selector_all (document, "img[data-inline]", NULL);
-
-       length = webkit_dom_node_list_get_length (list);
-       if (length == 0)
-               return parts;
-
-       added = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
-       for (ii = 0; ii < length; ii++) {
-               const gchar *id;
-               gchar *cid;
-               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
-               gchar *src = webkit_dom_element_get_attribute (
-                       WEBKIT_DOM_ELEMENT (node), "src");
-
-               if ((id = g_hash_table_lookup (added, src)) != NULL) {
-                       cid = g_strdup_printf ("cid:%s", id);
-               } else {
-                       CamelMimePart *part;
-
-                       part = e_html_editor_view_add_inline_image_from_element (
-                               view, WEBKIT_DOM_ELEMENT (node), "src", uid_domain);
-                       parts = g_list_append (parts, part);
-
-                       id = camel_mime_part_get_content_id (part);
-                       cid = g_strdup_printf ("cid:%s", id);
-
-                       g_hash_table_insert (added, src, (gpointer) id);
-               }
-               webkit_dom_element_set_attribute (
-                       WEBKIT_DOM_ELEMENT (node), "src", cid, NULL);
-               g_free (src);
-               g_free (cid);
-       }
-       g_object_unref (list);
-
-       list = webkit_dom_document_query_selector_all (
-               document, "[data-inline][background]", NULL);
-       length = webkit_dom_node_list_get_length (list);
-       for (ii = 0; ii < length; ii++) {
-               CamelMimePart *part;
-               const gchar *id;
-               gchar *cid = NULL;
-               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
-               gchar *src = webkit_dom_element_get_attribute (
-                       WEBKIT_DOM_ELEMENT (node), "background");
-
-               if ((id = g_hash_table_lookup (added, src)) != NULL) {
-                       cid = g_strdup_printf ("cid:%s", id);
-                       webkit_dom_element_set_attribute (
-                               WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
-               } else {
-                       part = e_html_editor_view_add_inline_image_from_element (
-                               view, WEBKIT_DOM_ELEMENT (node), "background", uid_domain);
-                       if (part) {
-                               parts = g_list_append (parts, part);
-                               id = camel_mime_part_get_content_id (part);
-                               g_hash_table_insert (added, src, (gpointer) id);
-                               cid = g_strdup_printf ("cid:%s", id);
-                               webkit_dom_element_set_attribute (
-                                       WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
-                       }
-               }
-               g_free (src);
-               g_free (cid);
-       }
-
-       g_object_unref (list);
-       g_hash_table_destroy (added);
-
-       return parts;
-}
-
-/**
- * e_html_editor_view_add_inline_image_from_mime_part:
- * @composer: a composer object
- * @part: a CamelMimePart containing image data
- *
- * This adds the mime part @part to @composer as an inline image.
- **/
-void
-e_html_editor_view_add_inline_image_from_mime_part (EHTMLEditorView *view,
-                                                    CamelMimePart *part)
-{
-       CamelDataWrapper *dw;
-       CamelStream *stream;
-       GByteArray *byte_array;
-       gchar *src, *base64_encoded, *mime_type, *cid_src;
-       const gchar *cid, *name;
-
-       stream = camel_stream_mem_new ();
-       dw = camel_medium_get_content (CAMEL_MEDIUM (part));
-       g_return_if_fail (dw);
-
-       mime_type = camel_data_wrapper_get_mime_type (dw);
-       camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
-       camel_stream_close (stream, NULL, NULL);
-
-       byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
-
-       if (!byte_array->data)
-               return;
-
-       base64_encoded = g_base64_encode ((const guchar *) byte_array->data, byte_array->len);
-
-       name = camel_mime_part_get_filename (part);
-       /* Insert file name before new src */
-       src = g_strconcat (name, ";data:", mime_type, ";base64,", base64_encoded, NULL);
-
-       cid = camel_mime_part_get_content_id (part);
-       if (!cid) {
-               camel_mime_part_set_content_id (part, NULL);
-               cid = camel_mime_part_get_content_id (part);
-       }
-       cid_src = g_strdup_printf ("cid:%s", cid);
-
-       g_hash_table_insert (view->priv->inline_images, cid_src, src);
-
-       g_free (base64_encoded);
-       g_free (mime_type);
-       g_object_unref (stream);
-}
-
 void
 e_html_editor_view_set_is_message_from_draft (EHTMLEditorView *view,
                                               gboolean value)
diff --git a/e-util/e-html-editor-view.h b/e-util/e-html-editor-view.h
index 260bd25..bf6ae00 100644
--- a/e-util/e-html-editor-view.h
+++ b/e-util/e-html-editor-view.h
@@ -113,7 +113,9 @@ void                e_html_editor_view_set_magic_smileys
 ESpellChecker *        e_html_editor_view_get_spell_checker
                                                (EHTMLEditorView *view);
 gchar *                e_html_editor_view_get_text_html
-                                               (EHTMLEditorView *view);
+                                               (EHTMLEditorView *view,
+                                                const gchar *from_domain,
+                                                GList **inline_images);
 gchar *                e_html_editor_view_get_text_html_for_drafts
                                                (EHTMLEditorView *view);
 gchar *                e_html_editor_view_get_text_plain
@@ -162,9 +164,6 @@ void                e_html_editor_view_force_spell_check
 void           e_html_editor_view_add_inline_image_from_mime_part
                                                (EHTMLEditorView *view,
                                                  CamelMimePart *part);
-GList *                e_html_editor_view_get_parts_for_inline_images
-                                               (EHTMLEditorView *view,
-                                                const gchar *uid_domain);
 void           remove_image_attributes_from_element
                                                (WebKitDOMElement *element);
 gboolean       e_html_editor_view_is_message_from_draft
diff --git a/e-util/e-html-editor.c b/e-util/e-html-editor.c
index 750e005..c3e0914 100644
--- a/e-util/e-html-editor.c
+++ b/e-util/e-html-editor.c
@@ -1157,7 +1157,7 @@ e_html_editor_save (EHTMLEditor *editor,
 
        if (as_html)
                content = e_html_editor_view_get_text_html (
-                       E_HTML_EDITOR_VIEW (editor));
+                       E_HTML_EDITOR_VIEW (editor), NULL, NULL);
        else
                content = e_html_editor_view_get_text_plain (
                        E_HTML_EDITOR_VIEW (editor));
diff --git a/e-util/e-mail-signature-editor.c b/e-util/e-mail-signature-editor.c
index 45c4999..b75481f 100644
--- a/e-util/e-mail-signature-editor.c
+++ b/e-util/e-mail-signature-editor.c
@@ -835,7 +835,7 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
 
        if (e_html_editor_view_get_html_mode (view)) {
                mime_type = "text/html";
-               contents = e_html_editor_view_get_text_html (view);
+               contents = e_html_editor_view_get_text_html (view, NULL, NULL);
        } else {
                mime_type = "text/plain";
                contents = e_html_editor_view_get_text_plain (view);
diff --git a/e-util/test-html-editor.c b/e-util/test-html-editor.c
index 9bb8a3b..e393f87 100644
--- a/e-util/test-html-editor.c
+++ b/e-util/test-html-editor.c
@@ -166,10 +166,14 @@ view_source_dialog (EHTMLEditor *editor,
 
        if (plain_text) {
                html = e_html_editor_view_get_text_plain (
-                               e_html_editor_get_view (editor));
+                       e_html_editor_get_view (editor));
        } else {
+               GList *inline_images;
+
                html = e_html_editor_view_get_text_html (
-                       e_html_editor_get_view (editor));
+                       e_html_editor_get_view (editor), "test-domain", &inline_images);
+
+               g_list_free_full (inline_images, g_object_unref);
        }
 
        if (show_source || plain_text) {


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