/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2000-2007 Jeffrey Stedfast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "testsuite.h" extern int verbose; #define v(x) if (verbose > 3) x #if 0 static void uputs (const char *str, FILE *out) { register const unsigned char *s = (const unsigned char *) str; char buf[4096], *d = buf; while (*s != '\0') { if (!isascii ((int) *s)) { d += sprintf (d, "\\x%.2x", *s); if (isxdigit ((int) s[1])) { *d++ = '"'; *d++ = ' '; *d++ = '"'; } } else *d++ = (char) *s; s++; } *d = '\0'; fputs (buf, out); } #endif static struct { const char *input; const char *display; const char *encoded; } addrspec[] = { { "fejj@helixcode.com", "fejj@helixcode.com", "fejj@helixcode.com" }, { "Jeffrey Stedfast ", "Jeffrey Stedfast ", "Jeffrey Stedfast " }, { "Jeffrey \"fejj\" Stedfast ", "Jeffrey fejj Stedfast ", "Jeffrey fejj Stedfast " }, { "\"Stedfast, Jeffrey\" ", "\"Stedfast, Jeffrey\" ", "\"Stedfast, Jeffrey\" " }, { "fejj@helixcode.com (Jeffrey Stedfast)", "Jeffrey Stedfast ", "Jeffrey Stedfast " }, { "Jeff ", "Jeff ", "Jeff " }, { "=?iso-8859-1?q?Kristoffer_Br=E5nemyr?= ", "Kristoffer Br\xc3\xa5nemyr ", "=?iso-8859-1?q?Kristoffer_Br=E5nemyr?= " }, { "fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons)", "Fran\xc3\xa7ois Pons ", "=?iso-8859-1?q?Fran=E7ois?= Pons " }, { "GNOME Hackers: miguel@gnome.org (Miguel de Icaza), Havoc Pennington ;, fejj@helixcode.com", "GNOME Hackers: Miguel de Icaza , Havoc Pennington ;, fejj@helixcode.com", "GNOME Hackers: Miguel de Icaza , Havoc Pennington ;, fejj@helixcode.com" }, { "Local recipients: phil, joe, alex, bob", "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, Muhammed.Ali@Vegas.WBA", "\":sysmail\"@Some-Group.Some-Org, Muhammed.Ali@Vegas.WBA" }, { "Charles S. Kerr ", "\"Charles S. Kerr\" ", "\"Charles S. Kerr\" " }, { "Charles \"Likes, to, put, commas, in, quoted, strings\" Kerr ", "\"Charles Likes, to, put, commas, in, quoted, strings Kerr\" ", "\"Charles Likes, to, put, commas, in, quoted, strings Kerr\" " }, { "Charles Kerr, Pan Programmer ", "\"Charles Kerr, Pan Programmer\" ", "\"Charles Kerr, Pan Programmer\" " }, { "Charles Kerr ", "Charles Kerr ", "Charles Kerr " }, { "Charles ", "Charles ", "Charles " }, { "Charles,, likes illegal commas ", "Charles, likes illegal commas ", "Charles, likes illegal commas " }, { "", "charles", "charles" }, { " (Charles Kerr)", "Charles Kerr ", "Charles Kerr " }, { "fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons likes _'s and 's too)", "\"Fran\xc3\xa7ois Pons likes _'s and 's too\" ", "=?iso-8859-1?q?Fran=E7ois?= Pons likes _'s and 's too " }, { "T\x81\xf5ivo Leedj\x81\xe4rv ", "T\xc2\x81\xc3\xb5ivo Leedj\xc2\x81\xc3\xa4rv ", "=?iso-8859-1?b?VIH1aXZvIExlZWRqgeRydg==?= " }, { "fbosi@mokabyte.it;, rspazzoli@mokabyte.it", "fbosi@mokabyte.it, rspazzoli@mokabyte.it", "fbosi@mokabyte.it, rspazzoli@mokabyte.it" }, { "\"Miles (Star Trekkin) O'Brian\" ", "\"Miles (Star Trekkin) O'Brian\" ", "\"Miles (Star Trekkin) O'Brian\" " }, { "undisclosed-recipients: ;", "undisclosed-recipients: ;", "undisclosed-recipients: ;" }, { "undisclosed-recipients:;", "undisclosed-recipients: ;", "undisclosed-recipients: ;" }, { "undisclosed-recipients:", "undisclosed-recipients: ;", "undisclosed-recipients: ;" }, { "undisclosed-recipients", "undisclosed-recipients", "undisclosed-recipients" }, }; static void test_addrspec (void) { InternetAddressList *addrlist; char *str; guint i; for (i = 0; i < G_N_ELEMENTS (addrspec); i++) { addrlist = NULL; str = NULL; testsuite_check ("addrspec[%u]", i); try { if (!(addrlist = internet_address_parse_string (addrspec[i].input))) throw (exception_new ("could not parse addr-spec", i)); str = internet_address_list_to_string (addrlist, FALSE); if (strcmp (addrspec[i].display, str) != 0) throw (exception_new ("display addr-spec does not match")); g_free (str); str = internet_address_list_to_string (addrlist, TRUE); if (strcmp (addrspec[i].encoded, str) != 0) throw (exception_new ("encoded addr-spec does not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("addrspec[%u]: %s", i, ex->message); } finally; g_free (str); if (addrlist) internet_address_list_destroy (addrlist); } } static struct { const char *in; const char *out; time_t date; int tzone; } dates[] = { { "Mon, 17 Jan 1994 11:14:55 -0500", "Mon, 17 Jan 1994 11:14:55 -0500", 758823295, -500 }, { "Mon, 17 Jan 01 11:14:55 -0500", "Wed, 17 Jan 2001 11:14:55 -0500", 979748095, -500 }, { "Tue, 30 Mar 2004 13:01:38 +0000", "Tue, 30 Mar 2004 13:01:38 +0000", 1080651698, 0 }, { "Sat Mar 24 21:23:03 EDT 2007", "Sat, 24 Mar 2007 21:23:03 -0400", 1174785783, -400 }, { "Sat, 24 Mar 2007 21:23:03 EDT", "Sat, 24 Mar 2007 21:23:03 -0400", 1174785783, -400 }, { "Sat, 24 Mar 2007 21:23:03 GMT", "Sat, 24 Mar 2007 21:23:03 +0000", 1174771383, 0 }, }; static void test_date_parser (void) { time_t date; int tzone; char *buf; guint i; for (i = 0; i < G_N_ELEMENTS (dates); i++) { buf = NULL; testsuite_check ("Date: '%s'", dates[i].in); try { date = g_mime_utils_header_decode_date (dates[i].in, &tzone); if (date != dates[i].date) throw (exception_new ("time_t's do not match")); if (tzone != dates[i].tzone) throw (exception_new ("timezones do not match")); buf = g_mime_utils_header_format_date (date, tzone); if (strcmp (dates[i].out, buf) != 0) throw (exception_new ("date strings do not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("Date: '%s': %s", dates[i].in, ex->message); } finally; g_free (buf); } } static struct { const char *input; const char *decoded; const char *encoded; } rfc2047_text[] = { #if 0 { "=?iso-8859-1?Q?blah?=:\t=?iso-8859-1?Q?I_am_broken?=", "blah:\tI am broken", "blah:\tI am broken" }, #endif { "=?iso-8859-1?Q?Copy_of_Rapport_fra_Norges_R=E5fisklag=2Edoc?=", "Copy of Rapport fra Norges R\xc3\xa5" "fisklag.doc", "Copy =?iso-8859-1?q?of_Rapport_fra_Norges_R=E5fisklag=2Edoc?=" }, { "=?iso-8859-1?Q?Copy_of_Rapport_fra_Norges_R=E5fisklag.doc?=", "Copy of Rapport fra Norges R\xc3\xa5" "fisklag.doc", "Copy =?iso-8859-1?q?of_Rapport_fra_Norges_R=E5fisklag=2Edoc?=" }, { "=?iso-8859-1?B?dGVzdOb45S50eHQ=?=", "test\xc3\xa6\xc3\xb8\xc3\xa5.txt", "=?iso-8859-1?b?dGVzdOb45S50eHQ=?=" }, { "Re: !!! =?windows-1250?Q?Nab=EDz=EDm_scanov=E1n=ED_negativ=F9?= =?windows-1250?Q?=2C_p=F8edloh_do_A4=2C_=E8/b_lasertov=FD_ti?= =?windows-1250?Q?sk_a_=E8/b_inkoutov=FD_tisk_do_A2!!!?=", "Re: !!! Nab\xc3\xadz\xc3\xadm scanov\xc3\xa1n\xc3\xad negativ\xc5\xaf, p\xc5\x99" "edloh do A4, \xc4\x8d/b lasertov\xc3\xbd tisk a \xc4\x8d/b inkoutov\xc3\xbd tisk do A2!!!", "Re: =?iso-8859-2?q?!!!_Nab=EDz=EDm_scanov=E1n=ED_negativ=F9=2C_?= =?iso-8859-2?q?p=F8edloh_do_A4=2C_=E8=2Fb_lasertov=FD_?= =?iso-8859-2?q?tisk_a_=E8=2Fb_inkoutov=FD?= tisk do A2!!!" }, { "Re: =?iso-8859-2?q?!!!_Nab=EDz=EDm_scanov=E1n=ED_negativ=F9=2C_?= =?iso-8859-2?q?p=F8edloh_do_A4=2C_=E8=2Fb_lasertov=FD_?= =?iso-8859-2?q?tisk_a_=E8=2Fb_inkoutov=FD?= tisk do A2!!!", "Re: !!! Nab\xc3\xadz\xc3\xadm scanov\xc3\xa1n\xc3\xad negativ\xc5\xaf, p\xc5\x99" "edloh do A4, \xc4\x8d/b lasertov\xc3\xbd tisk a \xc4\x8d/b inkoutov\xc3\xbd tisk do A2!!!", "Re: =?iso-8859-2?q?!!!_Nab=EDz=EDm_scanov=E1n=ED_negativ=F9=2C_?= =?iso-8859-2?q?p=F8edloh_do_A4=2C_=E8=2Fb_lasertov=FD_?= =?iso-8859-2?q?tisk_a_=E8=2Fb_inkoutov=FD?= tisk do A2!!!" }, { "OT - ich =?iso-8859-1?b?d2Vp3yw=?= trotzdem", "OT - ich wei\xc3\x9f, trotzdem", "=?iso-8859-1?q?OT_-_ich_wei=DF=2C?= trotzdem" }, { "=?iso-8859-5?b?tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2trY=?=", "\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96\xd0\x96", "=?iso-8859-5?b?tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2trY=?= =?iso-8859-5?b?tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2trY=?= =?iso-8859-5?b?tra2tg==?=" }, #ifdef ENABLE_RFC2047_WORKAROUNDS { "Copy of Rapport fra Norges R=?iso-8859-1?Q?=E5?=fisklag.doc", "Copy of Rapport fra Norges R\xc3\xa5" "fisklag.doc", "Copy =?iso-8859-1?q?of_Rapport_fra_Norges_R=E5fisklag=2Edoc?=" }, { "Copy of Rapport fra Norges =?iso-8859-1?Q?R=E5?=fisklag.doc", "Copy of Rapport fra Norges R\xc3\xa5" "fisklag.doc", "Copy =?iso-8859-1?q?of_Rapport_fra_Norges_R=E5fisklag=2Edoc?=" }, #endif /* ENABLE_RFC2047_WORKAROUNDS */ }; static struct { const char *input; const char *decoded; const char *encoded; } rfc2047_phrase[] = { /* FIXME: add some phrase tests */ }; static void test_rfc2047 (void) { char *enc, *dec; guint i; for (i = 0; i < G_N_ELEMENTS (rfc2047_text); i++) { dec = enc = NULL; testsuite_check ("rfc2047_text[%u]", i); try { dec = g_mime_utils_header_decode_text (rfc2047_text[i].input); if (strcmp (rfc2047_text[i].decoded, dec) != 0) throw (exception_new ("decoded text does not match")); enc = g_mime_utils_header_encode_text (dec); if (strcmp (rfc2047_text[i].encoded, enc) != 0) throw (exception_new ("encoded text does not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("rfc2047_text[%u]: %s", i, ex->message); } finally; g_free (dec); g_free (enc); } #if 0 for (i = 0; i < G_N_ELEMENTS (rfc2047_phrase); i++) { dec = enc = NULL; testsuite_check ("rfc2047_phrase[%u]", i); try { dec = g_mime_utils_header_decode_phrase (rfc2047_phrase[i].input); if (strcmp (rfc2047_phrase[i].decoded, dec) != 0) throw (exception_new ("decoded phrase does not match")); enc = g_mime_utils_header_encode_phrase (dec); if (strcmp (rfc2047_phrase[i].encoded, enc) != 0) throw (exception_new ("encoded phrase does not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("rfc2047_phrase[%u]: %s", i, ex->message); } finally; g_free (dec); g_free (enc); } #endif } static struct { const char *input; const char *encoded; } rfc2184[] = { { "this is a really really long filename that should force gmime to rfc2184 encode it - yay!.html", "Content-Disposition: attachment;\n\t" "filename*0*=iso-8859-1''this%20is%20a%20really%20really%20long%20filename;\n\t" "filename*1*=%20that%20should%20force%20gmime%20to%20rfc2184%20encode%20it;\n\t" "filename*2*=%20-%20yay!.html\n" }, }; static void test_rfc2184 (void) { GMimeParam param, *params; GString *str; size_t n; guint i; param.next = NULL; param.name = "filename"; str = g_string_new ("Content-Disposition: attachment"); n = str->len; for (i = 0; i < G_N_ELEMENTS (rfc2184); i++) { params = NULL; param.value = (char *) rfc2184[i].input; testsuite_check ("rfc2184[%u]", i); try { g_mime_param_write_to_string (¶m, TRUE, str); if (strcmp (rfc2184[i].encoded, str->str) != 0) throw (exception_new ("encoded param does not match")); if (!(params = g_mime_param_new_from_string (str->str + n + 2))) throw (exception_new ("could not parse encoded param list")); if (params->next != NULL) throw (exception_new ("parsed more than a single param?")); if (strcmp (rfc2184[i].input, params->value) != 0) throw (exception_new ("parsed param value does not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("rfc2184[%u]: %s", i, ex->message); } finally; if (params != NULL) g_mime_param_destroy (params); g_string_truncate (str, n); } g_string_free (str, TRUE); } static struct { const char *input; const char *unquoted; const char *quoted; } qstrings[] = { { "this is a \\\"quoted\\\" string", "this is a \"quoted\" string", "this is a \"quoted\" string" }, { "\\\"this\\\" and \\\"that\\\"", "\"this\" and \"that\"", "\"this\" and \"that\"" }, { "\"Dr. A. Cula\"", "Dr. A. Cula", "\"Dr. A. Cula\"" }, }; static void test_qstring (void) { char *str; guint i; for (i = 0; i < G_N_ELEMENTS (qstrings); i++) { str = NULL; testsuite_check ("qstrings[%u]", i); try { str = g_strdup (qstrings[i].input); g_mime_utils_unquote_string (str); if (strcmp (qstrings[i].unquoted, str) != 0) throw (exception_new ("unquoted string does not match")); g_free (str); str = g_mime_utils_quote_string (qstrings[i].unquoted); if (strcmp (qstrings[i].quoted, str) != 0) throw (exception_new ("quoted string does not match")); testsuite_check_passed (); } catch (ex) { testsuite_check_failed ("qstrings[%u]: %s", i, ex->message); } finally; g_free (str); } } int main (int argc, char **argv) { g_mime_init (0); testsuite_init (argc, argv); testsuite_start ("addr-spec parser"); test_addrspec (); testsuite_end (); testsuite_start ("date parser"); test_date_parser (); testsuite_end (); testsuite_start ("rfc2047 encoding/decoding"); test_rfc2047 (); testsuite_end (); testsuite_start ("rfc2184 encoding/decoding"); test_rfc2184 (); testsuite_end (); testsuite_start ("quoted-strings"); test_qstring (); testsuite_end (); g_mime_shutdown (); return testsuite_exit (); }