]> diplodocus.org Git - nmh/blobdiff - uip/mhparse.c
Change things so we only supply a form filename; most programs don't do
[nmh] / uip / mhparse.c
index f2f3a246191d3e63c343c7aa3343eae84ca1e211..444bf7d563caccf7b3c6bab236cd028092736c0e 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
@@ -838,7 +823,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
@@ -2478,13 +2463,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 +2662,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 +2792,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';
@@ -3255,19 +3219,20 @@ parse_header_attrs (const char *filename, const char *fieldname,
     struct sectlist {
        char *value;
        int index;
+       int len;
        struct sectlist *next;
-    } *sp;
+    } *sp, *sp2;
     struct parmlist {
        char *name;
        char *charset;
        char *lang;
        struct sectlist *sechead;
        struct parmlist *next;
-    } *pp, *phead = NULL;
+    } *pp, *pp2, *phead = NULL;
 
     while (*cp == ';') {
-       char *dp, *vp, *up, c, *nameptr, *valptr, *charset, *lang;
-       int encoded = 0, partial = 0, index = 0, len = 0;
+       char *dp, *vp, *up, *nameptr, *valptr, *charset = NULL, *lang = NULL;
+       int encoded = 0, partial = 0, len = 0, index = 0;
 
        cp++;
        while (isspace ((unsigned char) *cp))
@@ -3313,15 +3278,15 @@ parse_header_attrs (const char *filename, const char *fieldname,
         * If there's a * and one or more digits, then it's section N.
         *
         * Remember we can have one or the other, or both.  cp points to
-        * beginning of name, up points to the last character in the
+        * beginning of name, up points past the last character in the
         * parameter name.
         */
 
-       for (vp = cp; vp <= up; vp++) {
-           if (*vp == '*' && vp < up) {
+       for (vp = cp; vp < up; vp++) {
+           if (*vp == '*' && vp < up - 1) {
                partial = 1;
                continue;
-           } else if (*vp == '*' && vp == up) {
+           } else if (*vp == '*' && vp == up - 1) {
                encoded = 1;
            } else if (partial) {
                if (isdigit((unsigned char) *vp))
@@ -3357,7 +3322,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) {
@@ -3368,36 +3334,41 @@ parse_header_attrs (const char *filename, const char *fieldname,
                    } else {
                        charset = NULL;
                    }
+                   vp++;
                } else {
-                   advise(NULL, "missing charset in message %s's %s:
+                   advise(NULL, "missing charset in message %s's %s: "
                           "field\n%*s(parameter %s)", filename, fieldname,
                           strlen(invo_name) + 2, "", nameptr);
                    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 {
-                   charset = 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;
                }
-           } 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;
            }
 
            /*
@@ -3407,8 +3378,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)) ||
@@ -3432,8 +3402,8 @@ 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++) {
-               if (*vp = '%') {
+           for (vp = dp; istoken(*vp); vp++) {
+               if (*vp == '%') {
                    *up++ = decode_qp(*(vp + 1), *(vp + 2));
                    vp += 2;
                } else {
@@ -3442,6 +3412,7 @@ parse_header_attrs (const char *filename, const char *fieldname,
            }
 
            *up = '\0';
+           cp = vp;
        } else {
            /*
             * A "normal" string.  If it's got a leading quote, then we
@@ -3451,13 +3422,12 @@ parse_header_attrs (const char *filename, const char *fieldname,
             * buffer.
             */
 
-           dp = vp;
            len = 0;
 
            if (*dp == '"') {
                for (cp = dp + 1;;) {
                    switch (*cp++) {
-                   case '\0:
+                   case '\0':
 bad_quote:
                        advise (NULL,
                                "invalid quoted-string in message %s's %s: "
@@ -3484,9 +3454,30 @@ bad_quote:
                    break;
                }
 
-               valptr = mh_xmalloc(len + 1);
-           } else 
+           } else {
+               for (cp = dp; istoken (*cp); cp++) {
+                   len++;
+               }
+           }
 
+           valptr = mh_xmalloc(len + 1);
+
+           if (*dp == '"') {
+               int i;
+               for (cp = dp + 1, vp = valptr, i = 0; i < len; i++) {
+                   if (*cp == '\\') {
+                       cp++;
+                   }
+                   *vp++ = *cp++;
+               }
+               cp++;
+           } else {
+               strncpy(valptr, cp = dp, len);
+               cp += len;
+           }
+
+           valptr[len] = '\0';
+       }
 
        /*
         * If 'partial' is set, we don't allocate a parameter now.  We
@@ -3506,64 +3497,66 @@ bad_quote:
            if (pp == NULL) {
                pp = mh_xmalloc(sizeof(*pp));
                memset(pp, 0, sizeof(*pp));
+               pp->name = nameptr;
                pp->next = phead;
                phead = pp;
            }
 
-           if (index == 0 && encoded) {
-
-       pm = mh_xmalloc(sizeof(*pm));
-       memset(pm, 0, sizeof(*pm));
-
-       /* This is all mega-bozo and needs cleanup */
-       vp = (pm->pm_name = add (cp, NULL)) + (up - cp);
-       *vp = '\0';
-
-       /* Now store the attribute value. */
+           /*
+            * Insert this into the section linked list
+            */
 
-       vp = pm->pm_name + (dp - cp);
+           sp = mh_xmalloc(sizeof(*sp));
+           memset(sp, 0, sizeof(*sp));
+           sp->value = valptr;
+           sp->index = index;
+           sp->len = len;
 
-       if (*dp == '"') {
-           for (cp = ++dp, dp = vp;;) {
-               switch (*cp++) {
-                   case '\0':
-bad_quote:
-                       advise (NULL,
-                               "invalid quoted-string in message %s's %s: "
-                                "field\n%*s(parameter %s)",
+           if (pp->sechead == NULL || pp->sechead->index > index) {
+               sp->next = pp->sechead;
+               pp->sechead = sp;
+           } else {
+               for (sp2 = pp->sechead; sp2 != NULL; sp2 = sp2->next) {
+                   if (sp2->index == sp->index) {
+                       advise (NULL, "duplicate index (%d) in message "
+                               "%s's %s: field\n%*s(parameter %s)", sp->index,
                                filename, fieldname, strlen(invo_name) + 2, "",
-                               pm->pm_name);
+                               nameptr);
                        return NOTOK;
+                   }
+                   if (sp2->index < sp->index &&
+                       (sp2->next == NULL || sp2->next->index > sp->index)) {
+                       sp->next = sp2->next;
+                       sp2->next = sp;
+                       break;
+                   }
+               }
 
-                   case '\\':
-                       *dp++ = c;
-                       if ((c = *cp++) == '\0')
-                           goto bad_quote;
-                       /* else fall... */
+               if (sp2 == NULL) {
+                   advise(NULL, "Internal error: cannot insert partial "
+                          "param in message %s's %s: field\n%*s(parameter %s)",
+                          filename, fieldname, strlen(invo_name) + 2, "",
+                          nameptr);
+                   return NOTOK;
+               }
+           }
 
-                   default:
-                       *dp++ = c;
-                       continue;
+           /*
+            * Save our charset and lang tags.
+            */
 
-                   case '"':
-                       *dp = '\0';
-                       break;
-               }
-               break;
+           if (index == 0 && encoded) {
+               if (pp->charset)
+                   free(pp->charset);
+               pp->charset = charset;
+               if (pp->lang)
+                   free(pp->lang);
+               pp->lang = lang;
            }
        } else {
-           for (cp = dp, dp = vp; istoken (*cp); cp++, dp++)
-               continue;
-           *dp = '\0';
-       }
-       pm->pm_value = getcpy(vp); 
-       if (!*vp) {
-           advise (NULL,
-                   "invalid parameter in message %s's %s: "
-                    "field\n%*s(parameter %s)",
-                   filename, fieldname, strlen(invo_name) + 2, "",
-                   pm->pm_name);
-           return NOTOK;
+           pm = add_param(param_head, param_tail, nameptr, valptr, 1);
+           pm->pm_charset = charset;
+           pm->pm_lang = lang;
        }
 
        while (isspace ((unsigned char) *cp))
@@ -3573,20 +3566,70 @@ bad_quote:
             get_comment (filename, fieldname, &cp, commentp) == NOTOK) {
            return NOTOK;
         }
+    }
 
-       if (*param_head == NULL) {
-           *param_head = pm;
-           *param_tail = pm;
-       } else {
-           (*param_tail)->pm_next = pm;
-           *param_tail = pm;
+    /*
+     * 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
@@ -3994,14 +4037,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;
@@ -4014,6 +4057,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.
@@ -4049,7 +4119,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;
 
     /*
@@ -4124,9 +4197,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
      */