Bug#1009215: munpack does not properly decode split attachment filenames [patch]
Package: mpack
Version: 1.6-18
The munpack utility which is part of the mpack package does not handle
attachment filenames that are split into parts. The attached patch fixes this.
I have tested the patched version against a variety of split filenames formats,
some mail senders add a ; to the end of each part, some don't. And it have worked
fine for all the mails that I've tested it against so far.
I have attached the patch as a file since Gmail is known to mess up inlined patches.
Regards,
Henrik Holst
Description: fix munpack fail to decode splitted attachment filename
--- mpack-1.6.orig/decode.c
+++ mpack-1.6/decode.c
@@ -513,6 +513,50 @@
return value;
}
+static int copyFilename(char **in, char **out, char **buffer, int *alloced, int *left)
+{
+ if (*alloced == 0) {
+ *buffer = xmalloc(*alloced = VALUEGROWSIZE);
+ *out = *buffer;
+ *left = *alloced - 1;
+ }
+
+ /* Copy value into buffer */
+ if (**in == '\"') {
+ /* Quoted-string */
+ (*in)++;
+ while (**in && **in != '\"') {
+ if (!--(*left)) {
+ *alloced += VALUEGROWSIZE;
+ *left += VALUEGROWSIZE;
+ *buffer = xrealloc(*buffer, *alloced);
+ *out = *buffer + *alloced - *left - 2;
+ }
+ if (**in == '\\') {
+ (*in)++;
+ if (!**in) return 0;
+ }
+ *(*out)++ = *(*in)++;
+ }
+ if (!**in) return 0;
+ }
+ else {
+ /* Just a token */
+ while (**in && !isspace((unsigned char)(**in)) &&
+ **in != '(') {
+ if (!--(*left)) {
+ *alloced += VALUEGROWSIZE;
+ *left += VALUEGROWSIZE;
+ *buffer = xrealloc(*buffer, *alloced);
+ *out = *buffer + *alloced - *left - 2;
+ }
+ *(*out)++ = *(*in)++;
+ }
+ }
+ **out = '\0';
+ return 1;
+}
+
/*
* Get the value of the "filename" parameter in a Content-Disposition:
* header. Returns a pointer to a static buffer containing the value, or
@@ -523,8 +567,9 @@
{
static char *value;
static int alloced = 0;
- int left;
- char *to;
+ int parts = 0;
+ int left = alloced - 1;
+ char *to = value;
if (!disposition) return 0;
@@ -532,21 +577,21 @@
for (;;) {
/* Skip until we find ";" */
while (*disposition != ';') {
- if (!*disposition) return 0;
+ if (!disposition) goto early_exit;
else if (*disposition == '\"') {
++disposition;
while (*disposition && *disposition != '\"') {
if (*disposition == '\\') {
++disposition;
- if (!*disposition) return 0;
+ if (!disposition) goto early_exit;
}
++disposition;
}
- if (!*disposition) return 0;
+ if (!disposition) goto early_exit;
}
else if (*disposition == '(') {
SkipWhitespace(&disposition);
- if (!disposition) return 0;
+ if (!disposition) goto early_exit;
disposition--;
}
disposition++;
@@ -554,8 +599,10 @@
/* Skip over ";" and trailing whitespace */
disposition++;
+
+decode_next_part:
SkipWhitespace(&disposition);
- if (!disposition) return 0;
+ if (!disposition) goto early_exit;
/*
* If we're not looking at a "filename" token, go back
@@ -564,60 +611,43 @@
*/
if (strncasecmp(disposition, "filename", 8) != 0) continue;
disposition += 8;
+ if (*disposition == '*') { /* filename is split into parts */
+ disposition++;
+ parts++;
+ while (isdigit ((unsigned char)*disposition) != 0)
+ disposition++;
+ }
if (!isspace(*disposition) && *disposition != '=' &&
*disposition != '(') {
continue;
}
SkipWhitespace(&disposition);
- if (!disposition) return 0;
+ if (!disposition) goto early_exit;
/* If we're looking at a "=", we found what we're looking for */
- if (*disposition++ == '=') break;
- }
+ if (*disposition++ == '=') {
+ SkipWhitespace(&disposition);
+ if (!disposition) goto early_exit;
- SkipWhitespace(&disposition);
- if (!disposition) return 0;
-
- if (!alloced) {
- value = xmalloc(alloced = VALUEGROWSIZE);
- }
+ if (copyFilename(&disposition, &to, &value, &alloced, &left) == 0) {
+ parts--;
+ goto early_exit;
+ }
- /* Copy value into buffer */
- to = value;
- left = alloced - 1;
- if (*disposition == '\"') {
- /* Quoted-string */
- disposition++;
- while (*disposition && *disposition != '\"') {
- if (!--left) {
- alloced += VALUEGROWSIZE;
- left += VALUEGROWSIZE;
- value = xrealloc(value, alloced);
- to = value + alloced - left - 2;
- }
- if (*disposition == '\\') {
- disposition++;
- if (!*disposition) return 0;
- }
- *to++ = *disposition++;
- }
- if (!*disposition) return 0;
- }
- else {
- /* Just a token */
- while (*disposition && !isspace(*disposition) &&
- *disposition != '(') {
- if (!--left) {
- alloced += VALUEGROWSIZE;
- left += VALUEGROWSIZE;
- value = xrealloc(value, alloced);
- to = value + alloced - left - 2;
- }
- *to++ = *disposition++;
+ if (*disposition == '\"') disposition++;
+
+ if (parts)
+ goto decode_next_part;
+
+ return value;
}
}
- *to = '\0';
- return value;
+
+early_exit:
+ if (parts)
+ return value;
+
+ return 0;
}
/*
Reply to: