/*
- * mhparse.c -- routines to parse the contents of MIME messages
- *
- * This code is Copyright (c) 2002, by the authors of nmh. See the
- * COPYRIGHT file in the root directory of the nmh distribution for
- * complete copyright information.
- */
+** mhparse.c -- routines to parse the contents of MIME messages
+**
+** This code is Copyright (c) 2002, by the authors of nmh. See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
#include <h/mh.h>
#include <fcntl.h>
int checksw = 0; /* check Content-MD5 field */
/*
- * Directory to place temp files. This must
- * be set before these routines are called.
- */
+** Directory to place temp files. This must
+** be set before these routines are called.
+*/
char *tmp;
/*
- * Structures for TEXT messages
- */
+** Structures for TEXT messages
+*/
struct k2v SubText[] = {
{ "plain", TEXT_PLAIN },
{ "richtext", TEXT_RICHTEXT }, /* defined in RFC-1341 */
};
/*
- * Structures for MULTIPART messages
- */
+** Structures for MULTIPART messages
+*/
struct k2v SubMultiPart[] = {
{ "mixed", MULTI_MIXED },
{ "alternative", MULTI_ALTERNATE },
};
/*
- * Structures for MESSAGE messages
- */
+** Structures for MESSAGE messages
+*/
struct k2v SubMessage[] = {
{ "rfc822", MESSAGE_RFC822 },
{ "partial", MESSAGE_PARTIAL },
};
/*
- * Structure for APPLICATION messages
- */
+** Structure for APPLICATION messages
+*/
struct k2v SubApplication[] = {
{ "octet-stream", APPLICATION_OCTETS },
{ "postscript", APPLICATION_POSTSCRIPT },
void free_encoding (CT, int);
/*
- * static prototypes
- */
+** static prototypes
+*/
static CT get_content (FILE *, char *, int);
static int get_comment (CT, unsigned char **, int);
};
/*
- * NOTE WELL: si_key MUST NOT have value of NOTOK
- *
- * si_key is 1 if access method is anonymous.
- */
+** NOTE WELL: si_key MUST NOT have value of NOTOK
+**
+** si_key is 1 if access method is anonymous.
+*/
struct str2init str2methods[] = {
{ "afs", 1, InitFile },
{ "anon-ftp", 1, InitFTP },
/*
- * Main entry point for parsing a MIME message or file.
- * It returns the Content structure for the top level
- * entity in the file.
- */
+** Main entry point for parsing a MIME message or file.
+** It returns the Content structure for the top level
+** entity in the file.
+*/
CT
parse_mime (char *file)
{
CT ct;
/*
- * Check if file is actually standard input
- */
+ ** Check if file is actually standard input
+ */
if ((is_stdin = !(strcmp (file, "-")))) {
char *tfile = m_mktemp2(NULL, invo_name, NULL, &fp);
if (tfile == NULL) {
/*
- * Main routine for reading/parsing the headers
- * of a message content.
- *
- * toplevel = 1 # we are at the top level of the message
- * toplevel = 0 # we are inside message type or multipart type
- * # other than multipart/digest
- * toplevel = -1 # we are inside multipart/digest
- * NB: on failure we will fclose(in)!
- */
+** Main routine for reading/parsing the headers
+** of a message content.
+**
+** toplevel = 1 # we are at the top level of the message
+** toplevel = 0 # we are inside message type or multipart type
+** # other than multipart/digest
+** toplevel = -1 # we are inside multipart/digest
+** NB: on failure we will fclose(in)!
+*/
static CT
get_content (FILE *in, char *file, int toplevel)
ct->c_begin = ftell (ct->c_fp) + 1;
/*
- * Parse the header fields for this
- * content into a linked list.
- */
+ ** Parse the header fields for this
+ ** content into a linked list.
+ */
for (compnum = 1, state = FLD;;) {
switch (state = m_getfld (state, name, buf, sizeof(buf), in)) {
case FLD:
}
/*
- * Read the content headers. We will parse the
- * MIME related header fields into their various
- * structures and set internal flags related to
- * content type/subtype, etc.
- */
+ ** Read the content headers. We will parse the
+ ** MIME related header fields into their various
+ ** structures and set internal flags related to
+ ** content type/subtype, etc.
+ */
hp = ct->c_first_hf; /* start at first header field */
while (hp) {
admonish (NULL, "message %s has unknown value for %s: field (%s)",
ct->c_file, VRSN_FIELD, cp);
}
- }
- else if (!mh_strcasecmp (hp->name, TYPE_FIELD)) {
- /* Get Content-Type field */
+
+ } else if (!mh_strcasecmp (hp->name, TYPE_FIELD)) {
+ /* Get Content-Type field */
struct str2init *s2i;
CI ci = &ct->c_ctinfo;
goto out;
/*
- * Set the Init function and the internal
- * flag for this content type.
- */
+ ** Set the Init function and the internal
+ ** flag for this content type.
+ */
for (s2i = str2cts; s2i->si_key; s2i++)
if (!mh_strcasecmp (ci->ci_type, s2i->si_key))
break;
s2i++;
ct->c_type = s2i->si_val;
ct->c_ctinitfnx = s2i->si_init;
- }
- else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) {
- /* Get Content-Transfer-Encoding field */
+
+ } else if (!mh_strcasecmp (hp->name, ENCODING_FIELD)) {
+ /* Get Content-Transfer-Encoding field */
char c;
unsigned char *cp, *dp;
struct str2init *s2i;
/*
- * Check if we've already seen the
- * Content-Transfer-Encoding field
- */
+ ** Check if we've already seen the
+ ** Content-Transfer-Encoding field
+ */
if (ct->c_celine) {
advise (NULL, "message %s has multiple %s: fields",
ct->c_file, ENCODING_FIELD);
*dp = '\0';
/*
- * Find the internal flag and Init function
- * for this transfer encoding.
- */
+ ** Find the internal flag and Init function
+ ** for this transfer encoding.
+ */
for (s2i = str2ces; s2i->si_key; s2i++)
if (!mh_strcasecmp (cp, s2i->si_key))
break;
/* Call the Init function for this encoding */
if (s2i->si_init && (*s2i->si_init) (ct) == NOTOK)
goto out;
- }
- else if (!mh_strcasecmp (hp->name, MD5_FIELD)) {
- /* Get Content-MD5 field */
+
+ } else if (!mh_strcasecmp (hp->name, MD5_FIELD)) {
+ /* Get Content-MD5 field */
unsigned char *cp, *dp;
char *ep;
readDigest (ct, cp);
free (ep);
ct->c_digested++;
- }
- else if (!mh_strcasecmp (hp->name, ID_FIELD)) {
- /* Get Content-ID field */
+
+ } else if (!mh_strcasecmp (hp->name, ID_FIELD)) {
+ /* Get Content-ID field */
ct->c_id = add (hp->value, ct->c_id);
- }
- else if (!mh_strcasecmp (hp->name, DESCR_FIELD)) {
- /* Get Content-Description field */
+
+ } else if (!mh_strcasecmp (hp->name, DESCR_FIELD)) {
+ /* Get Content-Description field */
ct->c_descr = add (hp->value, ct->c_descr);
- }
- else if (!mh_strcasecmp (hp->name, DISPO_FIELD)) {
- /* Get Content-Disposition field */
+
+ } else if (!mh_strcasecmp (hp->name, DISPO_FIELD)) {
+ /* Get Content-Disposition field */
ct->c_dispo = add (hp->value, ct->c_dispo);
}
}
/*
- * Check if we saw a Content-Type field.
- * If not, then assign a default value for
- * it, and the Init function.
- */
+ ** Check if we saw a Content-Type field.
+ ** If not, then assign a default value for
+ ** it, and the Init function.
+ */
if (!ct->c_ctline) {
/*
- * If we are inside a multipart/digest message,
- * so default type is message/rfc822
- */
+ ** If we are inside a multipart/digest message,
+ ** so default type is message/rfc822
+ */
if (toplevel < 0) {
if (get_ctinfo ("message/rfc822", ct, 0) == NOTOK)
goto out;
ct->c_ctinitfnx = InitMessage;
} else {
/*
- * Else default type is text/plain
- */
+ ** Else default type is text/plain
+ */
if (get_ctinfo ("text/plain", ct, 0) == NOTOK)
goto out;
ct->c_type = CT_TEXT;
/*
- * small routine to add header field to list
- */
+** small routine to add header field to list
+*/
int
add_header (CT ct, char *name, char *value)
}
-/* Make sure that buf contains at least one appearance of name,
- followed by =. If not, insert both name and value, just after
- first semicolon, if any. Note that name should not contain a
- trailing =. And quotes will be added around the value. Typical
- usage: make sure that a Content-Disposition header contains
- filename="foo". If it doesn't and value does, use value from
- that. */
+/*
+** Make sure that buf contains at least one appearance of name,
+** followed by =. If not, insert both name and value, just after
+** first semicolon, if any. Note that name should not contain a
+** trailing =. And quotes will be added around the value. Typical
+** usage: make sure that a Content-Disposition header contains
+** filename="foo". If it doesn't and value does, use value from
+** that.
+*/
static char *
incl_name_value (unsigned char *buf, char *name, char *value) {
char *newbuf = buf;
*cp = '\0';
}
- insertion = concat ("; ", name, "=", "\"", value, "\"", NULL);
+ insertion = concat ("; ", name, "=", "\"", value, "\"",
+ NULL);
- /* Insert at first semicolon, if any. If none, append to
- end. */
+ /*
+ ** Insert at first semicolon, if any.
+ ** If none, append to end.
+ */
prefix = add (buf, NULL);
if ((cp = strchr (prefix, ';'))) {
suffix = concat (cp, NULL);
*cp = '\0';
- newbuf = concat (prefix, insertion, suffix, "\n", NULL);
+ newbuf = concat (prefix, insertion, suffix,
+ "\n", NULL);
free (suffix);
} else {
/* Append to end. */
return newbuf;
}
-/* Extract just name_suffix="foo", if any, from value. If there isn't
- one, return the entire value. Note that, for example, a name_suffix
- of name will match filename="foo", and return foo. */
+/*
+** Extract just name_suffix="foo", if any, from value. If there isn't
+** one, return the entire value. Note that, for example, a name_suffix
+** of name will match filename="foo", and return foo.
+*/
static char *
extract_name_value (char *name_suffix, char *value) {
char *extracted_name_value = value;
}
/*
- * Parse Content-Type line and (if `magic' is non-zero) mhbuild composition
- * directives. Fills in the information of the CTinfo structure.
- */
+** Parse Content-Type line and (if `magic' is non-zero) mhbuild composition
+** directives. Fills in the information of the CTinfo structure.
+*/
int
get_ctinfo (unsigned char *cp, CT ct, int magic)
{
if (!*ci->ci_type) {
advise (NULL, "invalid %s: field in message %s (empty type)",
- TYPE_FIELD, ct->c_file);
+ TYPE_FIELD, ct->c_file);
return NOTOK;
}
return NOTOK;
/*
- * Parse attribute/value pairs given with Content-Type
- */
+ ** Parse attribute/value pairs given with Content-Type
+ */
ep = (ap = ci->ci_attrs) + NPARMS;
while (*cp == ';') {
char *vp;
}
/*
- * Get any <Content-Id> given in buffer
- */
+ ** Get any <Content-Id> given in buffer
+ */
if (magic && *cp == '<') {
if (ct->c_id) {
free (ct->c_id);
}
/*
- * Get any [Content-Description] given in buffer.
- */
+ ** Get any [Content-Description] given in buffer.
+ */
if (magic && *cp == '[') {
ct->c_descr = ++cp;
for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
}
/*
- * Get any {Content-Disposition} given in buffer.
- */
+ ** Get any {Content-Disposition} given in buffer.
+ */
if (magic && *cp == '{') {
ct->c_dispo = ++cp;
for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
}
/*
- * Check if anything is left over
- */
+ ** Check if anything is left over
+ */
if (*cp) {
if (magic) {
ci->ci_magic = add (cp, NULL);
/*
- * If there is a Content-Disposition header and
- * it doesn't have a *filename=, extract it from
- * the magic contents. The r1bindex call skips
- * any leading directory components.
- */
+ ** If there is a Content-Disposition header and
+ ** it doesn't have a *filename=, extract it from
+ ** the magic contents. The r1bindex call skips
+ ** any leading directory components.
+ */
if (ct->c_dispo)
ct->c_dispo = incl_name_value (ct->c_dispo, "filename", r1bindex (extract_name_value ("name", ci->ci_magic), '/'));
} else
/*
- * CONTENTS
- *
- * Handles content types audio, image, and video.
- * There's not much to do right here.
- */
+** CONTENTS
+**
+** Handles content types audio, image, and video.
+** There's not much to do right here.
+*/
static int
InitGeneric (CT ct)
/*
- * TEXT
- */
+** TEXT
+*/
static int
InitText (CT ct)
}
/*
- * If we can not handle character set natively,
- * then check profile for string to modify the
- * terminal or display method.
- *
- * termproc is for mhshow, though mhlist -debug prints it, too.
- */
+ ** If we can not handle character set natively,
+ ** then check profile for string to modify the
+ ** terminal or display method.
+ **
+ ** termproc is for mhshow, though mhlist -debug prints it, too.
+ */
if (chset != NULL && !check_charset (chset, strlen (chset))) {
snprintf (buffer, sizeof(buffer), "%s-charset-%s", invo_name, chset);
if ((cp = context_find (buffer)))
/*
- * MULTIPART
- */
+** MULTIPART
+*/
static int
InitMultiPart (CT ct)
FILE *fp;
/*
- * The encoding for multipart messages must be either
- * 7bit, 8bit, or binary (per RFC2045).
- */
+ ** The encoding for multipart messages must be either
+ ** 7bit, 8bit, or binary (per RFC2045).
+ */
if (ct->c_encoding != CE_7BIT && ct->c_encoding != CE_8BIT
&& ct->c_encoding != CE_BINARY) {
admonish (NULL,
ct->c_subtype = kv->kv_value;
/*
- * Check for "boundary" parameter, which is
- * required for multipart messages.
- */
+ ** Check for "boundary" parameter, which is
+ ** required for multipart messages.
+ */
bp = 0;
for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
if (!mh_strcasecmp (*ap, "boundary")) {
reverse_parts (ct);
/*
- * label all subparts with part number, and
- * then initialize the content of the subpart.
- */
+ ** label all subparts with part number, and
+ ** then initialize the content of the subpart.
+ */
{
int partnum;
char *pp;
/*
- * reverse the order of the parts of a multipart
- */
+** reverse the order of the parts of a multipart
+*/
static void
reverse_parts (CT ct)
/*
- * MESSAGE
- */
+** MESSAGE
+*/
static int
InitMessage (CT ct)
adios (NULL, "out of memory");
ct->c_ctparams = (void *) p;
- /* scan for parameters "id", "number", and "total" */
+ /*
+ ** scan for parameters "id", "number",
+ ** and "total"
+ */
for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
if (!mh_strcasecmp (*ap, "id")) {
p->pm_partid = add (*ep, NULL);
/*
- * APPLICATION
- */
+** APPLICATION
+*/
static int
InitApplication (CT ct)
/*
- * TRANSFER ENCODINGS
- */
+** TRANSFER ENCODINGS
+*/
static int
init_encoding (CT ct, OpenCEFunc openfnx)
/*
- * BASE64
- */
+** BASE64
+*/
static unsigned char b642nib[0x80] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
}
if (cp != NULL && *cp != '\0') {
if (ce->ce_unlink) {
- // Temporary file already exists, so we rename to
- // version with extension.
+ /*
+ ** Temporary file already exists, so we rename to
+ ** version with extension.
+ */
char *file_org = strdup(ce->ce_file);
ce->ce_file = add (cp, ce->ce_file);
if (rename(file_org, ce->ce_file)) {
/*
- * QUOTED PRINTABLE
- */
+** QUOTED PRINTABLE
+*/
static char hex2nib[0x80] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
if (ce->ce_file) {
if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading");
return NOTOK;
}
goto ready_to_go;
char *file_org = strdup(ce->ce_file);
ce->ce_file = add (cp, ce->ce_file);
if (rename(file_org, ce->ce_file)) {
- adios (ce->ce_file, "unable to rename %s to ", file_org);
+ adios (ce->ce_file, "unable to rename %s to ",
+ file_org);
}
free(file_org);
}
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading/writing");
return NOTOK;
}
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading/writing");
return NOTOK;
}
content_error (ce->ce_file, ct, "error writing to");
goto clean_up;
}
- /* finished escape sequence; next may
- * be literal or a new escape
- * sequence */
+ /*
+ ** finished escape sequence; next may
+ ** be literal or a new escape sequence
+ */
quoted = 0;
}
/* on to next byte */
/* not in an escape sequence */
if (*cp == '=') {
- /* starting an escape sequence, or invalid '='? */
+ /*
+ ** starting an escape sequence,
+ ** or invalid '='?
+ */
if (cp + 1 < ep && cp[1] == '\n') {
/* "=\n" soft line break, eat the \n */
cp++;
continue;
}
if (cp + 1 >= ep || cp + 2 >= ep) {
- /* We don't have 2 bytes left, so this is an invalid
- * escape sequence; just show the raw bytes (below). */
+ /*
+ ** We don't have 2 bytes left,
+ ** so this is an invalid escape
+ ** sequence; just show the raw bytes
+ ** (below).
+ */
} else if (isxdigit (cp[1]) && isxdigit (cp[2])) {
- /* Next 2 bytes are hex digits, making this a valid escape
- * sequence; let's decode it (above). */
+ /*
+ ** Next 2 bytes are hex digits,
+ ** making this a valid escape
+ ** sequence; let's decode it (above).
+ */
quoted = 1;
continue;
} else {
- /* One or both of the next 2 is out of range, making this
- * an invalid escape sequence; just show the raw bytes
- * (below). */
+ /*
+ ** One or both of the next 2 is
+ ** out of range, making this an
+ ** invalid escape sequence; just
+ ** show the raw bytes (below).
+ */
}
}
/*
- * 7BIT
- */
+** 7BIT
+*/
static int
Init7Bit (CT ct)
if (ce->ce_file) {
if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading");
return NOTOK;
}
goto ready_to_go;
}
if (cp != NULL && *cp != '\0') {
if (ce->ce_unlink) {
- // Temporary file already exists, so we rename to
- // version with extension.
+ /*
+ ** Temporary file already exists, so we rename to
+ ** version with extension.
+ */
char *file_org = strdup(ce->ce_file);
ce->ce_file = add (cp, ce->ce_file);
if (rename(file_org, ce->ce_file)) {
- adios (ce->ce_file, "unable to rename %s to ", file_org);
+ adios (ce->ce_file, "unable to rename %s to ",
+ file_org);
}
free(file_org);
}
if ((ce->ce_fp = fopen (ce->ce_file, "w+")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading/writing");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading/writing");
return NOTOK;
}
CI ci = &ct->c_ctinfo;
len = 0;
- fprintf (ce->ce_fp, "%s: %s/%s", TYPE_FIELD, ci->ci_type, ci->ci_subtype);
+ fprintf (ce->ce_fp, "%s: %s/%s", TYPE_FIELD, ci->ci_type,
+ ci->ci_subtype);
len += strlen (TYPE_FIELD) + 2 + strlen (ci->ci_type)
+ 1 + strlen (ci->ci_subtype);
for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
putc (';', ce->ce_fp);
len++;
- snprintf (buffer, sizeof(buffer), "%s=\"%s\"", *ap, *ep);
+ snprintf (buffer, sizeof(buffer), "%s=\"%s\"",
+ *ap, *ep);
if (len + 1 + (cc = strlen (buffer)) >= CPERLIN) {
fputs ("\n\t", ce->ce_fp);
/*
- * External
- */
+** External
+*/
static int
openExternal (CT ct, CT cb, CE ce, char **file, int *fd)
if (ce->ce_file) {
if ((ce->ce_fp = fopen (ce->ce_file, "r")) == NULL) {
- content_error (ce->ce_file, ct, "unable to fopen for reading");
+ content_error (ce->ce_file, ct,
+ "unable to fopen for reading");
return NOTOK;
}
goto ready_already;
}
/*
- * File
- */
+** File
+*/
static int
InitFile (CT ct)
}
/*
- * FTP
- */
+** FTP
+*/
static int
InitFTP (CT ct)
buflen = sizeof(buffer);
/*
- * Construct the query message for user
- */
+ ** Construct the query message for user
+ */
snprintf (bp, buflen, "Retrieve %s", e->eb_name);
len = strlen (bp);
bp += len;
snprintf (bp, buflen, "? ");
/*
- * Now, check the answer
- */
+ ** Now, check the answer
+ */
if (!getanswer (buffer))
return NOTOK;
if (e->eb_flags) {
user = "anonymous";
- snprintf (buffer, sizeof(buffer), "%s@%s", getusername (), LocalName ());
+ snprintf (buffer, sizeof(buffer), "%s@%s", getusername (),
+ LocalName ());
pass = buffer;
} else {
ruserpass (e->eb_site, &username, &password);
caching = 0;
cachefile[0] = '\0';
if ((!e->eb_permission || mh_strcasecmp (e->eb_permission, "read-write"))
- && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id,
- cachefile, sizeof(cachefile)) != NOTOK) {
+ && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id,
+ cachefile, sizeof(cachefile)) != NOTOK) {
if (*file == NULL) {
ce->ce_unlink = 0;
caching = 1;
/*
- * Mail
- */
+** Mail
+*/
static int
InitMail (CT ct)
return NOTOK;
}
- /* showproc is for mhshow and mhstore, though mhlist -debug
- * prints it, too. */
+ /*
+ ** showproc is for mhshow and mhstore, though mhlist -debug
+ ** prints it, too.
+ */
if (ct->c_showproc)
free (ct->c_showproc);
ct->c_showproc = add ("true", NULL);
}
if (bitno != 18) {
if (debugsw)
- fprintf (stderr, "premature ending (bitno %d)\n", bitno);
+ fprintf (stderr, "premature ending (bitno %d)\n",
+ bitno);
return NOTOK;
}