-
-/*
- * 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
#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/utils.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 <sys/time.h>
extern int rfc934sw;
extern int contentidsw;
-/* cache policies */
-extern int rcachesw; /* mhcachesbr.c */
-extern int wcachesw; /* mhcachesbr.c */
-
static char prefix[] = "----- =_aaaaaaaaaa";
struct attach_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
*/
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;
/*
* Allocate space for primary (outside) content
*/
- if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(ct);
/*
* Allocate structure for handling decoded content
fclose(in);
free (ct);
return NULL;
- } else {
- adios (NULL, "draft shouldn't contain %s: field", name);
}
+ adios (NULL, "draft shouldn't contain %s: field", name);
}
/* ignore any Content-Type fields in the header */
}
/* 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) {
goto finish_field;
}
- entry = mh_xmalloc(sizeof(*entry));
- entry->filename = getcpy(s);
+ NEW(entry);
+ entry->filename = mh_xstrdup(s);
entry->next = NULL;
free(vp);
adios (NULL, "Multiple %s headers with different files"
" not allowed", type);
} else {
- convert->filename = getcpy (filename);
+ convert->filename = mh_xstrdup(filename);
}
} else {
- convert = mh_xcalloc (sizeof *convert, 1);
- convert->filename = getcpy (filename);
- convert->type = getcpy (type);
+ NEW0(convert);
+ convert->filename = mh_xstrdup(filename);
+ convert->type = mh_xstrdup(type);
if (convert_tail) {
convert_tail->next = convert;
adios (NULL, "Multiple %s headers with different "
"argstrings not allowed", type);
} else {
- convert->argstring = getcpy (argstring);
+ convert->argstring = mh_xstrdup(argstring);
}
} else {
- convert = mh_xcalloc (sizeof *convert, 1);
- convert->type = getcpy (type);
- convert->argstring = getcpy (argstring);
+ NEW0(convert);
+ convert->type = mh_xstrdup(type);
+ convert->argstring = mh_xstrdup(argstring);
if (convert_tail) {
convert_tail->next = convert;
case BODY:
fseek (in, (long) (-strlen (buf)), SEEK_CUR);
- /* fall through */
+ break;
case FILEEOF:
break;
*/
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.
*/
ct->c_type = CT_MULTIPART;
ct->c_subtype = MULTI_MIXED;
- if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(m);
ct->c_ctparams = (void *) m;
pp = &m->mp_parts;
CT p;
if (user_content (in, buf, &p, infile) == DONE) {
- admonish (NULL, "ignoring spurious #end");
+ inform("ignoring spurious #end, continuing...");
continue;
}
if (!p)
continue;
- if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(part);
*pp = part;
pp = &part->mp_next;
part->mp_part = p;
adios("reading", "Unable to open %s for", at_entry->filename);
}
- if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
- adios(NULL, "out of memory");
-
+ NEW0(p);
init_decoded_content(p, infile);
/*
setup_attach_content(p, at_entry->filename);
- if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(part);
*pp = part;
pp = &part->mp_next;
part->mp_part = p;
free (cts);
/* Extract the type part (as a CT) from filename. */
- if (! (cts = (CT *) mh_xcalloc ((size_t) 2, sizeof *cts))) {
- adios (NULL, "out of memory");
- } else if (! (cts[0] = parse_mime (convert_head->filename))) {
+ cts = mh_xcalloc(2, sizeof *cts);
+ if (! (cts[0] = parse_mime (convert_head->filename))) {
adios (NULL, "failed to parse %s", convert_head->filename);
}
struct part *part;
struct text *t;
- if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
- adios(NULL, "out of memory");
-
+ NEW0(p);
init_decoded_content(p, infile);
if (get_ctinfo ("text/plain", p, 0) == NOTOK)
* So this seems like the best option available since we're going
* to call scan_content() on this.
*/
- p->c_cefile.ce_file = getcpy("/dev/null");
+ p->c_cefile.ce_file = mh_xstrdup("/dev/null");
p->c_begin = ftell(in);
p->c_end = ftell(in);
- if ((t = (struct text *) mh_xcalloc (1, sizeof (*t))) == NULL)
- adios (NULL, "out of memory");
-
+ NEW0(t);
t->tx_charset = CHARSET_SPECIFIED;
p->c_ctparams = t;
- if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(part);
*pp = part;
part->mp_part = p;
}
if ((cp = strchr(prefix, 'a')) == NULL)
adios (NULL, "internal error(4)");
+ /*
+ * If using EAI, force 8-bit charset.
+ */
+ if (header_encoding == CE_8BIT) {
+ set_charset (ct, 1);
+ }
+
/*
* Scan the contents. Choose a transfer encoding, and
* check if prefix for multipart boundary clashes with
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) {
} else if (strcmp(s, "#pop\n") == 0) {
directive_pop();
} else {
- break;
+ return s;
}
}
-
- return s;
}
{
int extrnal, vrsn;
char *cp, **ap;
- char buffer[BUFSIZ];
+ char buffer[NMH_BUFSIZ];
struct multipart *m;
struct part **pp;
struct stat st;
}
/* allocate basic Content structure */
- if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(ct);
*ctp = ct;
/* allocate basic structure for handling decoded content */
}
/* 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;
goto rock_and_roll;
- } else {
- inlineD = 0;
}
+ inlineD = 0;
/* the directive is implicit */
strncpy (content, "text/plain", sizeof(content));
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",
ct->c_type == CT_MESSAGE ? "message" : "multipart");
* reference, we need to create another Content structure
* for the message/external-body to wrap it in.
*/
- if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(ct);
init_decoded_content(ct, infilename);
*ctp = ct;
if (get_ctinfo (buffer, ct, 0) == NOTOK)
ct->c_type = CT_MESSAGE;
ct->c_subtype = MESSAGE_EXTERNAL;
- if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(e);
ct->c_ctparams = (void *) e;
e->eb_parent = ct;
continue;
if (!*cp)
adios (NULL, "empty pipe command for #%s directive", ci->ci_type);
- cp = add (cp, NULL);
+ cp = mh_xstrdup(cp);
free (ci->ci_magic);
ci->ci_magic = cp;
} else {
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;
}
/* 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);
ct->c_type = CT_MULTIPART;
ct->c_subtype = MULTI_DIGEST;
- if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(m);
ct->c_ctparams = (void *) m;
pp = &m->mp_parts;
CT p;
CE pe;
- if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(p);
init_decoded_content (p, infilename);
pe = &p->c_cefile;
if (get_ctinfo ("message/rfc822", p, 0) == NOTOK)
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;
- if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(part);
*pp = part;
pp = &part->mp_next;
part->mp_part = p;
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;
}
ct->c_type = CT_MULTIPART;
ct->c_subtype = vrsn;
- if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(m);
ct->c_ctparams = (void *) m;
pp = &m->mp_parts;
if (!p)
continue;
- if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
- adios (NULL, "out of memory");
+ NEW0(part);
*pp = part;
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;
}
time (&clock);
snprintf (contentid, sizeof(contentid), "%s\n", message_id (clock, 1));
partno = 0;
- msgfmt = getcpy(contentid);
+ msgfmt = mh_xstrdup(contentid);
}
snprintf (contentid, sizeof(contentid), msgfmt, top ? 0 : ++partno);
- ct->c_id = getcpy (contentid);
+ ct->c_id = mh_xstrdup(contentid);
}
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;
}
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;
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;
case 'F':
/* %f, and stdout is not-redirected */
xstdout = 1;
- /* and fall... */
+ /* FALLTHRU */
case 'f':
/*
/*
* 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 */
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);
}
* 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)) {
* 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) {
np = output_params(len, ct->c_dispo_first, NULL, 0);
vp = add(np, vp);
vp = add("\n", vp);
- if (np)
- free(np);
- add_header (ct, getcpy(DISPO_FIELD), vp);
+ mh_xfree(np);
+ add_header (ct, mh_xstrdup(DISPO_FIELD), vp);
}
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);
}
/*
* output the Content-Transfer-Encoding
+ * If using EAI and message body is 7-bit, force 8-bit C-T-E.
*/
+ if (header_encoding == CE_8BIT && ct->c_encoding == CE_7BIT) {
+ ct->c_encoding = CE_8BIT;
+ }
+
switch (ct->c_encoding) {
case CE_7BIT:
/* Nothing to output */
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;
if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
adios (NULL, "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;
if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
adios (NULL, "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;
if (ct->c_type == CT_MESSAGE)
adios (NULL, "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;
/*
* 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.
*/
if (strcasecmp(ct->c_ctinfo.ci_subtype, "external-body") == 0)
adios(NULL, "external-body messages must be specified "
"by mhbuild directives");
- /* Fall through */
+ /* FALLTHRU */
default:
/*
for (pm = ct->c_ctinfo.ci_first_pm; pm; pm = pm->pm_next) {
if (strcasecmp(pm->pm_name, "name") == 0) {
- if (pm->pm_value)
- free(pm->pm_value);
- pm->pm_value = getcpy(simplename);
+ mh_xfree(pm->pm_value);
+ pm->pm_value = mh_xstrdup(simplename);
break;
}
}
add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm,
"name", simplename, 0);
- ct->c_descr = getcpy(simplename);
+ ct->c_descr = mh_xstrdup(simplename);
ct->c_descr = add("\n", ct->c_descr);
- ct->c_cefile.ce_file = getcpy(filename);
+ ct->c_cefile.ce_file = mh_xstrdup(filename);
set_disposition (ct);
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);
}
- ct->c_dispo_type = cp ? getcpy (cp) : getcpy ("attachment");
+ if (!cp)
+ cp = "attachment";
+ ct->c_dispo_type = mh_xstrdup(cp);
}
}
/*
* 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
struct text *t;
if (ct->c_ctparams == NULL) {
- if ((t = ct->c_ctparams =
- (struct text *) mh_xcalloc (1, sizeof (struct text))) ==
- NULL) {
- adios (NULL, "out of memory");
- }
+ NEW0(t);
+ ct->c_ctparams = t;
t->tx_charset = CHARSET_UNSPECIFIED;
} else {
t = (struct text *) ct->c_ctparams;
/* 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,
+ concat (convert, " ", FENDNULL(argstring), " >", reply_file,
NULL);
/* Convert here . . . */
- ct->c_storeproc = getcpy (convert_command);
+ ct->c_storeproc = mh_xstrdup(convert_command);
ct->c_umask = ~m_gmprot ();
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);
/* Fill out the the new ct, reply_ct. */
- reply_ct = (CT) mh_xcalloc (1, sizeof *reply_ct);
+ NEW0(reply_ct);
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);
return;
}
if ((fd = open (reply_file, O_RDONLY)) == NOTOK ||
scan_input (fd, &eightbit) == NOTOK) {
free (reply_file);
- admonish (NULL, "failed to read %s", reply_file);
+ inform("failed to read %s, continuing...", reply_file);
return;
- } else {
- (void) close (fd);
- }
+ }
+ (void) close (fd);
}
/* This sets reply_ct->c_ctparams, and reply_ct->c_termproc if the
reply_ct->c_cefile.ce_unlink = 1;
/* Attach the new part to the parent multipart/mixed, "m". */
- part = (struct part *) mh_xcalloc (1, sizeof *part);
+ NEW0(part);
part->mp_part = reply_ct;
if (m->mp_parts) {
struct part *p;
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;
}