[geary/mjog/rfc822-cleanup: 10/15] Geary.RFC822: Clean up message data interfaces and classes



commit 6e7631b8d30febe0f4c238e2e5a3670f3d9e52d4
Author: Michael Gratton <mike vee net>
Date:   Wed May 6 11:27:00 2020 +1000

    Geary.RFC822: Clean up message data interfaces and classes
    
    Split Geary.RFC822.MessageData interface up into DecodedMessageData and
    EncodedMessageData so the difference between the two is clear and they
    can't be used interchangeably.
    
    Add `DecodedMessageData::to_rfc822_string` to provide a common interface
    for round-tripping decoded data.
    
    Update all classes to implement one of these and follow the same general
    API patterns.

 src/engine/imap-db/imap-db-message-row.vala        |   8 +-
 src/engine/imap/api/imap-folder-session.vala       |   4 +-
 .../imap/response/imap-fetch-data-decoder.vala     |   4 +-
 src/engine/rfc822/rfc822-mailbox-address.vala      |   5 +-
 src/engine/rfc822/rfc822-mailbox-addresses.vala    |   3 +-
 src/engine/rfc822/rfc822-message-data.vala         | 174 ++++++++++++++-------
 test/engine/app/app-conversation-monitor-test.vala |   2 +-
 test/engine/app/app-conversation-set-test.vala     |   2 +-
 test/engine/app/app-conversation-test.vala         |   2 +-
 test/engine/rfc822/rfc822-message-data-test.vala   |  10 +-
 10 files changed, 137 insertions(+), 77 deletions(-)
---
diff --git a/src/engine/imap-db/imap-db-message-row.vala b/src/engine/imap-db/imap-db-message-row.vala
index f7b065dc6..0b09a8cd4 100644
--- a/src/engine/imap-db/imap-db-message-row.vala
+++ b/src/engine/imap-db/imap-db-message-row.vala
@@ -106,7 +106,7 @@ private class Geary.ImapDB.MessageRow {
         if (fields.is_all_set(Geary.Email.Field.DATE)) {
             try {
                 email.set_send_date(
-                    !String.is_empty(date) ? new RFC822.Date(date) : null
+                    !String.is_empty(date) ? new RFC822.Date.from_rfc822_string(date) : null
                 );
             } catch (GLib.Error err) {
                 debug("Error loading message date from db: %s", err.message);
@@ -133,7 +133,7 @@ private class Geary.ImapDB.MessageRow {
         }
 
         if (fields.is_all_set(Geary.Email.Field.SUBJECT))
-            email.set_message_subject(new RFC822.Subject.decode(subject ?? ""));
+            email.set_message_subject(new RFC822.Subject.from_rfc822_string(subject ?? ""));
 
         if (fields.is_all_set(Geary.Email.Field.HEADER))
             email.set_message_header(new RFC822.Header(header ?? Memory.EmptyBuffer.instance));
@@ -191,7 +191,7 @@ private class Geary.ImapDB.MessageRow {
         // null if empty
 
         if (email.fields.is_all_set(Geary.Email.Field.DATE)) {
-            date = (email.date != null) ? email.date.original : null;
+            date = (email.date != null) ? email.date.to_rfc822_string() : null;
             date_time_t = (email.date != null) ? email.date.value.to_unix() : -1;
 
             fields = fields.set(Geary.Email.Field.DATE);
@@ -222,7 +222,7 @@ private class Geary.ImapDB.MessageRow {
         }
 
         if (email.fields.is_all_set(Geary.Email.Field.SUBJECT)) {
-            subject = (email.subject != null) ? email.subject.original : null;
+            subject = (email.subject != null) ? email.subject.to_rfc822_string() : null;
 
             fields = fields.set(Geary.Email.Field.SUBJECT);
         }
diff --git a/src/engine/imap/api/imap-folder-session.vala b/src/engine/imap/api/imap-folder-session.vala
index a934fecc5..e0e376870 100644
--- a/src/engine/imap/api/imap-folder-session.vala
+++ b/src/engine/imap/api/imap-folder-session.vala
@@ -901,7 +901,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
                 RFC822.Date? date = null;
                 if (!String.is_empty(value)) {
                     try {
-                        date = new RFC822.Date(value);
+                        date = new RFC822.Date.from_rfc822_string(value);
                     } catch (GLib.Error err) {
                         warning(
                             "Error parsing date from FETCH response: %s",
@@ -979,7 +979,7 @@ private class Geary.Imap.FolderSession : Geary.Imap.SessionObject {
             if (required_but_not_set(Geary.Email.Field.SUBJECT, required_fields, email)) {
                 string? value = headers.get("Subject");
                 if (value != null)
-                    email.set_message_subject(new RFC822.Subject.decode(value));
+                    email.set_message_subject(new RFC822.Subject.from_rfc822_string(value));
                 else
                     email.set_message_subject(null);
             }
diff --git a/src/engine/imap/response/imap-fetch-data-decoder.vala 
b/src/engine/imap/response/imap-fetch-data-decoder.vala
index 8f9f42b92..2d3cfce6d 100644
--- a/src/engine/imap/response/imap-fetch-data-decoder.vala
+++ b/src/engine/imap/response/imap-fetch-data-decoder.vala
@@ -148,7 +148,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
         Geary.RFC822.Date? sent_date = null;
         if (sent != null) {
             try {
-                sent_date = new RFC822.Date(sent.ascii);
+                sent_date = new RFC822.Date.from_rfc822_string(sent.ascii);
             } catch (GLib.Error err) {
                 debug(
                     "Error parsing sent date from FETCH envelope: %s",
@@ -159,7 +159,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
 
         return new Envelope(
             sent_date,
-            new Geary.RFC822.Subject.decode(subject.ascii),
+            new Geary.RFC822.Subject.from_rfc822_string(subject.ascii),
             parse_addresses(from), parse_addresses(sender), parse_addresses(reply_to),
             (to != null) ? parse_addresses(to) : null,
             (cc != null) ? parse_addresses(cc) : null,
diff --git a/src/engine/rfc822/rfc822-mailbox-address.vala b/src/engine/rfc822/rfc822-mailbox-address.vala
index 7b9ea3f68..f4f622cea 100644
--- a/src/engine/rfc822/rfc822-mailbox-address.vala
+++ b/src/engine/rfc822/rfc822-mailbox-address.vala
@@ -17,9 +17,10 @@
  * See [[https://tools.ietf.org/html/rfc5322#section-3.4]]
  */
 public class Geary.RFC822.MailboxAddress :
+    Geary.MessageData.AbstractMessageData,
     Geary.MessageData.SearchableMessageData,
     Gee.Hashable<MailboxAddress>,
-    BaseObject {
+    DecodedMessageData {
 
     private static unichar[] ATEXT = {
         '!', '#', '$', '%', '&', '\'', '*', '+', '-',
@@ -551,7 +552,7 @@ public class Geary.RFC822.MailboxAddress :
      *
      * @see to_rfc822_string
      */
-    public string to_string() {
+    public override string to_string() {
         return to_rfc822_string();
     }
 
diff --git a/src/engine/rfc822/rfc822-mailbox-addresses.vala b/src/engine/rfc822/rfc822-mailbox-addresses.vala
index 1e2bdc7c7..5890f23f6 100644
--- a/src/engine/rfc822/rfc822-mailbox-addresses.vala
+++ b/src/engine/rfc822/rfc822-mailbox-addresses.vala
@@ -17,7 +17,8 @@
 public class Geary.RFC822.MailboxAddresses :
     Geary.MessageData.AbstractMessageData,
     Geary.MessageData.SearchableMessageData,
-    Geary.RFC822.MessageData, Gee.Hashable<MailboxAddresses> {
+    Gee.Hashable<MailboxAddresses>,
+    DecodedMessageData {
 
 
     /**
diff --git a/src/engine/rfc822/rfc822-message-data.vala b/src/engine/rfc822/rfc822-message-data.vala
index fdd75ccd3..e228b3443 100644
--- a/src/engine/rfc822/rfc822-message-data.vala
+++ b/src/engine/rfc822/rfc822-message-data.vala
@@ -1,46 +1,75 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright © 2016 Software Freedom Conservancy Inc.
+ * Copyright © 2020 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
 /**
- * RFC822.MessageData represents a base class for all the various elements that may be present in
- * an RFC822 message header.  Note that some common elements (such as MailAccount) are not
- * MessageData because they exist in an RFC822 header in list (i.e. multiple email addresses) form.
+ * A base interface for objects that represent decoded RFC822 headers.
+ *
+ * The value of these objects is the decoded form of the header
+ * data. Encoded forms can be obtained via {@link to_rfc822_string}.
  */
+public interface Geary.RFC822.DecodedMessageData :
+    Geary.MessageData.AbstractMessageData {
+
+    /** Returns an RFC822-safe string representation of the data. */
+    public abstract string to_rfc822_string();
 
-public interface Geary.RFC822.MessageData : Geary.MessageData.AbstractMessageData {
 }
 
 /**
- * An RFC822 Message-ID.
+ * A base interface for objects that represent encoded RFC822 header data.
  *
- * MessageID will normalize all strings so that they begin and end with the proper brackets ("<" and
- * ">").
+ * The value of these objects is the RFC822 encoded form of the header
+ * data. Decoded forms can be obtained via means specific to
+ * implementations of this interface.
  */
-public class Geary.RFC822.MessageID : Geary.MessageData.StringMessageData, Geary.RFC822.MessageData {
+public interface Geary.RFC822.EncodedMessageData :
+    Geary.MessageData.BlockMessageData {
+
+}
+
+/**
+ * A RFC822 Message-ID.
+ *
+ * The decoded form of the id is the `addr-spec` portion, that is,
+ * without the leading `<` and tailing `>`.
+ */
+public class Geary.RFC822.MessageID :
+    Geary.MessageData.StringMessageData, DecodedMessageData {
+
+    private string rfc822;
+
     public MessageID(string value) {
-        string? normalized = normalize(value);
-        base (normalized ?? value);
+        base(value);
     }
 
-    // Adds brackets if required, null if no change required
-    private static string? normalize(string value) {
-        bool needs_prefix = !value.has_prefix("<");
-        bool needs_suffix = !value.has_suffix(">");
-        if (!needs_prefix && !needs_suffix)
-            return null;
+    public MessageID.from_rfc822_string(string rfc822) {
+        base(GMime.utils_decode_message_id(rfc822));
+        this.rfc822 = rfc822;
+    }
 
-        return "%s%s%s".printf(needs_prefix ? "<" : "", value, needs_suffix ? ">" : "");
+    /**
+     * Returns the {@link Date} in RFC 822 format.
+     */
+    public string to_rfc822_string() {
+        if (this.rfc822 == null) {
+            this.rfc822 = "<%s>".printf(this.value);
+        }
+        return this.rfc822;
     }
+
 }
 
 /**
  * A immutable list of RFC822 Message-ID values.
  */
-public class Geary.RFC822.MessageIDList : Geary.MessageData.AbstractMessageData, Geary.RFC822.MessageData {
-    public Gee.List<MessageID> list { get; private set; }
+public class Geary.RFC822.MessageIDList :
+    Geary.MessageData.AbstractMessageData,
+    DecodedMessageData {
 
 
     /** Returns the number of ids in this list. */
@@ -189,71 +218,87 @@ 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 class Geary.RFC822.Date :
+    Geary.MessageData.AbstractMessageData,
+    Gee.Hashable<Geary.RFC822.Date>,
+    DecodedMessageData {
+
+
+    public GLib.DateTime value { get; private set; }
+
+    private string? rfc822;
 
-    public string original { get; private set; }
-    public DateTime value { get; private set; }
 
-    public Date(string rfc822) throws RFC822Error {
+    public Date(GLib.DateTime datetime) {
+        this.value = datetime;
+        this.rfc822 = null;
+    }
+
+    public Date.from_rfc822_string(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.rfc822 = rfc822;
         this.value = date;
-        this.original = rfc822;
-    }
-
-    public Date.from_date_time(DateTime datetime) {
-        this.original = null;
-        this.value = datetime;
     }
 
     /**
      * Returns the {@link Date} in RFC 822 format.
      */
     public string to_rfc822_string() {
-        return GMime.utils_header_format_date(this.value);
-    }
-
-    /**
-     * Returns {@link Date} for transmission.
-     *
-     * @see to_rfc822_string
-     */
-    public virtual string serialize() {
-        return to_rfc822_string();
+        if (this.rfc822 == null) {
+            this.rfc822 = GMime.utils_header_format_date(this.value);
+        }
+        return this.rfc822;
     }
 
     public virtual bool equal_to(Geary.RFC822.Date other) {
-        return (this != other) ? value.equal(other.value) : true;
+        return this == other || this.value.equal(other.value);
     }
 
     public virtual uint hash() {
-        return value.hash();
+        return this.value.hash();
     }
 
     public override string to_string() {
-        return original ?? value.to_string();
+        return this.value.to_string();
     }
 
 }
 
-public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData,
-    Geary.MessageData.SearchableMessageData, Geary.RFC822.MessageData {
+public class Geary.RFC822.Subject :
+    Geary.MessageData.StringMessageData,
+    Geary.MessageData.SearchableMessageData,
+    DecodedMessageData {
+
     public const string REPLY_PREFACE = "Re:";
     public const string FORWARD_PREFACE = "Fwd:";
 
-    public string original { get; private set; }
+
+    private string rfc822;
+
 
     public Subject(string value) {
-        base (value);
-        original = value;
+        base(value);
+        this.rfc822 = null;
     }
 
-    public Subject.decode(string value) {
-        base (GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value));
-        original = value;
+    public Subject.from_rfc822_string(string rfc822) {
+        base(GMime.utils_header_decode_text(get_parser_options(), rfc822));
+        this.rfc822 = rfc822;
+    }
+
+    /**
+     * Returns the subject line encoded for an RFC 822 message.
+     */
+    public string to_rfc822_string() {
+        if (this.rfc822 == null) {
+            this.rfc822 = GMime.utils_header_encode_text(
+                get_format_options(), this.value, null
+            );
+        }
+        return this.rfc822;
     }
 
     public bool is_reply() {
@@ -312,9 +357,13 @@ public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData,
     public string to_searchable_string() {
         return value;
     }
+
 }
 
-public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData {
+public class Geary.RFC822.Header :
+    Geary.MessageData.BlockMessageData, EncodedMessageData {
+
+
     private GMime.Message? message = null;
     private string[]? names = null;
 
@@ -353,22 +402,30 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
         }
         return this.names;
     }
+
 }
 
-public class Geary.RFC822.Text : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData {
+public class Geary.RFC822.Text :
+    Geary.MessageData.BlockMessageData, EncodedMessageData {
+
     public Text(Memory.Buffer buffer) {
-        base ("RFC822.Text", buffer);
+        base("RFC822.Text", buffer);
     }
+
 }
 
-public class Geary.RFC822.Full : Geary.MessageData.BlockMessageData, Geary.RFC822.MessageData {
+public class Geary.RFC822.Full :
+    Geary.MessageData.BlockMessageData, EncodedMessageData {
+
     public Full(Memory.Buffer buffer) {
-        base ("RFC822.Full", buffer);
+        base("RFC822.Full", buffer);
     }
+
 }
 
-// Used for decoding preview text.
+/** Represents text providing a preview of an email's body. */
 public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
+
     public PreviewText(Memory.Buffer _buffer) {
         base (_buffer);
     }
@@ -415,4 +472,5 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
     public PreviewText.from_string(string preview) {
         base (new Geary.Memory.StringBuffer(preview));
     }
+
 }
diff --git a/test/engine/app/app-conversation-monitor-test.vala 
b/test/engine/app/app-conversation-monitor-test.vala
index 0dec7655f..3224cf8b4 100644
--- a/test/engine/app/app-conversation-monitor-test.vala
+++ b/test/engine/app/app-conversation-monitor-test.vala
@@ -434,7 +434,7 @@ class Geary.App.ConversationMonitorTest : TestCase {
                 references.message_id
             );
         }
-        email.set_send_date(new Geary.RFC822.Date.from_date_time(now));
+        email.set_send_date(new RFC822.Date(now));
         email.set_email_properties(new MockEmailProperties(now));
         email.set_full_references(mid, null, refs_list);
         return email;
diff --git a/test/engine/app/app-conversation-set-test.vala b/test/engine/app/app-conversation-set-test.vala
index 1250ad6a2..2966e1341 100644
--- a/test/engine/app/app-conversation-set-test.vala
+++ b/test/engine/app/app-conversation-set-test.vala
@@ -489,7 +489,7 @@ class Geary.App.ConversationSetTest : TestCase {
                 references.message_id
             );
         }
-        email.set_send_date(new Geary.RFC822.Date.from_date_time(now));
+        email.set_send_date(new RFC822.Date(now));
         email.set_email_properties(new MockEmailProperties(now));
         email.set_full_references(mid, null, refs_list);
         return email;
diff --git a/test/engine/app/app-conversation-test.vala b/test/engine/app/app-conversation-test.vala
index e6c731431..03ebd8f28 100644
--- a/test/engine/app/app-conversation-test.vala
+++ b/test/engine/app/app-conversation-test.vala
@@ -289,7 +289,7 @@ class Geary.App.ConversationTest : TestCase {
         );
         email.set_full_references(mid, null, null);
         email.set_email_properties(new MockEmailProperties(now));
-        email.set_send_date(new Geary.RFC822.Date.from_date_time(now));
+        email.set_send_date(new RFC822.Date(now));
         return email;
     }
 
diff --git a/test/engine/rfc822/rfc822-message-data-test.vala 
b/test/engine/rfc822/rfc822-message-data-test.vala
index 504efaa0c..dd9b2bf36 100644
--- a/test/engine/rfc822/rfc822-message-data-test.vala
+++ b/test/engine/rfc822/rfc822-message-data-test.vala
@@ -61,7 +61,7 @@ class Geary.RFC822.MessageDataTest : TestCase {
 
     public void date_from_rfc822() throws GLib.Error {
         const string FULL_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -0100";
-        Date full_hour_tz = new Date(FULL_HOUR_TZ);
+        Date full_hour_tz = new Date.from_rfc822_string(FULL_HOUR_TZ);
         assert_int64(
             ((int64) (-1 * 3600)) * 1000 * 1000,
             full_hour_tz.value.get_utc_offset(),
@@ -81,7 +81,7 @@ class Geary.RFC822.MessageDataTest : TestCase {
         );
 
         const string HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 +1030";
-        Date half_hour_tz = new Date(HALF_HOUR_TZ);
+        Date half_hour_tz = new Date.from_rfc822_string(HALF_HOUR_TZ);
         assert_int64(
             ((int64) (10.5 * 3600)) * 1000 * 1000,
             half_hour_tz.value.get_utc_offset()
@@ -96,15 +96,15 @@ class Geary.RFC822.MessageDataTest : TestCase {
 
     public void date_to_rfc822() throws GLib.Error {
         const string FULL_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -0100";
-        Date full_hour_tz = new Date(FULL_HOUR_TZ);
+        Date full_hour_tz = new Date.from_rfc822_string(FULL_HOUR_TZ);
         assert_string(FULL_HOUR_TZ, full_hour_tz.to_rfc822_string());
 
         const string HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 +1030";
-        Date half_hour_tz = new Date(HALF_HOUR_TZ);
+        Date half_hour_tz = new Date.from_rfc822_string(HALF_HOUR_TZ);
         assert_string(HALF_HOUR_TZ, half_hour_tz.to_rfc822_string());
 
         const string NEG_HALF_HOUR_TZ = "Thu, 28 Feb 2019 00:00:00 -1030";
-        Date neg_half_hour_tz = new Date(NEG_HALF_HOUR_TZ);
+        Date neg_half_hour_tz = new Date.from_rfc822_string(NEG_HALF_HOUR_TZ);
         assert_string(NEG_HALF_HOUR_TZ, neg_half_hour_tz.to_rfc822_string());
     }
 


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