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 | |
'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 23091d3..1e32a8c 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 f5dc943..44cc613 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 e759d29..fdc23a8 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 b10b666..5801623 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; } |
