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 via email to