[geary] Stricter naming and controls on converting string data to ASCII



commit 2c0e29552a83ef8da3c511e12cb4f4ee9d064ff0
Author: Jim Nelson <jim yorba org>
Date:   Tue Nov 4 14:18:48 2014 -0800

    Stricter naming and controls on converting string data to ASCII
    
    This is the result of the recent fix for Turkish locale users.  That
    patch was sufficient to solve their issue, but this patch is more
    thorough in naming to ensure in the future it's understood that the
    IMAP StringParameter objects deal in ASCII, not UTF-8.  If a string
    cannot be converted into a StringParameter (must be represented by a
    LiteralParameter), that is now also enforced via an ImapError.

 src/console/main.vala                              |    9 ++-
 src/engine/imap/command/imap-command.vala          |    9 +--
 src/engine/imap/command/imap-list-command.vala     |    2 +-
 .../imap/command/imap-list-return-parameter.vala   |    2 +-
 src/engine/imap/command/imap-search-criterion.vala |   12 +--
 .../message/imap-fetch-body-data-specifier.vala    |    9 +-
 .../imap/message/imap-fetch-data-specifier.vala    |   20 ++----
 src/engine/imap/message/imap-flag.vala             |    2 +-
 src/engine/imap/message/imap-flags.vala            |   10 ++-
 src/engine/imap/message/imap-internal-date.vala    |    4 +-
 .../imap/message/imap-mailbox-parameter.vala       |    6 +-
 src/engine/imap/message/imap-message-flags.vala    |    2 +-
 src/engine/imap/message/imap-status-data-type.vala |   10 +--
 src/engine/imap/message/imap-tag.vala              |   22 +++---
 src/engine/imap/parameter/imap-atom-parameter.vala |    2 +-
 src/engine/imap/parameter/imap-list-parameter.vala |    2 +-
 src/engine/imap/parameter/imap-nil-parameter.vala  |    2 +-
 .../imap/parameter/imap-number-parameter.vala      |    6 +-
 src/engine/imap/parameter/imap-parameter.vala      |   17 ++++
 .../parameter/imap-quoted-string-parameter.vala    |    8 +-
 .../imap/parameter/imap-string-parameter.vala      |   83 +++++++++++++++-----
 .../parameter/imap-unquoted-string-parameter.vala  |    8 +-
 src/engine/imap/response/imap-capabilities.vala    |    2 +-
 .../imap/response/imap-fetch-data-decoder.vala     |   22 +++---
 src/engine/imap/response/imap-fetched-data.vala    |    2 +-
 .../imap/response/imap-mailbox-attributes.vala     |    2 +-
 .../imap/response/imap-mailbox-information.vala    |    6 +-
 .../imap/response/imap-response-code-type.vala     |   12 ++--
 .../imap/response/imap-server-data-type.vala       |   20 ++---
 src/engine/imap/response/imap-status-data.vala     |    2 +-
 src/engine/imap/response/imap-status-response.vala |    2 +-
 src/engine/imap/response/imap-status.vala          |   10 +--
 src/engine/imap/transport/imap-deserializer.vala   |    3 +
 33 files changed, 187 insertions(+), 143 deletions(-)
---
diff --git a/src/console/main.vala b/src/console/main.vala
index fdcfcae..418112a 100644
--- a/src/console/main.vala
+++ b/src/console/main.vala
@@ -483,7 +483,8 @@ class ImapConsole : Gtk.Window {
         
         Gee.ArrayList<Geary.Imap.FetchDataSpecifier> data_items = new 
Gee.ArrayList<Geary.Imap.FetchDataSpecifier>();
         for (int ctr = 1; ctr < args.length; ctr++) {
-            Geary.Imap.FetchDataSpecifier data_type = Geary.Imap.FetchDataSpecifier.decode(args[ctr]);
+            Geary.Imap.StringParameter stringp = Geary.Imap.StringParameter.get_best_for(args[ctr]);
+            Geary.Imap.FetchDataSpecifier data_type = Geary.Imap.FetchDataSpecifier.from_parameter(stringp);
             data_items.add(data_type);
         }
         
@@ -578,8 +579,10 @@ class ImapConsole : Gtk.Window {
         status("Status %s".printf(args[0]));
         
         Geary.Imap.StatusDataType[] data_items = new Geary.Imap.StatusDataType[0];
-        for (int ctr = 1; ctr < args.length; ctr++)
-            data_items += Geary.Imap.StatusDataType.decode(args[ctr]);
+        for (int ctr = 1; ctr < args.length; ctr++) {
+            Geary.Imap.StringParameter stringp = Geary.Imap.StringParameter.get_best_for(args[ctr]);
+            data_items += Geary.Imap.StatusDataType.from_parameter(stringp);
+        }
         
         cx.send_async.begin(new Geary.Imap.StatusCommand(new Geary.Imap.MailboxSpecifier(args[0]),
             data_items), null, on_get_status);
diff --git a/src/engine/imap/command/imap-command.vala b/src/engine/imap/command/imap-command.vala
index 5d3d8ba..01cd331 100644
--- a/src/engine/imap/command/imap-command.vala
+++ b/src/engine/imap/command/imap-command.vala
@@ -74,13 +74,8 @@ public class Geary.Imap.Command : RootParameters {
         add(tag);
         add(new AtomParameter(name));
         if (args != null) {
-            foreach (string arg in args) {
-                StringParameter? stringp = StringParameter.get_best_for(arg);
-                if (stringp != null)
-                    add(stringp);
-                else
-                    add(new LiteralParameter(new Memory.StringBuffer(arg)));
-            }
+            foreach (string arg in args)
+                add(Parameter.get_for_string(arg));
         }
     }
     
diff --git a/src/engine/imap/command/imap-list-command.vala b/src/engine/imap/command/imap-list-command.vala
index 54d37d9..d54d815 100644
--- a/src/engine/imap/command/imap-list-command.vala
+++ b/src/engine/imap/command/imap-list-command.vala
@@ -52,7 +52,7 @@ public class Geary.Imap.ListCommand : Command {
         if (return_param == null || return_param.size == 0)
             return;
         
-        add(StringParameter.get_best_for("return"));
+        add(StringParameter.get_best_for_unchecked("return"));
         add(return_param);
     }
 }
diff --git a/src/engine/imap/command/imap-list-return-parameter.vala 
b/src/engine/imap/command/imap-list-return-parameter.vala
index df88f87..c1dd2b4 100644
--- a/src/engine/imap/command/imap-list-return-parameter.vala
+++ b/src/engine/imap/command/imap-list-return-parameter.vala
@@ -30,7 +30,7 @@ public class Geary.Imap.ListReturnParameter : ListParameter {
     }
     
     public void add_special_use() {
-        add(StringParameter.get_best_for(SPECIAL_USE));
+        add(StringParameter.get_best_for_unchecked(SPECIAL_USE));
     }
 }
 
diff --git a/src/engine/imap/command/imap-search-criterion.vala 
b/src/engine/imap/command/imap-search-criterion.vala
index 6e44695..64aec2c 100644
--- a/src/engine/imap/command/imap-search-criterion.vala
+++ b/src/engine/imap/command/imap-search-criterion.vala
@@ -44,16 +44,12 @@ public class Geary.Imap.SearchCriterion : BaseObject {
      * Create a single criterion with a simple name and custom value.
      */
     public SearchCriterion.string_value(string name, string value) {
-        Parameter? valuep = StringParameter.get_best_for(value);
-        if (valuep == null)
-            valuep = new LiteralParameter(new Memory.StringBuffer(value));
-        
         parameters.add(prep_name(name));
-        parameters.add(valuep);
+        parameters.add(Parameter.get_for_string(value));
     }
     
     private static Parameter prep_name(string name) {
-        Parameter? namep = StringParameter.get_best_for(name);
+        Parameter? namep = StringParameter.try_get_best_for(name);
         if (namep == null) {
             warning("Using a search name that requires a literal parameter: %s", name);
             namep = new LiteralParameter(new Memory.StringBuffer(name));
@@ -106,7 +102,7 @@ public class Geary.Imap.SearchCriterion : BaseObject {
     /**
      * The IMAP SEARCH KEYWORD criterion, or if the { link MessageFlag} has a macro, that value.
      */
-    public static SearchCriterion has_flag(MessageFlag flag) {
+    public static SearchCriterion has_flag(MessageFlag flag) throws ImapError {
         string? keyword = flag.get_search_keyword(true);
         if (keyword != null)
             return new SearchCriterion.simple(keyword);
@@ -117,7 +113,7 @@ public class Geary.Imap.SearchCriterion : BaseObject {
     /**
      * The IMAP SEARCH UNKEYWORD criterion, or if the { link MessageFlag} has a macro, that value.
      */
-    public static SearchCriterion has_not_flag(MessageFlag flag) {
+    public static SearchCriterion has_not_flag(MessageFlag flag) throws ImapError {
         string? keyword = flag.get_search_keyword(false);
         if (keyword != null)
             return new SearchCriterion.simple(keyword);
diff --git a/src/engine/imap/message/imap-fetch-body-data-specifier.vala 
b/src/engine/imap/message/imap-fetch-body-data-specifier.vala
index 83af281..ff2e98d 100644
--- a/src/engine/imap/message/imap-fetch-body-data-specifier.vala
+++ b/src/engine/imap/message/imap-fetch-body-data-specifier.vala
@@ -331,7 +331,8 @@ public class Geary.Imap.FetchBodyDataSpecifier : BaseObject, Gee.Hashable<FetchB
             break;
             
             default:
-                throw new ImapError.PARSE_ERROR("%s is not a FETCH body data type %d", stringp.value, count);
+                throw new ImapError.PARSE_ERROR("%s is not a FETCH body data type %d", stringp.to_string(),
+                    count);
         }
         
         // convert section string into its parts:
@@ -343,7 +344,7 @@ public class Geary.Imap.FetchBodyDataSpecifier : BaseObject, Gee.Hashable<FetchB
         unowned string? fields_string;
         if (section_string.contains("(")) {
             if (section_string.scanf("%[^(](%[^)])", part_chars, fields_chars) != 2)
-                throw new ImapError.PARSE_ERROR("%s: malformed part/header names", stringp.value);
+                throw new ImapError.PARSE_ERROR("%s: malformed part/header names", stringp.to_string());
             
             part_string = (string) part_chars;
             fields_string = (string?) fields_chars;
@@ -398,12 +399,12 @@ public class Geary.Imap.FetchBodyDataSpecifier : BaseObject, Gee.Hashable<FetchB
         if (!String.is_empty(octet_string)) {
             if (octet_string.scanf("<%d>", out subset_start) != 1) {
                 throw new ImapError.PARSE_ERROR("Improperly formed octet \"%s\" in %s", octet_string,
-                    stringp.value);
+                    stringp.to_string());
             }
             
             if (subset_start < 0) {
                 throw new ImapError.PARSE_ERROR("Invalid octet count %d in %s", subset_start,
-                    stringp.value);
+                    stringp.to_string());
             }
         }
         
diff --git a/src/engine/imap/message/imap-fetch-data-specifier.vala 
b/src/engine/imap/message/imap-fetch-data-specifier.vala
index e6aa693..b7dace5 100644
--- a/src/engine/imap/message/imap-fetch-data-specifier.vala
+++ b/src/engine/imap/message/imap-fetch-data-specifier.vala
@@ -78,12 +78,12 @@ public enum Geary.Imap.FetchDataSpecifier {
     }
     
     /**
-     * Converts a plain string into a { link FetchDataType}.
+     * Decoders a { link StringParameter} into a { link FetchDataType} using { link decode}.
      *
-     * @throws ImapError.PARSE_ERROR if not a recognized value.
+     * @see decode
      */
-    public static FetchDataSpecifier decode(string value) throws ImapError {
-        switch (Ascii.strdown(value)) {
+    public static FetchDataSpecifier from_parameter(StringParameter strparam) throws ImapError {
+        switch (strparam.as_lower()) {
             case "uid":
                 return UID;
             
@@ -124,7 +124,8 @@ public enum Geary.Imap.FetchDataSpecifier {
                 return FULL;
             
             default:
-                throw new ImapError.PARSE_ERROR("\"%s\" is not a valid fetch-command data item", value);
+                throw new ImapError.PARSE_ERROR("\"%s\" is not a valid fetch-command data item",
+                    strparam.to_string());
         }
     }
     
@@ -136,15 +137,6 @@ public enum Geary.Imap.FetchDataSpecifier {
     }
     
     /**
-     * Decoders a { link StringParameter} into a { link FetchDataType} using { link decode}.
-     *
-     * @see decode
-     */
-    public static FetchDataSpecifier from_parameter(StringParameter strparam) throws ImapError {
-        return decode(strparam.value);
-    }
-    
-    /**
      * Returns the appropriate { link FetchDataDecoder} for this { link FetchDataType}.
      *
      * The FetchDataDecoder can then be used to convert the associated { link Parameter}s into
diff --git a/src/engine/imap/message/imap-flag.vala b/src/engine/imap/message/imap-flag.vala
index 0a2e2ce..dbb3c7b 100644
--- a/src/engine/imap/message/imap-flag.vala
+++ b/src/engine/imap/message/imap-flag.vala
@@ -35,7 +35,7 @@ public abstract class Geary.Imap.Flag : BaseObject, Gee.Hashable<Geary.Imap.Flag
     /**
      * Returns the { link Flag} as an appropriate { link Parameter}.
      */
-    public Parameter to_parameter() {
+    public StringParameter to_parameter() throws ImapError {
         return StringParameter.get_best_for(value);
     }
     
diff --git a/src/engine/imap/message/imap-flags.vala b/src/engine/imap/message/imap-flags.vala
index 72c6c0c..46f41e7 100644
--- a/src/engine/imap/message/imap-flags.vala
+++ b/src/engine/imap/message/imap-flags.vala
@@ -42,8 +42,14 @@ public abstract class Geary.Imap.Flags : Geary.MessageData.AbstractMessageData,
      */
     public virtual Parameter to_parameter() {
         ListParameter listp = new ListParameter();
-        foreach (Flag flag in list)
-            listp.add(flag.to_parameter());
+        foreach (Flag flag in list) {
+            try {
+                listp.add(flag.to_parameter());
+            } catch (ImapError ierr) {
+                // drop on floor with warning
+                message("Unable to parameterize flag \"%s\": %s", flag.to_string(), ierr.message);
+            }
+        }
         
         return listp;
     }
diff --git a/src/engine/imap/message/imap-internal-date.vala b/src/engine/imap/message/imap-internal-date.vala
index db66d7d..a9d98a2 100644
--- a/src/engine/imap/message/imap-internal-date.vala
+++ b/src/engine/imap/message/imap-internal-date.vala
@@ -98,7 +98,7 @@ public class Geary.Imap.InternalDate : Geary.MessageData.AbstractMessageData, Ge
      * Returns the { link InternalDate} as a { link Parameter}.
      */
     public Parameter to_parameter() {
-        return StringParameter.get_best_for(serialize());
+        return Parameter.get_for_string(serialize());
     }
     
     /**
@@ -107,7 +107,7 @@ public class Geary.Imap.InternalDate : Geary.MessageData.AbstractMessageData, Ge
      * @see serialize_for_search
      */
     public Parameter to_search_parameter() {
-        return StringParameter.get_best_for(serialize_for_search());
+        return Parameter.get_for_string(serialize());
     }
     
     /**
diff --git a/src/engine/imap/message/imap-mailbox-parameter.vala 
b/src/engine/imap/message/imap-mailbox-parameter.vala
index 5987c68..6519c37 100644
--- a/src/engine/imap/message/imap-mailbox-parameter.vala
+++ b/src/engine/imap/message/imap-mailbox-parameter.vala
@@ -18,7 +18,7 @@ public class Geary.Imap.MailboxParameter : StringParameter {
     }
     
     public MailboxParameter.from_string_parameter(StringParameter string_parameter) {
-        base (string_parameter.value);
+        base (string_parameter.ascii);
     }
     
     private static string utf8_to_imap_utf7(string utf8) {
@@ -40,7 +40,7 @@ public class Geary.Imap.MailboxParameter : StringParameter {
     }
     
     public string decode() {
-        return imap_utf7_to_utf8(value);
+        return imap_utf7_to_utf8(ascii);
     }
     
     /**
@@ -54,7 +54,7 @@ public class Geary.Imap.MailboxParameter : StringParameter {
      * { inheritDoc}
      */
     public override string to_string() {
-        return value;
+        return ascii;
     }
 }
 
diff --git a/src/engine/imap/message/imap-message-flags.vala b/src/engine/imap/message/imap-message-flags.vala
index 8b88aaa..39bded4 100644
--- a/src/engine/imap/message/imap-message-flags.vala
+++ b/src/engine/imap/message/imap-message-flags.vala
@@ -23,7 +23,7 @@ public class Geary.Imap.MessageFlags : Geary.Imap.Flags {
     public static MessageFlags from_list(ListParameter listp) throws ImapError {
         Gee.Collection<MessageFlag> list = new Gee.ArrayList<MessageFlag>();
         for (int ctr = 0; ctr < listp.size; ctr++)
-            list.add(new MessageFlag(listp.get_as_string(ctr).value));
+            list.add(new MessageFlag(listp.get_as_string(ctr).ascii));
         
         return new MessageFlags(list);
     }
diff --git a/src/engine/imap/message/imap-status-data-type.vala 
b/src/engine/imap/message/imap-status-data-type.vala
index 22e0ea1..07e4576 100644
--- a/src/engine/imap/message/imap-status-data-type.vala
+++ b/src/engine/imap/message/imap-status-data-type.vala
@@ -45,8 +45,8 @@ public enum Geary.Imap.StatusDataType {
         }
     }
     
-    public static StatusDataType decode(string value) throws ImapError {
-        switch (Ascii.strdown(value)) {
+    public static StatusDataType from_parameter(StringParameter stringp) throws ImapError {
+        switch (stringp.as_lower()) {
             case "messages":
                 return MESSAGES;
             
@@ -63,16 +63,12 @@ public enum Geary.Imap.StatusDataType {
                 return UNSEEN;
             
             default:
-                throw new ImapError.PARSE_ERROR("Unknown status data type \"%s\"", value);
+                throw new ImapError.PARSE_ERROR("Unknown status data type \"%s\"", stringp.to_string());
         }
     }
     
     public StringParameter to_parameter() {
         return new AtomParameter(to_string());
     }
-    
-    public static StatusDataType from_parameter(StringParameter stringp) throws ImapError {
-        return decode(stringp.value);
-    }
 }
 
diff --git a/src/engine/imap/message/imap-tag.vala b/src/engine/imap/message/imap-tag.vala
index 11fb9ec..d02bf2d 100644
--- a/src/engine/imap/message/imap-tag.vala
+++ b/src/engine/imap/message/imap-tag.vala
@@ -24,12 +24,12 @@ public class Geary.Imap.Tag : AtomParameter, Gee.Hashable<Geary.Imap.Tag> {
     private static Tag? unassigned = null;
     private static Tag? continuation = null;
     
-    public Tag(string value) {
-        base (value);
+    public Tag(string ascii) {
+        base (ascii);
     }
     
     public Tag.from_parameter(StringParameter strparam) {
-        base (strparam.value);
+        base (strparam.ascii);
     }
     
     internal static void init() {
@@ -67,15 +67,15 @@ public class Geary.Imap.Tag : AtomParameter, Gee.Hashable<Geary.Imap.Tag> {
         if (stringp is QuotedStringParameter)
             return false;
         
-        if (String.is_empty(stringp.value))
+        if (stringp.is_empty())
             return false;
         
-        if (stringp.value == UNTAGGED_VALUE || stringp.value == CONTINUATION_VALUE)
+        if (stringp.equals_cs(UNTAGGED_VALUE) || stringp.equals_cs(CONTINUATION_VALUE))
             return true;
         
         int index = 0;
         for (;;) {
-            char ch = stringp.value[index++];
+            char ch = stringp.ascii[index++];
             if (ch == String.EOS)
                 break;
             
@@ -87,26 +87,26 @@ public class Geary.Imap.Tag : AtomParameter, Gee.Hashable<Geary.Imap.Tag> {
     }
     
     public bool is_tagged() {
-        return (value != UNTAGGED_VALUE) && (value != CONTINUATION_VALUE) && (value != UNASSIGNED_VALUE);
+        return !equals_cs(UNTAGGED_VALUE) && !equals_cs(CONTINUATION_VALUE) && !equals_cs(UNASSIGNED_VALUE);
     }
     
     public bool is_continuation() {
-        return value == CONTINUATION_VALUE;
+        return equals_cs(CONTINUATION_VALUE);
     }
     
     public bool is_assigned() {
-        return (value != UNASSIGNED_VALUE) && (value != CONTINUATION_VALUE);
+        return !equals_cs(UNASSIGNED_VALUE) && !equals_cs(CONTINUATION_VALUE);
     }
     
     public uint hash() {
-        return Ascii.str_hash(value);
+        return Ascii.str_hash(ascii);
     }
     
     public bool equal_to(Geary.Imap.Tag tag) {
         if (this == tag)
             return true;
         
-        return equals_cs(tag.value);
+        return equals_cs(tag.ascii);
     }
 }
 
diff --git a/src/engine/imap/parameter/imap-atom-parameter.vala 
b/src/engine/imap/parameter/imap-atom-parameter.vala
index 374ce66..abe94cf 100644
--- a/src/engine/imap/parameter/imap-atom-parameter.vala
+++ b/src/engine/imap/parameter/imap-atom-parameter.vala
@@ -26,7 +26,7 @@ public class Geary.Imap.AtomParameter : Geary.Imap.UnquotedStringParameter {
      * { inheritDoc}
      */
     public override void serialize(Serializer ser, Tag tag) throws Error {
-        ser.push_unquoted_string(value);
+        ser.push_unquoted_string(ascii);
     }
 }
 
diff --git a/src/engine/imap/parameter/imap-list-parameter.vala 
b/src/engine/imap/parameter/imap-list-parameter.vala
index e742752..e561102 100644
--- a/src/engine/imap/parameter/imap-list-parameter.vala
+++ b/src/engine/imap/parameter/imap-list-parameter.vala
@@ -420,7 +420,7 @@ public class Geary.Imap.ListParameter : Geary.Imap.Parameter {
         
         StringParameter? stringp = get_if_string(index);
         if (stringp != null)
-            return new Memory.StringBuffer(stringp.value);
+            return stringp.as_buffer();
         
         return null;
     }
diff --git a/src/engine/imap/parameter/imap-nil-parameter.vala 
b/src/engine/imap/parameter/imap-nil-parameter.vala
index f9a26a1..f52a7c2 100644
--- a/src/engine/imap/parameter/imap-nil-parameter.vala
+++ b/src/engine/imap/parameter/imap-nil-parameter.vala
@@ -41,7 +41,7 @@ public class Geary.Imap.NilParameter : Geary.Imap.Parameter {
      * list.
      */
     public static bool is_nil(StringParameter stringp) {
-        return Ascii.stri_equal(VALUE, stringp.value);
+        return stringp.equals_ci(VALUE);
     }
     
     /**
diff --git a/src/engine/imap/parameter/imap-number-parameter.vala 
b/src/engine/imap/parameter/imap-number-parameter.vala
index 354a3f6..f6c29f5 100644
--- a/src/engine/imap/parameter/imap-number-parameter.vala
+++ b/src/engine/imap/parameter/imap-number-parameter.vala
@@ -41,12 +41,12 @@ public class Geary.Imap.NumberParameter : UnquotedStringParameter {
      * No checking is performed to verify that the string is only composed of numeric characters.
      * Use { link is_numeric}.
      */
-    public NumberParameter.from_string(string str) {
-        base (str);
+    public NumberParameter.from_ascii(string ascii) {
+        base (ascii);
     }
     
     /**
-     * Returns true if the string is composed of numeric characters.
+     * Returns true if the string is composed of numeric 7-bit characters.
      *
      * The only non-numeric character allowed is a dash ('-') at the beginning of the string to
      * indicate a negative value.  However, note that almost every IMAP use of a number is for a
diff --git a/src/engine/imap/parameter/imap-parameter.vala b/src/engine/imap/parameter/imap-parameter.vala
index 85bcc1d..7f1f6a3 100644
--- a/src/engine/imap/parameter/imap-parameter.vala
+++ b/src/engine/imap/parameter/imap-parameter.vala
@@ -14,6 +14,23 @@
 
 public abstract class Geary.Imap.Parameter : BaseObject {
     /**
+     * Returns an appropriate { link Parameter} for the string.
+     *
+     * get_for_string() goes from simple to complexity in terms of parameter encoding.  It uses
+     * { link StringParameter.get_best_for} first to attempt to produced an unquoted, then unquoted,
+     * string.  (It will also produce a { link NumberParameter} if appropriate.)  If the string
+     * cannot be held in those forms, it returns a { link LiteralParameter}, which is capable of
+     * transmitting 8-bit data.
+     */
+    public static Parameter get_for_string(string value) {
+        try {
+            return StringParameter.get_best_for(value);
+        } catch (ImapError ierr) {
+            return new LiteralParameter(new Memory.StringBuffer(value));
+        }
+    }
+    
+    /**
      * Invoked when the { link Parameter} is to be serialized out to the network.
      *
      * The supplied Tag will have (or will be) assigned to the message, so it should be passed
diff --git a/src/engine/imap/parameter/imap-quoted-string-parameter.vala 
b/src/engine/imap/parameter/imap-quoted-string-parameter.vala
index 55e2d2c..06362e2 100644
--- a/src/engine/imap/parameter/imap-quoted-string-parameter.vala
+++ b/src/engine/imap/parameter/imap-quoted-string-parameter.vala
@@ -16,22 +16,22 @@
  */
 
 public class Geary.Imap.QuotedStringParameter : Geary.Imap.StringParameter {
-    public QuotedStringParameter(string value) {
-        base (value);
+    public QuotedStringParameter(string ascii) {
+        base (ascii);
     }
     
     /**
      * { inheritDoc}
      */
     public override string to_string() {
-        return "\"%s\"".printf(value);
+        return "\"%s\"".printf(ascii);
     }
     
     /**
      * { inheritDoc}
      */
     public override void serialize(Serializer ser, Tag tag) throws Error {
-        ser.push_quoted_string(value);
+        ser.push_quoted_string(ascii);
     }
 }
 
diff --git a/src/engine/imap/parameter/imap-string-parameter.vala 
b/src/engine/imap/parameter/imap-string-parameter.vala
index c9d3a9b..0a164f5 100644
--- a/src/engine/imap/parameter/imap-string-parameter.vala
+++ b/src/engine/imap/parameter/imap-string-parameter.vala
@@ -21,21 +21,21 @@
 
 public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
     /**
-     * The unquoted, decoded string.
+     * The unquoted, decoded string as 7-bit ASCII.
      */
-    public string value { get; private set; }
+    public string ascii { get; private set; }
     
     /**
      * Returns { link value} or null if value is empty (zero-length).
      */
-    public string? nullable_value {
+    public string? nullable_ascii {
         get {
-            return String.is_empty(value) ? null : value;
+            return String.is_empty(ascii) ? null : ascii;
         }
     }
     
-    protected StringParameter(string value) {
-        this.value = value;
+    protected StringParameter(string ascii) {
+        this.ascii = ascii;
     }
     
     /**
@@ -48,11 +48,12 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
      * Because of these restrictions, should only be used when the context or syntax of the
      * Parameter is unknown or uncertain.
      *
-     * @return null if the string must be represented with a { link LiteralParameter}.
+     * @throws ImapError.NOT_SUPPORTED if the string must be represented as a { link LiteralParameter}.
+     * @see Parameter.get_for_string
      */
-    public static StringParameter? get_best_for(string value) {
+    public static StringParameter get_best_for(string value) throws ImapError {
         if (NumberParameter.is_numeric(value, null))
-            return new NumberParameter.from_string(value);
+            return new NumberParameter.from_ascii(value);
         
         switch (DataFormat.is_quoting_required(value)) {
             case DataFormat.Quoting.REQUIRED:
@@ -62,7 +63,7 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
                 return new UnquotedStringParameter(value);
             
             case DataFormat.Quoting.UNALLOWED:
-                return null;
+                throw new ImapError.NOT_SUPPORTED("String must be a literal parameter");
             
             default:
                 assert_not_reached();
@@ -70,18 +71,46 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
     }
     
     /**
+     * Like { link get_best_for} but the library will panic if the value cannot be turned into
+     * a { link StringParameter}.
+     *
+     * This should ''only'' be used with string constants that are guaranteed 7-bit ASCII.
+     */
+    public static StringParameter get_best_for_unchecked(string value) {
+        try {
+            return get_best_for(value);
+        } catch (ImapError ierr) {
+            error("Unable to create StringParameter for \"%s\": %s", value, ierr.message);
+        }
+    }
+    
+    /**
+     * Like { link get_best_for} but returns null if the value cannot be stored as a
+     * { link StringParameter}.
+     *
+     * @see Parameter.get_for_string
+     */
+    public static StringParameter? try_get_best_for(string value) {
+        try {
+            return get_best_for(value);
+        } catch (ImapError ierr) {
+            return null;
+        }
+    }
+    
+    /**
      * Can be used by subclasses to properly serialize the string value according to quoting rules.
      *
      * NOTE: Literal data is not currently supported.
      */
     protected void serialize_string(Serializer ser) throws Error {
-        switch (DataFormat.is_quoting_required(value)) {
+        switch (DataFormat.is_quoting_required(ascii)) {
             case DataFormat.Quoting.REQUIRED:
-                ser.push_quoted_string(value);
+                ser.push_quoted_string(ascii);
             break;
             
             case DataFormat.Quoting.OPTIONAL:
-                ser.push_unquoted_string(value);
+                ser.push_unquoted_string(ascii);
             break;
             
             case DataFormat.Quoting.UNALLOWED:
@@ -93,31 +122,45 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
     }
     
     /**
+     * Returns the string as a { link Memory.Buffer}.
+     */
+    public Memory.Buffer as_buffer() {
+        return new Memory.StringBuffer(ascii);
+    }
+    
+    /**
+     * Returns true if the string is empty (zero-length).
+     */
+    public bool is_empty() {
+        return String.is_empty(ascii);
+    }
+    
+    /**
      * Case-sensitive comparison.
      */
     public bool equals_cs(string value) {
-        return Ascii.str_equal(this.value, value);
+        return Ascii.str_equal(ascii, value);
     }
     
     /**
      * Case-insensitive comparison.
      */
     public bool equals_ci(string value) {
-        return Ascii.stri_equal(this.value, value);
+        return Ascii.stri_equal(ascii, value);
     }
     
     /**
      * Returns the string lowercased.
      */
     public string as_lower() {
-        return Ascii.strdown(value);
+        return Ascii.strdown(ascii);
     }
     
     /**
      * Returns the string uppercased.
      */
     public string as_upper() {
-        return Ascii.strup(value);
+        return Ascii.strup(ascii);
     }
     
     /**
@@ -127,7 +170,7 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
      *. added later.
      */
     public int as_int(int clamp_min = int.MIN, int clamp_max = int.MAX) throws ImapError {
-        return int.parse(value).clamp(clamp_min, clamp_max);
+        return int.parse(ascii).clamp(clamp_min, clamp_max);
     }
     
     /**
@@ -137,7 +180,7 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
      *. added later.
      */
     public long as_long(int clamp_min = int.MIN, int clamp_max = int.MAX) throws ImapError {
-        return long.parse(value).clamp(clamp_min, clamp_max);
+        return long.parse(ascii).clamp(clamp_min, clamp_max);
     }
     
     /**
@@ -147,7 +190,7 @@ public abstract class Geary.Imap.StringParameter : Geary.Imap.Parameter {
      *. added later.
      */
     public int64 as_int64(int64 clamp_min = int64.MIN, int64 clamp_max = int64.MAX) throws ImapError {
-        return int64.parse(value).clamp(clamp_min, clamp_max);
+        return int64.parse(ascii).clamp(clamp_min, clamp_max);
     }
 }
 
diff --git a/src/engine/imap/parameter/imap-unquoted-string-parameter.vala 
b/src/engine/imap/parameter/imap-unquoted-string-parameter.vala
index 766c6b2..d771c07 100644
--- a/src/engine/imap/parameter/imap-unquoted-string-parameter.vala
+++ b/src/engine/imap/parameter/imap-unquoted-string-parameter.vala
@@ -18,22 +18,22 @@
  */
 
 public class Geary.Imap.UnquotedStringParameter : Geary.Imap.StringParameter {
-    public UnquotedStringParameter(string value) {
-        base (value);
+    public UnquotedStringParameter(string ascii) {
+        base (ascii);
     }
     
     /**
      * { inheritDoc}
      */
     public override void serialize(Serializer ser, Tag tag) throws Error {
-        ser.push_unquoted_string(value);
+        ser.push_unquoted_string(ascii);
     }
     
     /**
      * { inheritDoc}
      */
     public override string to_string() {
-        return value;
+        return ascii;
     }
 }
 
diff --git a/src/engine/imap/response/imap-capabilities.vala b/src/engine/imap/response/imap-capabilities.vala
index f74dd25..b6f6e5d 100644
--- a/src/engine/imap/response/imap-capabilities.vala
+++ b/src/engine/imap/response/imap-capabilities.vala
@@ -30,7 +30,7 @@ public class Geary.Imap.Capabilities : Geary.GenericCapabilities {
     }
 
     public bool add_parameter(StringParameter stringp) {
-        return parse_and_add_capability(stringp.value);
+        return parse_and_add_capability(stringp.ascii);
     }
 
     public override string to_string() {
diff --git a/src/engine/imap/response/imap-fetch-data-decoder.vala 
b/src/engine/imap/response/imap-fetch-data-decoder.vala
index 6f9e2ca..142a2a3 100644
--- a/src/engine/imap/response/imap-fetch-data-decoder.vala
+++ b/src/engine/imap/response/imap-fetch-data-decoder.vala
@@ -97,7 +97,7 @@ public class Geary.Imap.MessageFlagsDecoder : Geary.Imap.FetchDataDecoder {
     protected override MessageData decode_list(ListParameter listp) throws ImapError {
         Gee.List<Flag> flags = new Gee.ArrayList<Flag>();
         for (int ctr = 0; ctr < listp.size; ctr++)
-            flags.add(new MessageFlag(listp.get_as_string(ctr).value));
+            flags.add(new MessageFlag(listp.get_as_string(ctr).ascii));
         
         return new MessageFlags(flags);
     }
@@ -109,7 +109,7 @@ public class Geary.Imap.InternalDateDecoder : Geary.Imap.FetchDataDecoder {
     }
     
     protected override MessageData decode_string(StringParameter stringp) throws ImapError {
-        return InternalDate.decode(stringp.value);
+        return InternalDate.decode(stringp.ascii);
     }
 }
 
@@ -142,17 +142,17 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
         
         // Although Message-ID is required to be returned by IMAP, it may be blank if the email
         // does not supply it (optional according to RFC822); deal with this cognitive dissonance
-        if (message_id != null && String.is_empty(message_id.value))
+        if (message_id != null && message_id.is_empty())
             message_id = null;
         
-        return new Envelope((sent != null) ? new Geary.RFC822.Date(sent.value) : null,
-            new Geary.RFC822.Subject.decode(subject.value),
+        return new Envelope((sent != null) ? new Geary.RFC822.Date(sent.ascii) : null,
+            new Geary.RFC822.Subject.decode(subject.ascii),
             parse_addresses(from), parse_addresses(sender), parse_addresses(reply_to),
             (to != null) ? parse_addresses(to) : null, 
             (cc != null) ? parse_addresses(cc) : null,
             (bcc != null) ? parse_addresses(bcc) : null,
-            (in_reply_to != null) ? new Geary.RFC822.MessageIDList.from_rfc822_string(in_reply_to.value) : 
null,
-            (message_id != null) ? new Geary.RFC822.MessageID(message_id.value) : null);
+            (in_reply_to != null) ? new Geary.RFC822.MessageIDList.from_rfc822_string(in_reply_to.ascii) : 
null,
+            (message_id != null) ? new Geary.RFC822.MessageID(message_id.ascii) : null);
     }
     
     // TODO: This doesn't handle group lists (see Johnson, p.268) -- this will throw an
@@ -167,10 +167,10 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
             StringParameter domain = fields.get_as_empty_string(3);
             
             Geary.RFC822.MailboxAddress addr = new Geary.RFC822.MailboxAddress.imap(
-                (name != null) ? name.nullable_value : null,
-                (source_route != null) ? source_route.nullable_value : null,
-                mailbox.value,
-                domain.value);
+                (name != null) ? name.nullable_ascii : null,
+                (source_route != null) ? source_route.nullable_ascii : null,
+                mailbox.ascii,
+                domain.ascii);
             list.add(addr);
         }
         
diff --git a/src/engine/imap/response/imap-fetched-data.vala b/src/engine/imap/response/imap-fetched-data.vala
index 6972c6d..a759b85 100644
--- a/src/engine/imap/response/imap-fetched-data.vala
+++ b/src/engine/imap/response/imap-fetched-data.vala
@@ -71,7 +71,7 @@ public class Geary.Imap.FetchedData : Object {
                 else
                     fetched_data.body_data_map.set(specifier, Memory.EmptyBuffer.instance);
             } else {
-                FetchDataSpecifier data_item = FetchDataSpecifier.decode(data_item_param.value);
+                FetchDataSpecifier data_item = FetchDataSpecifier.from_parameter(data_item_param);
                 FetchDataDecoder? decoder = data_item.get_decoder();
                 if (decoder == null) {
                     debug("Unable to decode fetch response for \"%s\": No decoder available",
diff --git a/src/engine/imap/response/imap-mailbox-attributes.vala 
b/src/engine/imap/response/imap-mailbox-attributes.vala
index b23af14..63599a0 100644
--- a/src/engine/imap/response/imap-mailbox-attributes.vala
+++ b/src/engine/imap/response/imap-mailbox-attributes.vala
@@ -33,7 +33,7 @@ public class Geary.Imap.MailboxAttributes : Geary.Imap.Flags {
     public static MailboxAttributes from_list(ListParameter listp) throws ImapError {
         Gee.Collection<MailboxAttribute> list = new Gee.ArrayList<MailboxAttribute>();
         for (int ctr = 0; ctr < listp.size; ctr++)
-            list.add(new MailboxAttribute(listp.get_as_string(ctr).value));
+            list.add(new MailboxAttribute(listp.get_as_string(ctr).ascii));
         
         return new MailboxAttributes(list);
     }
diff --git a/src/engine/imap/response/imap-mailbox-information.vala 
b/src/engine/imap/response/imap-mailbox-information.vala
index 741a958..93f1b0e 100644
--- a/src/engine/imap/response/imap-mailbox-information.vala
+++ b/src/engine/imap/response/imap-mailbox-information.vala
@@ -65,7 +65,7 @@ public class Geary.Imap.MailboxInformation : Object {
                 continue;
             }
             
-            attrlist.add(new MailboxAttribute(stringp.value));
+            attrlist.add(new MailboxAttribute(stringp.ascii));
         }
         
         // decode everything
@@ -77,10 +77,10 @@ public class Geary.Imap.MailboxInformation : Object {
         // Set \Inbox to standard path
         if (canonical_inbox && Geary.Imap.MailboxAttribute.SPECIAL_FOLDER_INBOX in attributes) {
             return new MailboxInformation(MailboxSpecifier.inbox,
-                (delim != null) ? delim.nullable_value : null, attributes);
+                (delim != null) ? delim.nullable_ascii : null, attributes);
         } else {
             return new MailboxInformation(new MailboxSpecifier.from_parameter(mailbox),
-                (delim != null) ? delim.nullable_value : null, attributes);
+                (delim != null) ? delim.nullable_ascii : null, attributes);
         }
     }
     
diff --git a/src/engine/imap/response/imap-response-code-type.vala 
b/src/engine/imap/response/imap-response-code-type.vala
index c7776f5..3bb0c84 100644
--- a/src/engine/imap/response/imap-response-code-type.vala
+++ b/src/engine/imap/response/imap-response-code-type.vala
@@ -61,17 +61,17 @@ public class Geary.Imap.ResponseCodeType : BaseObject, Gee.Hashable<ResponseCode
      * an {link ResponseCodeType}.
      */
     public ResponseCodeType.from_parameter(StringParameter stringp) throws ImapError {
-        init(stringp.value);
+        init(stringp.ascii);
     }
     
-    private void init(string str) throws ImapError {
+    private void init(string ascii) throws ImapError {
         // note that is_quoting_required() also catches empty strings (as they require quoting)
-        if (DataFormat.is_quoting_required(str) != DataFormat.Quoting.OPTIONAL)
-            throw new ImapError.INVALID("\"%s\" cannot be represented as a ResponseCodeType", str);
+        if (DataFormat.is_quoting_required(ascii) != DataFormat.Quoting.OPTIONAL)
+            throw new ImapError.INVALID("\"%s\" cannot be represented as a ResponseCodeType", ascii);
         
         // store lowercased so it's easily compared with const strings above
-        original = str;
-        value = Ascii.strdown(str);
+        original = ascii;
+        value = Ascii.strdown(ascii);
     }
     
     public bool is_value(string str) {
diff --git a/src/engine/imap/response/imap-server-data-type.vala 
b/src/engine/imap/response/imap-server-data-type.vala
index f2dc000..96277d7 100644
--- a/src/engine/imap/response/imap-server-data-type.vala
+++ b/src/engine/imap/response/imap-server-data-type.vala
@@ -63,8 +63,13 @@ public enum Geary.Imap.ServerDataType {
         }
     }
     
-    public static ServerDataType decode(string value) throws ImapError {
-        switch (Ascii.strdown(value)) {
+    /**
+     * Convert a { link StringParameter} into a ServerDataType.
+     *
+     * @throws ImapError.PARSE_ERROR if the StringParameter is not recognized as a ServerDataType.
+     */
+    public static ServerDataType from_parameter(StringParameter param) throws ImapError {
+        switch (param.as_lower()) {
             case "capability":
                 return CAPABILITY;
             
@@ -100,7 +105,7 @@ public enum Geary.Imap.ServerDataType {
                 return XLIST;
             
             default:
-                throw new ImapError.PARSE_ERROR("\"%s\" is not a valid server data type", value);
+                throw new ImapError.PARSE_ERROR("\"%s\" is not a valid server data type", param.to_string());
         }
     }
     
@@ -109,15 +114,6 @@ public enum Geary.Imap.ServerDataType {
     }
     
     /**
-     * Convert a { link StringParameter} into a ServerDataType.
-     *
-     * @throws ImapError.PARSE_ERROR if the StringParameter is not recognized as a ServerDataType.
-     */
-    public static ServerDataType from_parameter(StringParameter param) throws ImapError {
-        return decode(param.value);
-    }
-    
-    /**
      * Examines the { link RootParameters} looking for a ServerDataType.
      *
      * IMAP server responses don't offer a regular format for server data declations.  This method
diff --git a/src/engine/imap/response/imap-status-data.vala b/src/engine/imap/response/imap-status-data.vala
index c3eb3e9..56724c2 100644
--- a/src/engine/imap/response/imap-status-data.vala
+++ b/src/engine/imap/response/imap-status-data.vala
@@ -115,7 +115,7 @@ public class Geary.Imap.StatusData : Object {
                     break;
                     
                     default:
-                        message("Bad STATUS data type %s", typep.value);
+                        message("Bad STATUS data type %s", typep.to_string());
                     break;
                 }
             } catch (ImapError ierr) {
diff --git a/src/engine/imap/response/imap-status-response.vala 
b/src/engine/imap/response/imap-status-response.vala
index 6e07779..107f2c9 100644
--- a/src/engine/imap/response/imap-status-response.vala
+++ b/src/engine/imap/response/imap-status-response.vala
@@ -88,7 +88,7 @@ public class Geary.Imap.StatusResponse : ServerResponse {
         for (int index = 2; index < size; index++) {
             StringParameter? strparam = get_if_string(index);
             if (strparam != null) {
-                builder.append(strparam.value);
+                builder.append(strparam.ascii);
                 if (index < (size - 1))
                     builder.append_c(' ');
             }
diff --git a/src/engine/imap/response/imap-status.vala b/src/engine/imap/response/imap-status.vala
index 60b101a..6f7669c 100644
--- a/src/engine/imap/response/imap-status.vala
+++ b/src/engine/imap/response/imap-status.vala
@@ -39,8 +39,8 @@ public enum Geary.Imap.Status {
         }
     }
     
-    public static Status decode(string value) throws ImapError {
-        switch (Ascii.strdown(value)) {
+    public static Status from_parameter(StringParameter strparam) throws ImapError {
+        switch (strparam.as_lower()) {
             case "ok":
                 return OK;
             
@@ -57,14 +57,10 @@ public enum Geary.Imap.Status {
                 return BYE;
             
             default:
-                throw new ImapError.PARSE_ERROR("Unrecognized status response \"%s\"", value);
+                throw new ImapError.PARSE_ERROR("Unrecognized status response \"%s\"", strparam.to_string());
         }
     }
     
-    public static Status from_parameter(StringParameter strparam) throws ImapError {
-        return decode(strparam.value);
-    }
-    
     public Parameter to_parameter() {
         return new AtomParameter(to_string());
     }
diff --git a/src/engine/imap/transport/imap-deserializer.vala 
b/src/engine/imap/transport/imap-deserializer.vala
index 55e0d40..63cfd2f 100644
--- a/src/engine/imap/transport/imap-deserializer.vala
+++ b/src/engine/imap/transport/imap-deserializer.vala
@@ -94,6 +94,9 @@ public class Geary.Imap.Deserializer : BaseObject {
      * { link UnquotedStringParameter}s, { link ResponseCode}, and { link ListParameter}s.
      * Deserializer does not produce any other kind of Parameter due to its inability to deduce
      * them from syntax alone.  ResponseCode, however, can be.
+     *
+     * All strings are ASCII (7-bit) with control characters stripped (with the exception of
+     * { link QuotedStringParameter} which allows for some control characters).
      */
     public signal void parameters_ready(RootParameters root);
     



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