[geary] Don't strip CRLF from iCal, vCard, and other formats that requires them.



commit 65b44c3b3aafb4cc4528f48a9bff4758fb645a5b
Author: Michael James Gratton <mike vee net>
Date:   Sun May 20 12:51:59 2018 +1000

    Don't strip CRLF from iCal, vCard, and other formats that requires them.
    
    * src/engine/rfc822/rfc822-part.vala (Part): Add a blacklist for text
      types that shouldn't have CRLF's stripped. Add unit tests.

 src/engine/rfc822/rfc822-part.vala |   32 ++++++++++++++++++++++++++++--
 test/engine/rfc822-part-test.vala  |   37 +++++++++++++++++++++++++++++++++--
 2 files changed, 63 insertions(+), 6 deletions(-)
---
diff --git a/src/engine/rfc822/rfc822-part.vala b/src/engine/rfc822/rfc822-part.vala
index 53bf846..4a3f65f 100644
--- a/src/engine/rfc822/rfc822-part.vala
+++ b/src/engine/rfc822/rfc822-part.vala
@@ -26,6 +26,27 @@ public class Geary.RFC822.Part : Object {
         HTML;
     }
 
+
+    // The set of text/* types that must have CRLF preserved, since it
+    // is part of their format. These really should be under
+    // application/*, but here we are.
+    private static Gee.Set<string> CR_PRESERVING_TEXT_TYPES =
+        new Gee.HashSet<string>();
+
+    static construct {
+        // VCard
+        CR_PRESERVING_TEXT_TYPES.add("vcard");
+        CR_PRESERVING_TEXT_TYPES.add("x-vcard");
+        CR_PRESERVING_TEXT_TYPES.add("directory");
+
+        // iCal
+        CR_PRESERVING_TEXT_TYPES.add("calendar");
+
+        // MS RTF
+        CR_PRESERVING_TEXT_TYPES.add("rtf");
+    }
+
+
     /**
      * The entity's Content-Type.
      *
@@ -157,9 +178,14 @@ public class Geary.RFC822.Part : Object {
             bool flowed = content_type.params.has_value_ci("format", "flowed");
             bool delsp = content_type.params.has_value_ci("DelSp", "yes");
 
-            // Unconditionally remove the CR's in any CRLF sequence, since
-            // they are effectively a wire encoding.
-            filter.add(new GMime.FilterCRLF(false, false));
+            // Remove the CR's in any CRLF sequence since they are
+            // effectively a wire encoding, unless the format requires
+            // them.
+            GMime.ContentEncoding encoding =
+                 this.source_part.get_content_encoding();
+            if (!(content_type.media_subtype in CR_PRESERVING_TEXT_TYPES)) {
+                filter.add(new GMime.FilterCRLF(false, false));
+            }
 
             if (flowed) {
                 filter.add(
diff --git a/test/engine/rfc822-part-test.vala b/test/engine/rfc822-part-test.vala
index 513232d..4a0a264 100644
--- a/test/engine/rfc822-part-test.vala
+++ b/test/engine/rfc822-part-test.vala
@@ -7,17 +7,22 @@
 
 class Geary.RFC822.PartTest : TestCase {
 
-    private const string BODY = "This is an attachment.\n";
+    private const string CR_BODY = "This is an attachment.\n";
+    private const string CRLF_BODY = "This is an attachment.\r\n";
+    private const string ICAL_BODY = "BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n";
 
 
     public PartTest() {
         base("Geary.RFC822.PartTest");
         add_test("new_from_empty_mime_part", new_from_empty_mime_part);
         add_test("new_from_complete_mime_part", new_from_complete_mime_part);
+        add_test("write_to_buffer_plain", write_to_buffer_plain);
+        add_test("write_to_buffer_plain_crlf", write_to_buffer_plain_crlf);
+        add_test("write_to_buffer_plain_ical", write_to_buffer_plain_ical);
     }
 
     public void new_from_empty_mime_part() throws Error {
-        GMime.Part part = new_part(null, BODY.data);
+        GMime.Part part = new_part(null, CR_BODY.data);
         part.set_header("Content-Type", "");
 
         Part test = new Part(part);
@@ -33,7 +38,7 @@ class Geary.RFC822.PartTest : TestCase {
         const string ID = "test-id";
         const string DESC = "test description";
 
-        GMime.Part part = new_part(TYPE, BODY.data);
+        GMime.Part part = new_part(TYPE, CR_BODY.data);
         part.set_content_id(ID);
         part.set_content_description(DESC);
         part.set_content_disposition(
@@ -52,6 +57,32 @@ class Geary.RFC822.PartTest : TestCase {
         );
     }
 
+    public void write_to_buffer_plain() throws Error {
+        Part test = new Part(new_part("text/plain", CR_BODY.data));
+
+        Memory.Buffer buf = test.write_to_buffer();
+
+        assert_string(CR_BODY, buf.to_string());
+    }
+
+    public void write_to_buffer_plain_crlf() throws Error {
+        Part test = new Part(new_part("text/plain", CRLF_BODY.data));
+
+        Memory.Buffer buf = test.write_to_buffer();
+
+        // CRLF should be stripped
+        assert_string(CR_BODY, buf.to_string());
+    }
+
+    public void write_to_buffer_plain_ical() throws Error {
+        Part test = new Part(new_part("text/calendar", ICAL_BODY.data));
+
+        Memory.Buffer buf = test.write_to_buffer();
+
+        // CRLF should not be stripped
+        assert_string(ICAL_BODY, buf.to_string());
+    }
+
     private GMime.Part new_part(string? mime_type,
                                 uint8[] body,
                                 GMime.ContentEncoding encoding = GMime.ContentEncoding.DEFAULT) {


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