[geary] Update IMG SRC values when sending HTML messages with inline images.



commit 210a911bf75e4c95b1ceb75d22d920d9d5877b67
Author: Michael James Gratton <mike vee net>
Date:   Thu Sep 29 14:57:13 2016 +1000

    Update IMG SRC values when sending HTML messages with inline images.
    
    Bug 712995.
    
    * src/engine/rfc822/rfc822-message.vala (Message::from_composed_email):
      Create inline image parts with content id's and update IMG SRC values to
      use those before creating HTML body part, so the message acually
      references the inline images.
    
    * src/client/composer/composer-widget.vala
      (ComposerWidget::get_composed_email): Update the image sourc prefix
      value on the ComposedEmail.
    
    * src/engine/api/geary-composed-email.vala (ComposedEmail): Add
      img_src_prefix prop and replace_inline_img_src() method to allow
      updating IMG SRC attr values.

 src/client/composer/composer-widget.vala |    2 +
 src/engine/api/geary-composed-email.vala |   31 +++++++++++++++++++++++++-
 src/engine/rfc822/rfc822-message.vala    |   36 +++++++++++++++++------------
 3 files changed, 53 insertions(+), 16 deletions(-)
---
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index d95371e..e4f3cbd 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -981,6 +981,8 @@ public class ComposerWidget : Gtk.EventBox {
         email.attached_files.add_all(this.attached_files);
         email.inline_files.add_all(this.inline_files);
 
+        email.img_src_prefix = this.editor_allow_prefix;
+
         if (actions.get_action_state(ACTION_COMPOSE_AS_HTML).get_boolean() || only_html)
             email.body_html = get_html();
         if (!only_html)
diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala
index 3678893..d4cb4a0 100644
--- a/src/engine/api/geary-composed-email.vala
+++ b/src/engine/api/geary-composed-email.vala
@@ -4,6 +4,9 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
+/**
+ * Encapsulates a message created by the user in the composer.
+ */
 public class Geary.ComposedEmail : BaseObject {
     public const string MAILTO_SCHEME = "mailto:";;
     
@@ -37,6 +40,8 @@ public class Geary.ComposedEmail : BaseObject {
     public Gee.Set<File> inline_files { get; private set;
         default = new Gee.HashSet<File>(Geary.Files.nullable_hash, Geary.Files.nullable_equal); }
 
+    public string img_src_prefix { get; set; default = ""; }
+
     public ComposedEmail(DateTime date, RFC822.MailboxAddresses from, 
         RFC822.MailboxAddresses? to = null, RFC822.MailboxAddresses? cc = null,
         RFC822.MailboxAddresses? bcc = null, string? subject = null,
@@ -54,5 +59,29 @@ public class Geary.ComposedEmail : BaseObject {
     public Geary.RFC822.Message to_rfc822_message(string? message_id = null) {
         return new RFC822.Message.from_composed_email(this, message_id);
     }
-}
 
+    /**
+     * Replaces the IMG SRC value in the HTML part of any matching strings.
+     *
+     * Will also remove the random prefix set by the composer for
+     * security reasons.
+     *
+     * Returns true if `orig` has been replaced by `replacement`.
+     */
+    public bool replace_inline_img_src(string orig, string replacement) {
+        const string src = "src=\"%s%s\"";
+        bool ret = false;
+        if (this.body_html != null) {
+            string old_body = this.body_html;
+            this.body_html = old_body.replace(
+                src.printf(this.img_src_prefix, orig),
+                src.printf("", replacement)
+            );
+            // Avoid doing a proper comparison so we don't need to scan
+            // the whole string again.
+            ret = this.body_html.length != old_body.length;
+        }
+        return ret;
+    }
+
+}
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index f802ca1..de69d85 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -173,30 +173,36 @@ public class Geary.RFC822.Message : BaseObject {
 
         // Body: HTML format (also optional)
         if (email.body_html != null) {
-            GMime.Object? body_html = body_data_to_part(email.body_html.data,
-                                                        ref body_charset,
-                                                        ref body_encoding,
-                                                        "text/html",
-                                                        false);
-
-            // Create parts for inline images, if any
+            // Create parts for inline images, if any, and updating
+            // the IMG SRC attributes as we go.
             Gee.List<GMime.Object> related_parts =
                 new Gee.LinkedList<GMime.Object>();
             if (!email.inline_files.is_empty) {
                 uint index = 0;
                 foreach (File file in email.inline_files) {
-                    GMime.Object? inline_part = get_file_part(
-                        file, Geary.Mime.DispositionType.INLINE
-                    );
-                    if (inline_part != null) {
-                        inline_part.set_content_id(
-                            "inline_%u@geary".printf(index++)
-                        );
-                        related_parts.add(inline_part);
+                    string cid = "inline_%u@geary".printf(index++);
+                    // Only include the inline file if it is actually
+                    // referenced by the HTML - it may have been
+                    // deleted by the user after being added
+                    if (email.replace_inline_img_src(file.get_uri(),
+                                                     "cid:" + cid)) {
+                        GMime.Object? inline_part = get_file_part(
+                            file, Geary.Mime.DispositionType.INLINE
+                            );
+                        if (inline_part != null) {
+                            inline_part.set_content_id(cid);
+                            related_parts.add(inline_part);
+                        }
                     }
                 }
             }
 
+            GMime.Object? body_html = body_data_to_part(email.body_html.data,
+                                                        ref body_charset,
+                                                        ref body_encoding,
+                                                        "text/html",
+                                                        false);
+
             // Assemble the HTML and inline images into a related
             // part, if needed
             if (!related_parts.is_empty) {


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