X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/09a5aa6a090a1c2b2b5d9518fbfd4b014cadc7ea..ec173fd2c:/uip/mhbuildsbr.c?ds=inline diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index fc90dc01..c7b969c7 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -1,6 +1,4 @@ - -/* - * mhbuildsbr.c -- routines to expand/translate MIME composition files +/* mhbuildsbr.c -- routines to expand/translate MIME composition files * * 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,14 +13,43 @@ * streamlining and removal of unneeded code. */ -#include +#include "h/mh.h" +#include "sbr/m_gmprot.h" +#include "sbr/m_getfld.h" +#include "sbr/concat.h" +#include "sbr/r1bindex.h" +#include "sbr/encode_rfc2047.h" +#include "sbr/copyip.h" +#include "sbr/cpydata.h" +#include "sbr/trimcpy.h" +#include "sbr/uprf.h" +#include "sbr/check_charset.h" +#include "sbr/getcpy.h" +#include "sbr/m_convert.h" +#include "sbr/getfolder.h" +#include "sbr/folder_read.h" +#include "sbr/folder_free.h" +#include "sbr/context_find.h" +#include "sbr/brkstring.h" +#include "sbr/pidstatus.h" +#include "sbr/path.h" +#include "sbr/error.h" #include -#include -#include -#include -#include -#include -#include +#include "h/md5.h" +#include "h/mts.h" +#include "h/tws.h" +#include "h/fmt_scan.h" +#include "h/mime.h" +#include "h/mhparse.h" +#include "h/done.h" +#include "h/utils.h" +#include "h/mhcachesbr.h" +#include "mhmisc.h" +#include "sbr/m_mktemp.h" +#include "sbr/message_id.h" +#include "sbr/mime_type.h" +#include "mhfree.h" +#include "mhshowsbr.h" #ifdef HAVE_SYS_TIME_H # include @@ -32,13 +59,9 @@ extern int debugsw; -extern int listsw; -extern int rfc934sw; -extern int contentidsw; - -/* cache policies */ -extern int rcachesw; /* mhcachesbr.c */ -extern int wcachesw; /* mhcachesbr.c */ +extern bool listsw; +extern bool rfc934sw; +extern bool contentidsw; static char prefix[] = "----- =_aaaaaaaaaa"; @@ -54,24 +77,6 @@ typedef struct convert_list { struct convert_list *next; } convert_list; -/* - * Maximum size of URL token in message/external-body - */ - -#define MAXURLTOKEN 40 - - -/* mhmisc.c */ -void content_error (char *, CT, char *, ...); - -/* mhcachesbr.c */ -int find_cache (CT, int, int *, char *, char *, int); - -/* mhfree.c */ -extern CT *cts; -void freects_done (int) NORETURN; -void free_ctinfo (CT); -void free_encoding (CT, int); /* * static prototypes @@ -97,12 +102,14 @@ static int extract_headers (CT, char *, FILE **); static unsigned char directives_stack[32]; static unsigned int directives_index; -static int do_direct(void) +static int +do_direct(void) { return directives_stack[directives_index]; } -static void directive_onoff(int onoff) +static void +directive_onoff(int onoff) { if (directives_index >= sizeof(directives_stack) - 1) { fprintf(stderr, "mhbuild: #on/off overflow, continuing\n"); @@ -111,13 +118,15 @@ static void directive_onoff(int onoff) directives_stack[++directives_index] = onoff; } -static void directive_init(int onoff) +static void +directive_init(int onoff) { directives_index = 0; directives_stack[0] = onoff; } -static void directive_pop(void) +static void +directive_pop(void) { if (directives_index > 0) directives_index--; @@ -139,14 +148,14 @@ build_mime (char *infile, int autobuild, int dist, int directives, int header_encoding, size_t maxunencoded, int verbose) { int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; + char buf[NMH_BUFSIZ], name[NAMESZ]; char *cp, *np, *vp; struct multipart *m; struct part **pp; CT ct; FILE *in; HF hp; - m_getfld_state_t gstate = 0; + m_getfld_state_t gstate; struct attach_list *attach_head = NULL, *attach_tail = NULL, *at_entry; convert_list *convert_head = NULL, *convert_tail = NULL, *convert; @@ -175,10 +184,11 @@ build_mime (char *infile, int autobuild, int dist, int directives, * draft into the linked list of header fields for * the new MIME message. */ - 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++; @@ -191,26 +201,26 @@ build_mime (char *infile, int autobuild, int dist, int directives, free (ct); return NULL; } - adios (NULL, "draft shouldn't contain %s: field", name); + die("draft shouldn't contain %s: field", name); } /* ignore any Content-Type fields in the header */ if (!strcasecmp (name, TYPE_FIELD)) { while (state == FLDPLUS) { bufsz = sizeof buf; - state = m_getfld (&gstate, name, buf, &bufsz, in); + state = m_getfld2(&gstate, name, buf, &bufsz); } goto finish_field; } /* 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 */ } @@ -254,14 +264,14 @@ build_mime (char *infile, int autobuild, int dist, int directives, attach_head = attach_tail = entry; } } else if (strncasecmp(MHBUILD_FILE_PSEUDOHEADER, np, - strlen (MHBUILD_FILE_PSEUDOHEADER)) == 0) { + LEN(MHBUILD_FILE_PSEUDOHEADER)) == 0) { /* E.g., * Nmh-mhbuild-file-text/calendar: /home/user/Mail/inbox/9 */ - char *type = np + strlen (MHBUILD_FILE_PSEUDOHEADER); + char *type = np + LEN(MHBUILD_FILE_PSEUDOHEADER); char *filename = vp; - /* vp should begin with a space because m_getfld() + /* vp should begin with a space because m_getfld2() includes the space after the colon in buf. */ while (isspace((unsigned char) *filename)) { ++filename; } /* Trim trailing newline and any other whitespace. */ @@ -273,7 +283,7 @@ build_mime (char *infile, int autobuild, int dist, int directives, if (convert) { if (convert->filename && strcasecmp (convert->filename, filename)) { - adios (NULL, "Multiple %s headers with different files" + die("Multiple %s headers with different files" " not allowed", type); } else { convert->filename = mh_xstrdup(filename); @@ -294,14 +304,14 @@ build_mime (char *infile, int autobuild, int dist, int directives, free (vp); free (np); } else if (strncasecmp(MHBUILD_ARGS_PSEUDOHEADER, np, - strlen (MHBUILD_ARGS_PSEUDOHEADER)) == 0) { + LEN(MHBUILD_ARGS_PSEUDOHEADER)) == 0) { /* E.g., * Nmh-mhbuild-args-text/calendar: -reply accept */ - char *type = np + strlen (MHBUILD_ARGS_PSEUDOHEADER); + char *type = np + LEN(MHBUILD_ARGS_PSEUDOHEADER); char *argstring = vp; - /* vp should begin with a space because m_getfld() + /* vp should begin with a space because m_getfld2() includes the space after the colon in buf. */ while (isspace((unsigned char) *argstring)) { ++argstring; } /* Trim trailing newline and any other whitespace. */ @@ -313,7 +323,7 @@ build_mime (char *infile, int autobuild, int dist, int directives, if (convert) { if (convert->argstring && strcasecmp (convert->argstring, argstring)) { - adios (NULL, "Multiple %s headers with different " + die("Multiple %s headers with different " "argstrings not allowed", type); } else { convert->argstring = mh_xstrdup(argstring); @@ -343,16 +353,16 @@ finish_field: case BODY: fseek (in, (long) (-strlen (buf)), SEEK_CUR); - /* fall through */ + break; case FILEEOF: break; case LENERR: case FMTERR: - adios (NULL, "message format error in component #%d", compnum); + die("message format error in component #%d", compnum); default: - adios (NULL, "getfld() returned %d", state); + die("getfld() returned %d", state); } break; } @@ -366,7 +376,7 @@ finish_field: for (hp = ct->c_first_hf; hp != NULL; hp = hp->next) { if (encode_rfc2047(hp->name, &hp->value, header_encoding, NULL)) { - adios(NULL, "Unable to encode header \"%s\"", hp->name); + die("Unable to encode header \"%s\"", hp->name); } } } @@ -377,13 +387,13 @@ finish_field: */ if (! dist) { - np = add (VRSN_FIELD, NULL); + np = mh_xstrdup(VRSN_FIELD); vp = concat (" ", VRSN_VALUE, "\n", NULL); add_header (ct, np, vp); } /* - * We initally assume we will find multiple contents in the + * We initially assume we will find multiple contents in the * draft. So create a multipart/mixed content to hold everything. * We can remove this later, if it is not needed. */ @@ -405,7 +415,7 @@ finish_field: CT p; if (user_content (in, buf, &p, infile) == DONE) { - admonish (NULL, "ignoring spurious #end"); + inform("ignoring spurious #end, continuing..."); continue; } if (!p) @@ -460,7 +470,7 @@ finish_field: CT *ctp; convert_list *next; - done = freects_done; + set_done(freects_done); /* In case there are multiple calls that land here, prevent leak. */ for (ctp = cts; ctp && *ctp; ++ctp) { free_content (*ctp); } @@ -469,7 +479,7 @@ finish_field: /* Extract the type part (as a CT) from filename. */ cts = mh_xcalloc(2, sizeof *cts); if (! (cts[0] = parse_mime (convert_head->filename))) { - adios (NULL, "failed to parse %s", convert_head->filename); + die("failed to parse %s", convert_head->filename); } expand_pseudoheaders (cts[0], m, infile, convert_head); @@ -557,7 +567,7 @@ finish_field: compose_content (ct, verbose); if ((cp = strchr(prefix, 'a')) == NULL) - adios (NULL, "internal error(4)"); + die("internal error(4)"); /* * If using EAI, force 8-bit charset. @@ -576,9 +586,8 @@ finish_field: (*cp)++; } else { if (*++cp == 0) - adios (NULL, "giving up trying to find a unique delimiter string"); - else - (*cp)++; + die("giving up trying to find a unique delimiter string"); + (*cp)++; } } @@ -602,7 +611,7 @@ init_decoded_content (CT ct, const char *filename) ct->c_ceclosefnx = close_encoding; ct->c_cesizefnx = NULL; /* since unencoded */ ct->c_encoding = CE_7BIT; /* Seems like a reasonable default */ - ct->c_file = add(filename, NULL); + ct->c_file = mh_xstrdup(FENDNULL(filename)); return OK; } @@ -612,23 +621,26 @@ static char * fgetstr (char *s, int n, FILE *stream) { char *cp, *ep; - int o_n = n; + ep = s + n; while(1) { - for (ep = (cp = s) + o_n; cp < ep; ) { - int i; + for (cp = s; cp < ep;) { + int len; if (!fgets (cp, n, stream)) - return (cp != s ? s : NULL); + return cp == s ? NULL : s; /* "\\\nEOF" ignored. */ - if (cp == s && *cp != '#') - return s; + if (! do_direct() || (cp == s && *cp != '#')) + return s; /* Plaintext line. */ - cp += (i = strlen (cp)) - 1; - if (i <= 1 || *cp-- != '\n' || *cp != '\\') + len = strlen(cp); + if (len <= 1) + break; /* Can't contain "\\\n". */ + cp += len - 1; /* Just before NUL. */ + if (*cp-- != '\n' || *cp != '\\') break; - *cp = '\0'; - n -= (i - 2); + *cp = '\0'; /* Erase the trailing "\\\n". */ + n -= (len - 2); } if (strcmp(s, "#on\n") == 0) { @@ -638,11 +650,9 @@ fgetstr (char *s, int n, FILE *stream) } else if (strcmp(s, "#pop\n") == 0) { directive_pop(); } else { - break; + return s; } } - - return s; } @@ -656,7 +666,7 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename) { int extrnal, vrsn; char *cp, **ap; - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; struct multipart *m; struct part **pp; struct stat st; @@ -691,7 +701,7 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename) */ if (!do_direct() || buf[0] != '#' || buf[1] == '#' || buf[1] == '<') { int headers; - int inlineD; + bool inlineD; long pos; char content[BUFSIZ]; FILE *out; @@ -703,15 +713,15 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename) } /* use a temp file to collect the plain text lines */ - ce->ce_file = add (cp, NULL); + ce->ce_file = mh_xstrdup(cp); ce->ce_unlink = 1; if (do_direct() && (buf[0] == '#' && buf[1] == '<')) { strncpy (content, buf + 2, sizeof(content)); - inlineD = 1; + inlineD = true; goto rock_and_roll; } - inlineD = 0; + inlineD = false; /* the directive is implicit */ strncpy (content, "text/plain", sizeof(content)); @@ -721,13 +731,13 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename) int i; if (headers >= 0 && do_direct() && uprf (buffer, DESCR_FIELD) - && buffer[i = strlen (DESCR_FIELD)] == ':') { + && buffer[i = LEN(DESCR_FIELD)] == ':') { headers = 1; again_descr: ct->c_descr = add (buffer + i + 1, ct->c_descr); if (!fgetstr (buffer, sizeof(buffer) - 1, in)) - adios (NULL, "end-of-file after %s: field in plaintext", DESCR_FIELD); + die("end-of-file after %s: field in plaintext", DESCR_FIELD); switch (buffer[0]) { case ' ': case '\t': @@ -735,7 +745,7 @@ again_descr: goto again_descr; case '#': - adios (NULL, "#-directive after %s: field in plaintext", DESCR_FIELD); + die("#-directive after %s: field in plaintext", DESCR_FIELD); /* NOTREACHED */ default: @@ -744,13 +754,13 @@ again_descr: } if (headers >= 0 && do_direct() && uprf (buffer, DISPO_FIELD) - && buffer[i = strlen (DISPO_FIELD)] == ':') { + && buffer[i = LEN(DISPO_FIELD)] == ':') { headers = 1; again_dispo: ct->c_dispo = add (buffer + i + 1, ct->c_dispo); if (!fgetstr (buffer, sizeof(buffer) - 1, in)) - adios (NULL, "end-of-file after %s: field in plaintext", DISPO_FIELD); + die("end-of-file after %s: field in plaintext", DISPO_FIELD); switch (buffer[0]) { case ' ': case '\t': @@ -758,7 +768,7 @@ again_dispo: goto again_dispo; case '#': - adios (NULL, "#-directive after %s: field in plaintext", DISPO_FIELD); + die("#-directive after %s: field in plaintext", DISPO_FIELD); /* NOTREACHED */ default: @@ -808,9 +818,9 @@ rock_and_roll: ct->c_encoding = CE_7BIT; goto call_init; } - /* else fall... */ + /* FALLTHRU */ case CT_MULTIPART: - adios (NULL, "it doesn't make sense to define an in-line %s content", + die("it doesn't make sense to define an in-line %s content", ct->c_type == CT_MESSAGE ? "message" : "multipart"); /* NOTREACHED */ @@ -852,24 +862,23 @@ call_init: */ if (s2i->si_key) { if (!ci->ci_subtype) - adios (NULL, "missing subtype in \"#%s\"", ci->ci_type); + die("missing subtype in \"#%s\"", ci->ci_type); switch (ct->c_type = s2i->si_val) { case CT_MULTIPART: - adios (NULL, "use \"#begin ... #end\" instead of \"#%s/%s\"", + die("use \"#begin ... #end\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); /* NOTREACHED */ case CT_MESSAGE: if (!strcasecmp (ci->ci_subtype, "partial")) - adios (NULL, "sorry, \"#%s/%s\" isn't supported", + die("sorry, \"#%s/%s\" isn't supported", ci->ci_type, ci->ci_subtype); if (!strcasecmp (ci->ci_subtype, "external-body")) - adios (NULL, "use \"#@type/subtype ... [] ...\" instead of \"#%s/%s\"", + die("use \"#@type/subtype ... [] ...\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); use_forw: - adios (NULL, - "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", + die( "use \"#forw [+folder] [msgs]\" instead of \"#%s/%s\"", ci->ci_type, ci->ci_subtype); /* NOTREACHED */ @@ -887,7 +896,7 @@ use_forw: CT p; if (!ci->ci_magic) - adios (NULL, "need external information for \"#@%s/%s\"", + die("need external information for \"#@%s/%s\"", ci->ci_type, ci->ci_subtype); p = ct; @@ -929,8 +938,8 @@ use_forw: for (cp = ci->ci_magic + 1; isspace ((unsigned char) *cp); cp++) continue; if (!*cp) - adios (NULL, "empty pipe command for #%s directive", ci->ci_type); - cp = add (cp, NULL); + die("empty pipe command for #%s directive", ci->ci_type); + cp = mh_xstrdup(cp); free (ci->ci_magic); ci->ci_magic = cp; } else { @@ -954,12 +963,12 @@ use_forw: content_error (NULL, ct, "don't know how to compose content"); done (1); } - ci->ci_magic = add (cp, NULL); + ci->ci_magic = mh_xstrdup(cp); return OK; } if (extrnal) - adios (NULL, "external definition not allowed for \"#%s\"", ci->ci_type); + die("external definition not allowed for \"#%s\"", ci->ci_type); /* * Message directive @@ -984,18 +993,17 @@ use_forw: cp = *ap; if (*cp == '+' || *cp == '@') { if (folder) - adios (NULL, "only one folder per #forw directive"); - else - folder = pluspath (cp); + die("only one folder per #forw directive"); + folder = pluspath (cp); } } /* else, use the current folder */ if (!folder) - folder = add (getfolder (1), NULL); + folder = mh_xstrdup(getfolder(1)); if (!(mp = folder_read (folder, 0))) - adios (NULL, "unable to read folder %s", folder); + die("unable to read folder %s", folder); for (ap = arguments; *ap; ap++) { cp = *ap; if (*cp != '+' && *cp != '@') @@ -1037,7 +1045,7 @@ use_forw: p->c_subtype = MESSAGE_RFC822; snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - pe->ce_file = add (buffer, NULL); + pe->ce_file = mh_xstrdup(buffer); if (listsw && stat (pe->ce_file, &st) != NOTOK) p->c_end = (long) st.st_size; @@ -1056,7 +1064,7 @@ use_forw: msgnum = mp->lowsel; snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum); - ce->ce_file = add (buffer, NULL); + ce->ce_file = mh_xstrdup(buffer); if (listsw && stat (ce->ce_file, &st) != NOTOK) ct->c_end = (long) st.st_size; } @@ -1111,7 +1119,7 @@ use_forw: if (user_content (in, buffer, &p, infilename) == DONE) { if (!m->mp_parts) - adios (NULL, "empty \"#begin ... #end\" sequence"); + die("empty \"#begin ... #end\" sequence"); return OK; } if (!p) @@ -1122,14 +1130,14 @@ use_forw: pp = &part->mp_next; part->mp_part = p; } - admonish (NULL, "premature end-of-file, missing #end"); + inform("premature end-of-file, missing #end, continuing..."); return OK; } /* * Unknown directive */ - adios (NULL, "unknown directive \"#%s\"", ci->ci_type); + die("unknown directive \"#%s\"", ci->ci_type); return NOTOK; /* NOT REACHED */ } @@ -1185,7 +1193,7 @@ compose_content (CT ct, int verbose) CT p = part->mp_part; sprintf (pp, "%d", partnum); - p->c_partno = add (partnam, NULL); + p->c_partno = mh_xstrdup(partnam); if (compose_content (p, verbose) == NOTOK) return NOTOK; } @@ -1197,13 +1205,13 @@ compose_content (CT ct, int verbose) * subparts with the rfc934 compatibility mode flag. */ if (rfc934sw && ct->c_subtype == MULTI_DIGEST) { - int is934 = 1; + bool is934 = true; for (part = m->mp_parts; part; part = part->mp_next) { CT p = part->mp_part; if (p->c_subtype != MESSAGE_RFC822) { - is934 = 0; + is934 = false; break; } } @@ -1219,7 +1227,7 @@ compose_content (CT ct, int verbose) if (listsw) { ct->c_end = (partnum = strlen (prefix) + 2) + 2; if (ct->c_rfc934) - ct->c_end += 1; + ct->c_end++; for (part = m->mp_parts; part; part = part->mp_next) ct->c_end += part->mp_part->c_end + partnum; @@ -1237,7 +1245,8 @@ compose_content (CT ct, int verbose) default: if (!ce->ce_file) { pid_t child_id; - int i, xstdout, len, buflen; + bool xstdout; + int len, buflen; char *bp, *cp; char *vec[4], buffer[BUFSIZ]; FILE *out; @@ -1245,16 +1254,16 @@ compose_content (CT ct, int verbose) char *tfile = NULL; if (!(cp = ci->ci_magic)) - adios (NULL, "internal error(5)"); + die("internal error(5)"); if ((tfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { adios("mhbuildsbr", "unable to create temporary file in %s", get_temp_dir()); } - ce->ce_file = add (tfile, NULL); + ce->ce_file = mh_xstrdup(tfile); ce->ce_unlink = 1; - xstdout = 0; + xstdout = false; /* Get buffer ready to go */ bp = buffer; @@ -1286,8 +1295,8 @@ compose_content (CT ct, int verbose) case 'F': /* %f, and stdout is not-redirected */ - xstdout = 1; - /* and fall... */ + xstdout = true; + /* FALLTHRU */ case 'f': /* @@ -1337,8 +1346,7 @@ raw: if ((out = fopen (ce->ce_file, "w")) == NULL) adios (ce->ce_file, "unable to open for writing"); - for (i = 0; (child_id = fork()) == NOTOK && i > 5; i++) - sleep (5); + child_id = fork(); switch (child_id) { case NOTOK: adios ("fork", "unable to fork"); @@ -1351,7 +1359,7 @@ raw: execvp ("/bin/sh", vec); fprintf (stderr, "unable to exec "); perror ("/bin/sh"); - _exit (-1); + _exit(1); /* NOTREACHED */ default: @@ -1393,12 +1401,12 @@ static int scan_content (CT ct, size_t maxunencoded) { int prefix_len; - int check8bit = 0, contains8bit = 0; /* check if contains 8bit data */ - int checknul = 0, containsnul = 0; /* check if contains NULs */ - int checklinelen = 0, linelen = 0; /* check for long lines */ - int checkllinelen = 0; /* check for extra-long lines */ - int checkboundary = 0, boundaryclash = 0; /* check if clashes with multipart boundary */ - int checklinespace = 0, linespace = 0; /* check if any line ends with space */ + bool check8bit = false, contains8bit = false; /* check if contains 8bit data */ + bool checknul = false, containsnul = false; /* check if contains NULs */ + bool checklinelen = false, linelen = false; /* check for long lines */ + bool checkllinelen = false; /* check for extra-long lines */ + bool checkboundary = false, boundaryclash = false; /* check if clashes with multipart boundary */ + bool checklinespace = false, linespace = false; /* check if any line ends with space */ char *cp = NULL; char *bufp = NULL; size_t buflen; @@ -1446,18 +1454,18 @@ scan_content (CT ct, size_t maxunencoded) if (ct->c_type == CT_TEXT) { t = (struct text *) ct->c_ctparams; if (t->tx_charset == CHARSET_UNSPECIFIED) { - checknul = 1; + checknul = true; } - check8bit = 1; + check8bit = true; } switch (ct->c_reqencoding) { case CE_8BIT: - checkllinelen = 1; - checkboundary = 1; + checkllinelen = true; + checkboundary = true; break; case CE_QUOTED: - checkboundary = 1; + checkboundary = true; break; case CE_BASE64: break; @@ -1465,34 +1473,34 @@ scan_content (CT ct, size_t maxunencoded) /* Use the default rules based on content-type */ switch (ct->c_type) { case CT_TEXT: - checkboundary = 1; - checklinelen = 1; + checkboundary = true; + checklinelen = true; if (ct->c_subtype == TEXT_PLAIN) { - checklinespace = 0; + checklinespace = false; } else { - checklinespace = 1; + checklinespace = true; } break; case CT_APPLICATION: - check8bit = 1; - checknul = 1; - checklinelen = 1; - checklinespace = 1; - checkboundary = 1; + check8bit = true; + checknul = true; + checklinelen = true; + checklinespace = true; + checkboundary = true; break; case CT_MESSAGE: - checklinelen = 0; - checklinespace = 0; + checklinelen = false; + checklinespace = false; /* don't check anything for message/external */ if (ct->c_subtype == MESSAGE_EXTERNAL) { - checkboundary = 0; - check8bit = 0; + checkboundary = false; + check8bit = false; } else { - checkboundary = 1; - check8bit = 1; + checkboundary = true; + check8bit = true; } break; @@ -1504,10 +1512,10 @@ scan_content (CT ct, size_t maxunencoded) * since we are forcing use of base64, unless * the content-type was specified by a mhbuild directive. */ - check8bit = 0; - checklinelen = 0; - checklinespace = 0; - checkboundary = 0; + check8bit = false; + checklinelen = false; + checklinespace = false; + checkboundary = false; break; } } @@ -1528,12 +1536,12 @@ scan_content (CT ct, size_t maxunencoded) for (cp = bufp; (check8bit || checknul) && cp < bufp + gotlen; cp++) { if (!isascii ((unsigned char) *cp)) { - contains8bit = 1; - check8bit = 0; /* no need to keep checking */ + contains8bit = true; + check8bit = false; /* no need to keep checking */ } if (!*cp) { - containsnul = 1; - checknul = 0; /* no need to keep checking */ + containsnul = true; + checknul = false; /* no need to keep checking */ } } @@ -1541,8 +1549,8 @@ scan_content (CT ct, size_t maxunencoded) * Check line length. */ if (checklinelen && ((size_t)gotlen > maxunencoded + 1)) { - linelen = 1; - checklinelen = 0; /* no need to keep checking */ + linelen = true; + checklinelen = false; /* no need to keep checking */ } /* @@ -1553,7 +1561,7 @@ scan_content (CT ct, size_t maxunencoded) if (checkllinelen && !linelen && (gotlen > MAXLONGLINE + 1)) { - adios(NULL, "Line in content exceeds maximum line limit (%d)", + die("Line in content exceeds maximum line limit (%d)", MAXLONGLINE); } @@ -1562,8 +1570,8 @@ scan_content (CT ct, size_t maxunencoded) */ if (checklinespace && (cp = bufp + gotlen - 2) > bufp && isspace ((unsigned char) *cp)) { - linespace = 1; - checklinespace = 0; /* no need to keep checking */ + linespace = true; + checklinespace = false; /* no need to keep checking */ } /* @@ -1577,8 +1585,8 @@ scan_content (CT ct, size_t maxunencoded) *++cp = '\0'; if (!strncmp(bufp + 2, prefix, prefix_len) && isdigit((unsigned char) bufp[2 + prefix_len])) { - boundaryclash = 1; - checkboundary = 0; /* no need to keep checking */ + boundaryclash = true; + checkboundary = false; /* no need to keep checking */ } } } @@ -1637,7 +1645,7 @@ scan_content (CT ct, size_t maxunencoded) } } - return (boundaryclash ? NOTOK : OK); + return boundaryclash ? NOTOK : OK; } @@ -1678,11 +1686,11 @@ build_headers (CT ct, int header_encoding) /* * output the content type and subtype */ - np = add (TYPE_FIELD, NULL); + np = mh_xstrdup(TYPE_FIELD); vp = concat (" ", ci->ci_type, "/", ci->ci_subtype, NULL); /* keep track of length of line */ - len = strlen (TYPE_FIELD) + strlen (ci->ci_type) + len = LEN(TYPE_FIELD) + strlen (ci->ci_type) + strlen (ci->ci_subtype) + 3; extbody = ct->c_type == CT_MESSAGE && ct->c_subtype == MESSAGE_EXTERNAL; @@ -1697,7 +1705,7 @@ build_headers (CT ct, int header_encoding) char *s = output_params(len, ci->ci_first_pm, &len, mailbody); if (!s) - adios(NULL, "Internal error: failed outputting Content-Type " + die("Internal error: failed outputting Content-Type " "parameters"); vp = add (s, vp); @@ -1724,10 +1732,12 @@ build_headers (CT ct, int header_encoding) add_header (ct, np, vp); /* - * output the Content-ID, unless disabled by -nocontentid + * output the Content-ID, unless disabled by -nocontentid. Note that + * RFC 2045 always requires a Content-ID header for message/external-body + * entities. */ - if (contentidsw && ct->c_id) { - np = add (ID_FIELD, NULL); + if ((contentidsw || ct->c_ctexbody) && ct->c_id) { + np = mh_xstrdup(ID_FIELD); vp = concat (" ", ct->c_id, NULL); add_header (ct, np, vp); } @@ -1735,11 +1745,11 @@ build_headers (CT ct, int header_encoding) * output the Content-Description */ if (ct->c_descr) { - np = add (DESCR_FIELD, NULL); + np = mh_xstrdup(DESCR_FIELD); vp = concat (" ", ct->c_descr, NULL); if (header_encoding != CE_8BIT) { if (encode_rfc2047(DESCR_FIELD, &vp, header_encoding, NULL)) { - adios(NULL, "Unable to encode %s header", DESCR_FIELD); + die("Unable to encode %s header", DESCR_FIELD); } } add_header (ct, np, vp); @@ -1750,16 +1760,16 @@ build_headers (CT ct, int header_encoding) * set, then we need to build it. */ if (ct->c_dispo) { - np = add (DISPO_FIELD, NULL); + np = mh_xstrdup(DISPO_FIELD); vp = concat (" ", ct->c_dispo, NULL); add_header (ct, np, vp); } else if (ct->c_dispo_type) { vp = concat (" ", ct->c_dispo_type, NULL); - len = strlen(DISPO_FIELD) + strlen(vp) + 1; + len = LEN(DISPO_FIELD) + strlen(vp) + 1; np = output_params(len, ct->c_dispo_first, NULL, 0); vp = add(np, vp); vp = add("\n", vp); - mh_xfree(np); + free(np); add_header (ct, mh_xstrdup(DISPO_FIELD), vp); } @@ -1776,8 +1786,8 @@ skip_headers: * output the Content-MD5 */ if (checksw) { - np = add (MD5_FIELD, NULL); - vp = calculate_digest (ct, (ct->c_encoding == CE_QUOTED) ? 1 : 0); + np = mh_xstrdup(MD5_FIELD); + vp = calculate_digest (ct, ct->c_encoding == CE_QUOTED); add_header (ct, np, vp); } @@ -1795,40 +1805,40 @@ skip_headers: break; case CE_8BIT: - np = add (ENCODING_FIELD, NULL); + np = mh_xstrdup(ENCODING_FIELD); vp = concat (" ", "8bit", "\n", NULL); add_header (ct, np, vp); break; case CE_QUOTED: if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios (NULL, "internal error, invalid encoding"); + die("internal error, invalid encoding"); - np = add (ENCODING_FIELD, NULL); + np = mh_xstrdup(ENCODING_FIELD); vp = concat (" ", "quoted-printable", "\n", NULL); add_header (ct, np, vp); break; case CE_BASE64: if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART) - adios (NULL, "internal error, invalid encoding"); + die("internal error, invalid encoding"); - np = add (ENCODING_FIELD, NULL); + np = mh_xstrdup(ENCODING_FIELD); vp = concat (" ", "base64", "\n", NULL); add_header (ct, np, vp); break; case CE_BINARY: if (ct->c_type == CT_MESSAGE) - adios (NULL, "internal error, invalid encoding"); + die("internal error, invalid encoding"); - np = add (ENCODING_FIELD, NULL); + np = mh_xstrdup(ENCODING_FIELD); vp = concat (" ", "binary", "\n", NULL); add_header (ct, np, vp); break; default: - adios (NULL, "unknown transfer encoding in content"); + die("unknown transfer encoding in content"); break; } @@ -1927,7 +1937,7 @@ calculate_digest (CT ct, int asciiP) unsigned char *ep; fprintf (stderr, "MD5 digest="); - for (ep = (dp = digest) + sizeof(digest) / sizeof(digest[0]); + for (ep = (dp = digest) + sizeof digest; dp < ep; dp++) fprintf (stderr, "%02x", *dp & 0xff); fprintf (stderr, "\n"); @@ -1935,7 +1945,7 @@ calculate_digest (CT ct, int asciiP) /* encode the digest using base64 */ for (dp = digest, op = (char *) outbuf, - cc = sizeof(digest) / sizeof(digest[0]); + cc = sizeof digest; cc > 0; cc -= 3, op += 4) { unsigned long bits; char *bp; @@ -1977,12 +1987,12 @@ setup_attach_content(CT ct, char *filename) PM pm; if (! (type = mime_type(filename))) { - adios(NULL, "Unable to determine MIME type of \"%s\"", filename); + die("Unable to determine MIME type of \"%s\"", filename); } /* * Parse the Content-Type. get_ctinfo() parses MIME parameters, but - * since we're just feeding it a MIME type we have to add those ourself. + * since we're just feeding it a MIME type we have to add those ourselves. * Map that to a valid content-type label and call any initialization * function. */ @@ -2004,17 +2014,17 @@ setup_attach_content(CT ct, char *filename) switch (ct->c_type = s2i->si_val) { case CT_MULTIPART: - adios (NULL, "multipart types must be specified by mhbuild directives"); + die("multipart types must be specified by mhbuild directives"); /* NOTREACHED */ case CT_MESSAGE: if (strcasecmp(ct->c_ctinfo.ci_subtype, "partial") == 0) - adios(NULL, "Sorry, %s/%s isn't supported", ct->c_ctinfo.ci_type, + die("Sorry, %s/%s isn't supported", ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype); if (strcasecmp(ct->c_ctinfo.ci_subtype, "external-body") == 0) - adios(NULL, "external-body messages must be specified " + die("external-body messages must be specified " "by mhbuild directives"); - /* Fall through */ + /* FALLTHRU */ default: /* @@ -2032,7 +2042,7 @@ setup_attach_content(CT ct, char *filename) for (pm = ct->c_ctinfo.ci_first_pm; pm; pm = pm->pm_next) { if (strcasecmp(pm->pm_name, "name") == 0) { - mh_xfree(pm->pm_value); + free(pm->pm_value); pm->pm_value = mh_xstrdup(simplename); break; } @@ -2059,20 +2069,21 @@ setup_attach_content(CT ct, char *filename) * 'attachment'. */ void -set_disposition (CT ct) { +set_disposition (CT ct) +{ if (ct->c_dispo_type == NULL) { char *cp = context_find_by_type ("disposition", ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype); if (cp && strcasecmp (cp, "attachment") && strcasecmp (cp, "inline")) { - admonish (NULL, "configuration problem: %s-disposition-%s%s%s " - "specifies '%s' but only 'attachment' and 'inline' are " - "allowed", invo_name, - ct->c_ctinfo.ci_type, - ct->c_ctinfo.ci_subtype ? "/" : "", - ct->c_ctinfo.ci_subtype ? ct->c_ctinfo.ci_subtype : "", - cp); + inform("configuration problem: %s-disposition-%s%s%s specifies " + "'%s' but only 'attachment' and 'inline' are allowed, " + "continuing...", invo_name, + ct->c_ctinfo.ci_type, + ct->c_ctinfo.ci_subtype ? "/" : "", + FENDNULL(ct->c_ctinfo.ci_subtype), + cp); } if (!cp) @@ -2083,13 +2094,14 @@ set_disposition (CT ct) { /* * Set text content charset if it was unspecified. contains8bit - * selctions: + * selections: * 0: content does not contain 8-bit characters * 1: content contains 8-bit characters * -1: ignore content and use user's locale to determine charset */ void -set_charset (CT ct, int contains8bit) { +set_charset (CT ct, int contains8bit) +{ if (ct->c_type == CT_TEXT) { struct text *t; @@ -2108,7 +2120,7 @@ set_charset (CT ct, int contains8bit) { if (contains8bit == 1 && strcasecmp (eightbitcharset, "US-ASCII") == 0) { - adios (NULL, "Text content contains 8 bit characters, but " + die("Text content contains 8 bit characters, but " "character set is US-ASCII"); } @@ -2128,7 +2140,8 @@ set_charset (CT ct, int contains8bit) { */ void expand_pseudoheaders (CT ct, struct multipart *m, const char *infile, - const convert_list *convert_head) { + const convert_list *convert_head) +{ /* text_plain_ct is used to concatenate all of the text/plain replies into one part, instead of having each one in a separate part. */ @@ -2140,7 +2153,7 @@ expand_pseudoheaders (CT ct, struct multipart *m, const char *infile, struct part *part; if (ct->c_subtype == MULTI_ALTERNATE) { - int matched = 0; + bool matched = false; /* The parts are in descending priority order (defined by RFC 2046 Sec. 5.1.4) because they were reversed by @@ -2163,7 +2176,7 @@ expand_pseudoheaders (CT ct, struct multipart *m, const char *infile, expand_pseudoheader (part->mp_part, &text_plain_ct, m, infile, c->type, c->argstring); - matched = 1; + matched = true; break; } } @@ -2204,7 +2217,8 @@ expand_pseudoheaders (CT ct, struct multipart *m, const char *infile, void expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, const char *infile, const char *type, - const char *argstring) { + const char *argstring) +{ char *reply_file; FILE *reply_fp = NULL; char *convert, *type_p, *subtype_p; @@ -2214,7 +2228,6 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, struct str2init *s2i; CT reply_ct; struct part *part; - int eightbit = 0; int status; type_p = getcpy (type); @@ -2229,15 +2242,13 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, free (type_p); if (! (convert)) { - /* No mhbuild-convert- entry in mhn.defaults or profile - for type. */ + /* No mhbuild-convert- entry in mhn.defaults or profile for type. */ return; } /* reply_file is used to pass the output of the convert. */ reply_file = getcpy (m_mktemp2 (NULL, invo_name, NULL, NULL)); convert_command = - concat (convert, " ", argstring ? argstring : "", " >", reply_file, - NULL); + concat (convert, " ", FENDNULL(argstring), " >", reply_file, NULL); /* Convert here . . . */ ct->c_storeproc = mh_xstrdup(convert_command); @@ -2245,7 +2256,7 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, if ((status = show_content_aux (ct, 0, convert_command, NULL, NULL)) != OK) { - admonish (NULL, "store of %s content failed", type); + inform("store of %s content failed, continuing...", type); } free (convert_command); @@ -2254,26 +2265,12 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, init_decoded_content (reply_ct, infile); if (extract_headers (reply_ct, reply_file, &reply_fp) == NOTOK) { - free (reply_file); - admonish (NULL, - "failed to extract headers from convert output in %s", - reply_file); + inform("failed to extract headers from convert output in %s, " + "continuing...", reply_file); + free(reply_file); return; } - /* For text content only, see if it is 8-bit text. */ - if (reply_ct->c_type == CT_TEXT) { - int fd; - - if ((fd = open (reply_file, O_RDONLY)) == NOTOK || - scan_input (fd, &eightbit) == NOTOK) { - free (reply_file); - admonish (NULL, "failed to read %s", reply_file); - return; - } - (void) close (fd); - } - /* This sets reply_ct->c_ctparams, and reply_ct->c_termproc if the charset can't be handled natively. */ for (s2i = str2cts; s2i->si_key; s2i++) { @@ -2286,45 +2283,22 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, (*reply_ct->c_ctinitfnx)(reply_ct); } - if ((cp = - get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1))) { + if ((cp = get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1))) { /* The reply Content-Type had the charset. */ charset = cp; } else { set_charset (reply_ct, -1); charset = get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1); - if (reply_ct->c_reqencoding == CE_UNKNOWN && - reply_ct->c_type == CT_TEXT) { - /* Assume that 8bit is sufficient (for text). In other words, - don't allow it to be encoded as quoted printable if lines - are too long. This also sidesteps the check for whether - it needs to be encoded as binary; instead, it relies on - the applicable mhbuild-convert-text directive to ensure - that the resultant text is not binary. */ - reply_ct->c_reqencoding = eightbit ? CE_8BIT : CE_7BIT; - } } /* Concatenate text/plain parts. */ - if (reply_ct->c_type == CT_TEXT && - reply_ct->c_subtype == TEXT_PLAIN) { + if (reply_ct->c_type == CT_TEXT && reply_ct->c_subtype == TEXT_PLAIN) { if (! *text_plain_ct && m->mp_parts && m->mp_parts->mp_part && m->mp_parts->mp_part->c_type == CT_TEXT && m->mp_parts->mp_part->c_subtype == TEXT_PLAIN) { *text_plain_ct = m->mp_parts->mp_part; - /* Make sure that the charset is set in the text/plain - part. */ + /* Make sure that the charset is set in the text/plain part. */ set_charset (*text_plain_ct, -1); - if ((*text_plain_ct)->c_reqencoding == CE_UNKNOWN) { - /* Assume that 8bit is sufficient (for text). In other words, - don't allow it to be encoded as quoted printable if lines - are too long. This also sidesteps the check for whether - it needs to be encoded as binary; instead, it relies on - the applicable mhbuild-convert-text directive to ensure - that the resultant text is not binary. */ - (*text_plain_ct)->c_reqencoding = - eightbit ? CE_8BIT : CE_7BIT; - } } if (*text_plain_ct) { @@ -2393,9 +2367,10 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m, /* Extract any Content-Type header from beginning of convert output. */ int -extract_headers (CT ct, char *reply_file, FILE **reply_fp) { +extract_headers (CT ct, char *reply_file, FILE **reply_fp) +{ char *buffer = NULL, *cp, *end_of_header; - int found_header = 0; + bool found_header = false; struct stat statbuf; /* Read the convert reply from the file to memory. */ @@ -2415,14 +2390,14 @@ extract_headers (CT ct, char *reply_file, FILE **reply_fp) { buffer[statbuf.st_size] = '\0'; /* Look for a header in the convert reply. */ - if (strncasecmp (buffer, TYPE_FIELD, strlen (TYPE_FIELD)) == 0 && - buffer[strlen (TYPE_FIELD)] == ':') { + if (strncasecmp (buffer, TYPE_FIELD, LEN(TYPE_FIELD)) == 0 && + buffer[LEN(TYPE_FIELD)] == ':') { if ((end_of_header = strstr (buffer, "\r\n\r\n"))) { end_of_header += 2; - found_header = 1; + found_header = true; } else if ((end_of_header = strstr (buffer, "\n\n"))) { ++end_of_header; - found_header = 1; + found_header = true; } } @@ -2430,28 +2405,29 @@ extract_headers (CT ct, char *reply_file, FILE **reply_fp) { CT tmp_ct; char *tmp_file; FILE *tmp_f; - size_t n; + size_t n, written; /* Truncate buffer to just the C-T. */ *end_of_header = '\0'; n = strlen (buffer); if (get_ctinfo (buffer + 14, ct, 0) != OK) { - admonish (NULL, "unable to get content info for reply"); + inform("unable to get content info for reply, continuing..."); goto failed_to_extract_ct; } /* Hack. Use parse_mime() to detect the type/subtype of the reply, which we'll use below. */ tmp_file = getcpy (m_mktemp2 (NULL, invo_name, NULL, NULL)); - if ((tmp_f = fopen (tmp_file, "w")) && - fwrite (buffer, 1, n, tmp_f) == n) { - fclose (tmp_f); - } else { + tmp_f = fopen(tmp_file, "w"); + if (!tmp_f) + goto failed_to_extract_ct; + written = fwrite(buffer, 1, n, tmp_f); + fclose(tmp_f); + if (written != n) goto failed_to_extract_ct; - } - tmp_ct = parse_mime (tmp_file); + tmp_ct = parse_mime (tmp_file); if (tmp_ct) { /* The type and subtype were detected from the reply using parse_mime() above. */ @@ -2483,7 +2459,7 @@ extract_headers (CT ct, char *reply_file, FILE **reply_fp) { ct->c_subtype = TEXT_PLAIN; if (get_ctinfo ("text/plain", ct, 0) == NOTOK) { /* This never should fail, but just in case. */ - adios (NULL, "unable to get content info for reply"); + die("unable to get content info for reply"); } }