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
*/
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 */
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;
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;
}
}
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);
}
/*
* 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);
* 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)) >=
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;
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);
* 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);
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;
static void free_multi (CT);
static void free_partial (CT);
static void free_external (CT);
+static void free_pmlist (PM);
/*
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)
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;
}
+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.
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
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));
/* 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",
* 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);
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++)
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;
}
int status;
ci = &ct->c_ctinfo;
- i = strlen (invo_name) + 2;
/* store copy of Content-Type line */
cp = ct->c_ctline = add (cp, NULL);
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++)
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 != '/') {
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++)
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;
}
/*
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;
case '\0':
invalid:
advise (NULL, "invalid comment in message %s's %s: field",
- filename, istype ? TYPE_FIELD : VRSN_FIELD);
+ filename, fieldname);
return NOTOK;
case '\\':
}
*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);
}
}
}
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;
}
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 */
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;;) {
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 '\\':
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;
}
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;
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;
+}