[geary] Attach inline parts to outgoing messages. Bug 712995.



commit 4b946847f3ce5bd9d68fa45bc2ce182567d541c2
Author: Michael James Gratton <mike vee net>
Date:   Thu Sep 29 13:35:19 2016 +1000

    Attach inline parts to outgoing messages. Bug 712995.
    
    * src/engine/rfc822/rfc822-message.vala (Message::from_composed_email):
      Check for inline files on the ComposedEmail, if found create a new
      related multipart to encapsulate the HTML and its images.
      (Message::coalesce_related): New method that sets the Type header for
      multipart/related parts.
      (Message.get_file_part): Renamed from get_attachment_part, add
      disposition type arg to allow specifying if content disposition of the
      new part.
    
    * src/engine/api/geary-composed-email.vala (ComposedEmail): Replace
      attachment_files field with both attached_files and inline_files, so
      that inline attachments can be passed through to RFC822.Message.
    
    * src/client/composer/composer-widget.vala
      (ComposerWidget::get_composed_email): Set both attached and inline
      files on the composed email.

 src/client/composer/composer-widget.vala |    4 +-
 src/engine/api/geary-composed-email.vala |    7 ++-
 src/engine/rfc822/rfc822-message.vala    |   67 ++++++++++++++++++++++++------
 3 files changed, 61 insertions(+), 17 deletions(-)
---
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 92a6c9f..d95371e 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -978,8 +978,8 @@ public class ComposerWidget : Gtk.EventBox {
         if (!Geary.String.is_empty(this.subject))
             email.subject = this.subject;
 
-        email.attachment_files.add_all(this.attached_files);
-        //email.inline_files.add_all(this.inline_files);
+        email.attached_files.add_all(this.attached_files);
+        email.inline_files.add_all(this.inline_files);
 
         if (actions.get_action_state(ACTION_COMPOSE_AS_HTML).get_boolean() || only_html)
             email.body_html = get_html();
diff --git a/src/engine/api/geary-composed-email.vala b/src/engine/api/geary-composed-email.vala
index 9e9683f..3678893 100644
--- a/src/engine/api/geary-composed-email.vala
+++ b/src/engine/api/geary-composed-email.vala
@@ -31,9 +31,12 @@ public class Geary.ComposedEmail : BaseObject {
     public string? body_text { get; set; default = null; }
     public string? body_html { get; set; default = null; }
     public string? mailer { get; set; default = null; }
-    public Gee.Set<File> attachment_files { get; private set;
+
+    public Gee.Set<File> attached_files { get; private set;
         default = new Gee.HashSet<File>(Geary.Files.nullable_hash, Geary.Files.nullable_equal); }
-    
+    public Gee.Set<File> inline_files { get; private set;
+        default = new Gee.HashSet<File>(Geary.Files.nullable_hash, Geary.Files.nullable_equal); }
+
     public ComposedEmail(DateTime date, RFC822.MailboxAddresses from, 
         RFC822.MailboxAddresses? to = null, RFC822.MailboxAddresses? cc = null,
         RFC822.MailboxAddresses? bcc = null, string? subject = null,
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index b2f4923..a3322e3 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -168,7 +168,7 @@ public class Geary.RFC822.Message : BaseObject {
         }
 
         // Body: HTML format (also optional)
-        GMime.Part? body_html = null;
+        GMime.Object? body_html = null;
         if (email.body_html != null) {
             body_html = body_data_to_part(email.body_html.data,
                                           ref body_charset,
@@ -179,19 +179,50 @@ public class Geary.RFC822.Message : BaseObject {
 
         // Build the message's mime part.
         Gee.List<GMime.Object> main_parts = new Gee.LinkedList<GMime.Object>();
-        
+
         Gee.List<GMime.Object> body_parts = new Gee.LinkedList<GMime.Object>();
         if (body_text != null)
             body_parts.add(body_text);
-        if (body_html != null)
+
+        if (body_html != null) {
+            Gee.List<GMime.Object> related_parts =
+                new Gee.LinkedList<GMime.Object>();
+            if (!email.inline_files.is_empty) {
+                // Check inline images to be attached
+                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);
+                    }
+                }
+            }
+
+            if (!related_parts.is_empty) {
+                related_parts.insert(0, body_html);
+                GMime.Object? related_part =
+                   coalesce_related(related_parts, "text/html");
+                if (related_part != null)
+                    body_html = related_part;
+            }
+
             body_parts.add(body_html);
+        }
+
         GMime.Object? body_part = coalesce_parts(body_parts, "alternative");
         if (body_part != null)
             main_parts.add(body_part);
-        
+
         Gee.List<GMime.Object> attachment_parts = new Gee.LinkedList<GMime.Object>();
-        foreach (File attachment_file in email.attachment_files) {
-            GMime.Object? attachment_part = get_attachment_part(attachment_file);
+        foreach (File file in email.attached_files) {
+            GMime.Object? attachment_part = get_file_part(
+                file, Geary.Mime.DispositionType.ATTACHMENT
+            );
             if (attachment_part != null)
                 attachment_parts.add(attachment_part);
         }
@@ -235,7 +266,16 @@ public class Geary.RFC822.Message : BaseObject {
         
         message.set_mime_part(original_mime_part);
     }
-    
+
+    private GMime.Object? coalesce_related(Gee.List<GMime.Object> parts,
+                                           string type) {
+        GMime.Object? part = coalesce_parts(parts, "related");
+        if (parts.size > 1) {
+            part.set_header("Type", type);
+        }
+        return part;
+    }
+
     private GMime.Object? coalesce_parts(Gee.List<GMime.Object> parts, string subtype) {
         if (parts.size == 0) {
             return null;
@@ -248,11 +288,12 @@ public class Geary.RFC822.Message : BaseObject {
             return multipart;
         }
     }
-    
-    private GMime.Part? get_attachment_part(File file) {
+
+    private GMime.Part? get_file_part(File file,
+                                      Geary.Mime.DispositionType disposition) {
         if (!file.query_exists())
             return null;
-            
+
         FileInfo file_info;
         try {
             file_info = file.query_info(FileAttribute.STANDARD_CONTENT_TYPE, FileQueryInfoFlags.NONE);
@@ -260,12 +301,12 @@ public class Geary.RFC822.Message : BaseObject {
             debug("Error querying info from file: %s", err.message);
             return null;
         }
-        
+
         GMime.Part part = new GMime.Part();
-        part.set_disposition("attachment");
+        part.set_disposition(disposition.serialize());
         part.set_filename(file.get_basename());
         part.set_content_type(new GMime.ContentType.from_string(file_info.get_content_type()));
-        
+
         // This encoding is the initial encoding of the stream.
         GMime.StreamGIO stream = new GMime.StreamGIO(file);
         stream.set_owner(false);


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