[geary/mjog/dovecot-envelope-mailbox-quirk: 3/8] Geary.RFC822.MailboxAddress: Handle empty mailbox and domain parts better




commit cad31671d84e3e145517811d428847c933aeb41c
Author: Michael Gratton <mike vee net>
Date:   Mon Aug 17 13:57:15 2020 +1000

    Geary.RFC822.MailboxAddress: Handle empty mailbox and domain parts better
    
    If an address does not have an `@`, or if the IMAP constructor is called
    with empty mailbox or domain parts, then these properties will be empty.
    This is not uncommon, especially on UNIX hosts where system accounts
    send email.
    
    Ensure this is handled correctly in the constructors and are
    round-tripped correctly by `to_rfc822_address` and hence
    `to_rfc822_string`.

 src/engine/rfc822/rfc822-mailbox-address.vala      |  59 ++++--
 .../engine/rfc822/rfc822-mailbox-address-test.vala | 201 +++++++++++++--------
 2 files changed, 169 insertions(+), 91 deletions(-)
---
diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala
index 80cb01122..627d8b870 100644
--- a/src/engine/rfc822/rfc822-mailbox-address.vala
+++ b/src/engine/rfc822/rfc822-mailbox-address.vala
@@ -233,7 +233,18 @@ public class Geary.RFC822.MailboxAddress :
         this.source_route = source_route;
         this.mailbox = decode_address_part(mailbox);
         this.domain = domain;
-        this.address = "%s@%s".printf(mailbox, domain);
+
+        bool empty_mailbox = String.is_empty_or_whitespace(mailbox);
+        bool empty_domain = String.is_empty_or_whitespace(domain);
+        if (!empty_mailbox && !empty_domain) {
+            this.address = "%s@%s".printf(mailbox, domain);
+        } else if (empty_mailbox) {
+            this.address = domain;
+        } else if (empty_domain) {
+            this.address = mailbox;
+        } else {
+            this.address = "";
+        }
     }
 
     public MailboxAddress.from_rfc822_string(string rfc822) throws Error {
@@ -266,9 +277,11 @@ public class Geary.RFC822.MailboxAddress :
         // GMime strips source route for us, so the address part
         // should only ever contain a single '@'
         string? name = mailbox.get_name();
-        if (name != "") {
-            this.name = decode_name(name);
-        }
+        this.name = (
+            !String.is_empty_or_whitespace(name)
+            ? decode_name(name)
+            : null
+        );
 
         string address = mailbox.get_addr();
         int atsign = Ascii.last_index_of(address, '@');
@@ -286,7 +299,7 @@ public class Geary.RFC822.MailboxAddress :
         } else {
             this.mailbox = "";
             this.domain = "";
-            this.address = address;
+            this.address = decode_address_part(address);
         }
     }
 
@@ -502,15 +515,35 @@ public class Geary.RFC822.MailboxAddress :
         // GMime.utils_header_encode_text will use MIME encoding,
         // which is disallowed in mailboxes by RFC 2074 §5. So quote
         // manually.
-        string local_part = this.mailbox;
-        if (local_part_needs_quoting(local_part)) {
-            local_part = quote_string(local_part);
+        var address = "";
+        if (this.mailbox != "") {
+            address = this.mailbox;
+            if (local_part_needs_quoting(address)) {
+                address = quote_string(address);
+            }
+            if (this.domain != "") {
+                address = "%s@%s".printf(
+                    address,
+                    // XXX Need to punycode international domains.
+                    this.domain
+                );
+            } else {
+                address = this.domain;
+            }
         }
-        return "%s@%s".printf(
-            local_part,
-            // XXX Need to punycode international domains.
-            this.domain
-        );
+        if (address == "") {
+            // Both mailbox and domain are empty, i.e. there was no
+            // '@' symbol in the address, so just assume the address
+            // is a mailbox since this is not uncommon practice on
+            // UNIX systems where mail is sent from a local account,
+            // and it supports a greater range of characters than the
+            // domain component
+            address = this.address;
+            if (local_part_needs_quoting(address)) {
+                address = quote_string(address);
+            }
+        }
+        return address;
     }
 
     /**
diff --git a/test/engine/rfc822/rfc822-mailbox-address-test.vala 
b/test/engine/rfc822/rfc822-mailbox-address-test.vala
index 8718636de..e967c3813 100644
--- a/test/engine/rfc822/rfc822-mailbox-address-test.vala
+++ b/test/engine/rfc822/rfc822-mailbox-address-test.vala
@@ -9,6 +9,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
 
     public MailboxAddressTest() {
         base("Geary.RFC822.MailboxAddressTest");
+        add_test("imap_address", imap_address);
         add_test("is_valid_address", is_valid_address);
         add_test("unescaped_constructor", unescaped_constructor);
         add_test("from_rfc822_string_encoded", from_rfc822_string_encoded);
@@ -24,6 +25,25 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
         add_test("equal_to", equal_to);
     }
 
+    public void imap_address() throws GLib.Error {
+        assert_equal(
+            new MailboxAddress.imap(null, null, "test", "example.com").address,
+            "test example com"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "test", "").address,
+            "test"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "", "example.com").address,
+            "example.com"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "", "").address,
+            ""
+        );
+    }
+
     public void is_valid_address() throws GLib.Error {
         assert(Geary.RFC822.MailboxAddress.is_valid_address("john dep aol.museum") == true);
         assert(Geary.RFC822.MailboxAddress.is_valid_address("test example com") == true);
@@ -73,84 +93,93 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
     }
 
     public void from_rfc822_string_encoded() throws GLib.Error {
-        try {
-            MailboxAddress addr = new MailboxAddress.from_rfc822_string("test example com");
-            assert(addr.name == null);
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("\"test\"@example.com");
-            assert(addr.name == null);
-            assert(addr.address == "test example com");
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("=?UTF-8?b?dGVzdA==?=@example.com");
-            assert(addr.name == null);
-            assert(addr.address == "test example com");
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("\"=?UTF-8?b?dGVzdA==?=\"@example.com");
-            assert(addr.name == null);
-            assert(addr.address == "test example com");
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("<test example com>");
-            assert(addr.name == null);
-            assert(addr.address == "test example com");
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("<\"test\"@example.com>");
-            assert(addr.name == null);
-            assert(addr.address == "test example com");
-            assert(addr.mailbox == "test");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("Test 1 <test2 example com>");
-            assert(addr.name == "Test 1");
-            assert(addr.address == "test2 example com");
-            assert(addr.mailbox == "test2");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("\"Test 1\" <test2 example com>");
-            assert(addr.name == "Test 1");
-            assert(addr.address == "test2 example com");
-            assert(addr.mailbox == "test2");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("Test 1 <\"test2\"@example.com>");
-            assert(addr.name == "Test 1");
-            assert(addr.address == "test2 example com");
-            assert(addr.mailbox == "test2");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("=?UTF-8?b?VGVzdCAx?= <test2 example com>");
-            assert(addr.name == "Test 1");
-            assert(addr.address == "test2 example com");
-            assert(addr.mailbox == "test2");
-            assert(addr.domain == "example.com");
-
-            addr = new MailboxAddress.from_rfc822_string("\"=?UTF-8?b?VGVzdCAx?=\" <test2 example com>");
-            assert(addr.name == "Test 1");
-            assert(addr.address == "test2 example com");
-            assert(addr.mailbox == "test2");
-            assert(addr.domain == "example.com");
-
-            // Courtesy Mailsploit https://www.mailsploit.com
-            addr = new 
MailboxAddress.from_rfc822_string("\"=?utf-8?b?dGVzdCIgPHBvdHVzQHdoaXRlaG91c2UuZ292Pg==?==?utf-8?Q?=00=0A?=\" 
<demo mailsploit com>");
-            assert(addr.name == "test <potus whitehouse gov>?");
-            assert(addr.address == "demo mailsploit com");
-
-            // Courtesy Mailsploit https://www.mailsploit.com
-            addr = new 
MailboxAddress.from_rfc822_string("\"=?utf-8?Q?=42=45=47=49=4E=20=2F=20=28=7C=29=7C=3C=7C=3E=7C=40=7C=2C=7C=3B=7C=3A=7C=5C=7C=22=7C=2F=7C=5B=7C=5D=7C=3F=7C=2E=7C=3D=20=2F=20=00=20=50=41=53=53=45=44=20=4E=55=4C=4C=20=42=59=54=45=20=2F=20=0D=0A=20=50=41=53=53=45=44=20=43=52=4C=46=20=2F=20?==?utf-8?b?RU5E=?=\"");
-            assert(addr.name == null);
-            assert(addr.address == "BEGIN / (|)|<|>|@|,|;|:|\\|\"|/|[|]|?|.|= / ? PASSED NULL BYTE / \r\n 
PASSED CRLF / END");
-        } catch (Error err) {
-            assert_not_reached();
-        }
+        var encoded = "test example com";
+        var addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+
+        encoded = "\"test\"@example.com";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test example com", encoded);
+
+        encoded = "=?UTF-8?b?dGVzdA==?=@example.com";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test example com", encoded);
+
+        encoded = "\"=?UTF-8?b?dGVzdA==?=\"@example.com";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test example com", encoded);
+
+        encoded = "<test example com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test");
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test example com", encoded);
+
+        encoded = "<\"test\"@example.com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_null(addr.name, encoded);
+        assert_equal(addr.mailbox, "test", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test example com", encoded);
+
+        encoded = "Test 1 <test2 example com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "Test 1", encoded);
+        assert_equal(addr.mailbox, "test2", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test2 example com", encoded);
+
+        encoded = "\"Test 1\" <test2 example com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "Test 1", encoded);
+        assert_equal(addr.mailbox, "test2", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test2 example com", encoded);
+
+        encoded = "Test 1 <\"test2\"@example.com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "Test 1", encoded);
+        assert_equal(addr.mailbox, "test2", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test2 example com", encoded);
+
+        encoded = "=?UTF-8?b?VGVzdCAx?= <test2 example com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "Test 1", encoded);
+        assert_equal(addr.mailbox, "test2", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test2 example com", encoded);
+
+        encoded = "\"=?UTF-8?b?VGVzdCAx?=\" <test2 example com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "Test 1", encoded);
+        assert_equal(addr.mailbox, "test2", encoded);
+        assert_equal(addr.domain, "example.com", encoded);
+        assert_equal(addr.address, "test2 example com", encoded);
+
+        // Courtesy Mailsploit https://www.mailsploit.com
+        encoded = "\"=?utf-8?b?dGVzdCIgPHBvdHVzQHdoaXRlaG91c2UuZ292Pg==?==?utf-8?Q?=00=0A?=\" <demo 
mailsploit com>";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, "test <potus whitehouse gov>?", encoded);
+        assert_equal(addr.address, "demo mailsploit com", encoded);
+
+        // Courtesy Mailsploit https://www.mailsploit.com
+        encoded = 
"\"=?utf-8?Q?=42=45=47=49=4E=20=2F=20=28=7C=29=7C=3C=7C=3E=7C=40=7C=2C=7C=3B=7C=3A=7C=5C=7C=22=7C=2F=7C=5B=7C=5D=7C=3F=7C=2E=7C=3D=20=2F=20=00=20=50=41=53=53=45=44=20=4E=55=4C=4C=20=42=59=54=45=20=2F=20=0D=0A=20=50=41=53=53=45=44=20=43=52=4C=46=20=2F=20?==?utf-8?b?RU5E=?=\"";
+        addr = new MailboxAddress.from_rfc822_string(encoded);
+        assert_equal(addr.name, null, encoded);
+        assert_equal(addr.address, "BEGIN / (|)|<|>|@|,|;|:|\\|\"|/|[|]|?|.|= / ? PASSED NULL BYTE / \r\n 
PASSED CRLF / END", encoded);
     }
 
     public void prepare_header_text_part() throws GLib.Error {
@@ -286,6 +315,22 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
             "😸@example.com"
         );
 
+        assert_equal(
+            new MailboxAddress(null, "example1").to_rfc822_address(),
+            "example1"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "example2", "").to_rfc822_address(),
+            "example2"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "", "example3").to_rfc822_address(),
+            "example3"
+        );
+        assert_equal(
+            new MailboxAddress.imap(null, null, "", "").to_rfc822_address(),
+            ""
+        );
     }
 
     public void to_rfc822_string() throws GLib.Error {


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