Change LocalName() to take an argument (about whether or not to use
[mmh] / uip / mhlsbr.c
index f22303b..6bfbade 100644 (file)
@@ -2,7 +2,9 @@
 /*
  * mhlsbr.c -- main routines for nmh message lister
  *
- * $Id$
+ * This code is Copyright (c) 2002, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
  */
 
 #include <h/mh.h>
 #include <h/addrsbr.h>
 #include <h/fmt_scan.h>
 #include <h/tws.h>
-#include <setjmp.h>
+#include <h/utils.h>
+#include <h/m_setjmp.h>
 #include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
 
 /*
  * MAJOR BUG:
@@ -106,8 +112,10 @@ static struct swit mhlswitches[] = {
 #define        FACEDFLT    0x008000    /* default for face                  */
 #define        SPLIT       0x010000    /* split headers (don't concatenate) */
 #define        NONEWLINE   0x020000    /* don't write trailing newline      */
-#define        LBITS   "\020\01NOCOMPONENT\02UPPERCASE\03CENTER\04CLEARTEXT\05EXTRA\06HDROUTPUT\07CLEARSCR\010LEFTADJUST\011COMPRESS\012ADDRFMT\013BELL\014DATEFMT\015FORMAT\016INIT\017FACEFMT\020FACEDFLT\021SPLIT\022NONEWLINE"
-#define        GFLAGS  (NOCOMPONENT | UPPERCASE | CENTER | LEFTADJUST | COMPRESS | SPLIT)
+#define NOWRAP      0x040000   /* Don't wrap lines ever             */
+#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 {
     char *c_name;              /* component name          */
@@ -131,11 +139,11 @@ static struct mcomp *fmthd = NULL;
 static struct mcomp *fmttl = NULL;
 
 static struct mcomp global = {
-    NULL, NULL, "", NULL, NULL, 0, -1, 80, -1, 40, BELL, 0
+    NULL, NULL, NULL, NULL, NULL, NULL, 0, -1, 80, -1, 40, BELL, NULL
 };
 
 static struct mcomp holder = {
-    NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT, 0
+    NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, NOCOMPONENT, NULL
 };
 
 struct pair {
@@ -189,6 +197,10 @@ static struct triple triples[] = {
     { "datefield",     DATEFMT,     ADDRFMT },
     { "newline",       0,           NONEWLINE },
     { "nonewline",     NONEWLINE,   0 },
+    { "wrap",          0,           NOWRAP },
+    { "nowrap",        NOWRAP,      0 },
+    { "format",        FMTFILTER,   0 },
+    { "noformat",      0,           FMTFILTER },
     { NULL,            0,           0 }
 };
 
@@ -215,17 +227,17 @@ static int mhldebug = 0;
 static int ontty = NOTTY;
 
 static int row;
-static int column;
+static unsigned int column;
 
 static int lm;
 static int llim;
 static int ovoff;
 static int term;
-static int wid;
+static unsigned int wid;
 
 static char *ovtxt;
 
-static char *onelp;
+static unsigned char *onelp;
 
 static char *parptr;
 
@@ -266,16 +278,17 @@ static struct mcomp *add_queue (struct mcomp **, struct mcomp **, char *, char *
 static void free_queue (struct mcomp **, struct mcomp **);
 static void putcomp (struct mcomp *, struct mcomp *, int);
 static char *oneline (char *, long);
-static void putstr (char *);
-static void putch (char);
-static RETSIGTYPE intrser (int);
-static RETSIGTYPE pipeser (int);
-static RETSIGTYPE quitser (int);
+static void putstr (char *, long);
+static void putch (char, long);
+static void intrser (int);
+static void pipeser (int);
+static void quitser (int);
 static void face_format (struct mcomp *);
 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 *(*)());
@@ -286,7 +299,6 @@ int SOprintf (char *, ...);           /* from termsbr.c */
 int sc_width (void);                  /* from termsbr.c */
 int sc_length (void);                 /* from termsbr.c */
 int sc_hardcopy (void);               /* from termsbr.c */
-struct hostent *gethostbystring ();
 
 
 int
@@ -476,6 +488,11 @@ mhl (int argc, char **argv)
                    vecp > 1 ? "s" : "");
     }
 
+    fflush(stdout);
+    if(ferror(stdout)){
+           adios("output", "error writing");
+    }
+    
     if (clearflg > 0 && ontty == NOTTY)
        clear_screen ();
 
@@ -553,7 +570,7 @@ mhl_format (char *file, int length, int width)
                 * Split this list of fields to ignore, and copy
                 * it to the end of the current "ignores" list.
                 */
-               if (!strcasecmp (name, "ignores")) {
+               if (!mh_strcasecmp (name, "ignores")) {
                    char **tmparray, **p;
                    int n = 0;
 
@@ -610,7 +627,8 @@ mhl_format (char *file, int length, int width)
            fprintf (stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n",
                    c1->c_name, c1->c_text, c1->c_ovtxt);
            fprintf (stderr, "\tnfs=0x%x fmt=0x%x\n",
-                   (unsigned int) c1->c_nfs, (unsigned int) c1->c_fmt);
+                    (unsigned int)(unsigned long) c1->c_nfs,
+                    (unsigned int)(unsigned long) c1->c_fmt);
            fprintf (stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d length=%d\n",
                    c1->c_offset, c1->c_ovoff, c1->c_width,
                    c1->c_cwidth, c1->c_length);
@@ -657,17 +675,17 @@ evalvar (struct mcomp *c1)
        return 0;
     strncpy (name, parse(), sizeof(name));
 
-    if (!strcasecmp (name, "component")) {
+    if (!mh_strcasecmp (name, "component")) {
        if (ptos (name, &c1->c_text))
            return 1;
        c1->c_flags &= ~NOCOMPONENT;
        return 0;
     }
 
-    if (!strcasecmp (name, "overflowtext"))
+    if (!mh_strcasecmp (name, "overflowtext"))
        return ptos (name, &c1->c_ovtxt);
 
-    if (!strcasecmp (name, "formatfield")) {
+    if (!mh_strcasecmp (name, "formatfield")) {
        char *nfs;
 
        if (ptos (name, &cp))
@@ -678,7 +696,7 @@ evalvar (struct mcomp *c1)
        return 0;
     }
 
-    if (!strcasecmp (name, "decode")) {
+    if (!mh_strcasecmp (name, "decode")) {
        char *nfs;
 
        nfs = new_fs (NULL, NULL, "%(decode{text})");
@@ -687,21 +705,21 @@ evalvar (struct mcomp *c1)
        return 0;
     }
 
-    if (!strcasecmp (name, "offset"))
+    if (!mh_strcasecmp (name, "offset"))
        return ptoi (name, &c1->c_offset);
-    if (!strcasecmp (name, "overflowoffset"))
+    if (!mh_strcasecmp (name, "overflowoffset"))
        return ptoi (name, &c1->c_ovoff);
-    if (!strcasecmp (name, "width"))
+    if (!mh_strcasecmp (name, "width"))
        return ptoi (name, &c1->c_width);
-    if (!strcasecmp (name, "compwidth"))
+    if (!mh_strcasecmp (name, "compwidth"))
        return ptoi (name, &c1->c_cwidth);
-    if (!strcasecmp (name, "length"))
+    if (!mh_strcasecmp (name, "length"))
        return ptoi (name, &c1->c_length);
-    if (!strcasecmp (name, "nodashstuffing"))
+    if (!mh_strcasecmp (name, "nodashstuffing"))
        return (dashstuff = -1);
 
     for (ap = triples; ap->t_name; ap++)
-       if (!strcasecmp (ap->t_name, name)) {
+       if (!mh_strcasecmp (ap->t_name, name)) {
            c1->c_flags |= ap->t_on;
            c1->c_flags &= ~ap->t_off;
            return 0;
@@ -784,11 +802,11 @@ parse (void)
 static void
 process (char *folder, char *fname, int ofilen, int ofilec)
 {
-    char *cp;
-    FILE *fp;
+    char *cp = NULL;
+    FILE *fp = NULL;
     struct mcomp *c1;
 
-    switch (setjmp (env)) {
+    switch (m_setjmp (env)) {
        case OK: 
            if (fname) {
                fp = mhl_action ? (*mhl_action) (fname) : fopen (fname, "r");
@@ -894,7 +912,7 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec)
            case FLD: 
            case FLDPLUS: 
                for (ip = ignores; *ip; ip++)
-                   if (!strcasecmp (name, *ip)) {
+                   if (!mh_strcasecmp (name, *ip)) {
                        while (state == FLDPLUS)
                            state = m_getfld (state, name, buf, sizeof(buf), fp);
                        break;
@@ -903,12 +921,12 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec)
                    continue;
 
                for (c2 = fmthd; c2; c2 = c2->c_next)
-                   if (!strcasecmp (c2->c_name, name))
+                   if (!mh_strcasecmp (c2->c_name, name))
                        break;
                c1 = NULL;
                if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT))
                    for (c1 = msghd; c1; c1 = c1->c_next)
-                       if (!strcasecmp (c1->c_name, c3->c_name)) {
+                       if (!mh_strcasecmp (c1->c_name, c3->c_name)) {
                            c1->c_text =
                                mcomp_add (c1->c_flags, buf, c1->c_text);
                            break;
@@ -931,7 +949,7 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec)
                        putcomp (c1, c1, ONECOMP);
                        continue;
                    }
-                   if (!strcasecmp (c1->c_name, "messagename")) {
+                   if (!mh_strcasecmp (c1->c_name, "messagename")) {
                        holder.c_text = concat ("(Message ", mname, ")\n",
                                            NULL);
                        putcomp (c1, &holder, ONECOMP);
@@ -939,27 +957,31 @@ mhlfile (FILE *fp, char *mname, int ofilen, int ofilec)
                        holder.c_text = NULL;
                        continue;
                    }
-                   if (!strcasecmp (c1->c_name, "extras")) {
+                   if (!mh_strcasecmp (c1->c_name, "extras")) {
                        for (c2 = msghd; c2; c2 = c2->c_next)
                            if (c2->c_flags & EXTRA)
                                putcomp (c1, c2, TWOCOMP);
                        continue;
                    }
-                   if (dobody && !strcasecmp (c1->c_name, "body")) {
-                       if ((holder.c_text = malloc (sizeof(buf))) == NULL)
-                           adios (NULL, "unable to allocate buffer memory");
-                       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 (dobody && !mh_strcasecmp (c1->c_name, "body")) {
+                       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)
-                       if (!strcasecmp (c2->c_name, c1->c_name)) {
+                       if (!mh_strcasecmp (c2->c_name, c1->c_name)) {
                            putcomp (c1, c2, ONECOMP);
                            if (!(c1->c_flags & SPLIT))
                                break;
@@ -997,7 +1019,7 @@ mcomp_flags (char *name)
     struct pair *ap;
 
     for (ap = pairs; ap->p_name; ap++)
-       if (!strcasecmp (ap->p_name, name))
+       if (!mh_strcasecmp (ap->p_name, name))
            return (ap->p_flags);
 
     return 0;
@@ -1074,7 +1096,7 @@ mcomp_format (struct mcomp *c1, struct mcomp *c2)
            if ((c1->c_flags & FACEDFLT) && c2->c_face == NULL) {
                char   *h, *o;
                if ((h = mp->m_host) == NULL)
-                   h = LocalName ();
+                   h = LocalName (0);
                if ((o = OfficialName (h)))
                    h = o;
                c2->c_face = concat ("address ", h, " ", mp->m_mbox,
@@ -1176,7 +1198,7 @@ static void
 putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
 {
     int count, cchdr;
-    char *cp;
+    unsigned char *cp;
 
     cchdr = 0;
     lm = 0;
@@ -1192,8 +1214,8 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
     onelp = NULL;
 
     if (c1->c_flags & CLEARTEXT) {
-       putstr (c1->c_text);
-       putstr ("\n");
+       putstr (c1->c_text, c1->c_flags);
+       putstr ("\n", c1->c_flags);
        return;
     }
 
@@ -1226,9 +1248,9 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
            for (cp = (c1->c_text ? c1->c_text : c1->c_name); *cp; cp++)
                if (islower (*cp))
                    *cp = toupper (*cp);
-       putstr (c1->c_text ? c1->c_text : c1->c_name);
+       putstr (c1->c_text ? c1->c_text : c1->c_name, c1->c_flags);
        if (flag != BODYCOMP) {
-           putstr (": ");
+           putstr (": ", c1->c_flags);
            if (!(c1->c_flags & SPLIT))
                c1->c_flags |= HDROUTPUT;
 
@@ -1236,7 +1258,7 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
        if ((count = c1->c_cwidth -
                strlen (c1->c_text ? c1->c_text : c1->c_name) - 2) > 0)
            while (count--)
-               putstr (" ");
+               putstr (" ", c1->c_flags);
        }
        else
            c1->c_flags |= HDROUTPUT;           /* for BODYCOMP */
@@ -1249,15 +1271,15 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
            for (cp = c2->c_name; *cp; cp++)
                if (islower (*cp))
                    *cp = toupper (*cp);
-       putstr (c2->c_name);
-       putstr (": ");
+       putstr (c2->c_name, c1->c_flags);
+       putstr (": ", c1->c_flags);
        if (!(c1->c_flags & SPLIT))
            c2->c_flags |= HDROUTPUT;
 
        cchdr++;
        if ((count = c1->c_cwidth - strlen (c2->c_name) - 2) > 0)
            while (count--)
-               putstr (" ");
+               putstr (" ", c1->c_flags);
     }
     if (c1->c_flags & UPPERCASE)
        for (cp = c2->c_text; *cp; cp++)
@@ -1268,27 +1290,29 @@ putcomp (struct mcomp *c1, struct mcomp *c2, int flag)
     if (cchdr) {
        if (flag == TWOCOMP)
            count = (c1->c_cwidth >= 0) ? c1->c_cwidth
-                       : strlen (c2->c_name) + 2;
+                       : (int) strlen (c2->c_name) + 2;
        else
-           count = (c1->c_cwidth >= 0) ? c1->c_cwidth
+           count = (c1->c_cwidth >= 0) ? (size_t) c1->c_cwidth
                        : strlen (c1->c_text ? c1->c_text : c1->c_name) + 2;
     }
     count += c1->c_offset;
 
     if ((cp = oneline (c2->c_text, c1->c_flags)))
-       putstr(cp);
+       putstr(cp, c1->c_flags);
     if (term == '\n')
-       putstr ("\n");
+       putstr ("\n", c1->c_flags);
     while ((cp = oneline (c2->c_text, c1->c_flags))) {
        lm = count;
        if (flag == BODYCOMP
                && !(c1->c_flags & NOCOMPONENT))
-           putstr (c1->c_text ? c1->c_text : c1->c_name);
+           putstr (c1->c_text ? c1->c_text : c1->c_name, c1->c_flags);
        if (*cp)
-           putstr (cp);
+           putstr (cp, c1->c_flags);
        if (term == '\n')
-           putstr ("\n");
+           putstr ("\n", c1->c_flags);
     }
+    if (flag == BODYCOMP && term == '\n')
+       c1->c_flags &= ~HDROUTPUT;              /* Buffer ended on a newline */
 }
 
 
@@ -1345,27 +1369,27 @@ oneline (char *stuff, long flags)
 
 
 static void
-putstr (char *string)
+putstr (char *string, long flags)
 {
     if (!column && lm > 0) {
        while (lm > 0)
            if (lm >= 8) {
-               putch ('\t');
+               putch ('\t', flags);
                lm -= 8;
            }
            else {
-               putch (' ');
+               putch (' ', flags);
                lm--;
            }
     }
     lm = 0;
     while (*string)
-       putch (*string++);
+       putch (*string++, flags);
 }
 
 
 static void
-putch (char ch)
+putch (char ch, long flags)
 {
     char buf[BUFSIZ];
 
@@ -1422,12 +1446,12 @@ putch (char ch)
            break;
     }
 
-    if (column >= wid) {
-       putch ('\n');
+    if (column >= wid && (flags & NOWRAP) == 0) {
+       putch ('\n', flags);
        if (ovoff > 0)
            lm = ovoff;
-       putstr (ovtxt ? ovtxt : "");
-       putch (ch);
+       putstr (ovtxt ? ovtxt : "", flags);
+       putch (ch, flags);
        return;
     }
 
@@ -1435,12 +1459,10 @@ putch (char ch)
 }
 
 
-static RETSIGTYPE
+static void
 intrser (int i)
 {
-#ifndef RELIABLE_SIGNALS
-    SIGNAL (SIGINT, intrser);
-#endif
+    NMH_UNUSED (i);
 
     discard (stdout);
     putchar ('\n');
@@ -1448,23 +1470,19 @@ intrser (int i)
 }
 
 
-static RETSIGTYPE
+static void
 pipeser (int i)
 {
-#ifndef RELIABLE_SIGNALS
-    SIGNAL (SIGPIPE, pipeser);
-#endif
+    NMH_UNUSED (i);
 
     done (NOTOK);
 }
 
 
-static RETSIGTYPE
+static void
 quitser (int i)
 {
-#ifndef RELIABLE_SIGNALS
-    SIGNAL (SIGQUIT, quitser);
-#endif
+    NMH_UNUSED (i);
 
     putchar ('\n');
     fflush (stdout);
@@ -1485,7 +1503,7 @@ face_format (struct mcomp *c1)
        if ((mp = getm (cp, NULL, 0, AD_NAME, NULL))) {
            char *h, *o;
            if ((h = mp->m_host) == NULL)
-               h = LocalName ();
+               h = LocalName (0);
            if ((o = OfficialName (h)))
                h = o;
            c1->c_face = concat ("address ", h, " ", mp->m_mbox, NULL);
@@ -1506,26 +1524,22 @@ face_format (struct mcomp *c1)
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netdb.h>
-
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
+#include <arpa/inet.h>
 
 static int
 doface (struct mcomp *c1)
 {
     int        result, sd;
-    struct sockaddr_in in_socket;
-    struct sockaddr_in *isock = &in_socket;
     static int inited = OK;
-    static int addrlen;
-    static struct in_addr addr;
-    static unsigned short portno;
+    static struct sockaddr_storage ss;
+    static socklen_t socklen;
+    static int socktype;
+    static int protocol;
 
     if (inited == OK) {
        char *cp;
        char **ap = brkstring (cp = getcpy (faceproc), " ", "\n");
-       struct hostent *hp;
+       struct addrinfo hints, *res;
 
        if (ap[0] == NULL || ap[1] == NULL) {
 bad_faceproc: ;
@@ -1533,27 +1547,32 @@ bad_faceproc: ;
            return (inited = NOTOK);
        }
 
-       if (!(hp = gethostbystring (ap[0])))
+       memset(&hints, 0, sizeof(hints));
+#ifdef AI_ADDRCONFIG
+       hints.ai_flags = AI_ADDRCONFIG;
+#endif
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+
+       if (getaddrinfo(ap[0], ap[1], &hints, &res) != 0)
            goto bad_faceproc;
-       memcpy((char *) &addr, hp->h_addr, addrlen = hp->h_length);
 
-       portno = htons ((unsigned short) atoi (ap[1]));
-       free (cp);
+       memcpy(&ss, res->ai_addr, res->ai_addrlen);
+       socklen = res->ai_addrlen;
+       socktype = res->ai_socktype;
+       protocol = res->ai_protocol;
+       freeaddrinfo(res);
 
        inited = DONE;
     }
     if (inited == NOTOK)
        return NOTOK;
 
-    isock->sin_family = AF_INET;
-    isock->sin_port = portno;
-    memcpy((char *) &isock->sin_addr, (char *) &addr, addrlen);
-
-    if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) == NOTOK)
+    if ((sd = socket (ss.ss_family, socktype, protocol)) == NOTOK)
        return NOTOK;
 
     result = sendto (sd, c1->c_text, strlen (c1->c_text), 0,
-               (struct sockaddr *) isock, sizeof(*isock));
+               (struct sockaddr *) &ss, socklen);
 
     close (sd);
 
@@ -1635,14 +1654,12 @@ doface (struct mcomp *c1)
                if (cp) {
                    int j;
                    char *dp;
-                   if ((dp = realloc (cp, (unsigned) (j = len + i))) == NULL)
-                       adios (NULL, "unable to allocate face storage");
+                   dp = mh_xrealloc (cp, (unsigned) (j = len + i));
                    memcpy(dp + len, buffer, i);
                    cp = dp, len = j;
                }
                else {
-                   if ((cp = malloc ((unsigned) i)) == NULL)
-                       adios (NULL, "unable to allocate face storage");
+                   cp = mh_xmalloc ((unsigned) i);
                    memcpy(cp, buffer, i);
                    len = i;
                }
@@ -1676,11 +1693,11 @@ doface (struct mcomp *c1)
 int
 mhlsbr (int argc, char **argv, FILE *(*action)())
 {
-    SIGNAL_HANDLER istat, pstat, qstat;
-    char *cp;
+    SIGNAL_HANDLER istat = NULL, pstat = NULL, qstat = NULL;
+    char *cp = NULL;
     struct mcomp *c1;
 
-    switch (setjmp (mhlenv)) {
+    switch (m_setjmp (mhlenv)) {
        case OK: 
            cp = invo_name;
            sleepsw = 0;        /* XXX */
@@ -1759,7 +1776,7 @@ m_popen (char *name)
     if (pipe (pd) == NOTOK)
        adios ("pipe", "unable to");
 
-    switch (m_pid = vfork ()) {
+    switch (m_pid = vfork()) {
        case NOTOK: 
            adios ("fork", "unable to");
 
@@ -1808,3 +1825,167 @@ 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 - 1)) > 0) {
+       buf[cc] = '\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]);
+}