* test/tests/mhshow/test-qp: Test various valid and invalid
[mmh] / uip / mhparse.c
index 8d3397e..6771789 100644 (file)
@@ -127,8 +127,8 @@ CT parse_mime (char *);
  */
 static CT get_content (FILE *, char *, int);
 static int add_header (CT, char *, char *);
-static int get_ctinfo (char *, CT);
-static int get_comment (CT, char **, int);
+static int get_ctinfo (unsigned char *, CT);
+static int get_comment (CT, unsigned char **, int);
 static int InitGeneric (CT);
 static int InitText (CT);
 static int InitMultiPart (CT);
@@ -209,7 +209,8 @@ pidcheck (int status)
 
     fflush (stdout);
     fflush (stderr);
-    return done (1);
+    done (1);
+    return 1;
 }
 
 
@@ -377,7 +378,8 @@ get_content (FILE *in, char *file, int toplevel)
        /* Get MIME-Version field */
        if (!mh_strcasecmp (hp->name, VRSN_FIELD)) {
            int ucmp;
-           char c, *cp, *dp;
+           char c;
+           unsigned char *cp, *dp;
 
            if (ct->c_vrsn) {
                advise (NULL, "message %s has multiple %s: fields",
@@ -444,7 +446,8 @@ get_content (FILE *in, char *file, int toplevel)
        }
        else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) {
        /* Get Content-Transfer-Encoding field */
-           char c, *cp, *dp;
+           char c;
+           unsigned char *cp, *dp;
            struct str2init *s2i;
 
            /*
@@ -485,7 +488,8 @@ get_content (FILE *in, char *file, int toplevel)
        }
        else if (!mh_strcasecmp (hp->name, MD5_FIELD)) {
        /* Get Content-MD5 field */
-           char *cp, *dp, *ep;
+           unsigned char *cp, *dp;
+           char *ep;
 
            if (!checksw)
                goto next_header;
@@ -611,10 +615,11 @@ add_header (CT ct, char *name, char *value)
  */
 
 static int
-get_ctinfo (char *cp, CT ct)
+get_ctinfo (unsigned char *cp, CT ct)
 {
     int        i;
-    char *dp, **ap, **ep;
+    unsigned char *dp;
+    char **ap, **ep;
     char c;
     CI ci;
 
@@ -708,7 +713,8 @@ magic_skip:
      */
     ep = (ap = ci->ci_attrs) + NPARMS;
     while (*cp == ';') {
-       char *vp, *up;
+       char *vp;
+       unsigned char *up;
 
        if (ap >= ep) {
            advise (NULL,
@@ -812,10 +818,11 @@ bad_quote:
 
 
 static int
-get_comment (CT ct, char **ap, int istype)
+get_comment (CT ct, unsigned char **ap, int istype)
 {
     int i;
-    char *bp, *cp;
+    char *bp;
+    unsigned char *cp;
     char c, buffer[BUFSIZ], *dp;
     CI ci;
 
@@ -956,7 +963,8 @@ InitMultiPart (CT ct)
 {
     int        inout;
     long last, pos;
-    char *cp, *dp, **ap, **ep;
+    unsigned char *cp, *dp;
+    char **ap, **ep;
     char *bp, buffer[BUFSIZ];
     struct multipart *m;
     struct k2v *kv;
@@ -1112,7 +1120,7 @@ last_part:
        char partnam[BUFSIZ];
 
        if (ct->c_partno) {
-           snprintf (partnam, sizeof(partnum), "%s.", ct->c_partno);
+           snprintf (partnam, sizeof(partnam), "%s.", ct->c_partno);
            pp = partnam + strlen (partnam);
        } else {
            pp = partnam;
@@ -1568,7 +1576,8 @@ openBase64 (CT ct, char **file)
     int fd, len, skip;
     unsigned long bits;
     unsigned char value, *b, *b1, *b2, *b3;
-    char *cp, *ep, buffer[BUFSIZ];
+    unsigned char *cp, *ep;
+    char buffer[BUFSIZ];
     /* sbeck -- handle prefixes */
     CI ci;
     CE ce;
@@ -1779,7 +1788,7 @@ static int
 openQuoted (CT ct, char **file)
 {
     int        cc, digested, len, quoted;
-    char *cp, *ep;
+    unsigned char *cp, *ep;
     char buffer[BUFSIZ];
     unsigned char mask;
     CE ce;
@@ -1850,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;
@@ -1867,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;
            }
        }
     }
@@ -2675,7 +2670,7 @@ invalid_digest:
            while (*cp)
                cp++;
            fprintf (stderr, "invalid MD5 digest (got %d octets)\n",
-                    cp - bp);
+                    (int)(cp - bp));
        }
 
        return NOTOK;