X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/1d08c1e0c0de0d321883ece1c36bce851fe893c7..9ffabd06f0dc8e7478b7484fceee4906990d44e2:/uip/mhparse.c?ds=inline diff --git a/uip/mhparse.c b/uip/mhparse.c index 7ec030ba..ca01545f 100644 --- a/uip/mhparse.c +++ b/uip/mhparse.c @@ -1,6 +1,4 @@ - -/* - * mhparse.c -- routines to parse the contents of MIME messages +/* mhparse.c -- routines to parse the contents of MIME messages * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -15,6 +13,9 @@ #include #include #include +#include +#include "../sbr/m_mktemp.h" +#include "mhfree.h" #ifdef HAVE_ICONV # include #endif /* HAVE_ICONV */ @@ -22,10 +23,6 @@ extern int debugsw; -/* cache policies */ -extern int rcachesw; /* mhcachesbr.c */ -extern int wcachesw; /* mhcachesbr.c */ - int checksw = 0; /* check Content-MD5 field */ /* @@ -34,13 +31,16 @@ int checksw = 0; /* check Content-MD5 field */ * 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. + * lists. */ 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; + +/* + * By default, suppress warning about multiple MIME-Version header fields. + */ int suppress_multiple_mime_version_warning = 1; /* list of preferred type/subtype pairs, for -prefer */ @@ -54,8 +54,8 @@ int npreferred; */ struct k2v SubText[] = { { "plain", TEXT_PLAIN }, - { "richtext", TEXT_RICHTEXT }, /* defined in RFC-1341 */ - { "enriched", TEXT_ENRICHED }, /* defined in RFC-1896 */ + { "richtext", TEXT_RICHTEXT }, /* defined in RFC 1341 */ + { "enriched", TEXT_ENRICHED }, /* defined in RFC 1896 */ { NULL, TEXT_UNKNOWN } /* this one must be last! */ }; @@ -106,17 +106,11 @@ static struct k2v EncodingType[] = { }; -/* mhcachesbr.c */ -int find_cache (CT, int, int *, char *, char *, int); - /* mhmisc.c */ int part_ok (CT); int type_ok (CT, int); void content_error (char *, CT, char *, ...); -/* mhfree.c */ -void free_encoding (CT, int); - /* * static prototypes */ @@ -151,7 +145,6 @@ static int openURL (CT, char **); static int parse_header_attrs (const char *, const char *, char **, PM *, PM *, char **); static size_t param_len(PM, int, size_t, int *, int *, size_t *); -static size_t encode_param(PM, char *, size_t, size_t, size_t, int); static size_t normal_param(PM, char *, size_t, size_t, size_t); static int get_dispo (char *, CT, int); @@ -180,7 +173,7 @@ struct str2init str2ces[] = { /* * NOTE WELL: si_key MUST NOT have value of NOTOK * - * si_key is 1 if access method is anonymous. + * si_val is 1 if access method is anonymous. */ struct str2init str2methods[] = { { "afs", 1, InitFile }, @@ -207,6 +200,9 @@ parse_mime (char *file) FILE *fp; CT ct; size_t n; + struct stat statbuf; + + bogus_mp_content = 0; /* * Check if file is actually standard input @@ -218,7 +214,7 @@ parse_mime (char *file) get_temp_dir()); return NULL; } - file = add (tfile, NULL); + file = mh_xstrdup(tfile); while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) { if (fwrite(buffer, 1, n, fp) != n) { @@ -240,6 +236,13 @@ parse_mime (char *file) return NULL; } fseek (fp, 0L, SEEK_SET); + } else if (stat (file, &statbuf) == NOTOK) { + advise (file, "unable to stat"); + return NULL; + } else if (S_ISDIR(statbuf.st_mode)) { + /* Don't try to parse a directory. */ + inform("%s is a directory", file); + return NULL; } else if ((fp = fopen (file, "r")) == NULL) { advise (file, "unable to read"); return NULL; @@ -248,7 +251,7 @@ parse_mime (char *file) if (!(ct = get_content (fp, file, 1))) { if (is_stdin) (void) m_unlink (file); - advise (NULL, "unable to decode %s", file); + inform("unable to decode %s", file); return NULL; } @@ -288,16 +291,14 @@ static CT get_content (FILE *in, char *file, int toplevel) { int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; + char buf[NMH_BUFSIZ], name[NAMESZ]; char *np, *vp; CT ct; HF hp; - m_getfld_state_t gstate = 0; + m_getfld_state_t gstate; /* allocate the content structure */ - if (!(ct = (CT) mh_xcalloc (1, sizeof(*ct)))) - adios (NULL, "out of memory"); - + NEW0(ct); ct->c_fp = in; ct->c_file = add (file, NULL); ct->c_begin = ftell (ct->c_fp) + 1; @@ -306,22 +307,23 @@ get_content (FILE *in, char *file, int toplevel) * Parse the header fields for this * content into a linked list. */ - m_getfld_track_filepos (&gstate, in); + gstate = m_getfld_state_init(in); + m_getfld_track_filepos2(&gstate); for (compnum = 1;;) { int bufsz = sizeof buf; - switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) { + switch (state = m_getfld2(&gstate, name, buf, &bufsz)) { case FLD: case FLDPLUS: compnum++; /* get copies of the buffers */ - np = add (name, NULL); - vp = add (buf, NULL); + np = mh_xstrdup(name); + vp = mh_xstrdup(buf); /* if necessary, get rest of field */ while (state == FLDPLUS) { bufsz = sizeof buf; - state = m_getfld (&gstate, name, buf, &bufsz, in); + state = m_getfld2(&gstate, name, buf, &bufsz); vp = add (buf, vp); /* add to previous value */ } @@ -333,7 +335,28 @@ get_content (FILE *in, char *file, int toplevel) continue; case BODY: - ct->c_begin = ftell (in) - strlen (buf); + /* There are two cases. The unusual one is when there is no + * blank line between the headers and the body. This is + * indicated by the name of the header starting with `:'. + * + * For both cases, normal first, `1' is the desired c_begin + * file position for the start of the body, and `2' is the + * file position when buf is returned. + * + * f o o : b a r \n \n b o d y \n bufsz = 6 + * 1 2 move -5 + * f o o : b a r \n b o d y \n bufsz = 4 + * 1 2 move -4 + * + * For the normal case, bufsz includes the + * header-terminating `\n', even though it is not in buf, + * but bufsz isn't affected when it's missing in the unusual + * case. */ + if (name[0] == ':') { + ct->c_begin = ftell(in) - bufsz; + } else { + ct->c_begin = ftell (in) - (bufsz - 1); + } break; case FILEEOF: @@ -395,14 +418,14 @@ get_content (FILE *in, char *file, int toplevel) ucmp = !strcasecmp (cp, VRSN_VALUE); *dp = c; if (!ucmp) { - admonish (NULL, "message %s has unknown value for %s: field (%s)", + inform("message %s has unknown value for %s: field (%s), continuing...", ct->c_file, VRSN_FIELD, cp); } if (!ct->c_vrsn) { ct->c_vrsn = vrsn; } else { if (! suppress_multiple_mime_version_warning) - advise (NULL, "message %s has multiple %s: fields", + inform("message %s has multiple %s: fields", ct->c_file, VRSN_FIELD); free(vrsn); } @@ -414,7 +437,7 @@ get_content (FILE *in, char *file, int toplevel) /* Check if we've already seen a Content-Type header */ if (ct->c_ctline) { - advise (NULL, "message %s has multiple %s: fields", + inform("message %s has multiple %s: fields", ct->c_file, TYPE_FIELD); goto next_header; } @@ -445,7 +468,7 @@ get_content (FILE *in, char *file, int toplevel) * Content-Transfer-Encoding field */ if (ct->c_celine) { - advise (NULL, "message %s has multiple %s: fields", + inform("message %s has multiple %s: fields", ct->c_file, ENCODING_FIELD); goto next_header; } @@ -484,7 +507,7 @@ get_content (FILE *in, char *file, int toplevel) goto next_header; if (ct->c_digested) { - advise (NULL, "message %s has multiple %s: fields", + inform("message %s has multiple %s: fields", ct->c_file, MD5_FIELD); goto next_header; } @@ -584,7 +607,7 @@ add_header (CT ct, char *name, char *value) HF hp; /* allocate header field structure */ - hp = mh_xmalloc (sizeof(*hp)); + NEW(hp); /* link data into header structure */ hp->name = name; @@ -643,20 +666,18 @@ get_ctinfo (char *cp, CT ct, int magic) for (dp = cp; istoken (*dp); dp++) continue; - c = *dp, *dp = '\0'; - ci->ci_type = add (cp, NULL); /* store content type */ - *dp = c, cp = dp; + c = *dp; + *dp = '\0'; + ci->ci_type = mh_xstrdup(cp); /* store content type */ + *dp = c; + cp = dp; if (!*ci->ci_type) { - advise (NULL, "invalid %s: field in message %s (empty type)", + inform("invalid %s: field in message %s (empty type)", TYPE_FIELD, ct->c_file); return NOTOK; } - - /* down case the content type string */ - for (dp = ci->ci_type; *dp; dp++) - if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) - *dp = tolower ((unsigned char) *dp); + to_lower(ci->ci_type); while (isspace ((unsigned char) *cp)) cp++; @@ -667,7 +688,7 @@ get_ctinfo (char *cp, CT ct, int magic) if (*cp != '/') { if (!magic) - ci->ci_subtype = add ("", NULL); + ci->ci_subtype = mh_xstrdup(""); goto magic_skip; } @@ -681,21 +702,18 @@ get_ctinfo (char *cp, CT ct, int magic) for (dp = cp; istoken (*dp); dp++) continue; - c = *dp, *dp = '\0'; - ci->ci_subtype = add (cp, NULL); /* store the content subtype */ - *dp = c, cp = dp; + c = *dp; + *dp = '\0'; + ci->ci_subtype = mh_xstrdup(cp); /* store the content subtype */ + *dp = c; + cp = dp; if (!*ci->ci_subtype) { - advise (NULL, - "invalid %s: field in message %s (empty subtype for \"%s\")", - TYPE_FIELD, ct->c_file, ci->ci_type); + inform("invalid %s: field in message %s (empty subtype for \"%s\")", + TYPE_FIELD, ct->c_file, ci->ci_type); return NOTOK; } - - /* down case the content subtype string */ - for (dp = ci->ci_subtype; *dp; dp++) - if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) - *dp = tolower ((unsigned char) *dp); + to_lower(ci->ci_subtype); magic_skip: while (isspace ((unsigned char) *cp)) @@ -715,12 +733,10 @@ magic_skip: * Get any given in buffer */ if (magic && *cp == '<') { - if (ct->c_id) { - free (ct->c_id); - ct->c_id = NULL; - } + mh_xfree(ct->c_id); + ct->c_id = NULL; if (!(dp = strchr(ct->c_id = ++cp, '>'))) { - advise (NULL, "invalid ID in message %s", ct->c_file); + inform("invalid ID in message %s", ct->c_file); return NOTOK; } c = *dp; @@ -745,7 +761,7 @@ magic_skip: if (*dp == ']') break; if (dp < cp) { - advise (NULL, "invalid description in message %s", ct->c_file); + inform("invalid description in message %s", ct->c_file); ct->c_descr = NULL; return NOTOK; } @@ -772,7 +788,7 @@ magic_skip: if (*dp == '}') break; if (dp < cp) { - advise (NULL, "invalid disposition in message %s", ct->c_file); + inform("invalid disposition in message %s", ct->c_file); ct->c_dispo = NULL; return NOTOK; } @@ -806,7 +822,7 @@ magic_skip: cp++; if (dp == cp) { - advise (NULL, "invalid null transfer encoding specification"); + inform("invalid null transfer encoding specification"); return NOTOK; } @@ -823,7 +839,7 @@ magic_skip: } if (ct->c_reqencoding == CE_UNKNOWN) { - advise (NULL, "invalid CTE specification: \"%s\"", dp); + inform("invalid CTE specification: \"%s\"", dp); return NOTOK; } @@ -836,7 +852,7 @@ magic_skip: */ if (*cp) { if (magic) { - ci->ci_magic = add (cp, NULL); + ci->ci_magic = mh_xstrdup(cp); /* If there is a Content-Disposition header and it doesn't have a *filename=, extract it from the magic contents. @@ -849,9 +865,8 @@ magic_skip: } } else - advise (NULL, - "extraneous information in message %s's %s: field\n%*s(%s)", - ct->c_file, TYPE_FIELD, strlen(invo_name) + 2, "", cp); + inform("extraneous information in message %s's %s: field\n" + " (%s)", ct->c_file, TYPE_FIELD, cp); } return OK; @@ -902,9 +917,11 @@ get_dispo (char *cp, CT ct, int buildflag) for (dp = cp; istoken (*dp); dp++) continue; - c = *dp, *dp = '\0'; - ct->c_dispo_type = add (cp, NULL); /* store disposition type */ - *dp = c, cp = dp; + c = *dp; + *dp = '\0'; + ct->c_dispo_type = mh_xstrdup(cp); /* store disposition type */ + *dp = c; + cp = dp; if (*cp == '(' && get_comment (ct->c_file, DISPO_FIELD, &cp, NULL) == NOTOK) return NOTOK; @@ -917,9 +934,8 @@ get_dispo (char *cp, CT ct, int buildflag) return NOTOK; } } else if (*cp) { - advise (NULL, - "extraneous information in message %s's %s: field\n%*s(%s)", - ct->c_file, DISPO_FIELD, strlen(invo_name) + 2, "", cp); + inform("extraneous information in message %s's %s: field\n (%s)", + ct->c_file, DISPO_FIELD, cp); } if (buildflag) @@ -947,7 +963,7 @@ get_comment (const char *filename, const char *fieldname, char **ap, switch (c = *cp++) { case '\0': invalid: - advise (NULL, "invalid comment in message %s's %s: field", + inform("invalid comment in message %s's %s: field", filename, fieldname); return NOTOK; @@ -960,7 +976,7 @@ invalid: case '(': i++; - /* and fall... */ + /* FALLTHRU */ default: *bp++ = c; continue; @@ -980,7 +996,7 @@ invalid: *commentp = concat (dp, " ", buffer, NULL); free (dp); } else { - *commentp = add (buffer, NULL); + *commentp = mh_xstrdup(buffer); } } @@ -1030,8 +1046,7 @@ InitText (CT ct) ct->c_subtype = ct_str_subtype (CT_TEXT, ci->ci_subtype); /* allocate text character set structure */ - if ((t = (struct text *) mh_xcalloc (1, sizeof(*t))) == NULL) - adios (NULL, "out of memory"); + NEW0(t); ct->c_ctparams = (void *) t; /* scan for charset parameter */ @@ -1057,7 +1072,7 @@ InitText (CT ct) if (chset != NULL && !check_charset (chset, strlen (chset))) { snprintf (buffer, sizeof(buffer), "%s-charset-%s", invo_name, chset); if ((cp = context_find (buffer))) - ct->c_termproc = getcpy (cp); + ct->c_termproc = mh_xstrdup(cp); } return OK; @@ -1087,25 +1102,24 @@ InitMultiPart (CT ct) /* * The encoding for multipart messages must be either - * 7bit, 8bit, or binary (per RFC2045). + * 7bit, 8bit, or binary (per RFC 2045). */ if (! skip_mp_cte_check && ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT && ct->c_encoding != CE_BINARY) { /* Copy the Content-Transfer-Encoding header field body so we can remove any trailing whitespace and leading blanks from it. */ - char *cte = add (ct->c_celine ? ct->c_celine : "(null)", NULL); + char *cte = mh_xstrdup(ct->c_celine ? ct->c_celine : "(null)"); bp = cte + strlen (cte) - 1; while (bp >= cte && isspace ((unsigned char) *bp)) *bp-- = '\0'; for (bp = cte; *bp && isblank ((unsigned char) *bp); ++bp) continue; - admonish (NULL, - "\"%s/%s\" type in message %s must be encoded in\n" - "7bit, 8bit, or binary, per RFC 2045 (6.4). " - "mhfixmsg -fixcte can fix it, or\n" - "manually edit the file and change the \"%s\"\n" - "Content-Transfer-Encoding to one of those. For now", - ci->ci_type, ci->ci_subtype, ct->c_file, bp); + inform("\"%s/%s\" type in message %s must be encoded in\n" + "7bit, 8bit, or binary, per RFC 2045 (6.4). " + "mhfixmsg -fixcte can fix it, or\n" + "manually edit the file and change the \"%s\"\n" + "Content-Transfer-Encoding to one of those. For now, continuing...", + ci->ci_type, ci->ci_subtype, ct->c_file, bp); free (cte); return NOTOK; @@ -1128,22 +1142,20 @@ InitMultiPart (CT ct) /* complain if boundary parameter is missing */ if (!pm) { - advise (NULL, - "a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field", - ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); + inform("a \"boundary\" parameter is mandatory for \"%s/%s\" type in message %s's %s: field", + ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); return NOTOK; } /* allocate primary structure for multipart info */ - if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL) - adios (NULL, "out of memory"); + NEW0(m); ct->c_ctparams = (void *) m; /* check if boundary parameter contains only whitespace characters */ for (cp = bp; isspace ((unsigned char) *cp); cp++) continue; if (!*cp) { - advise (NULL, "invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field", + inform("invalid \"boundary\" parameter for \"%s/%s\" type in message %s's %s: field", ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); return NOTOK; } @@ -1180,8 +1192,7 @@ InitMultiPart (CT ct) if (strcmp (bufp + 2, m->mp_start)) continue; next_part: - if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL) - adios (NULL, "out of memory"); + NEW0(part); *next = part; next = &part->mp_next; @@ -1207,15 +1218,14 @@ end_part: if (inout) goto next_part; goto last_part; - } else { - if (strcmp (bufp + 2, m->mp_stop) == 0) - goto end_part; } + if (strcmp (bufp + 2, m->mp_stop) == 0) + goto end_part; } } if (! suppress_bogus_mp_content_warning) { - advise (NULL, "bogus multipart content in message %s", ct->c_file); + inform("bogus multipart content in message %s", ct->c_file); } bogus_mp_content = 1; @@ -1229,7 +1239,7 @@ end_part: continue; *next = NULL; free_content (p); - free ((char *) part); + free(part); } } @@ -1261,7 +1271,7 @@ last_part: p = part->mp_part; sprintf (pp, "%d", partnum); - p->c_partno = add (partnam, NULL); + p->c_partno = mh_xstrdup(partnam); /* initialize the content of the subparts */ if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) { @@ -1289,7 +1299,7 @@ last_part: * ease of choosing/displaying it later on. from a mail message on * nmh-workers, from kenh: * "Stock" MH 6.8.5 did not have a reverse_parts() function, but I - * see code in mhn that did the same thing... Acccording to the RCS + * see code in mhn that did the same thing... According to the RCS * logs, that code was around from the initial checkin of mhn.c by * John Romine in 1992, which is as far back as we have." */ @@ -1398,9 +1408,9 @@ InitMessage (CT ct) CI ci = &ct->c_ctinfo; if ((ct->c_encoding != CE_7BIT) && (ct->c_encoding != CE_8BIT)) { - admonish (NULL, - "\"%s/%s\" type in message %s should be encoded in 7bit or 8bit", - ci->ci_type, ci->ci_subtype, ct->c_file); + inform("\"%s/%s\" type in message %s should be encoded in " + "7bit or 8bit, continuing...", ci->ci_type, ci->ci_subtype, + ct->c_file); return NOTOK; } @@ -1420,8 +1430,7 @@ InitMessage (CT ct) PM pm; struct partial *p; - if ((p = (struct partial *) mh_xcalloc (1, sizeof(*p))) == NULL) - adios (NULL, "out of memory"); + NEW0(p); ct->c_ctparams = (void *) p; /* scan for parameters "id", "number", and "total" */ @@ -1434,10 +1443,9 @@ InitMessage (CT ct) if (sscanf (pm->pm_value, "%d", &p->pm_partno) != 1 || p->pm_partno < 1) { invalid_param: - advise (NULL, - "invalid %s parameter for \"%s/%s\" type in message %s's %s field", - pm->pm_name, ci->ci_type, ci->ci_subtype, - ct->c_file, TYPE_FIELD); + inform("invalid %s parameter for \"%s/%s\" type in message %s's %s field", + pm->pm_name, ci->ci_type, ci->ci_subtype, + ct->c_file, TYPE_FIELD); return NOTOK; } continue; @@ -1453,10 +1461,8 @@ invalid_param: if (!p->pm_partid || !p->pm_partno || (p->pm_maxno && p->pm_partno > p->pm_maxno)) { - advise (NULL, - "invalid parameters for \"%s/%s\" type in message %s's %s field", - ci->ci_type, ci->ci_subtype, - ct->c_file, TYPE_FIELD); + inform("invalid parameters for \"%s/%s\" type in message %s's %s field", + ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); return NOTOK; } } @@ -1469,8 +1475,7 @@ invalid_param: CT p; FILE *fp; - if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL) - adios (NULL, "out of memory"); + NEW0(e); ct->c_ctparams = (void *) e; if (!ct->c_fp @@ -1537,7 +1542,7 @@ no_body: case CT_MESSAGE: if (p->c_subtype != MESSAGE_RFC822) break; - /* else fall... */ + /* FALLTHRU */ default: e->eb_partno = ct->c_partno; if (p->c_ctinitfnx) @@ -1642,9 +1647,8 @@ params_external (CT ct, int composing) } if (!e->eb_access) { - advise (NULL, - "invalid parameters for \"%s/%s\" type in message %s's %s field", - ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); + inform("invalid parameters for \"%s/%s\" type in message %s's %s field", + ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD); return NOTOK; } @@ -1710,8 +1714,7 @@ size_encoding (CT ct) if (ce->ce_file) { if (stat (ce->ce_file, &st) != NOTOK) return (long) st.st_size; - else - return 0L; + return 0L; } if (ct->c_encoding == CE_EXTERNAL) @@ -1771,7 +1774,7 @@ openBase64 (CT ct, char **file) if (*file == NULL) { ce->ce_unlink = 1; } else { - ce->ce_file = add (*file, NULL); + ce->ce_file = mh_xstrdup(*file); ce->ce_unlink = 0; } @@ -1793,7 +1796,7 @@ openBase64 (CT ct, char **file) adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -1838,13 +1841,16 @@ openBase64 (CT ct, char **file) *cp = '\0'; if (decodeBase64 (buffer, &decoded, &decoded_len, ct->c_type == CT_TEXT, - ct->c_digested ? digest : NULL) == OK) { + ct->c_digested ? digest : NULL) != OK) + goto clean_up; + + { size_t i; unsigned char *decoded_p = decoded; for (i = 0; i < decoded_len; ++i) { putc (*decoded_p++, ce->ce_fp); } - free ((char *) decoded); + free(decoded); if (ferror (ce->ce_fp)) { content_error (ce->ce_file, ct, "error writing to"); goto clean_up; @@ -1852,7 +1858,7 @@ openBase64 (CT ct, char **file) if (ct->c_digested) { if (memcmp(digest, ct->c_digest, - sizeof(digest) / sizeof(digest[0]))) { + sizeof digest)) { content_error (NULL, ct, "content integrity suspect (digest mismatch) -- continuing"); } else { @@ -1861,8 +1867,6 @@ openBase64 (CT ct, char **file) } } } - } else { - goto clean_up; } fseek (ct->c_fp, 0L, SEEK_SET); @@ -1955,7 +1959,7 @@ openQuoted (CT ct, char **file) if (*file == NULL) { ce->ce_unlink = 1; } else { - ce->ce_file = add (*file, NULL); + ce->ce_file = mh_xstrdup(*file); ce->ce_unlink = 0; } @@ -1977,7 +1981,7 @@ openQuoted (CT ct, char **file) adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -2018,7 +2022,8 @@ openQuoted (CT ct, char **file) for (ep = (cp = bufp) + cc - 1; cp <= ep; ep--) if (!isspace ((unsigned char) *ep)) break; - *++ep = '\n', ep++; + *++ep = '\n'; + ep++; for (; cp < ep; cp++) { if (quoted > 0) { @@ -2064,11 +2069,10 @@ openQuoted (CT ct, char **file) * sequence; let's decode it (above). */ quoted = 1; continue; - } else { - /* One or both of the next 2 is out of range, making this - * an invalid escape sequence; just show the raw bytes - * (below). */ } + /* One or both of the next 2 is out of range, making this + * an invalid escape sequence; just show the raw bytes + * (below). */ } /* Just show the raw byte. */ @@ -2104,12 +2108,11 @@ openQuoted (CT ct, char **file) MD5Final (digest, &mdContext); if (memcmp((char *) digest, (char *) ct->c_digest, - sizeof(digest) / sizeof(digest[0]))) + sizeof digest)) content_error (NULL, ct, "content integrity suspect (digest mismatch) -- continuing"); - else - if (debugsw) - fprintf (stderr, "content integrity confirmed\n"); + else if (debugsw) + fprintf (stderr, "content integrity confirmed\n"); } fseek (ce->ce_fp, 0L, SEEK_SET); @@ -2175,7 +2178,7 @@ open7Bit (CT ct, char **file) if (*file == NULL) { ce->ce_unlink = 1; } else { - ce->ce_file = add (*file, NULL); + ce->ce_file = mh_xstrdup(*file); ce->ce_unlink = 0; } @@ -2197,7 +2200,7 @@ open7Bit (CT ct, char **file) adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -2330,15 +2333,14 @@ openExternal (CT ct, CT cb, CE ce, char **file, int *fd) if (find_cache (ct, rcachesw, (int *) 0, cb->c_id, cachefile, sizeof(cachefile)) != NOTOK) { if ((ce->ce_fp = fopen (cachefile, "r"))) { - ce->ce_file = getcpy (cachefile); + ce->ce_file = mh_xstrdup(cachefile); ce->ce_unlink = 0; goto ready_already; - } else { - admonish (cachefile, "unable to fopen for reading"); } + admonish (cachefile, "unable to fopen for reading"); } - *fd = fileno (ce->ce_fp); + *fd = ce->ce_fp ? fileno (ce->ce_fp) : -1; return OK; ready_already: @@ -2382,7 +2384,7 @@ openFile (CT ct, char **file) return NOTOK; } - ce->ce_file = getcpy (e->eb_name); + ce->ce_file = mh_xstrdup(e->eb_name); ce->ce_unlink = 0; if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { @@ -2414,12 +2416,10 @@ openFile (CT ct, char **file) if (ferror (gp)) { admonish (ce->ce_file, "error reading"); (void) m_unlink (cachefile); - } - else - if (ferror (fp)) { - admonish (cachefile, "error writing"); - (void) m_unlink (cachefile); - } + } else if (ferror (fp)) { + admonish (cachefile, "error writing"); + (void) m_unlink (cachefile); + } fclose (fp); } umask (mask); @@ -2523,7 +2523,7 @@ openFTP (CT ct, char **file) LocalName (1)); pass = buffer; } else { - ruserpass (e->eb_site, &username, &password); + ruserpass (e->eb_site, &username, &password, 0); user = username; pass = password; } @@ -2541,16 +2541,16 @@ openFTP (CT ct, char **file) } if (*file) - ce->ce_file = add (*file, NULL); + ce->ce_file = mh_xstrdup(*file); else if (caching) - ce->ce_file = add (cachefile, NULL); + ce->ce_file = mh_xstrdup(cachefile); else { char *tempfile; if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); } if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) { @@ -2625,12 +2625,10 @@ openFTP (CT ct, char **file) if (ferror (gp)) { admonish (ce->ce_file, "error reading"); (void) m_unlink (cachefile); - } - else - if (ferror (fp)) { - admonish (cachefile, "error writing"); - (void) m_unlink (cachefile); - } + } else if (ferror (fp)) { + admonish (cachefile, "error writing"); + (void) m_unlink (cachefile); + } fclose (fp); } umask (mask); @@ -2729,7 +2727,7 @@ openMail (CT ct, char **file) default: if (pidXwait (child_id, NULL) == OK) - advise (NULL, "request sent"); + inform("request sent"); break; } @@ -2739,10 +2737,10 @@ openMail (CT ct, char **file) adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); ce->ce_unlink = 1; } else { - ce->ce_file = add (*file, NULL); + ce->ce_file = mh_xstrdup(*file); ce->ce_unlink = 0; } @@ -2753,9 +2751,8 @@ openMail (CT ct, char **file) /* showproc is for mhshow and mhstore, though mhlist -debug * prints it, too. */ - if (ct->c_showproc) - free (ct->c_showproc); - ct->c_showproc = add ("true", NULL); + mh_xfree(ct->c_showproc); + ct->c_showproc = mh_xstrdup("true"); fseek (ce->ce_fp, 0L, SEEK_SET); *file = ce->ce_file; @@ -2822,16 +2819,16 @@ openURL (CT ct, char **file) } if (*file) - ce->ce_file = add(*file, NULL); + ce->ce_file = mh_xstrdup(*file); else if (caching) - ce->ce_file = add(cachefile, NULL); + ce->ce_file = mh_xstrdup(cachefile); else { char *tempfile; if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { adios(NULL, "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tempfile, NULL); + ce->ce_file = mh_xstrdup(tempfile); } if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) { @@ -2896,7 +2893,7 @@ openURL (CT ct, char **file) fseeko(ce->ce_fp, 0, SEEK_SET); *file = ce->ce_file; - return fd; + return fileno(ce->ce_fp); } @@ -2911,7 +2908,7 @@ readDigest (CT ct, char *cp) size_t len; if (decodeBase64 (cp, &digest, &len, 0, NULL) == OK) { - const size_t maxlen = sizeof ct->c_digest / sizeof ct->c_digest[0]; + const size_t maxlen = sizeof ct->c_digest; if (strlen ((char *) digest) <= maxlen) { memcpy (ct->c_digest, digest, maxlen); @@ -2927,17 +2924,16 @@ readDigest (CT ct, char *cp) } return OK; - } else { - if (debugsw) { - fprintf (stderr, "invalid MD5 digest (got %d octets)\n", - (int) strlen ((char *) digest)); - } - - return NOTOK; } - } else { + if (debugsw) { + fprintf (stderr, "invalid MD5 digest (got %d octets)\n", + (int) strlen ((char *) digest)); + } + return NOTOK; } + + return NOTOK; } @@ -3292,27 +3288,22 @@ parse_header_attrs (const char *filename, const char *fieldname, if (*cp == 0) { if (! suppress_extraneous_trailing_semicolon_warning) { - advise (NULL, - "extraneous trailing ';' in message %s's %s: " - "parameter list", - filename, fieldname); + inform("extraneous trailing ';' in message %s's %s: " + "parameter list", filename, fieldname); } - extraneous_trailing_semicolon = 1; return DONE; } /* down case the attribute name */ for (dp = cp; istoken ((unsigned char) *dp); dp++) - if (isalpha((unsigned char) *dp) && isupper ((unsigned char) *dp)) - *dp = tolower ((unsigned char) *dp); + *dp = tolower ((unsigned char) *dp); for (up = dp; isspace ((unsigned char) *dp);) dp++; if (dp == cp || *dp != '=') { - advise (NULL, - "invalid parameter in message %s's %s: " - "field\n%*sparameter %s (error detected at offset %d)", - filename, fieldname, strlen(invo_name) + 2, "",cp, dp - cp); + inform("invalid parameter in message %s's %s: field\n" + " parameter %s (error detected at offset %ld)", + filename, fieldname, cp, (long)(dp - cp)); return NOTOK; } @@ -3336,15 +3327,15 @@ parse_header_attrs (const char *filename, const char *fieldname, if (*vp == '*' && vp < up - 1) { partial = 1; continue; - } else if (*vp == '*' && vp == up - 1) { + } + if (*vp == '*' && vp == up - 1) { encoded = 1; } else if (partial) { if (isdigit((unsigned char) *vp)) index = *vp - '0' + index * 10; else { - advise (NULL, "invalid parameter index in message %s's " - "%s: field\n%*s(parameter %s)", filename, - fieldname, strlen(invo_name) + 2, "", cp); + inform("invalid parameter index in message %s's %s: field" + "\n (parameter %s)", filename, fieldname, cp); return NOTOK; } } else { @@ -3386,9 +3377,8 @@ parse_header_attrs (const char *filename, const char *fieldname, } vp++; } else { - advise(NULL, "missing charset in message %s's %s: " - "field\n%*s(parameter %s)", filename, fieldname, - strlen(invo_name) + 2, "", nameptr); + inform("missing charset in message %s's %s: field\n" + " (parameter %s)", filename, fieldname, nameptr); free(nameptr); return NOTOK; } @@ -3409,12 +3399,10 @@ parse_header_attrs (const char *filename, const char *fieldname, } vp++; } else { - advise(NULL, "missing language tag in message %s's %s: " - "field\n%*s(parameter %s)", filename, fieldname, - strlen(invo_name) + 2, "", nameptr); + inform("missing language tag in message %s's %s: field\n" + " (parameter %s)", filename, fieldname, nameptr); free(nameptr); - if (charset) - free(charset); + mh_xfree(charset); return NOTOK; } @@ -3434,15 +3422,11 @@ parse_header_attrs (const char *filename, const char *fieldname, !isxdigit((unsigned char) *(vp + 1)) || *(vp + 2) == '\0' || !isxdigit((unsigned char) *(vp + 2))) { - advise(NULL, "invalid encoded sequence in message " - "%s's %s: field\n%*s(parameter %s)", - filename, fieldname, strlen(invo_name) + 2, - "", nameptr); + inform("invalid encoded sequence in message %s's %s: field\n" + " (parameter %s)", filename, fieldname, nameptr); free(nameptr); - if (charset) - free(charset); - if (lang) - free(lang); + mh_xfree(charset); + mh_xfree(lang); return NOTOK; } vp += 2; @@ -3479,16 +3463,11 @@ parse_header_attrs (const char *filename, const char *fieldname, switch (*cp++) { case '\0': bad_quote: - advise (NULL, - "invalid quoted-string in message %s's %s: " - "field\n%*s(parameter %s)", - filename, fieldname, strlen(invo_name) + 2, "", - nameptr); + inform("invalid quoted-string in message %s's %s: field\n" + " (parameter %s)", filename, fieldname, nameptr); free(nameptr); - if (charset) - free(charset); - if (lang) - free(lang); + mh_xfree(charset); + mh_xfree(lang); return NOTOK; case '"': break; @@ -3496,7 +3475,7 @@ bad_quote: case '\\': if (*++cp == '\0') goto bad_quote; - /* FALL THROUGH */ + /* FALLTHRU */ default: len++; continue; @@ -3540,13 +3519,15 @@ bad_quote: if (partial) { for (pp = phead; pp != NULL; pp = pp->next) { - if (strcasecmp(nameptr, pp->name) == 0) + if (strcasecmp(nameptr, pp->name) == 0) { + free (nameptr); + nameptr = pp->name; break; + } } if (pp == NULL) { - pp = mh_xmalloc(sizeof(*pp)); - memset(pp, 0, sizeof(*pp)); + NEW0(pp); pp->name = nameptr; pp->next = phead; phead = pp; @@ -3556,8 +3537,7 @@ bad_quote: * Insert this into the section linked list */ - sp = mh_xmalloc(sizeof(*sp)); - memset(sp, 0, sizeof(*sp)); + NEW0(sp); sp->value = valptr; sp->index = index; sp->len = len; @@ -3568,11 +3548,9 @@ bad_quote: } 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, "", - nameptr); - free (nameptr); + inform("duplicate index (%d) in message %s's %s: field" + "\n (parameter %s)", sp->index, filename, + fieldname, nameptr); return NOTOK; } if (sp2->index < sp->index && @@ -3584,11 +3562,9 @@ bad_quote: } 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); - free (nameptr); + inform("Internal error: cannot insert partial param " + "in message %s's %s: field\n (parameter %s)", + filename, fieldname, nameptr); return NOTOK; } } @@ -3598,11 +3574,9 @@ bad_quote: */ if (index == 0 && encoded) { - if (pp->charset) - free(pp->charset); + mh_xfree(pp->charset); pp->charset = charset; - if (pp->lang) - free(pp->lang); + mh_xfree(pp->lang); pp->lang = lang; } } else { @@ -3630,10 +3604,9 @@ bad_quote: 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); + inform("missing section %d for parameter in message " + "%s's %s: field\n (parameter %s)", pindex - 1, + filename, fieldname, pp->name); return NOTOK; } tlen += sp->len; @@ -3673,7 +3646,7 @@ content_charset (CT ct) { ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0); - return ret_charset ? ret_charset : getcpy ("US-ASCII"); + return ret_charset ? ret_charset : mh_xstrdup("US-ASCII"); } @@ -3701,9 +3674,8 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external) continue; if (strlen(params->pm_name) > CPERLIN) { - advise(NULL, "Parameter name \"%s\" is too long", params->pm_name); - if (paramout) - free(paramout); + inform("Parameter name \"%s\" is too long", params->pm_name); + mh_xfree(paramout); return NULL; } @@ -3740,8 +3712,7 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external) numchars, valoff); if (i == 0) { - if (paramout) - free(paramout); + mh_xfree(paramout); return NULL; } @@ -3784,7 +3755,7 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external) } /* - * At this point, we're either finishing a contined parameter, or + * At this point, we're either finishing a continued parameter, or * we're working on a new one. */ @@ -3804,8 +3775,7 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external) strlen(params->pm_value + valoff), valoff); if (i == 0) { - if (paramout) - free(paramout); + mh_xfree(paramout); return NULL; } @@ -3904,13 +3874,13 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont, */ if (! pm->pm_charset) { - pm->pm_charset = getcpy(write_charset_8bit()); + pm->pm_charset = mh_xstrdup(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 */ + pm->pm_lang = mh_xstrdup(""); /* Default to a blank lang tag */ len++; /* For the encoding marker */ maxfit--; @@ -3954,7 +3924,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont, case '\\': len++; maxfit--; - /* FALL THROUGH */ + /* FALLTHRU */ default: len++; maxfit--; @@ -3981,7 +3951,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont, * Output an encoded parameter string. */ -static size_t +size_t encode_param(PM pm, char *output, size_t len, size_t valuelen, size_t valueoff, int index) { @@ -4008,7 +3978,7 @@ encode_param(PM pm, char *output, size_t len, size_t valuelen, output += n; outlen += n; if (output > endptr) { - advise(NULL, "Internal error: parameter buffer overflow"); + inform("Internal error: parameter buffer overflow"); return 0; } } @@ -4028,7 +3998,7 @@ encode_param(PM pm, char *output, size_t len, size_t valuelen, outlen++; } if (output > endptr) { - advise(NULL, "Internal error: parameter buffer overflow"); + inform("Internal error: parameter buffer overflow"); return 0; } } @@ -4062,18 +4032,19 @@ normal_param(PM pm, char *output, size_t len, size_t valuelen, case '"': *output++ = '\\'; outlen++; + /* FALLTHRU */ default: *output++ = *p++; outlen++; } if (output > endptr) { - advise(NULL, "Internal error: parameter buffer overflow"); + inform("Internal error: parameter buffer overflow"); return 0; } } if (output - 2 > endptr) { - advise(NULL, "Internal error: parameter buffer overflow"); + inform("Internal error: parameter buffer overflow"); return 0; } @@ -4090,10 +4061,9 @@ normal_param(PM pm, char *output, size_t len, size_t valuelen, PM 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; + NEW0(pm); pm->pm_name = nocopy ? name : getcpy(name); pm->pm_value = nocopy ? value : getcpy(value); @@ -4147,8 +4117,7 @@ get_param(PM first, const char *name, char replace, int fetchonly) if (strcasecmp(name, first->pm_name) == 0) { if (fetchonly) return first->pm_value; - else - return getcpy(get_param_value(first, replace)); + return getcpy(get_param_value(first, replace)); } first = first->pm_next; } @@ -4253,13 +4222,13 @@ noiconv: #endif /* HAVE_ICONV */ /* - * Take everything non-ASCII and substituite the replacement character + * Take everything non-ASCII and substitute the replacement character */ q = buffer; bufsize = sizeof(buffer); for (p = pm->pm_value; *p != '\0' && bufsize > 1; p++, q++, bufsize--) { - if (isascii((unsigned char) *p) && !iscntrl((unsigned char) *p)) + if (isascii((unsigned char) *p) && isprint((unsigned char) *p)) *q = *p; else *q = replace;