]> diplodocus.org Git - nmh/blobdiff - uip/mhparse.c
Removed export of most of the variables in test/common.sh.in. The
[nmh] / uip / mhparse.c
index 6e16a5aa613b9ecd66a36d13c2f3daad56decc77..a3a80f9a1b4b0242c5b395a382df5ca7664d37ba 100644 (file)
@@ -34,10 +34,14 @@ int checksw = 0;    /* check Content-MD5 field */
  * 1) Instruct parser not to detect invalid Content-Transfer-Encoding
  *    in a multipart.
  * 2) Suppress the warning about bogus multipart content, and report it.
+ * 3) Suppress the warning about extraneous trailing ';' in header parameter
+ *    lists, and report it.
  */
 int skip_mp_cte_check;
 int suppress_bogus_mp_content_warning;
 int bogus_mp_content;
+int suppress_extraneous_trailing_semicolon_warning;
+int extraneous_trailing_semicolon;
 
 /*
  * Structures for TEXT messages
@@ -59,6 +63,7 @@ struct k2v SubMultiPart[] = {
     { "alternative", MULTI_ALTERNATE },
     { "digest",      MULTI_DIGEST },
     { "parallel",    MULTI_PARALLEL },
+    { "related",     MULTI_RELATED },
     { NULL,          MULTI_UNKNOWN }    /* this one must be last! */
 };
 
@@ -115,7 +120,7 @@ static int get_comment (const char *, const char *, char **, char **);
 static int InitGeneric (CT);
 static int InitText (CT);
 static int InitMultiPart (CT);
-void reverse_parts (CT);
+static void reverse_parts (CT);
 static int InitMessage (CT);
 static int InitApplication (CT);
 static int init_encoding (CT, OpenCEFunc);
@@ -283,7 +288,7 @@ get_content (FILE *in, char *file, int toplevel)
     m_getfld_state_t gstate = 0;
 
     /* allocate the content structure */
-    if (!(ct = (CT) calloc (1, sizeof(*ct))))
+    if (!(ct = (CT) mh_xcalloc (1, sizeof(*ct))))
        adios (NULL, "out of memory");
 
     ct->c_fp = in;
@@ -1003,7 +1008,6 @@ InitText (CT ct)
     char *chset = NULL;
     char *cp;
     PM pm;
-    struct k2v *kv;
     struct text *t;
     CI ci = &ct->c_ctinfo;
 
@@ -1012,13 +1016,10 @@ InitText (CT ct)
        ci->ci_subtype = add ("plain", ci->ci_subtype);
 
     /* match subtype */
-    for (kv = SubText; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_TEXT, ci->ci_subtype);
 
     /* allocate text character set structure */
-    if ((t = (struct text *) calloc (1, sizeof(*t))) == NULL)
+    if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL)
        adios (NULL, "out of memory");
     ct->c_ctparams = (void *) t;
 
@@ -1068,7 +1069,6 @@ InitMultiPart (CT ct)
     size_t buflen;
     ssize_t gotlen;
     struct multipart *m;
-    struct k2v *kv;
     struct part *part, **next;
     CI ci = &ct->c_ctinfo;
     CT p;
@@ -1100,10 +1100,7 @@ InitMultiPart (CT ct)
     }
 
     /* match subtype */
-    for (kv = SubMultiPart; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_MULTIPART, ci->ci_subtype);
 
     /*
      * Check for "boundary" parameter, which is
@@ -1126,7 +1123,7 @@ InitMultiPart (CT ct)
     }
 
     /* allocate primary structure for multipart info */
-    if ((m = (struct multipart *) calloc (1, sizeof(*m))) == NULL)
+    if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
        adios (NULL, "out of memory");
     ct->c_ctparams = (void *) m;
 
@@ -1171,7 +1168,7 @@ InitMultiPart (CT ct)
            if (strcmp (bufp + 2, m->mp_start))
                continue;
 next_part:
-           if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL)
+           if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
                adios (NULL, "out of memory");
            *next = part;
            next = &part->mp_next;
@@ -1179,7 +1176,6 @@ 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;
            }
@@ -1277,7 +1273,7 @@ last_part:
  * reverse the order of the parts of a multipart/alternative
  */
 
-void
+static void
 reverse_parts (CT ct)
 {
     struct multipart *m = (struct multipart *) ct->c_ctparams;
@@ -1294,6 +1290,30 @@ reverse_parts (CT ct)
 }
 
 
+
+
+/* parse_mime() arranges alternates in reverse (priority) order.  This
+   function can be used to reverse them back.  This will put, for
+   example, a text/plain part before a text/html part in a
+   multipart/alternative part, for example, where it belongs. */
+void
+reverse_alternative_parts (CT ct) {
+    if (ct->c_type == CT_MULTIPART) {
+        struct multipart *m = (struct multipart *) ct->c_ctparams;
+        struct part *part;
+
+        if (ct->c_subtype == MULTI_ALTERNATE) {
+            reverse_parts (ct);
+        }
+
+        /* And call recursively on each part of a multipart. */
+        for (part = m->mp_parts; part; part = part->mp_next) {
+            reverse_alternative_parts (part->mp_part);
+        }
+    }
+}
+
+
 /*
  * MESSAGE
  */
@@ -1301,7 +1321,6 @@ reverse_parts (CT ct)
 static int
 InitMessage (CT ct)
 {
-    struct k2v *kv;
     CI ci = &ct->c_ctinfo;
 
     if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) {
@@ -1316,10 +1335,7 @@ InitMessage (CT ct)
        ci->ci_subtype = add ("rfc822", ci->ci_subtype);
 
     /* match subtype */
-    for (kv = SubMessage; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_MESSAGE, ci->ci_subtype);
 
     switch (ct->c_subtype) {
        case MESSAGE_RFC822:
@@ -1330,7 +1346,7 @@ InitMessage (CT ct)
                PM pm;
                struct partial *p;
 
-               if ((p = (struct partial *) calloc (1, sizeof(*p))) == NULL)
+               if ((p = (struct partial *) mh_xcalloc (1, sizeof(*p))) == NULL)
                    adios (NULL, "out of memory");
                ct->c_ctparams = (void *) p;
 
@@ -1379,7 +1395,7 @@ invalid_param:
                CT p;
                FILE *fp;
 
-               if ((e = (struct exbody *) calloc (1, sizeof(*e))) == NULL)
+               if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL)
                    adios (NULL, "out of memory");
                ct->c_ctparams = (void *) e;
 
@@ -1569,14 +1585,10 @@ params_external (CT ct, int composing)
 static int
 InitApplication (CT ct)
 {
-    struct k2v *kv;
     CI ci = &ct->c_ctinfo;
 
     /* match subtype */
-    for (kv = SubApplication; kv->kv_key; kv++)
-       if (!strcasecmp (ci->ci_subtype, kv->kv_key))
-           break;
-    ct->c_subtype = kv->kv_value;
+    ct->c_subtype = ct_str_subtype (CT_APPLICATION, ci->ci_subtype);
 
     return OK;
 }
@@ -2103,6 +2115,7 @@ ready_to_go:
       fclose (ct->c_fp);
       ct->c_fp = NULL;
     }
+    free (bufp);
     return fileno (ce->ce_fp);
 
 clean_up:
@@ -2111,6 +2124,7 @@ clean_up:
       fclose (ct->c_fp);
       ct->c_fp = NULL;
     }
+    free (bufp);
     return NOTOK;
 }
 
@@ -2250,7 +2264,9 @@ open7Bit (CT ct, char **file)
                cc = len;
            len -= cc;
 
-           fwrite (buffer, sizeof(*buffer), cc, ce->ce_fp);
+           if ((int) fwrite (buffer, sizeof(*buffer), cc, ce->ce_fp) < cc) {
+               advise ("open7Bit", "fwrite");
+           }
            if (ferror (ce->ce_fp)) {
                content_error (ce->ce_file, ct, "error writing to");
                goto clean_up;
@@ -2317,6 +2333,7 @@ openExternal (CT ct, CT cb, CE ce, char **file, int *fd)
        }
     }
 
+    *fd = fileno (ce->ce_fp);
     return OK;
 
 ready_already:
@@ -2384,7 +2401,9 @@ openFile (CT ct, char **file)
 
            while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp))
                       > 0)
-               fwrite (buffer, sizeof(*buffer), cc, fp);
+               if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) {
+                   advise ("openFile", "fwrite");
+               }
            fflush (fp);
 
            if (ferror (gp)) {
@@ -2593,7 +2612,9 @@ openFTP (CT ct, char **file)
 
                while ((cc= fread (buffer, sizeof(*buffer), sizeof(buffer), gp))
                           > 0)
-                   fwrite (buffer, sizeof(*buffer), cc, fp);
+                   if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) {
+                       advise ("openFTP", "fwrite");
+                   }
                fflush (fp);
 
                if (ferror (gp)) {
@@ -2853,7 +2874,9 @@ openURL (CT ct, char **file)
 
                while ((cc = fread(buffer, sizeof(*buffer),
                                   sizeof(buffer), gp)) > 0)
-                   fwrite(buffer, sizeof(*buffer), cc, fp);
+                   if ((int) fwrite(buffer, sizeof(*buffer), cc, fp) < cc) {
+                       advise ("openURL", "fwrite");
+                   }
 
                fflush(fp);
 
@@ -3115,6 +3138,8 @@ ct_subtype_str (int type, int subtype) {
             return "digest";
         case MULTI_PARALLEL:
             return "parallel";
+        case MULTI_RELATED:
+            return "related";
         default:
             return "unknown_multipart_subtype";
         }
@@ -3135,6 +3160,62 @@ ct_subtype_str (int type, int subtype) {
 }
 
 
+int
+ct_str_type (const char *type) {
+    struct str2init *s2i;
+
+    for (s2i = str2cts; s2i->si_key; ++s2i) {
+        if (! strcasecmp (type, s2i->si_key)) {
+            break;
+        }
+    }
+    if (! s2i->si_key  &&  ! uprf (type, "X-")) {
+        ++s2i;
+    }
+
+    return s2i->si_val;
+}
+
+
+int
+ct_str_subtype (int type, const char *subtype) {
+    struct k2v *kv;
+
+    switch (type) {
+    case CT_APPLICATION:
+        for (kv = SubApplication; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_MESSAGE:
+        for (kv = SubMessage; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_MULTIPART:
+        for (kv = SubMultiPart; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    case CT_TEXT:
+        for (kv = SubText; kv->kv_key; ++kv) {
+            if (! strcasecmp (subtype, kv->kv_key)) {
+                break;
+            }
+        }
+        return kv->kv_value;
+    default:
+        return 0;
+    }
+}
+
+
 /* Find the content type and InitFunc for the CT. */
 const struct str2init *
 get_ct_init (int type) {
@@ -3239,10 +3320,13 @@ parse_header_attrs (const char *filename, const char *fieldname,
         }
 
        if (*cp == 0) {
-           advise (NULL,
-                   "extraneous trailing ';' in message %s's %s: "
-                    "parameter list",
-                   filename, fieldname);
+           if (! suppress_extraneous_trailing_semicolon_warning) {
+               advise (NULL,
+                       "extraneous trailing ';' in message %s's %s: "
+                       "parameter list",
+                       filename, fieldname);
+           }
+           extraneous_trailing_semicolon = 1;
            return DONE;
        }
 
@@ -3517,6 +3601,7 @@ bad_quote:
                                "%s's %s: field\n%*s(parameter %s)", sp->index,
                                filename, fieldname, strlen(invo_name) + 2, "",
                                nameptr);
+                       free (nameptr);
                        return NOTOK;
                    }
                    if (sp2->index < sp->index &&
@@ -3532,6 +3617,7 @@ bad_quote:
                           "param in message %s's %s: field\n%*s(parameter %s)",
                           filename, fieldname, strlen(invo_name) + 2, "",
                           nameptr);
+                   free (nameptr);
                    return NOTOK;
                }
            }
@@ -3607,21 +3693,16 @@ bad_quote:
 }
 
 /*
- * Return the charset for a particular content type.  Return pointer is
- * only valid until the next call to content_charset().
+ * Return the charset for a particular content type.
  */
 
 char *
 content_charset (CT ct) {
-    static char *ret_charset = NULL;
-
-    if (ret_charset != NULL) {
-       free(ret_charset);
-    }
+    char *ret_charset = NULL;
 
     ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0);
 
-    return ret_charset ? ret_charset : "US-ASCII";
+    return ret_charset ? ret_charset : getcpy ("US-ASCII");
 }
 
 
@@ -3851,8 +3932,12 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont,
         * add them now.
         */
 
-       if (! pm->pm_charset)
+       if (! pm->pm_charset) {
            pm->pm_charset = getcpy(write_charset_8bit());
+           if (strcasecmp(pm->pm_charset, "US-ASCII") == 0)
+               adios(NULL, "8-bit characters in parameter \"%s\", but "
+                     "local character set is US-ASCII", pm->pm_name);
+       }
        if (! pm->pm_lang)
            pm->pm_lang = getcpy(NULL); /* Default to a blank lang tag */