Hoi, I will be out of town for about ten days. Maybe I can read my emails at times.
Before I go off, I like to share what I worked on the last two days. It's neither cleaned up nor much tested. Please see it as code in development. It may though be interesting for people who work on nmh currently, for not doing the same work twice. (I'm looking at you Peter. ;-) ) During the last week I thought a lot about how to do the MIME stuff right. My studies of send(1) and Peter's mail with this thoughts were the basis. >From my current knowledge I believe that Jon Steinhart's attachment system (read docs/README-ATTACHMENTS) is the way to go for sending MIME messages. It can cover comp(1) and the MIME part of forw(1), and in fact any other sending of mail because is sits in send(1). Peter already pointed out that he believes that that's the right point for it. What I did: - I changed Jon's attachment system to get the attachment header name and format from the profile and not from command line arguments. This made the involved commands and functions less bulky because the values need not to be passed through all the time. It also makes this data avaliable to any program who ``likes to take part''. This alone I regard as an improvement. The new profile names are: `attachment-header' and `attachment-format'. (attach_fmt should likely be a char* too.) The -attach and -attachformat cmdline options of whatnow(1) and send(1) vanished. - The main change was done in uip/sendsbr.c:attach(). The message gets now MIMEified if it has attachment headers or (this is new) contains any non-ASCII character. Also handling of the body and forwarded messages is done directly. Until now if the body contained non-ASCII chars it would have gone as application/octet-stream if attachment headers had been present. This is fixed. (The content-typing of unknown attachments is still poor, but that's a different task.) - In uip/forw.c the action of the -mime switch was changed. Instead of inserting a mhbuild directive (#forw) it now inserts an attachment header that looks similar to the #forw directive. Therefore I replaced copy_mime_draft() with add_forw_hdr() which uses annotate(). The header will get converted to a #forw directive in sendsbr.c. This prevents /^#/ from being special, thanks to Jon's system. - I updated parts of the man pages but not very carefully and not well. Notes: The mime action of whatnow must not be used as it will collide with send's MIME facility. Thus automimeproc should not be set. I think whatnow's `mime' action should probably be removed then. If one does not use attachments (Jon's system) and mails include only ASCII chars then no MIME will be used and everything is like it had been. If either one is used then MIME will be used, which probably is what is wanted. (Peter pointed to the direction that nmh should behave just reasonable.) The space-tab-mixture of the indentation may be non-standard, by accident. You may test the patch if you like, but please see it as work in progress. I publish it now because it's good to release often, also now it's hot and I still know what I did ;-) . I very much like to clean every thing up when I'm back. meillo Diffstats: config/config.c | 7 +++- h/mh.h | 2 + h/prototypes.h | 2 - man/send.man | 40 ++++++++++++------------- man/whatnow.man | 2 - sbr/readconfig.c | 2 + uip/forw.c | 21 ++++++------- uip/mhparam.c | 2 + uip/send.c | 31 +------------------ uip/sendsbr.c | 86 ++++++++++++++++++++++++++++++------------------------- uip/viamail.c | 2 - uip/whatnowsbr.c | 79 +++++--------------------------------------------- 12 files changed, 101 insertions(+), 175 deletions(-)
diff -r f306353298cc config/config.c --- a/config/config.c Wed Nov 10 13:18:11 2010 -0300 +++ b/config/config.c Fri Nov 12 20:02:06 2010 -0300 @@ -166,6 +166,12 @@ char *mh_seq = ".mh_sequences"; #endif +/* + * Default attachment header field name and attachment format. + */ +char *attach_hdr = "X-MH-Attachment"; +int attach_fmt = 0; + /* * nmh globals */ @@ -365,4 +371,3 @@ */ char *msgprot = DEFAULT_MESSAGE_MODE; - diff -r f306353298cc h/mh.h --- a/h/mh.h Wed Nov 10 13:18:11 2010 -0300 +++ b/h/mh.h Fri Nov 12 20:02:06 2010 -0300 @@ -299,6 +299,8 @@ * their values and reloading the various modules, nmh will run * on any system. */ +extern char *attach_hdr; +extern int attach_fmt; extern char *buildmimeproc; extern char *catproc; extern char *components; diff -r f306353298cc h/prototypes.h --- a/h/prototypes.h Wed Nov 10 13:18:11 2010 -0300 +++ b/h/prototypes.h Fri Nov 12 20:02:06 2010 -0300 @@ -162,7 +162,7 @@ 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); +int sendsbr (char **, int, char *, struct stat *, int); int what_now (char *, int, int, char *, char *, int, struct msgs *, char *, int, char *); diff -r f306353298cc man/send.man --- a/man/send.man Wed Nov 10 13:18:11 2010 -0300 +++ b/man/send.man Fri Nov 12 20:02:06 2010 -0300 @@ -44,10 +44,6 @@ \&...] .RB [ \-version ] .RB [ \-help ] -.RB [ \-attach -.IR header-field-name ] -.RB [ \-attachformat -.IR 0 " | " 1 " | " 2 ] .ad .SH DESCRIPTION .B Send @@ -73,21 +69,24 @@ .BR post . .PP -If a -.I header-field-name -is supplied using the -.B -attach -option, the draft is scanned for a header whose field name matches the -supplied -.IR header-field-name . -The draft is converted to a MIME message if one or more matches are found. +The draft is scanned for a header whose field name matches the +.I attachment-header +profile entry. +The draft is converted to a MIME message if one or more matches are found +or the message body contains non-ASCII characters. This conversion occurs before all other processing. .PP The first part of the MIME message is the draft body if that body contains any non-blank characters. The body of each header field whose name matches the -.I header-field-name -is interpreted as a file name, and each file named is included as a separate +.I attachment-header +profile entry is interpreted either as a file name or as a mail message. +The former case is an absolute path name (beginning with `/'). +The latter case begins with a `+', followed by an absolute path name +to a mail folder and, separated by spaces, one or more message numbers. +The format matches the one of the ``message'' directive (#forw) in +.BR mhbuild (1). +Each file named is included as a separate part in the MIME message. .PP For file names with dot suffixes, the context is scanned for a @@ -108,8 +107,8 @@ command on the file. .PP The -.B -attachformat -option specifies the MIME header field formats: a value of +.B attachment-format +profile entry specifies the MIME header field formats: a value of .B 0, the default, includes the @@ -128,20 +127,20 @@ prompt. .PP Here are example message part headers for each of the -.B -attachformat +.B attachment-format values: .PP .nf --attachformat 0: +attachment-format: 0: Content-Type: text/plain; name="VERSION"; x-unix-mode="0644"; charset="us-ascii" Content-Description: ASCII text --attachformat 1: +attachment-format: 1: Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="VERSION" --attachformat 2: +attachment-format: 2: Content-Type: text/plain; charset="us-ascii" Content-Disposition: attachment; filename="VERSION"; modification-date="Mon, 19 Dec 2005 22:39:51 -0600" .fi @@ -403,7 +402,6 @@ .RB ` \-noverbose ' .RB ` \-nowatch ' .RB ` "\-width\ 72" ' -.RB ` "\-attachformat\ 0" ' .fi .SH CONTEXT diff -r f306353298cc man/whatnow.man --- a/man/whatnow.man Wed Nov 10 13:18:11 2010 -0300 +++ b/man/whatnow.man Fri Nov 12 20:02:06 2010 -0300 @@ -22,8 +22,6 @@ .RI [ file ] .RB [ \-version ] .RB [ \-help ] -.RB [ \-attach -.IR header-field-name ] .ad .SH DESCRIPTION .B Whatnow diff -r f306353298cc sbr/readconfig.c --- a/sbr/readconfig.c Wed Nov 10 13:18:11 2010 -0300 +++ b/sbr/readconfig.c Fri Nov 12 20:02:06 2010 -0300 @@ -19,6 +19,8 @@ }; static struct procstr procs[] = { + { "attachment-header", &attach_hdr }, + { "attachment-format", &attach_fmt }, { "context", &context }, { "mh-sequences", &mh_seq }, { "buildmimeproc", &buildmimeproc }, diff -r f306353298cc uip/forw.c --- a/uip/forw.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/forw.c Fri Nov 12 20:02:06 2010 -0300 @@ -116,7 +116,7 @@ */ static void mhl_draft (int, char *, int, int, char *, char *, int); static void copy_draft (int, char *, char *, int, int, int); -static void copy_mime_draft (int); +static void add_forw_hdr (char *draft); static int build_form (char *, char *, int, int); @@ -419,12 +419,13 @@ */ if (filter) mhl_draft (out, digest, volume, issue, drft, filter, dashstuff); - else if (mime) - copy_mime_draft (out); - else + else if (!mime) copy_draft (out, digest, drft, volume, issue, dashstuff); close (out); + if (mime) + add_forw_hdr (drft); + if (digest) { snprintf (buf, sizeof(buf), IFORMAT, digest); snprintf (value, sizeof(value), "%d", issue); @@ -626,20 +627,18 @@ */ static void -copy_mime_draft (int out) +add_forw_hdr (char *draft) { int msgnum; char buffer[BUFSIZ]; - snprintf (buffer, sizeof(buffer), "#forw [forwarded message%s] +%s", - mp->numsel == 1 ? "" : "s", mp->foldpath); - write (out, buffer, strlen (buffer)); + snprintf (buffer, sizeof(buffer), "+%s", mp->foldpath); for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) if (is_selected (mp, msgnum)) { - snprintf (buffer, sizeof(buffer), " %s", m_name (msgnum)); - write (out, buffer, strlen (buffer)); + strncat (buffer, " ", sizeof(buffer)-strlen(buffer)-1); + strncat (buffer, m_name (msgnum), sizeof(buffer)-strlen(buffer)-1); } - write (out, "\n", 1); + annotate(draft, attach_hdr, buffer, 1, 0, -2, 1); } diff -r f306353298cc uip/mhparam.c --- a/uip/mhparam.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/mhparam.c Fri Nov 12 20:02:06 2010 -0300 @@ -42,6 +42,8 @@ }; static struct proc procs [] = { + { "attachment-header", &attach_hdr }, + { "attachment-format", &attach_fmt }, { "context", &context }, { "mh-sequences", &mh_seq }, { "buildmimeproc", &buildmimeproc }, diff -r f306353298cc uip/send.c --- a/uip/send.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/send.c Fri Nov 12 20:02:06 2010 -0300 @@ -102,11 +102,7 @@ { "saslmech mechanism", SASLminc(-5) }, #define USERSW 39 { "user username", SASLminc(-4) }, -#define ATTACHSW 40 - { "attach", 6 }, -#define ATTACHFORMATSW 41 - { "attachformat", 7 }, -#define PORTSW 42 +#define PORTSW 40 { "port server-port-name/number" , 4 }, { NULL, 0 } }; @@ -145,8 +141,6 @@ char *msgs[MAXARGS], *vec[MAXARGS]; 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 */ @@ -281,26 +275,6 @@ adios (NULL, "missing argument to %s", argp[-2]); vec[vecp++] = cp; continue; - - case ATTACHSW: - 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; @@ -464,8 +438,7 @@ closefds (3); for (msgnum = 0; msgnum < msgp; msgnum++) { - switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach, - attachformat)) { + switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1)) { case DONE: done (++status); case NOTOK: diff -r f306353298cc uip/sendsbr.c --- a/uip/sendsbr.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/sendsbr.c Fri Nov 12 20:02:06 2010 -0300 @@ -54,7 +54,7 @@ /* * external prototypes */ -int sendsbr (char **, int, char *, struct stat *, int, char *, int); +int sendsbr (char **, int, char *, struct stat *, int); char *getusername (void); /* @@ -68,10 +68,10 @@ static int splitmsg (char **, int, char *, struct stat *, int); static int sendaux (char **, int, char *, struct stat *); -static int attach(char *, char *, int); +static int attach(char *); static void clean_up_temporary_files(void); static int get_line(void); -static void make_mime_composition_file_entry(char *, int); +static void make_mime_composition_file_entry(char *); /* @@ -79,7 +79,7 @@ */ int -sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name, int attachformat) +sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft) { int status; char buffer[BUFSIZ], file[BUFSIZ]; @@ -96,25 +96,22 @@ original_draft = drft; /* - * There might be attachments if a header field name for attachments is supplied. * Convert the draft to a MIME message. Use the mhbuild composition file for the * draft if there was a successful conversion because that now contains the MIME * message. A nice side effect of this is that it leaves the original draft file * untouched so that it can be retrieved and modified if desired. */ - if (attachment_header_field_name != (char *)0) { - switch (attach(attachment_header_field_name, drft, attachformat)) { - case OK: - drft = composition_file_name; - break; + switch (attach(drft)) { + case OK: + drft = composition_file_name; + break; - case NOTOK: - return (NOTOK); + case NOTOK: + return (NOTOK); - case DONE: - break; - } + case DONE: + break; } done=armed_done; @@ -191,13 +188,13 @@ } static int -attach(char *attachment_header_field_name, char *draft_file_name, - int attachformat) +attach(char *draft_file_name) { char buf[MAXPATHLEN + 6]; /* miscellaneous buffer */ int c; /* current character for body copy */ int has_attachment; /* draft has at least one attachment */ int has_body; /* draft has a message body */ + int non_ascii; /* msg body contains non-ASCII chars */ int length; /* length of attachment header field name */ char *p; /* miscellaneous string pointer */ @@ -216,43 +213,49 @@ field = (char *)mh_xmalloc(field_size = 256); /* - * Scan the draft file for a header field name that matches the -attach - * argument. The existence of one indicates that the draft has attachments. + * Scan the draft file for a header field name. + * The existence of one indicates that the draft has attachments. * Bail out if there are no attachments because we're done. Read to the * end of the headers even if we have no attachments. */ - length = strlen(attachment_header_field_name); + length = strlen(attach_hdr); has_attachment = 0; while (get_line() != EOF && *field != '\0' && *field != '-') - if (strncasecmp(field, attachment_header_field_name, length) == 0 && field[length] == ':') + if (strncasecmp(field, attach_hdr, length) == 0 && field[length] == ':') has_attachment = 1; - if (has_attachment == 0) - return (DONE); - /* - * We have at least one attachment. Look for at least one non-blank line - * in the body of the message which indicates content in the body. + * Check if body contains at least one non-blank char (= not empty) + * and if it contains non-ASCII chars (= need MIME). */ has_body = 0; + non_ascii = 0; while (get_line() != EOF) { for (p = field; *p != '\0'; p++) { - if (*p != ' ' && *p != '\t') { + if (*p != ' ' && *p != '\t') has_body = 1; - break; - } + if (*p > 127 || *p < 0) + non_ascii = 1; } - if (has_body) + if (has_body && non_ascii) break; } /* + * Bail out if there are no attachments and only ASCII text. + * This means we don't need to convert it to MIME. + */ + + if (!has_attachment && non_ascii == 0) + return (DONE); + + /* * Make names for the temporary files. */ @@ -281,7 +284,7 @@ rewind(draft_file); while (get_line() != EOF && *field != '\0' && *field != '-') - if (strncasecmp(field, attachment_header_field_name, length) != 0 || field[length] != ':') + if (strncasecmp(field, attach_hdr, length) != 0 || field[length] != ':') (void)fprintf(composition_file, "%s\n", field); (void)fputs("--------\n", composition_file); @@ -301,8 +304,10 @@ * Add a mhbuild MIME composition file line for the body if there was one. */ - if (has_body) - make_mime_composition_file_entry(body_file_name, attachformat); + if (has_body) { + /* charset will be discovered/guessed by buildmimeproc */ + fprintf(composition_file, "#text/plain %s\n", body_file_name); + } /* * Now, go back to the beginning of the draft file and look for header fields @@ -312,11 +317,14 @@ rewind(draft_file); while (get_line() != EOF && *field != '\0' && *field != '-') { - if (strncasecmp(field, attachment_header_field_name, length) == 0 && field[length] == ':') { + if (strncasecmp(field, attach_hdr, length) == 0 && field[length] == ':') { for (p = field + length + 1; *p == ' ' || *p == '\t'; p++) ; - - make_mime_composition_file_entry(p, attachformat); + if (*p == '+') { + /* forwarded message (all other paths are absolute) */ + fprintf(composition_file, "#forw [forwarded message(s)] %s\n", p); + } else + make_mime_composition_file_entry(p); } } @@ -384,7 +392,7 @@ } static void -make_mime_composition_file_entry(char *file_name, int attachformat) +make_mime_composition_file_entry(char *file_name) { int binary; /* binary character found flag */ int c; /* current character */ @@ -452,7 +460,7 @@ adios((char *)0, "unable to access file \"%s\"", file_name); } - switch (attachformat) { + switch (attach_fmt) { case 0: /* Insert name, file mode, and Content-Id. */ (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho", @@ -529,7 +537,7 @@ break; default: - adios ((char *)0, "unsupported attachformat %d", attachformat); + adios ((char *)0, "unsupported attachment-format %d", attach_fmt); } /* diff -r f306353298cc uip/viamail.c --- a/uip/viamail.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/viamail.c Fri Nov 12 20:02:06 2010 -0300 @@ -237,7 +237,7 @@ if (verbsw) vec[vecp++] = "-verbose"; - switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0, 0)) { + switch (sendsbr (vec, vecp, tmpfil, &st, 0)) { case DONE: case NOTOK: status++; diff -r f306353298cc uip/whatnowsbr.c --- a/uip/whatnowsbr.c Wed Nov 10 13:18:11 2010 -0300 +++ b/uip/whatnowsbr.c Fri Nov 12 20:02:06 2010 -0300 @@ -10,7 +10,7 @@ * * Several options have been added to ease the inclusion of attachments * using the header field name mechanism added to anno and send. The - * -attach option is used to specify the header field name for attachments. + * header field name for attachments is read from the profile. * * Several commands have been added at the whatnow prompt: * @@ -62,10 +62,7 @@ #define VERSIONSW 6 { "version", 0 }, #define HELPSW 7 - { "help", 0 }, -#define ATTACHSW 8 - { "attach header-field-name", 0 }, - { NULL, 0 } + { "help", 0 } }; /* @@ -140,7 +137,6 @@ char buf[BUFSIZ], prompt[BUFSIZ]; char **argp, **arguments; struct stat st; - char *attach = (char *)0; /* attachment header field name */ char cwd[MAXPATHLEN + 1]; /* current working directory */ char file[MAXPATHLEN + 1]; /* file name buffer */ char shell[MAXPATHLEN + 1]; /* shell response buffer */ @@ -213,13 +209,6 @@ if (!(myprompt = *argp++) || *myprompt == '-') adios (NULL, "missing argument to %s", argp[-2]); continue; - - case ATTACHSW: - if (attach != (char *)0) - adios(NULL, "only one attachment header field name at a time!"); - if (!(attach = *argp++) || *attach == '-') - adios (NULL, "missing argument to %s", argp[-2]); - continue; } } if (drft) @@ -367,11 +356,6 @@ * -n numbers listing */ - if (attach == (char *)0) { - advise((char *)0, "can't list because no header field name was given."); - break; - } - l = (char *)0; n = 0; @@ -397,21 +381,13 @@ advise((char *)0, "usage is alist [-ln]."); else - annolist(drft, attach, l, n); + annolist(drft, attach_hdr, l, n); break; case ATTACHCMDSW: /* * Attach files to current draft. - */ - - if (attach == (char *)0) { - advise((char *)0, "can't attach because no header field name was given."); - break; - } - - /* * Build a command line that causes the user's shell to list the file name * arguments. This handles and wildcard expansion, tilde expansion, etc. */ @@ -430,10 +406,10 @@ *(strchr(shell, '\n')) = '\0'; if (*shell == '/') - (void)annotate(drft, attach, shell, 1, 0, -2, 1); + (void)annotate(drft, attach_hdr, shell, 1, 0, -2, 1); else { (void)sprintf(file, "%s/%s", cwd, shell); - (void)annotate(drft, attach, file, 1, 0, -2, 1); + (void)annotate(drft, attach_hdr, file, 1, 0, -2, 1); } } @@ -448,14 +424,6 @@ case DETACHCMDSW: /* * Detach files from current draft. - */ - - if (attach == (char *)0) { - advise((char *)0, "can't detach because no header field name was given."); - break; - } - - /* * Scan the arguments for a -n. Mixed file names and numbers aren't allowed, * so this catches a -n anywhere in the argument list. */ @@ -481,7 +449,7 @@ if (**arguments != '\0') { n = atoi(*arguments); - (void)annotate(drft, attach, (char *)0, 1, 0, n, 1); + (void)annotate(drft, attach_hdr, (char *)0, 1, 0, n, 1); for (argp = arguments + 1; *argp != (char *)0; argp++) { if (atoi(*argp) > n) { @@ -508,7 +476,7 @@ if ((f = popen_in_dir(cwd, buf, "r")) != (FILE *)0) { while (fgets(shell, sizeof (shell), f) != (char *)0) { *(strchr(shell, '\n')) = '\0'; - (void)annotate(drft, attach, shell, 1, 0, 0, 1); + (void)annotate(drft, attach_hdr, shell, 1, 0, 0, 1); } pclose(f); } else { @@ -1059,11 +1027,7 @@ { "saslmech", SASLminc(-5) }, #define USERSW 38 { "user", SASLminc(4) }, -#define SNDATTACHSW 39 - { "attach file", 6 }, -#define SNDATTACHFORMAT 40 - { "attachformat", 7 }, -#define PORTSW 41 +#define PORTSW 39 { "port server-port-name/number", 4 }, { NULL, 0 } }; @@ -1089,9 +1053,6 @@ char *cp, buf[BUFSIZ], **argp; 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; @@ -1246,28 +1207,6 @@ } case SNDRFSW: continue; - - case SNDATTACHSW: - if (!(attach = *argp++) || *attach == '-') { - advise (NULL, "missing argument to %s", argp[-2]); - 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); @@ -1333,7 +1272,7 @@ vec[0] = r1bindex (postproc, '/'); closefds (3); - if (sendsbr (vec, vecp, file, &st, 1, attach, attachformat) == OK) + if (sendsbr (vec, vecp, file, &st, 1) == OK) done (0); }
_______________________________________________ Nmh-workers mailing list Nmh-workers@nongnu.org http://lists.nongnu.org/mailman/listinfo/nmh-workers