[geary: 1/23] Change GMime dependency from 2.6.17 to 3.2.4



commit 1aac6f22847f2602b10b9f3da91d8d38a949ec0f
Author: Torben <torben letorbi gmail com>
Date:   Sat Nov 30 20:09:28 2019 +0100

    Change GMime dependency from 2.6.17 to 3.2.4
    
    This commit squashes several non-compiling commits:
    
    66dd6500 Change required GMime version to 3.2.4 or higher
    4b9c8a38 Fix some compilations errors in test code
    98aa5a2e Fix some (hopefully) last compilation errors
    558360c6 Fix parser format when getting message headers
    cc248ffc Fix name of stream-buffer mode
    b293c66b Fix another iteration over a header-list
    52fa183f Fix parsing of Gmime parameters
    e078ee62 Use Unix2Dos-, Dos2Unix- and/or SmtpData-filters instead of 'FilterCRLF'
    ff31b8e5 Fix setting of email headers
    eb676482 Fix compilation errros due to string-uint8-char conversion problems
    8558769f Fix datetime conversion
    d44a28cd Remove some obsolete arguments
    1ce81662 Pass charset where it's required
    6013806f Pass GMime.ParserOptions to header-decode methods
    986d05a0 Pass GMime.FormatOptions where it's required
    e9b93187 Pass GMime.ParserOptions where it's required
    640ce667 Fix compilation errors in GMime initialization
    312f80bf Remove use of GMime.HeaderIter
    acc73d14 Change GMime dependency from 2.6 to 3.0
    54fc250a Adapt names to 'offical' gmime-2.6 bindings
    
    The commits are part of the branch 'letorbi/gmime-3-spread', which can be
    found at: https://gitlab.gnome.org/letorbi/geary/tree/letorbi/gmime-3-spread

 meson.build                                        |   2 +-
 src/engine/imap-db/imap-db-attachment.vala         |   2 +-
 src/engine/mime/mime-content-disposition.vala      |   2 +-
 src/engine/mime/mime-content-parameters.vala       |  10 +-
 src/engine/mime/mime-content-type.vala             |   7 +-
 .../rfc822/rfc822-gmime-filter-blockquotes.vala    |   8 +-
 src/engine/rfc822/rfc822-gmime-filter-flowed.vala  |   6 +-
 src/engine/rfc822/rfc822-gmime-filter-plain.vala   |   6 +-
 src/engine/rfc822/rfc822-mailbox-address.vala      |  32 ++-
 src/engine/rfc822/rfc822-mailbox-addresses.vala    |  17 +-
 src/engine/rfc822/rfc822-message-data.vala         |  50 ++---
 src/engine/rfc822/rfc822-message.vala              | 215 ++++++++++++---------
 src/engine/rfc822/rfc822-part.vala                 |   4 +-
 src/engine/rfc822/rfc822-utils.vala                |   4 +-
 src/engine/rfc822/rfc822.vala                      |  24 +--
 test/engine/imap-db/imap-db-attachment-test.vala   |  20 +-
 test/engine/rfc822-part-test.vala                  |  12 +-
 17 files changed, 227 insertions(+), 194 deletions(-)
---
diff --git a/meson.build b/meson.build
index 62f092a6..c8e0c277 100644
--- a/meson.build
+++ b/meson.build
@@ -57,7 +57,7 @@ target_webkit = '2.24'
 
 # Primary deps
 glib = dependency('glib-2.0', version: '>=' + target_glib)
-gmime = dependency('gmime-2.6', version: '>= 2.6.17')
+gmime = dependency('gmime-3.0', version: '>= 3.2.4')
 gtk = dependency('gtk+-3.0', version: '>=' + target_gtk)
 sqlite = dependency('sqlite3', version: '>= 3.24')
 webkit2gtk = dependency('webkit2gtk-4.0', version: '>=' + target_webkit)
diff --git a/src/engine/imap-db/imap-db-attachment.vala b/src/engine/imap-db/imap-db-attachment.vala
index f2aacc25..4db81717 100644
--- a/src/engine/imap-db/imap-db-attachment.vala
+++ b/src/engine/imap-db/imap-db-attachment.vala
@@ -180,7 +180,7 @@ private class Geary.ImapDB.Attachment : Geary.Attachment {
             target_stream
         );
         stream = new GMime.StreamBuffer(
-            stream, GMime.StreamBufferMode.BLOCK_WRITE
+            stream, GMime.StreamBufferMode.WRITE
         );
 
         part.write_to_stream(stream, RFC822.Part.EncodingConversion.NONE);
diff --git a/src/engine/mime/mime-content-disposition.vala b/src/engine/mime/mime-content-disposition.vala
index 9b34849f..675aac75 100644
--- a/src/engine/mime/mime-content-disposition.vala
+++ b/src/engine/mime/mime-content-disposition.vala
@@ -102,7 +102,7 @@ public class Geary.Mime.ContentDisposition : Geary.BaseObject {
             out is_unknown);
         is_unknown_disposition_type = is_unknown;
         original_disposition_type_string = content_disposition.get_disposition();
-        params = new ContentParameters.from_gmime(content_disposition.get_params());
+        params = new ContentParameters.from_gmime(content_disposition.get_parameters());
     }
 }
 
diff --git a/src/engine/mime/mime-content-parameters.vala b/src/engine/mime/mime-content-parameters.vala
index 0267a9d5..cc201053 100644
--- a/src/engine/mime/mime-content-parameters.vala
+++ b/src/engine/mime/mime-content-parameters.vala
@@ -51,11 +51,13 @@ public class Geary.Mime.ContentParameters : BaseObject {
         }
     }
 
-    internal ContentParameters.from_gmime(GMime.Param? gmime_param) {
+    internal ContentParameters.from_gmime(GMime.ParamList? gmime_params) {
         Gee.Map<string,string> params = new Gee.HashMap<string,string>();
-        while (gmime_param != null) {
-            params.set(gmime_param.get_name(), gmime_param.get_value());
-            gmime_param = gmime_param.get_next();
+        if (gmime_params != null) {
+            for (int i=0; i < gmime_params.length(); i++) {
+              GMime.Param gmime_param = gmime_params.get_parameter_at(i);
+              params.set(gmime_param.get_name(), gmime_param.get_value());
+            }
         }
         this(params);
     }
diff --git a/src/engine/mime/mime-content-type.vala b/src/engine/mime/mime-content-type.vala
index ed59a491..9fe333d8 100644
--- a/src/engine/mime/mime-content-type.vala
+++ b/src/engine/mime/mime-content-type.vala
@@ -74,7 +74,10 @@ public class Geary.Mime.ContentType : Geary.BaseObject {
         if (!str.contains("/"))
             throw new MimeError.PARSE("Invalid MIME Content-Type: %s", str);
 
-        return new ContentType.from_gmime(new GMime.ContentType.from_string(str));
+        return new ContentType.from_gmime(GMime.ContentType.parse(
+          Geary.RFC822.get_parser_options(),
+          str
+        ));
     }
 
     /**
@@ -158,7 +161,7 @@ public class Geary.Mime.ContentType : Geary.BaseObject {
     internal ContentType.from_gmime(GMime.ContentType content_type) {
         media_type = content_type.get_media_type().strip();
         media_subtype = content_type.get_media_subtype().strip();
-        params = new ContentParameters.from_gmime(content_type.get_params());
+        params = new ContentParameters.from_gmime(content_type.get_parameters());
     }
 
     /**
diff --git a/src/engine/rfc822/rfc822-gmime-filter-blockquotes.vala 
b/src/engine/rfc822/rfc822-gmime-filter-blockquotes.vala
index 7d18342d..6f8c118f 100644
--- a/src/engine/rfc822/rfc822-gmime-filter-blockquotes.vala
+++ b/src/engine/rfc822/rfc822-gmime-filter-blockquotes.vala
@@ -49,7 +49,7 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
         return new_filter;
     }
 
-    private void do_filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    private void do_filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace, bool flush) {
 
         // This may not be strictly necessary.
@@ -64,7 +64,7 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
         }
 
         for (uint i = 0; i < inbuf.length; i++) {
-            char c = inbuf[i];
+            uint8 c = inbuf[i];
 
             if (in_prefix && !in_tag) {
                 if (c == Geary.RFC822.Utils.QUOTE_MARKER) {
@@ -122,12 +122,12 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
         outprespace = this.outpre;
     }
 
-    public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
         do_filter(inbuf, prespace, out processed_buffer, out outprespace, false);
     }
 
-    public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
         do_filter(inbuf, prespace, out processed_buffer, out outprespace, true);
     }
diff --git a/src/engine/rfc822/rfc822-gmime-filter-flowed.vala 
b/src/engine/rfc822/rfc822-gmime-filter-flowed.vala
index 3f5a28a9..d018c537 100644
--- a/src/engine/rfc822/rfc822-gmime-filter-flowed.vala
+++ b/src/engine/rfc822/rfc822-gmime-filter-flowed.vala
@@ -57,7 +57,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
         return new_filter;
     }
 
-    public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
 
         // Worst-case scenario: We are about to leave the prefix,
@@ -67,7 +67,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
 
         uint out_index = 0;
         for (uint i = 0; i < inbuf.length; i++) {
-            char c = inbuf[i];
+            uint8 c = inbuf[i];
 
             if (this.in_prefix) {
                 if (c == '>') {
@@ -147,7 +147,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
         outprespace = this.outpre;
     }
 
-    public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
         filter(inbuf, prespace, out processed_buffer, out outprespace);
     }
diff --git a/src/engine/rfc822/rfc822-gmime-filter-plain.vala 
b/src/engine/rfc822/rfc822-gmime-filter-plain.vala
index d66e3284..b38baac0 100644
--- a/src/engine/rfc822/rfc822-gmime-filter-plain.vala
+++ b/src/engine/rfc822/rfc822-gmime-filter-plain.vala
@@ -26,7 +26,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
         return new_filter;
     }
 
-    public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
 
         // This may not be strictly necessary.
@@ -34,7 +34,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
 
         uint out_index = 0;
         for (uint i = 0; i < inbuf.length; i++) {
-            char c = inbuf[i];
+            uint8 c = inbuf[i];
 
             if (in_prefix) {
                 if (c == '>') {
@@ -56,7 +56,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
         outprespace = this.outpre;
     }
 
-    public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
+    public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
         out size_t outprespace) {
         filter(inbuf, prespace, out processed_buffer, out outprespace);
     }
diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala
index 73803f19..1153cdd1 100644
--- a/src/engine/rfc822/rfc822-mailbox-address.vala
+++ b/src/engine/rfc822/rfc822-mailbox-address.vala
@@ -42,11 +42,17 @@ public class Geary.RFC822.MailboxAddress :
     }
 
     private static string decode_name(string name) {
-        return GMime.utils_header_decode_phrase(prepare_header_text_part(name));
+        return GMime.utils_header_decode_phrase(
+            Geary.RFC822.get_parser_options(),
+            prepare_header_text_part(name)
+        );
     }
 
     private static string decode_address_part(string mailbox) {
-        return GMime.utils_header_decode_text(prepare_header_text_part(mailbox));
+        return GMime.utils_header_decode_text(
+          Geary.RFC822.get_parser_options(),
+          prepare_header_text_part(mailbox)
+        );
     }
 
     private static bool display_name_needs_quoting(string name) {
@@ -118,8 +124,9 @@ public class Geary.RFC822.MailboxAddress :
         // _internet_address_decode_name() function.
 
         // see if a broken mailer has sent raw 8-bit information
-        string text = GMime.utils_text_is_8bit(part, part.length)
-            ? part : GMime.utils_decode_8bit(part, part.length);
+        string text = GMime.utils_text_is_8bit(part.data)
+            ? part : GMime.utils_decode_8bit(Geary.RFC822.get_parser_options(),
+                                            part.data);
 
         // unquote the string then decode the text
         GMime.utils_unquote_string(text);
@@ -222,16 +229,19 @@ public class Geary.RFC822.MailboxAddress :
     }
 
     public MailboxAddress.from_rfc822_string(string rfc822) throws RFC822Error {
-        InternetAddressList addrlist = InternetAddressList.parse_string(rfc822);
+        GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse(
+            Geary.RFC822.get_parser_options(),
+            rfc822
+        );
         if (addrlist == null)
             return;
 
         int length = addrlist.length();
         for (int ctr = 0; ctr < length; ctr++) {
-            InternetAddress? addr = addrlist.get_address(ctr);
+            GMime.InternetAddress? addr = addrlist.get_address(ctr);
 
             // TODO: Handle group lists
-            InternetAddressMailbox? mbox_addr = addr as InternetAddressMailbox;
+            GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox;
             if (mbox_addr != null) {
                 this.gmime(mbox_addr);
                 return;
@@ -240,7 +250,7 @@ public class Geary.RFC822.MailboxAddress :
         throw new RFC822Error.INVALID("Could not parse RFC822 address: %s", rfc822);
     }
 
-    public MailboxAddress.gmime(InternetAddressMailbox mailbox) {
+    public MailboxAddress.gmime(GMime.InternetAddressMailbox mailbox) {
         // GMime strips source route for us, so the address part
         // should only ever contain a single '@'
         string? name = mailbox.get_name();
@@ -456,7 +466,11 @@ public class Geary.RFC822.MailboxAddress :
     public string to_rfc822_string() {
         return has_distinct_name()
             ? "%s <%s>".printf(
-                GMime.utils_header_encode_phrase(this.name),
+                GMime.utils_header_encode_phrase(
+                    Geary.RFC822.get_format_options(),
+                    this.name,
+                    Geary.RFC822.get_charset()
+                ),
                 to_rfc822_address()
             )
             : to_rfc822_address();
diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala
index 8ebf79de..5d647fa7 100644
--- a/src/engine/rfc822/rfc822-mailbox-addresses.vala
+++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala
@@ -74,27 +74,30 @@ public class Geary.RFC822.MailboxAddresses :
     }
 
     public MailboxAddresses.from_rfc822_string(string rfc822) {
-        InternetAddressList addrlist = InternetAddressList.parse_string(rfc822);
+        GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse(
+            Geary.RFC822.get_parser_options(),
+            rfc822
+        );
         if (addrlist == null)
             return;
 
         int length = addrlist.length();
         for (int ctr = 0; ctr < length; ctr++) {
-            InternetAddress? addr = addrlist.get_address(ctr);
+            GMime.InternetAddress? addr = addrlist.get_address(ctr);
 
-            InternetAddressMailbox? mbox_addr = addr as InternetAddressMailbox;
+            GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox;
             if (mbox_addr != null) {
                 this.addrs.add(new MailboxAddress.gmime(mbox_addr));
             } else {
                 // XXX this is pretty bad - we just flatten the
                 // group's addresses into this list, merging lists and
                 // losing the group names.
-                InternetAddressGroup? mbox_group = addr as InternetAddressGroup;
+                GMime.InternetAddressGroup? mbox_group = addr as GMime.InternetAddressGroup;
                 if (mbox_group != null) {
-                    InternetAddressList group_list = mbox_group.get_members();
+                    GMime.InternetAddressList group_list = mbox_group.get_members();
                     for (int i = 0; i < group_list.length(); i++) {
-                        InternetAddressMailbox? group_addr =
-                            addrlist.get_address(i) as InternetAddressMailbox;
+                        GMime.InternetAddressMailbox? group_addr =
+                            addrlist.get_address(i) as GMime.InternetAddressMailbox;
                         if (group_addr != null) {
                             this.addrs.add(new MailboxAddress.gmime(group_addr));
                         }
diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala
index 2d399986..b5d62ad5 100644
--- a/src/engine/rfc822/rfc822-message-data.vala
+++ b/src/engine/rfc822/rfc822-message-data.vala
@@ -173,27 +173,13 @@ public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.Abs
     public DateTime value { get; private set; }
 
     public Date(string rfc822) throws ImapError {
-        int offset = 0;
-        int64 time_t_utc = GMime.utils_header_decode_date(rfc822, out offset);
-        if (time_t_utc == 0)
-            throw new ImapError.PARSE_ERROR(
-                "Unable to parse \"%s\": Not ISO-8601 date", rfc822
-            );
-
-        DateTime? value = new DateTime.from_unix_utc(time_t_utc);
+        DateTime? value = GMime.utils_header_decode_date(rfc822);
         if (value == null) {
             throw new ImapError.PARSE_ERROR(
                 "Unable to parse \"%s\": Outside supported range", rfc822
             );
         }
         this.value = value;
-
-        if (offset != 0) {
-            this.value = value.to_timezone(
-                new GLib.TimeZone("%+05d".printf(offset))
-            );
-        }
-
         this.original = rfc822;
     }
 
@@ -206,18 +192,7 @@ public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.Abs
      * Returns the {@link Date} in RFC 822 format.
      */
     public string to_rfc822_string() {
-        // Although GMime documents its conversion methods as
-        // requiring the tz offset in hours, it appears the number is
-        // handed directly to the string (i.e. an offset of -7:30 becomes
-        // "-0007", whereas we want "-0730").
-        int hours = (int) GLib.Math.floor(value.get_utc_offset() / TimeSpan.HOUR);
-        int minutes = (int) (
-            (value.get_utc_offset() % TimeSpan.HOUR) / (double) TimeSpan.HOUR * 60
-        );
-        return GMime.utils_header_format_date(
-            (time_t) this.value.to_utc().to_unix(),
-            (hours * 100) + minutes
-        );
+        return GMime.utils_header_format_date(this.value);
     }
 
     /**
@@ -261,7 +236,7 @@ public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData,
     }
 
     public Subject.decode(string value) {
-        base (GMime.utils_header_decode_text(value));
+        base (GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value));
         original = value;
     }
 
@@ -337,9 +312,10 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
 
         GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(buffer));
         parser.set_respect_content_length(false);
-        parser.set_scan_from(false);
+        // TODO Could this be omitted?
+        parser.set_format(GMime.Format.MESSAGE);
 
-        message = parser.construct_message();
+        message = parser.construct_message(Geary.RFC822.get_parser_options());
         if (message == null)
             throw new RFC822Error.INVALID("Unable to parse RFC 822 headers");
 
@@ -347,17 +323,15 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
     }
 
     public string? get_header(string name) throws RFC822Error {
-        return get_headers().get(name);
+        return get_headers().get_header(name).get_value();
     }
 
     public string[] get_header_names() throws RFC822Error {
         if (this.names == null) {
             this.names = new string[0];
-            GMime.HeaderIter iter = new GMime.HeaderIter();
-            if (get_headers().get_iter(iter) && iter.first()) {
-                do {
-                    names += iter.get_name();
-                } while (iter.next());
+            GMime.HeaderList headers = get_headers();
+            for (int i = 0; i < headers.get_count(); i++) {
+                names += headers.get_header_at(i).get_name();
             }
         }
         return this.names;
@@ -388,7 +362,7 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
         // Parse the header.
         GMime.Stream header_stream = Utils.create_stream_mem(preview_header);
         GMime.Parser parser = new GMime.Parser.with_stream(header_stream);
-        GMime.Part? gpart = parser.construct_part() as GMime.Part;
+        GMime.Part? gpart = parser.construct_part(Geary.RFC822.get_parser_options()) as GMime.Part;
         if (gpart != null) {
             Part part = new Part(gpart);
 
@@ -402,7 +376,7 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
                     new GMime.StreamMem.with_buffer(preview.get_uint8_array()),
                     gpart.get_content_encoding()
                 );
-                gpart.set_content_object(body);
+                gpart.set_content(body);
 
                 try {
                     Memory.Buffer preview_buffer = part.write_to_buffer(
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index 02d4b397..8a94cf2c 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -29,6 +29,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
      */
     public delegate string? InlinePartReplacer(Part part);
 
+    private const string HEADER_DATE = "Date";
     private const string HEADER_SENDER = "Sender";
     private const string HEADER_IN_REPLY_TO = "In-Reply-To";
     private const string HEADER_REFERENCES = "References";
@@ -89,7 +90,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
     public Message(Full full) throws RFC822Error {
         GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(full.buffer));
 
-        message = parser.construct_message();
+        message = parser.construct_message(Geary.RFC822.get_parser_options());
         if (message == null)
             throw new RFC822Error.INVALID("Unable to parse RFC 822 message");
 
@@ -115,7 +116,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data()));
 
         GMime.Parser parser = new GMime.Parser.with_stream(stream_cat);
-        message = parser.construct_message();
+        message = parser.construct_message(Geary.RFC822.get_parser_options());
         if (message == null)
             throw new RFC822Error.INVALID("Unable to parse RFC 822 message");
 
@@ -136,67 +137,71 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         this.from = email.from;
         this.date = email.date;
 
-        // GMimeMessage.set_sender actually sets the From header - and
-        // although the API docs make it sound otherwise, it also
-        // supports a list of addresses
-        message.set_sender(this.from.to_rfc822_string());
-        message.set_date_as_string(this.date.serialize());
-        if (message_id != null) {
-            this.message_id = new MessageID(message_id);
-            message.set_message_id(message_id);
+        //message.set_date_as_string(this.date.serialize());
+        this.message.set_header(HEADER_DATE,
+                                this.date.serialize(),
+                                Geary.RFC822.get_charset());
+        
+        if (email.from != null) {
+            foreach (RFC822.MailboxAddress mailbox in email.from)
+                this.message.add_mailbox(GMime.AddressType.FROM, mailbox.name, mailbox.address);
+        }
+
+        if (email.sender != null) {
+            this.message.add_mailbox(GMime.AddressType.SENDER, this.sender.name, this.sender.address);
+            // TODO Is setting the header still required?
+            this.message.set_header(HEADER_SENDER,
+                                    this.sender.to_rfc822_string(),
+                                    Geary.RFC822.get_charset());
         }
 
         // Optional headers
         if (email.to != null) {
             this.to = email.to;
             foreach (RFC822.MailboxAddress mailbox in email.to)
-                this.message.add_recipient(GMime.RecipientType.TO, mailbox.name, mailbox.address);
+                this.message.add_mailbox(GMime.AddressType.TO, mailbox.name, mailbox.address);
         }
 
         if (email.cc != null) {
             this.cc = email.cc;
             foreach (RFC822.MailboxAddress mailbox in email.cc)
-                this.message.add_recipient(GMime.RecipientType.CC, mailbox.name, mailbox.address);
+                this.message.add_mailbox(GMime.AddressType.CC, mailbox.name, mailbox.address);
         }
 
         if (email.bcc != null) {
             this.bcc = email.bcc;
             foreach (RFC822.MailboxAddress mailbox in email.bcc)
-                this.message.add_recipient(GMime.RecipientType.BCC, mailbox.name, mailbox.address);
-        }
-
-        if (email.sender != null) {
-            this.sender = email.sender;
-            this.message.set_header(HEADER_SENDER,
-                                    email.sender.to_rfc822_string());
-        }
-
-        if (email.reply_to != null) {
-            this.reply_to = email.reply_to;
-            this.message.set_reply_to(email.reply_to.to_rfc822_string());
+                this.message.add_mailbox(GMime.AddressType.BCC, mailbox.name, mailbox.address);
         }
 
         if (email.in_reply_to != null) {
             this.in_reply_to = email.in_reply_to;
+            foreach (RFC822.MailboxAddress mailbox in email.reply_to)
+                this.message.add_mailbox(GMime.AddressType.BCC, mailbox.name, mailbox.address);
+            // TODO Is setting the header still required?
             this.message.set_header(HEADER_IN_REPLY_TO,
-                                    email.in_reply_to.to_rfc822_string());
+                                    email.in_reply_to.to_rfc822_string(),
+                                    Geary.RFC822.get_charset());
         }
 
         if (email.references != null) {
             this.references = email.references;
             this.message.set_header(HEADER_REFERENCES,
-                                    email.references.to_rfc822_string());
+                                    email.references.to_rfc822_string(),
+                                    Geary.RFC822.get_charset());
         }
 
         if (email.subject != null) {
             this.subject = email.subject;
-            this.message.set_subject(email.subject.value);
+            this.message.set_subject(email.subject.value,
+                                     Geary.RFC822.get_charset());
         }
 
         // User-Agent
         if (!Geary.String.is_empty(email.mailer)) {
             this.mailer = email.mailer;
-            this.message.set_header(HEADER_MAILER, email.mailer);
+            this.message.set_header(HEADER_MAILER, email.mailer,
+                                    Geary.RFC822.get_charset());
         }
 
         // Build the message's body mime parts
@@ -406,7 +411,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
                                            string type) {
         GMime.Object? part = coalesce_parts(parts, "related");
         if (parts.size > 1) {
-            part.set_header("Type", type);
+            part.set_header("Type", type, Geary.RFC822.get_charset());
         }
         return part;
     }
@@ -437,7 +442,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         part.set_disposition(disposition.serialize());
         part.set_filename(file.get_basename());
 
-        GMime.ContentType content_type = new GMime.ContentType.from_string(
+        GMime.ContentType content_type = GMime.ContentType.parse(
+            Geary.RFC822.get_parser_options(),
             file_info.get_content_type()
         );
         part.set_content_type(content_type);
@@ -468,7 +474,10 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
                 );
         }
 
-        GMime.ContentType? content_type = new GMime.ContentType.from_string(mime_type.get_mime_type());
+        GMime.ContentType? content_type = GMime.ContentType.parse(
+            Geary.RFC822.get_parser_options(),
+            mime_type.get_mime_type()
+        );
 
         if (content_type == null) {
             throw new RFC822Error.INVALID(
@@ -515,7 +524,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         }
 
         part.set_content_encoding(encoding);
-        part.set_content_object(
+        part.set_content(
             new GMime.DataWrapper.with_stream(
                 stream, GMime.ContentEncoding.BINARY
             )
@@ -536,7 +545,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         Geary.Email email = new Geary.Email(id);
 
         email.set_message_header(new Geary.RFC822.Header(new Geary.Memory.StringBuffer(
-            message.get_headers())));
+            message.get_headers(Geary.RFC822.get_format_options()))));
         email.set_send_date(date);
         email.set_originators(from, sender, reply_to);
         email.set_receivers(to, cc, bcc);
@@ -884,68 +893,72 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
     }
 
     private void stock_from_gmime() {
-        this.message.get_header_list().foreach((name, value) => {
-                switch (name.down()) {
-                case "from":
-                    this.from = append_address(this.from, value);
-                    break;
-
-                case "sender":
-                    try {
-                        this.sender = new RFC822.MailboxAddress.from_rfc822_string(value);
-                    } catch (Error err) {
-                        debug("Could parse subject: %s", err.message);
-                    }
-                    break;
+        GMime.HeaderList headers = this.message.get_header_list();
+        for (int i=0; i < headers.get_count(); i++) {
+            GMime.Header header = headers.get_header_at(i);
+            string name = header.get_name();
+            string value = header.get_value();
+            switch (name.down()) {
+            case "from":
+                this.from = append_address(this.from, value);
+                break;
+
+            case "sender":
+                try {
+                    this.sender = new RFC822.MailboxAddress.from_rfc822_string(value);
+                } catch (Error err) {
+                    debug("Could parse subject: %s", err.message);
+                }
+                break;
 
-                case "reply-to":
-                    this.reply_to = append_address(this.reply_to, value);
-                    break;
+            case "reply-to":
+                this.reply_to = append_address(this.reply_to, value);
+                break;
 
-                case "to":
-                    this.to = append_address(this.to, value);
-                    break;
+            case "to":
+                this.to = append_address(this.to, value);
+                break;
 
-                case "cc":
-                    this.cc = append_address(this.cc, value);
-                    break;
+            case "cc":
+                this.cc = append_address(this.cc, value);
+                break;
 
-                case "bcc":
-                    this.bcc = append_address(this.bcc, value);
-                    break;
+            case "bcc":
+                this.bcc = append_address(this.bcc, value);
+                break;
 
-                case "subject":
-                    this.subject = new RFC822.Subject.decode(value);
-                    break;
+            case "subject":
+                this.subject = new RFC822.Subject.decode(value);
+                break;
 
-                case "date":
-                    try {
-                        this.date = new Geary.RFC822.Date(value);
-                    } catch (Error err) {
-                        debug("Could not parse date: %s", err.message);
-                    }
-                    break;
+            case "date":
+                try {
+                    this.date = new Geary.RFC822.Date(value);
+                } catch (Error err) {
+                    debug("Could not parse date: %s", err.message);
+                }
+                break;
 
-                case "message-id":
-                    this.message_id = new MessageID(value);
-                    break;
+            case "message-id":
+                this.message_id = new MessageID(value);
+                break;
 
-                case "in-reply-to":
-                    this.in_reply_to = append_message_id(this.in_reply_to, value);
-                    break;
+            case "in-reply-to":
+                this.in_reply_to = append_message_id(this.in_reply_to, value);
+                break;
 
-                case "references":
-                    this.references = append_message_id(this.references, value);
-                    break;
+            case "references":
+                this.references = append_message_id(this.references, value);
+                break;
 
-                case "x-mailer":
-                    this.mailer = GMime.utils_header_decode_text(value);
-                    break;
+            case "x-mailer":
+                this.mailer = GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value);
+                break;
 
-                default:
-                    break;
-                }
-            });
+            default:
+                break;
+            }
+        };
     }
 
     private MailboxAddresses append_address(MailboxAddresses? existing,
@@ -990,11 +1003,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 
             if (requested_disposition == Mime.DispositionType.UNSPECIFIED || disposition == 
requested_disposition) {
                 GMime.Stream stream = new GMime.StreamMem();
-                message.write_to_stream(stream);
+                message.write_to_stream(Geary.RFC822.get_format_options(), stream);
                 GMime.DataWrapper data = new GMime.DataWrapper.with_stream(stream,
                     GMime.ContentEncoding.BINARY);  // Equivalent to no encoding
                 GMime.Part part = new GMime.Part.with_type("message", "rfc822");
-                part.set_content_object(data);
+                part.set_content(data);
                 part.set_filename((message.get_subject() ?? _("(no subject)")) + ".eml");
                 attachments.add(new Part(part));
             }
@@ -1017,7 +1030,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 #if WITH_TNEF_SUPPORT
                 if (content_type.is_type("application", "vnd.ms-tnef")) {
                     GMime.StreamMem stream = new GMime.StreamMem();
-                    ((GMime.Part) root).get_content_object().write_to_stream(stream);
+                    ((GMime.Part) root).get_content().write_to_stream(stream);
                     ByteArray tnef_data = stream.get_byte_array();
                     Ytnef.TNEFStruct tn;
                     if (Ytnef.ParseMemory(tnef_data.data, out tn) == 0) {
@@ -1052,8 +1065,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 
         GMime.Part part = new GMime.Part();
         part.set_filename(filename);
-        part.set_content_type(new GMime.ContentType.from_string(GLib.ContentType.guess(filename, data, 
null)));
-        part.set_content_object(new GMime.DataWrapper.with_stream(new GMime.StreamMem.with_buffer(data), 
GMime.ContentEncoding.BINARY));
+        part.set_content_type(GMime.ContentType.parse(Geary.RFC822.get_parser_options(), 
GLib.ContentType.guess(filename, data, null)));
+        part.set_content(new GMime.DataWrapper.with_stream(new GMime.StreamMem.with_buffer(data), 
GMime.ContentEncoding.BINARY));
         return part;
     }
 #endif
@@ -1092,9 +1105,17 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         stream.set_owner(false);
 
         GMime.StreamFilter stream_filter = new GMime.StreamFilter(stream);
-        stream_filter.add(new GMime.FilterCRLF(encoded, dotstuffed));
+        if (encoded) {
+            stream_filter.add(new GMime.FilterUnix2Dos(false));
+        }
+        else {
+            stream_filter.add(new GMime.FilterDos2Unix(false));
+        }
+        if (dotstuffed) {
+            stream_filter.add(new GMime.FilterSmtpData());
+        }
 
-        if (message.write_to_stream(stream_filter) < 0)
+        if (message.write_to_stream(Geary.RFC822.get_format_options(), stream_filter) < 0)
             throw new RFC822Error.FAILED("Unable to write RFC822 message to memory buffer");
 
         if (stream_filter.flush() != 0)
@@ -1104,7 +1125,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
     }
 
     public string to_string() {
-        return message.to_string();
+        return message.to_string(Geary.RFC822.get_format_options());
     }
 
     /**
@@ -1152,11 +1173,13 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
             // Base64-encoded text needs to have CR's added after LF's
             // before encoding, otherwise it breaks format=flowed. See
             // Bug 753528.
-            filter_stream.add(new GMime.FilterCRLF(true, false));
+            filter_stream.add(new GMime.FilterUnix2Dos(false));
         }
 
-        GMime.ContentType complete_type =
-            new GMime.ContentType.from_string(content_type);
+        GMime.ContentType complete_type = GMime.ContentType.parse(
+                                              Geary.RFC822.get_parser_options(),
+                                              content_type
+                                          );
         complete_type.set_parameter("charset", charset);
         if (is_flowed) {
             complete_type.set_parameter("format", "flowed");
@@ -1168,7 +1191,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 
         GMime.Part body_part = new GMime.Part();
         body_part.set_content_type(complete_type);
-        body_part.set_content_object(body);
+        body_part.set_content(body);
         body_part.set_content_encoding(encoding);
         return body_part;
     }
diff --git a/src/engine/rfc822/rfc822-part.vala b/src/engine/rfc822/rfc822-part.vala
index b8a3b2a8..6d0521d1 100644
--- a/src/engine/rfc822/rfc822-part.vala
+++ b/src/engine/rfc822/rfc822-part.vala
@@ -160,7 +160,7 @@ public class Geary.RFC822.Part : Object {
                                   BodyFormatting format = BodyFormatting.NONE)
         throws RFC822Error {
         GMime.DataWrapper? wrapper = (this.source_part != null)
-            ? this.source_part.get_content_object() : null;
+            ? this.source_part.get_content() : null;
         if (wrapper == null) {
             throw new RFC822Error.INVALID(
                 "Could not get the content wrapper for content-type %s",
@@ -201,7 +201,7 @@ public class Geary.RFC822.Part : Object {
             if ((this.source_part == null ||
                  this.source_part.encoding != BASE64) &&
                 !(content_type.media_subtype in CR_PRESERVING_TEXT_TYPES)) {
-                filter.add(new GMime.FilterCRLF(false, false));
+                filter.add(new GMime.FilterDos2Unix(false));
             }
 
             if (flowed) {
diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala
index 37a967fb..d9278f64 100644
--- a/src/engine/rfc822/rfc822-utils.vala
+++ b/src/engine/rfc822/rfc822-utils.vala
@@ -186,7 +186,7 @@ public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses
 }
 
 
-public bool comp_char_arr_slice(char[] array, uint start, string comp) {
+public bool comp_char_arr_slice(uint8[] array, uint start, string comp) {
     for (int i = 0; i < comp.length; i++) {
         if (array[start + i] != comp[i])
             return false;
@@ -277,7 +277,7 @@ public async string get_best_charset(GMime.Stream in_stream,
         },
         cancellable
     );
-    return filter.charset();
+    return filter.get_charset();
 }
 
 /**
diff --git a/src/engine/rfc822/rfc822.vala b/src/engine/rfc822/rfc822.vala
index 9195eac1..39a400e5 100644
--- a/src/engine/rfc822/rfc822.vala
+++ b/src/engine/rfc822/rfc822.vala
@@ -32,18 +32,7 @@ public void init() {
     if (init_count++ != 0)
         return;
 
-    GMime.init(GMime.ENABLE_RFC2047_WORKAROUNDS);
-
-    // This has the effect of ensuring all non US-ASCII and non-ISO-8859-1
-    // headers are always encoded as UTF-8. This should be fine because
-    // message bodies are also always sent as UTF-8.
-    const string?[] USER_CHARSETS =  {
-        UTF8_CHARSET,
-        // GMime.set_user_charsets calls g_strdupv under the hood, so
-        // the array needs to be null-terminated
-        null
-    };
-    GMime.set_user_charsets(USER_CHARSETS);
+    GMime.init();
 
     try {
         invalid_filename_character_re = new Regex("[/\\0]");
@@ -52,6 +41,17 @@ public void init() {
     }
 }
 
+public GMime.FormatOptions get_format_options() {
+    return new GMime.FormatOptions();
+}
+
+public GMime.ParserOptions get_parser_options() {
+    return new GMime.ParserOptions();
+}
+
+public string? get_charset() {
+    return null;
+}
 
 internal bool is_utf_8(string charset) {
     string up = charset.up();
diff --git a/test/engine/imap-db/imap-db-attachment-test.vala 
b/test/engine/imap-db/imap-db-attachment-test.vala
index d24f2b8d..9366802e 100644
--- a/test/engine/imap-db/imap-db-attachment-test.vala
+++ b/test/engine/imap-db/imap-db-attachment-test.vala
@@ -21,7 +21,7 @@ class Geary.ImapDB.AttachmentTest : TestCase {
 
     public void new_from_minimal_mime_part() throws Error {
         GMime.Part part = new_part(null, ATTACHMENT_BODY.data);
-        part.set_header("Content-Type", "");
+        part.set_header("Content-Type", "", Geary.RFC822.get_charset());
 
         Attachment test = new Attachment.from_part(
             1, new Geary.RFC822.Part(part)
@@ -51,7 +51,8 @@ class Geary.ImapDB.AttachmentTest : TestCase {
         part.set_content_id(ID);
         part.set_content_description(DESC);
         part.set_content_disposition(
-            new GMime.ContentDisposition.from_string(
+            GMime.ContentDisposition.parse(
+                Geary.RFC822.get_parser_options(),
                 "attachment; filename=%s".printf(NAME)
             )
         );
@@ -74,7 +75,10 @@ class Geary.ImapDB.AttachmentTest : TestCase {
     public void new_from_inline_mime_part() throws Error {
         GMime.Part part = new_part(null, ATTACHMENT_BODY.data);
         part.set_content_disposition(
-            new GMime.ContentDisposition.from_string("inline")
+            GMime.ContentDisposition.parse(
+                Geary.RFC822.get_parser_options(),
+                "inline"
+            )
         );
 
         Attachment test = new Attachment.from_part(
@@ -205,7 +209,8 @@ CREATE TABLE MessageAttachmentTable (
         part.set_content_id(ID);
         part.set_content_description(DESCRIPTION);
         part.set_content_disposition(
-            new GMime.ContentDisposition.from_string(
+            GMime.ContentDisposition.parse(
+                Geary.RFC822.get_parser_options(),
                 "inline; filename=%s;".printf(FILENAME)
             ));
 
@@ -352,12 +357,15 @@ private GMime.Part new_part(string? mime_type,
                             GMime.ContentEncoding encoding = GMime.ContentEncoding.DEFAULT) {
     GMime.Part part = new GMime.Part();
     if (mime_type != null) {
-        part.set_content_type(new GMime.ContentType.from_string(mime_type));
+        part.set_content_type(GMime.ContentType.parse(
+            Geary.RFC822.get_parser_options(),
+            mime_type
+        ));
     }
     GMime.DataWrapper body_wrapper = new GMime.DataWrapper.with_stream(
         new GMime.StreamMem.with_buffer(body),
         encoding
     );
-    part.set_content_object(body_wrapper);
+    part.set_content(body_wrapper);
     return part;
 }
diff --git a/test/engine/rfc822-part-test.vala b/test/engine/rfc822-part-test.vala
index b6e82e60..4fbe5d87 100644
--- a/test/engine/rfc822-part-test.vala
+++ b/test/engine/rfc822-part-test.vala
@@ -40,7 +40,10 @@ class Geary.RFC822.PartTest : TestCase {
         part.set_content_id(ID);
         part.set_content_description(DESC);
         part.set_content_disposition(
-            new GMime.ContentDisposition.from_string("inline")
+            GMime.ContentDisposition.parse(
+                Geary.RFC822.get_parser_options(),
+                "inline"
+            )
         );
 
         Part test = new Part(part);
@@ -93,13 +96,16 @@ class Geary.RFC822.PartTest : TestCase {
                                 uint8[] body) {
         GMime.Part part = new GMime.Part();
         if (mime_type != null) {
-            part.set_content_type(new GMime.ContentType.from_string(mime_type));
+            part.set_content_type(GMime.ContentType.parse(
+                Geary.RFC822.get_parser_options(),
+                mime_type
+            ));
         }
         GMime.DataWrapper body_wrapper = new GMime.DataWrapper.with_stream(
             new GMime.StreamMem.with_buffer(body),
             GMime.ContentEncoding.BINARY
         );
-        part.set_content_object(body_wrapper);
+        part.set_content(body_wrapper);
         part.encode(GMime.EncodingConstraint.7BIT);
         return part;
     }



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