[gmime] Updated InternetAddress and GMimeParam to capture the charset used in rfc2047 encoded-words



commit a2dd94286a545cf83c707191f0534506186dda44
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Thu Mar 16 20:03:43 2017 -0400

    Updated InternetAddress and GMimeParam to capture the charset used in rfc2047 encoded-words

 gmime/gmime-internal.h   |    2 +
 gmime/gmime-param.c      |    9 ++-
 gmime/gmime-utils.c      |   71 ++++++++++++++++++++---
 gmime/internet-address.c |   37 ++++++++-----
 tests/test-mime.c        |  140 ++++++++++++++++++++++++++++++----------------
 5 files changed, 185 insertions(+), 74 deletions(-)
---
diff --git a/gmime/gmime-internal.h b/gmime/gmime-internal.h
index 0ddf70b..8afc1c7 100644
--- a/gmime/gmime-internal.h
+++ b/gmime/gmime-internal.h
@@ -69,6 +69,8 @@ G_GNUC_INTERNAL void _g_mime_object_set_header (GMimeObject *object, const char
 /* utils */
 G_GNUC_INTERNAL char *_g_mime_utils_unstructured_header_fold (GMimeParserOptions *options, const char 
*field, const char *value);
 G_GNUC_INTERNAL char *_g_mime_utils_structured_header_fold (GMimeParserOptions *options, const char *field, 
const char *value);
+G_GNUC_INTERNAL char *_g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text, const 
char **charset);
+G_GNUC_INTERNAL char *_g_mime_utils_header_decode_phrase (GMimeParserOptions *options, const char *text, 
const char **charset);
 
 G_END_DECLS
 
diff --git a/gmime/gmime-param.c b/gmime/gmime-param.c
index f56e99a..ddb37f4 100644
--- a/gmime/gmime-param.c
+++ b/gmime/gmime-param.c
@@ -1042,7 +1042,7 @@ decode_rfc2184_param (const char **in, char **namep, int *part, gboolean *encode
 
 static gboolean
 decode_param (GMimeParserOptions *options, const char **in, char **namep, char **valuep, int *id,
-             gboolean *encoded, GMimeParamEncodingMethod *method)
+             const char **rfc2047_charset, gboolean *encoded, GMimeParamEncodingMethod *method)
 {
        gboolean is_rfc2184 = FALSE;
        const char *inptr = *in;
@@ -1050,6 +1050,7 @@ decode_param (GMimeParserOptions *options, const char **in, char **namep, char *
        char *val;
        
        *method = GMIME_PARAM_ENCODING_METHOD_DEFAULT;
+       *rfc2047_charset = NULL;
        
        if ((is_rfc2184 = decode_rfc2184_param (&inptr, &name, id, encoded)))
                *method = GMIME_PARAM_ENCODING_METHOD_RFC2231;
@@ -1065,7 +1066,7 @@ decode_param (GMimeParserOptions *options, const char **in, char **namep, char *
                                 * this, we should handle this case.
                                 */
                                
-                               if ((val = g_mime_utils_header_decode_text (options, value))) {
+                               if ((val = _g_mime_utils_header_decode_text (options, value, 
rfc2047_charset))) {
                                        *method = GMIME_PARAM_ENCODING_METHOD_RFC2047;
                                        g_free (value);
                                        value = val;
@@ -1301,6 +1302,7 @@ decode_param_list (GMimeParserOptions *options, const char *in)
        struct _rfc2184_param *rfc2184, *list, *t;
        char *name, *value, *charset, *lang;
        GMimeParamEncodingMethod method;
+       const char *rfc2047_charset;
        struct _rfc2184_part *part;
        GHashTable *rfc2184_hash;
        const char *inptr = in;
@@ -1321,7 +1323,7 @@ decode_param_list (GMimeParserOptions *options, const char *in)
        
        do {
                /* invalid format? */
-               if (!decode_param (options, &inptr, &name, &value, &id, &encoded, &method)) {
+               if (!decode_param (options, &inptr, &name, &value, &id, &rfc2047_charset, &encoded, &method)) 
{
                        skip_cfws (&inptr);
                        
                        if (*inptr == ';')
@@ -1357,6 +1359,7 @@ decode_param_list (GMimeParserOptions *options, const char *in)
                                g_free (value);
                        } else {
                                /* normal parameter value */
+                               param->charset = rfc2047_charset ? g_strdup (rfc2047_charset) : NULL;
                                param->method = method;
                                param->value = value;
                        }
diff --git a/gmime/gmime-utils.c b/gmime/gmime-utils.c
index 443c213..746c55d 100644
--- a/gmime/gmime-utils.c
+++ b/gmime/gmime-utils.c
@@ -52,6 +52,7 @@
 
 #include "gmime-utils.h"
 #include "gmime-common.h"
+#include "gmime-internal.h"
 #include "gmime-table-private.h"
 #include "gmime-parse-utils.h"
 #include "gmime-part.h"
@@ -2042,7 +2043,7 @@ rfc2047_token_decode (rfc2047_token *token, unsigned char *outbuf, int *state, g
 }
 
 static char *
-rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_t buflen)
+rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_t buflen, const char 
**charset_out)
 {
        rfc2047_token *token, *next;
        size_t outlen, ninval, len;
@@ -2058,6 +2059,9 @@ rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_
        
        decoded = g_string_sized_new (buflen + 1);
        outbuf = g_byte_array_sized_new (76);
+
+       if (charset_out)
+               *charset_out = NULL;
        
        token = tokens;
        while (token != NULL) {
@@ -2073,6 +2077,11 @@ rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_
                        state = 0;
                        save = 0;
                        
+                       /* Note: if any token was encoded in UTF-8, return UTF-8 as the charset used;
+                        * otherwise, use the first charset we encounter... */
+                       if (charset_out && (*charset_out == NULL || !g_ascii_strcasecmp (charset, "UTF-8")))
+                               *charset_out = charset;
+                       
                        /* find the end of the run (and measure the buffer length we'll need) */
                        while (next && next->encoding == encoding && !strcmp (next->charset, charset)) {
                                len += next->length;
@@ -2155,9 +2164,10 @@ rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_
 
 
 /**
- * g_mime_utils_header_decode_text:
+ * _g_mime_utils_header_decode_text:
  * @text: header text to decode
  * @options: a #GMimeParserOptions
+ * @charset: if non-%NULL, this will be set to the charset used in the rfc2047 encoded-word tokens
  *
  * Decodes an rfc2047 encoded 'text' header.
  *
@@ -2165,17 +2175,21 @@ rfc2047_decode_tokens (GMimeParserOptions *options, rfc2047_token *tokens, size_
  * header.
  **/
 char *
-g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text)
+_g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text, const char **charset)
 {
        rfc2047_token *tokens;
        char *decoded;
        size_t len;
        
-       if (text == NULL)
+       if (text == NULL) {
+               if (charset)
+                       *charset = NULL;
+               
                return g_strdup ("");
+       }
        
        tokens = tokenize_rfc2047_text (options, text, &len);
-       decoded = rfc2047_decode_tokens (options, tokens, len);
+       decoded = rfc2047_decode_tokens (options, tokens, len, charset);
        rfc2047_token_list_free (tokens);
        
        return decoded;
@@ -2183,9 +2197,27 @@ g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text)
 
 
 /**
- * g_mime_utils_header_decode_phrase:
+ * g_mime_utils_header_decode_text:
+ * @text: header text to decode
+ * @options: a #GMimeParserOptions
+ *
+ * Decodes an rfc2047 encoded 'text' header.
+ *
+ * Returns: a newly allocated UTF-8 string representing the the decoded
+ * header.
+ **/
+char *
+g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text)
+{
+       return _g_mime_utils_header_decode_text (options, text, NULL);
+}
+
+
+/**
+ * _g_mime_utils_header_decode_phrase:
  * @phrase: header to decode
  * @options: a #GMimeParserOptions
+ * @charset: if non-%NULL, this will be set to the charset used in the rfc2047 encoded-word tokens
  *
  * Decodes an rfc2047 encoded 'phrase' header.
  *
@@ -2193,23 +2225,44 @@ g_mime_utils_header_decode_text (GMimeParserOptions *options, const char *text)
  * header.
  **/
 char *
-g_mime_utils_header_decode_phrase (GMimeParserOptions *options, const char *phrase)
+_g_mime_utils_header_decode_phrase (GMimeParserOptions *options, const char *phrase, const char **charset)
 {
        rfc2047_token *tokens;
        char *decoded;
        size_t len;
        
-       if (phrase == NULL)
+       if (phrase == NULL) {
+               if (charset)
+                       *charset = NULL;
+               
                return g_strdup ("");
+       }
        
        tokens = tokenize_rfc2047_phrase (options, phrase, &len);
-       decoded = rfc2047_decode_tokens (options, tokens, len);
+       decoded = rfc2047_decode_tokens (options, tokens, len, charset);
        rfc2047_token_list_free (tokens);
        
        return decoded;
 }
 
 
+/**
+ * g_mime_utils_header_decode_phrase:
+ * @phrase: header to decode
+ * @options: a #GMimeParserOptions
+ *
+ * Decodes an rfc2047 encoded 'phrase' header.
+ *
+ * Returns: a newly allocated UTF-8 string representing the the decoded
+ * header.
+ **/
+char *
+g_mime_utils_header_decode_phrase (GMimeParserOptions *options, const char *phrase)
+{
+       return _g_mime_utils_header_decode_phrase (options, phrase, NULL);
+}
+
+
 /* rfc2047 version of quoted-printable */
 static size_t
 quoted_encode (const char *in, size_t len, unsigned char *out, gushort safemask)
diff --git a/gmime/internet-address.c b/gmime/internet-address.c
index 8b4e075..3ca008e 100644
--- a/gmime/internet-address.c
+++ b/gmime/internet-address.c
@@ -32,9 +32,9 @@
 #include "gmime-table-private.h"
 #include "gmime-parse-utils.h"
 #include "gmime-iconv-utils.h"
+#include "gmime-internal.h"
 #include "gmime-events.h"
 #include "gmime-utils.h"
-#include "list.h"
 
 
 #ifdef ENABLE_WARNINGS
@@ -1278,7 +1278,7 @@ internet_address_list_writer (InternetAddressList *list, GString *str)
 
 
 static char *
-decode_name (GMimeParserOptions *options, const char *name, size_t len)
+decode_name (GMimeParserOptions *options, const char *name, size_t len, const char **charset)
 {
        char *value, *buf = NULL;
        
@@ -1291,7 +1291,7 @@ decode_name (GMimeParserOptions *options, const char *name, size_t len)
        
        /* decode the phrase */
        g_mime_utils_unquote_string (buf);
-       value = g_mime_utils_header_decode_phrase (options, buf);
+       value = _g_mime_utils_header_decode_phrase (options, buf, charset);
        g_strstrip (value);
        g_free (buf);
        
@@ -1659,7 +1659,7 @@ group_parse (InternetAddressGroup *group, GMimeParserOptions *options, const cha
 }
 
 static gboolean
-address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char **in, InternetAddress 
**address)
+address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char **in, const char **charset, 
InternetAddress **address)
 {
        gboolean strict = options->addresses != GMIME_RFC_COMPLIANCE_LOOSE;
        gboolean trim_leading_quote = FALSE;
@@ -1718,7 +1718,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                /* Note: some clients don't quote commas in the name */
                if (*inptr == ',' && words > 1) {
                        inptr++;
-
+                       
                        length = (size_t) (inptr - start);
                        
                        if (!skip_cfws (&inptr))
@@ -1759,7 +1759,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                        
                        comment++;
                        
-                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment));
+                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment), charset);
                } else {
                        name = g_strdup ("");
                }
@@ -1795,7 +1795,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                }
                
                if (length > 0) {
-                       name = decode_name (options, phrase, length);
+                       name = decode_name (options, phrase, length, charset);
                } else {
                        name = g_strdup ("");
                }
@@ -1814,7 +1814,8 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                goto error;
        
        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 */
+               /* 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 */
@@ -1834,7 +1835,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                        
                        comment++;
                        
-                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment));
+                       name = decode_name (options, comment, (size_t) ((inptr - 1) - comment), charset);
                } else {
                        name = g_strdup ("");
                }
@@ -1855,7 +1856,8 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                }
                
                if (*inptr == '<') {
-                       /* We have an address like "user example com <user example com>"; i.e. the name is an 
unquoted string with an '@'. */
+                       /* 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)
@@ -1871,8 +1873,9 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                        
                        /* 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>
+                       /* 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;
@@ -1901,7 +1904,7 @@ address_parse (GMimeParserOptions *options, AddressParserFlags flags, const char
                }
                
                if (length > 0) {
-                       name = decode_name (options, phrase, length);
+                       name = decode_name (options, phrase, length, charset);
                } else {
                        name = g_strdup ("");
                }
@@ -1924,6 +1927,7 @@ static gboolean
 address_list_parse (InternetAddressList *list, GMimeParserOptions *options, const char **in, gboolean 
is_group)
 {
        InternetAddress *address;
+       const char *charset;
        const char *inptr;
        
        if (!skip_cfws (in))
@@ -1938,12 +1942,17 @@ address_list_parse (InternetAddressList *list, GMimeParserOptions *options, cons
                if (is_group && *inptr ==  ';')
                        break;
                
-               if (!address_parse (options, ALLOW_ANY, &inptr, &address)) {
+               charset = NULL;
+               
+               if (!address_parse (options, ALLOW_ANY, &inptr, &charset, &address)) {
                        /* skip this address... */
                        while (*inptr && *inptr != ',' && (!is_group || *inptr != ';'))
                                inptr++;
                } else {
                        _internet_address_list_add (list, address);
+                       
+                       if (charset)
+                               address->charset = g_strdup (charset);
                }
                
                /* Note: we loop here in case there are any null addresses between commas */
diff --git a/tests/test-mime.c b/tests/test-mime.c
index 79e31ba..ae6dbd3 100644
--- a/tests/test-mime.c
+++ b/tests/test-mime.c
@@ -63,150 +63,152 @@ uputs (const char *str, FILE *out)
 
 static struct {
        const char *input;
+       const char *charset;
        const char *display;
        const char *encoded;
 } addrspec[] = {
-       { "fejj helixcode com",
+       { "fejj helixcode com", NULL,
          "fejj helixcode com",
          "fejj helixcode com" },
-       { "Jeffrey Stedfast <fejj helixcode com>",
+       { "Jeffrey Stedfast <fejj helixcode com>", NULL,
          "Jeffrey Stedfast <fejj helixcode com>",
          "Jeffrey Stedfast <fejj helixcode com>" },
-       { "Jeffrey \"fejj\" Stedfast <fejj helixcode com>",
+       { "Jeffrey \"fejj\" Stedfast <fejj helixcode com>", NULL,
          "Jeffrey fejj Stedfast <fejj helixcode com>",
          "Jeffrey fejj Stedfast <fejj helixcode com>" },
-       { "\"Jeffrey \\\"fejj\\\" Stedfast\" <fejj helixcode com>",
+       { "\"Jeffrey \\\"fejj\\\" Stedfast\" <fejj helixcode com>", NULL,
          "Jeffrey \"fejj\" Stedfast <fejj helixcode com>",
          "\"Jeffrey \\\"fejj\\\" Stedfast\" <fejj helixcode com>" },
-       { "\"Stedfast, Jeffrey\" <fejj helixcode com>",
+       { "\"Stedfast, Jeffrey\" <fejj helixcode com>", NULL,
          "\"Stedfast, Jeffrey\" <fejj helixcode com>",
          "\"Stedfast, Jeffrey\" <fejj helixcode com>" },
-       { "fejj helixcode com (Jeffrey Stedfast)",
+       { "fejj helixcode com (Jeffrey Stedfast)", NULL,
          "Jeffrey Stedfast <fejj helixcode com>",
          "Jeffrey Stedfast <fejj helixcode com>" },
-       { "Jeff <fejj(recursive (comment) block)@helixcode.(and a comment here)com>",
+       { "Jeff <fejj(recursive (comment) block)@helixcode.(and a comment here)com>", NULL,
          "Jeff <fejj helixcode com>",
          "Jeff <fejj helixcode com>" },
-       { "=?iso-8859-1?q?Kristoffer_Br=E5nemyr?= <ztion swipenet se>",
+       { "=?iso-8859-1?q?Kristoffer_Br=E5nemyr?= <ztion swipenet se>", "iso-8859-1",
          "Kristoffer Br\xc3\xa5nemyr <ztion swipenet se>",
          "Kristoffer =?iso-8859-1?q?Br=E5nemyr?= <ztion swipenet se>" },
-       { "fpons mandrakesoft com (=?iso-8859-1?q?Fran=E7ois?= Pons)",
+       { "fpons mandrakesoft com (=?iso-8859-1?q?Fran=E7ois?= Pons)", "iso-8859-1",
          "Fran\xc3\xa7ois Pons <fpons mandrakesoft com>",
          "=?iso-8859-1?q?Fran=E7ois?= Pons <fpons mandrakesoft com>" },
-       { "GNOME Hackers: miguel gnome org (Miguel de Icaza), Havoc Pennington <hp redhat com>;, fejj 
helixcode com",
+       { "GNOME Hackers: miguel gnome org (Miguel de Icaza), Havoc Pennington <hp redhat com>;, fejj 
helixcode com", NULL,
          "GNOME Hackers: Miguel de Icaza <miguel gnome org>, Havoc Pennington <hp redhat com>;, fejj 
helixcode com",
          "GNOME Hackers: Miguel de Icaza <miguel gnome org>, Havoc Pennington <hp redhat com>;, fejj 
helixcode com" },
-       { "Local recipients: phil, joe, alex, bob",
+       { "Local recipients: phil, joe, alex, bob", NULL,
          "Local recipients: phil, joe, alex, bob;",
          "Local recipients: phil, joe, alex, bob;" },
-       { "\":sysmail\"@  Some-Group. Some-Org,\n Muhammed.(I am  the greatest) Ali @(the)Vegas.WBA",
+       { "\":sysmail\"@  Some-Group. Some-Org,\n Muhammed.(I am  the greatest) Ali @(the)Vegas.WBA", NULL,
          "\":sysmail\"@Some-Group.Some-Org, Muhammed Ali Vegas WBA",
          "\":sysmail\"@Some-Group.Some-Org, Muhammed Ali Vegas WBA" },
-       { "Charles S. Kerr <charles foo com>",
+       { "Charles S. Kerr <charles foo com>", NULL,
          "\"Charles S. Kerr\" <charles foo com>",
          "\"Charles S. Kerr\" <charles foo com>" },
-       { "Charles \"Likes, to, put, commas, in, quoted, strings\" Kerr <charles foo com>",
+       { "Charles \"Likes, to, put, commas, in, quoted, strings\" Kerr <charles foo com>", NULL,
          "\"Charles Likes, to, put, commas, in, quoted, strings Kerr\" <charles foo com>",
          "\"Charles Likes, to, put, commas, in, quoted, strings Kerr\" <charles foo com>" },
-       { "Charles Kerr, Pan Programmer <charles superpimp org>",
+       { "Charles Kerr, Pan Programmer <charles superpimp org>", NULL,
          "\"Charles Kerr, Pan Programmer\" <charles superpimp org>",
          "\"Charles Kerr, Pan Programmer\" <charles superpimp org>" },
-       { "Charles Kerr <charles@[127.0.0.1]>",
+       { "Charles Kerr <charles@[127.0.0.1]>", NULL,
          "Charles Kerr <charles@[127.0.0.1]>",
          "Charles Kerr <charles@[127.0.0.1]>" },
-       { "Charles <charles@[127..0.1]>",
+       { "Charles <charles@[127..0.1]>", NULL,
          "Charles <charles@[127..0.1]>",
          "Charles <charles@[127..0.1]>" },
-       { "Charles,, likes illegal commas <charles superpimp org>",
+       { "Charles,, likes illegal commas <charles superpimp org>", NULL,
          "Charles, likes illegal commas <charles superpimp org>",
          "Charles, likes illegal commas <charles superpimp org>" },
-       { "<charles broken host com.>",
+       { "<charles broken host com.>", NULL,
          "charles broken host com",
          "charles broken host com" },
-       { "fpons mandrakesoft com (=?iso-8859-1?q?Fran=E7ois?= Pons likes _'s and       's too)",
+       { "fpons mandrakesoft com (=?iso-8859-1?q?Fran=E7ois?= Pons likes _'s and       's too)", 
"iso-8859-1",
          "\"Fran\xc3\xa7ois Pons likes _'s and         's too\" <fpons mandrakesoft com>",
          "=?iso-8859-1?q?Fran=E7ois?= Pons likes _'s and       's too <fpons mandrakesoft com>" },
-       { "T\x81\xf5ivo Leedj\x81\xe4rv <leedjarv interest ee>",
+       { "T\x81\xf5ivo Leedj\x81\xe4rv <leedjarv interest ee>", NULL,
          "T\xc2\x81\xc3\xb5ivo Leedj\xc2\x81\xc3\xa4rv <leedjarv interest ee>",
          "=?iso-8859-1?b?VIH1aXZvIExlZWRqgeRydg==?= <leedjarv interest ee>" },
-       { "fbosi mokabyte it;, rspazzoli mokabyte it",
+       { "fbosi mokabyte it;, rspazzoli mokabyte it", NULL,
          "fbosi mokabyte it, rspazzoli mokabyte it",
          "fbosi mokabyte it, rspazzoli mokabyte it" },
-       { "\"Miles (Star Trekkin) O'Brian\" <mobrian starfleet org>",
+       { "\"Miles (Star Trekkin) O'Brian\" <mobrian starfleet org>", NULL,
          "\"Miles (Star Trekkin) O'Brian\" <mobrian starfleet org>",
          "\"Miles (Star Trekkin) O'Brian\" <mobrian starfleet org>" },
-       { "undisclosed-recipients: ;",
+       { "undisclosed-recipients: ;", NULL,
          "undisclosed-recipients: ;",
          "undisclosed-recipients: ;" },
-       { "undisclosed-recipients:;",
+       { "undisclosed-recipients:;", NULL,
          "undisclosed-recipients: ;",
          "undisclosed-recipients: ;" },
-       { "undisclosed-recipients:",
+       { "undisclosed-recipients:", NULL,
          "undisclosed-recipients: ;",
          "undisclosed-recipients: ;" },
-       { "undisclosed-recipients",
+       { "undisclosed-recipients", NULL,
          "undisclosed-recipients",
          "undisclosed-recipients" },
        /* The following test case is to check that we properly handle
         * mailbox addresses that do not have any lwsp between the
         * name component and the addr-spec. See Evolution bug
         * #347520 */
-       { "Canonical Patch Queue Manager<pqm pqm ubuntu com>",
+       { "Canonical Patch Queue Manager<pqm pqm ubuntu com>", NULL,
          "Canonical Patch Queue Manager <pqm pqm ubuntu com>",
          "Canonical Patch Queue Manager <pqm pqm ubuntu com>" },
        /* Some examples pulled from rfc5322 */
-       { "Pete(A nice \\) chap) <pete(his account)@silly.test(his host)>",
+       { "Pete(A nice \\) chap) <pete(his account)@silly.test(his host)>", NULL,
          "Pete <pete silly test>",
          "Pete <pete silly test>" },
-       { "A Group(Some people):Chris Jones <c@(Chris's host.)public.example>, joe example org, John <jdoe 
one test> (my dear friend); (the end of the group)",
+       { "A Group(Some people):Chris Jones <c@(Chris's host.)public.example>, joe example org, John <jdoe 
one test> (my dear friend); (the end of the group)", NULL,
          "A Group: Chris Jones <c@public.example>, joe example org, John <jdoe one test>;",
          "A Group: Chris Jones <c@public.example>, joe example org, John <jdoe one test>;" },
        /* The following tests cases are meant to test forgivingness
         * of the parser when it encounters unquoted specials in the
         * name component */
-       { "Warren Worthington, Jr. <warren worthington com>",
+       { "Warren Worthington, Jr. <warren worthington com>", NULL,
          "\"Warren Worthington, Jr.\" <warren worthington com>",
          "\"Warren Worthington, Jr.\" <warren worthington com>" },
-       { "dot.com <dot.com>",
+       { "dot.com <dot.com>", NULL,
          "\"dot.com\" <dot.com>",
          "\"dot.com\" <dot.com>" },
-       { "=?UTF-8?Q?agatest123_\"test\"?= <agatest123 o2 pl>",
+       { "=?UTF-8?Q?agatest123_\"test\"?= <agatest123 o2 pl>", "utf-8",
          "agatest123 test <agatest123 o2 pl>",
          "agatest123 test <agatest123 o2 pl>" },
-       { "\"=?ISO-8859-2?Q?TEST?=\" <p p org>",
+       { "\"=?ISO-8859-2?Q?TEST?=\" <p p org>", "iso-8859-2",
          "TEST <p p org>",
          "TEST <p p org>" },
-       { "sdfasf wp pl,c tert wp pl,sffdg rtre op pl",
+       { "sdfasf wp pl,c tert wp pl,sffdg rtre op pl", NULL,
          "sdfasf wp pl, sffdg rtre op pl",
          "sdfasf wp pl, sffdg rtre op pl" },
        
        /* obsolete routing address syntax tests */
-       { "<@route:user domain com>",
+       { "<@route:user domain com>", NULL,
          "user domain com",
          "user domain com" },
-       { "<@route1,,@route2,,,@route3:user domain com>",
+       { "<@route1,,@route2,,,@route3:user domain com>", NULL,
          "user domain com",
          "user domain com" },
 };
 
 static struct {
        const char *input;
+       const char *charset;
        const char *display;
        const char *encoded;
 } broken_addrspec[] = {
-       { "\"Biznes=?ISO-8859-2?Q?_?=INTERIA.PL\"=?ISO-8859-2?Q?_?=<biuletyny firma interia pl>",
+       { "\"Biznes=?ISO-8859-2?Q?_?=INTERIA.PL\"=?ISO-8859-2?Q?_?=<biuletyny firma interia pl>", 
"iso-8859-2",
          "\"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>",
+       { "=?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>", "utf-8",
          "\"{#Dèé£åý M$áí.çøm}\" <user domain com>",
-         "=?iso-8859-1?b?eyNE6Omj5f0gTSTh7S7n+G19?= <user domain com>" },
+         "=?UTF-8?b?eyNEw6jDqcKjw6XDvSBNJMOhw60uw6fDuG19?= <user domain com>" },
        /* quoted-printable payload split between multiple encoded-word tokens */
-       { "=?utf-8?Q?{#D=C3=A8=C3=A9=C2=?= =?utf-8?Q?A3=C3=A5=C3=BD_M$=C3=A1=C?= 
=?utf-8?Q?3=AD.=C3=A7=C3=B8m}?= <user domain com>",
+       { "=?utf-8?Q?{#D=C3=A8=C3=A9=C2=?= =?utf-8?Q?A3=C3=A5=C3=BD_M$=C3=A1=C?= 
=?utf-8?Q?3=AD.=C3=A7=C3=B8m}?= <user domain com>", "utf-8",
          "\"{#Dèé£åý M$áí.çøm}\" <user domain com>",
-         "=?iso-8859-1?b?eyNE6Omj5f0gTSTh7S7n+G19?= <user domain com>" },
+         "=?UTF-8?b?eyNEw6jDqcKjw6XDvSBNJMOhw60uw6fDuG19?= <user domain com>" },
        /* base64 payload split between multiple encoded-word tokens */
-       { "=?iso-8859-1?b?ey?= =?iso-8859-1?b?NE6Omj5f0gTSTh7S7n+G1AI30=?= <user domain com>",
+       { "=?iso-8859-1?b?ey?= =?iso-8859-1?b?NE6Omj5f0gTSTh7S7n+G1AI30=?= <user domain com>", "iso-8859-1",
          "\"{#Dèé£åý M$áí.çøm@#}\" <user domain com>",
          "=?iso-8859-1?b?eyNE6Omj5f0gTSTh7S7n+G1AI30=?= <user domain com>" },
 };
@@ -215,6 +217,8 @@ static void
 test_addrspec (GMimeParserOptions *options, gboolean test_broken)
 {
        InternetAddressList *addrlist;
+       InternetAddress *address;
+       const char *charset;
        char *str;
        guint i;
        
@@ -227,6 +231,19 @@ test_addrspec (GMimeParserOptions *options, gboolean test_broken)
                        if (!(addrlist = internet_address_list_parse (options, addrspec[i].input)))
                                throw (exception_new ("could not parse: %s", addrspec[i].input));
                        
+                       if (!(address = internet_address_list_get_address (addrlist, 0)))
+                               throw (exception_new ("could not get first address: %s", addrspec[i].input));
+                       
+                       charset = internet_address_get_charset (address);
+                       if (addrspec[i].charset != NULL) {
+                               if (charset == NULL)
+                                       throw (exception_new ("expected '%s' but got NULL charset: %s", 
addrspec[i].charset, addrspec[i].input));
+                               if (g_ascii_strcasecmp (addrspec[i].charset, charset) != 0)
+                                       throw (exception_new ("expected '%s' but got '%s' charset: %s", 
addrspec[i].charset, charset, addrspec[i].input));
+                       } else if (charset != NULL) {
+                               throw (exception_new ("expected NULL charset but address has a charset of 
'%s': %s", charset, addrspec[i].input));
+                       }
+                       
                        str = internet_address_list_to_string (addrlist, FALSE);
                        if (strcmp (addrspec[i].display, str) != 0)
                                throw (exception_new ("display strings do not match.\ninput: %s\nexpected: 
%s\nactual: %s", addrspec[i].input, addrspec[i].display, str));
@@ -255,6 +272,19 @@ test_addrspec (GMimeParserOptions *options, gboolean test_broken)
                        try {
                                if (!(addrlist = internet_address_list_parse (options, 
broken_addrspec[i].input)))
                                        throw (exception_new ("could not parse: %s", 
broken_addrspec[i].input));
+
+                               if (!(address = internet_address_list_get_address (addrlist, 0)))
+                                       throw (exception_new ("could not get first address: %s", 
broken_addrspec[i].input));
+                               
+                               charset = internet_address_get_charset (address);
+                               if (broken_addrspec[i].charset != NULL) {
+                                       if (charset == NULL)
+                                               throw (exception_new ("expected '%s' but got NULL charset: 
%s", broken_addrspec[i].charset, broken_addrspec[i].input));
+                                       if (g_ascii_strcasecmp (broken_addrspec[i].charset, charset) != 0)
+                                               throw (exception_new ("expected '%s' but got '%s' charset: 
%s", broken_addrspec[i].charset, charset, broken_addrspec[i].input));
+                               } else if (charset != NULL) {
+                                       throw (exception_new ("expected NULL charset but address has a 
charset of '%s': %s", charset, broken_addrspec[i].input));
+                               }
                                
                                str = internet_address_list_to_string (addrlist, FALSE);
                                if (strcmp (broken_addrspec[i].display, str) != 0)
@@ -542,6 +572,13 @@ static struct {
          "Content-Disposition: attachment;\n\t"
          "filename*=iso-8859-1'en'{#D%E8%E9%A3%E5%FD%20M$%E1%ED.%E7%F8m}.doc\n",
          GMIME_PARAM_ENCODING_METHOD_RFC2231 },
+       
+       /* Note: technically these aren't rfc2184-encoded... but they need to be parsed... */
+       { "{#Dèé£åý M$áí.çøm}.doc",
+         "iso-8859-1",
+         "Content-Disposition: attachment;\n\t"
+         "filename=\"=?iso-8859-1?b?eyNE6Omj5f0gTSTh7S7n+G19LmRvYw==?=\"\n",
+         GMIME_PARAM_ENCODING_METHOD_RFC2047 },
 };
 
 static void
@@ -555,11 +592,12 @@ test_rfc2184 (GMimeParserOptions *options)
        int count;
        size_t n;
        guint i;
-
+       
        for (i = 0; i < G_N_ELEMENTS (rfc2184); i++) {
                params = g_mime_param_list_new ();
                g_mime_param_list_set_parameter (params, "filename", rfc2184[i].input);
                param = g_mime_param_list_get_parameter (params, "filename");
+               g_mime_param_set_encoding_method (param, rfc2184[i].method);
                g_mime_param_set_lang (param, "en");
                
                str = g_string_new ("Content-Disposition: attachment");
@@ -588,13 +626,19 @@ test_rfc2184 (GMimeParserOptions *options)
                        if (strcmp (rfc2184[i].input, value) != 0)
                                throw (exception_new ("parsed param value does not match: %s", value));
                        
-                       value = g_mime_param_get_charset (param);
+                       if (!(value = g_mime_param_get_charset (param)))
+                               throw (exception_new ("parsed charset is NULL"));
+                       
                        if (strcmp (rfc2184[i].charset, value) != 0)
                                throw (exception_new ("parsed charset does not match: %s", value));
                        
-                       value = g_mime_param_get_lang (param);
-                       if (strcmp (value, "en") != 0)
-                               throw (exception_new ("parsed lang does not match: %s", value));
+                       if (rfc2184[i].method != GMIME_PARAM_ENCODING_METHOD_RFC2047) {
+                               if (!(value = g_mime_param_get_lang (param)))
+                                       throw (exception_new ("parsed lang is NULL"));
+                               
+                               if (strcmp (value, "en") != 0)
+                                       throw (exception_new ("parsed lang does not match: %s", value));
+                       }
                        
                        method = g_mime_param_get_encoding_method (param);
                        if (method != rfc2184[i].method)


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