From 5ff96d61ee5af34956ae958a0bc72ee78734a4d7 Mon Sep 17 00:00:00 2001 From: David Levine Date: Tue, 21 Feb 2006 03:58:31 +0000 Subject: [PATCH] * h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c, uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man: added -attachformat switch to send, to support alternate MIME header contents when using -attach. See send man page for description. --- ChangeLog | 6 +++ h/mh.h | 2 + h/prototypes.h | 2 +- man/send.man | 41 ++++++++++++++++++ uip/mhbuildsbr.c | 126 ++++++++++++++++++++++++++++++++---------------------- uip/send.c | 21 ++++++++- uip/sendsbr.c | 112 +++++++++++++++++++++++++++++------------------- uip/viamail.c | 2 +- uip/whatnowsbr.c | 21 ++++++++- 9 files changed, 233 insertions(+), 100 deletions(-) diff --git a/ChangeLog b/ChangeLog index 79d6428..2e6103c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2006-02-20 David Levine + * h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c, + uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man: + added -attachformat switch to send, to support alternate MIME + header contents when using -attach. See send man page for + description. + * man/mhbuild.man: wrapped one appearance of "Content-Disposition" with quotes, to be consistent with others. diff --git a/h/mh.h b/h/mh.h index 81a6021..130bfde 100644 --- a/h/mh.h +++ b/h/mh.h @@ -58,6 +58,8 @@ struct swit { extern struct swit anoyes[]; /* standard yes/no switches */ +#define ATTACHFORMATS 3 /* Number of send attach formats. */ + /* * general folder attributes */ diff --git a/h/prototypes.h b/h/prototypes.h index de57cb8..1d1d456 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -158,7 +158,7 @@ void annopreserve(int); int distout (char *, char *, char *); void replout (FILE *, char *, char *, struct msgs *, int, int, char *, char *, char *); -int sendsbr (char **, int, char *, struct stat *, int, char *); +int sendsbr (char **, int, char *, struct stat *, int, char *, int); int what_now (char *, int, int, char *, char *, int, struct msgs *, char *, int, char *); diff --git a/man/send.man b/man/send.man index 65a5d1e..57f37b7 100644 --- a/man/send.man +++ b/man/send.man @@ -42,6 +42,8 @@ send \- send a message .RB [ \-help ] .RB [ \-attach .IR header-field-name ] +.RB [ \-attachformat +.IR 0 " | " 1 " | " 2 ] .ad .SH DESCRIPTION .B Send @@ -101,6 +103,44 @@ Finally, a description attribute is generated by running the .I file command on the file. .PP +The +.B -attachformat +option specifies the MIME header field formats: a value of +.B 0, +the default, +includes the +.I x-unix-mode +attribute as noted above. A value of +.B 1 +suppresses both that and the \*(lqContent-Description\*(rq header, and +adds a \*(lqContent-Disposition\*(rq header. A value of +.B 2 +adds the file +.I modification-date +parameter to the \*(lqContent-Disposition\*(rq header. You can +specify one value in your profile, and override it for individual +messages at the +.I whatnow +prompt. +.PP +Here are example message part headers for each of the +.B -attachformat +values: +.PP +.nf +-attachformat 0: +Content-Type: text/plain; name="VERSION"; x-unix-mode="0644"; +Content-Description: ASCII text + +-attachformat 1: +Content-Type: text/plain; charset="us-ascii" +Content-Disposition: attachment; filename="VERSION" + +-attachformat 2: +Content-Type: text/plain; charset="us-ascii" +Content-Disposition: attachment; filename="VERSION"; modification-date="Mon, 19 Dec 2005 22:39:51 -0600" +.fi +.PP If .B \-push is specified, @@ -350,6 +390,7 @@ comp(1), dist(1), forw(1), repl(1), mh\-alias(5), post(8) .RB ` \-noverbose ' .RB ` \-nowatch ' .RB ` "\-width\ 72" ' +.RB ` "\-attachformat\ 0" ' .fi .SH CONTEXT diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 25924e9..c6f5098 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -1108,17 +1108,18 @@ bad_quote: 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), - '/')); + ct->c_dispo = + incl_name_value (ct->c_dispo, + "filename", + r1bindex (extract_name_value ("name", + ci-> + ci_magic), + '/')); } else advise (NULL, "extraneous information in message %s's %s: field\n%*.*s(%s)", - ct->c_file, TYPE_FIELD, i, i, "", cp); + ct->c_file, TYPE_FIELD, i, i, "", cp); } return OK; @@ -4317,64 +4318,85 @@ invalid_digest: /* Make sure that buf contains at least one appearance of name, - followed by =. If not, append both name and value. 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. */ + 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 (char *buf, char *name, char *value) { - char *newbuf = buf; + char *newbuf = buf; - /* Assume that name is non-null. */ - if (buf && value) { - char *name_plus_equal = concat (name, "=", NULL); + /* Assume that name is non-null. */ + if (buf && value) { + char *name_plus_equal = concat (name, "=", NULL); - if (! strstr (buf, name_plus_equal)) { - char *appendage; - char *cp; + if (! strstr (buf, name_plus_equal)) { + char *insertion; + char *cp; + char *prefix, *suffix; - /* Trim trailing space, esp. newline. */ - for (cp = &buf[strlen (buf) - 1]; cp >= buf && isspace (*cp); --cp) { - *cp = '\0'; - } + /* Trim trailing space, esp. newline. */ + for (cp = &buf[strlen (buf) - 1]; + cp >= buf && isspace (*cp); + --cp) { + *cp = '\0'; + } - appendage = concat ("; ", name, "=", "\"", value, "\"\n", NULL); - newbuf = add (appendage, buf); - free (appendage); - } + insertion = concat ("; ", name, "=", "\"", value, "\"", NULL); + + /* 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); + free (suffix); + } else { + /* Append to end. */ + newbuf = concat (buf, insertion, "\n", NULL); + } + + free (prefix); + free (insertion); + free (buf); + } - free (name_plus_equal); - } + free (name_plus_equal); + } - return newbuf; + return newbuf; } -/* Extract just name_suffix="foo", if any, from value. If there isn't +/* 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; - char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL); - char *name_suffix_equals = strstr (value, name_suffix_plus_quote); - char *cp; - - free (name_suffix_plus_quote); - if (name_suffix_equals) { - char *name_suffix_begin; - - /* Find first \". */ - for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */; - name_suffix_begin = ++cp; - /* Find second \". */ - for (; *cp != '"'; ++cp) /* empty */; - - extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1); - memcpy (extracted_name_value, name_suffix_begin, cp - name_suffix_begin); - extracted_name_value[cp - name_suffix_begin] = '\0'; - } - - return extracted_name_value; + char *extracted_name_value = value; + char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL); + char *name_suffix_equals = strstr (value, name_suffix_plus_quote); + char *cp; + + free (name_suffix_plus_quote); + if (name_suffix_equals) { + char *name_suffix_begin; + + /* Find first \". */ + for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */; + name_suffix_begin = ++cp; + /* Find second \". */ + for (; *cp != '"'; ++cp) /* empty */; + + extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1); + memcpy (extracted_name_value, + name_suffix_begin, + cp - name_suffix_begin); + extracted_name_value[cp - name_suffix_begin] = '\0'; + } + + return extracted_name_value; } diff --git a/uip/send.c b/uip/send.c index 514f073..7849472 100644 --- a/uip/send.c +++ b/uip/send.c @@ -104,6 +104,8 @@ static struct swit switches[] = { { "user", SASLminc(-4) }, #define ATTACHSW 40 { "attach", 6 }, +#define ATTACHFORMATSW 41 + { "attachformat", 7 }, { NULL, 0 } }; @@ -142,6 +144,7 @@ main (int argc, char **argv) struct msgs *mp; struct stat st; char *attach = (char *)0; /* header field name for attachments */ + int attachformat = 0; /* mhbuild format specifier for attachments */ #ifdef UCI FILE *fp; #endif /* UCI */ @@ -280,6 +283,21 @@ main (int argc, char **argv) if (!(attach = *argp++) || *attach == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; + + case ATTACHFORMATSW: + if (! *argp || **argp == '-') + adios (NULL, "missing argument to %s", argp[-1]); + else { + attachformat = atoi (*argp); + if (attachformat < 0 || + attachformat > ATTACHFORMATS - 1) { + advise (NULL, "unsupported attachformat %d", + attachformat); + continue; + } + } + ++argp; + continue; } } else { msgs[msgp++] = cp; @@ -443,7 +461,8 @@ go_to_it: closefds (3); for (msgnum = 0; msgnum < msgp; msgnum++) { - switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach)) { + switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach, + attachformat)) { case DONE: done (++status); case NOTOK: diff --git a/uip/sendsbr.c b/uip/sendsbr.c index f793b1c..a43627f 100644 --- a/uip/sendsbr.c +++ b/uip/sendsbr.c @@ -54,7 +54,7 @@ static FILE *composition_file; /* composition file pointer */ /* * external prototypes */ -int sendsbr (char **, int, char *, struct stat *, int, char *); +int sendsbr (char **, int, char *, struct stat *, int, char *, int); int done (int); char *getusername (void); @@ -68,10 +68,10 @@ static void annoaux (int); static int splitmsg (char **, int, char *, struct stat *, int); static int sendaux (char **, int, char *, struct stat *); -static int attach(char *, char *); +static int attach(char *, char *, int); static void clean_up_temporary_files(void); static int get_line(void); -static void make_mime_composition_file_entry(char *); +static void make_mime_composition_file_entry(char *, int); /* @@ -79,7 +79,7 @@ static void make_mime_composition_file_entry(char *); */ int -sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name) +sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name, int attachformat) { int status; char buffer[BUFSIZ], file[BUFSIZ]; @@ -104,7 +104,7 @@ sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, cha */ if (attachment_header_field_name != (char *)0) { - switch (attach(attachment_header_field_name, drft)) { + switch (attach(attachment_header_field_name, drft, attachformat)) { case OK: drft = composition_file_name; break; @@ -188,7 +188,8 @@ sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, cha } static int -attach(char *attachment_header_field_name, char *draft_file_name) +attach(char *attachment_header_field_name, char *draft_file_name, + int attachformat) { char buf[MAXPATHLEN + 6]; /* miscellaneous buffer */ int c; /* current character for body copy */ @@ -294,7 +295,7 @@ attach(char *attachment_header_field_name, char *draft_file_name) */ if (has_body) - make_mime_composition_file_entry(body_file_name); + make_mime_composition_file_entry(body_file_name, attachformat); /* * Now, go back to the beginning of the draft file and look for header fields @@ -308,7 +309,7 @@ attach(char *attachment_header_field_name, char *draft_file_name) for (p = field + length + 1; *p == ' ' || *p == '\t'; p++) ; - make_mime_composition_file_entry(p); + make_mime_composition_file_entry(p, attachformat); } } @@ -376,7 +377,7 @@ get_line(void) } static void -make_mime_composition_file_entry(char *file_name) +make_mime_composition_file_entry(char *file_name, int attachformat) { int binary; /* binary character found flag */ int c; /* current character */ @@ -444,41 +445,64 @@ make_mime_composition_file_entry(char *file_name) adios((char *)0, "unable to access file \"%s\"", file_name); } - (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho", - content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, (unsigned short)(st.st_mode & 0777)); - - if (strlen(file_name) > MAXPATHLEN) { - clean_up_temporary_files(); - adios((char *)0, "attachment file name `%s' too long.", file_name); - } - - (void)sprintf(cmd, "file '%s'", file_name); - - if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp) != (char *)0) { - *strchr(cmd, '\n') = '\0'; - - /* - * The output of the "file" command is of the form - * - * file: description - * - * Strip off the "file:" and subsequent white space. - */ - - for (p = cmd; *p != '\0'; p++) { - if (*p == ':') { - for (p++; *p != '\0'; p++) { - if (*p != '\t') - break; - } - break; - } - } - - if (*p != '\0') - (void)fprintf(composition_file, " [ %s ]", p); - - (void)pclose(fp); + switch (attachformat) { + case 0: + /* Insert name, file mode, and Content-Id. */ + (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho", + content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, (unsigned short)(st.st_mode & 0777)); + + if (strlen(file_name) > MAXPATHLEN) { + clean_up_temporary_files(); + adios((char *)0, "attachment file name `%s' too long.", file_name); + } + + (void)sprintf(cmd, "file '%s'", file_name); + + if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp) != (char *)0) { + *strchr(cmd, '\n') = '\0'; + + /* + * The output of the "file" command is of the form + * + * file: description + * + * Strip off the "file:" and subsequent white space. + */ + + for (p = cmd; *p != '\0'; p++) { + if (*p == ':') { + for (p++; *p != '\0'; p++) { + if (*p != '\t') + break; + } + break; + } + } + + if (*p != '\0') + /* Insert Content-Description. */ + (void)fprintf(composition_file, " [ %s ]", p); + + (void)pclose(fp); + } + + break; + case 1: + /* Suppress Content-Id, insert simple Content-Disposition. */ + (void) fprintf (composition_file, "#%s <>{attachment}", content_type); + + break; + case 2: + /* Suppress Content-Id, insert Content-Disposition with + modification date. */ + (void) fprintf (composition_file, + "#%s <>{attachment; modification-date=\"%s\"}", + content_type, + dtime (&st.st_mtim, 0)); + + break; + default: + adios ((char *)0, "unsupported attachformat %d", attachformat); } /* diff --git a/uip/viamail.c b/uip/viamail.c index 3dbd27c..859dfaf 100644 --- a/uip/viamail.c +++ b/uip/viamail.c @@ -236,7 +236,7 @@ via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw, if (verbsw) vec[vecp++] = "-verbose"; - switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0)) { + switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0, 0)) { case DONE: case NOTOK: status++; diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index d863b5b..0a959db 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -1005,6 +1005,8 @@ static struct swit sendswitches[] = { { "user", SASLminc(-4) }, #define SNDATTACHSW 39 { "attach file", 6 }, +#define SNDATTACHFORMAT 40 + { "attachformat", 7 }, { NULL, 0 } }; @@ -1030,6 +1032,8 @@ sendit (char *sp, char **arg, char *file, int pushed) char **arguments, *vec[MAXARGS]; struct stat st; char *attach = (char *)0; /* attachment header field name */ + int attachformat = 0; /* mhbuild format specifier for + attachments */ #ifndef lint int distsw = 0; @@ -1190,6 +1194,21 @@ sendit (char *sp, char **arg, char *file, int pushed) return; } continue; + + case SNDATTACHFORMAT: + if (! *argp || **argp == '-') + adios (NULL, "missing argument to %s", argp[-1]); + else { + attachformat = atoi (*argp); + if (attachformat < 0 || + attachformat > ATTACHFORMATS - 1) { + advise (NULL, "unsupported attachformat %d", + attachformat); + continue; + } + } + ++argp; + continue; } } advise (NULL, "usage: %s [switches]", sp); @@ -1255,7 +1274,7 @@ sendit (char *sp, char **arg, char *file, int pushed) vec[0] = r1bindex (postproc, '/'); closefds (3); - if (sendsbr (vec, vecp, file, &st, 1, attach) == OK) + if (sendsbr (vec, vecp, file, &st, 1, attach, attachformat) == OK) done (0); } -- 1.7.10.4