* test/tests/mhshow/test-qp: Test various valid and invalid
authorEric Gillespie <epg@pretzelnet.org>
Wed, 13 Aug 2008 01:01:12 +0000 (01:01 +0000)
committerEric Gillespie <epg@pretzelnet.org>
Wed, 13 Aug 2008 01:01:12 +0000 (01:01 +0000)
escape sequences.

* uip/mhparse.c (openQuoted): Simplify the decode-or-show for loop by
peeking ahead to the next byte(s) when encountering '=', and just let
invalid escape sequences through as literals (fixes bug #15245).

ChangeLog
test/tests/mhshow/test-qp [new file with mode: 0644]
uip/mhparse.c

index 1016132..e33aec2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-08-12  Eric Gillespie  <epg@pretzelnet.org>
+
+       * test/tests/mhshow/test-qp: Test various valid and invalid
+       escape sequences.
+
+       * uip/mhparse.c (openQuoted): Simplify the decode-or-show for loop by
+       peeking ahead to the next byte(s) when encountering '=', and just let
+       invalid escape sequences through as literals (fixes bug #15245).
+
 2008-08-12  Peter Maydell  <pmaydell@chiark.greenend.org.uk>
 
        * autogen.sh (new file): add script for running the GNU
diff --git a/test/tests/mhshow/test-qp b/test/tests/mhshow/test-qp
new file mode 100644 (file)
index 0000000..25dde49
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+set -e
+
+expected=$MH_TEST_DIR/$$.expected
+actual=$MH_TEST_DIR/$$.actual
+
+# Write message with bogus quoted-printable data.
+msgfile=$(mhpath new)
+msgnum=$(basename $msgfile)
+cat > $msgfile <<EOF
+From: foo@example.edu
+To: bar@example.edu
+Subject: test
+MIME-Version: 1.0
+Content-Transfer-Encoding: quoted-printable
+Date: Sun, 18 Dec 2005 00:52:39 +0100
+
+=3D
+=3d
+ignored space at end 
+ignored tab at end     
+just a newline =
+
+==3d ====3D
+=      just a tab
+= just a space
+=cl
+=l with a space
+=l
+=\b ^H (backspace) character, probably erased = in diff output
+EOF
+
+# check it
+cat > $expected <<EOF
+Date:    Sun, 18 Dec 2005 00:52:39 +0100
+To:      bar@example.edu
+From:    foo@example.edu
+Subject: test
+
+MIME-Version: 1.0
+
+part       text/plain                 181
+=
+=
+ignored space at end
+ignored tab at end
+just a newline 
+== ====
+=      just a tab
+= just a space
+=cl
+=l with a space
+=l
+=\b ^H (backspace) character, probably erased = in diff output
+EOF
+mhshow -nopause $msgnum > $actual 2>&1
+diff -u $expected $actual
index 4887d9a..6771789 100644 (file)
@@ -1859,8 +1859,6 @@ openQuoted (CT ct, char **file)
 
     fseek (ct->c_fp, ct->c_begin, SEEK_SET);
     while (len > 0) {
-       char *dp;
-
        if (fgets (buffer, sizeof(buffer) - 1, ct->c_fp) == NULL) {
            content_error (NULL, ct, "premature eof");
            goto clean_up;
@@ -1876,79 +1874,67 @@ openQuoted (CT ct, char **file)
        *++ep = '\n', ep++;
 
        for (; cp < ep; cp++) {
-           if (quoted) {
-               if (quoted > 1) {
-                   if (!isxdigit (*cp)) {
-invalid_hex:
-                       dp = "expecting hexidecimal-digit";
-                       goto invalid_encoding;
-                   }
+           if (quoted > 0) {
+               /* in an escape sequence */
+               if (quoted == 1) {
+                   /* at byte 1 of an escape sequence */
+                   mask = hex2nib[*cp & 0x7f];
+                   /* next is byte 2 */
+                   quoted = 2;
+               } else {
+                   /* at byte 2 of an escape sequence */
                    mask <<= 4;
                    mask |= hex2nib[*cp & 0x7f];
                    putc (mask, ce->ce_fp);
                    if (digested)
                        MD5Update (&mdContext, &mask, 1);
-               } else {
-                   switch (*cp) {
-                   case ':':
-                       putc (*cp, ce->ce_fp);
-                       if (digested)
-                           MD5Update (&mdContext, (unsigned char *) ":", 1);
-                       break;
-
-                   default:
-                       if (!isxdigit (*cp))
-                           goto invalid_hex;
-                       mask = hex2nib[*cp & 0x7f];
-                       quoted = 2;
-                       continue;
+                   if (ferror (ce->ce_fp)) {
+                       content_error (ce->ce_file, ct, "error writing to");
+                       goto clean_up;
                    }
+                   /* finished escape sequence; next may be literal or a new
+                    * escape sequence */
+                   quoted = 0;
                }
-
-               if (ferror (ce->ce_fp)) {
-                   content_error (ce->ce_file, ct, "error writing to");
-                   goto clean_up;
-               }
-               quoted = 0;
+               /* on to next byte */
                continue;
            }
 
-           switch (*cp) {
-           default:
-               if (*cp < '!' || *cp > '~') {
-                   int i;
-                   dp = "expecting character in range [!..~]";
-
-invalid_encoding:
-                   i = strlen (invo_name) + 2;
-                   content_error (NULL, ct,
-                                  "invalid QUOTED-PRINTABLE encoding -- %s,\n%*.*sbut got char 0x%x",
-                                  dp, i, i, "", *cp);
-                   goto clean_up;
-               }
-               /* and fall...*/
-           case ' ':
-           case '\t':
-           case '\n':
-               putc (*cp, ce->ce_fp);
-               if (digested) {
-                   if (*cp == '\n')
-                       MD5Update (&mdContext, (unsigned char *) "\r\n",2);
-                   else
-                       MD5Update (&mdContext, (unsigned char *) cp, 1);
+           /* not in an escape sequence */
+           if (*cp == '=') {
+               /* starting an escape sequence, or invalid '='? */
+               if (cp + 1 < ep && cp[1] == '\n') {
+                   /* "=\n" soft line break, eat the \n */
+                   cp++;
+                   continue;
                }
-               if (ferror (ce->ce_fp)) {
-                   content_error (ce->ce_file, ct, "error writing to");
-                   goto clean_up;
+               if (cp + 1 >= ep || cp + 2 >= ep) {
+                   /* We don't have 2 bytes left, so this is an invalid
+                    * escape sequence; just show the raw bytes (below). */
+               } else if (isxdigit (cp[1]) && isxdigit (cp[2])) {
+                   /* Next 2 bytes are hex digits, making this a valid escape
+                    * sequence; let's decode it (above). */
+                   quoted = 1;
+                   continue;
+               } else {
+                   /* One or both of the next 2 is out of range, making this
+                    * an invalid escape sequence; just show the raw bytes
+                    * (below). */
                }
-               break;
+           }
 
-           case '=':
-               if (*++cp != '\n') {
-                   quoted = 1;
-                   cp--;
+           /* Just show the raw byte. */
+           putc (*cp, ce->ce_fp);
+           if (digested) {
+               if (*cp == '\n') {
+                   MD5Update (&mdContext, (unsigned char *) "\r\n",2);
+               } else {
+                   MD5Update (&mdContext, (unsigned char *) cp, 1);
                }
-               break;
+           }
+           if (ferror (ce->ce_fp)) {
+               content_error (ce->ce_file, ct, "error writing to");
+               goto clean_up;
            }
        }
     }