]> diplodocus.org Git - nmh/blobdiff - uip/mhparse.c
add new sample files for mhbuild tests to Makefile.am
[nmh] / uip / mhparse.c
index 9cd38f996b3a448b92da2f6607627bcf72d28077..f61edeb652830109158a41c499e478235ceac59d 100644 (file)
@@ -23,8 +23,6 @@
 
 extern int debugsw;
 
-extern pid_t xpid;     /* mhshowsbr.c  */
-
 /* cache policies */
 extern int rcachesw;   /* mhcachesbr.c */
 extern int wcachesw;   /* mhcachesbr.c */
@@ -183,19 +181,6 @@ struct str2init str2methods[] = {
 };
 
 
-int
-pidcheck (int status)
-{
-    if ((status & 0xff00) == 0xff00 || (status & 0x007f) != SIGQUIT)
-       return status;
-
-    fflush (stdout);
-    fflush (stderr);
-    done (1);
-    return 1;
-}
-
-
 /*
  * Main entry point for parsing a MIME message or file.
  * It returns the Content structure for the top level
@@ -209,6 +194,7 @@ parse_mime (char *file)
     char buffer[BUFSIZ];
     FILE *fp;
     CT ct;
+    size_t n;
 
     /*
      * Check if file is actually standard input
@@ -222,8 +208,13 @@ parse_mime (char *file)
         }
        file = add (tfile, NULL);
 
-       while (fgets (buffer, sizeof(buffer), stdin))
-           fputs (buffer, fp);
+       while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
+           if (fwrite(buffer, 1, n, fp) != n) {
+               (void) m_unlink (file);
+               advise (file, "error copying to temporary file");
+               return NULL;
+           }
+       }
        fflush (fp);
 
        if (ferror (stdin)) {
@@ -838,7 +829,7 @@ magic_skip:
             if (ct->c_dispo_type &&
                !get_param(ct->c_dispo_first, "filename", '_', 1)) {
                add_param(&ct->c_dispo_first, &ct->c_dispo_last, "filename",
-                         r1bindex(ci->ci_magic, '/'));
+                         r1bindex(ci->ci_magic, '/'), 0);
            }
         }
        else
@@ -1072,7 +1063,10 @@ InitMultiPart (CT ct)
     long last, pos;
     char *cp, *dp;
     PM pm;
-    char *bp, buffer[BUFSIZ];
+    char *bp;
+    char *bufp = NULL;
+    size_t buflen;
+    ssize_t gotlen;
     struct multipart *m;
     struct k2v *kv;
     struct part *part, **next;
@@ -1166,15 +1160,15 @@ InitMultiPart (CT ct)
     part = NULL;
     inout = 1;
 
-    while (fgets (buffer, sizeof(buffer) - 1, fp)) {
+    while ((gotlen = getline(&bufp, &buflen, fp)) != -1) {
        if (pos > last)
            break;
 
-       pos += strlen (buffer);
-       if (buffer[0] != '-' || buffer[1] != '-')
+       pos += gotlen;
+       if (bufp[0] != '-' || bufp[1] != '-')
            continue;
        if (inout) {
-           if (strcmp (buffer + 2, m->mp_start))
+           if (strcmp (bufp + 2, m->mp_start))
                continue;
 next_part:
            if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL)
@@ -1184,6 +1178,8 @@ next_part:
 
            if (!(p = get_content (fp, ct->c_file,
                        ct->c_subtype == MULTI_DIGEST ? -1 : 0))) {
+               free(bufp);
+               fclose (ct->c_fp);
                ct->c_fp = NULL;
                return NOTOK;
            }
@@ -1193,18 +1189,18 @@ next_part:
            fseek (fp, pos, SEEK_SET);
            inout = 0;
        } else {
-           if (strcmp (buffer + 2, m->mp_start) == 0) {
+           if (strcmp (bufp + 2, m->mp_start) == 0) {
                inout = 1;
 end_part:
                p = part->mp_part;
-               p->c_end = ftell(fp) - (strlen(buffer) + 1);
+               p->c_end = ftell(fp) - (gotlen + 1);
                if (p->c_end < p->c_begin)
                    p->c_begin = p->c_end;
                if (inout)
                    goto next_part;
                goto last_part;
            } else {
-               if (strcmp (buffer + 2, m->mp_stop) == 0)
+               if (strcmp (bufp + 2, m->mp_stop) == 0)
                    goto end_part;
            }
        }
@@ -1259,6 +1255,7 @@ last_part:
 
            /* initialize the content of the subparts */
            if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) {
+               free(bufp);
                fclose (ct->c_fp);
                ct->c_fp = NULL;
                return NOTOK;
@@ -1269,6 +1266,7 @@ last_part:
     get_leftover_mp_content (ct, 1);
     get_leftover_mp_content (ct, 0);
 
+    free(bufp);
     fclose (ct->c_fp);
     ct->c_fp = NULL;
     return OK;
@@ -1924,6 +1922,9 @@ openQuoted (CT ct, char **file)
     int        cc, digested, len, quoted, own_ct_fp = 0;
     char *cp, *ep;
     char buffer[BUFSIZ];
+    char *bufp = NULL;
+    size_t buflen;
+    ssize_t gotlen;
     unsigned char mask;
     CE ce = &ct->c_cefile;
     /* sbeck -- handle suffixes */
@@ -2005,16 +2006,16 @@ openQuoted (CT ct, char **file)
 
     fseek (ct->c_fp, ct->c_begin, SEEK_SET);
     while (len > 0) {
-       if (fgets (buffer, sizeof(buffer) - 1, ct->c_fp) == NULL) {
+       if ((gotlen = getline(&bufp, &buflen, ct->c_fp)) == -1) {
            content_error (NULL, ct, "premature eof");
            goto clean_up;
        }
 
-       if ((cc = strlen (buffer)) > len)
+       if ((cc = gotlen) > len)
            cc = len;
        len -= cc;
 
-       for (ep = (cp = buffer) + cc - 1; cp <= ep; ep--)
+       for (ep = (cp = bufp) + cc - 1; cp <= ep; ep--)
            if (!isspace ((unsigned char) *ep))
                break;
        *++ep = '\n', ep++;
@@ -2478,13 +2479,6 @@ openFTP (CT ct, char **file)
        return NOTOK;
     }
 
-    if (xpid) {
-       if (xpid < 0)
-           xpid = -xpid;
-       pidcheck (pidwait (xpid, NOTOK));
-       xpid = 0;
-    }
-
     /* Get the buffer ready to go */
     bp = buffer;
     buflen = sizeof(buffer);
@@ -2684,13 +2678,6 @@ openMail (CT ct, char **file)
        return NOTOK;
     }
 
-    if (xpid) {
-       if (xpid < 0)
-           xpid = -xpid;
-       pidcheck (pidwait (xpid, NOTOK));
-       xpid = 0;
-    }
-
     /* Get buffer ready to go */
     bp = buffer;
     buflen = sizeof(buffer);
@@ -2821,13 +2808,6 @@ openURL (CT ct, char **file)
        return NOTOK;
     }
 
-    if (xpid) {
-       if (xpid < 0)
-           xpid = -xpid;
-       pidcheck (pidwait (xpid, NOTOK));
-       xpid = 0;
-    }
-
     ce->ce_unlink = (*file == NULL);
     caching = 0;
     cachefile[0] = '\0';
@@ -2996,12 +2976,15 @@ invalid_digest:
    after the last subpart that hasn't been stored anywhere else, so do
    that. */
 int
-get_leftover_mp_content (CT ct, int before /* or after */) {
+get_leftover_mp_content (CT ct, int before /* or after */)
+{
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     char *boundary;
     int found_boundary = 0;
-    char buffer[BUFSIZ];
     int max = BUFSIZ;
+    char *bufp = NULL;
+    size_t buflen;
+    ssize_t gotlen;
     int read = 0;
     char *content = NULL;
 
@@ -3034,18 +3017,18 @@ get_leftover_mp_content (CT ct, int before /* or after */) {
     }
 
     /* Back up by 1 to pick up the newline. */
-    while (fgets (buffer, sizeof(buffer) - 1, ct->c_fp)) {
-        read += strlen (buffer);
+    while ((gotlen = getline(&bufp, &buflen, ct->c_fp)) != -1) {
+        read += gotlen;
         /* Don't look beyond beginning of first subpart (before) or
            next part (after). */
-        if (read > max) buffer[read-max] = '\0';
+        if (read > max) bufp[read-max] = '\0';
 
         if (before) {
-            if (! strcmp (buffer, boundary)) {
+            if (! strcmp (bufp, boundary)) {
                 found_boundary = 1;
             }
         } else {
-            if (! found_boundary  &&  ! strcmp (buffer, boundary)) {
+            if (! found_boundary  &&  ! strcmp (bufp, boundary)) {
                 found_boundary = 1;
                 continue;
             }
@@ -3054,12 +3037,12 @@ get_leftover_mp_content (CT ct, int before /* or after */) {
         if ((before && ! found_boundary)  ||  (! before && found_boundary)) {
             if (content) {
                 char *old_content = content;
-                content = concat (content, buffer, NULL);
+                content = concat (content, bufp, NULL);
                 free (old_content);
             } else {
                 content = before
-                    ?  concat ("\n", buffer, NULL)
-                    :  concat (buffer, NULL);
+                    ?  concat ("\n", bufp, NULL)
+                    :  concat (bufp, NULL);
             }
         }
 
@@ -3093,6 +3076,7 @@ get_leftover_mp_content (CT ct, int before /* or after */) {
     }
 
     free (boundary);
+    free (bufp);
 
     return OK;
 }
@@ -3255,6 +3239,7 @@ parse_header_attrs (const char *filename, const char *fieldname,
     struct sectlist {
        char *value;
        int index;
+       int len;
        struct sectlist *next;
     } *sp, *sp2;
     struct parmlist {
@@ -3263,11 +3248,11 @@ parse_header_attrs (const char *filename, const char *fieldname,
        char *lang;
        struct sectlist *sechead;
        struct parmlist *next;
-    } *pp, *phead = NULL;
+    } *pp, *pp2, *phead = NULL;
 
     while (*cp == ';') {
        char *dp, *vp, *up, *nameptr, *valptr, *charset = NULL, *lang = NULL;
-       int encoded = 0, partial = 0, index = 0, len = 0;
+       int encoded = 0, partial = 0, len = 0, index = 0;
 
        cp++;
        while (isspace ((unsigned char) *cp))
@@ -3357,7 +3342,8 @@ parse_header_attrs (const char *filename, const char *fieldname,
             */
            if (index == 0) {
                vp = dp;
-               while (*vp != '\'' && !isspace((unsigned char) *vp))
+               while (*vp != '\'' && !isspace((unsigned char) *vp) &&
+                                                       *vp != '\0')
                    vp++;
                if (*vp == '\'') {
                    if (vp != dp) {
@@ -3376,30 +3362,33 @@ parse_header_attrs (const char *filename, const char *fieldname,
                    free(nameptr);
                    return NOTOK;
                }
-           }
+               dp = vp;
 
-           vp = (dp = vp);
-           while (*vp != '\'' && !isspace((unsigned char) *vp))
-               vp++;
+               while (*vp != '\'' && !isspace((unsigned char) *vp) &&
+                                                       *vp != '\0')
+                   vp++;
 
-           if (*vp == '\'') {
-               if (vp != dp) {
-                   len = vp - dp;
-                   lang = mh_xmalloc(len + 1);
-                   strncpy(lang, dp, len);
-                   lang[len] = '\0';
+               if (*vp == '\'') {
+                   if (vp != dp) {
+                       len = vp - dp;
+                       lang = mh_xmalloc(len + 1);
+                       strncpy(lang, dp, len);
+                       lang[len] = '\0';
+                   } else {
+                       lang = NULL;
+                   }
+                   vp++;
                } else {
-                   lang = NULL;
+                   advise(NULL, "missing language tag in message %s's %s: "
+                          "field\n%*s(parameter %s)", filename, fieldname,
+                          strlen(invo_name) + 2, "", nameptr);
+                   free(nameptr);
+                   if (charset)
+                       free(charset);
+                   return NOTOK;
                }
-               vp++;
-           } else {
-               advise(NULL, "missing language tag in message %s's %s: "
-                      "field\n%*s(parameter %s)", filename, fieldname,
-                      strlen(invo_name) + 2, "", nameptr);
-               free(nameptr);
-               if (charset)
-                    free(charset);
-               return NOTOK;
+
+               dp = vp;
            }
 
            /*
@@ -3409,8 +3398,7 @@ parse_header_attrs (const char *filename, const char *fieldname,
             * length so we can allocate the correct buffer size.
             */
 
-           for (dp = vp, len = 0; *vp != '\0' && !isspace((unsigned char) *vp);
-                                                               vp++) {
+           for (vp = dp, len = 0; istoken(*vp); vp++) {
                if (*vp == '%') {
                     if (*(vp + 1) == '\0' ||
                                !isxdigit((unsigned char) *(vp + 1)) ||
@@ -3434,7 +3422,7 @@ parse_header_attrs (const char *filename, const char *fieldname,
 
            up = valptr = mh_xmalloc(len + 1);
 
-           for (vp = dp; *vp != '\0' && !isspace((unsigned char) *vp); vp++) {
+           for (vp = dp; istoken(*vp); vp++) {
                if (*vp == '%') {
                    *up++ = decode_qp(*(vp + 1), *(vp + 2));
                    vp += 2;
@@ -3542,6 +3530,7 @@ bad_quote:
            memset(sp, 0, sizeof(*sp));
            sp->value = valptr;
            sp->index = index;
+           sp->len = len;
 
            if (pp->sechead == NULL || pp->sechead->index > index) {
                sp->next = pp->sechead;
@@ -3556,7 +3545,7 @@ bad_quote:
                        return NOTOK;
                    }
                    if (sp2->index < sp->index &&
-                       (sp2->next == NULL || sp2->next->index < sp->index)) {
+                       (sp2->next == NULL || sp2->next->index > sp->index)) {
                        sp->next = sp2->next;
                        sp2->next = sp;
                        break;
@@ -3565,7 +3554,7 @@ bad_quote:
 
                if (sp2 == NULL) {
                    advise(NULL, "Internal error: cannot insert partial "
-                          "param in message %s's %s: field\n*s(parameter %s)",
+                          "param in message %s's %s: field\n%*s(parameter %s)",
                           filename, fieldname, strlen(invo_name) + 2, "",
                           nameptr);
                    return NOTOK;
@@ -3585,9 +3574,7 @@ bad_quote:
                pp->lang = lang;
            }
        } else {
-           pm = add_param(param_head, param_tail, nameptr, valptr);
-           free(nameptr);
-           free(valptr);
+           pm = add_param(param_head, param_tail, nameptr, valptr, 1);
            pm->pm_charset = charset;
            pm->pm_lang = lang;
        }
@@ -3601,10 +3588,68 @@ bad_quote:
         }
     }
 
+    /*
+     * Now that we're done, reassemble all of the partial parameters.
+     */
+
+    for (pp = phead; pp != NULL; ) {
+       char *p, *q;
+       size_t tlen = 0;
+       int pindex = 0;
+       for (sp = pp->sechead; sp != NULL; sp = sp->next) {
+           if (sp->index != pindex++) {
+               advise(NULL, "missing section %d for parameter in "
+                      "message %s's %s: field\n%*s(parameter %s)", pindex - 1,
+                      filename, fieldname, strlen(invo_name) + 2, "",
+                      pp->name);
+               return NOTOK;
+           }
+           tlen += sp->len;
+       }
+
+       p = q = mh_xmalloc(tlen + 1);
+       for (sp = pp->sechead; sp != NULL; ) {
+           memcpy(q, sp->value, sp->len);
+           q += sp->len;
+           free(sp->value);
+           sp2 = sp->next;
+           free(sp);
+           sp = sp2;
+       }
+
+       p[tlen] = '\0';
+
+       pm = add_param(param_head, param_tail, pp->name, p, 1);
+       pm->pm_charset = pp->charset;
+       pm->pm_lang = pp->lang;
+       pp2 = pp->next;
+       free(pp);
+       pp = pp2;
+    }
+
     *header_attrp = cp;
     return OK;
 }
 
+/*
+ * Return the charset for a particular content type.  Return pointer is
+ * only valid until the next call to content_charset().
+ */
+
+char *
+content_charset (CT ct) {
+    static char *ret_charset = NULL;
+
+    if (ret_charset != NULL) {
+       free(ret_charset);
+    }
+
+    ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0);
+
+    return ret_charset ? ret_charset : "US-ASCII";
+}
+
+
 /*
  * Create a string based on a list of output parameters.  Assume that this
  * parameter string will be appended to an existing header, so start out
@@ -4012,14 +4057,14 @@ normal_param(PM pm, char *output, size_t len, size_t valuelen,
  */
 
 PM
-add_param(PM *first, PM *last, const char *name, const char *value)
+add_param(PM *first, PM *last, char *name, char *value, int nocopy)
 {
     PM pm = mh_xmalloc(sizeof(*pm));
 
     memset(pm, 0, sizeof(*pm));
 
-    pm->pm_name = getcpy(name);
-    pm->pm_value = getcpy(value);
+    pm->pm_name = nocopy ? name : getcpy(name);
+    pm->pm_value = nocopy ? value : getcpy(value);
 
     if (*first) {
        (*last)->pm_next = pm;
@@ -4032,6 +4077,33 @@ add_param(PM *first, PM *last, const char *name, const char *value)
     return pm;
 }
 
+/*
+ * Either replace a current parameter with a new value, or add the parameter
+ * to the parameter linked list.
+ */
+
+PM
+replace_param(PM *first, PM *last, char *name, char *value, int nocopy)
+{
+    PM pm;
+
+    for (pm = *first; pm != NULL; pm = pm->pm_next) {
+       if (strcasecmp(name, pm->pm_name) == 0) {
+           /*
+            * If nocopy is set, it's assumed that we own both name
+            * and value.  We don't need name, so we discard it now.
+            */
+           if (nocopy)
+               free(name);
+           free(pm->pm_value);
+           pm->pm_value = nocopy ? value : getcpy(value);
+           return pm;
+       }
+    }
+
+    return add_param(first, last, name, value, nocopy);
+}
+
 /*
  * Retrieve a parameter value from a parameter linked list.  If the parameter
  * value needs converted to the local character set, do that now.
@@ -4067,7 +4139,10 @@ char *get_param_value(PM pm, char replace)
     int utf8;
     iconv_t cd;
     ICONV_CONST char *p;
+#else /* HAVE_ICONV */
+    char *p;
 #endif /* HAVE_ICONV */
+
     char *q;
 
     /*
@@ -4142,9 +4217,10 @@ char *get_param_value(PM pm, char replace)
     *q = '\0';
 
     return buffer;
-#endif /* HAVE_ICONV */
 
 noiconv:
+#endif /* HAVE_ICONV */
+
     /*
      * Take everything non-ASCII and substituite the replacement character
      */