summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2017-02-18 08:30:02 +0200
committerSergey Poznyakoff <gray@gnu.org>2017-02-18 08:40:45 +0200
commit480f7d0b369cc32ca30df6f10ed16c7308beab63 (patch)
treed2f6d20e1f5eb068a1568217856128f95d81d531
parentafaecb9b14696dfe12e2f2f501906dbd01cec27e (diff)
downloadmailutils-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.c83
-rw-r--r--libmailutils/filter/qpflt.c28
-rw-r--r--libmailutils/tests/encode2047.at33
-rw-r--r--libmailutils/tests/encode2047.c89
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;
}

Return to:

Send suggestions and report system problems to the System administrator.