X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/ebc5d74891031b94075b1547a9bd842224df67d3..3789a22b9fd7711d55e9b54997e4677d2b96dc78:/uip/mhparse.c diff --git a/uip/mhparse.c b/uip/mhparse.c index 6e16a5aa..a3a80f9a 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -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 */