From: Ken Hornstein Date: Thu, 9 Jan 2014 21:03:21 +0000 (-0500) Subject: Preliminary Attach: header support. Untested just yet. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/430ffdd38f6ea76f20d8559a3e2a6f7835117d47?hp=8f23987f274cfa41bce9d78ac0f818aa6bfeccf3 Preliminary Attach: header support. Untested just yet. --- diff --git a/Makefile.am b/Makefile.am index 83118f63..6dc80179 100644 --- a/Makefile.am +++ b/Makefile.am @@ -316,7 +316,7 @@ uip_mark_LDADD = $(LDADD) $(POSTLINK) uip_mhbuild_SOURCES = uip/mhbuild.c uip/mhbuildsbr.c uip/mhcachesbr.c \ uip/mhlistsbr.c uip/mhoutsbr.c uip/mhmisc.c \ - uip/mhfree.c uip/mhparse.c uip/md5.c + uip/mhfree.c uip/mhparse.c uip/md5.c uip/attach.c uip_mhbuild_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK) uip_mhfixmsg_SOURCES = uip/mhfixmsg.c uip/mhparse.c uip/mhcachesbr.c \ diff --git a/h/mime.h b/h/mime.h index 2f8a6a32..2ed5378c 100644 --- a/h/mime.h +++ b/h/mime.h @@ -12,6 +12,7 @@ #define DESCR_FIELD "Content-Description" #define DISPO_FIELD "Content-Disposition" #define MD5_FIELD "Content-MD5" +#define ATTACH_FIELD "Attach" #define isatom(c) (isascii((unsigned char) c) \ && !isspace ((unsigned char) c) \ diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index e4499170..58540f1b 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -52,6 +52,11 @@ pid_t xpid = 0; static char prefix[] = "----- =_aaaaaaaaaa"; +struct attach_list { + char *filename; + struct attach_list *next; +}; + /* * Maximum size of URL token in message/external-body */ @@ -73,6 +78,7 @@ void free_encoding (CT, int); * static prototypes */ static int init_decoded_content (CT); +static void setup_attach_content(CT, const char *); static char *fgetstr (char *, int, FILE *); static int user_content (FILE *, char *, char *, CT *); static void set_id (CT, int); @@ -134,6 +140,7 @@ build_mime (char *infile, int directives, int header_encoding) FILE *in; HF hp; m_getfld_state_t gstate = 0; + struct attach_list *attach_head = NULL, *attach_tail = NULL, *at_entry; directive_init(directives); @@ -197,8 +204,25 @@ build_mime (char *infile, int directives, int header_encoding) vp = add (buf, vp); /* add to previous value */ } - /* Now add the header data to the list */ - add_header (ct, np, vp); + /* + * Now add the header data to the list, unless it's an attach + * header; in that case, add it to our attach list + */ + + if (strcasecmp(ATTACH_FIELD, np) == 0) { + struct attach_list *entry; + free(np); + entry = mh_xmalloc(sizeof(*entry)); + entry->filename = vp; + if (! attach_tail) { + attach_tail->next = entry; + attach_tail = entry; + } else { + attach_head = attach_tail = entry; + } + } else { + add_header (ct, np, vp); + } finish_field: /* if this wasn't the last header field, then continue */ @@ -286,6 +310,44 @@ finish_field: */ fclose (in); + /* + * Add any Attach headers to the list of MIME parts at the end of the + * message. + */ + + for (at_entry = attach_head; at_entry; ) { + struct attach_list *at_prev = at_entry; + struct part *part; + CT p; + + if (! access(at_entry->filename, R_OK)) { + adios("reading", "Unable to open %s for", at_entry->filename); + } + + if ((p = (CT) calloc (1, sizeof(*p))) == NULL) + adios(NULL, "out of memory"); + + init_decoded_content(p); + + /* + * Initialize our content structure based on the filename, + * and fill in all of the relevant fields. Also place MIME + * parameters in the attributes array. + */ + + setup_attach_content(p, at_entry->filename); + + if ((part = (struct part *) calloc (1, sizeof(*part))) == NULL) + adios (NULL, "out of memory"); + *pp = part; + pp = &part->mp_next; + part->mp_part = p; + + at_entry = at_entry->next; + free(at_prev->filename); + free(at_prev); + } + /* check if any contents were found */ if (!m->mp_parts) adios (NULL, "no content directives found"); @@ -1709,3 +1771,102 @@ calculate_digest (CT ct, int asciiP) vp = concat (" ", outbuf, "\n", NULL); return vp; } + +/* + * Set things up for the content structure for file "filename" that + * we want to attach + */ + +static void +setup_attach_content(CT ct, const char *filename) +{ + char *type, **ap, **ep; + struct str2init *s2i; + + if (! (type = mime_type(filename))) { + adios(NULL, "Unable to determine MIME type of \"%s\"", filename); + } + + /* + * Parse the Content-Type. get_ctinfo() parses MIME parameters, but + * since we're just feeding it a MIME type we have to add those ourself. + * Map that to a valid content-type label and call any initialization + * function. + */ + + if (get_ctinfo(type, ct, 0) == NOTOK) + done(1); + + free(type); + + for (s2i = str2cts; s2i->si_key; s2i++) + if (strcasecmp(ct->c_ctinfo.ci_type, s2i->si_key) == 0) + break; + if (!s2i->si_key && !uprf(ct->c_ctinfo.ci_type, "X-")) + s2i++; + + /* + * Make sure the type isn't incompatible with what we can handle + */ + + switch (ct->c_type = s2i->si_val) { + case CT_MULTIPART: + adios (NULL, "multipart types must be specified by mhbuild directives"); + /* NOTREACHED */ + + case CT_MESSAGE: + if (strcasecmp(ct->c_ctinfo.ci_subtype, "partial") == 0) + adios(NULL, "Sorry, %s/%s isn't supported", ct->c_ctinfo.ci_type, + ct->c_ctinfo.ci_subtype); + if (strcasecmp(ct->c_ctinfo.ci_subtype, "external-body") == 0) + adios(NULL, "external-body messages must be specified " + "by mhbuild directives"); + /* Fall through */ + + default: + /* + * This sets the subtype, if it's significant + */ + if ((ct->c_ctinitfnx = s2i->si_init)) + (*ct->c_ctinitfnx)(ct); + break; + } + + /* + * Feed in a few attributes; specifically, the name attribute, the + * content-description, and the content-disposition. + */ + + for (ap = ct->c_ctinfo.ci_attrs, ep = ct->c_ctinfo.ci_values; *ap; + ap++, ep++) { + if (strcasecmp(*ap, "name") == 0) { + if (*ep) + free(*ep); + *ep = getcpy(filename); + break; + } + } + + if (*ap == NULL) { + *ap = getcpy("name"); + *ep = getcpy(filename); + } + + ct->c_descr = getcpy(filename); + + /* + * If it's a text/calendar, we need to make sure it's an inline, + * otherwise it won't work with some calendar programs. Otherwise + * assume attachment + */ + + if (strcasecmp(ct->c_ctinfo.ci_type, "text") == 0 && + strcasecmp(ct->c_ctinfo.ci_subtype, "calendar") == 0) { + ct->c_dispo = getcpy("inline; filename=\""); + } else { + ct->c_dispo = getcpy("attachment; filename=\""); + } + + ct->c_dispo = add(filename, ct->c_dispo); + ct->c_dispo = add("\"", ct->c_dispo); +}