nmh-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Nmh-commits] [SCM] The nmh Mail Handling System branch, master, updated


From: Ken Hornstein
Subject: [Nmh-commits] [SCM] The nmh Mail Handling System branch, master, updated. 3e151103c954aad7871a197b438b8d79d557e07e
Date: Tue, 31 Jan 2012 17:58:26 +0000

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 <address@hidden>
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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]