[gmime] Rewrote address parser



commit 752a0135252efe61f2f4ab58b61ae08fff6c92b4
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Wed Feb 8 11:02:19 2017 -0500

    Rewrote address parser
    
    Some unit tests are failing so there's still improvements to be made...

 gmime/gmime-content-type.c |    2 +-
 gmime/gmime-message.c      |  107 ++-----
 gmime/gmime-param.c        |   24 +-
 gmime/gmime-parse-utils.c  |  204 +++++++++--
 gmime/gmime-parse-utils.h  |   20 +-
 gmime/gmime-utils.c        |   14 +-
 gmime/internet-address.c   |  882 +++++++++++++++++++++++++++++---------------
 tests/test-mime.c          |   15 +-
 8 files changed, 814 insertions(+), 454 deletions(-)
---
diff --git a/gmime/gmime-content-type.c b/gmime/gmime-content-type.c
index 022bfdf..dc182f1 100644
--- a/gmime/gmime-content-type.c
+++ b/gmime/gmime-content-type.c
@@ -192,7 +192,7 @@ g_mime_content_type_parse (GMimeParserOptions *options, const char *str)
        mime_type->type = type;
        
        /* skip past any remaining junk that shouldn't be here... */
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        while (*inptr && *inptr != ';')
                inptr++;
        
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 04d418c..ffa3f76 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -265,87 +265,25 @@ struct _received_token {
        token_skip_t skip;
 };
 
-static void skip_atom     (const char **in);
-static void skip_domain   (const char **in);
-static void skip_addr     (const char **in);
-static void skip_msgid    (const char **in);
+static void skip_cfws_atom (const char **in);
+static void skip_domain    (const char **in);
+static void skip_addr      (const char **in);
+static void skip_msgid     (const char **in);
 
 static struct _received_token received_tokens[] = {
-       { "from ", 5, skip_domain   },
-       { "by ",   3, skip_domain   },
-       { "via ",  4, skip_atom     },
-       { "with ", 5, skip_atom     },
-       { "id ",   3, skip_msgid    },
-       { "for ",  4, skip_addr     }
+       { "from ", 5, skip_domain    },
+       { "by ",   3, skip_domain    },
+       { "via ",  4, skip_cfws_atom },
+       { "with ", 5, skip_cfws_atom },
+       { "id ",   3, skip_msgid     },
+       { "for ",  4, skip_addr      }
 };
 
 static void
-skip_atom (const char **in)
+skip_cfws_atom (const char **in)
 {
-       register const char *inptr;
-       
-       decode_lwsp (in);
-       inptr = *in;
-       while (is_atom (*inptr))
-               inptr++;
-       *in = inptr;
-}
-
-static void
-skip_comment (const char **in)
-{
-       register const char *inptr = *in;
-       int depth = 1;
-       
-       if (*inptr == '(')
-               inptr++;
-       
-       while (*inptr && depth > 0) {
-               if (*inptr == '(')
-                       depth++;
-               else if (*inptr == ')')
-                       depth--;
-               inptr++;
-       }
-       
-       if (*inptr == ')')
-               inptr++;
-       
-       *in = inptr;
-}
-
-static void
-skip_quoted_string (const char **in)
-{
-       const char *inptr = *in;
-       
-       decode_lwsp (&inptr);
-       if (*inptr == '"') {
-               inptr++;
-               while (*inptr && *inptr != '"') {
-                       if (*inptr == '\\')
-                               inptr++;
-                       
-                       if (*inptr)
-                               inptr++;
-               }
-               
-               if (*inptr == '"')
-                       inptr++;
-       }
-       
-       *in = inptr;
-}
-
-static void
-skip_word (const char **in)
-{
-       decode_lwsp (in);
-       if (**in == '"') {
-               skip_quoted_string (in);
-       } else {
-               skip_atom (in);
-       }
+       skip_cfws (in);
+       skip_atom (in);
 }
 
 static void
@@ -357,7 +295,7 @@ skip_domain_subliteral (const char **in)
                if (is_dtext (*inptr)) {
                        inptr++;
                } else if (is_lwsp (*inptr)) {
-                       decode_lwsp (&inptr);
+                       skip_cfws (&inptr);
                } else {
                        break;
                }
@@ -371,7 +309,7 @@ skip_domain_literal (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        while (*inptr && *inptr != ']') {
                skip_domain_subliteral (&inptr);
                if (*inptr && *inptr != ']')
@@ -387,7 +325,7 @@ skip_domain (const char **in)
        const char *save, *inptr = *in;
        
        while (inptr && *inptr) {
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr == '[') {
                        /* domain literal */
                        inptr++;
@@ -399,7 +337,7 @@ skip_domain (const char **in)
                }
                
                save = inptr;
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr != '.') {
                        inptr = save;
                        break;
@@ -416,14 +354,15 @@ skip_addrspec (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        skip_word (&inptr);
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        while (*inptr == '.') {
                inptr++;
+               skip_cfws (&inptr);
                skip_word (&inptr);
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
        }
        
        if (*inptr == '@') {
@@ -439,7 +378,7 @@ skip_addr (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        if (*inptr == '<') {
                inptr++;
                skip_addrspec (&inptr);
@@ -457,7 +396,7 @@ skip_msgid (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        if (*inptr == '<') {
                inptr++;
                skip_addrspec (&inptr);
diff --git a/gmime/gmime-param.c b/gmime/gmime-param.c
index 3f357dd..d495566 100644
--- a/gmime/gmime-param.c
+++ b/gmime/gmime-param.c
@@ -94,7 +94,7 @@ decode_int (const char **in)
        const unsigned char *inptr;
        int digit, n = 0;
        
-       decode_lwsp (in);
+       skip_cfws (in);
        
        inptr = (const unsigned char *) *in;
        while (isdigit ((int) *inptr)) {
@@ -122,7 +122,7 @@ decode_quoted_string (const char **in)
        char *outptr, *out = NULL;
        gboolean unescape = FALSE;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        if (*inptr != '"') {
                *in = inptr;
@@ -169,7 +169,7 @@ decode_token (const char **in)
        const char *inptr = *in;
        const char *start;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        start = inptr;
 #ifdef STRICT_PARSER
@@ -200,7 +200,7 @@ decode_value (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        *in = inptr;
        
        if (*inptr == '"') {
@@ -225,7 +225,7 @@ decode_param_token (const char **in)
        const char *inptr = *in;
        const char *start;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        start = inptr;
        while (is_ttoken (*inptr) && *inptr != '*')
@@ -250,13 +250,13 @@ decode_rfc2184_param (const char **in, char **paramp, int *part, gboolean *encod
        
        param = decode_param_token (&inptr);
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        if (*inptr == '*') {
                is_rfc2184 = TRUE;
                inptr++;
                
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr == '=') {
                        /* form := param*=value */
                        *encoded = TRUE;
@@ -264,12 +264,12 @@ decode_rfc2184_param (const char **in, char **paramp, int *part, gboolean *encod
                        /* form := param*#=value or param*#*=value */
                        *part = decode_int (&inptr);
                        
-                       decode_lwsp (&inptr);
+                       skip_cfws (&inptr);
                        if (*inptr == '*') {
                                /* form := param*#*=value */
                                inptr++;
                                *encoded = TRUE;
-                               decode_lwsp (&inptr);
+                               skip_cfws (&inptr);
                        }
                }
        }
@@ -549,12 +549,12 @@ decode_param_list (GMimeParserOptions *options, const char *in)
        t = (struct _rfc2184_param *) &list;
        rfc2184_hash = g_hash_table_new (g_mime_strcase_hash, g_mime_strcase_equal);
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        
        do {
                /* invalid format? */
                if (!decode_param (options, &inptr, &name, &value, &id, &encoded)) {
-                       decode_lwsp (&inptr);
+                       skip_cfws (&inptr);
                        
                        if (*inptr == ';')
                                continue;
@@ -596,7 +596,7 @@ decode_param_list (GMimeParserOptions *options, const char *in)
                        tail = param;
                }
                
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
        } while (*inptr++ == ';');
        
        g_hash_table_destroy (rfc2184_hash);
diff --git a/gmime/gmime-parse-utils.c b/gmime/gmime-parse-utils.c
index ccb9e4e..230bb4d 100644
--- a/gmime/gmime-parse-utils.c
+++ b/gmime/gmime-parse-utils.c
@@ -56,7 +56,7 @@ g_mime_parse_content_type (const char **in, char **type, char **subtype)
        register const char *inptr;
        const char *start = *in;
        
-       decode_lwsp (&start);
+       skip_cfws (&start);
        inptr = start;
        
        /* decode the type */
@@ -66,7 +66,7 @@ g_mime_parse_content_type (const char **in, char **type, char **subtype)
        *type = g_strndup (start, (size_t) (inptr - start));
        
        start = inptr;
-       decode_lwsp (&start);
+       skip_cfws (&start);
        
        /* check for type/subtype delimeter */
        if (*start++ != '/') {
@@ -76,7 +76,7 @@ g_mime_parse_content_type (const char **in, char **type, char **subtype)
                return FALSE;
        }
        
-       decode_lwsp (&start);
+       skip_cfws (&start);
        inptr = start;
        
        /* decode the subtype */
@@ -101,41 +101,178 @@ g_mime_parse_content_type (const char **in, char **type, char **subtype)
 
 
 /**
- * g_mime_decode_lwsp:
- * @in: address of input text string
+ * g_mime_skip_comment:
+ * @in: address of input string
+ *
+ * Skips a comment.
  *
- * Skips past any LWSP or rfc822 comments in *@in and updates @in.
+ * Returns: %TRUE on success or %FALSE otherwise.
  **/
-void
-g_mime_decode_lwsp (const char **in)
+gboolean
+g_mime_skip_comment (const char **in)
 {
-       const char *inptr = *in;
+       register const char *inptr = *in;
+       int depth = 1;
        
-       while (*inptr && (*inptr == '(' || is_lwsp (*inptr))) {
-               while (*inptr && is_lwsp (*inptr))
+       /* skip over the '(' */
+       inptr++;
+       while (*inptr && depth) {
+               if (*inptr == '\\' && *(inptr + 1))
                        inptr++;
+               else if (*inptr == '(')
+                       depth++;
+               else if (*inptr == ')')
+                       depth--;
                
-               /* skip over any comments */
-               if (*inptr == '(') {
-                       int depth = 1;
-                       
-                       inptr++;
-                       while (*inptr && depth) {
-                               if (*inptr == '\\' && *(inptr + 1))
-                                       inptr++;
-                               else if (*inptr == '(')
-                                       depth++;
-                               else if (*inptr == ')')
-                                       depth--;
-                               
-                               inptr++;
-                       }
+               inptr++;
+       }
+       
+       *in = inptr;
+       
+       return depth == 0;
+}
+
+
+/**
+ * g_mime_skip_lwsp:
+ * @in: address of input string
+ *
+ * Skips whitespace.
+ *
+ * Returns: %TRUE if any input was skipped or %FALSE otherwise.
+ **/
+gboolean
+g_mime_skip_lwsp (const char **in)
+{
+       register const char *inptr = *in;
+       const char *start = inptr;
+       
+       while (is_lwsp (*inptr))
+               inptr++;
+       
+       *in = inptr;
+       
+       return inptr > start;
+}
+
+
+/**
+ * g_mime_skip_cfws:
+ * @in: address of input string
+ *
+ * Skips comments and whitespace.
+ *
+ * Returns: %TRUE on success or %FALSE on error.
+ **/
+gboolean
+g_mime_skip_cfws (const char **in)
+{
+       const char *inptr = *in;
+       
+       skip_lwsp (&inptr);
+       
+       while (*inptr == '(') {
+               if (!skip_comment (&inptr))
+                       return FALSE;
+               
+               skip_lwsp (&inptr);
+       }
+       
+       *in = inptr;
+       
+       return TRUE;
+}
+
+
+/**
+ * g_mime_skip_quoted:
+ * @in: address of input string
+ *
+ * Skips a quoted string.
+ *
+ * Returns: %TRUE on success or %FALSE on error.
+ **/
+gboolean
+g_mime_skip_quoted (const char **in)
+{
+       register const char *inptr = *in;
+       gboolean escaped = FALSE;
+       
+       /* skip over leading '"' */
+       inptr++;
+       
+       while (*inptr) {
+               if (*inptr == '\\') {
+                       escaped = !escaped;
+               } else if (!escaped) {
+                       if (*inptr == '"')
+                               break;
+               } else {
+                       escaped = FALSE;
                }
+               
+               inptr++;
        }
        
+       if (*inptr == '\0') {
+               *in = inptr;
+               
+               return FALSE;
+       }
+       
+       /* skip over the closing '"' */
+       inptr++;
+       
+       *in = inptr;
+       
+       return TRUE;
+}
+
+
+/**
+ * g_mime_skip_atom:
+ * @in: address of input string
+ *
+ * Skips an atom.
+ *
+ * Returns: %TRUE if any input was skipped or %FALSE otherwise.
+ **/
+gboolean
+g_mime_skip_atom (const char **in)
+{
+       register const char *inptr = *in;
+       const char *start = inptr;
+       
+       while (is_atom (*inptr))
+               inptr++;
+       
        *in = inptr;
+       
+       return inptr > start;
 }
 
+
+/**
+ * g_mime_skip_word:
+ * @in: address of input string
+ *
+ * Skips a word token.
+ *
+ * Returns: %TRUE on success or %FALSE otherwise.
+ **/
+gboolean
+g_mime_skip_word (const char **in)
+{
+       if (**in == '"')
+               return skip_quoted (in);
+       
+       if (is_atom (**in))
+               return skip_atom (in);
+       
+       return FALSE;
+}
+
+
 static const char *
 decode_quoted_string (const char **in)
 {
@@ -195,7 +332,7 @@ g_mime_decode_word (const char **in)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        if (*inptr == '"') {
                *in = inptr;
                return decode_quoted_string (in);
@@ -216,10 +353,11 @@ decode_subliteral (const char **in, GString *domain)
                        g_string_append_c (domain, *inptr);
                        inptr++;
                        got = TRUE;
-               } else if (is_lwsp (*inptr))
-                       decode_lwsp (&inptr);
-               else
+               } else if (is_lwsp (*inptr)) {
+                       skip_cfws (&inptr);
+               } else {
                        break;
+               }
        }
        
        *in = inptr;
@@ -232,7 +370,7 @@ decode_domain_literal (const char **in, GString *domain)
 {
        const char *inptr = *in;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        while (*inptr && *inptr != ']') {
                if (decode_subliteral (&inptr, domain) && *inptr == '.') {
                        g_string_append_c (domain, *inptr);
@@ -268,7 +406,7 @@ g_mime_decode_domain (const char **in, GString *domain)
        
        inptr = *in;
        while (inptr && *inptr) {
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr == '[') {
                        /* domain literal */
                        g_string_append_c (domain, '[');
@@ -294,7 +432,7 @@ g_mime_decode_domain (const char **in, GString *domain)
                }
                
                save = inptr;
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr != '.') {
                        inptr = save;
                        break;
diff --git a/gmime/gmime-parse-utils.h b/gmime/gmime-parse-utils.h
index 0a56f56..ebc2a5e 100644
--- a/gmime/gmime-parse-utils.h
+++ b/gmime/gmime-parse-utils.h
@@ -26,8 +26,24 @@ G_BEGIN_DECLS
 
 G_GNUC_INTERNAL gboolean g_mime_parse_content_type (const char **in, char **type, char **subtype);
 
-G_GNUC_INTERNAL void g_mime_decode_lwsp (const char **in);
-#define decode_lwsp(in) g_mime_decode_lwsp (in)
+G_GNUC_INTERNAL gboolean g_mime_skip_comment (const char **in);
+#define skip_comment(in) g_mime_skip_comment (in)
+
+G_GNUC_INTERNAL gboolean g_mime_skip_lwsp (const char **in);
+#define skip_lwsp(in) g_mime_skip_lwsp (in)
+
+G_GNUC_INTERNAL gboolean g_mime_skip_cfws (const char **in);
+#define skip_cfws(in) g_mime_skip_cfws (in)
+
+G_GNUC_INTERNAL gboolean g_mime_skip_quoted (const char **in);
+#define skip_quoted(in) g_mime_skip_quoted (in)
+
+G_GNUC_INTERNAL gboolean g_mime_skip_atom (const char **in);
+#define skip_atom(in) g_mime_skip_atom (in)
+
+G_GNUC_INTERNAL gboolean g_mime_skip_word (const char **in);
+#define skip_word(in) g_mime_skip_word (in)
+
 
 G_GNUC_INTERNAL const char *g_mime_decode_word (const char **in);
 #define decode_word(in) g_mime_decode_word (in)
diff --git a/gmime/gmime-utils.c b/gmime/gmime-utils.c
index a77e8b9..b7f413d 100644
--- a/gmime/gmime-utils.c
+++ b/gmime/gmime-utils.c
@@ -902,7 +902,7 @@ decode_addrspec (const char **in)
        GString *addrspec;
        char *str;
        
-       decode_lwsp (in);
+       skip_cfws (in);
        inptr = *in;
        
        if (!(word = decode_word (&inptr))) {
@@ -914,12 +914,12 @@ decode_addrspec (const char **in)
        g_string_append_len (addrspec, word, (size_t) (inptr - word));
        
        /* get the rest of the local-part */
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        while (*inptr == '.') {
                g_string_append_c (addrspec, *inptr++);
                if ((word = decode_word (&inptr))) {
                        g_string_append_len (addrspec, word, (size_t) (inptr - word));
-                       decode_lwsp (&inptr);
+                       skip_cfws (&inptr);
                } else {
                        w(g_warning ("Invalid local-part in addr-spec: %s", *in));
                        goto exception;
@@ -958,16 +958,16 @@ decode_msgid (const char **in)
        const char *inptr = *in;
        char *msgid = NULL;
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        if (*inptr != '<') {
                w(g_warning ("Invalid msg-id; missing '<': %s", *in));
        } else {
                inptr++;
        }
        
-       decode_lwsp (&inptr);
+       skip_cfws (&inptr);
        if ((msgid = decode_addrspec (&inptr))) {
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr != '>') {
                        w(g_warning ("Invalid msg-id; missing '>': %s", *in));
                } else {
@@ -1028,7 +1028,7 @@ g_mime_references_decode (const char *text)
        refs.next = NULL;
        
        while (*inptr) {
-               decode_lwsp (&inptr);
+               skip_cfws (&inptr);
                if (*inptr == '<') {
                        /* looks like a msg-id */
                        if ((msgid = decode_msgid (&inptr))) {
diff --git a/gmime/internet-address.c b/gmime/internet-address.c
index 940d1d4..44ee15a 100644
--- a/gmime/internet-address.c
+++ b/gmime/internet-address.c
@@ -1276,384 +1276,683 @@ internet_address_list_writer (InternetAddressList *list, GString *str)
        _internet_address_list_to_string (list, flags, &linelen, str);
 }
 
-static void
-_internet_address_decode_name (GMimeParserOptions *options, InternetAddress *ia, GString *name)
+
+static char *
+decode_name (GMimeParserOptions *options, const char *name, size_t len)
 {
        char *value, *buf = NULL;
-       char *phrase;
        
-       if (!g_utf8_validate (name->str, name->len, NULL)) {
+       if (!g_utf8_validate (name, len, NULL)) {
                /* A (broken) mailer has sent us raw 8bit/multibyte text data... */
-               buf = g_mime_utils_decode_8bit (options, name->str, name->len);
-               phrase = buf;
+               buf = g_mime_utils_decode_8bit (options, name, len);
        } else {
-               phrase = name->str;
+               buf = g_strndup (name, len);
        }
        
        /* decode the phrase */
-       g_mime_utils_unquote_string (phrase);
-       value = g_mime_utils_header_decode_phrase (options, phrase);
-       g_free (ia->name);
-       ia->name = value;
+       g_mime_utils_unquote_string (buf);
+       value = g_mime_utils_header_decode_phrase (options, buf);
+       g_strstrip (value);
        g_free (buf);
+       
+       return value;
 }
 
-static InternetAddress *decode_address (GMimeParserOptions *options, const char **in);
 
-static void
-skip_lwsp (const char **in)
+typedef enum {
+       ALLOW_MAILBOX = 1 << 0,
+       ALLOW_GROUP   = 1 << 1,
+       ALLOW_ANY     = ALLOW_MAILBOX | ALLOW_GROUP
+} AddressParserFlags;
+
+static gboolean
+decode_route (const char **in)
 {
-       register const char *inptr = *in;
+       const char *start = *in;
+       const char *inptr = *in;
+       GString *route;
        
-       while (*inptr && is_lwsp (*inptr))
+       route = g_string_new ("");
+       
+       do {
+               inptr++;
+               
+               g_string_append_c (route, '@');
+               if (!decode_domain (&inptr, route)) {
+                       g_string_free (route, TRUE);
+                       goto error;
+               }
+               
+               skip_cfws (&inptr);
+               if (*inptr == ',') {
+                       g_string_append_c (route, ',');
+                       inptr++;
+                       skip_cfws (&inptr);
+                       
+                       /* obs-domain-lists allow commas with nothing between them... */
+                       while (*inptr == ',') {
+                               inptr++;
+                               skip_cfws (&inptr);
+                       }
+               }
+       } while (*inptr == '@');
+       
+       g_string_free (route, TRUE);
+       skip_cfws (&inptr);
+       
+       if (*inptr != ':') {
+               w(g_warning ("Invalid route domain-list, missing ':': %.*s", inptr - start, start));
+               goto error;
+       }
+       
+       *in = inptr;
+       
+       return TRUE;
+       
+ error:
+       
+       while (*inptr && *inptr != ':' && *inptr != '>')
                inptr++;
        
        *in = inptr;
+       
+       return FALSE;
 }
 
-static InternetAddress *
-decode_addrspec (const char **in)
+static gboolean
+localpart_parse (GString *localpart, const char **in)
 {
-       InternetAddress *mailbox = NULL;
-       const char *start, *inptr, *word;
-       gboolean got_local = FALSE;
-       GString *addr;
-       size_t len;
+       const char *inptr = *in;
+       const char *start = *in;
+       const char *word;
        
-       addr = g_string_new ("");
-       inptr = *in;
+       do {
+               word = inptr;
+               
+               if (!skip_word (&inptr))
+                       goto error;
+               
+               if (!g_utf8_validate (word, (size_t) (inptr - word), NULL))
+                       goto error;
+               
+               g_string_append_len (localpart, word, (size_t) (inptr - word));
+               
+               if (!skip_cfws (&inptr))
+                       goto error;
+               
+               if (*inptr != '.')
+                       break;
+               
+               g_string_append_c (localpart, *inptr++);
+               
+               if (!skip_cfws (&inptr))
+                       goto error;
+               
+               if (*inptr == '\0')
+                       goto error;
+       } while (TRUE);
        
-       decode_lwsp (&inptr);
+       *in = inptr;
        
-       /* some spam bots set their addresses to stuff like: ).ORHH em ca */
-       while (*inptr && !(*inptr == '"' || is_atom (*inptr)))
-               inptr++;
+       return TRUE;
        
-       start = inptr;
+ error:
+       *in = inptr;
        
-       /* extract the first word of the local-part */
-       if ((word = decode_word (&inptr))) {
-               g_string_append_len (addr, word, (size_t) (inptr - word));
-               decode_lwsp (&inptr);
-               got_local = TRUE;
-       }
+       return FALSE;
+}
+
+#define COMMA_GREATER_THAN_OR_SEMICOLON ",>;"
+
+static gboolean
+dotatom_parse (GString *str, const char **in, const char *sentinels)
+{
+       const char *atom, *comment;
+       const char *inptr = *in;
+       const char *start = *in;
        
-       /* extract the rest of the local-part */
-       while (word && *inptr == '.') {
-               /* Note: According to the spec, only a single '.' is
-                * allowed between word tokens in the local-part of an
-                * addr-spec token, but according to Evolution bug
-                * #547969, some Japanese cellphones have email
-                * addresses that look like x  y somewhere jp */
-               do {
+       do {
+               if (!is_atom (*inptr))
+                       goto error;
+               
+               atom = inptr;
+               while (is_atom (*inptr))
                        inptr++;
-                       decode_lwsp (&inptr);
-                       g_string_append_c (addr, '.');
-               } while (*inptr == '.');
                
-               if ((word = decode_word (&inptr)))
-                       g_string_append_len (addr, word, (size_t) (inptr - word));
+               if (!g_utf8_validate (atom, (size_t) (inptr - atom), NULL))
+                       goto error;
                
-               decode_lwsp (&inptr);
-       }
-       
-       if (*inptr == '@') {
-               len = addr->len;
+               g_string_append_len (str, atom, (size_t) (inptr - atom));
                
-               g_string_append_c (addr, '@');
-               inptr++;
+               comment = inptr;
+               if (!skip_cfws (&inptr))
+                       goto error;
                
-               if (!decode_domain (&inptr, addr)) {
-                       /* drop the @domain and continue as if it weren't there */
-                       w(g_warning ("Missing domain in addr-spec: %.*s",
-                                    inptr - start, start));
-                       g_string_truncate (addr, len);
+               if (*inptr != '.') {
+                       inptr = comment;
+                       break;
                }
-       } else if (got_local) {
-               w(g_warning ("Missing '@' and domain in addr-spec: %.*s",
-                            inptr - start, start));
-       }
+               
+               /* skip over the '.' */
+               inptr++;
+               
+               if (!skip_cfws (&inptr))
+                       goto error;
+               
+               /* allow domains to end with a '.', but strip it off */
+               if (*inptr == '\0' || strchr (sentinels, *inptr))
+                       break;
+               
+               g_string_append_c (str, '.');
+       } while (TRUE);
        
        *in = inptr;
        
-       if (!got_local) {
-               w(g_warning ("Invalid addr-spec, missing local-part: %.*s",
-                            inptr - start, start));
-               g_string_free (addr, TRUE);
-               return NULL;
-       }
+       return TRUE;
        
-       mailbox = g_object_newv (INTERNET_ADDRESS_TYPE_MAILBOX, 0, NULL);
-       ((InternetAddressMailbox *) mailbox)->addr = addr->str;
-       g_string_free (addr, FALSE);
+ error:
+       *in = inptr;
        
-       return mailbox;
+       return FALSE;
 }
 
-static InternetAddress *
-decode_group (GMimeParserOptions *options, const char **in)
+static gboolean
+domain_literal_parse (GString *str, const char **in)
 {
-       InternetAddressGroup *group;
-       InternetAddress *addr;
-       const char *inptr;
+       const char *inptr = *in;
        
-       inptr = *in;
+       g_string_append_c (str, '[');
+       inptr++;
        
-       addr = internet_address_group_new (NULL);
-       group = (InternetAddressGroup *) addr;
+       skip_lwsp (&inptr);
        
-       decode_lwsp (&inptr);
-       while (*inptr && *inptr != ';') {
-               InternetAddress *member;
+       do {
+               while (is_dtext (*inptr))
+                       g_string_append_c (str, *inptr++);
                
-               if ((member = decode_address (options, &inptr)))
-                       _internet_address_group_add_member (group, member);
+               skip_lwsp (&inptr);
                
-               decode_lwsp (&inptr);
-               while (*inptr == ',') {
-                       inptr++;
-                       decode_lwsp (&inptr);
-                       if ((member = decode_address (options, &inptr)))
-                               _internet_address_group_add_member (group, member);
-                       
-                       decode_lwsp (&inptr);
-               }
-       }
+               if (*inptr == '\0')
+                       goto error;
+               
+               if (*inptr == ']')
+                       break;
+               
+               if (!is_dtext (*inptr))
+                       goto error;
+       } while (TRUE);
+       
+       g_string_append_c (str, ']');
+       *in = inptr + 1;
+       
+       return TRUE;
        
+ error:
        *in = inptr;
        
-       return addr;
+       return FALSE;
 }
 
 static gboolean
-decode_route (const char **in)
+domain_parse (GString *str, const char **in, const char *sentinels)
 {
+       if (**in == '[')
+               return domain_literal_parse (str, in);
+       
+       return dotatom_parse (str, in, sentinels);
+}
+
+static gboolean
+addrspec_parse (const char **in, const char *sentinels, char **addrspec)
+{
+       const char *inptr = *in;
        const char *start = *in;
+       GString *str;
+       
+       str = g_string_new ("");
+       
+       if (!localpart_parse (str, &inptr))
+               goto error;
+       
+       if (*inptr == '\0' || strchr (sentinels, *inptr)) {
+               *addrspec = g_string_free (str, FALSE);
+               *in = inptr;
+               return TRUE;
+       }
+       
+       if (*inptr != '@')
+               goto error;
+       
+       g_string_append_c (str, *inptr++);
+       
+       if (*inptr == '\0')
+               goto error;
+       
+       if (!skip_cfws (&inptr))
+               goto error;
+       
+       if (*inptr == '\0')
+               goto error;
+       
+       if (!domain_parse (str, &inptr, sentinels))
+               goto error;
+       
+       *addrspec = g_string_free (str, FALSE);
+       *in = inptr;
+       
+       return TRUE;
+       
+ error:
+       g_string_free (str, TRUE);
+       *addrspec = NULL;
+       *in = inptr;
+       
+       return FALSE;
+}
+
+// TODO: rename to angleaddr_parse??
+static gboolean
+mailbox_parse (GMimeParserOptions *options, const char **in, const char *name, InternetAddress **address)
+{
        const char *inptr = *in;
-       GString *route;
+       char *addrspec = NULL;
        
-       route = g_string_new ("");
+       /* skip over the '<' */
+       inptr++;
        
-       do {
+       /* Note: check for excessive angle brackets like the example described in section 7.1.2 of rfc7103... 
*/
+       if (*inptr == '<') {
+               if (options->addresses != GMIME_RFC_COMPLIANCE_LOOSE)
+                       goto error;
+               
+               do {
+                       inptr++;
+               } while (*inptr == '<');
+       }
+       
+       if (*inptr == '\0')
+               goto error;
+       
+       if (!skip_cfws (&inptr))
+               goto error;
+       
+       if (*inptr == '@') {
+               if (!decode_route (&inptr))
+                       goto error;
+               
+               if (*inptr != ':')
+                       goto error;
+               
                inptr++;
                
-               g_string_append_c (route, '@');
-               if (!decode_domain (&inptr, route)) {
-                       g_string_free (route, TRUE);
+               if (!skip_cfws (&inptr))
                        goto error;
-               }
+       }
+       
+       // Note: The only syntactically correct sentinel token here is the '>', but alas... to deal with the 
first example
+       // in section 7.1.5 of rfc7103, we need to at least handle ',' as a sentinel and might as well handle 
';' as well
+       // in case the mailbox is within a group address.
+       //
+       // Example: <third example net, fourth example net>
+       if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec))
+               goto error;
+       
+       if (!skip_cfws (&inptr))
+               goto error;
+       
+       if (*inptr != '>') {
+               if (options->addresses != GMIME_RFC_COMPLIANCE_LOOSE)
+                       goto error;
+       } else {
+               /* skip over the '>' */
+               inptr++;
                
-               decode_lwsp (&inptr);
-               if (*inptr == ',') {
-                       g_string_append_c (route, ',');
-                       inptr++;
-                       decode_lwsp (&inptr);
+               /* Note: check for excessive angle brackets like the example described in section 7.1.2 of 
rfc7103... */
+               if (*inptr == '>') {
+                       if (options->addresses != GMIME_RFC_COMPLIANCE_LOOSE)
+                               goto error;
                        
-                       /* obs-domain-lists allow commas with nothing between them... */
-                       while (*inptr == ',') {
+                       do {
                                inptr++;
-                               decode_lwsp (&inptr);
-                       }
+                       } while (*inptr == '>');
                }
-       } while (*inptr == '@');
-       
-       g_string_free (route, TRUE);
-       decode_lwsp (&inptr);
-       
-       if (*inptr != ':') {
-               w(g_warning ("Invalid route domain-list, missing ':': %.*s", inptr - start, start));
-               goto error;
        }
        
-       /* eat the ':' */
-       *in = inptr + 1;
+       *address = internet_address_mailbox_new (name, addrspec);
+       g_free (addrspec);
+       *in = inptr;
        
        return TRUE;
        
  error:
+       g_free (addrspec);
+       *address = NULL;
+       *in = inptr;
        
-       while (*inptr && *inptr != ':' && *inptr != '>')
-               inptr++;
+       return FALSE;
+}
+
+static gboolean address_list_parse (InternetAddressList *list, GMimeParserOptions *options, const char **in, 
gboolean is_group);
+
+static gboolean
+group_parse (GMimeParserOptions *options, const char **in, const char *name, InternetAddress **address)
+{
+       InternetAddressGroup *group;
+       const char *inptr = *in;
+       
+       /* skip over the ':' */
+       inptr++;
+       
+       if (*inptr == '\0') {
+               *address = NULL;
+               *in = inptr;
+               
+               return FALSE;
+       }
        
-       if (*inptr == ':')
+       group = (InternetAddressGroup *) internet_address_group_new (name);
+       address_list_parse (group->members, options, &inptr, TRUE);
+       
+       if (*inptr != ';') {
+               while (*inptr && *inptr != ';')
+                       inptr++;
+       } else {
                inptr++;
+       }
        
+       *address = (InternetAddress *) group;
        *in = inptr;
        
-       return FALSE;
+       return TRUE;
 }
 
-static InternetAddress *
-decode_address (GMimeParserOptions *options, const char **in)
+static gboolean
+address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char **in, InternetAddress 
**address)
 {
-       const char *inptr, *start, *word, *comment = NULL;
-       InternetAddress *addr = NULL;
-       gboolean has_lwsp = FALSE;
-       gboolean is_word;
-       GString *name;
+       gboolean strict = options->addresses != GMIME_RFC_COMPLIANCE_LOOSE;
+       gboolean trim_leading_quote = FALSE;
+       const char *inptr = *in;
+       const char *start;
+       size_t length;
        
-       decode_lwsp (in);
-       start = inptr = *in;
+       if (!skip_cfws (&inptr) || *inptr == '\0')
+               goto error;
        
-       name = g_string_new ("");
+       /* keep track of the start & length of the phrase */
+       start = inptr;
+       length = 0;
        
-       /* Both groups and mailboxes can begin with a phrase (denoting
-        * the display name for the address). Collect all of the
-        * tokens that make up this name phrase.
-        */
        while (*inptr) {
-               if ((word = decode_word (&inptr))) {
-                       g_string_append_len (name, word, (size_t) (inptr - word));
-                       
-               check_lwsp:
-                       word = inptr;
-                       skip_lwsp (&inptr);
-                       
-                       /* is the next token a word token? */
-                       is_word = *inptr == '"' || is_atom (*inptr);
-                       
-                       if (inptr > word && is_word) {
-                               g_string_append_c (name, ' ');
-                               has_lwsp = TRUE;
-                       }
-                       
-                       if (is_word)
-                               continue;
-               }
-               
-               /* specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
-                *             /  "," / ";" / ":" / "\" / <">  ;  string, to use
-                *             /  "." / "[" / "]"              ;  within a word.
-                */
-               if (*inptr == ':') {
-                       /* rfc2822 group */
-                       inptr++;
-                       addr = decode_group (options, &inptr);
-                       decode_lwsp (&inptr);
-                       if (*inptr != ';')
-                               w(g_warning ("Invalid group spec, missing closing ';': %.*s",
-                                            inptr - start, start));
-                       else
-                               inptr++;
-                       break;
-               } else if (*inptr == '<') {
-                       /* rfc2822 angle-addr */
-                       inptr++;
-                       
-                       /* check for obsolete routing... */
-                       if (*inptr != '@' || decode_route (&inptr)) {
-                               /* rfc2822 addr-spec */
-                               addr = decode_addrspec (&inptr);
-                       }
+               if (strict) {
+                       if (!skip_word (&inptr))
+                               break;
+               } else if (*inptr == '"') {
+                       const char *qstring = inptr;
                        
-                       decode_lwsp (&inptr);
-                       if (*inptr != '>') {
-                               w(g_warning ("Invalid rfc2822 angle-addr, missing closing '>': %.*s",
-                                            inptr - start, start));
+                       if (!skip_quoted (&inptr)) {
+                               inptr = qstring + 1;
                                
-                               while (*inptr && *inptr != '>' && *inptr != ',')
-                                       inptr++;
+                               skip_lwsp (&inptr);
                                
-                               if (*inptr == '>')
-                                       inptr++;
-                       } else {
-                               inptr++;
+                               if (!skip_atom (&inptr))
+                                       break;
+                               
+                               if (start == qstring)
+                                       trim_leading_quote = TRUE;
                        }
+               } else {
+                       if (!skip_atom (&inptr))
+                               break;
+               }
+               
+               length = (size_t) (inptr - start);
+               
+               do {
+                       if (!skip_cfws (&inptr))
+                               goto error;
                        
-                       /* if comment is non-NULL, we can check for a comment containing a name */
-                       comment = inptr;
-                       break;
-               } else if (*inptr == '(') {
-                       /* beginning of a comment, use decode_lwsp() to skip past it */
-                       decode_lwsp (&inptr);
-               } else if (*inptr && strchr ("@,;", *inptr)) {
-                       if (name->len == 0) {
-                               if (*inptr == '@') {
-                                       GString *domain;
-                                       
-                                       w(g_warning ("Unexpected address: %s: skipping.", start));
-                                       
-                                       /* skip over @domain? */
-                                       inptr++;
-                                       domain = g_string_new ("");
-                                       decode_domain (&inptr, domain);
-                                       g_string_free (domain, TRUE);
-                               } else {
-                                       /* empty address */
-                               }
+                       /* Note: some clients don't quote dots in the name */
+                       if (*inptr != '.')
                                break;
-                       } else if (has_lwsp) {
-                               /* assume this is just an unquoted special that we should
-                                  treat as part of the name */
-                               w(g_warning ("Unquoted '%c' in address name: %s: ignoring.", *inptr, start));
-                               g_string_append_c (name, *inptr);
-                               inptr++;
-                               
-                               goto check_lwsp;
-                       }
                        
-               addrspec:
-                       /* what we thought was a name was actually an addrspec? */
-                       g_string_truncate (name, 0);
-                       inptr = start;
+                       inptr++;
+               } while (TRUE);
+       }
+       
+       if (!skip_cfws (&inptr))
+               goto error;
+       
+       // specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
+       //             /  "," / ";" / ":" / "\" / <">  ;  string, to use
+       //             /  "." / "[" / "]"              ;  within a word.
+       
+       if (*inptr == '\0' || *inptr == ',' || *inptr == '>' || *inptr == ';') {
+               /* we've completely gobbled up an addr-spec w/o a domain */
+               char sentinel = *inptr != '\0' ? *inptr : ',';
+               char sentinels[2] = { sentinel, 0 };
+               char *name, *addrspec;
+               
+               /* rewind back to the beginning of the local-part */
+               inptr = start;
+               
+               if (!(flags & ALLOW_MAILBOX))
+                       goto error;
+               
+               if (!addrspec_parse (&inptr, sentinels, &addrspec))
+                       goto error;
+               
+               skip_lwsp (&inptr);
+               
+               if (*inptr == '(') {
+                       const char *comment = inptr;
+                       char *buf;
+                       
+                       if (!skip_comment (&inptr))
+                               goto error;
                        
-                       addr = decode_addrspec (&inptr);
+                       comment++;
                        
-                       /* if comment is non-NULL, we can check for a comment containing a name */
-                       comment = inptr;
-                       break;
-               } else if (*inptr == '.') {
-                       /* This would normally signify that we are
-                        * decoding the local-part of an addr-spec,
-                        * but sadly, it is common for broken mailers
-                        * to forget to quote/encode .'s in the name
-                        * phrase. */
-                       g_string_append_c (name, *inptr);
-                       inptr++;
+                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment));
+               } else {
+                       name = g_strdup ("");
+               }
+               
+               if (*inptr == '>') {
+                       if (strict)
+                               goto error;
                        
-                       goto check_lwsp;
-               } else if (*inptr) {
-                       /* Technically, these are all invalid tokens
-                        * but in the interest of being liberal in
-                        * what we accept, we'll ignore them. */
-                       w(g_warning ("Unexpected char '%c' in address: %s: ignoring.", *inptr, start));
-                       g_string_append_c (name, *inptr);
                        inptr++;
-                       
-                       goto check_lwsp;
+               }
+               
+               *address = internet_address_mailbox_new (name, addrspec);
+               g_free (addrspec);
+               g_free (name);
+               *in = inptr;
+               
+               return TRUE;
+       }
+       
+       if (*inptr == ':') {
+               /* rfc2822 group address */
+               const char *phrase = start;
+               gboolean retval;
+               char *name;
+               
+               if (!(flags & ALLOW_GROUP))
+                       goto error;
+               
+               if (trim_leading_quote) {
+                       phrase++;
+                       length--;
+               }
+               
+               if (length > 0) {
+                       name = decode_name (options, phrase, length);
                } else {
-                       goto addrspec;
+                       name = g_strdup ("");
                }
+               
+               retval = group_parse (options, &inptr, name, address);
+               g_free (name);
+               *in = inptr;
+               
+               return retval;
        }
        
-       /* Note: will also skip over any comments */
-       decode_lwsp (&inptr);
+       if (!(flags & ALLOW_MAILBOX))
+               goto error;
        
-       if (name->len == 0 && comment && inptr > comment) {
-               /* missing a name, look for a trailing comment */
-               if ((comment = memchr (comment, '(', inptr - comment))) {
-                       const char *cend;
+       if (*inptr == '@') {
+               /* we're either in the middle of an addr-spec token or we completely gobbled up an addr-spec 
w/o a domain */
+               char *name, *addrspec;
+               
+               /* rewind back to the beginning of the local-part */
+               inptr = start;
+               
+               if (!addrspec_parse (&inptr, COMMA_GREATER_THAN_OR_SEMICOLON, &addrspec))
+                       goto error;
+               
+               skip_lwsp (&inptr);
+               
+               if (*inptr == '(') {
+                       const char *comment = inptr;
+                       char *buf;
+                       
+                       if (!skip_comment (&inptr))
+                               goto error;
+                       
+                       comment++;
+                       
+                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment));
+               } else {
+                       name = g_strdup ("");
+               }
+               
+               if (!skip_cfws (&inptr)) {
+                       g_free (addrspec);
+                       g_free (name);
+                       goto error;
+               }
+               
+               if (*inptr == '\0') {
+                       *address = internet_address_mailbox_new (name, addrspec);
+                       g_free (addrspec);
+                       g_free (name);
+                       *in = inptr;
+                       
+                       return TRUE;
+               }
+               
+               if (*inptr == '<') {
+                       /* We have an address like "user example com <user example com>"; i.e. the name is an 
unquoted string with an '@'. */
+                       const char *end;
+                       
+                       if (strict)
+                               goto error;
                        
-                       /* find the end of the comment */
-                       cend = inptr - 1;
-                       while (cend > comment && is_lwsp (*cend))
-                               cend--;
+                       end = inptr;
+                       while (end > start && is_lwsp (*(end - 1)))
+                               end--;
+                       
+                       length = (size_t) (end - start);
+                       g_free (addrspec);
+                       g_free (name);
+                       
+                       /* fall through to the rfc822 angle-addr token case... */
+               } else {
+                       // Note: since there was no '<', there should not be a '>'... but we handle it anyway 
in order to
+                       // deal with the second Unbalanced Angle Brackets example in section 7.1.3: second 
example org>
+                       if (*inptr == '>') {
+                               if (strict)
+                                       goto error;
+                               
+                               inptr++;
+                       }
                        
-                       if (*cend == ')')
-                               cend--;
+                       *address = internet_address_mailbox_new (name, addrspec);
+                       g_free (addrspec);
+                       g_free (name);
+                       *in = inptr;
                        
-                       g_string_append_len (name, comment + 1, (size_t) (cend - comment));
+                       return TRUE;
+               }
+       }
+       
+       if (*inptr == '<') {
+               /* rfc2822 angle-addr token */
+               const char *phrase = start;
+               gboolean retval;
+               char *name;
+               
+               if (trim_leading_quote) {
+                       phrase++;
+                       length--;
+               }
+               
+               if (length > 0) {
+                       name = decode_name (options, phrase, length);
+               } else {
+                       name = g_strdup ("");
                }
+               
+               retval = mailbox_parse (options, &inptr, name, address);
+               g_free (name);
+               *in = inptr;
+               
+               return retval;
        }
        
-       if (addr && name->len > 0)
-               _internet_address_decode_name (options, addr, name);
+ error:
+       *address = NULL;
+       *in = inptr;
+       
+       return FALSE;
+}
+
+static gboolean
+address_list_parse (InternetAddressList *list, GMimeParserOptions *options, const char **in, gboolean 
is_group)
+{
+       InternetAddress *address;
+       const char *inptr;
+       
+       if (!skip_cfws (in))
+               return FALSE;
+       
+       inptr = *in;
+       
+       if (*inptr == '\0')
+               return FALSE;
        
-       g_string_free (name, TRUE);
+       while (*inptr) {
+               if (is_group && *inptr ==  ';')
+                       break;
+               
+               if (!address_parse (options, ALLOW_ANY, &inptr, &address)) {
+                       /* skip this address... */
+                       while (*inptr && *inptr != ',' && (!is_group || *inptr != ';'))
+                               inptr++;
+               } else {
+                       _internet_address_list_add (list, address);
+               }
+               
+               /* Note: we loop here in case there are any null addresses between commas */
+               do {
+                       if (!skip_cfws (&inptr)) {
+                               *in = inptr;
+                               
+                               return FALSE;
+                       }
+                       
+                       if (*inptr != ',')
+                               break;
+                       
+                       inptr++;
+               } while (TRUE);
+       }
        
        *in = inptr;
        
-       return addr;
+       return TRUE;
 }
 
 
@@ -1670,45 +1969,16 @@ decode_address (GMimeParserOptions *options, const char **in)
 InternetAddressList *
 internet_address_list_parse (GMimeParserOptions *options, const char *str)
 {
-       InternetAddressList *addrlist;
+       InternetAddressList *list;
        const char *inptr = str;
-       InternetAddress *addr;
-       const char *start;
        
-       addrlist = internet_address_list_new ();
-       
-       while (inptr && *inptr) {
-               start = inptr;
-               
-               if ((addr = decode_address (options, &inptr))) {
-                       _internet_address_list_add (addrlist, addr);
-               } else {
-                       w(g_warning ("Invalid or incomplete address: %.*s",
-                                    inptr - start, start));
-               }
-               
-               decode_lwsp (&inptr);
-               if (*inptr == ',') {
-                       inptr++;
-                       decode_lwsp (&inptr);
-                       
-                       /* obs-mbox-list and obs-addr-list allow for empty members (commas with nothing 
between them) */
-                       while (*inptr == ',') {
-                               inptr++;
-                               decode_lwsp (&inptr);
-                       }
-               } else if (*inptr) {
-                       w(g_warning ("Parse error at '%s': expected ','", inptr));
-                       /* try skipping to the next address */
-                       if ((inptr = strchr (inptr, ',')))
-                               inptr++;
-               }
-       }
+       g_return_val_if_fail (str != NULL, NULL);
        
-       if (addrlist->array->len == 0) {
-               g_object_unref (addrlist);
-               addrlist = NULL;
+       list = internet_address_list_new ();
+       if (!address_list_parse (list, options, &inptr, FALSE) || list->array->len == 0) {
+               g_object_unref (list);
+               return NULL;
        }
        
-       return addrlist;
+       return list;
 }
diff --git a/tests/test-mime.c b/tests/test-mime.c
index 038cb61..7b2fa85 100644
--- a/tests/test-mime.c
+++ b/tests/test-mime.c
@@ -69,9 +69,6 @@ static struct {
        { "fejj helixcode com",
          "fejj helixcode com",
          "fejj helixcode com" },
-       { "this is\n\ta folded name <folded name com>",
-         "this is a folded name <folded name com>",
-         "this is a folded name <folded name com>" },
        { "Jeffrey Stedfast <fejj helixcode com>",
          "Jeffrey Stedfast <fejj helixcode com>",
          "Jeffrey Stedfast <fejj helixcode com>" },
@@ -118,8 +115,8 @@ static struct {
          "Charles Kerr <charles@[127.0.0.1]>",
          "Charles Kerr <charles@[127.0.0.1]>" },
        { "Charles <charles@[127..0.1]>",
-         "Charles <charles@[127.0.1]>",
-         "Charles <charles@[127.0.1]>" },
+         "Charles <charles@[127..0.1]>",
+         "Charles <charles@[127..0.1]>" },
        { "Charles,, likes illegal commas <charles superpimp org>",
          "Charles, likes illegal commas <charles superpimp org>",
          "Charles, likes illegal commas <charles superpimp org>" },
@@ -192,8 +189,8 @@ static struct {
          "TEST <p p org>",
          "TEST <p p org>" },
        { "sdfasf wp pl,c tert wp pl,sffdg rtre op pl",
-         "sdfasf wp pl, c, sffdg rtre op pl",
-         "sdfasf wp pl, c, sffdg rtre op pl" },
+         "sdfasf wp pl, sffdg rtre op pl",
+         "sdfasf wp pl, sffdg rtre op pl" },
        
        /* obsolete routing address syntax tests */
        { "<@route:user domain com>",
@@ -210,7 +207,7 @@ static struct {
        const char *encoded;
 } broken_addrspec[] = {
        { "\"Biznes=?ISO-8859-2?Q?_?=INTERIA.PL\"=?ISO-8859-2?Q?_?=<biuletyny firma interia pl>",
-         "\"Biznes INTERIA.PL \" <biuletyny firma interia pl>",
+         "\"Biznes INTERIA.PL\" <biuletyny firma interia pl>",
          "\"Biznes INTERIA.PL\" <biuletyny firma interia pl>", },
        /* UTF-8 sequence split between multiple encoded-word tokens */
        { "=?utf-8?Q?{#D=C3=A8=C3=A9=C2=A3=C3=A5=C3=BD_M$=C3=A1=C3?= =?utf-8?Q?=AD.=C3=A7=C3=B8m@#}?= <user 
domain com>",
@@ -240,7 +237,7 @@ test_addrspec (GMimeParserOptions *options, gboolean test_broken)
                testsuite_check ("addrspec[%u]", i);
                try {
                        if (!(addrlist = internet_address_list_parse (options, addrspec[i].input)))
-                               throw (exception_new ("could not parse addr-spec"));
+                               throw (exception_new ("could not parse: %s", addrspec[i].input));
                        
                        str = internet_address_list_to_string (addrlist, FALSE);
                        if (strcmp (addrspec[i].display, str) != 0)



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