Added -mts switch to post, send, and whom. Replaced test-sendmail-pipe
[mmh] / uip / post.c
index 2048228..3c47161 100644 (file)
@@ -20,7 +20,6 @@
 #include <h/mts.h>
 
 #include <errno.h>
-#include <setjmp.h>
 #include <signal.h>
 
 #ifdef HAVE_SYS_TIME_H
@@ -28,9 +27,7 @@
 #endif
 #include <time.h>
 
-#ifdef SMTPMTS
-# include <mts/smtp/smtp.h>
-#endif
+#include <mts/smtp/smtp.h>
 
 #ifndef CYRUS_SASL
 # define SASLminc(a) (a)
@@ -46,8 +43,6 @@
 
 #define FCCS           10      /* max number of fccs allowed */
 
-#define        uptolow(c)      ((isalpha(c) && isupper (c)) ? tolower (c) : c)
-
 /* In the following array of structures, the numeric second field of the
    structures (minchars) is apparently used like this:
 
@@ -104,46 +99,40 @@ static struct swit switches[] = {
     { "dashstuffing", -12 },           /* should we dashstuff BCC messages? */
 #define NBITSTUFFSW              23
     { "nodashstuffing", -14 },
-#define        MAILSW                   24
-    { "mail", -4 },                    /* specify MAIL smtp mode */
-#define        SAMLSW                   25
-    { "saml", -4 },                    /* specify SAML smtp mode */
-#define        SENDSW                   26
-    { "send", -4 },                    /* specify SEND smtp mode */
-#define        SOMLSW                   27
-    { "soml", -4 },                    /* specify SOML smtp mode */
-#define        ANNOSW                   28
+#define        ANNOSW                   24
     { "idanno number", -6 },           /* interface from send    */
-#define        DLVRSW                   29
-    { "deliver address-list", -7 },
-#define        CLIESW                   30
+#define        CLIESW                   25
     { "client host", -6 },
-#define        SERVSW                   31
-    { "server host", -6 },             /* specify alternate SMTP server */
-#define        SNOOPSW                  32
+#define        SERVSW                   26
+    { "server host", 6 },              /* specify alternate SMTP server */
+#define        SNOOPSW                  27
     { "snoop", -5 },                   /* snoop the SMTP transaction */
-#define        FILLSW                   33
-    { "fill-in file", -7 },
-#define        FILLUSW                  34
-    { "fill-up", -7 },
-#define        PARTSW                   35
+#define        PARTSW                   28
     { "partno", -6 },
-#define        QUEUESW                  36
+#define        QUEUESW                  29
     { "queued", -6 },
-#define SASLSW                   37
+#define SASLSW                   30
     { "sasl", SASLminc(-4) },
-#define SASLMECHSW               38
+#define NOSASLSW                 31
+    { "nosasl", SASLminc(-6) },
+#define SASLMXSSFSW              32
+    { "saslmaxssf", SASLminc(-10) },
+#define SASLMECHSW               33
     { "saslmech", SASLminc(-5) },
-#define USERSW                   39
+#define USERSW                   34
     { "user", SASLminc(-4) },
-#define PORTSW                  40
+#define PORTSW                  35
     { "port server port name/number", 4 },
-#define TLSSW                   41
+#define TLSSW                   36
     { "tls", TLSminc(-3) },
-#define FILEPROCSW              42
+#define NTLSSW                   37
+    { "notls", TLSminc(-5) },
+#define FILEPROCSW              38
     { "fileproc", -4 },
-#define MHLPROCSW               43
+#define MHLPROCSW               39
     { "mhlproc", -3 },
+#define MTSSW                   40
+    { "mts smtp|sendmail/smtp|sendmail/pipe", 2 },
     { NULL, 0 }
 };
 
@@ -157,50 +146,56 @@ struct headers {
 /*
  * flags for headers->flags
  */
-#define        HNOP  0x0000            /* just used to keep .set around          */
-#define        HBAD  0x0001            /* bad header - don't let it through      */
-#define        HADR  0x0002            /* header has an address field            */
-#define        HSUB  0x0004            /* Subject: header                        */
-#define        HTRY  0x0008            /* try to send to addrs on header         */
-#define        HBCC  0x0010            /* don't output this header               */
-#define        HMNG  0x0020            /* munge this header                      */
-#define        HNGR  0x0040            /* no groups allowed in this header       */
-#define        HFCC  0x0080            /* FCC: type header                       */
-#define        HNIL  0x0100            /* okay for this header not to have addrs */
-#define        HIGN  0x0200            /* ignore this header                     */
-#define        HDCC  0x0400            /* another undocumented feature           */
+#define        HNOP  0x0000    /* just used to keep .set around                      */
+#define        HBAD  0x0001    /* bad header - don't let it through                  */
+#define        HADR  0x0002    /* header has an address field                        */
+#define        HSUB  0x0004    /* Subject: header                                    */
+#define        HTRY  0x0008    /* try to send to addrs on header                     */
+#define        HBCC  0x0010    /* don't output this header, unless MTS_SENDMAIL_PIPE */
+#define        HMNG  0x0020    /* munge this header                                  */
+#define        HNGR  0x0040    /* no groups allowed in this header                   */
+#define        HFCC  0x0080    /* FCC: type header                                   */
+#define        HNIL  0x0100    /* okay for this header not to have addrs             */
+#define        HIGN  0x0200    /* ignore this header                                 */
+#define        HDCC  0x0400    /* another undocumented feature                       */
+#define HONE  0x0800   /* Only (zero or) one address allowed                 */
+#define HEFM  0x1000   /* Envelope-From: header                              */
 
 /*
  * flags for headers->set
  */
-#define        MFRM  0x0001            /* we've seen a From:        */
-#define        MDAT  0x0002            /* we've seen a Date:        */
-#define        MRFM  0x0004            /* we've seen a Resent-From: */
-#define        MVIS  0x0008            /* we've seen sighted addrs  */
-#define        MINV  0x0010            /* we've seen blind addrs    */
+#define        MFRM  0x0001    /* we've seen a From:        */
+#define        MDAT  0x0002    /* we've seen a Date:        */
+#define        MRFM  0x0004    /* we've seen a Resent-From: */
+#define        MVIS  0x0008    /* we've seen sighted addrs  */
+#define        MINV  0x0010    /* we've seen blind addrs    */
+#define MSND  0x0020   /* we've seen a Sender:      */
+#define MRSN  0x0040   /* We've seen a Resent-Sendr:*/
+#define MEFM  0x0080   /* We've seen Envelope-From: */
 
 
 static struct headers NHeaders[] = {
-    { "Return-Path", HBAD,                0 },
-    { "Received",    HBAD,                0 },
-    { "Reply-To",    HADR|HNGR,           0 },
-    { "From",        HADR|HNGR,           MFRM },
-    { "Sender",      HADR|HBAD,           0 },
-    { "Date",        HBAD,                0 },
-    { "Subject",     HSUB,                0 },
-    { "To",          HADR|HTRY,           MVIS },
-    { "cc",          HADR|HTRY,           MVIS },
-    { "Bcc",         HADR|HTRY|HBCC|HNIL, MINV },
-    { "Dcc",         HADR|HTRY|HDCC|HNIL, MVIS },      /* sorta cc & bcc combined */
-    { "Message-ID",  HBAD,                0 },
-    { "Fcc",         HFCC,                0 },
-    { NULL,          0,                   0 }
+    { "Return-Path",   HBAD,                0 },
+    { "Received",      HBAD,                0 },
+    { "Reply-To",      HADR|HNGR,           0 },
+    { "From",          HADR|HNGR,           MFRM },
+    { "Sender",        HADR|HNGR|HONE,      MSND },
+    { "Date",          HBAD,                0 },
+    { "Subject",       HSUB,                0 },
+    { "To",            HADR|HTRY,           MVIS },
+    { "cc",            HADR|HTRY,           MVIS },
+    { "Bcc",           HADR|HTRY|HBCC|HNIL, MINV },
+    { "Dcc",           HADR|HTRY|HDCC|HNIL, MVIS },    /* sorta cc & bcc combined */
+    { "Message-ID",    HBAD,                0 },
+    { "Fcc",           HFCC,                0 },
+    { "Envelope-From", HADR|HONE|HEFM,      MEFM },
+    { NULL,            0,                   0 }
 };
 
 static struct headers RHeaders[] = {
     { "Resent-Reply-To",   HADR|HNGR,           0 },
     { "Resent-From",       HADR|HNGR,           MRFM },
-    { "Resent-Sender",     HADR|HBAD,           0 },
+    { "Resent-Sender",     HADR|HNGR,           MRSN },
     { "Resent-Date",       HBAD,                0 },
     { "Resent-Subject",    HSUB,                0 },
     { "Resent-To",         HADR|HTRY,           MVIS },
@@ -210,12 +205,13 @@ static struct headers RHeaders[] = {
     { "Resent-Fcc",        HFCC,                0 },
     { "Reply-To",          HADR,                0 },
     { "From",              HADR|HNGR,           MFRM },
-    { "Sender",            HADR|HNGR,           0 },
+    { "Sender",            HADR|HNGR,           MSND },
     { "Date",              HNOP,                MDAT },
     { "To",                HADR|HNIL,           0 },
     { "cc",                HADR|HNIL,           0 },
     { "Bcc",               HADR|HTRY|HBCC|HNIL, 0 },
     { "Fcc",               HIGN,                0 },
+    { "Envelope-From",     HADR|HONE|HEFM,      MEFM },
     { NULL,                0,                   0 }
 };
 
@@ -240,10 +236,13 @@ static int checksw = 0;           /* whom -check                           */
 static int linepos=0;          /* putadr()'s position on the line       */
 static int nameoutput=0;       /* putadr() has output header name       */
 static int sasl=0;             /* Use SASL auth for SMTP                */
+static int saslssf=-1;         /* Our maximum SSF for SASL              */
 static char *saslmech=NULL;    /* Force use of particular SASL mech     */
 static char *user=NULL;                /* Authenticate as this user             */
 static char *port="smtp";      /* Name of server port for SMTP          */
 static int tls=0;              /* Use TLS for encryption                */
+static int fromcount=0;                /* Count of addresses on From: header    */
+static int seensender=0;       /* Have we seen a Sender: header?        */
 
 static unsigned msgflags = 0;  /* what we've seen */
 
@@ -259,6 +258,8 @@ static char tmpfil[BUFSIZ];
 static char bccfil[BUFSIZ];
 
 static char from[BUFSIZ];      /* my network address            */
+static char sender[BUFSIZ];    /* my Sender: header             */
+static char efrom[BUFSIZ];     /* my Envelope-From: header      */
 static char signature[BUFSIZ]; /* my signature                  */
 static char *filter = NULL;    /* the filter for BCC'ing        */
 static char *subject = NULL;   /* the subject field for BCC'ing */
@@ -266,29 +267,22 @@ static char *fccfold[FCCS];       /* foldernames for FCC'ing       */
 
 static struct headers  *hdrtab;        /* table for the message we're doing */
 
-static struct mailname localaddrs={NULL};      /* local addrs     */
-static struct mailname netaddrs={NULL};                /* network addrs   */
-static struct mailname uuaddrs={NULL};         /* uucp addrs      */
-static struct mailname tmpaddrs={NULL};                /* temporary queue */
+static struct mailname localaddrs;             /* local addrs     */
+static struct mailname netaddrs;               /* network addrs   */
+static struct mailname uuaddrs;                        /* uucp addrs      */
+static struct mailname tmpaddrs;               /* temporary queue */
 
-#ifdef SMTPMTS
 static int snoop      = 0;
-static int smtpmode   = S_MAIL;
 static char *clientsw = NULL;
 static char *serversw = NULL;
 
 extern struct smtp sm_reply;
-#endif /* SMTPMTS */
 
 static char prefix[] = "----- =_aaaaaaaaaa";
 
-static int fill_up = 0;
-static char *fill_in = NULL;
 static char *partno = NULL;
 static int queued = 0;
 
-extern boolean  draft_from_masquerading;  /* defined in mts.c */
-
 /*
  * static prototypes
  */
@@ -304,14 +298,14 @@ static void anno (void);
 static int annoaux (struct mailname *);
 static void insert_fcc (struct headers *, unsigned char *);
 static void make_bcc_file (int);
-static void verify_all_addresses (int);
+static void verify_all_addresses (int, char *);
 static void chkadr (void);
 static void sigon (void);
 static void sigoff (void);
 static void p_refile (char *);
 static void fcc (char *, char *);
 static void die (char *, char *, ...);
-static void post (char *, int, int);
+static void post (char *, int, int, char *);
 static void do_text (char *file, int fd);
 static void do_an_address (struct mailname *, int);
 static void do_addresses (int, int);
@@ -322,7 +316,7 @@ int
 main (int argc, char **argv)
 {
     int state, compnum, dashstuff = 0;
-    char *cp, *msg = NULL, **argp, **arguments;
+    char *cp, *msg = NULL, **argp, **arguments, *envelope;
     char buf[BUFSIZ], name[NAMESZ];
     FILE *in, *out;
 
@@ -351,10 +345,10 @@ main (int argc, char **argv)
                case HELPSW: 
                    snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
                    print_help (buf, switches, 0);
-                   done (1);
+                   done (0);
                case VERSIONSW:
                    print_version(invo_name);
-                   done (1);
+                   done (0);
 
                case LIBSW:
                    if (!(cp = *argp++) || *cp == '-')
@@ -457,33 +451,6 @@ main (int argc, char **argv)
                        adios (NULL, "bad argument %s %s", argp[-2], cp);
                    continue;
 
-               case DLVRSW:
-                   if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
-                   continue;
-
-#ifndef        SMTPMTS
-               case CLIESW:
-               case SERVSW:
-                   if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
-                   continue;
-
-               case SNOOPSW:
-                   continue;
-#else /* SMTPMTS */
-               case MAILSW:
-                   smtpmode = S_MAIL;
-                   continue;
-               case SAMLSW:
-                   smtpmode = S_SAML;
-                   continue;
-               case SOMLSW:
-                   smtpmode = S_SOML;
-                   continue;
-               case SENDSW:
-                   smtpmode = S_SEND;
-                   continue;
                case CLIESW:
                    if (!(clientsw = *argp++) || *clientsw == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -495,15 +462,7 @@ main (int argc, char **argv)
                case SNOOPSW:
                    snoop++;
                    continue;
-#endif /* SMTPMTS */
 
-               case FILLSW:
-                   if (!(fill_in = *argp++) || *fill_in == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
-                   continue;
-               case FILLUSW:
-                   fill_up++;
-                   continue;
                case PARTSW:
                    if (!(partno = *argp++) || *partno == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -516,6 +475,16 @@ main (int argc, char **argv)
                case SASLSW:
                    sasl++;
                    continue;
+
+               case NOSASLSW:
+                   sasl = 0;
+                   continue;
+
+               case SASLMXSSFSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   saslssf = atoi(cp);
+                   continue;
                
                case SASLMECHSW:
                    if (!(saslmech = *argp++) || *saslmech == '-')
@@ -536,6 +505,10 @@ main (int argc, char **argv)
                    tls++;
                    continue;
 
+               case NTLSSW:
+                   tls = 0;
+                   continue;
+
                case FILEPROCSW:
                    if (!(cp = *argp++) || *cp == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -547,6 +520,12 @@ main (int argc, char **argv)
                        adios (NULL, "missing argument to %s", argp[-2]);
                    mhlproc = cp;
                    continue;
+
+               case MTSSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    save_mts_method (cp);
+                   continue;
            }
        }
        if (msg)
@@ -572,7 +551,7 @@ main (int argc, char **argv)
        discard (out = stdout); /* XXX: reference discard() to help loader */
     } else {
        if (whomsw) {
-           if ((out = fopen (fill_in ? fill_in : "/dev/null", "w")) == NULL)
+           if ((out = fopen ("/dev/null", "w")) == NULL)
                adios ("/dev/null", "unable to open");
        } else {
             char *cp = m_mktemp(m_maildir(invo_name), NULL, &out);
@@ -610,7 +589,7 @@ main (int argc, char **argv)
            case BODY: 
            case BODYEOF: 
                finish_headers (out);
-               if (whomsw && !fill_in)
+               if (whomsw)
                    break;
                fprintf (out, "\n%s", buf);
                while (state == BODY) {
@@ -644,23 +623,46 @@ main (int argc, char **argv)
        fclose (out);
     }
 
+    /*
+     * Here's how we decide which address to use as the envelope-from
+     * address for SMTP.
+     *
+     * - If we were given an Envelope-From header, use that.
+     * - If we were given a Sender: address, use that.
+     * - Otherwise, use the address on the From: line
+     */
+
+    if (msgflags & MEFM) {
+       envelope = efrom;
+    } else if (seensender) {
+       envelope = sender;
+    } else {
+       envelope = from;
+    }
+
     /* If we are doing a "whom" check */
     if (whomsw) {
-       if (!fill_up)
-           verify_all_addresses (1);
+       /* This won't work with MTS_SENDMAIL_PIPE. */
+       verify_all_addresses (1, envelope);
        done (0);
     }
 
     if (msgflags & MINV) {
        make_bcc_file (dashstuff);
        if (msgflags & MVIS) {
-           verify_all_addresses (verbose);
-           post (tmpfil, 0, verbose);
+           if (sm_mts != MTS_SENDMAIL_PIPE) {
+               /* It would be nice to have support to call
+                  verify_all_addresses with MTS_SENDMAIL_PIPE, but
+                  that might require running sendmail as root.  Note
+                  that spost didn't verify addresses. */
+               verify_all_addresses (verbose, envelope);
+           }
+           post (tmpfil, 0, verbose, envelope);
        }
-       post (bccfil, 1, verbose);
+       post (bccfil, 1, verbose, envelope);
        unlink (bccfil);
     } else {
-       post (tmpfil, 0, isatty (1));
+       post (tmpfil, 0, isatty (1), envelope);
     }
 
     p_refile (tmpfil);
@@ -703,17 +705,11 @@ putfmt (char *name, char *str, FILE *out)
 
     hdr = &hdrtab[i];
     if (hdr->flags & HIGN) {
-       if (fill_in)
-           fprintf (out, "%s: %s", name, str);
        return;
     }
     if (hdr->flags & HBAD) {
-       if (fill_in)
-           fprintf (out, "%s: %s", name, str);
-       else {
-           advise (NULL, "illegal header line -- %s:", name);
-           badmsg++;
-       }
+       advise (NULL, "illegal header line -- %s:", name);
+       badmsg++;
        return;
     }
     msgflags |= (hdr->set & ~(MVIS | MINV));
@@ -721,11 +717,6 @@ putfmt (char *name, char *str, FILE *out)
     if (hdr->flags & HSUB)
        subject = subject ? add (str, add ("\t", subject)) : getcpy (str);
     if (hdr->flags & HFCC) {
-       if (fill_in) {
-           fprintf (out, "%s: %s", name, str);
-           return;
-       }
-
        if ((cp = strrchr(str, '\n')))
            *cp = 0;
        for (cp = pp = str; (cp = strchr(pp, ',')); pp = cp) {
@@ -760,6 +751,14 @@ putfmt (char *name, char *str, FILE *out)
        if (hdr->flags & HNIL)
            fprintf (out, "%s: %s", name, str);
        else {
+           /*
+            * Sender (or Resent-Sender) can have only one address
+            */
+           if ((msgstate == RESENT) ? (hdr->set & MRSN)
+                                       : (hdr->set & MSND)) {
+               advise (NULL, "%s: field requires one address", name);
+               badmsg++;
+           }
 #ifdef notdef
            advise (NULL, "%s: field requires at least one address", name);
            badmsg++;
@@ -768,9 +767,15 @@ putfmt (char *name, char *str, FILE *out)
        return;
     }
 
+    if (count > 1 && (hdr->flags & HONE)) {
+       advise (NULL, "%s: field only permits one address", name);
+       badmsg++;
+       return;
+    }
+
     nameoutput = linepos = 0;
     snprintf (namep, sizeof(namep), "%s%s",
-               !fill_in && (hdr->flags & HMNG) ? "Original-" : "", name);
+               (hdr->flags & HMNG) ? "Original-" : "", name);
 
     for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np)
        if (mp->m_nohost) {     /* also used to test (hdr->flags & HTRY) */
@@ -786,17 +791,37 @@ putfmt (char *name, char *str, FILE *out)
                    continue;
                }
 
-               if (draft_from_masquerading && ((msgstate == RESENT)
-                                               ? (hdr->set & MRFM)
-                                               : (hdr->set & MFRM)))
-                   /* The user manually specified a [Resent-]From: address in
-                      their draft and the "masquerade:" line in mts.conf
-                      doesn't contain "draft_from", so we'll set things up to
-                      use the actual email address embedded in the draft
-                      [Resent-]From: (after alias substitution, and without the
-                      GECOS full name or angle brackets) as the envelope
-                      From:. */
+               /*
+                * If it's a From: or Resent-From: header, save the address
+                * for later possible use (as the envelope address for SMTP)
+                */
+
+               if ((msgstate == RESENT) ? (hdr->set & MRFM)
+                                               : (hdr->set & MFRM)) {
                    strncpy(from, auxformat(mp, 0), sizeof(from) - 1);
+                   from[sizeof(from) - 1] = '\0';
+                   fromcount = count;
+               }
+
+               /*
+                * Also save the Sender: or Resent-Sender: header as well
+                */
+
+               if ((msgstate == RESENT) ? (hdr->set & MRSN)
+                                               : (hdr->set & MSND)) {
+                   strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1);
+                   sender[sizeof(sender) - 1] = '\0';
+                   seensender++;
+               }
+
+               /*
+                * ALSO ... save Envelope-From
+                */
+
+               if (hdr->set & MEFM) {
+                   strncpy(efrom, auxformat(mp, 0), sizeof(efrom) - 1);
+                   efrom[sizeof(efrom) - 1] = '\0';
+               }
 
                if (hdr->flags & HBCC)
                    mp->m_bcc++;
@@ -818,17 +843,37 @@ putfmt (char *name, char *str, FILE *out)
        }
        else {
            /* Address includes a host, so no alias substitution is needed. */
-           if (draft_from_masquerading && ((msgstate == RESENT)
-                                           ? (hdr->set & MRFM)
-                                           : (hdr->set & MFRM)))
-               /* The user manually specified a [Resent-]From: address in
-                  their draft and the "masquerade:" line in mts.conf
-                  doesn't contain "draft_from", so we'll set things up to
-                  use the actual email address embedded in the draft
-                  [Resent-]From: (after alias substitution, and without the
-                  GECOS full name or angle brackets) as the envelope
-                  From:. */
+
+           /*
+            * If it's a From: or Resent-From header, save the address
+            * for later possible use (as the envelope address for SMTP)
+            */
+
+           if ((msgstate == RESENT) ? (hdr->set & MRFM)
+                                           : (hdr->set & MFRM)) {
                strncpy(from, auxformat(mp, 0), sizeof(from) - 1);
+               fromcount = count;
+           }
+
+           /*
+            * Also save the Sender: header as well
+            */
+
+           if ((msgstate == RESENT) ? (hdr->set & MRSN)
+                                           : (hdr->set & MSND)) {
+               strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1);
+               sender[sizeof(sender) - 1] = '\0';
+               seensender++;
+           }
+
+           /*
+            * ALSO ... save Envelope-From
+            */
+
+           if (hdr->set & MEFM) {
+               strncpy(efrom, auxformat(mp, 0), sizeof(efrom) - 1);
+               efrom[sizeof(efrom) - 1] = '\0';
+           }
 
            if (hdr->flags & HBCC)
                mp->m_bcc++;
@@ -851,8 +896,6 @@ putfmt (char *name, char *str, FILE *out)
        badmsg++;
     }
     if (linepos) {
-       if (fill_in && grp > 0)
-           putc (';', out);
        putc ('\n', out);
     }
 }
@@ -862,23 +905,25 @@ static void
 start_headers (void)
 {
     unsigned char  *cp;
-    char myhost[BUFSIZ], sigbuf[BUFSIZ];
+    char sigbuf[BUFSIZ];
     struct mailname *mp;
 
     myuid = getuid ();
     mygid = getgid ();
     time (&tclock);
 
-    strncpy (from, adrsprintf (NULL, NULL), sizeof(from));
-    strncpy (myhost, LocalName (), sizeof(myhost));
+    /*
+     * Probably not necessary, but just in case ...
+     */
 
-    for (cp = myhost; *cp; cp++)
-       *cp = uptolow (*cp);
+    from[0] = '\0';
+    efrom[0] = '\0';
+    sender[0] = '\0';
 
     if ((cp = getfullname ()) && *cp) {
        strncpy (sigbuf, cp, sizeof(sigbuf));
        snprintf (signature, sizeof(signature), "%s <%s>",
-               sigbuf, adrsprintf (NULL, NULL));
+               sigbuf, getlocaladdr());
        if ((cp = getname (signature)) == NULL)
            adios (NULL, "getname () failed -- you lose extraordinarily big");
        if ((mp = getm (cp, NULL, 0, AD_HOST, NULL)) == NULL)
@@ -887,7 +932,7 @@ start_headers (void)
        while (getname (""))
            continue;
     } else {
-       strncpy (signature, adrsprintf (NULL, NULL), sizeof(signature));
+       strncpy (signature, getlocaladdr(), sizeof(signature));
     }
 }
 
@@ -903,27 +948,46 @@ finish_headers (FILE *out)
 {
     switch (msgstate) {
        case NORMAL: 
-           if (whomsw && !fill_up)
+           if (!(msgflags & MFRM)) {
+               /*
+                * A From: header is now required in the draft.
+                */
+               advise (NULL, "message has no From: header");
+               advise (NULL, "See default components files for examples");
+               badmsg++;
+               break;
+           }
+
+           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
+               advise (NULL, "A Sender: or Envelope-From: header is required "
+                       "with multiple\nFrom: addresses");
+               badmsg++;
+               break;
+           }
+
+           if (whomsw)
                break;
 
            fprintf (out, "Date: %s\n", dtime (&tclock, 0));
            if (msgid)
                fprintf (out, "Message-ID: <%d.%ld@%s>\n",
-                       (int) getpid (), (long) tclock, LocalName ());
-           if (msgflags & MFRM) {
-               /* There was already a From: in the draft.  Don't add one. */
-               if (!draft_from_masquerading)
-                   /* mts.conf didn't contain "masquerade:[...]draft_from[...]"
-                      so we'll reveal the user's actual account@thismachine
-                      address in a Sender: header (and use it as the envelope
-                      From: later). */
-                   fprintf (out, "Sender: %s\n", from);
+                       (int) getpid (), (long) tclock, LocalName (1));
+           /*
+            * If we have multiple From: addresses, make sure we have an
+            * Sender: header.  If we don't have one, then generate one
+            * from Envelope-From: (which in this case, cannot be blank)
+            */
+
+           if (fromcount > 1 && seensender == 0) {
+               if (efrom[0] == '\0') {
+                   advise (NULL, "Envelope-From cannot be blank when there "
+                           "is multiple From: addresses\nand no Sender: "
+                           "header");
+                   badmsg++;
+               } else {
+                   fprintf (out, "Sender: %s\n", efrom);
+               }
            }
-           else
-               /* Construct a From: header. */
-               fprintf (out, "From: %s\n", signature);
-           if (whomsw)
-               break;
 
            if (!(msgflags & MVIS))
                fprintf (out, "Bcc: Blind Distribution List: ;\n");
@@ -938,27 +1002,43 @@ finish_headers (FILE *out)
                advise (NULL, "message has no From: header");
                badmsg++;
            }
-           if (whomsw && !fill_up)
+           if (!(msgflags & MRFM)) {
+               advise (NULL, "message has no Resent-From: header");
+               advise (NULL, "See default components files for examples");
+               badmsg++;
+               break;
+           }
+           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
+               advise (NULL, "A Resent-Sender: or Envelope-From: header is "
+                       "required with multiple\nResent-From: addresses");
+               badmsg++;
+               break;
+           }
+
+           if (whomsw)
                break;
 
            fprintf (out, "Resent-Date: %s\n", dtime (&tclock, 0));
            if (msgid)
                fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n",
-                       (int) getpid (), (long) tclock, LocalName ());
-           if (msgflags & MRFM) {
-               /* There was already a Resent-From: in draft.  Don't add one. */
-               if (!draft_from_masquerading)
-                   /* mts.conf didn't contain "masquerade:[...]draft_from[...]"
-                      so we'll reveal the user's actual account@thismachine
-                      address in a Sender: header (and use it as the envelope
-                      From: later). */
-                   fprintf (out, "Resent-Sender: %s\n", from);
+                       (int) getpid (), (long) tclock, LocalName (1));
+           /*
+            * If we have multiple Resent-From: addresses, make sure we have an
+            * Resent-Sender: header.  If we don't have one, then generate one
+            * from Envelope-From (which in this case, cannot be blank)
+            */
+
+           if (fromcount > 1 && seensender == 0) {
+               if (efrom[0] == '\0') {
+                   advise (NULL, "Envelope-From cannot be blank when there "
+                           "is multiple Resent-From: addresses and no "
+                           "Resent-Sender: header");
+                   badmsg++;
+               } else {
+                   fprintf (out, "Resent-Sender: %s\n", efrom);
+               }
            }
-           else
-               /* Construct a Resent-From: header. */
-               fprintf (out, "Resent-From: %s\n", signature);
-           if (whomsw)
-               break;
+
            if (!(msgflags & MVIS))
                fprintf (out, "Resent-Bcc: Blind Re-Distribution List: ;\n");
            break;
@@ -993,7 +1073,8 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
 
     if (mp->m_mbox == NULL || ((flags & HTRY) && !insert (mp)))
        return 0;
-    if ((!fill_in && (flags & (HBCC | HDCC))) || mp->m_ingrp)
+    if (sm_mts != MTS_SENDMAIL_PIPE &&
+        ((flags & (HBCC | HDCC | HEFM)) || mp->m_ingrp))
        return 1;
 
     if (!nameoutput) {
@@ -1004,7 +1085,7 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
     if (*aka && mp->m_type != UUCPHOST && !mp->m_pers)
        mp->m_pers = getcpy (aka);
     if (format) {
-       if (mp->m_gname && !fill_in) {
+       if (mp->m_gname) {
            snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname);
            cp = buffer;
        } else {
@@ -1037,17 +1118,15 @@ putgrp (char *name, char *group, FILE *out, unsigned int flags)
     int len;
     char *cp;
 
-    if (!fill_in && (flags & HBCC))
+    if (sm_mts != MTS_SENDMAIL_PIPE && (flags & HBCC))
        return;
 
     if (!nameoutput) {
        fprintf (out, "%s: ", name);
        linepos += (nameoutput = strlen (name) + 2);
-       if (fill_in)
-           linepos -= strlen (group);
     }
 
-    cp = fill_in ? group : concat (group, ";", NULL);
+    cp = concat (group, ";", NULL);
     len = strlen (cp);
 
     if (linepos > nameoutput) {
@@ -1198,19 +1277,7 @@ make_bcc_file (int dashstuff)
     fprintf (out, "Date: %s\n", dtime (&tclock, 0));
     if (msgid)
        fprintf (out, "Message-ID: <%d.%ld@%s>\n",
-               (int) getpid (), (long) tclock, LocalName ());
-    if (msgflags & MFRM) {
-      /* There was already a From: in the draft.  Don't add one. */
-      if (!draft_from_masquerading)
-        /* mts.conf didn't contain "masquerade:[...]draft_from[...]"
-           so we'll reveal the user's actual account@thismachine
-           address in a Sender: header (and use it as the envelope
-           From: later). */
-        fprintf (out, "Sender: %s\n", from);
-    }
-    else
-      /* Construct a From: header. */
-      fprintf (out, "From: %s\n", signature);
+               (int) getpid (), (long) tclock, LocalName (1));
     if (subject)
        fprintf (out, "Subject: %s", subject);
     fprintf (out, "BCC:\n");
@@ -1396,10 +1463,8 @@ do_addresses (int bccque, int talk)
 
     chkadr ();
 
-#ifdef SMTPMTS
     if (rp_isbad (retval = sm_waend ()))
        die (NULL, "problem ending addresses; %s", rp_string (retval));
-#endif /* SMTPMTS */
 }
 
 
@@ -1412,15 +1477,13 @@ do_addresses (int bccque, int talk)
  * SENDMAIL/SMTP routines
  */
 
-#ifdef SMTPMTS
-
 static void
-post (char *file, int bccque, int talk)
+post (char *file, int bccque, int talk, char *envelope)
 {
-    int fd, onex;
-    int        retval;
+    int fd;
+    int        retval, i;
+    pid_t child_id;
 
-    onex = !(msgflags & MINV) || bccque;
     if (verbose) {
        if (msgflags & MINV)
            printf (" -- Posting for %s Recipients --\n",
@@ -1431,38 +1494,71 @@ post (char *file, int bccque, int talk)
 
     sigon ();
 
-    if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose,
-                                   snoop, onex, queued, sasl, saslmech,
-                                   user, tls))
-           || rp_isbad (retval = sm_winit (smtpmode, from)))
-       die (NULL, "problem initializing server; %s", rp_string (retval));
-
-    do_addresses (bccque, talk && verbose);
-    if ((fd = open (file, O_RDONLY)) == NOTOK)
-       die (file, "unable to re-open");
-    do_text (file, fd);
-    close (fd);
-    fflush (stdout);
+    if (sm_mts == MTS_SENDMAIL_PIPE) {
+       char *sargv[16], **argp;
 
-    sm_end (onex ? OK : DONE);
-    sigoff ();
+       for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
+           sleep (5);
+       switch (child_id) {
+           case NOTOK: 
+               adios ("fork", "unable to");
 
-    if (verbose) {
-       if (msgflags & MINV)
-           printf (" -- %s Recipient Copies Posted --\n",
-                   bccque ? "Blind" : "Sighted");
-       else
-           printf (" -- Recipient Copies Posted --\n");
-    }
+           case OK:
+               if (freopen( file, "r", stdin) == NULL) {
+                   adios (file, "can't reopen for sendmail");
+               }
 
-    fflush (stdout);
+               argp = sargv;
+               *argp++ = "sendmail";
+               *argp++ = "-t"; /* read msg for recipients */
+               *argp++ = "-i"; /* don't stop on "." */
+               if (whomsw)
+                   *argp++ = "-bv";
+               if (snoop)
+                   *argp++ = "-v";
+               *argp = NULL;
+
+               execv (sendmail, sargv);
+               adios (sendmail, "can't exec");
+
+           default: 
+               pidXwait (child_id, NULL);
+               break;
+       }
+    } else {
+        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
+                                        verbose, snoop, queued, sasl,
+                                        saslssf, saslmech, user, tls))  ||
+            rp_isbad (retval = sm_winit (envelope)))
+           die (NULL, "problem initializing server; %s", rp_string (retval));
+
+        do_addresses (bccque, talk && verbose);
+        if ((fd = open (file, O_RDONLY)) == NOTOK)
+          die (file, "unable to re-open");
+        do_text (file, fd);
+        close (fd);
+        fflush (stdout);
+
+        sm_end (!(msgflags & MINV) || bccque ? OK : DONE);
+        sigoff ();
+
+        if (verbose) {
+            if (msgflags & MINV)
+               printf (" -- %s Recipient Copies Posted --\n",
+                       bccque ? "Blind" : "Sighted");
+            else
+               printf (" -- Recipient Copies Posted --\n");
+        }
+
+        fflush (stdout);
+    }
 }
 
 
 /* Address Verification */
 
 static void
-verify_all_addresses (int talk)
+verify_all_addresses (int talk, char *envelope)
 {
     int retval;
     struct mailname *lp;
@@ -1471,9 +1567,9 @@ verify_all_addresses (int talk)
 
     if (!whomsw || checksw)
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
-                                       verbose, snoop, 0, queued, sasl,
-                                       saslmech, user, tls))
-               || rp_isbad (retval = sm_winit (smtpmode, from)))
+                                       verbose, snoop, queued, sasl,
+                                       saslssf, saslmech, user, tls))
+               || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));
 
     if (talk && !whomsw)
@@ -1598,8 +1694,6 @@ do_text (char *file, int fd)
     }
 }
 
-#endif /* SMTPMTS */
-
 
 /*
  * SIGNAL HANDLING
@@ -1614,10 +1708,8 @@ sigser (int i)
     if (msgflags & MINV)
        unlink (bccfil);
 
-#ifdef SMTPMTS
     if (!whomsw || checksw)
        sm_end (NOTOK);
-#endif /* SMTPMTS */
 
     done (1);
 }
@@ -1733,10 +1825,8 @@ die (char *what, char *fmt, ...)
     if (msgflags & MINV)
        unlink (bccfil);
 
-#ifdef SMTPMTS
     if (!whomsw || checksw)
        sm_end (NOTOK);
-#endif /* SMTPMTS */
 
     va_start(ap, fmt);
     advertise (what, NULL, fmt, ap);