]> diplodocus.org Git - nmh/blobdiff - uip/post.c
lock_file.c: close(2) file descriptor on failure, avoiding leak.
[nmh] / uip / post.c
index cd96ed73ed6665b88ddf95febe9c06e74cc409ea..69fe6b86c2c62ec1458badda67f56317e5321c28 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * post.c -- enter messages into the mail transport system
+/* post.c -- enter messages into the mail transport system
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
 #include <h/dropsbr.h>
 #include <h/mime.h>
 #include <h/utils.h>
-
 #include <h/tws.h>
 #include <h/mts.h>
+#include "sbr/m_mktemp.h"
+#include "sbr/message_id.h"
 
-#include <errno.h>
-#include <setjmp.h>
-#include <signal.h>
-
-#ifdef TIME_WITH_SYS_TIME
+#ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
-# include <time.h>
-#else
-# ifdef TM_IN_SYS_TIME
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
 #endif
+#include <time.h>
 
-#ifdef SMTPMTS
-# include <mts/smtp/smtp.h>
-#endif
+#include <mts/smtp/smtp.h>
 
 #ifndef CYRUS_SASL
 # define SASLminc(a) (a)
 # define TLSminc(a)   0
 #endif /* TLS_SUPPORT */
 
-#define FCCS           10      /* max number of fccs allowed */
+#ifndef OAUTH_SUPPORT
+# define OAUTHminc(a)  (a)
+#else /* OAUTH_SUPPORT */
+# define OAUTHminc(a)  0
+#endif /* OAUTH_SUPPORT */
 
-#define        uptolow(c)      ((isalpha(c) && isupper (c)) ? tolower (c) : c)
+#define FCCS           10      /* max number of fccs allowed */
 
 /* In the following array of structures, the numeric second field of the
    structures (minchars) is apparently used like this:
    0  : Switch can't be abbreviated;               switch shown in -help.
    #  : Switch can be abbreviated to # characters; switch shown in -help. */
 
-static struct swit switches[] = {
-#define        ALIASW                    0
-    { "alias aliasfile", 0 },
-#define        CHKSW                     1
-    { "check", -5 },                   /* interface from whom */
-#define        NCHKSW                    2
-    { "nocheck", -7 },                 /* interface from whom */
-#define        DEBUGSW                   3
-    { "debug", -5 },
-#define        DISTSW                    4
-    { "dist", -4 },                    /* interface from dist */
-#define        FILTSW                    5
-    { "filter filterfile", 0 },
-#define        NFILTSW                   6
-    { "nofilter", 0 },
-#define        FRMTSW                    7
-    { "format", 0 },
-#define        NFRMTSW                   8
-    { "noformat", 0 },
-#define        LIBSW                     9
-    { "library directory", -7 },       /* interface from send, whom */
-#define        MIMESW                   10
-    { "mime", 0 },
-#define        NMIMESW                  11
-    { "nomime", 0 },
-#define        MSGDSW                   12
-    { "msgid", 0 },
-#define        NMSGDSW                  13
-    { "nomsgid", 0 },
-#define        VERBSW                   14
-    { "verbose", 0 },
-#define        NVERBSW                  15
-    { "noverbose", 0 },
-#define        WATCSW                   16
-    { "watch", 0 },
-#define        NWATCSW                  17
-    { "nowatch", 0 },
-#define        WHOMSW                   18
-    { "whom", -4 },                    /* interface from whom */
-#define        WIDTHSW                  19
-    { "width columns", 0 },
-#define VERSIONSW                20
-    { "version", 0 },
-#define        HELPSW                   21
-    { "help", 0 },
-#define BITSTUFFSW               22
-    { "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
-    { "idanno number", -6 },           /* interface from send    */
-#define        DLVRSW                   29
-    { "deliver address-list", -7 },
-#define        CLIESW                   30
-    { "client host", -6 },
-#define        SERVSW                   31
-    { "server host", -6 },             /* specify alternate SMTP server */
-#define        SNOOPSW                  32
-    { "snoop", -5 },                   /* snoop the SMTP transaction */
-#define        FILLSW                   33
-    { "fill-in file", -7 },
-#define        FILLUSW                  34
-    { "fill-up", -7 },
-#define        PARTSW                   35
-    { "partno", -6 },
-#define        QUEUESW                  36
-    { "queued", -6 },
-#define SASLSW                   37
-    { "sasl", SASLminc(-4) },
-#define SASLMECHSW               38
-    { "saslmech", SASLminc(-5) },
-#define USERSW                   39
-    { "user", SASLminc(-4) },
-#define PORTSW                  40
-    { "port server port name/number", 4 },
-#define TLSSW                   41
-    { "tls", TLSminc(-3) },
-    { NULL, 0 }
-};
+#define POST_SWITCHES \
+    X("alias aliasfile", 0, ALIASW) \
+    X("check", -5, CHKSW) /* interface from whom */ \
+    X("nocheck", -7, NCHKSW) /* interface from whom */ \
+    X("debug", -5, DEBUGSW) \
+    X("dist", -4, DISTSW) /* interface from dist */ \
+    X("filter filterfile", 0, FILTSW) \
+    X("nofilter", 0, NFILTSW) \
+    X("format", 0, FRMTSW) \
+    X("noformat", 0, NFRMTSW) \
+    X("library directory", -7, LIBSW) /* interface from send, whom */ \
+    X("mime", 0, MIMESW) \
+    X("nomime", 0, NMIMESW) \
+    X("msgid", 0, MSGDSW) \
+    X("nomsgid", 0, NMSGDSW) \
+    X("verbose", 0, VERBSW) \
+    X("noverbose", 0, NVERBSW) \
+    X("watch", 0, WATCSW) \
+    X("nowatch", 0, NWATCSW) \
+    X("whom", -4, WHOMSW) /* interface from whom */ \
+    X("width columns", 0, WIDTHSW) \
+    X("version", 0, VERSIONSW) \
+    X("help", 0, HELPSW) \
+    X("dashstuffing", -12, BITSTUFFSW) /* should we dashstuff BCC messages? */ \
+    X("nodashstuffing", -14, NBITSTUFFSW) \
+    X("idanno number", -6, ANNOSW) /* interface from send    */ \
+    X("client host", -6, CLIESW) \
+    X("server host", 6, SERVSW) /* specify alternate SMTP server */ \
+    X("snoop", -5, SNOOPSW) /* snoop the SMTP transaction */ \
+    X("partno", -6, PARTSW) \
+    X("sasl", SASLminc(4), SASLSW) \
+    X("nosasl", SASLminc(6), NOSASLSW) \
+    X("saslmech", SASLminc(5), SASLMECHSW) \
+    X("user", SASLminc(-4), USERSW) \
+    X("port server submission port name/number", 4, PORTSW) \
+    X("tls", TLSminc(-3), TLSSW) \
+    X("initialtls", TLSminc(-10), INITTLSSW) \
+    X("notls", TLSminc(-5), NTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
+    X("fileproc", -4, FILEPROCSW) \
+    X("mhlproc", -3, MHLPROCSW) \
+    X("sendmail program", 0, MTSSM) \
+    X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
+    X("credentials legacy|file:filename", 0, CREDENTIALSSW) \
+    X("messageid localname|random", 2, MESSAGEIDSW) \
+    X("authservice auth-service-name", OAUTHminc(-11), AUTHSERVICESW) \
+    X("oauthcredfile credential-file", OAUTHminc(-7), OAUTHCREDFILESW) \
+    X("oauthclientid client-id", OAUTHminc(-12), OAUTHCLIDSW) \
+    X("oauthclientsecret client-secret", OAUTHminc(-12), OAUTHCLSECSW) \
+    X("oauthauthendpoint authentication-endpoint", OAUTHminc(-6), OAUTHAUTHENDSW) \
+    X("oauthredirect redirect-uri", OAUTHminc(-6), OAUTHREDIRSW) \
+    X("oauthtokenendpoint token-endpoint", OAUTHminc(-6), OAUTHTOKENDSW) \
+    X("oauthscope scope", OAUTHminc(-6), OAUTHSCOPESW) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(POST);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(POST, switches);
+#undef X
+
 
+/*
+ * Mapping between command-line switches and profile entries, communicated
+ * from 'send'.  We use a service name of 'post' internally.
+ */
+
+static struct {
+    const char *profname;
+    int switchnum;
+    const char *value;
+} oauthswitches[] = {
+    { "oauth-%s-credential-file", OAUTHCREDFILESW, NULL },
+    { "oauth-%s-client_id", OAUTHCLIDSW, NULL },
+    { "oauth-%s-client_secret", OAUTHCLSECSW, NULL },
+    { "oauth-%s-auth_endpoint", OAUTHAUTHENDSW, NULL },
+    { "oauth-%s-redirect_uri", OAUTHREDIRSW, NULL },
+    { "oauth-%s-token_endpoint", OAUTHTOKENDSW, NULL },
+    { "oauth-%s-scope", OAUTHSCOPESW, NULL },
+    { NULL, 0, NULL }
+};
 
 struct headers {
     char *value;
@@ -159,50 +145,60 @@ 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                              */
+#define HMIM  0x2000    /* MIME-Version: header                               */
+#define HCTE  0x4000    /* Content-Transfer-Encoding: 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-Sender: */
+#define MEFM  0x0080   /* We've seen Envelope-From: */
+#define MMIM  0x0100    /* We've seen Mime-Version:  */
 
 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 },
+    { "MIME-Version",  HMIM,                MMIM },
+    { "Content-Transfer-Encoding",  HCTE,   0 },
+    { 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 },
@@ -212,12 +208,15 @@ 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 },
+    { "MIME-Version",      HMIM,                MMIM },
+    { "Content-Transfer-Encoding",  HCTE,       0 },
     { NULL,                0,                   0 }
 };
 
@@ -225,8 +224,6 @@ static short fccind = 0;    /* index into fccfold[] */
 static short outputlinelen = OUTPUTLINELEN;
 
 static int pfd = NOTOK;                /* fd to write annotation list to        */
-static uid_t myuid= -1;                /* my user id                            */
-static gid_t mygid= -1;                /* my group id                           */
 static int recipients = 0;     /* how many people will get a copy       */
 static int unkadr = 0;         /* how many of those were unknown        */
 static int badadr = 0;         /* number of bad addrs                   */
@@ -244,8 +241,10 @@ static int nameoutput=0;   /* putadr() has output header name       */
 static int sasl=0;             /* Use SASL auth for SMTP                */
 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 char *port="submission";        /* Name of server port for SMTP submission */
+static int tlsflag=0;          /* Flags to control TLS settings         */
+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 */
 
@@ -261,59 +260,54 @@ static char tmpfil[BUFSIZ];
 static char bccfil[BUFSIZ];
 
 static char from[BUFSIZ];      /* my network address            */
-static char signature[BUFSIZ]; /* my signature                  */
+static char sender[BUFSIZ];    /* my Sender: header             */
+static char efrom[BUFSIZ];     /* my Envelope-From: header      */
+static char fullfrom[BUFSIZ];  /* full contents of From header  */
 static char *filter = NULL;    /* the filter for BCC'ing        */
 static char *subject = NULL;   /* the subject field for BCC'ing */
 static char *fccfold[FCCS];    /* foldernames for FCC'ing       */
+enum encoding { UNKNOWN = 0, BINARY = 1, SEVENBIT = 7, EIGHTBIT = 8 };
+static enum encoding cte = UNKNOWN;
 
 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
  */
-static void putfmt (char *, char *, FILE *);
+static void putfmt (char *, char *, int *, FILE *);
 static void start_headers (void);
 static void finish_headers (FILE *);
-static int get_header (char *, struct headers *);
-static int putadr (char *, char *, struct mailname *, FILE *, unsigned int);
+static int get_header (char *, struct headers *) PURE;
+static int putadr (char *, char *, struct mailname *, FILE *, unsigned int,
+                  char *, unsigned int);
 static void putgrp (char *, char *, FILE *, unsigned int);
 static int insert (struct mailname *);
 static void pl (void);
 static void anno (void);
 static int annoaux (struct mailname *);
-static void insert_fcc (struct headers *, unsigned char *);
+static void insert_fcc (struct headers *, char *);
 static void make_bcc_file (int);
-static void verify_all_addresses (int);
-static void chkadr (void);
+static void verify_all_addresses (int, int, char *, int, char *);
+static void chkadr (void) PURE;
 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 fatal (char *, char *, ...) CHECK_PRINTF(2, 3);
+static void post (char *, int, int, int, char *, int, char *);
 static void do_text (char *file, int fd);
 static void do_an_address (struct mailname *, int);
 static void do_addresses (int, int);
@@ -323,27 +317,23 @@ static int find_prefix (void);
 int
 main (int argc, char **argv)
 {
-    int state, compnum, dashstuff = 0;
-    char *cp, *msg = NULL, **argp, **arguments;
-    char buf[BUFSIZ], name[NAMESZ];
+    int state, compnum, dashstuff = 0, swnum, oauth_flag = 0, tls = -1;
+    int noverify = 0;
+    int eai = 0; /* use Email Address Internationalization (EAI) (SMTPUTF8) */
+    char *cp, *msg = NULL, **argp, **arguments, *envelope;
+    char buf[NMH_BUFSIZ], name[NAMESZ], *auth_svc = NULL;
     FILE *in, *out;
+    m_getfld_state_t gstate;
 
-#ifdef LOCALE
-    setlocale(LC_ALL, "");
-#endif
-    invo_name = r1bindex (argv[0], '/');
-
-    /* foil search of user profile/context */
-    if (context_foil (NULL) == -1)
-       done (1);
+    if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
 
-    mts_init (invo_name);
+    mts_init ();
     arguments = getarguments (invo_name, argc, argv, 0);
     argp = arguments;
 
     while ((cp = *argp++)) {
        if (*cp == '-') {
-           switch (smatch (++cp, switches)) {
+           switch ((swnum = smatch (++cp, switches))) {
                case AMBIGSW: 
                    ambigsw (cp, switches);
                    done (1);
@@ -353,10 +343,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 == '-')
@@ -459,33 +449,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]);
@@ -497,33 +460,59 @@ 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]);
                    continue;
 
-               case QUEUESW:
-                   queued++;
-                   continue;
-               
                case SASLSW:
                    sasl++;
                    continue;
-               
+
+               case NOSASLSW:
+                   sasl = 0;
+                   continue;
+
                case SASLMECHSW:
                    if (!(saslmech = *argp++) || *saslmech == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
                    continue;
-               
+
+               case AUTHSERVICESW:
+                   if (!(auth_svc = *argp++) || *auth_svc == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   oauth_flag++;
+                   continue;
+
+               case OAUTHCREDFILESW:
+               case OAUTHCLIDSW:
+               case OAUTHCLSECSW:
+               case OAUTHAUTHENDSW:
+               case OAUTHREDIRSW:
+               case OAUTHTOKENDSW:
+               case OAUTHSCOPESW:
+               {
+                   int i;
+
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+
+                   for (i = 0; oauthswitches[i].profname != NULL; i++) {
+                       if (oauthswitches[i].switchnum == swnum) {
+                           oauthswitches[i].value = cp;
+                           break;
+                       }
+                   }
+
+                   if (oauthswitches[i].profname == NULL)
+                       adios (NULL, "internal error: cannot map switch %s "
+                              "to profile entry", argp[-2]);
+
+                   oauth_flag++;
+                   continue;
+               }
+
                case USERSW:
                    if (!(user = *argp++) || *user == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -535,14 +524,67 @@ main (int argc, char **argv)
                    continue;
 
                case TLSSW:
-                   tls++;
+                   tls = 1;
+                   continue;
+
+               case INITTLSSW:
+                   tls = 2;
+                   continue;
+
+               case NTLSSW:
+                   tls = 0;
+                   continue;
+
+               case CERTVERSW:
+                   noverify = 0;
+                   continue;
+
+               case NOCERTVERSW:
+                   noverify++;
+                   continue;
+
+               case FILEPROCSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   fileproc = cp;
+                   continue;
+
+               case MHLPROCSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   mhlproc = cp;
+                   continue;
+
+               case MTSSM:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    sendmail = cp;
+                   continue;
+
+               case MTSSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    save_mts_method (cp);
+                   continue;
+
+               case CREDENTIALSSW: {
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   add_profile_entry ("credentials", cp);
+                   continue;
+               }
+
+               case MESSAGEIDSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    if (save_message_id_style (cp) != 0)
+                       adios (NULL, "unsupported messageid \"%s\"", cp);
                    continue;
            }
        }
        if (msg)
            adios (NULL, "only one message at a time!");
-       else
-           msg = cp;
+        msg = cp;
     }
 
     alias (AliasFile);
@@ -559,52 +601,48 @@ main (int argc, char **argv)
     start_headers ();
     if (debug) {
        verbose++;
-       discard (out = stdout); /* XXX: reference discard() to help loader */
+       out = stdout;
     } 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);
-            if (cp == NULL) {
-                cp = m_mktemp2(NULL, invo_name, NULL, &out);
-                if (cp == NULL) {
-                   adios ("post", "unable to create temporary file");
-                }
-            }
+           char *cp = m_mktemp2(NULL, invo_name, NULL, &out);
+           if (cp == NULL) {
+               adios(NULL, "unable to create temporary file in %s",
+                     get_temp_dir());
+           }
             strncpy(tmpfil, cp, sizeof(tmpfil));
-           chmod (tmpfil, 0600);
        }
     }
 
     hdrtab = msgstate == NORMAL ? NHeaders : RHeaders;
 
-    for (compnum = 1, state = FLD;;) {
-       switch (state = m_getfld (state, name, buf, sizeof(buf), in)) {
+    gstate = m_getfld_state_init(in);
+    for (compnum = 1;;) {
+       int bufsz = sizeof buf;
+       switch (state = m_getfld2(&gstate, name, buf, &bufsz)) {
            case FLD: 
-           case FLDEOF: 
            case FLDPLUS: 
-               compnum++;
-               cp = add (buf, NULL);
+                compnum++;
+               cp = mh_xstrdup(buf);
                while (state == FLDPLUS) {
-                   state = m_getfld (state, name, buf, sizeof(buf), in);
+                   bufsz = sizeof buf;
+                   state = m_getfld2(&gstate, name, buf, &bufsz);
                    cp = add (buf, cp);
                }
-               putfmt (name, cp, out);
+               putfmt (name, cp, &eai, out);
                free (cp);
-               if (state != FLDEOF)
-                   continue;
-               finish_headers (out);
-               break;
+               continue;
 
            case BODY: 
-           case BODYEOF: 
                finish_headers (out);
-               if (whomsw && !fill_in)
+               if (whomsw)
                    break;
                fprintf (out, "\n%s", buf);
                while (state == BODY) {
-                   state = m_getfld (state, name, buf, sizeof(buf), in);
+                   bufsz = sizeof buf;
+                   state = m_getfld2(&gstate, name, buf, &bufsz);
                    fputs (buf, out);
                }
                break;
@@ -622,6 +660,7 @@ main (int argc, char **argv)
        }
        break;
     }
+    m_getfld_state_destroy (&gstate);
 
     if (pfd != NOTOK)
        anno ();
@@ -630,35 +669,112 @@ main (int argc, char **argv)
     if (debug) {
        pl ();
        done (0);
+    }
+    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 {
-       fclose (out);
+       envelope = from;
+    }
+
+    if (tls == -1) {
+#ifdef TLS_SUPPORT
+       /*
+        * The user didn't specify any of the tls switches.  Try to
+        * help them by implying -initialtls if they're using port 465
+        * (smtps, until IANA revoked that registration in 1998).
+        */
+       tls = ! strcmp (port, "465")  ||  ! strcasecmp (port, "smtps")
+           ?  2
+           :  0;
+#else  /* ! TLS_SUPPORT */
+       tls = 0;
+#endif /* ! TLS_SUPPORT */
+    }
+
+    if (tls == 1)
+       tlsflag = S_STARTTLS;
+    else if (tls == 2)
+       tlsflag = S_INITTLS;
+    else
+       tlsflag = 0;
+
+    if (noverify)
+       tlsflag |= S_NOVERIFY;
+
+    /*
+     * If we were given any oauth flags, store the appropriate profile
+     * entries and make sure an authservice was given (we have to do this
+     * here because we aren't guaranteed the authservice will be given on
+     * the command line before the other OAuth flags are given).
+     */
+
+    if (oauth_flag) {
+       int i;
+       char sbuf[128];
+
+       if (auth_svc == NULL) {
+           adios(NULL, "No authentication service given with -authservice");
+       }
+
+       for (i = 0; oauthswitches[i].profname != NULL; i++) {
+               if (oauthswitches[i].value != NULL) {
+                   snprintf(sbuf, sizeof(sbuf),
+                   oauthswitches[i].profname, auth_svc);
+                   sbuf[sizeof(sbuf) - 1] = '\0';
+                   add_profile_entry(sbuf, oauthswitches[i].value);
+               }
+       }
     }
 
     /* 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, eai, envelope, oauth_flag, auth_svc);
        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, eai, envelope, oauth_flag,
+                                      auth_svc);
+           }
+           post (tmpfil, 0, verbose, eai, envelope, oauth_flag, auth_svc);
        }
-       post (bccfil, 1, verbose);
-       unlink (bccfil);
+       post (bccfil, 1, verbose, eai, envelope, oauth_flag, auth_svc);
+       (void) m_unlink (bccfil);
     } else {
-       post (tmpfil, 0, isatty (1));
+       post (tmpfil, 0, isatty (1), eai, envelope, oauth_flag, auth_svc);
     }
 
     p_refile (tmpfil);
-    unlink (tmpfil);
+    (void) m_unlink (tmpfil);
+
+    if (verbose) {
+       if (partno)
+           printf ("Partial Message #%s Processed\n", partno);
+       else
+           puts("Message Processed");
+    }
 
-    if (verbose)
-       printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n",
-               partno);
     done (0);
     return 1;
 }
@@ -669,11 +785,13 @@ main (int argc, char **argv)
  */
 
 static void
-putfmt (char *name, char *str, FILE *out)
+putfmt (char *name, char *str, int *eai, FILE *out)
 {
     int count, grp, i, keep;
     char *cp, *pp, *qp;
-    char namep[BUFSIZ];
+    char namep[BUFSIZ], error[BUFSIZ];
+    char *savehdr = NULL;
+    unsigned int savehdrlen = 0;
     struct mailname *mp = NULL, *np = NULL;
     struct headers *hdr;
 
@@ -681,86 +799,143 @@ putfmt (char *name, char *str, FILE *out)
        str++;
 
     if (msgstate == NORMAL && uprf (name, "resent")) {
-       advise (NULL, "illegal header line -- %s:", name);
+       inform("illegal header line -- %s:", name);
        badmsg++;
        return;
     }
 
+    if (! *eai) {
+        /* Check each header field value to see if it has any 8-bit characters.
+           If it does, enable EAI support. */
+        if (contains8bit(str, NULL)) {
+            if (verbose) {
+                puts("EAI/SMTPUTF8 enabled");
+            }
+
+            /* Enable SMTPUTF8. */
+            *eai = 1;
+
+            /* Enable passing of utf-8 setting to getname()/getadrx(). */
+            enable_eai();
+        }
+    }
+
     if ((i = get_header (name, hdrtab)) == NOTOK) {
-       fprintf (out, "%s: %s", name, str);
+        if (strncasecmp (name, "nmh-", 4)) {
+           fprintf (out, "%s: %s", name, str);
+       } else {
+           /* Filter out all Nmh-* headers, because Norm asked.  They
+              should never have reached this point.  Warn about any
+              that are non-empty. */
+           if (strcmp (str, "\n")) {
+                trim_suffix_c(str, '\n');
+               if (! whomsw) {
+                   inform("ignoring header line -- %s: %s", name, str);
+               }
+           }
+       }
+
        return;
     }
 
     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++;
-       }
+       inform("illegal header line -- %s:", name);
+       badmsg++;
        return;
     }
     msgflags |= (hdr->set & ~(MVIS | MINV));
 
     if (hdr->flags & HSUB)
-       subject = subject ? add (str, add ("\t", subject)) : getcpy (str);
+       subject = subject ? add (str, add ("\t", subject)) : mh_xstrdup(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) {
+       for (pp = str; (cp = strchr(pp, ',')); pp = cp) {
            *cp++ = 0;
            insert_fcc (hdr, pp);
        }
        insert_fcc (hdr, pp);
        return;
     }
-
+    if (hdr->flags & HCTE) {
+        if (strncasecmp (str, "7bit", 4) == 0) {
+            cte = SEVENBIT;
+        } else if (strncasecmp (str, "8bit", 4) == 0) {
+            cte = EIGHTBIT;
+        } else if (strncasecmp (str, "binary", 6) == 0) {
+            cte = BINARY;
+        }
+    }
     if (!(hdr->flags & HADR)) {
        fprintf (out, "%s: %s", name, str);
        return;
     }
 
+    /*
+     * If this is a From:/Resent-From: header, save the full thing for
+     * later in case we need it for use when constructing a Bcc draft message.
+     * Because we want to capture the results of alias expansion, save
+     * the output from putadr().
+     */
+
+    if ((msgstate == RESENT) ? (hdr->set & MRFM) : (hdr->set & MFRM)) {
+       savehdr = fullfrom;
+       savehdr[0] = '\0';
+       savehdrlen = sizeof(fullfrom);
+    }
+
     tmpaddrs.m_next = NULL;
-    for (count = 0; (cp = getname (str)); count++)
-       if ((mp = getm (cp, NULL, 0, AD_HOST, NULL))) {
+
+    for (count = 0; (cp = getname (str)); count++) {
+       if ((mp = getm (cp, NULL, 0, error, sizeof(error)))) {
            if (tmpaddrs.m_next)
                np->m_next = mp;
            else
                tmpaddrs.m_next = mp;
            np = mp;
        }
-       else
+       else {
+           admonish(cp, "%s", error);
            if (hdr->flags & HTRY)
                badadr++;
            else
                badmsg++;
+       }
+    }
 
     if (count < 1) {
        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)) {
+               inform("%s: field requires one address", name);
+               badmsg++;
+           }
 #ifdef notdef
-           advise (NULL, "%s: field requires at least one address", name);
+           inform("%s: field requires at least one address", name);
            badmsg++;
 #endif /* notdef */
        }
        return;
     }
 
+    if (count > 1 && (hdr->flags & HONE)) {
+       inform("%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) */
@@ -771,33 +946,68 @@ putfmt (char *name, char *str, FILE *out)
            if (np->m_gname)
                putgrp (namep, np->m_gname, out, hdr->flags);
            while ((cp = getname (pp))) {
-               if (!(mp = getm (cp, NULL, 0, AD_HOST, NULL))) {
+               if (!(mp = getm (cp, NULL, 0, error, sizeof(error)))) {
+                   admonish(cp, "%s", error);
                    badadr++;
                    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++;
                if (np->m_ingrp)
                    mp->m_ingrp = np->m_ingrp;
-               else
-                   if (mp->m_gname)
-                       putgrp (namep, mp->m_gname, out, hdr->flags);
-               if (mp->m_ingrp)
+               else if (mp->m_gname)
+                    putgrp (namep, mp->m_gname, out, hdr->flags);
+               if (mp->m_ingrp) {
+                   if (sm_mts == MTS_SENDMAIL_PIPE) {
+                       /* Catch this before sendmail chokes with:
+                          "553 List:; syntax illegal for recipient
+                           addresses".
+                          If we wanted to, we could expand out blind
+                          aliases and put them in Bcc:, but then
+                          they'd have the Blind-Carbon-Copy
+                          indication. */
+                       adios (NULL,
+                              "blind lists not compatible with"
+                              " sendmail/pipe");
+                   }
+
                    grp++;
-               if (putadr (namep, qp, mp, out, hdr->flags))
+               }
+               if (putadr (namep, qp, mp, out, hdr->flags, savehdr,
+                           savehdrlen))
                    msgflags |= (hdr->set & (MVIS | MINV));
                else
                    mnfree (mp);
@@ -808,17 +1018,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++;
@@ -826,7 +1056,7 @@ putfmt (char *name, char *str, FILE *out)
                putgrp (namep, mp->m_gname, out, hdr->flags);
            if (mp->m_ingrp)
                grp++;
-           keep = putadr (namep, "", mp, out, hdr->flags);
+           keep = putadr (namep, "", mp, out, hdr->flags, savehdr, savehdrlen);
            np = mp->m_next;
            if (keep) {
                mp->m_next = NULL;
@@ -836,13 +1066,22 @@ putfmt (char *name, char *str, FILE *out)
                mnfree (mp);
        }
 
+    /*
+     * If it was a From header, strip off any trailing newlines from
+     * the alias-expanded From line.
+     */
+
+    if ((msgstate == RESENT) ? (hdr->set & MRFM) : (hdr->set & MFRM)) {
+       while (*fullfrom && fullfrom[strlen(fullfrom) - 1] == '\n') {
+           fullfrom[strlen(fullfrom) - 1] = '\0';
+       }
+    }
+
     if (grp > 0 && (hdr->flags & HNGR)) {
-       advise (NULL, "%s: field does not allow groups", name);
+       inform("%s: field does not allow groups", name);
        badmsg++;
     }
     if (linepos) {
-       if (fill_in && grp > 0)
-           putc (';', out);
        putc ('\n', out);
     }
 }
@@ -851,34 +1090,16 @@ putfmt (char *name, char *str, FILE *out)
 static void
 start_headers (void)
 {
-    unsigned char  *cp;
-    char myhost[BUFSIZ], sigbuf[BUFSIZ];
-    struct mailname *mp;
-
-    myuid = getuid ();
-    mygid = getgid ();
     time (&tclock);
 
-    strncpy (from, adrsprintf (NULL, NULL), sizeof(from));
-    strncpy (myhost, LocalName (), sizeof(myhost));
-
-    for (cp = myhost; *cp; cp++)
-       *cp = uptolow (*cp);
-
-    if ((cp = getfullname ()) && *cp) {
-       strncpy (sigbuf, cp, sizeof(sigbuf));
-       snprintf (signature, sizeof(signature), "%s <%s>",
-               sigbuf, adrsprintf (NULL, NULL));
-       if ((cp = getname (signature)) == NULL)
-           adios (NULL, "getname () failed -- you lose extraordinarily big");
-       if ((mp = getm (cp, NULL, 0, AD_HOST, NULL)) == NULL)
-           adios (NULL, "bad signature '%s'", sigbuf);
-       mnfree (mp);
-       while (getname (""))
-           continue;
-    } else {
-       strncpy (signature, adrsprintf (NULL, NULL), sizeof(signature));
-    }
+    /*
+     * Probably not necessary, but just in case ...
+     */
+
+    from[0] = '\0';
+    efrom[0] = '\0';
+    sender[0] = '\0';
+    fullfrom[0] = '\0';
 }
 
 
@@ -893,62 +1114,96 @@ finish_headers (FILE *out)
 {
     switch (msgstate) {
        case NORMAL: 
-           if (whomsw && !fill_up)
+           if (!(msgflags & MFRM)) {
+               /*
+                * A From: header is now required in the draft.
+                */
+               inform("message has no From: header");
+               inform("See default components files for examples");
+               badmsg++;
                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);
+           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
+               inform("A Sender: or Envelope-From: header is required "
+                       "with multiple\nFrom: addresses");
+               badmsg++;
+               break;
            }
-           else
-               /* Construct a From: header. */
-               fprintf (out, "From: %s\n", signature);
+
            if (whomsw)
                break;
 
+           fprintf (out, "Date: %s\n", dtime (&tclock, 0));
+           if (msgid)
+               fprintf (out, "Message-ID: %s\n", message_id (tclock, 0));
+           /*
+            * 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') {
+                   inform("Envelope-From cannot be blank when there "
+                           "is multiple From: addresses\nand no Sender: "
+                           "header");
+                   badmsg++;
+               } else {
+                   fprintf (out, "Sender: %s\n", efrom);
+               }
+           }
+
            if (!(msgflags & MVIS))
                fprintf (out, "Bcc: Blind Distribution List: ;\n");
            break;
 
        case RESENT: 
            if (!(msgflags & MDAT)) {
-               advise (NULL, "message has no Date: header");
+               inform("message has no Date: header");
                badmsg++;
            }
            if (!(msgflags & MFRM)) {
-               advise (NULL, "message has no From: header");
+               inform("message has no From: header");
+               badmsg++;
+           }
+           if (!(msgflags & MRFM)) {
+               inform("message has no Resent-From: header");
+               inform("See default components files for examples");
+               badmsg++;
+               break;
+           }
+           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
+               inform("A Resent-Sender: or Envelope-From: header is "
+                       "required with multiple\nResent-From: addresses");
                badmsg++;
+               break;
            }
-           if (whomsw && !fill_up)
+
+           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);
+               fprintf (out, "Resent-Message-ID: %s\n",
+                        message_id (tclock, 0));
+           /*
+            * 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') {
+                   inform("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;
@@ -967,7 +1222,7 @@ get_header (char *header, struct headers *table)
     struct headers *h;
 
     for (h = table; h->value; h++)
-       if (!mh_strcasecmp (header, h->value))
+       if (!strcasecmp (FENDNULL(header), FENDNULL(h->value)))
            return (h - table);
 
     return NOTOK;
@@ -975,15 +1230,18 @@ get_header (char *header, struct headers *table)
 
 
 static int
-putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flags)
+putadr (char *name, char *aka, struct mailname *mp, FILE *out,
+       unsigned int flags, char *savehdr, unsigned int savehdrsize)
 {
-    int len;
+    int len, saveappend = 0;
+    unsigned int shlen;
     char *cp;
     char buffer[BUFSIZ];
 
     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) {
@@ -991,10 +1249,15 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
        linepos += (nameoutput = strlen (name) + 2);
     }
 
+    if (savehdr) {
+       shlen = strlen(savehdr);
+       saveappend = 1;
+    }
+
     if (*aka && mp->m_type != UUCPHOST && !mp->m_pers)
-       mp->m_pers = getcpy (aka);
+       mp->m_pers = mh_xstrdup(aka);
     if (format) {
-       if (mp->m_gname && !fill_in) {
+       if (mp->m_gname) {
            snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname);
            cp = buffer;
        } else {
@@ -1006,15 +1269,34 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
     len = strlen (cp);
 
     if (linepos != nameoutput) {
-       if (len + linepos + 2 > outputlinelen)
+       if (len + linepos + 2 > outputlinelen) {
            fprintf (out, ",\n%*s", linepos = nameoutput, "");
-       else {
+           if (saveappend) {
+               if (shlen + 2 + nameoutput + len >= savehdrsize) {
+                   saveappend = 0;
+               } else {
+                   snprintf(savehdr + shlen, savehdrsize - shlen, ",\n%*s",
+                            linepos, "");
+               }
+           }
+       } else {
            fputs (", ", out);
            linepos += 2;
+           if (saveappend) {
+               if (shlen + 2 + len >= savehdrsize) {
+                   saveappend = 0;
+               } else {
+                   strncat(savehdr, ", ", savehdrsize - shlen);
+               }
+           }
        }
     }
 
     fputs (cp, out);
+
+    if (saveappend && shlen + len < savehdrsize)
+       strncat(savehdr, cp, savehdrsize - shlen + len);
+
     linepos += len;
 
     return (flags & HTRY);
@@ -1027,17 +1309,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) {
@@ -1069,9 +1349,11 @@ insert (struct mailname *np)
            : &netaddrs;
            mp->m_next;
            mp = mp->m_next)
-       if (!mh_strcasecmp (np->m_host, mp->m_next->m_host)
-               && !mh_strcasecmp (np->m_mbox, mp->m_next->m_mbox)
-               && np->m_bcc == mp->m_next->m_bcc)
+       if (!strcasecmp (FENDNULL(np->m_host),
+                        FENDNULL(mp->m_next->m_host)) &&
+           !strcasecmp (FENDNULL(np->m_mbox),
+                        FENDNULL(mp->m_next->m_mbox)) &&
+           np->m_bcc == mp->m_next->m_bcc)
            return 0;
 
     mp->m_next = np;
@@ -1094,7 +1376,7 @@ pl (void)
 
     printf ("\nnet:\t");
     for (mp = netaddrs.m_next; mp; mp = mp->m_next)
-       printf ("%s%s@%s%s%s", mp->m_path ? mp->m_path : "",
+       printf ("%s%s@%s%s%s", FENDNULL(mp->m_path),
                mp->m_mbox, mp->m_host,
                mp->m_bcc ? "[BCC]" : "",
                mp->m_next ? ",\n\t" : "");
@@ -1108,7 +1390,7 @@ pl (void)
     printf ("\n\t-- Folder Copies --\nfcc:\t");
     for (i = 0; i < fccind; i++)
        printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : "");
-    printf ("\n");
+    putchar('\n');
 }
 
 
@@ -1149,13 +1431,13 @@ annoaux (struct mailname *mp)
 
 
 static void
-insert_fcc (struct headers *hdr, unsigned char *pp)
+insert_fcc (struct headers *hdr, char *pp)
 {
-    unsigned char *cp;
+    char *cp;
 
-    for (cp = pp; isspace (*cp); cp++)
+    for (cp = pp; isspace ((unsigned char) *cp); cp++)
        continue;
-    for (pp += strlen (pp) - 1; pp > cp && isspace (*pp); pp--)
+    for (pp += strlen (pp) - 1; pp > cp && isspace ((unsigned char) *pp); pp--)
        continue;
     if (pp >= cp)
        *++pp = 0;
@@ -1164,7 +1446,7 @@ insert_fcc (struct headers *hdr, unsigned char *pp)
 
     if (fccind >= FCCS)
        adios (NULL, "too many %ss", hdr->value);
-    fccfold[fccind++] = getcpy (cp);
+    fccfold[fccind++] = mh_xstrdup(cp);
 }
 
 /*
@@ -1176,31 +1458,19 @@ make_bcc_file (int dashstuff)
 {
     int fd, i;
     pid_t child_id;
-    char *vec[6];
+    char **vec;
     FILE *out;
-    char *tfile = NULL;
+    char *tfile = NULL, *program;
 
-    tfile = m_mktemp2(NULL, "bccs", NULL, &out);
-    if (tfile == NULL) adios("bcc", "unable to create temporary file");
-    chmod (bccfil, 0600);
+    if ((tfile = m_mktemp2(NULL, "bccs", NULL, &out)) == NULL) {
+       adios(NULL, "unable to create temporary file in %s", get_temp_dir());
+    }
     strncpy (bccfil, tfile, sizeof(bccfil));
 
+    fprintf (out, "From: %s\n", fullfrom);
     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);
+       fprintf (out, "Message-ID: %s\n", message_id (tclock, 0));
     if (subject)
        fprintf (out, "Subject: %s", subject);
     fprintf (out, "BCC:\n");
@@ -1222,11 +1492,10 @@ make_bcc_file (int dashstuff)
        while (find_prefix () == NOTOK) {
            if (*cp < 'z')
                (*cp)++;
-           else
-               if (*++cp == 0)
-                   adios (NULL, "can't find a unique delimiter string");
-               else
-                   (*cp)++;
+           else if (*++cp == 0)
+                adios (NULL, "can't find a unique delimiter string");
+            else
+                (*cp)++;
        }
 
        fprintf (out, "%s: %s\n%s: multipart/digest; boundary=\"",
@@ -1243,10 +1512,7 @@ make_bcc_file (int dashstuff)
      * of MIME encapsulation.
      */
     if (filter != NULL) {
-       vec[0] = r1bindex (mhlproc, '/');
-
-       for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
-           sleep (5);
+       child_id = fork();
        switch (child_id) {
            case NOTOK: 
                adios ("fork", "unable to");
@@ -1254,7 +1520,7 @@ make_bcc_file (int dashstuff)
            case OK: 
                dup2 (fileno (out), 1);
 
-               i = 1;
+               vec = argsplit(mhlproc, &program, &i);
                vec[i++] = "-forward";
                vec[i++] = "-form";
                vec[i++] = filter;
@@ -1267,7 +1533,7 @@ make_bcc_file (int dashstuff)
                    vec[i++] = "-nodashstuffing";
                vec[i] = NULL;
 
-               execvp (mhlproc, vec);
+               execvp (program, vec);
                fprintf (stderr, "unable to exec ");
                perror (mhlproc);
                _exit (-1);
@@ -1310,18 +1576,18 @@ static int
 find_prefix (void)
 {
     int        result = OK;
-    unsigned char buffer[BUFSIZ];
+    char buffer[BUFSIZ];
     FILE *in;
 
     if ((in = fopen (tmpfil, "r")) == NULL)
        adios (tmpfil, "unable to re-open");
 
-    while (fgets (buffer, sizeof(buffer) - 1, in))
+    while (fgets (buffer, sizeof buffer, in))
        if (buffer[0] == '-' && buffer[1] == '-') {
-           unsigned char *cp;
+           char *cp;
 
            for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
-               if (!isspace (*cp))
+               if (!isspace ((unsigned char) *cp))
                    break;
            *++cp = '\0';
            if (strcmp (buffer + 2, prefix) == 0) {
@@ -1335,18 +1601,16 @@ find_prefix (void)
 }
 
 
-#define        plural(x) (x == 1 ? "" : "s")
-
 static void
 chkadr (void)
 {
     if (badadr && unkadr)
-       die (NULL, "%d address%s unparsable, %d addressee%s undeliverable",
-               badadr, plural (badadr), unkadr, plural (badadr));
+       fatal (NULL, "%d address%s unparsable, %d addressee%s undeliverable",
+               badadr, PLURALS(badadr), unkadr, PLURALS(badadr));
     if (badadr)
-       die (NULL, "%d address%s unparsable", badadr, plural (badadr));
+       fatal (NULL, "%d address%s unparsable", badadr, PLURALS(badadr));
     if (unkadr)
-       die (NULL, "%d addressee%s undeliverable", unkadr, plural (unkadr));
+       fatal (NULL, "%d addressee%s undeliverable", unkadr, PLURALS(unkadr));
 }
 
 
@@ -1361,7 +1625,7 @@ do_addresses (int bccque, int talk)
     for (lp = localaddrs.m_next; lp; lp = lp->m_next)
        if (lp->m_bcc ? bccque : !bccque) {
            if (talk && !state)
-               printf ("  -- Local Recipients --\n");
+               puts("  -- Local Recipients --");
            do_an_address (lp, talk);
            state++;
        }
@@ -1370,7 +1634,7 @@ do_addresses (int bccque, int talk)
     for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
        if (lp->m_bcc ? bccque : !bccque) {
            if (talk && !state)
-               printf ("  -- UUCP Recipients --\n");
+               puts("  -- UUCP Recipients --");
            do_an_address (lp, talk);
            state++;
        }
@@ -1379,17 +1643,15 @@ do_addresses (int bccque, int talk)
     for (lp = netaddrs.m_next; lp; lp = lp->m_next)
        if (lp->m_bcc ? bccque : !bccque) {
            if (talk && !state)
-               printf ("  -- Network Recipients --\n");
+               puts("  -- Network Recipients --");
            do_an_address (lp, talk);
            state++;
        }
 
     chkadr ();
 
-#ifdef SMTPMTS
     if (rp_isbad (retval = sm_waend ()))
-       die (NULL, "problem ending addresses; %s", rp_string (retval));
-#endif /* SMTPMTS */
+       fatal (NULL, "problem ending addresses; %s", rp_string (retval));
 }
 
 
@@ -1402,93 +1664,147 @@ 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, int eai, char *envelope,
+      int oauth_flag, char *auth_svc)
 {
-    int fd, onex;
-    int        retval;
+    int retval;
+    pid_t child_id;
 
-    onex = !(msgflags & MINV) || bccque;
     if (verbose) {
        if (msgflags & MINV)
            printf (" -- Posting for %s Recipients --\n",
                    bccque ? "Blind" : "Sighted");
        else
-           printf (" -- Posting for All Recipients --\n");
+           puts(" -- Posting for All Recipients --");
     }
 
     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 **argp, *program;
+       int argc;
 
-    sm_end (onex ? OK : DONE);
-    sigoff ();
+       child_id = fork();
+       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 = argsplit(sendmail, &program, &argc);
+               argp[argc++] = "-t"; /* read msg for recipients */
+               argp[argc++] = "-i"; /* don't stop on "." */
+               if (whomsw)
+                   argp[argc++] = "-bv";
+               if (snoop)
+                   argp[argc++] = "-v";
+               argp[argc] = NULL;
+
+               execv (program, argp);
+               adios (sendmail, "can't exec");
+
+           default: 
+               pidXwait (child_id, NULL);
+               break;
+       }
+    } else {
+        const int fd = open (file, O_RDONLY);
+        int eightbit = 0;
+
+        if (fd == NOTOK) {
+          fatal (file, "unable to re-open");
+        }
+
+        if (msgflags & MMIM  &&  cte != UNKNOWN) {
+            /* MIME message with C-T-E header.  (BINARYMIME isn't
+               supported, use 8BITMIME instead for binary.) */
+            eightbit = cte != SEVENBIT;
+        } else {
+            if (scan_input (fd, &eightbit) == NOTOK) {
+                close (fd);
+                fatal (file, "problem reading from");
+            }
+        }
+
+       if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
+                                       verbose, snoop, sasl, saslmech, user,
+                                       oauth_flag ? auth_svc : NULL, tlsflag))
+               || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
+           close (fd);
+           fatal (NULL, "problem initializing server; %s", rp_string (retval));
+       }
+
+        do_addresses (bccque, talk && verbose);
+        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
+               puts(" -- Recipient Copies Posted --");
+        }
+
+        fflush (stdout);
+    }
 }
 
 
 /* Address Verification */
 
 static void
-verify_all_addresses (int talk)
+verify_all_addresses (int talk, int eai, char *envelope, int oauth_flag,
+                      char *auth_svc)
 {
     int retval;
     struct mailname *lp;
 
     sigon ();
 
-    if (!whomsw || checksw)
+    if (!whomsw || checksw) {
+        /* Not sending message body, so don't need to use 8BITMIME. */
+        const int eightbit = 0;
+
        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)))
-           die (NULL, "problem initializing server; %s", rp_string (retval));
+                                       verbose, snoop, sasl, saslmech, user,
+                                       oauth_flag ? auth_svc : NULL, tlsflag))
+               || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
+           fatal (NULL, "problem initializing server; %s", rp_string (retval));
+       }
+    }
 
     if (talk && !whomsw)
-       printf (" -- Address Verification --\n");
+       puts(" -- Address Verification --");
     if (talk && localaddrs.m_next)
-       printf ("  -- Local Recipients --\n");
+       puts("  -- Local Recipients --");
     for (lp = localaddrs.m_next; lp; lp = lp->m_next)
        do_an_address (lp, talk);
 
     if (talk && uuaddrs.m_next)
-       printf ("  -- UUCP Recipients --\n");
+       puts("  -- UUCP Recipients --");
     for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
        do_an_address (lp, talk);
 
     if (talk && netaddrs.m_next)
-       printf ("  -- Network Recipients --\n");
+       puts("  -- Network Recipients --");
     for (lp = netaddrs.m_next; lp; lp = lp->m_next)
        do_an_address (lp, talk);
 
     chkadr ();
     if (talk && !whomsw)
-       printf (" -- Address Verification Successful --\n");
+       puts(" -- Address Verification Successful --");
 
     if (!whomsw || checksw)
-       sm_end (DONE);
+       sm_end (whomsw ? OK : DONE);
 
     fflush (stdout);
     sigoff ();
@@ -1537,7 +1853,7 @@ do_an_address (struct mailname *lp, int talk)
                         lp->m_type != UUCPHOST ? lp->m_path : NULL)) {
        case RP_OK: 
            if (talk)
-               printf ("address ok\n");
+               puts("address ok");
            break;
 
        case RP_NO: 
@@ -1552,7 +1868,7 @@ do_an_address (struct mailname *lp, int talk)
        default: 
            if (!talk)
                fprintf (stderr, "  %s: ", addr);
-           die (NULL, "unexpected response; %s", rp_string (retval));
+           fatal (NULL, "unexpected response; %s", rp_string (retval));
     }
 
     fflush (stdout);
@@ -1565,15 +1881,15 @@ do_text (char *file, int fd)
     int retval, state;
     char buf[BUFSIZ];
 
-    lseek (fd, (off_t) 0, SEEK_SET);
+    lseek(fd, 0, SEEK_SET);
 
     while ((state = read (fd, buf, sizeof(buf))) > 0) {
        if (rp_isbad (retval = sm_wtxt (buf, state)))
-           die (NULL, "problem writing text; %s\n", rp_string (retval));
+           fatal (NULL, "problem writing text; %s\n", rp_string (retval));
     }
 
     if (state == NOTOK)
-       die (file, "problem reading from");
+       fatal (file, "problem reading from");
 
     switch (retval = sm_wtend ()) {
        case RP_OK: 
@@ -1581,35 +1897,30 @@ do_text (char *file, int fd)
 
        case RP_NO: 
        case RP_NDEL: 
-           die (NULL, "posting failed; %s", rp_string (retval));
+           fatal (NULL, "posting failed; %s", rp_string (retval));
+           break;
 
        default: 
-           die (NULL, "unexpected response; %s", rp_string (retval));
+           fatal (NULL, "unexpected response; %s", rp_string (retval));
     }
 }
 
-#endif /* SMTPMTS */
-
 
 /*
  * SIGNAL HANDLING
  */
 
-static RETSIGTYPE
+static void
 sigser (int i)
 {
-#ifndef RELIABLE_SIGNALS
-    SIGNAL (i, SIG_IGN);
-#endif
+    NMH_UNUSED (i);
 
-    unlink (tmpfil);
+    (void) m_unlink (tmpfil);
     if (msgflags & MINV)
-       unlink (bccfil);
+       (void) m_unlink (bccfil);
 
-#ifdef SMTPMTS
     if (!whomsw || checksw)
        sm_end (NOTOK);
-#endif /* SMTPMTS */
 
     done (1);
 }
@@ -1653,11 +1964,11 @@ p_refile (char *file)
        return;
 
     if (verbose)
-       printf (" -- Filing Folder Copies --\n");
+       puts(" -- Filing Folder Copies --");
     for (i = 0; i < fccind; i++)
        fcc (file, fccfold[i]);
     if (verbose)
-       printf (" -- Folder Copies Filed --\n");
+       puts(" -- Folder Copies Filed --");
 }
 
 
@@ -1669,16 +1980,15 @@ static void
 fcc (char *file, char *folder)
 {
     pid_t child_id;
-    int i, status;
+    int status, argp;
     char fold[BUFSIZ];
+    char **arglist, *program;
 
     if (verbose)
        printf ("  %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder);
     fflush (stdout);
 
-    for (i = 0; (child_id = fork ()) == NOTOK && i < 5; i++)
-       sleep (5);
-
+    child_id = fork();
     switch (child_id) {
        case NOTOK: 
            if (!verbose)
@@ -1693,8 +2003,14 @@ fcc (char *file, char *folder)
                    *folder == '+' || *folder == '@' ? "" : "+", folder);
 
            /* now exec the fileproc */
-           execlp (fileproc, r1bindex (fileproc, '/'),
-                   "-link", "-file", file, fold, NULL);
+
+           arglist = argsplit(fileproc, &program, &argp);
+           arglist[argp++] = "-link";
+           arglist[argp++] = "-file";
+           arglist[argp++] = file;
+           arglist[argp++] = fold;
+           arglist[argp] = NULL;
+           execvp (program, arglist);
            _exit (-1);
 
        default: 
@@ -1702,10 +2018,10 @@ fcc (char *file, char *folder)
                if (!verbose)
                    fprintf (stderr, "  %sFcc %s: ",
                            msgstate == RESENT ? "Resent-" : "", folder);
-               pidstatus (status, verbose ? stdout : stderr, NULL);
+               pidstatus (status, verbose ? stdout : stderr, fileproc);
            } else {
                if (verbose)
-                   printf ("folder ok\n");
+                   puts("folder ok");
            }
     }
 
@@ -1717,20 +2033,22 @@ fcc (char *file, char *folder)
  */
 
 static void
-die (char *what, char *fmt, ...)
+fatal (char *what, char *fmt, ...)
 {
+    int err;
     va_list ap;
 
-    unlink (tmpfil);
+    err = errno;
+
+    (void) m_unlink (tmpfil);
     if (msgflags & MINV)
-       unlink (bccfil);
+       (void) m_unlink (bccfil);
 
-#ifdef SMTPMTS
     if (!whomsw || checksw)
        sm_end (NOTOK);
-#endif /* SMTPMTS */
 
     va_start(ap, fmt);
+    errno = err;
     advertise (what, NULL, fmt, ap);
     va_end(ap);
     done (1);