[geary/mjog/rfc822-cleanup: 5/21] Geary.RFC822: Ensure various data constructors throw errors



commit c6bb391f4bc08268a77a15525eb53b1e0958af12
Author: Michael Gratton <mike vee net>
Date:   Tue May 5 21:48:11 2020 +1000

    Geary.RFC822: Ensure various data constructors throw errors
    
    Rather than just silently ignoring error conditions, throw RFC822
    errors instead.

 src/client/accounts/accounts-manager.vala       |  13 +-
 src/client/composer/composer-email-entry.vala   |  11 +-
 src/engine/imap-db/imap-db-message-row.vala     |  28 +++--
 src/engine/imap/message/imap-message-data.vala  |  10 +-
 src/engine/rfc822/rfc822-mailbox-address.vala   |  34 +++---
 src/engine/rfc822/rfc822-mailbox-addresses.vala |  13 +-
 src/engine/rfc822/rfc822-message-data.vala      |  60 +++++-----
 src/engine/rfc822/rfc822-message.vala           | 153 ++++++++++++------------
 test/engine/rfc822-message-test.vala            |   3 +-
 test/integration/smtp/client-session.vala       |   3 +-
 10 files changed, 172 insertions(+), 156 deletions(-)
---
diff --git a/src/client/accounts/accounts-manager.vala b/src/client/accounts/accounts-manager.vala
index f6d5749f5..7b7c101ca 100644
--- a/src/client/accounts/accounts-manager.vala
+++ b/src/client/accounts/accounts-manager.vala
@@ -1274,10 +1274,15 @@ public class Accounts.AccountConfigLegacy : AccountConfig, GLib.Object {
             ALTERNATE_EMAILS_KEY
         );
         foreach (string alt_email in alt_email_list) {
-            Geary.RFC822.MailboxAddresses mailboxes =
-                new Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email);
-            foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) {
-                info.append_sender(mailbox);
+            try {
+                var mailboxes = new Geary.RFC822.MailboxAddresses.from_rfc822_string(alt_email);
+                foreach (Geary.RFC822.MailboxAddress mailbox in mailboxes.get_all()) {
+                    info.append_sender(mailbox);
+                }
+            } catch (Geary.RFC822Error error) {
+                throw new ConfigError.SYNTAX(
+                    "Invalid alternate email: %s", error.message
+                );
             }
         }
 
diff --git a/src/client/composer/composer-email-entry.vala b/src/client/composer/composer-email-entry.vala
index b5e87314c..cd4202b0b 100644
--- a/src/client/composer/composer-email-entry.vala
+++ b/src/client/composer/composer-email-entry.vala
@@ -81,9 +81,14 @@ public class Composer.EmailEntry : Gtk.Entry {
             this._addresses = new Geary.RFC822.MailboxAddresses();
             this.is_valid = false;
         } else {
-            this._addresses =
-                new Geary.RFC822.MailboxAddresses.from_rfc822_string(text);
-            this.is_valid = true;
+            try {
+                this._addresses =
+                    new Geary.RFC822.MailboxAddresses.from_rfc822_string(text);
+                this.is_valid = true;
+            } catch (Geary.RFC822Error err) {
+                this._addresses = new Geary.RFC822.MailboxAddresses();
+                this.is_valid = false;
+            }
         }
     }
 
diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala
index 36a4699b8..4744a9572 100644
--- a/src/engine/imap-db/imap-db-message-row.vala
+++ b/src/engine/imap-db/imap-db-message-row.vala
@@ -272,20 +272,22 @@ private class Geary.ImapDB.MessageRow {
         return (addrs == null || addrs.size == 0) ? null : addrs.to_rfc822_string();
     }
 
-    private RFC822.MailboxAddress? unflatten_address(string? str) {
-        RFC822.MailboxAddress? addr = null;
-        if (str != null) {
-            try {
-                addr = new RFC822.MailboxAddress.from_rfc822_string(str);
-            } catch (RFC822Error e) {
-                // oh well
-            }
-        }
-        return addr;
+    private RFC822.MailboxAddress? unflatten_address(string? str)
+        throws RFC822Error {
+        return (
+            String.is_empty_or_whitespace(str)
+            ? null
+            : new RFC822.MailboxAddress.from_rfc822_string(str)
+        );
     }
 
-    private RFC822.MailboxAddresses? unflatten_addresses(string? str) {
-        return String.is_empty(str) ? null : new RFC822.MailboxAddresses.from_rfc822_string(str);
+    private RFC822.MailboxAddresses? unflatten_addresses(string? str)
+        throws RFC822Error {
+        return (
+            String.is_empty_or_whitespace(str)
+            ? null
+            : new RFC822.MailboxAddresses.from_rfc822_string(str)
+        );
     }
-}
 
+}
diff --git a/src/engine/imap/message/imap-message-data.vala b/src/engine/imap/message/imap-message-data.vala
index e4d423ff0..07c10f3cd 100644
--- a/src/engine/imap/message/imap-message-data.vala
+++ b/src/engine/imap/message/imap-message-data.vala
@@ -26,8 +26,13 @@ public class Geary.Imap.RFC822Size : Geary.RFC822.Size, Geary.Imap.MessageData {
 }
 
 public class Geary.Imap.RFC822Header : Geary.RFC822.Header, Geary.Imap.MessageData {
-    public RFC822Header(Memory.Buffer buffer) {
-        base (buffer);
+    public RFC822Header(Memory.Buffer buffer)
+        throws ImapError {
+        try {
+            base(buffer);
+        } catch (RFC822Error error) {
+            throw new ImapError.INVALID(error.message);
+        }
     }
 }
 
@@ -42,4 +47,3 @@ public class Geary.Imap.RFC822Full : Geary.RFC822.Full, Geary.Imap.MessageData {
         base (buffer);
     }
 }
-
diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala
index 6d994136c..5f5ad87e2 100644
--- a/src/engine/rfc822/rfc822-mailbox-address.vala
+++ b/src/engine/rfc822/rfc822-mailbox-address.vala
@@ -233,21 +233,27 @@ public class Geary.RFC822.MailboxAddress :
             Geary.RFC822.get_parser_options(),
             rfc822
         );
-        if (addrlist == null)
-            return;
-
-        int length = addrlist.length();
-        for (int ctr = 0; ctr < length; ctr++) {
-            GMime.InternetAddress? addr = addrlist.get_address(ctr);
-
-            // TODO: Handle group lists
-            GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox;
-            if (mbox_addr != null) {
-                this.gmime(mbox_addr);
-                return;
-            }
+        if (addrlist == null) {
+            throw new RFC822Error.INVALID(
+                "Not a RFC822 mailbox address: %s", rfc822
+            );
+        }
+        if (addrlist.length() != 1) {
+            throw new RFC822Error.INVALID(
+                "Not a single RFC822 mailbox address: %s", rfc822
+            );
         }
-        throw new RFC822Error.INVALID("Could not parse RFC822 address: %s", rfc822);
+
+        GMime.InternetAddress? addr = addrlist.get_address(0);
+        // TODO: Handle group lists
+        var mbox_addr = addr as GMime.InternetAddressMailbox;
+        if (mbox_addr == null) {
+            throw new RFC822Error.INVALID(
+                "Group lists not currently supported: %s", rfc822
+            );
+        }
+
+        this.gmime(mbox_addr);
     }
 
     public MailboxAddress.gmime(GMime.InternetAddressMailbox mailbox) {
diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala
index 4afd096de..41886acba 100644
--- a/src/engine/rfc822/rfc822-mailbox-addresses.vala
+++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala
@@ -78,13 +78,12 @@ public class Geary.RFC822.MailboxAddresses :
         this.addrs.add(addr);
     }
 
-    public MailboxAddresses.from_rfc822_string(string rfc822) {
-        GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse(
-            Geary.RFC822.get_parser_options(),
-            rfc822
-        );
-        if (addrlist == null)
-            return;
+    public MailboxAddresses.from_rfc822_string(string rfc822)
+        throws RFC822Error {
+        var addrlist = GMime.InternetAddressList.parse(null, rfc822);
+        if (addrlist == null) {
+            throw new RFC822Error.INVALID("Not a RFC822 mailbox address list");
+        }
 
         int length = addrlist.length();
         for (int ctr = 0; ctr < length; ctr++) {
diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala
index d4a3aa0aa..e7f5df124 100644
--- a/src/engine/rfc822/rfc822-message-data.vala
+++ b/src/engine/rfc822/rfc822-message-data.vala
@@ -169,17 +169,15 @@ public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData,
 public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.AbstractMessageData,
     Gee.Hashable<Geary.RFC822.Date> {
 
-    public string? original { get; private set; }
+    public string original { get; private set; }
     public DateTime value { get; private set; }
 
-    public Date(string rfc822) throws ImapError {
-        DateTime? value = GMime.utils_header_decode_date(rfc822);
-        if (value == null) {
-            throw new ImapError.PARSE_ERROR(
-                "Unable to parse \"%s\": Outside supported range", rfc822
-            );
+    public Date(string rfc822) throws RFC822Error {
+        var date = GMime.utils_header_decode_date(rfc822);
+        if (date == null) {
+            throw new RFC822Error.INVALID("Not ISO-8601 date: %s", rfc822);
         }
-        this.value = value;
+        this.value = date;
         this.original = rfc822;
     }
 
@@ -302,42 +300,38 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
     private GMime.Message? message = null;
     private string[]? names = null;
 
-    public Header(Memory.Buffer buffer) {
+    public Header(Memory.Buffer buffer) throws RFC822Error {
         base("RFC822.Header", buffer);
-    }
 
-    private unowned GMime.HeaderList get_headers() throws RFC822Error {
-        if (message != null)
-            return message.get_header_list();
-
-        GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(buffer));
+        var parser = new GMime.Parser.with_stream(
+            Utils.create_stream_mem(buffer)
+        );
         parser.set_respect_content_length(false);
+        parser.set_format(MESSAGE);
 
-        message = parser.construct_message(Geary.RFC822.get_parser_options());
-        if (message == null)
+        this.message = parser.construct_message(null);
+        if (this.message == null) {
             throw new RFC822Error.INVALID("Unable to parse RFC 822 headers");
-
-        return message.get_header_list();
+        }
     }
 
-    public string? get_header(string name) throws RFC822Error {
-        GMime.Header header = get_headers().get_header(name);
-        if (header != null)
-            // We should not parse the raw-value here, but use GMime's parsing
-            // functionality instead.
-            // See: https://gitlab.gnome.org/GNOME/geary/merge_requests/382#note_669699
-            return GMime.utils_header_unfold(header.get_raw_value());
-        else
-            return null;
+    public string? get_header(string name) {
+        string? value = null;
+        var header = this.message.get_header_list().get_header(name);
+        if (header != null) {
+            value = header.get_value();
+        }
+        return value;
     }
 
-    public string[] get_header_names() throws RFC822Error {
+    public string[] get_header_names() {
         if (this.names == null) {
-            this.names = new string[0];
-            GMime.HeaderList headers = get_headers();
-            for (int i = 0; i < headers.get_count(); i++) {
-                names += headers.get_header_at(i).get_name();
+            GMime.HeaderList headers = this.message.get_header_list();
+            var names = new string[headers.get_count()];
+            for (int i = 0; i < names.length; i++) {
+                names[i] = headers.get_header_at(0).get_name();
             }
+            this.names = names;
         }
         return this.names;
     }
diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala
index 4ef341c8e..ff63f58eb 100644
--- a/src/engine/rfc822/rfc822-message.vala
+++ b/src/engine/rfc822/rfc822-message.vala
@@ -6,6 +6,7 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
+
 /**
  * An RFC-822 style email message.
  *
@@ -99,16 +100,19 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         stock_from_gmime();
     }
 
-    public Message.from_gmime_message(GMime.Message message) {
+    public Message.from_gmime_message(GMime.Message message)
+        throws RFC822Error {
         this.message = message;
         stock_from_gmime();
     }
 
-    public Message.from_buffer(Memory.Buffer full_email) throws RFC822Error {
+    public Message.from_buffer(Memory.Buffer full_email)
+        throws RFC822Error {
         this(new Geary.RFC822.Full(full_email));
     }
 
-    public Message.from_parts(Header header, Text body) throws RFC822Error {
+    public Message.from_parts(Header header, Text body)
+        throws RFC822Error {
         GMime.StreamCat stream_cat = new GMime.StreamCat();
         stream_cat.add_source(new GMime.StreamMem.with_buffer(header.buffer.get_bytes().get_data()));
         stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data()));
@@ -126,9 +130,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
 
     public async Message.from_composed_email(Geary.ComposedEmail email,
                                              string? message_id,
-                                             GLib.Cancellable? cancellable) {
+                                             GLib.Cancellable? cancellable)
+        throws RFC822Error {
         this.message = new GMime.Message(true);
 
+        //
         // Required headers
 
         this.from = email.from;
@@ -802,7 +808,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
      * disabled by passing false in include_sub_messages).  Note that values
      * that come out of this function are persisted.
      */
-    public string? get_searchable_body(bool include_sub_messages = true) {
+    public string? get_searchable_body(bool include_sub_messages = true)
+        throws RFC822Error {
         string? body = null;
         bool html = false;
         try {
@@ -880,81 +887,70 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         return attachments;
     }
 
-    private void stock_from_gmime() {
-        GMime.HeaderList headers = this.message.get_header_list();
+    private void stock_from_gmime() throws RFC822Error {
+        GMime.HeaderList headers = this.message.headers;
         for (int i = 0; i < headers.get_count(); i++) {
             GMime.Header header = headers.get_header_at(i);
-            string name = header.get_name();
-            // We should not parse the raw-value here, but use GMime's parsing
-            // functionality instead.
-            // See: https://gitlab.gnome.org/GNOME/geary/merge_requests/382#note_669699
-            string value = GMime.utils_header_unfold(header.get_raw_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 "to":
-                  this.to = append_address(this.to, value);
-              break;
-
-              case "cc":
-                  this.cc = append_address(this.cc, value);
-              break;
-
-              case "bcc":
-                  this.bcc = append_address(this.bcc, 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 "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 "references":
-                  this.references = append_message_id(this.references, value);
-              break;
-
-              case "x-mailer":
-                  this.mailer = GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value);
-              break;
-
-              default:
-                // do nothing
-              break;
+            string value = header.get_value();
+            switch (header.get_name().down()) {
+            case "from":
+                this.from = append_address(this.from, value);
+                break;
+
+            case "sender":
+                this.sender = new MailboxAddress.from_rfc822_string(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 "cc":
+                this.cc = append_address(this.cc, value);
+                break;
+
+            case "bcc":
+                this.bcc = append_address(this.bcc, value);
+                break;
+
+            case "subject":
+                this.subject = new Subject.decode(value);
+                break;
+
+            case "date":
+                this.date = new Date(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 "references":
+                this.references = append_message_id(this.references, value);
+                break;
+
+            case "x-mailer":
+                this.mailer = GMime.utils_header_decode_text(null, value);
+                break;
+
+            default:
+                // Ignore anything else not
+                break;
             }
-        };
+        }
     }
 
     private MailboxAddresses append_address(MailboxAddresses? existing,
-                                            string header_value) {
+                                            string header_value)
+        throws RFC822Error {
         MailboxAddresses addresses = new MailboxAddresses.from_rfc822_string(header_value);
         if (existing != null) {
             addresses = existing.append(addresses);
@@ -1063,13 +1059,16 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
     }
 #endif
 
-    public Gee.List<Geary.RFC822.Message> get_sub_messages() {
+    public Gee.List<Geary.RFC822.Message> get_sub_messages()
+        throws RFC822Error {
         Gee.List<Geary.RFC822.Message> messages = new Gee.ArrayList<Geary.RFC822.Message>();
         find_sub_messages(messages, message.get_mime_part());
         return messages;
     }
 
-    private void find_sub_messages(Gee.List<Geary.RFC822.Message> messages, GMime.Object root) {
+    private void find_sub_messages(Gee.List<Message> messages,
+                                   GMime.Object root)
+        throws RFC822Error {
         // If this is a multipart container, check each of its children.
         GMime.Multipart? multipart = root as GMime.Multipart;
         if (multipart != null) {
@@ -1084,7 +1083,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
         if (messagepart != null) {
             GMime.Message sub_message = messagepart.get_message();
             if (sub_message != null) {
-                messages.add(new Geary.RFC822.Message.from_gmime_message(sub_message));
+                messages.add(new Message.from_gmime_message(sub_message));
             } else {
                 warning("Corrupt message, possibly bug 769697");
             }
diff --git a/test/engine/rfc822-message-test.vala b/test/engine/rfc822-message-test.vala
index cc3f0a405..979fcccb1 100644
--- a/test/engine/rfc822-message-test.vala
+++ b/test/engine/rfc822-message-test.vala
@@ -371,7 +371,8 @@ This is the second line.
         assert_true(out_buffer.size > (buffer.size+buffer2.size), "Expected sizeable message");
     }
 
-    private async Geary.RFC822.Message message_from_composed_email(Geary.ComposedEmail composed) {
+    private async Message message_from_composed_email(ComposedEmail composed)
+        throws RFC822Error {
         return yield new Geary.RFC822.Message.from_composed_email(
             composed,
             GMime.utils_generate_message_id(composed.from.get(0).domain),
diff --git a/test/integration/smtp/client-session.vala b/test/integration/smtp/client-session.vala
index b6c0c8017..33ee89d02 100644
--- a/test/integration/smtp/client-session.vala
+++ b/test/integration/smtp/client-session.vala
@@ -118,7 +118,8 @@ class Integration.Smtp.ClientSession : TestCase {
     }
 
     private async Geary.RFC822.Message new_message(Geary.RFC822.MailboxAddress from,
-                                                   Geary.RFC822.MailboxAddress to) {
+                                                   Geary.RFC822.MailboxAddress to)
+        throws Geary.RFC822Error {
         Geary.ComposedEmail composed = new Geary.ComposedEmail(
             new GLib.DateTime.now_local(),
             new Geary.RFC822.MailboxAddresses.single(from)


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