diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2017-02-18 08:30:02 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2017-02-18 08:40:45 +0200 |
commit | 480f7d0b369cc32ca30df6f10ed16c7308beab63 (patch) | |
tree | d2f6d20e1f5eb068a1568217856128f95d81d531 | |
parent | afaecb9b14696dfe12e2f2f501906dbd01cec27e (diff) | |
download | mailutils-480f7d0b369cc32ca30df6f10ed16c7308beab63.tar.gz mailutils-480f7d0b369cc32ca30df6f10ed16c7308beab63.tar.bz2 |
'Q' encoding: encode question mark properly; limit length of encoded words
* libmailutils/base/rfc2047.c (mu_rfc2047_encode): Limit length
of encoded word to 75 bytes.
* libmailutils/filter/qpflt.c: Treat '?' as special character in
Q encoder.
* libmailutils/tests/encode2047.at: Add more tests.
* libmailutils/tests/encode2047.c: Use mailutils string I/O
-rw-r--r-- | libmailutils/base/rfc2047.c | 83 | ||||
-rw-r--r-- | libmailutils/filter/qpflt.c | 28 | ||||
-rw-r--r-- | libmailutils/tests/encode2047.at | 33 | ||||
-rw-r--r-- | libmailutils/tests/encode2047.c | 89 |
4 files changed, 110 insertions, 123 deletions
diff --git a/libmailutils/base/rfc2047.c b/libmailutils/base/rfc2047.c index 23091d3e4..1e32a8cf3 100644 --- a/libmailutils/base/rfc2047.c +++ b/libmailutils/base/rfc2047.c @@ -286,17 +286,23 @@ mu_rfc2047_decode (const char *tocode, const char *input, char **ptostr) @return 0 on success */ + +#define MAX_ENCODED_WORD 75 + int mu_rfc2047_encode (const char *charset, const char *encoding, const char *text, char **result) { mu_stream_t input_stream; - mu_stream_t output_stream; + mu_stream_t inter_stream; int rc; if (charset == NULL || encoding == NULL || text == NULL) return EINVAL; + if (strlen (charset) > MAX_ENCODED_WORD - 8) + return EINVAL; + if (strcmp (encoding, "base64") == 0) encoding = "B"; else if (strcmp (encoding, "quoted-printable") == 0) @@ -304,42 +310,67 @@ mu_rfc2047_encode (const char *charset, const char *encoding, else if (encoding[1] || !strchr ("BQ", encoding[0])) return MU_ERR_BAD_2047_ENCODING; + rc = mu_static_memory_stream_create (&input_stream, text, strlen (text)); if (rc) return rc; - rc = mu_filter_create (&output_stream, input_stream, + rc = mu_filter_create (&inter_stream, input_stream, encoding, MU_FILTER_ENCODE, MU_STREAM_READ); mu_stream_unref (input_stream); if (rc == 0) { - /* Assume strlen(qp_encoded_text) <= strlen(text) * 3 */ - /* malloced length is composed of: - "=?" - charset - "?" - B or Q - "?" - encoded_text - "?=" - zero terminator */ - - *result = malloc (2 + strlen (charset) + 3 + strlen (text) * 3 + 3); - if (*result) + mu_stream_t output_stream; + rc = mu_memory_stream_create (&output_stream, MU_STREAM_RDWR); + if (rc == 0) { - char *p = *result; - size_t s; - - p += sprintf (p, "=?%s?%s?", charset, encoding); + char buf[MAX_ENCODED_WORD]; + size_t start, bs, n; + + start = snprintf (buf, sizeof buf, "=?%s?%s?", charset, encoding); + bs = sizeof buf - start - 2; - rc = mu_stream_read (output_stream, - p, - strlen (text) * 3, &s); + while (1) + { + rc = mu_stream_read (inter_stream, buf + start, bs, &n); + if (rc || n == 0) + break; + rc = mu_stream_write (output_stream, buf, n + start, NULL); + if (rc) + break; + rc = mu_stream_write (output_stream, "?=", 2, NULL); + if (rc) + break; + if (n == bs) + rc = mu_stream_write (output_stream, "\n ", 2, NULL); + else + break; + } + + if (rc == 0) + { + mu_off_t sz; + char *ptr; + + mu_stream_size (output_stream, &sz); + ptr = malloc (sz + 1); + if (!ptr) + rc = ENOMEM; + else + { + if ((rc = mu_stream_seek (output_stream, 0, MU_SEEK_SET, + NULL)) == 0 + && (rc = mu_stream_read (output_stream, ptr, sz, NULL)) + == 0) + { + ptr[sz] = 0; + *result = ptr; + } + } + } - strcpy (p + s, "?="); + mu_stream_destroy (&output_stream); } - else - rc = ENOMEM; - mu_stream_destroy (&output_stream); + mu_stream_destroy (&inter_stream); } else mu_stream_destroy (&input_stream); diff --git a/libmailutils/filter/qpflt.c b/libmailutils/filter/qpflt.c index f5dc94377..44cc6133b 100644 --- a/libmailutils/filter/qpflt.c +++ b/libmailutils/filter/qpflt.c @@ -37,7 +37,7 @@ _qp_decoder (void *xd, size_t isize; char *optr; size_t osize; - int underscore_special = *(int*)xd; + char *specials = xd; switch (cmd) { @@ -143,7 +143,7 @@ _qp_decoder (void *xd, consumed += 2; } } - else if (underscore_special && c == '_') + else if (c == '_' && specials && strchr (specials, c)) { *optr++ = ' '; nbytes++; @@ -175,7 +175,7 @@ _qp_encoder (void *xd, size_t isize; char *optr; size_t osize; - int underscore_special = *(int*)xd; + char *specials = xd; switch (cmd) { @@ -203,7 +203,7 @@ _qp_encoder (void *xd, /* candidate byte to convert */ c = *(unsigned char*) iptr; - if (underscore_special && c == '_') + if (specials && strchr (specials, c)) simple_char = 0; else simple_char = (c >= 32 && c <= 60) @@ -216,7 +216,7 @@ _qp_encoder (void *xd, /* a non-quoted character uses up one byte */ if (nbytes + 1 > osize) break; - if (underscore_special && c == ' ') + if (c == ' ' && specials && strchr (specials, '_')) *optr++ = '_'; else *optr++ = c; @@ -248,20 +248,9 @@ _qp_encoder (void *xd, return mu_filter_ok; } -static int -alloc_qp (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) -{ - int *x = malloc (sizeof (*x)); - if (!x) - return ENOMEM; - *x = 0; - *pret = x; - return 0; -} - static struct _mu_filter_record _qp_filter = { "quoted-printable", - alloc_qp, + NULL, _qp_encoder, _qp_decoder }; @@ -271,10 +260,7 @@ mu_filter_record_t mu_qp_filter = &_qp_filter; static int alloc_Q (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) { - int *x = malloc (sizeof (*x)); - if (!x) - return ENOMEM; - *x = 1; + char *x = strdup ("_?"); *pret = x; return 0; } diff --git a/libmailutils/tests/encode2047.at b/libmailutils/tests/encode2047.at index e759d2966..fdc23a8e8 100644 --- a/libmailutils/tests/encode2047.at +++ b/libmailutils/tests/encode2047.at @@ -20,7 +20,7 @@ dnl m4_pushdef([TESTENC2047],[ m4_pushdef([MU_TEST_GROUP],[Encode 2047]) m4_pushdef([MU_TEST_KEYWORDS],[encode2047 encode]) -m4_pushdef([MU_TEST_COMMAND],[encode2047 -eB $3]) +m4_pushdef([MU_TEST_COMMAND],[encode2047 $3]) MU_GENERIC_TEST([$1],[$2],[$4],[],[$5 ]) m4_popdef([MU_TEST_COMMAND]) @@ -29,25 +29,40 @@ m4_popdef([MU_TEST_GROUP]) ]) TESTENC2047([8-bit input],[enc01], - [-c koi8-r -o], - [\\345\326\305\304\316\305\327\316\331\312\040\317\324\336\305\324], + [-eB -c koi8-r -o], + [\345\326\305\304\316\305\327\316\331\312\040\317\324\336\305\324], [=?koi8-r?B?5dbFxM7F187ZyiDP1N7F1A==?=]) - + TESTENC2047([padding 1],[enc02], - [], + [-eB], [abcd], [=?iso-8859-1?B?YWJjZA==?=]) TESTENC2047([padding 2],[enc03], - [], + [-eB], [abcdef], [=?iso-8859-1?B?YWJjZGVm?=]) TESTENC2047([padding 3],[enc04], - [-cUTF-8], + [-eB -cUTF-8], [Wichtige Mitteilung zur Schaltung Ihres Anschlusses], - [=?UTF-8?B?V2ljaHRpZ2UgTWl0dGVpbHVuZyB6dXIgU2NoYWx0dW5nIElocmVzIEFuc2NobHVzc2Vz?=]) - + [=?UTF-8?B?V2ljaHRpZ2UgTWl0dGVpbHVuZyB6dXIgU2NoYWx0dW5nIElocmVzIEFuc2NobHV?= + =?UTF-8?B?zc2Vz?=]) + +TESTENC2047([specials],[enc05], + [-eQ], + [_?=], + [=?iso-8859-1?Q?=5F=3F=3D?=]) + +TESTENC2047([length limit],[enc06], + [-cUTF-8 -eQ], + [J'interdis aux marchands de vanter trop leur marchandises. Car ils se font vite pédagogues et t'enseignent comme but ce qui n'est par essence qu'un moyen, et te trompant ainsi sur la route à suivre les voilà bientôt qui te dégradent, car si leur musique est vulgaire ils te fabriquent pour te la vendre une âme vulgaire.], + [=?UTF-8?Q?J'interdis_aux_marchands_de_vanter_trop_leur_marchandises._Car_?= + =?UTF-8?Q?ils_se_font_vite_p=C3=A9dagogues_et_t'enseignent_comme_but_ce_q?= + =?UTF-8?Q?ui_n'est_par_essence_qu'un_moyen,_et_te_trompant_ainsi_sur_la_r?= + =?UTF-8?Q?oute_=C3=A0_suivre_les_voil=C3=A0_bient=C3=B4t_qui_te_d=C3=A9gr?= + =?UTF-8?Q?adent,_car_si_leur_musique_est_vulgaire_ils_te_fabriquent_pour_?= + =?UTF-8?Q?te_la_vendre_une_=C3=A2me_vulgaire.?=]) m4_popdef([TESTENC2047]) diff --git a/libmailutils/tests/encode2047.c b/libmailutils/tests/encode2047.c index b10b666f6..5801623c6 100644 --- a/libmailutils/tests/encode2047.c +++ b/libmailutils/tests/encode2047.c @@ -104,24 +104,23 @@ decode_octal (char *buf) int main (int argc, char *argv[]) { - int c; - char buf[256]; - char vbuf[256]; - char *charset = strdup ("iso-8859-1"); - char *encoding = strdup ("quoted-printable"); + int rc; + char *buf = NULL; + size_t size = 0; + size_t n; + char *charset = "iso-8859-1"; + char *encoding = "quoted-printable"; int octal = 0; - while ((c = getopt (argc, argv, "c:e:hot")) != EOF) - switch (c) + while ((rc = getopt (argc, argv, "c:e:hot")) != EOF) + switch (rc) { case 'c': - free (charset); - charset = strdup (optarg); + charset = optarg; break; case 'e': - free (encoding); - encoding = strdup (optarg); + encoding = optarg; break; case 'o': @@ -140,67 +139,23 @@ main (int argc, char *argv[]) exit (1); } - while (fgets (buf, sizeof (buf), stdin)) + mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); + while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0) { - int len; - char *p = NULL; - char *cmd; - int rc; - - len = strlen (buf); - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = 0; - strncpy(vbuf, buf, sizeof vbuf); - cmd = vbuf; - if (cmd[0] == '\\') - { - if (cmd[1] == 0) - { - fprintf (stderr, "Unfinished command\n"); - continue; - } - - for (p = cmd + 2; *p && *p == ' '; p++) - ; - switch (cmd[1]) - { - case 'c': - free (charset); - charset = strdup (p); - continue; - - case 'e': - free (encoding); - encoding = strdup (p); - continue; - - case 'o': - octal = 1; - continue; - - case 't': - octal = 0; - continue; - - case '\\': - cmd++; - break; - - default: - fprintf (stderr, "Unknown command\n"); - continue; - } - } - + char *p; + + mu_rtrim_class (buf, MU_CTYPE_ENDLN); if (octal) - decode_octal (cmd); + decode_octal (buf); - rc = mu_rfc2047_encode (charset, encoding, cmd, &p); + rc = mu_rfc2047_encode (charset, encoding, buf, &p); if (rc) - fprintf (stderr, "%s", mu_strerror (rc)); + mu_diag_funcall (MU_DIAG_ERROR, "mu_rfc2047_encode", NULL, rc); else if (p) - printf ("%s\n", p); + mu_printf ("%s\n", p); free (p); } - return 0; + if (rc) + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_getline", NULL, rc); + return 0; } |