This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The nmh Mail Handling System".
The branch, master has been updated via 3e151103c954aad7871a197b438b8d79d557e07e (commit) from 8a5ee47c4884d56e13a50c4d28d22559101e1510 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- http://git.savannah.gnu.org/cgit/nmh.git/commit/?id=3e151103c954aad7871a197b438b8d79d557e07e commit 3e151103c954aad7871a197b438b8d79d557e07e Author: Ken Hornstein <k...@pobox.com> Date: Tue Jan 31 12:58:04 2012 -0500 Add support for calling an external format program inside of mhl. diff --git a/config/config.c b/config/config.c index 82d20b1..72896c2 100644 --- a/config/config.c +++ b/config/config.c @@ -194,6 +194,13 @@ char *faceproc = NULL; char *fileproc = nmhbindir (/refile); +/* + * This program is used to optionally format the bodies of messages by + * "mhl". + */ + +char *formatproc = NULL; + /* * This program is called to incorporate messages into a folder. */ diff --git a/h/mh.h b/h/mh.h index b0a841a..1f563b9 100644 --- a/h/mh.h +++ b/h/mh.h @@ -315,6 +315,7 @@ extern char *draft; extern char *faceproc; extern char *fileproc; extern char *foldprot; +extern char *formatproc; extern char *forwcomps; extern char *inbox; extern char *incproc; diff --git a/man/mhl.man b/man/mhl.man index cc62b7c..eff230f 100644 --- a/man/mhl.man +++ b/man/mhl.man @@ -250,6 +250,10 @@ decode flag decode text as RFC-2047 encoded header field addrfield flag field contains addresses datefield flag field contains dates +format flag Run component through formatproc filter + (body only) +noformat flag Do not run component through + formatproc filter (default) .fi .RE .PP @@ -315,7 +319,24 @@ can be given a default format string for either address or date fields (but not both). To do this, on a global line specify: either the flag addrfield or datefield, along with the appropriate formatfield variable string. - +.PP +The \*(lqformat\*(rq flag specifies that this component will be run through +the filter program specified by the +.IR formatproc +profile entry. This filter program is expected to read data on standard +input and output data on standard output. Currently the \*(lqformat\*(rq +flag is only supported for the \(*lqbody\*(rq component. The component +name will be prefixed to the output +.IR after +the filter has been run. The expected use of this is to filter a message +body to create more pleasing text to use in a reply message. +A suggested filter to use for +.BR repl(1) +is as follows: +.PP +.RS 5 +body:component=">",overflowtext=">",overflowoffset=0,format,nowrap +.RE .SH FILES .fc ^ ~ .nf @@ -331,6 +352,8 @@ appropriate formatfield variable string. .ta 2.4i .ta \w'ExtraBigProfileName 'u ^moreproc:~^Program to use as interactive front\-end +^formatproc:~^Program to use as a filter for components that +^^have the \*(lqformat\*(rq flag set. .fi .SH "SEE ALSO" diff --git a/man/repl.man b/man/repl.man index acc1c76..f67cee7 100644 --- a/man/repl.man +++ b/man/repl.man @@ -303,6 +303,22 @@ This message filter file cites the Message-ID and author of the message being replied\-to, and then outputs each line of the body prefaced with the \*(lq>\*(rq character. .PP +You can also use an external format program to format the message body. +The format program is specified by the +.IR formatproc +profile entry, and is enabled by the \*(lqformat\(*rq flag. A message +filter using an external format program would look like this: +.PP +.RS 5 +.nf +body:component=\*(lq>\*(rq,\|nowrap,\|format +.fi +.RE +.PP +See the +.BR mhl(1) +documentation for more information. +.PP To use the MIME rules for encapsulation, specify the .B \-mime switch. diff --git a/sbr/readconfig.c b/sbr/readconfig.c index 2a68019..7f30975 100644 --- a/sbr/readconfig.c +++ b/sbr/readconfig.c @@ -22,6 +22,7 @@ static struct procstr procs[] = { { "buildmimeproc", &buildmimeproc }, { "faceproc", &faceproc }, { "fileproc", &fileproc }, + { "formatproc", &formatproc }, { "incproc", &incproc }, { "installproc", &installproc }, { "lproc", &lproc }, diff --git a/uip/mhlsbr.c b/uip/mhlsbr.c index 5f355ab..1446c2a 100644 --- a/uip/mhlsbr.c +++ b/uip/mhlsbr.c @@ -15,6 +15,7 @@ #include <h/utils.h> #include <h/m_setjmp.h> #include <signal.h> +#include <errno.h> /* * MAJOR BUG: @@ -110,7 +111,8 @@ static struct swit mhlswitches[] = { #define SPLIT 0x010000 /* split headers (don't concatenate) */ #define NONEWLINE 0x020000 /* don't write trailing newline */ #define NOWRAP 0x040000 /* Don't wrap lines ever */ -#define LBITS "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT\017FACEFMT\020FACEDFLT\021SPLIT\022NONEWLINE\023NOWRAP" +#define FMTFILTER 0x080000 /* Filter through format filter */ +#define LBITS "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT\017FACEFMT\020FACEDFLT\021SPLIT\022NONEWLINE\023NOWRAP\024FMTFILTER" #define GFLAGS (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS | SPLIT | NOWRAP) struct mcomp { @@ -195,6 +197,8 @@ static struct triple triples[] = { { "nonewline", NONEWLINE, 0 }, { "wrap", 0, NOWRAP }, { "nowrap", NOWRAP, 0 }, + { "format", FMTFILTER, 0 }, + { "noformat", 0, FMTFILTER }, { NULL, 0, 0 } }; @@ -282,6 +286,7 @@ static int doface (struct mcomp *); static void mhladios (char *, char *, ...); static void mhldone (int); static void m_popen (char *); +static void filterbody (struct mcomp *, char *, int, int, FILE *); int mhl (int, char **); int mhlsbr (int, char **, FILE *(*)()); @@ -957,15 +962,20 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec) continue; } if (dobody && !mh_strcasecmp (c1->c_name, "body")) { - holder.c_text = mh_xmalloc (sizeof(buf)); - strncpy (holder.c_text, buf, sizeof(buf)); - while (state == BODY) { - putcomp (c1, &holder, BODYCOMP); - state = m_getfld (state, name, holder.c_text, - sizeof(buf), fp); + if (c1->c_flags & FMTFILTER && state == BODY && + formatproc != NULL) { + filterbody(c1, buf, sizeof(buf), state, fp); + } else { + holder.c_text = mh_xmalloc (sizeof(buf)); + strncpy (holder.c_text, buf, sizeof(buf)); + while (state == BODY) { + putcomp (c1, &holder, BODYCOMP); + state = m_getfld (state, name, holder.c_text, + sizeof(buf), fp); + } + free (holder.c_text); + holder.c_text = NULL; } - free (holder.c_text); - holder.c_text = NULL; continue; } for (c2 = msghd; c2; c2 = c2->c_next) @@ -1813,3 +1823,166 @@ m_pclose (void) pidwait (m_pid, OK); m_pid = NOTOK; } + + +/* + * Filter the body of a message through a specified format program + */ + +void +filterbody (struct mcomp *c1, char *buf, int bufsz, int state, FILE *fp) +{ + struct mcomp holder; + char name[NAMESZ]; + int fdinput[2], fdoutput[2], waitstat; + ssize_t cc; + pid_t writerpid, filterpid; + + /* + * Create pipes so we can communicate with our filter process. + */ + + if (pipe(fdinput) < 0) { + adios(NULL, "Unable to create input pipe"); + } + + if (pipe(fdoutput) < 0) { + adios(NULL, "Unable to create output pipe"); + } + + /* + * Here's what we're doing to do. + * + * - Fork ourselves and start writing data to the write side of the + * input pipe (fdinput[1]). + * + * - Fork and exec our filter program. We set the standard input of + * our filter program to be the read side of our input pipe (fdinput[0]). + * Standard output is set to the write side of our output pipe + * (fdoutput[1]). + * + * - We read from the read side of the output pipe (fdoutput[0]). + * + * We're forking because that's the simplest way to prevent any deadlocks. + * (without doing something like switching to non-blocking I/O and using + * select or poll, and I'm not interested in doing that). + */ + + switch (writerpid = fork()) { + case 0: + /* + * Our child process - just write to the filter input (fdinput[1]). + * Close all other descriptors that we don't need. + */ + + close(fdinput[0]); + close(fdoutput[0]); + close(fdoutput[1]); + + /* + * Call m_getfld() until we're no longer in the BODY state + */ + + while (state == BODY) { + write(fdinput[1], buf, strlen(buf)); + state = m_getfld(state, name, buf, bufsz, fp); + } + + /* + * We should be done; time to exit. + */ + + close(fdinput[1]); + exit(0); + break; + case -1: + adios(NULL, "Unable to fork for filter writer process"); + break; + } + + /* + * Fork and exec() our filter program, after redirecting standard in + * and standard out appropriately. + */ + + switch (filterpid = fork()) { + case 0: + if (dup2(fdinput[0], STDIN_FILENO) < 0) { + adios("formatproc", "Unable to dup2() standard input"); + } + if (dup2(fdoutput[1], STDOUT_FILENO) < 0) { + adios("formatproc", "Unable to dup2() standard output"); + } + + /* + * Close everything (especially the old input and output + * descriptors, since they've been dup'd to stdin and stdout), + * and exec the formatproc. + */ + + close(fdinput[0]); + close(fdinput[1]); + close(fdoutput[0]); + close(fdoutput[1]); + + execlp(formatproc, formatproc, (char *) NULL); + + adios(formatproc, "Unable to execute filter"); + + break; + + case -1: + adios(NULL, "Unable to fork format program"); + } + + /* + * Close everything except our reader (fdoutput[0]); + */ + + close(fdinput[0]); + close(fdinput[1]); + close(fdoutput[1]); + + /* + * As we read in this data, send it to putcomp + */ + + holder.c_text = buf; + + while ((cc = read(fdoutput[0], buf, bufsz)) > 0) { + putcomp(c1, &holder, BODYCOMP); + } + + if (cc < 0) { + adios(NULL, "reading from formatproc"); + } + + /* + * See if we got any errors along the way. I'm a little leery of calling + * waitpid() without WNOHANG, but it seems to be the most correct solution. + */ + + if (waitpid(filterpid, &waitstat, 0) < 0) { + if (errno != ECHILD) { + adios("filterproc", "Unable to determine status"); + } + } else { + if (! (WIFEXITED(waitstat) && WEXITSTATUS(waitstat) == 0)) { + pidstatus(waitstat, stderr, "filterproc"); + } + } + + if (waitpid(writerpid, &waitstat, 0) < 0) { + if (errno != ECHILD) { + adios("writer process", "Unable to determine status"); + done(1); + } + } else { + if (! (WIFEXITED(waitstat) && WEXITSTATUS(waitstat) == 0)) { + pidstatus(waitstat, stderr, "writer process"); + done(1); + } + } + + close(fdoutput[0]); +} diff --git a/uip/mhparam.c b/uip/mhparam.c index 8384544..1b35518 100644 --- a/uip/mhparam.c +++ b/uip/mhparam.c @@ -46,6 +46,7 @@ static struct proc procs [] = { { "faceproc", &faceproc }, { "fileproc", &fileproc }, { "foldprot", &foldprot }, + { "formatproc", &formatproc }, { "incproc", &incproc }, { "installproc", &installproc }, { "lproc", &lproc }, ----------------------------------------------------------------------- Summary of changes: config/config.c | 7 ++ h/mh.h | 1 + man/mhl.man | 25 +++++++- man/repl.man | 16 +++++ sbr/readconfig.c | 1 + uip/mhlsbr.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++--- uip/mhparam.c | 1 + 7 files changed, 232 insertions(+), 10 deletions(-) hooks/post-receive -- The nmh Mail Handling System _______________________________________________ Nmh-commits mailing list Nmh-commits@nongnu.org https://lists.nongnu.org/mailman/listinfo/nmh-commits