X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/81c57383273bb818858b2d7e6fdb4bbdb5df70d7..937ee92013bed7b3ebd30fff2c17a751d37b1a61:/uip/mhfixmsg.c?ds=sidebyside diff --git a/uip/mhfixmsg.c b/uip/mhfixmsg.c index 33faf468..2737dac8 100644 --- a/uip/mhfixmsg.c +++ b/uip/mhfixmsg.c @@ -1,5 +1,4 @@ -/* - * mhfixmsg.c -- rewrite a message with various transformations +/* mhfixmsg.c -- rewrite a message with various transformations * * This code is Copyright (c) 2002 and 2013, by the authors of nmh. * See the COPYRIGHT file in the root directory of the nmh @@ -7,10 +6,17 @@ */ #include +#include #include #include #include #include +#include "../sbr/m_maildir.h" +#include "../sbr/m_mktemp.h" +#include "../sbr/mime_type.h" +#include "mhfree.h" +#include "mhoutsbr.h" +#include "mhshowsbr.h" #include #define MHFIXMSG_SWITCHES \ @@ -61,18 +67,10 @@ extern int suppress_bogus_mp_content_warning; /* flag to InitMultiPart */ extern int bogus_mp_content; /* flag from InitMultiPart */ /* flags to/from parse_header_attrs */ extern int suppress_extraneous_trailing_semicolon_warning; -extern int extraneous_trailing_semicolon; - -/* mhoutsbr.c */ -int output_message (CT, char *); /* mhmisc.c */ void flush_errors (void); -/* mhfree.c */ -extern CT *cts; -void freects_done (int) NORETURN; - /* * static prototypes */ @@ -89,9 +87,10 @@ typedef struct fix_transformations { char *textcharset; } fix_transformations; -int mhfixmsgsbr (CT *, const fix_transformations *, char *); +int mhfixmsgsbr (CT *, char *, const fix_transformations *, FILE **, char *, + FILE **); static int fix_boundary (CT *, int *); -static int copy_input_to_output (const char *, const char *); +static int copy_input_to_output (const char *, FILE *, const char *, FILE *); static int get_multipart_boundary (CT, char **); static int replace_boundary (CT, char *, char *); static int fix_types (CT, svector_t, int *); @@ -123,7 +122,7 @@ static int convert_charsets (CT, char *, int *); static int fix_always (CT, int *); static int fix_filename_param (char *, char *, PM *, PM *); static int fix_filename_encoding (CT); -static int write_content (CT, const char *, char *, int, int); +static int write_content (CT, const char *, char *, FILE *, int, int); static void set_text_ctparams(CT, char *, int); static int remove_file (const char *); static void report (char *, char *, char *, char *, ...); @@ -134,12 +133,12 @@ int main (int argc, char **argv) { int msgnum; char *cp, *file = NULL, *folder = NULL; - char *maildir, buf[100], *outfile = NULL; + char *maildir = NULL, buf[100], *outfile = NULL; char **argp, **arguments; struct msgs_array msgs = { 0, 0, NULL }; struct msgs *mp = NULL; CT *ctp; - FILE *fp; + FILE *fp, *infp = NULL, *outfp = NULL; int using_stdin = 0; int chgflag = 1; int status = OK; @@ -154,8 +153,6 @@ main (int argc, char **argv) { if (nmh_init(argv[0], 2)) { return 1; } - done = freects_done; - arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -259,13 +256,13 @@ main (int argc, char **argv) { if (! (cp = *argp++) || (*cp == '-' && cp[1])) { adios (NULL, "missing argument to %s", argp[-2]); } - file = *cp == '-' ? add (cp, NULL) : path (cp, TFILE); + file = *cp == '-' ? mh_xstrdup (cp) : path (cp, TFILE); continue; case OUTFILESW: if (! (cp = *argp++) || (*cp == '-' && cp[1])) { adios (NULL, "missing argument to %s", argp[-2]); } - outfile = *cp == '-' ? add (cp, NULL) : path (cp, TFILE); + outfile = *cp == '-' ? mh_xstrdup (cp) : path (cp, TFILE); continue; case RPROCSW: if (!(rmmproc = *argp++) || *rmmproc == '-') { @@ -298,7 +295,7 @@ main (int argc, char **argv) { } else { if (*cp == '/') { /* Interpret a full path as a filename, not a message. */ - file = add (cp, NULL); + file = mh_xstrdup (cp); } else { app_msgarg (&msgs, cp); } @@ -327,6 +324,16 @@ main (int argc, char **argv) { adios (NULL, "cannot specify msg and file at same time!"); } + if (outfile) { + /* Open the outfile now, so we don't have to risk opening it + after running out of fds. */ + if (strcmp (outfile, "-") == 0) { + outfp = stdout; + } else if ((outfp = fopen (outfile, "w")) == NULL) { + adios (outfile, "unable to open for writing"); + } + } + /* * check if message is coming from file */ @@ -348,7 +355,7 @@ main (int argc, char **argv) { get_temp_dir()); } else { free (file); - file = add (cp, NULL); + file = mh_xstrdup (cp); cpydata (STDIN_FILENO, fd, "-", file); } @@ -365,17 +372,26 @@ main (int argc, char **argv) { set_text_ctparams(ct, fx.decodetypes, fx.lf_line_endings); *ctp++ = ct; } else { - advise (NULL, "unable to parse message from file %s", file); + inform("unable to parse message from file %s", file); status = NOTOK; - /* If there's an outfile, pass the input message unchanged, so the message won't - get dropped from a pipeline. */ + /* If there's an outfile, pass the input message unchanged, so the + message won't get dropped from a pipeline. */ if (outfile) { - /* Something went wrong. Output might be expected, such as if this were run - as a filter. Just copy the input to the output. */ - if (copy_input_to_output (file, outfile) != OK) { - advise (NULL, "unable to copy message to %s, it might be lost\n", outfile); + /* Something went wrong. Output might be expected, such as if + this were run as a filter. Just copy the input to the + output. */ + if ((infp = fopen (file, "r")) == NULL) { + adios (file, "unable to open for reading"); + } + + if (copy_input_to_output (file, infp, outfile, outfp) != OK) { + inform("unable to copy message to %s, " + "it might be lost\n", outfile); } + + fclose (infp); + infp = NULL; } } } else { @@ -390,8 +406,10 @@ main (int argc, char **argv) { if (! folder) { folder = getfolder (1); } - maildir = m_maildir (folder); + maildir = mh_xstrdup(m_maildir (folder)); + /* chdir so that error messages, esp. from MIME parser, just + refer to the message and not its path. */ if (chdir (maildir) == NOTOK) { adios (maildir, "unable to change directory to"); } @@ -418,26 +436,42 @@ main (int argc, char **argv) { for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { if (is_selected(mp, msgnum)) { - char *msgnam; + char *msgnam = m_name (msgnum); - msgnam = m_name (msgnum); if ((ct = parse_mime (msgnam))) { set_text_ctparams(ct, fx.decodetypes, fx.lf_line_endings); *ctp++ = ct; } else { - advise (NULL, "unable to parse message %s", msgnam); + inform("unable to parse message %s", msgnam); status = NOTOK; - /* If there's an outfile, pass the input message unchanged, so the message won't - get dropped from a pipeline. */ + /* If there's an outfile, pass the input message + unchanged, so the message won't get dropped from a + pipeline. */ if (outfile) { - /* Something went wrong. Output might be expected, such as if this were run - as a filter. Just copy the input to the output. */ - const char *input_filename = path (msgnam, TFILE); + /* Something went wrong. Output might be expected, + such as if this were run as a filter. Just copy + the input to the output. */ + /* Can't use path() here because 1) it might have been + called before and it caches the pwd, and 2) we call + chdir() after that. */ + char *input_filename = + concat (maildir, "/", msgnam, NULL); + + if ((infp = fopen (input_filename, "r")) == NULL) { + adios (input_filename, + "unable to open for reading"); + } - if (copy_input_to_output (input_filename, outfile) != OK) { - advise (NULL, "unable to copy message to %s, it might be lost\n", outfile); + if (copy_input_to_output (input_filename, infp, + outfile, outfp) != OK) { + inform("unable to copy message to %s, " + "it might be lost\n", outfile); } + + fclose (infp); + infp = NULL; + free (input_filename); } } } @@ -453,7 +487,8 @@ main (int argc, char **argv) { if (*cts) { for (ctp = cts; *ctp; ++ctp) { - status += mhfixmsgsbr (ctp, &fx, outfile); + status += mhfixmsgsbr (ctp, maildir, &fx, &infp, outfile, &outfp); + free_content (*ctp); if (using_stdin) { (void) m_unlink (file); @@ -468,13 +503,17 @@ main (int argc, char **argv) { status = 1; } + mh_xfree(maildir); + free (cts); + if (fx.fixtypes != NULL) { svector_free (fx.fixtypes); } + if (infp) { fclose (infp); } /* even if stdin */ + if (outfp) { fclose (outfp); } /* even if stdout */ free (outfile); free (file); free (folder); free (arguments); - /* done is freects_done, which will clean up all of cts. */ done (status); return NOTOK; } @@ -484,28 +523,40 @@ main (int argc, char **argv) { * Apply transformations to one message. */ int -mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { +mhfixmsgsbr (CT *ctp, char *maildir, const fix_transformations *fx, + FILE **infp, char *outfile, FILE **outfp) { /* Store input filename in case one of the transformations, i.e., fix_boundary(), rewrites to a tmp file. */ - char *input_filename = add ((*ctp)->c_file, NULL); + char *input_filename = maildir + ? concat (maildir, "/", (*ctp)->c_file, NULL) + : mh_xstrdup ((*ctp)->c_file); int modify_inplace = 0; int message_mods = 0; int status = OK; + /* Though the input file won't need to be opened if everything goes + well, do it here just in case there's a failure, and that failure is + running out of file descriptors. */ + if ((*infp = fopen (input_filename, "r")) == NULL) { + adios (input_filename, "unable to open for reading"); + } + if (outfile == NULL) { modify_inplace = 1; if ((*ctp)->c_file) { char *tempfile; - if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, NULL)) == NULL) { + /* outfp will be closed by the caller */ + if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, outfp)) == + NULL) { adios (NULL, "unable to create temporary file in %s", get_temp_dir()); } - outfile = add (tempfile, NULL); + outfile = mh_xstrdup (tempfile); } else { adios (NULL, "missing both input and output filenames\n"); } - } + } /* else *outfp was defined by caller */ reverse_alternative_parts (*ctp); status = fix_always (*ctp, &message_mods); @@ -547,14 +598,16 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { * Write the content to a file */ if (status == OK) { - status = write_content (*ctp, input_filename, outfile, modify_inplace, - message_mods); + status = write_content (*ctp, input_filename, outfile, *outfp, + modify_inplace, message_mods); } else if (! modify_inplace) { /* Something went wrong. Output might be expected, such as if this were run as a filter. Just copy the input to the output. */ - if (copy_input_to_output (input_filename, outfile) != OK) { - advise (NULL, "unable to copy message to %s, it might be lost\n", outfile); + if (copy_input_to_output (input_filename, *infp, outfile, + *outfp) != OK) { + inform("unable to copy message to %s, it might be lost\n", + outfile); } } @@ -564,6 +617,8 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { outfile = NULL; } + fclose (*infp); + *infp = NULL; free (input_filename); return status; @@ -575,11 +630,10 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { * might be running as part of a pipeline. */ static int -copy_input_to_output (const char *input_filename, const char *output_filename) { - int in = open (input_filename, O_RDONLY); - int out = strcmp (output_filename, "-") - ? open (output_filename, O_WRONLY | O_CREAT, m_gmprot ()) - : STDOUT_FILENO; +copy_input_to_output (const char *input_filename, FILE *infp, + const char *output_filename, FILE *outfp) { + int in = fileno (infp); + int out = fileno (outfp); int status = OK; if (in != -1 && out != -1) { @@ -588,9 +642,6 @@ copy_input_to_output (const char *input_filename, const char *output_filename) { status = NOTOK; } - close (out); - close (in); - return status; } @@ -624,7 +675,7 @@ fix_boundary (CT *ct, int *message_mods) { if ((fixed = m_mktemp2 (NULL, invo_name, NULL, &(*ct)->c_fp))) { if (replace_boundary (*ct, fixed, part_boundary) == OK) { - char *filename = add ((*ct)->c_file, NULL); + char *filename = mh_xstrdup ((*ct)->c_file); CT fixed_ct; free_content (*ct); @@ -639,16 +690,16 @@ fix_boundary (CT *ct, int *message_mods) { } } else { *ct = NULL; - advise (NULL, "unable to parse fixed part"); + inform("unable to parse fixed part"); status = NOTOK; } free (filename); } else { - advise (NULL, "unable to replace broken boundary"); + inform("unable to replace broken boundary"); status = NOTOK; } } else { - advise (NULL, "unable to create temporary file in %s", + inform("unable to create temporary file in %s", get_temp_dir()); status = NOTOK; } @@ -676,7 +727,7 @@ fix_boundary (CT *ct, int *message_mods) { */ static int get_multipart_boundary (CT ct, char **part_boundary) { - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; char *end_boundary = NULL; off_t begin = (off_t) ct->c_end > (off_t) (ct->c_begin + sizeof buffer) ? (off_t) (ct->c_end - sizeof buffer) @@ -684,10 +735,10 @@ get_multipart_boundary (CT ct, char **part_boundary) { size_t bytes_read; int status = OK; - /* This will fail if the boundary spans fread() calls. BUFSIZ should + /* This will fail if the boundary spans fread() calls. NMH_BUFSIZ should be big enough, even if it's just 1024, to make that unlikely. */ - /* free_content() will close ct->c_fp. */ + /* free_content() will close ct->c_fp if bogus MP boundary is fixed. */ if (! ct->c_fp && (ct->c_fp = fopen (ct->c_file, "r")) == NULL) { advise (ct->c_file, "unable to open for reading"); return NOTOK; @@ -707,18 +758,16 @@ get_multipart_boundary (CT ct, char **part_boundary) { if ((end = rfind_str (buffer, cp - buffer, "\n"))) { if (strlen (end) > 3 && *end++ == '\n' && *end++ == '-' && *end++ == '-') { - end_boundary = add (end, NULL); + end_boundary = mh_xstrdup (end); break; } } } } - if (! end_boundary && begin > (off_t) (ct->c_begin + sizeof buffer)) { - begin -= sizeof buffer; - } else { + if (end_boundary || begin <= (off_t) (ct->c_begin + sizeof buffer)) break; - } + begin -= sizeof buffer; } /* Get boundary at beginning of multipart. */ @@ -744,6 +793,11 @@ get_multipart_boundary (CT ct, char **part_boundary) { status = NOTOK; } + if (ct->c_fp) { + fclose (ct->c_fp); + ct->c_fp = NULL; + } + if (status == OK) { *part_boundary = end_boundary; } else { @@ -762,13 +816,13 @@ static int replace_boundary (CT ct, char *file, char *boundary) { FILE *fpin, *fpout; int compnum, state; - char buf[BUFSIZ], name[NAMESZ]; + char buf[NMH_BUFSIZ], name[NAMESZ]; char *np, *vp; - m_getfld_state_t gstate = 0; + m_getfld_state_t gstate; int status = OK; if (ct->c_file == NULL) { - advise (NULL, "missing input filename"); + inform("missing input filename"); return NOTOK; } @@ -783,22 +837,23 @@ replace_boundary (CT ct, char *file, char *boundary) { return NOTOK; } + gstate = m_getfld_state_init(fpin); for (compnum = 1;;) { int bufsz = (int) sizeof buf; - switch (state = m_getfld (&gstate, name, buf, &bufsz, fpin)) { + 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, fpin); + state = m_getfld2(&gstate, name, buf, &bufsz); vp = add (buf, vp); /* add to previous value */ } @@ -817,11 +872,9 @@ replace_boundary (CT ct, char *file, char *boundary) { strlen(new_ctline) + 1, ct->c_ctinfo.ci_first_pm, NULL, 0); fprintf (fpout, "%s:%s%s\n", np, new_ctline, - new_params ? new_params : ""); + FENDNULL(new_params)); free(new_ctline); - if (new_params) { - free(new_params); - } + mh_xfree(new_params); } free (vp); @@ -830,7 +883,7 @@ replace_boundary (CT ct, char *file, char *boundary) { continue; case BODY: - fputs ("\n", fpout); + putc('\n', fpout); /* buf will have a terminating NULL, skip it. */ if ((int) fwrite (buf, 1, bufsz-1, fpout) < bufsz-1) { advise (file, "fwrite"); @@ -842,12 +895,12 @@ replace_boundary (CT ct, char *file, char *boundary) { case LENERR: case FMTERR: - advise (NULL, "message format error in component #%d", compnum); + inform("message format error in component #%d", compnum); status = NOTOK; break; default: - advise (NULL, "getfld() returned %d", state); + inform("getfld() returned %d", state); status = NOTOK; break; } @@ -924,12 +977,12 @@ fix_types (CT ct, svector_t fixtypes, int *message_mods) { * c_ctline */ /* Extract type and subtype from type/subtype. */ - ct_type = getcpy (ct_type_subtype); + ct_type = mh_xstrdup(ct_type_subtype); if ((cp = strchr (ct_type, '/'))) { *cp = '\0'; - ct_subtype = getcpy (++cp); + ct_subtype = mh_xstrdup(++cp); } else { - advise (NULL, "missing / in MIME type of %s %s", + inform("missing / in MIME type of %s %s", ct->c_file, ct->c_partno); free (ct_type); return NOTOK; @@ -944,7 +997,7 @@ fix_types (CT ct, svector_t fixtypes, int *message_mods) { ct->c_ctinfo.ci_subtype = ct_subtype; if (! replace_substring (&ct->c_ctline, type, ct_type_subtype)) { - advise (NULL, "did not find %s in %s", + inform("did not find %s in %s", type, ct->c_ctline); } @@ -961,10 +1014,8 @@ fix_types (CT ct, svector_t fixtypes, int *message_mods) { type, ct_type_subtype); } break; - } else { - advise (NULL, "did not find %s in %s", - type, hf->value); } + inform("did not find %s in %s", type, hf->value); } } } @@ -991,7 +1042,7 @@ replace_substring (char **str, const char *old, const char *new) { char *prefix, *new_str; if (cp - *str) { - prefix = getcpy (*str); + prefix = mh_xstrdup(*str); *(prefix + (cp - *str)) = '\0'; new_str = concat (prefix, new, remainder, NULL); free (prefix); @@ -1002,9 +1053,9 @@ replace_substring (char **str, const char *old, const char *new) { free (*str); return *str = new_str; - } else { - return NULL; } + + return NULL; } @@ -1014,7 +1065,7 @@ replace_substring (char **str, const char *old, const char *new) { char * remove_parameter (char *str, const char *name) { /* It looks to me, based on the BNF in RFC 2045, than there can't - be whitespace betwwen the parameter name and the "=", or + be whitespace between the parameter name and the "=", or between the "=" and the parameter value. */ char *param_name = concat (name, "=", NULL); char *cp; @@ -1078,9 +1129,10 @@ fix_composite_cte (CT ct, int *message_mods) { if (! strncasecmp (name, ENCODING_FIELD, strlen (ENCODING_FIELD))) { char *prefix = "Nmh-REPLACED-INVALID-"; - HF h = mh_xmalloc (sizeof *h); + HF h; - h->name = add (hf->name, NULL); + NEW(h); + h->name = mh_xstrdup (hf->name); h->hf_encoding = hf->hf_encoding; h->next = hf->next; hf->next = h; @@ -1098,7 +1150,7 @@ fix_composite_cte (CT ct, int *message_mods) { free (encoding); } - h->value = add (" 8bit\n", NULL); + h->value = mh_xstrdup (" 8bit\n"); /* Don't need to warn for multiple C-T-E header fields, parse_mime() already does that. But @@ -1171,17 +1223,17 @@ set_ce (CT ct, int encoding) { } } if (! found_cte) { - add_header (ct, add (ENCODING_FIELD, NULL), cte); + add_header (ct, mh_xstrdup (ENCODING_FIELD), cte); } /* Update c_celine. It's used only by mhlist -debug. */ free (ct->c_celine); - ct->c_celine = add (cte, NULL); + ct->c_celine = mh_xstrdup (cte); return OK; - } else { - return NOTOK; } + + return NOTOK; } @@ -1276,12 +1328,12 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) { HF hf; parent->c_subtype = MULTI_ALTERNATE; - parent->c_ctinfo.ci_subtype = getcpy ("alternative"); + free (parent->c_ctinfo.ci_subtype); + parent->c_ctinfo.ci_subtype = mh_xstrdup("alternative"); if (! replace_substring (&parent->c_ctline, "/related", "/alternative")) { - advise (NULL, - "did not find multipart/related in %s", - parent->c_ctline); + inform("did not find multipart/related in %s", + parent->c_ctline); } /* Update Content-Type header field. */ @@ -1300,11 +1352,9 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) { multipart/alternative. */ remove_parameter (hf->value, "type"); break; - } else { - advise (NULL, "did not find multipart/" - "related in header %s", - hf->value); } + inform("did not find multipart/" + "related in header %s", hf->value); } } } else { @@ -1395,8 +1445,9 @@ find_textplain_sibling (CT parent, int replacetextplain, static int insert_new_text_plain_part (CT ct, int new_subpart_number, CT parent) { struct multipart *mp = (struct multipart *) parent->c_ctparams; - struct part *new_part = mh_xmalloc (sizeof *new_part); + struct part *new_part; + NEW(new_part); if ((new_part->mp_part = build_text_plain_part (ct))) { char buffer[16]; snprintf (buffer, sizeof buffer, "%d", new_subpart_number); @@ -1408,12 +1459,12 @@ insert_new_text_plain_part (CT ct, int new_subpart_number, CT parent) { buffer, NULL); return 1; - } else { - free_content (new_part->mp_part); - free (new_part); - - return 0; } + + free_content (new_part->mp_part); + free (new_part); + + return 0; } @@ -1432,11 +1483,12 @@ build_text_plain_part (CT encoded_part) { be unlinked by free_content (). */ char *tempfile; + /* This m_mktemp2() call closes the temp file. */ if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, NULL)) == NULL) { - advise (NULL, "unable to create temporary file in %s", + inform("unable to create temporary file in %s", get_temp_dir()); } else { - tmp_plain_file = add (tempfile, NULL); + tmp_plain_file = mh_xstrdup (tempfile); if (reformat_part (tp_part, tmp_plain_file, tp_part->c_ctinfo.ci_type, tp_part->c_ctinfo.ci_subtype, @@ -1504,7 +1556,7 @@ divide_part (CT ct) { NEW0(new_part); /* Just copy over what is needed for decoding. c_vrsn and c_celine aren't necessary. */ - new_part->c_file = add (ct->c_file, NULL); + new_part->c_file = mh_xstrdup (ct->c_file); new_part->c_begin = ct->c_begin; new_part->c_end = ct->c_end; copy_ctinfo (&new_part->c_ctinfo, &ct->c_ctinfo); @@ -1518,7 +1570,7 @@ divide_part (CT ct) { /* c_ctline is used by reformat__part(), so it can preserve anything after the type/subtype. */ - new_part->c_ctline = add (ct->c_ctline, NULL); + new_part->c_ctline = mh_xstrdup (ct->c_ctline); return new_part; } @@ -1531,22 +1583,22 @@ static void copy_ctinfo (CI dest, CI src) { 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; + dest->ci_type = src->ci_type ? mh_xstrdup (src->ci_type) : NULL; + dest->ci_subtype = src->ci_subtype ? mh_xstrdup (src->ci_subtype) : NULL; 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, 0); if (s_pm->pm_charset) { - d_pm->pm_charset = getcpy(s_pm->pm_charset); + d_pm->pm_charset = mh_xstrdup(s_pm->pm_charset); } if (s_pm->pm_lang) { - d_pm->pm_lang = getcpy(s_pm->pm_lang); + d_pm->pm_lang = mh_xstrdup(s_pm->pm_lang); } } - dest->ci_comment = src->ci_comment ? add (src->ci_comment, NULL) : NULL; - dest->ci_magic = src->ci_magic ? add (src->ci_magic, NULL) : NULL; + dest->ci_comment = src->ci_comment ? mh_xstrdup (src->ci_comment) : NULL; + dest->ci_magic = src->ci_magic ? mh_xstrdup (src->ci_magic) : NULL; } @@ -1557,18 +1609,22 @@ static int decode_part (CT ct) { char *tmp_decoded; int status; + FILE *file; char *tempfile; - if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, NULL)) == NULL) { + if ((tempfile = m_mktemp2 (NULL, invo_name, NULL, &file)) == NULL) { adios (NULL, "unable to create temporary file in %s", get_temp_dir()); } - tmp_decoded = add (tempfile, NULL); + tmp_decoded = mh_xstrdup (tempfile); /* The following call will load ct->c_cefile.ce_file with the tmp filename of the decoded content. tmp_decoded will contain the encoded output, get rid of that. */ - status = output_message (ct, tmp_decoded); + status = output_message_fp (ct, file, tmp_decoded); (void) m_unlink (tmp_decoded); free (tmp_decoded); + if (fclose (file)) { + inform("unable to close temporary file %s, continuing...", tempfile); + } return status; } @@ -1594,19 +1650,18 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) { /* Check for invo_name-format-type/subtype. */ if ((cf = context_find_by_type ("format", type, subtype)) == NULL) { if (verbosw) { - advise (NULL, "Don't know how to convert %s, there is no " + inform("Don't know how to convert %s, there is no " "%s-format-%s/%s profile entry", ct->c_file, invo_name, type, subtype); } return NOTOK; - } else { - if (strchr (cf, '>')) { - advise (NULL, "'>' prohibited in \"%s\",\nplease fix your " - "%s-format-%s/%s profile entry", cf, invo_name, type, - subtype ? subtype : ""); + } + if (strchr (cf, '>')) { + inform("'>' prohibited in \"%s\",\nplease fix your " + "%s-format-%s/%s profile entry", cf, invo_name, type, + FENDNULL(subtype)); - return NOTOK; - } + return NOTOK; } cp = concat (cf, " >", file, NULL); @@ -1630,7 +1685,8 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) { } output_encoding = content_encoding (ct, &reason); - if (set_ct_type (ct, c_type, output_subtype, output_encoding) == OK) { + if (status == OK && + set_ct_type (ct, c_type, output_subtype, output_encoding) == OK) { ct->c_cefile.ce_file = file; ct->c_cefile.ce_unlink = 1; } else { @@ -1671,7 +1727,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { c_showproc, c_termproc, c_storeproc, c_storage, c_folder */ - ct->c_file = add (first_alt->c_file, NULL); + ct->c_file = mh_xstrdup (first_alt->c_file); ct->c_type = type; ct->c_subtype = subtype; @@ -1693,8 +1749,8 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { if ((found_boundary = boundary_in_content (&new_part->c_cefile.ce_fp, new_part->c_cefile.ce_file, - boundary)) == -1) { - free (ct); + boundary)) == NOTOK) { + free_content (ct); return NULL; } } @@ -1702,10 +1758,11 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { /* Ensure that the boundary doesn't appear in the encoded content. */ if (! found_boundary && new_part->c_file) { - if ((found_boundary = boundary_in_content (&new_part->c_fp, - new_part->c_file, - boundary)) == -1) { - free (ct); + if ((found_boundary = + boundary_in_content (&new_part->c_fp, + new_part->c_file, + boundary)) == NOTOK) { + free_content (ct); return NULL; } } @@ -1719,14 +1776,14 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { snprintf (buffer2, sizeof buffer2, "%d", serial); boundary = concat (boundary_prefix, - first_alt->c_partno ? first_alt->c_partno : "", + FENDNULL(first_alt->c_partno), "-", buffer2, NULL); } } if (found_boundary) { - advise (NULL, "giving up trying to find a unique boundary"); - free (ct); + inform("giving up trying to find a unique boundary"); + free_content (ct); return NULL; } } @@ -1736,30 +1793,30 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { /* Load c_first_hf and c_last_hf. */ transfer_noncontent_headers (first_alt, ct); - add_header (ct, add (TYPE_FIELD, NULL), concat (name, "\n", NULL)); + add_header (ct, mh_xstrdup (TYPE_FIELD), concat (name, "\n", NULL)); free (name); /* Load c_partno. */ if (first_alt->c_partno) { - ct->c_partno = add (first_alt->c_partno, NULL); + ct->c_partno = mh_xstrdup (first_alt->c_partno); free (first_alt->c_partno); first_alt->c_partno = concat (ct->c_partno, ".1", NULL); new_part->c_partno = concat (ct->c_partno, ".2", NULL); } else { - first_alt->c_partno = add ("1", NULL); - new_part->c_partno = add ("2", NULL); + first_alt->c_partno = mh_xstrdup ("1"); + new_part->c_partno = mh_xstrdup ("2"); } if (ctinit) { - ct->c_ctinfo.ci_type = add (typename, NULL); - ct->c_ctinfo.ci_subtype = add (subtypename, NULL); + ct->c_ctinfo.ci_type = mh_xstrdup (typename); + ct->c_ctinfo.ci_subtype = mh_xstrdup (subtypename); } add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm, "boundary", boundary, 0); - p = (struct part *) mh_xmalloc (sizeof *p); - p->mp_next = (struct part *) mh_xmalloc (sizeof *p->mp_next); + NEW(p); + NEW(p->mp_next); p->mp_next->mp_next = NULL; p->mp_next->mp_part = first_alt; @@ -1780,7 +1837,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) { */ static int boundary_in_content (FILE **fp, char *file, const char *boundary) { - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; size_t bytes_read; int found_boundary = 0; @@ -1870,14 +1927,14 @@ set_ct_type (CT ct, int type, int subtype, int encoding) { free (hf->value); hf->value = (cp = strchr (ct->c_ctline, ';')) ? concat (type_subtypename, cp, "\n", NULL) - : add (name_plus_nl, NULL); + : mh_xstrdup (name_plus_nl); } } if (! found_content_type) { - add_header (ct, add (TYPE_FIELD, NULL), + add_header (ct, mh_xstrdup (TYPE_FIELD), (cp = strchr (ct->c_ctline, ';')) ? concat (type_subtypename, cp, "\n", NULL) - : add (name_plus_nl, NULL)); + : mh_xstrdup (name_plus_nl)); } /* Some of these might not be used, but set them anyway. */ @@ -1888,9 +1945,9 @@ set_ct_type (CT ct, int type, int subtype, int encoding) { ct->c_ctline = ctline; /* Leave other ctinfo members as they were. */ free (ct->c_ctinfo.ci_type); - ct->c_ctinfo.ci_type = add (typename, NULL); + ct->c_ctinfo.ci_type = mh_xstrdup (typename); free (ct->c_ctinfo.ci_subtype); - ct->c_ctinfo.ci_subtype = add (subtypename, NULL); + ct->c_ctinfo.ci_subtype = mh_xstrdup (subtypename); ct->c_type = type; ct->c_subtype = subtype; @@ -1962,8 +2019,7 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, report (NULL, ct->c_partno, ct->c_file, "will not decode%s because it is binary (%s)", ct->c_partno ? "" - : ct->c_ctline ? ct->c_ctline - : "", + : (FENDNULL(ct->c_ctline)), reason); } (void) m_unlink (ct->c_cefile.ce_file); @@ -1977,8 +2033,7 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, report (NULL, ct->c_partno, ct->c_file, "will not decode%s because it is 8bit", ct->c_partno ? "" - : ct->c_ctline ? ct->c_ctline - : ""); + : (FENDNULL(ct->c_ctline))); } (void) m_unlink (ct->c_cefile.ce_file); free (ct->c_cefile.ce_file); @@ -1997,7 +2052,7 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, ++*message_mods; if (verbosw) { report (NULL, ct->c_partno, ct->c_file, "decode%s", - ct->c_ctline ? ct->c_ctline : ""); + FENDNULL(ct->c_ctline)); } if (lf_line_endings) { strip_crs (ct, message_mods); @@ -2074,7 +2129,7 @@ content_encoding (CT ct, const char **reason) { if (ce->ce_file) { size_t line_len = 0; - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; size_t inbytes; if (! ce->ce_fp && (ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) { @@ -2104,13 +2159,14 @@ content_encoding (CT ct, const char **reason) { *reason = ""; } break; - } else if (*cp == '\n') { + } + if (*cp == '\n') { line_len = 0; } else if (! isascii ((unsigned char) *cp)) { encoding = CE_8BIT; } - last_char_was_cr = *cp == '\r' ? 1 : 0; + last_char_was_cr = *cp == '\r'; } } @@ -2169,7 +2225,7 @@ strip_crs (CT ct, int *message_mods) { } if (fp && *fp) { - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; size_t bytes_read; size_t bytes_to_read = end > 0 && end > begin ? end - begin : sizeof buffer; @@ -2193,7 +2249,7 @@ strip_crs (CT ct, int *message_mods) { break; } - last_char_was_cr = *cp == '\r' ? 1 : 0; + last_char_was_cr = *cp == '\r'; } } @@ -2206,7 +2262,7 @@ strip_crs (CT ct, int *message_mods) { adios (NULL, "unable to create temporary file in %s", get_temp_dir()); } - stripped_content_file = add (tempfile, NULL); + stripped_content_file = mh_xstrdup (tempfile); /* Strip each CR before a LF from the content. */ fseeko (*fp, begin, SEEK_SET); @@ -2239,18 +2295,16 @@ strip_crs (CT ct, int *message_mods) { } if (close (fd)) { - admonish (NULL, "unable to write temporary file %s", + inform("unable to write temporary file %s, continuing...", stripped_content_file); (void) m_unlink (stripped_content_file); status = NOTOK; } else { /* Replace the decoded file with the converted one. */ - if (ct->c_cefile.ce_file) { - if (ct->c_cefile.ce_unlink) { - (void) m_unlink (ct->c_cefile.ce_file); - } - free (ct->c_cefile.ce_file); - } + if (ct->c_cefile.ce_file && ct->c_cefile.ce_unlink) + (void) m_unlink (ct->c_cefile.ce_file); + + mh_xfree(ct->c_cefile.ce_file); ct->c_cefile.ce_file = stripped_content_file; ct->c_cefile.ce_unlink = 1; @@ -2299,7 +2353,7 @@ update_cte (CT ct) { } } if (! found_cte) { - add_header (ct, add (ENCODING_FIELD, NULL), cte); + add_header (ct, mh_xstrdup (ENCODING_FIELD), cte); } } } @@ -2525,12 +2579,9 @@ fix_always (CT ct, int *message_mods) { */ static int fix_filename_param (char *name, char *value, PM *first_pm, PM *last_pm) { - size_t value_len; int fixed = 0; - if (((value_len = strlen (value)) > 0) && - strncmp (value, "=?", 2) == 0 && - strncmp (&value[value_len - 2], "?=", 2) == 0) { + if (has_prefix(value, "=?") && has_suffix(value, "?=")) { /* Looks like an RFC 2047 encoded parameter. */ char decoded[PATH_MAX + 1]; @@ -2539,7 +2590,7 @@ fix_filename_param (char *name, char *value, PM *first_pm, PM *last_pm) { replace_param (first_pm, last_pm, name, decoded, 0); fixed = 1; } else { - advise (NULL, "failed to decode %s parameter %s", name, value); + inform("failed to decode %s parameter %s", name, value); } } @@ -2601,10 +2652,10 @@ fix_filename_encoding (CT ct) { const char *const new_params = concat (params, "\n", NULL); replace_substring (&hf->value, semicolon_loc, new_params); - free ((char *) new_params); - free ((char *) params); + free((void *)new_params); /* Cast away const. Sigh. */ + free((void *)params); } else { - advise (NULL, "did not find semicolon in %s:%s\n", + inform("did not find semicolon in %s:%s\n", hf->name, hf->value); } } @@ -2618,16 +2669,16 @@ fix_filename_encoding (CT ct) { * Output content in input file to output file. */ static int -write_content (CT ct, const char *input_filename, char *outfile, int modify_inplace, - int message_mods) { +write_content (CT ct, const char *input_filename, char *outfile, FILE *outfp, + int modify_inplace, int message_mods) { int status = OK; if (modify_inplace) { if (message_mods > 0) { - if ((status = output_message (ct, outfile)) == OK) { + if ((status = output_message_fp (ct, outfp, outfile)) == OK) { char *infile = input_filename - ? add (input_filename, NULL) - : add (ct->c_file ? ct->c_file : "-", NULL); + ? mh_xstrdup (input_filename) + : mh_xstrdup (ct->c_file ? ct->c_file : "-"); if (remove_file (infile) == OK) { if (rename (outfile, infile)) { @@ -2640,7 +2691,7 @@ write_content (CT ct, const char *input_filename, char *outfile, int modify_inpl int i = -1; if (old != -1 && new != -1) { - char buffer[BUFSIZ]; + char buffer[NMH_BUFSIZ]; while ((i = read (old, buffer, sizeof buffer)) > 0) { @@ -2659,15 +2710,15 @@ write_content (CT ct, const char *input_filename, char *outfile, int modify_inpl expand filename to absolute path. */ int file = ct->c_file && ct->c_file[0] == '/'; - admonish (NULL, "unable to rename %s %s to %s", + inform("unable to rename %s %s to %s, continuing...", file ? "file" : "message", outfile, infile); status = NOTOK; } } } else { - admonish (NULL, "unable to remove input file %s, " - "not modifying it", infile); + inform("unable to remove input file %s, " + "not modifying it, continuing...", infile); (void) m_unlink (outfile); status = NOTOK; } @@ -2683,7 +2734,7 @@ write_content (CT ct, const char *input_filename, char *outfile, int modify_inpl } else { /* Output is going to some file. Produce it whether or not there were modifications. */ - status = output_message (ct, outfile); + status = output_message_fp (ct, outfp, outfile); } flush_errors (); @@ -2739,12 +2790,11 @@ remove_file (const char *file) { free (rmm_command); return WIFEXITED (status) ? WEXITSTATUS (status) : NOTOK; - } else { - /* This is OK for a non-message file, it still uses the - BACKUP_PREFIX form. The backup file will be in the same - directory as file. */ - return rename (file, m_backup (file)); } + /* This is OK for a non-message file, it still uses the + BACKUP_PREFIX form. The backup file will be in the same + directory as file. */ + return rename (file, m_backup (file)); } @@ -2759,7 +2809,7 @@ report (char *what, char *partno, char *filename, char *message, ...) { if (verbosw) { va_start (args, message); fmt = concat (filename, partno ? " part " : ", ", - partno ? partno : "", partno ? ", " : "", message, NULL); + FENDNULL(partno), partno ? ", " : "", message, NULL); advertise (what, NULL, fmt, args);