/*
- * 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
- * complete copyright information.
- */
+** 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
+** complete copyright information.
+*/
/*
- * This code was originally part of mhn.c. I split it into
- * a separate program (mhbuild.c) and then later split it
- * again (mhbuildsbr.c). But the code still has some of
- * the mhn.c code in it. This program needs additional
- * streamlining and removal of unneeded code.
- */
+** This code was originally part of mhn.c. I split it into
+** a separate program (mhbuild.c) and then later split it
+** again (mhbuildsbr.c). But the code still has some of
+** the mhn.c code in it. This program needs additional
+** streamlining and removal of unneeded code.
+*/
#include <h/mh.h>
#include <fcntl.h>
extern int wcachesw; /* mhcachesbr.c */
/*
- * Directory to place tmp files. This must
- * be set before these routines are called.
- */
+** Directory to place tmp files. This must
+** be set before these routines are called.
+*/
char *tmp;
pid_t xpid = 0;
void free_encoding (CT, int);
/*
- * prototypes
- */
+** prototypes
+*/
CT build_mime (char *);
/*
- * static prototypes
- */
+** static prototypes
+*/
static int init_decoded_content (CT);
static char *fgetstr (char *, int, FILE *);
static int user_content (FILE *, char *, char *, CT *);
/*
- * Main routine for translating composition file
- * into valid MIME message. It translates the draft
- * into a content structure (actually a tree of content
- * structures). This message then can be manipulated
- * in various ways, including being output via
- * output_message().
- */
+** Main routine for translating composition file
+** into valid MIME message. It translates the draft
+** into a content structure (actually a tree of content
+** structures). This message then can be manipulated
+** in various ways, including being output via
+** output_message().
+*/
CT
build_mime (char *infile)
adios (infile, "unable to open for reading");
/*
- * Allocate space for primary (outside) content
- */
+ ** Allocate space for primary (outside) content
+ */
if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL)
adios (NULL, "out of memory");
/*
- * Allocate structure for handling decoded content
- * for this part. We don't really need this, but
- * allocate it to remain consistent.
- */
+ ** Allocate structure for handling decoded content
+ ** for this part. We don't really need this, but
+ ** allocate it to remain consistent.
+ */
init_decoded_content (ct);
/*
- * Parse some of the header fields in the composition
- * draft into the linked list of header fields for
- * the new MIME message.
- */
+ ** Parse some of the header fields in the composition
+ ** draft into the linked list of header fields for
+ ** the new MIME message.
+ */
for (compnum = 1, state = FLD;;) {
switch (state = m_getfld (state, name, buf, sizeof(buf), in)) {
case FLD:
if (!mh_strcasecmp (name, VRSN_FIELD))
adios (NULL, "draft shouldn't contain %s: field", VRSN_FIELD);
- /* abort if draft has Content-Transfer-Encoding header field */
+ /*
+ ** abort if draft has Content-Transfer-Encoding
+ ** header field
+ */
if (!mh_strcasecmp (name, ENCODING_FIELD))
adios (NULL, "draft shouldn't contain %s: field", ENCODING_FIELD);
/* ignore any Content-Type fields in the header */
if (!mh_strcasecmp (name, TYPE_FIELD)) {
while (state == FLDPLUS)
- state = m_getfld (state, name, buf, sizeof(buf), in);
+ state = m_getfld (state, name, buf,
+ sizeof(buf), in);
goto finish_field;
}
/* if necessary, get rest of field */
while (state == FLDPLUS) {
state = m_getfld (state, name, buf, sizeof(buf), in);
- vp = add (buf, vp); /* add to previous value */
+ vp = add (buf, vp); /* add to prev value */
}
/* Now add the header data to the list */
add_header (ct, np, vp);
finish_field:
- /* if this wasn't the last header field, then continue */
+ /* if this wasn't the last hdr field, then continue */
if (state != FLDEOF)
continue;
/* else fall... */
case LENERR:
case FMTERR:
- adios (NULL, "message format error in component #%d", compnum);
+ adios (NULL, "message format error in component #%d",
+ compnum);
default:
adios (NULL, "getfld() returned %d", state);
}
/*
- * Now add the MIME-Version header field
- * to the list of header fields.
- */
+ ** Now add the MIME-Version header field
+ ** to the list of header fields.
+ */
np = add (VRSN_FIELD, NULL);
vp = concat (" ", VRSN_VALUE, "\n", NULL);
add_header (ct, np, vp);
/*
- * We initally 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.
- */
+ ** We initally 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.
+ */
if (get_ctinfo ("multipart/mixed", ct, 0) == NOTOK)
done (1);
ct->c_type = CT_MULTIPART;
pp = &m->mp_parts;
/*
- * read and parse the composition file
- * and the directives it contains.
- */
+ ** read and parse the composition file
+ ** and the directives it contains.
+ */
while (fgetstr (buf, sizeof(buf) - 1, in)) {
struct part *part;
CT p;
}
/*
- * close the composition draft since
- * it's not needed any longer.
- */
+ ** close the composition draft since
+ ** it's not needed any longer.
+ */
fclose (in);
/* check if any contents were found */
adios (NULL, "no content directives found");
/*
- * If only one content was found, then remove and
- * free the outer multipart content.
- */
+ ** If only one content was found, then remove and
+ ** free the outer multipart content.
+ */
if (!m->mp_parts->mp_next) {
CT p;
}
/*
- * Fill out, or expand directives. Parse and execute
- * commands specified by profile composition strings.
- */
+ ** Fill out, or expand directives. Parse and execute
+ ** commands specified by profile composition strings.
+ */
compose_content (ct);
if ((cp = strchr(prefix, 'a')) == NULL)
adios (NULL, "internal error(4)");
/*
- * Scan the contents. Choose a transfer encoding, and
- * check if prefix for multipart boundary clashes with
- * any of the contents.
- */
+ ** Scan the contents. Choose a transfer encoding, and
+ ** check if prefix for multipart boundary clashes with
+ ** any of the contents.
+ */
while (scan_content (ct) == NOTOK) {
if (*cp < 'z') {
(*cp)++;
/*
- * Set up structures for placing unencoded
- * content when building parts.
- */
+** Set up structures for placing unencoded
+** content when building parts.
+*/
static int
init_decoded_content (CT ct)
/*
- * Parse the composition draft for text and directives.
- * Do initial setup of Content structure.
- */
+** Parse the composition draft for text and directives.
+** Do initial setup of Content structure.
+*/
static int
user_content (FILE *in, char *file, char *buf, CT *ctp)
set_id (ct, 0);
/*
- * Handle inline text. Check if line
- * is one of the following forms:
- *
- * 1) doesn't begin with '#' (implicit directive)
- * 2) begins with "##" (implicit directive)
- * 3) begins with "#<"
- */
+ ** Handle inline text. Check if line
+ ** is one of the following forms:
+ **
+ ** 1) doesn't begin with '#' (implicit directive)
+ ** 2) begins with "##" (implicit directive)
+ ** 3) begins with "#<"
+ */
if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') {
int headers;
int inlineD;
char *cp;
cp = m_mktemp2(NULL, invo_name, NULL, &out);
- if (cp == NULL) adios("mhbuildsbr", "unable to create temporary file");
+ if (cp == NULL)
+ adios("mhbuildsbr", "unable to create temporary file");
/* use a temp file to collect the plain text lines */
ce->ce_file = add (cp, NULL);
int i;
if (headers >= 0 && uprf (buffer, DESCR_FIELD)
- && buffer[i = strlen (DESCR_FIELD)] == ':') {
+ && buffer[i = strlen (DESCR_FIELD)] == ':') {
headers = 1;
again_descr:
s2i++;
/*
- * check type specified (possibly implicitly)
- */
+ ** check type specified (possibly implicitly)
+ */
switch (ct->c_type = s2i->si_val) {
case CT_MESSAGE:
if (!mh_strcasecmp (ci->ci_subtype, "rfc822")) {
/* else fall... */
case CT_MULTIPART:
adios (NULL, "it doesn't make sense to define an in-line %s content",
- ct->c_type == CT_MESSAGE ? "message" : "multipart");
+ ct->c_type == CT_MESSAGE ? "message" :
+ "multipart");
/* NOTREACHED */
default:
}
/*
- * If we've reached this point, the next line
- * must be some type of explicit directive.
- */
+ ** If we've reached this point, the next line
+ ** must be some type of explicit directive.
+ */
/* check if directive is external-type */
extrnal = (buf[1] == '@');
break;
/*
- * Check if the directive specified a valid type.
- * This will happen if it was one of the following forms:
- *
- * #type/subtype (or)
- * #@type/subtype
- */
+ ** Check if the directive specified a valid type.
+ ** This will happen if it was one of the following forms:
+ **
+ ** #type/subtype (or)
+ ** #@type/subtype
+ */
if (s2i->si_key) {
if (!ci->ci_subtype)
adios (NULL, "missing subtype in \"#%s\"", ci->ci_type);
}
/*
- * #@type/subtype (external types directive)
- */
+ ** #@type/subtype (external types directive)
+ */
if (extrnal) {
struct exbody *e;
CT p;
ci->ci_magic = NULL;
/*
- * Since we are using the current Content structure to
- * hold information about the type of the external
- * reference, we need to create another Content structure
- * for the message/external-body to wrap it in.
- */
+ ** Since we are using the current Content structure to
+ ** hold information about the type of the external
+ ** reference, we need to create another Content
+ ** structure for the message/external-body to wrap
+ ** it in.
+ */
if ((ct = (CT) calloc (1, sizeof(*ct))) == NULL)
adios (NULL, "out of memory");
*ctp = ct;
}
/*
- * No [file] argument, so check profile for
- * method to compose content.
- */
+ ** No [file] argument, so check profile for
+ ** method to compose content.
+ */
snprintf (buffer, sizeof(buffer), "%s-compose-%s/%s",
invo_name, ci->ci_type, ci->ci_subtype);
if ((cp = context_find (buffer)) == NULL || *cp == '\0') {
- snprintf (buffer, sizeof(buffer), "%s-compose-%s", invo_name, ci->ci_type);
+ snprintf (buffer, sizeof(buffer), "%s-compose-%s",
+ invo_name, ci->ci_type);
if ((cp = context_find (buffer)) == NULL || *cp == '\0') {
content_error (NULL, ct, "don't know how to compose content");
done (1);
}
if (extrnal)
- adios (NULL, "external definition not allowed for \"#%s\"", ci->ci_type);
+ adios (NULL, "external definition not allowed for \"#%s\"",
+ ci->ci_type);
/*
- * Message directive
- * #forw [+folder] [msgs]
- */
+ ** Message directive
+ ** #forw [+folder] [msgs]
+ */
if (!mh_strcasecmp (ci->ci_type, "forw")) {
int msgnum;
char *folder, *arguments[MAXARGS];
free_ctinfo (ct);
/*
- * If there is more than one message to include, make this
- * a content of type "multipart/digest" and insert each message
- * as a subpart. If there is only one message, then make this
- * a content of type "message/rfc822".
- */
+ ** If there is more than one message to include, make this
+ ** a content of type "multipart/digest" and insert each message
+ ** as a subpart. If there is only one message, then make this
+ ** a content of type "message/rfc822".
+ */
if (mp->numsel > 1) {
/* we are forwarding multiple messages */
if (get_ctinfo ("multipart/digest", ct, 0) == NOTOK)
}
/*
- * #end
- */
+ ** #end
+ */
if (!mh_strcasecmp (ci->ci_type, "end")) {
free_content (ct);
*ctp = NULL;
}
/*
- * #begin [ alternative | parallel ]
- */
+ ** #begin [ alternative | parallel ]
+ */
if (!mh_strcasecmp (ci->ci_type, "begin")) {
if (!ci->ci_magic) {
vrsn = MULTI_MIXED;
}
/*
- * Unknown directive
- */
+ ** Unknown directive
+ */
adios (NULL, "unknown directive \"#%s\"", ci->ci_type);
return NOTOK; /* NOT REACHED */
}
/*
- * Fill out, or expand the various contents in the composition
- * draft. Read-in any necessary files. Parse and execute any
- * commands specified by profile composition strings.
- */
+** Fill out, or expand the various contents in the composition
+** draft. Read-in any necessary files. Parse and execute any
+** commands specified by profile composition strings.
+*/
static int
compose_content (CT ct)
}
/* first, we call compose_content on all the subparts */
- for (part = m->mp_parts, partnum = 1; part; part = part->mp_next, partnum++) {
+ for (part = m->mp_parts, partnum = 1; part;
+ part = part->mp_next, partnum++) {
CT p = part->mp_part;
sprintf (pp, "%d", partnum);
}
/*
- * If the -rfc934mode switch is given, then check all
- * the subparts of a multipart/digest. If they are all
- * message/rfc822, then mark this content and all
- * subparts with the rfc934 compatibility mode flag.
- */
+ ** If the -rfc934mode switch is given, then check all
+ ** the subparts of a multipart/digest. If they are all
+ ** message/rfc822, then mark this content and all
+ ** subparts with the rfc934 compatibility mode flag.
+ */
if (rfc934sw && ct->c_subtype == MULTI_DIGEST) {
int is934 = 1;
break;
/*
- * Discrete types (text/application/audio/image/video)
- */
+ ** Discrete types (text/application/audio/image/video)
+ */
default:
if (!ce->ce_file) {
pid_t child_id;
buflen = sizeof(buffer);
/*
- * Parse composition string into buffer
- */
+ ** Parse composition string into buffer
+ */
for ( ; *cp; cp++) {
if (*cp == '%') {
switch (*++cp) {
case 'a':
{
- /* insert parameters from directive */
+ /*
+ ** insert parameters from
+ ** directive
+ */
char **ep;
char *s = "";
case 'f':
/*
- * insert temporary filename where
- * content should be written
- */
+ ** insert temporary filename
+ ** where content should be
+ ** written
+ */
snprintf (bp, buflen, "%s", ce->ce_file);
break;
buflen -= len;
} else {
raw:
- *bp++ = *cp;
- *bp = '\0';
- buflen--;
+ *bp++ = *cp;
+ *bp = '\0';
+ buflen--;
}
}
/*
- * Scan the content.
- *
- * 1) choose a transfer encoding.
- * 2) check for clashes with multipart boundary string.
- * 3) for text content, figure out which character set is being used.
- *
- * If there is a clash with one of the contents and the multipart boundary,
- * this function will exit with NOTOK. This will cause the scanning process
- * to be repeated with a different multipart boundary. It is possible
- * (although highly unlikely) that this scan will be repeated multiple times.
- */
+** Scan the content.
+**
+** 1) choose a transfer encoding.
+** 2) check for clashes with multipart boundary string.
+** 3) for text content, figure out which character set is being used.
+**
+** If there is a clash with one of the contents and the multipart boundary,
+** this function will exit with NOTOK. This will cause the scanning process
+** to be repeated with a different multipart boundary. It is possible
+** (although highly unlikely) that this scan will be repeated multiple times.
+*/
static int
scan_content (CT ct)
CE ce = ct->c_cefile;
/*
- * handle multipart by scanning all subparts
- * and then checking their encoding.
- */
+ ** handle multipart by scanning all subparts
+ ** and then checking their encoding.
+ */
if (ct->c_type == CT_MULTIPART) {
struct multipart *m = (struct multipart *) ct->c_ctparams;
struct part *part;
if (scan_content (p) == NOTOK) /* choose encoding for subpart */
return NOTOK;
- /* if necessary, enlarge encoding for enclosing multipart */
+ /*
+ ** if necessary, enlarge encoding for enclosing
+ ** multipart
+ */
if (p->c_encoding == CE_BINARY)
ct->c_encoding = CE_BINARY;
if (p->c_encoding == CE_8BIT && ct->c_encoding != CE_BINARY)
}
/*
- * Decide what to check while scanning this content.
- */
+ ** Decide what to check while scanning this content.
+ */
switch (ct->c_type) {
case CT_TEXT:
check8bit = 1;
case CT_IMAGE:
case CT_VIDEO:
/*
- * Don't check anything for these types,
- * since we are forcing use of base64.
- */
+ ** Don't check anything for these types,
+ ** since we are forcing use of base64.
+ */
check8bit = 0;
checkebcdic = 0;
checklinelen = 0;
}
/*
- * Scan the unencoded content
- */
+ ** Scan the unencoded content
+ */
if (check8bit || checklinelen || checklinespace || checkboundary) {
if ((in = fopen (ce->ce_file, "r")) == NULL)
adios (ce->ce_file, "unable to open for reading");
while (fgets (buffer, sizeof(buffer) - 1, in)) {
/*
- * Check for 8bit data.
- */
+ ** Check for 8bit data.
+ */
if (check8bit) {
for (cp = buffer; *cp; cp++) {
if (!isascii (*cp)) {
contains8bit = 1;
- check8bit = 0; /* no need to keep checking */
+ /* no need to keep checking */
+ check8bit = 0;
}
/*
- * Check if character is ebcdic-safe. We only check
- * this if also checking for 8bit data.
- */
+ ** Check if character is ebcdic-safe.
+ ** We only check this if also checking
+ ** for 8bit data.
+ */
if (checkebcdic && !ebcdicsafe[*cp & 0xff]) {
ebcdicunsafe = 1;
- checkebcdic = 0; /* no need to keep checking */
+ /* no need to keep checking */
+ checkebcdic = 0;
}
}
}
/*
- * Check line length.
- */
+ ** Check line length.
+ */
if (checklinelen && (strlen (buffer) > CPERLIN + 1)) {
linelen = 1;
checklinelen = 0; /* no need to keep checking */
}
/*
- * Check if line ends with a space.
- */
- if (checklinespace && (cp = buffer + strlen (buffer) - 2) > buffer && isspace (*cp)) {
+ ** Check if line ends with a space.
+ */
+ if (checklinespace &&
+ (cp = buffer + strlen (buffer) - 2) >
+ buffer && isspace (*cp)) {
linespace = 1;
- checklinespace = 0; /* no need to keep checking */
+ /* no need to keep checking */
+ checklinespace = 0;
}
/*
- * Check if content contains a line that clashes
- * with our standard boundary for multipart messages.
- */
+ ** Check if content contains a line that clashes
+ ** with our standard boundary for multipart messages.
+ */
if (checkboundary && buffer[0] == '-' && buffer[1] == '-') {
for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
if (!isspace (*cp))
*++cp = '\0';
if (!strncmp(buffer + 2, prefix, len) && isdigit(buffer[2 + len])) {
boundaryclash = 1;
- checkboundary = 0; /* no need to keep checking */
+ /* no need to keep checking */
+ checkboundary = 0;
}
}
}
}
/*
- * Decide which transfer encoding to use.
- */
+ ** Decide which transfer encoding to use.
+ */
switch (ct->c_type) {
case CT_TEXT:
/*
- * If the text content didn't specify a character
- * set, we need to figure out which one was used.
- */
+ ** If the text content didn't specify a character
+ ** set, we need to figure out which one was used.
+ */
t = (struct text *) ct->c_ctparams;
if (t->tx_charset == CHARSET_UNSPECIFIED) {
CI ci = &ct->c_ctinfo;
/*
- * Scan the content structures, and build header
- * fields that will need to be output into the
- * message.
- */
+** Scan the content structures, and build header
+** fields that will need to be output into the
+** message.
+*/
static int
build_headers (CT ct)
CI ci = &ct->c_ctinfo;
/*
- * If message is type multipart, then add the multipart
- * boundary to the list of attribute/value pairs.
- */
+ ** If message is type multipart, then add the multipart
+ ** boundary to the list of attribute/value pairs.
+ */
if (ct->c_type == CT_MULTIPART) {
char *cp;
static int level = 0; /* store nesting level */
}
/*
- * Skip the output of Content-Type, parameters, content
- * description and disposition, and Content-ID if the
- * content is of type "message" and the rfc934 compatibility
- * flag is set (which means we are inside multipart/digest
- * and the switch -rfc934mode was given).
- */
+ ** Skip the output of Content-Type, parameters, content
+ ** description and disposition, and Content-ID if the
+ ** content is of type "message" and the rfc934 compatibility
+ ** flag is set (which means we are inside multipart/digest
+ ** and the switch -rfc934mode was given).
+ */
if (ct->c_type == CT_MESSAGE && ct->c_rfc934)
goto skip_headers;
/*
- * output the content type and subtype
- */
+ ** output the content type and subtype
+ */
np = add (TYPE_FIELD, NULL);
vp = concat (" ", ci->ci_type, "/", ci->ci_subtype, NULL);
&& ((struct exbody *) ct->c_ctparams)->eb_body;
/*
- * Append the attribute/value pairs to
- * the end of the Content-Type line.
- */
+ ** Append the attribute/value pairs to
+ ** the end of the Content-Type line.
+ */
for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
if (mailbody && !mh_strcasecmp (*ap, "body"))
continue;
}
/*
- * Append any RFC-822 comment to the end of
- * the Content-Type line.
- */
+ ** Append any RFC-822 comment to the end of
+ ** the Content-Type line.
+ */
if (ci->ci_comment) {
snprintf (buffer, sizeof(buffer), "(%s)", ci->ci_comment);
if (len + 1 + (cc = 2 + strlen (ci->ci_comment)) >= CPERLIN) {
add_header (ct, np, vp);
/*
- * output the Content-ID, unless disabled by -nocontentid
- */
+ ** output the Content-ID, unless disabled by -nocontentid
+ */
if (contentidsw && ct->c_id) {
np = add (ID_FIELD, NULL);
vp = concat (" ", ct->c_id, NULL);
}
/*
- * output the Content-Description
- */
+ ** output the Content-Description
+ */
if (ct->c_descr) {
np = add (DESCR_FIELD, NULL);
vp = concat (" ", ct->c_descr, NULL);
}
/*
- * output the Content-Disposition
- */
+ ** output the Content-Disposition
+ */
if (ct->c_dispo) {
np = add (DISPO_FIELD, NULL);
vp = concat (" ", ct->c_dispo, NULL);
skip_headers:
/*
- * If this is the internal content structure for a
- * "message/external", then we are done with the
- * headers (since it has no body).
- */
+ ** If this is the internal content structure for a
+ ** "message/external", then we are done with the
+ ** headers (since it has no body).
+ */
if (ct->c_ctexbody)
return OK;
/*
- * output the Content-MD5
- */
+ ** output the Content-MD5
+ */
if (checksw) {
np = add (MD5_FIELD, NULL);
vp = calculate_digest (ct, (ct->c_encoding == CE_QUOTED) ? 1 : 0);
}
/*
- * output the Content-Transfer-Encoding
- */
+ ** output the Content-Transfer-Encoding
+ */
switch (ct->c_encoding) {
case CE_7BIT:
/* Nothing to output */
}
/*
- * Additional content specific header processing
- */
+ ** Additional content specific header processing
+ */
switch (ct->c_type) {
case CT_MULTIPART:
{
}
} else {
while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), in)) > 0)
- MD5Update (&mdContext, (unsigned char *) buffer, (unsigned int) cc);
+ MD5Update (&mdContext, (unsigned char *) buffer,
+ (unsigned int) cc);
}
/* md5 finalization. Write digest and zero md5 context */