]> diplodocus.org Git - nmh/commitdiff
Getting closer to getting something working.
authorKen Hornstein <kenh@pobox.com>
Fri, 21 Feb 2014 19:49:07 +0000 (14:49 -0500)
committerKen Hornstein <kenh@pobox.com>
Fri, 21 Feb 2014 19:49:07 +0000 (14:49 -0500)
h/mhparse.h
uip/mhbuildsbr.c
uip/mhfixmsg.c
uip/mhfree.c
uip/mhlistsbr.c
uip/mhparse.c

index 3c0756d..0d4ef46 100644 (file)
@@ -341,7 +341,28 @@ char *ct_subtype_str (int, int);
 const struct str2init *get_ct_init (int);
 const char *ce_str (int);
 const struct str2init *get_ce_method (const char *);
-int parse_header_attrs (const char *, int, char **, CI, int *);
+
+/*
+ * Parse a series of MIME attributes (or parameters) given a header as
+ * input.
+ *
+ * Arguments include:
+ *
+ * filename    - Name of input file (for error messages)
+ * fieldname   - Name of field being processed
+ * headerp     - Pointer to pointer of the beginning of the MIME attributes.
+ *               Updated to point to end of attributes when finished.
+ * param_head  - Pointer to head of parameter list
+ * param_tail  - Pointer to tail of parameter list
+ * commentp    - Pointer to header comment pointer (may be NULL)
+ *
+ * Returns OK if parsing was successful, NOTOK if parsing failed, and
+ * DONE to indicate a benign error (minor parsing error, but the program
+ * should continue).
+ */
+int parse_header_attrs (const char *filename, const char *fieldname,
+                       char **headerp, PM *param_head, PM *param_tail,
+                       char **commentp);
 
 /*
  * Given a linked list of parameters, build an output string for them.  This
@@ -361,4 +382,18 @@ int parse_header_attrs (const char *, int, char **, CI, int *);
  */
 char *output_params(size_t initialwidth, PM params, int *offsetout);
 
+/*
+ * Add a parameter to the parameter linked list.
+ *
+ * Arguments are:
+ *
+ * first       - Pointer to head of linked list
+ * last                - Pointer to tail of linked list
+ * name                - Name of parameter
+ * value       - Value of parameter
+ *
+ * Returned allocated parameter element
+ */
+PM add_param(PM *first, PM *last, const char *name, const char *value);
+
 extern int checksw;    /* Add Content-MD5 field */
index b2949c3..6798bba 100644 (file)
@@ -1159,11 +1159,12 @@ compose_content (CT ct)
                    case 'a':
                    {
                        /* insert parameters from directive */
-                       char **ep;
                        char *s = "";
+                       PM pm;
 
-                       for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
-                           snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
+                       for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) {
+                           snprintf (bp, buflen, "%s%s=\"%s\"", s,
+                                     pm->pm_name, pm->pm_value);
                            len = strlen (bp);
                            bp += len;
                            buflen -= len;
@@ -1466,22 +1467,10 @@ scan_content (CT ct, size_t maxunencoded)
        t = (struct text *) ct->c_ctparams;
        if (t->tx_charset == CHARSET_UNSPECIFIED) {
            CI ci = &ct->c_ctinfo;
-           char **ap, **ep;
 
-           for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
-               continue;
-
-           if (contains8bit) {
-               *ap = concat ("charset=", write_charset_8bit(), NULL);
-           } else {
-               *ap = add ("charset=us-ascii", NULL);
-           }
+           add_param(&ci->ci_first_pm, &ci->ci_last_pm, "charset",
+                     contains8bit ? write_charset_8bit() : "us-ascii");
            t->tx_charset = CHARSET_SPECIFIED;
-
-           cp = strchr(*ap++, '=');
-           *ap = NULL;
-           *cp++ = '\0';
-           *ep = cp;
        }
     }
 
@@ -1537,25 +1526,19 @@ static int
 build_headers (CT ct)
 {
     int        cc, mailbody, extbody, len;
-    char **ap, **ep;
     char *np, *vp, buffer[BUFSIZ];
     CI ci = &ct->c_ctinfo;
+    PM pm;
 
     /*
      * If message is type multipart, then add the multipart
      * boundary to the list of attribute/value pairs.
      */
     if (ct->c_type == CT_MULTIPART) {
-       char *cp;
        static int level = 0;   /* store nesting level */
 
-       ap = ci->ci_attrs;
-       ep = ci->ci_values;
-       snprintf (buffer, sizeof(buffer), "boundary=%s%d", prefix, level++);
-       cp = strchr(*ap++ = add (buffer, NULL), '=');
-       *ap = NULL;
-       *cp++ = '\0';
-       *ep = cp;
+       snprintf (buffer, sizeof(buffer), "%s%d", prefix, level++);
+       add_param(&ci->ci_first_pm, &ci->ci_last_pm, "boundary", buffer);
     }
 
     /*
@@ -1585,8 +1568,8 @@ build_headers (CT ct)
      * Append the attribute/value pairs to
      * the end of the Content-Type line.
      */
-    for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
-       if (mailbody && !strcasecmp (*ap, "body"))
+    for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) {
+       if (mailbody && !strcasecmp (pm->pm_name, "body"))
            continue;
 
        vp = add (";", vp);
@@ -1597,8 +1580,8 @@ build_headers (CT ct)
         * we have to break it across multiple lines
         */
 
-       if (extbody && strcasecmp (*ap, "url") == 0) {
-           char *value = *ep;
+       if (extbody && strcasecmp (pm->pm_name, "url") == 0) {
+           char *value = pm->pm_value;
 
            /* 7 here refers to " url=\"\"" */
            if (len + 1 + (cc = (min(MAXURLTOKEN, strlen(value)) + 7)) >=
@@ -1628,7 +1611,7 @@ build_headers (CT ct)
            continue;
        }
 
-       snprintf (buffer, sizeof(buffer), "%s=\"%s\"", *ap, *ep);
+       snprintf (buffer, sizeof(buffer), "%s=\"%s\"", pm->pm_name, pm->pm_value);
        if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
            vp = add ("\n\t", vp);
            len = 8;
@@ -1889,8 +1872,9 @@ calculate_digest (CT ct, int asciiP)
 static void
 setup_attach_content(CT ct, char *filename)
 {
-    char *type, **ap, **ep, *simplename = r1bindex(filename, '/');
+    char *type, *simplename = r1bindex(filename, '/');
     struct str2init *s2i;
+    PM pm;
 
     if (! (type = mime_type(filename))) {
        adios(NULL, "Unable to determine MIME type of \"%s\"", filename);
@@ -1946,20 +1930,18 @@ setup_attach_content(CT ct, char *filename)
      * content-description, and the content-disposition.
      */
 
-    for (ap = ct->c_ctinfo.ci_attrs, ep = ct->c_ctinfo.ci_values; *ap;
-        ap++, ep++) {
-       if (strcasecmp(*ap, "name") == 0) {
-           if (*ep)
-               free(*ep);
-           *ep = getcpy(simplename);
+    for (pm = ct->c_ctinfo.ci_first_pm; pm; pm = pm->pm_next) {
+       if (strcasecmp(pm->pm_name, "name") == 0) {
+           if (pm->pm_value)
+               free(pm->pm_value);
+           pm->pm_value = getcpy(simplename);
            break;
        }
     }
 
-    if (*ap == NULL) {
-       *ap = getcpy("name");
-       *ep = getcpy(simplename);
-    }
+    if (pm == NULL)
+       add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm,
+                 "name", simplename);
 
     ct->c_descr = getcpy(simplename);
     ct->c_descr = add("\n", ct->c_descr);
index 2016250..a5787ff 100644 (file)
@@ -1073,19 +1073,19 @@ divide_part (CT ct) {
 
 static void
 copy_ctinfo (CI dest, CI src) {
-    char **s_ap, **d_ap, **s_vp, **d_vp;
+    PM s_pm, d_pm;
 
     dest->ci_type = src->ci_type ? add (src->ci_type, NULL) : NULL;
     dest->ci_subtype = src->ci_subtype ? add (src->ci_subtype, NULL) : NULL;
 
-    for (s_ap = src->ci_attrs, d_ap = dest->ci_attrs,
-             s_vp = src->ci_values, d_vp = dest->ci_values;
-         *s_ap;
-         ++s_ap, ++d_ap, ++s_vp, ++d_vp) {
-        *d_ap = add (*s_ap, NULL);
-        *d_vp = *s_vp;
+    for (s_pm = src->ci_first_pm; s_pm; s_pm = s_pm->pm_next) {
+       d_pm = add_param(&dest->ci_first_pm, &dest->ci_last_pm, s_pm->pm_name,
+                        s_pm->pm_value);
+       if (s_pm->pm_charset)
+           d_pm->pm_charset = getcpy(s_pm->pm_charset);
+       if (s_pm->pm_lang)
+           d_pm->pm_lang = getcpy(s_pm->pm_lang);
     }
-    *d_ap = NULL;
 
     dest->ci_comment = src->ci_comment ? add (src->ci_comment, NULL) : NULL;
     dest->ci_magic = src->ci_magic ? add (src->ci_magic, NULL) : NULL;
index 2975687..3f62482 100644 (file)
@@ -30,6 +30,7 @@ static void free_text (CT);
 static void free_multi (CT);
 static void free_partial (CT);
 static void free_external (CT);
+static void free_pmlist (PM);
 
 
 /*
@@ -103,6 +104,7 @@ free_content (CT ct)
        free (ct->c_descr);
     if (ct->c_dispo)
        free (ct->c_dispo);
+    free_pmlist (ct->c_dispo_first);
 
     if (ct->c_file) {
        if (ct->c_unlink)
@@ -162,10 +164,7 @@ free_ctinfo (CT ct)
        free (ci->ci_subtype);
        ci->ci_subtype = NULL;
     }
-    for (ap = ci->ci_attrs; *ap; ap++) {
-       free (*ap);
-       *ap = NULL;
-    }
+    free_pmlist(ci->ci_first_pm);
     if (ci->ci_comment) {
        free (ci->ci_comment);
        ci->ci_comment = NULL;
@@ -253,6 +252,27 @@ free_external (CT ct)
 }
 
 
+static void
+free_pmlist (PM pm)
+{
+    PM pm2;
+
+    while (pm != NULL) {
+       if (pm->pm_name)
+           free (pm->pm_name);
+       if (pm->pm_value)
+           free (pm->pm_value);
+       if (pm->pm_charset)
+           free (pm->pm_charset);
+       if (pm->pm_lang)
+           free (pm->pm_lang);
+       pm2 = pm->pm_next;
+       free(pm);
+       pm = pm2;
+    }
+}
+
+
 /*
  * Free data structures related to encoding/decoding
  * Content-Transfer-Encodings.
index 9380c3d..a3ac0c2 100644 (file)
@@ -199,11 +199,11 @@ list_content (CT ct, int toplevel, int realsize, int verbose, int debug)
     printf ("\n");
 
     if (verbose) {
-       char **ap, **ep;
        CI ci = &ct->c_ctinfo;
+       PM pm;
 
-       for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
-           printf ("\t     %s=\"%s\"\n", *ap, *ep);
+       for (pm = ci->ci_first_pm; pm; pm = pm->pm_next)
+           printf ("\t     %s=\"%s\"\n", pm->pm_name, pm->pm_value);
 
        /*
         * If verbose, print any RFC-822 comments in the
@@ -233,8 +233,8 @@ list_content (CT ct, int toplevel, int realsize, int verbose, int debug)
 static int
 list_debug (CT ct)
 {
-    char **ap, **ep;
     CI ci = &ct->c_ctinfo;
+    PM pm;
 
     fflush (stdout);
     fprintf (stderr, "  partno \"%s\"\n", empty (ct->c_partno));
@@ -255,8 +255,8 @@ list_debug (CT ct)
 
     /* print parsed parameters attached to content type */
     fprintf (stderr, "    parameters\n");
-    for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++)
-       fprintf (stderr, "      %s=\"%s\"\n", *ap, *ep);
+    for (pm = ci->ci_first_pm; pm; pm = pm->pm_next)
+       fprintf (stderr, "      %s=\"%s\"\n", pm->pm_name, pm->pm_value);
 
     /* print internal flags for type/subtype */
     fprintf (stderr, "    type 0x%x subtype 0x%x params 0x%x\n",
index 4db22d8..043effd 100644 (file)
@@ -109,7 +109,7 @@ void free_encoding (CT, int);
  * static prototypes
  */
 static CT get_content (FILE *, char *, int);
-static int get_comment (const char *, CI, char **, int);
+static int get_comment (const char *, const char *, char **, char **);
 
 static int InitGeneric (CT);
 static int InitText (CT);
@@ -380,7 +380,7 @@ get_content (FILE *in, char *file, int toplevel)
                fprintf (stderr, "%s: %s\n", VRSN_FIELD, cp);
 
            if (*cp == '('  &&
-                get_comment (ct->c_file, &ct->c_ctinfo, &cp, 0) == NOTOK)
+                get_comment (ct->c_file, VRSN_FIELD, &cp, NULL) == NOTOK)
                goto out;
 
            for (dp = cp; istoken (*dp); dp++)
@@ -490,7 +490,7 @@ get_content (FILE *in, char *file, int toplevel)
                fprintf (stderr, "%s: %s\n", MD5_FIELD, cp);
 
            if (*cp == '('  &&
-                get_comment (ct->c_file, &ct->c_ctinfo, &cp, 0) == NOTOK) {
+                get_comment (ct->c_file, MD5_FIELD, &cp, NULL) == NOTOK) {
                free (ep);
                goto out;
            }
@@ -686,7 +686,6 @@ get_ctinfo (char *cp, CT ct, int magic)
     int status;
 
     ci = &ct->c_ctinfo;
-    i = strlen (invo_name) + 2;
 
     /* store copy of Content-Type line */
     cp = ct->c_ctline = add (cp, NULL);
@@ -707,7 +706,8 @@ get_ctinfo (char *cp, CT ct, int magic)
     if (debugsw)
        fprintf (stderr, "%s: %s\n", TYPE_FIELD, cp);
 
-    if (*cp == '(' && get_comment (ct->c_file, &ct->c_ctinfo, &cp, 1) == NOTOK)
+    if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     for (dp = cp; istoken (*dp); dp++)
@@ -730,7 +730,8 @@ get_ctinfo (char *cp, CT ct, int magic)
     while (isspace ((unsigned char) *cp))
        cp++;
 
-    if (*cp == '(' && get_comment (ct->c_file, &ct->c_ctinfo, &cp, 1) == NOTOK)
+    if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     if (*cp != '/') {
@@ -743,7 +744,8 @@ get_ctinfo (char *cp, CT ct, int magic)
     while (isspace ((unsigned char) *cp))
        cp++;
 
-    if (*cp == '(' && get_comment (ct->c_file, &ct->c_ctinfo, &cp, 1) == NOTOK)
+    if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     for (dp = cp; istoken (*dp); dp++)
@@ -768,11 +770,14 @@ magic_skip:
     while (isspace ((unsigned char) *cp))
        cp++;
 
-    if (*cp == '(' && get_comment (ct->c_file, &ct->c_ctinfo, &cp, 1) == NOTOK)
+    if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
-    if (parse_header_attrs (ct->c_file, i, &cp, ci, &status) == NOTOK) {
-       return status;
+    if ((status = parse_header_attrs (ct->c_file, TYPE_FIELD, &cp,
+                                     &ci->ci_first_pm, &ci->ci_last_pm,
+                                     &ci->ci_comment)) != OK) {
+       return status == NOTOK ? NOTOK : OK;
     }
 
     /*
@@ -926,7 +931,8 @@ magic_skip:
 
 
 static int
-get_comment (const char *filename, CI ci, char **ap, int istype)
+get_comment (const char *filename, const char *fieldname, char **ap,
+            char **commentp)
 {
     int i;
     char *bp, *cp;
@@ -941,7 +947,7 @@ get_comment (const char *filename, CI ci, char **ap, int istype)
        case '\0':
 invalid:
        advise (NULL, "invalid comment in message %s's %s: field",
-               filename, istype ? TYPE_FIELD : VRSN_FIELD);
+               filename, fieldname);
        return NOTOK;
 
        case '\\':
@@ -968,12 +974,12 @@ invalid:
     }
     *bp = '\0';
 
-    if (istype) {
-       if ((dp = ci->ci_comment)) {
-           ci->ci_comment = concat (dp, " ", buffer, NULL);
+    if (commentp) {
+       if ((dp = *commentp)) {
+           *commentp = concat (dp, " ", buffer, NULL);
            free (dp);
        } else {
-           ci->ci_comment = add (buffer, NULL);
+           *commentp = add (buffer, NULL);
        }
     }
 
@@ -3227,32 +3233,22 @@ get_ce_method (const char *method) {
 }
 
 int
-parse_header_attrs (const char *filename, int len, char **header_attrp, CI ci,
-                    int *status) {
-    char **attr = ci->ci_attrs;
+parse_header_attrs (const char *filename, const char *fieldname,
+                   char **header_attrp, PM *param_head, PM *param_tail,
+                   char **commentp)
+{
     char *cp = *header_attrp;
+    PM pm;
 
     while (*cp == ';') {
        char *dp, *vp, *up, c;
 
-        /* Relies on knowledge of this declaration:
-         *   char *ci_attrs[NPARMS + 2];
-         */
-       if (attr >= ci->ci_attrs + sizeof ci->ci_attrs/sizeof (char *) - 2) {
-           advise (NULL,
-                   "too many parameters in message %s's %s: field (%d max)",
-                   filename, TYPE_FIELD, NPARMS);
-           *status = NOTOK;
-           return NOTOK;
-       }
-
        cp++;
        while (isspace ((unsigned char) *cp))
            cp++;
 
        if (*cp == '('  &&
-            get_comment (filename, ci, &cp, 1) == NOTOK) {
-           *status = NOTOK;
+            get_comment (filename, fieldname, &cp, commentp) == NOTOK) {
            return NOTOK;
         }
 
@@ -3260,9 +3256,8 @@ parse_header_attrs (const char *filename, int len, char **header_attrp, CI ci,
            advise (NULL,
                    "extraneous trailing ';' in message %s's %s: "
                     "parameter list",
-                   filename, TYPE_FIELD);
-           *status = OK;
-           return NOTOK;
+                   filename, fieldname);
+           return DONE;
        }
 
        /* down case the attribute name */
@@ -3275,19 +3270,23 @@ parse_header_attrs (const char *filename, int len, char **header_attrp, CI ci,
        if (dp == cp || *dp != '=') {
            advise (NULL,
                    "invalid parameter in message %s's %s: "
-                    "field\n%*.*sparameter %s (error detected at offset %d)",
-                   filename, TYPE_FIELD, len, len, "", cp, dp - cp);
-           *status = NOTOK;
+                    "field\n%*sparameter %s (error detected at offset %d)",
+                   filename, fieldname, strlen(invo_name) + 2, "",cp, dp - cp);
            return NOTOK;
        }
 
-       vp = (*attr = add (cp, NULL)) + (up - cp);
+       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';
        for (dp++; isspace ((unsigned char) *dp);)
            dp++;
 
        /* Now store the attribute value. */
-       ci->ci_values[attr - ci->ci_attrs] = vp = *attr + (dp - cp);
+
+       pm->pm_value = vp = pm->pm_name + (dp - cp);
 
        if (*dp == '"') {
            for (cp = ++dp, dp = vp;;) {
@@ -3296,9 +3295,9 @@ parse_header_attrs (const char *filename, int len, char **header_attrp, CI ci,
 bad_quote:
                        advise (NULL,
                                "invalid quoted-string in message %s's %s: "
-                                "field\n%*.*s(parameter %s)",
-                               filename, TYPE_FIELD, len, len, "", *attr);
-                       *status = NOTOK;
+                                "field\n%*s(parameter %s)",
+                               filename, fieldname, strlen(invo_name) + 2, "",
+                               pm->pm_name);
                        return NOTOK;
 
                    case '\\':
@@ -3325,9 +3324,9 @@ bad_quote:
        if (!*vp) {
            advise (NULL,
                    "invalid parameter in message %s's %s: "
-                    "field\n%*.*s(parameter %s)",
-                   filename, TYPE_FIELD, len, len, "", *attr);
-           *status = NOTOK;
+                    "field\n%*s(parameter %s)",
+                   filename, fieldname, strlen(invo_name) + 2, "",
+                   pm->pm_name);
            return NOTOK;
        }
 
@@ -3335,12 +3334,17 @@ bad_quote:
            cp++;
 
        if (*cp == '('  &&
-            get_comment (filename, ci, &cp, 1) == NOTOK) {
-           *status = NOTOK;
+            get_comment (filename, fieldname, &cp, commentp) == NOTOK) {
            return NOTOK;
         }
 
-        ++attr;
+       if (*param_head == NULL) {
+           *param_head = pm;
+           *param_tail = pm;
+       } else {
+           (*param_tail)->pm_next = pm;
+           *param_tail = pm;
+       }
     }
 
     *header_attrp = cp;
@@ -3698,3 +3702,28 @@ normal_param(PM pm, char *output, size_t len, size_t valuelen,
 
     return outlen + 1;
 }
+
+/*
+ * Add a parameter to the parameter linked list
+ */
+
+PM
+add_param(PM *first, PM *last, const char *name, const char *value)
+{
+    PM pm = mh_xmalloc(sizeof(*pm));
+
+    memset(pm, 0, sizeof(*pm));
+
+    pm->pm_name = getcpy(name);
+    pm->pm_value = getcpy(name);
+
+    if (*first) {
+       (*last)->pm_next = pm;
+       *last = pm;
+    } else {
+       *first = pm;
+       *last = pm;
+    }
+
+    return pm;
+}