]> diplodocus.org Git - nmh/blobdiff - uip/post.c
Add basic support for the STLS command in POP
[nmh] / uip / post.c
index e78677f831106cd195edb6967e0d82019c9aac8b..86c53ae79a12dff8422563c63d35b8f02d286553 100644 (file)
@@ -1,29 +1,46 @@
-
-/*
- * 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
  * complete copyright information.
  */
 
-#include <h/mh.h>
+#include "h/mh.h"
+#include "sbr/dtime.h"
+#include "sbr/m_getfld.h"
+#include "sbr/getarguments.h"
+#include "sbr/concat.h"
+#include "sbr/smatch.h"
+#include "sbr/cpydata.h"
+#include "sbr/cpydgst.h"
+#include "sbr/uprf.h"
+#include "sbr/context_foil.h"
+#include "sbr/readconfig.h"
+#include "sbr/ambigsw.h"
+#include "sbr/pidstatus.h"
+#include "sbr/print_version.h"
+#include "sbr/print_help.h"
+#include "sbr/arglist.h"
+#include "sbr/error.h"
 #include <fcntl.h>
-#include <h/signals.h>
-#include <h/addrsbr.h>
-#include <h/aliasbr.h>
-#include <h/dropsbr.h>
-#include <h/mime.h>
-#include <h/utils.h>
-#include <h/tws.h>
-#include <h/mts.h>
+#include "h/signals.h"
+#include "h/addrsbr.h"
+#include "h/aliasbr.h"
+#include "h/dropsbr.h"
+#include "h/mime.h"
+#include "h/done.h"
+#include "h/utils.h"
+#include "h/tws.h"
+#include "h/mts.h"
+#include "sbr/m_mktemp.h"
+#include "sbr/message_id.h"
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
 #include <time.h>
 
-#include <mts/smtp/smtp.h>
+#include "mts/smtp/smtp.h"
 
 #ifndef CYRUS_SASL
 # define SASLminc(a) (a)
@@ -40,7 +57,7 @@
 #ifndef OAUTH_SUPPORT
 # define OAUTHminc(a)  (a)
 #else /* OAUTH_SUPPORT */
-# define OAUTHmine(a)  0
+# define OAUTHminc(a)  0
 #endif /* OAUTH_SUPPORT */
 
 #define FCCS           10      /* max number of fccs allowed */
     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("saslmaxssf", SASLminc(-10), SASLMXSSFSW) \
-    X("saslmech", SASLminc(-5), SASLMECHSW) \
+    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("oauthcredfile", OAUTHminc(-7), OAUTHCREDFILESW) \
-    X("oauthclientid", OAUTHminc(-12), OAUTHCLIDSW) \
-    X("oauthclientsecret", OAUTHminc(-12), OAUTHCLSECSW) \
-    X("oauthauthendpoint", OAUTHminc(-6), OAUTHAUTHENDSW) \
-    X("oauthredirect", OAUTHminc(-6), OAUTHREDIRSW) \
-    X("oauthtokenendpoint", OAUTHminc(-6), OAUTHTOKENDSW) \
-    X("oauthscope", OAUTHminc(-6), OAUTHSCOPESW) \
+    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);
@@ -114,6 +133,26 @@ 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;
     unsigned int flags;
@@ -137,6 +176,8 @@ struct headers {
 #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
@@ -147,9 +188,9 @@ struct headers {
 #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 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 },
@@ -166,6 +207,8 @@ static struct headers NHeaders[] = {
     { "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 }
 };
 
@@ -189,6 +232,8 @@ static struct headers RHeaders[] = {
     { "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 }
 };
 
@@ -196,28 +241,27 @@ static short fccind = 0;  /* index into fccfold[] */
 static short outputlinelen = OUTPUTLINELEN;
 
 static int pfd = NOTOK;                /* fd to write annotation list to        */
-static int recipients = 0;     /* how many people will get a copy       */
+static bool recipients;        /* 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                   */
-static int badmsg = 0;         /* message has bad semantics             */
-static int verbose = 0;                /* spell it out                          */
-static int format = 1;         /* format addresses                      */
-static int mime = 0;           /* use MIME-style encapsulations for Bcc */
-static int msgid = 0;          /* add msgid                             */
-static int debug = 0;          /* debugging post                        */
-static int watch = 0;          /* watch the delivery process            */
-static int whomsw = 0;         /* we are whom not post                  */
-static int checksw = 0;                /* whom -check                           */
+static bool badmsg;            /* message has bad semantics             */
+static bool verbose;           /* spell it out                          */
+static bool format = true;     /* format addresses                      */
+static bool mime;              /* use MIME-style encapsulations for Bcc */
+static bool msgid;             /* add msgid                             */
+static bool debug;             /* debugging post                        */
+static bool watch;             /* watch the delivery process            */
+static bool whomsw;            /* we are whom not post                  */
+static bool checksw;           /* 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 bool sasl;              /* 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="submission";        /* Name of server port for SMTP submission */
-static int tls=-1;             /* Use TLS for encryption                */
+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 bool seensender;        /* Have we seen a Sender: header?        */
 
 static unsigned msgflags = 0;  /* what we've seen */
 
@@ -239,6 +283,8 @@ 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 */
 
@@ -247,7 +293,7 @@ static struct mailname netaddrs;            /* network addrs   */
 static struct mailname uuaddrs;                        /* uucp addrs      */
 static struct mailname tmpaddrs;               /* temporary queue */
 
-static int snoop      = 0;
+static bool snoop;
 static char *clientsw = NULL;
 static char *serversw = NULL;
 
@@ -258,11 +304,12 @@ static char *partno = NULL;
 /*
  * 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);
@@ -270,14 +317,14 @@ static void anno (void);
 static int annoaux (struct mailname *);
 static void insert_fcc (struct headers *, char *);
 static void make_bcc_file (int);
-static void verify_all_addresses (int, char *);
+static void verify_all_addresses (int, int, char *, 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, char *);
+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);
@@ -287,26 +334,30 @@ static int find_prefix (void);
 int
 main (int argc, char **argv)
 {
-    int state, compnum, dashstuff = 0;
+    int state, compnum, dashstuff = 0, swnum;
+    bool oauth_flag = false;
+    int tls = -1;
+    bool noverify = false;
+    int eai = 0; /* use Email Address Internationalization (EAI) (SMTPUTF8) */
     char *cp, *msg = NULL, **argp, **arguments, *envelope;
-    char buf[BUFSIZ], name[NAMESZ];
+    char buf[NMH_BUFSIZ], name[NAMESZ], *auth_svc = NULL;
     FILE *in, *out;
-    m_getfld_state_t gstate = 0;
+    m_getfld_state_t gstate;
 
-    if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
+    if (nmh_init(argv[0], false, false)) { 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);
                case UNKWNSW: 
-                   adios (NULL, "-%s unknown", cp);
+                   die("-%s unknown", cp);
 
                case HELPSW: 
                    snprintf (buf, sizeof(buf), "%s [switches] file", invo_name);
@@ -318,7 +369,7 @@ main (int argc, char **argv)
 
                case LIBSW:
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    /* create a minimal context */
                    if (context_foil (cp) == -1)
                        done (1);
@@ -326,21 +377,21 @@ main (int argc, char **argv)
 
                case ALIASW: 
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    if ((state = alias (cp)) != AK_OK)
-                       adios (NULL, "aliasing error in %s - %s",
+                       die("aliasing error in %s - %s",
                                cp, akerror (state));
                    continue;
 
                case CHKSW: 
-                   checksw++;
+                   checksw = true;
                    continue;
                case NCHKSW: 
-                   checksw = 0;
+                   checksw = false;
                    continue;
 
                case DEBUGSW: 
-                   debug++;
+                   debug = true;
                    continue;
 
                case DISTSW:
@@ -349,18 +400,18 @@ main (int argc, char **argv)
 
                case FILTSW:
                    if (!(filter = *argp++) || *filter == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
-                   mime = 0;
+                       die("missing argument to %s", argp[-2]);
+                   mime = false;
                    continue;
                case NFILTSW:
                    filter = NULL;
                    continue;
                
                case FRMTSW: 
-                   format++;
+                   format = true;
                    continue;
                case NFRMTSW: 
-                   format = 0;
+                   format = false;
                    continue;
 
                case BITSTUFFSW:
@@ -371,96 +422,124 @@ main (int argc, char **argv)
                    continue;
 
                case MIMESW:
-                   mime++;
+                   mime = true;
                    filter = NULL;
                    continue;
                case NMIMESW: 
-                   mime = 0;
+                   mime = false;
                    continue;
 
                case MSGDSW: 
-                   msgid++;
+                   msgid = true;
                    continue;
                case NMSGDSW: 
-                   msgid = 0;
+                   msgid = false;
                    continue;
 
                case VERBSW: 
-                   verbose++;
+                   verbose = true;
                    continue;
                case NVERBSW: 
-                   verbose = 0;
+                   verbose = false;
                    continue;
 
                case WATCSW: 
-                   watch++;
+                   watch = true;
                    continue;
                case NWATCSW: 
-                   watch = 0;
+                   watch = false;
                    continue;
 
                case WHOMSW: 
-                   whomsw++;
+                   whomsw = true;
                    continue;
 
                case WIDTHSW: 
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    if ((outputlinelen = atoi (cp)) < 10)
-                       adios (NULL, "impossible width %d", outputlinelen);
+                       die("impossible width %d", outputlinelen);
                    continue;
 
                case ANNOSW: 
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    if ((pfd = atoi (cp)) <= 2)
-                       adios (NULL, "bad argument %s %s", argp[-2], cp);
+                       die("bad argument %s %s", argp[-2], cp);
                    continue;
 
                case CLIESW:
                    if (!(clientsw = *argp++) || *clientsw == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
                case SERVSW:
                    if (!(serversw = *argp++) || *serversw == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
                case SNOOPSW:
-                   snoop++;
+                   snoop = true;
                    continue;
 
                case PARTSW:
                    if (!(partno = *argp++) || *partno == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
 
                case SASLSW:
-                   sasl++;
+                   sasl = true;
                    continue;
 
                case NOSASLSW:
-                   sasl = 0;
+                   sasl = false;
                    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 == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
-               
+
+               case AUTHSERVICESW:
+                   if (!(auth_svc = *argp++) || *auth_svc == '-')
+                       die("missing argument to %s", argp[-2]);
+                   oauth_flag = true;
+                   continue;
+
+               case OAUTHCREDFILESW:
+               case OAUTHCLIDSW:
+               case OAUTHCLSECSW:
+               case OAUTHAUTHENDSW:
+               case OAUTHREDIRSW:
+               case OAUTHTOKENDSW:
+               case OAUTHSCOPESW:
+               {
+                   int i;
+
+                   if (!(cp = *argp++) || *cp == '-')
+                       die("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)
+                       die("internal error: cannot map switch %s "
+                              "to profile entry", argp[-2]);
+
+                   oauth_flag = true;
+                   continue;
+               }
+
                case USERSW:
                    if (!(user = *argp++) || *user == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
 
                case PORTSW:
                    if (!(port = *argp++) || *port == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    continue;
 
                case TLSSW:
@@ -475,65 +554,72 @@ main (int argc, char **argv)
                    tls = 0;
                    continue;
 
+               case CERTVERSW:
+                   noverify = false;
+                   continue;
+
+               case NOCERTVERSW:
+                   noverify = true;
+                   continue;
+
                case FILEPROCSW:
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    fileproc = cp;
                    continue;
 
                case MHLPROCSW:
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                    mhlproc = cp;
                    continue;
 
                case MTSSM:
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("missing argument to %s", argp[-2]);
                     sendmail = cp;
                    continue;
 
                case MTSSW:
                    if (!(cp = *argp++) || *cp == '-')
-                       adios (NULL, "missing argument to %s", argp[-2]);
+                       die("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]);
+                       die("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]);
+                       die("missing argument to %s", argp[-2]);
                     if (save_message_id_style (cp) != 0)
-                       adios (NULL, "unsupported messageid \"%s\"", cp);
+                       die("unsupported messageid \"%s\"", cp);
                    continue;
            }
        }
        if (msg)
-           adios (NULL, "only one message at a time!");
-       else
-           msg = cp;
+           die("only one message at a time!");
+        msg = cp;
     }
 
     alias (AliasFile);
 
     if (!msg)
-       adios (NULL, "usage: %s [switches] file", invo_name);
+       die("usage: %s [switches] file", invo_name);
 
     if (outputlinelen < 10)
-       adios (NULL, "impossible width %d", outputlinelen);
+       die("impossible width %d", outputlinelen);
 
     if ((in = fopen (msg, "r")) == NULL)
        adios (msg, "unable to open");
 
     start_headers ();
     if (debug) {
-       verbose++;
+       verbose = true;
        out = stdout;
     } else {
        if (whomsw) {
@@ -542,7 +628,7 @@ main (int argc, char **argv)
        } else {
            char *cp = m_mktemp2(NULL, invo_name, NULL, &out);
            if (cp == NULL) {
-               adios(NULL, "unable to create temporary file in %s",
+               die("unable to create temporary file in %s",
                      get_temp_dir());
            }
             strncpy(tmpfil, cp, sizeof(tmpfil));
@@ -551,19 +637,20 @@ main (int argc, char **argv)
 
     hdrtab = msgstate == NORMAL ? NHeaders : RHeaders;
 
+    gstate = m_getfld_state_init(in);
     for (compnum = 1;;) {
        int bufsz = sizeof buf;
-       switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) {
+       switch (state = m_getfld2(&gstate, name, buf, &bufsz)) {
            case FLD: 
            case FLDPLUS: 
-               compnum++;
-               cp = add (buf, NULL);
+                compnum++;
+               cp = mh_xstrdup(buf);
                while (state == FLDPLUS) {
                    bufsz = sizeof buf;
-                   state = m_getfld (&gstate, name, buf, &bufsz, in);
+                   state = m_getfld2(&gstate, name, buf, &bufsz);
                    cp = add (buf, cp);
                }
-               putfmt (name, cp, out);
+               putfmt (name, cp, &eai, out);
                free (cp);
                continue;
 
@@ -574,7 +661,7 @@ main (int argc, char **argv)
                fprintf (out, "\n%s", buf);
                while (state == BODY) {
                    bufsz = sizeof buf;
-                   state = m_getfld (&gstate, name, buf, &bufsz, in);
+                   state = m_getfld2(&gstate, name, buf, &bufsz);
                    fputs (buf, out);
                }
                break;
@@ -585,10 +672,10 @@ main (int argc, char **argv)
 
            case LENERR: 
            case FMTERR: 
-               adios (NULL, "message format error in component #%d", compnum);
+               die("message format error in component #%d", compnum);
 
            default: 
-               adios (NULL, "getfld() returned %d", state);
+               die("getfld() returned %d", state);
        }
        break;
     }
@@ -601,9 +688,8 @@ main (int argc, char **argv)
     if (debug) {
        pl ();
        done (0);
-    } else {
-       fclose (out);
     }
+    fclose (out);
 
     /*
      * Here's how we decide which address to use as the envelope-from
@@ -637,10 +723,45 @@ main (int argc, char **argv)
 #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) {
+           die("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) {
        /* This won't work with MTS_SENDMAIL_PIPE. */
-       verify_all_addresses (1, envelope);
+        verify_all_addresses (1, eai, envelope, oauth_flag, auth_svc);
        done (0);
     }
 
@@ -652,14 +773,15 @@ main (int argc, char **argv)
                   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);
+               verify_all_addresses (verbose, eai, envelope, oauth_flag,
+                                      auth_svc);
            }
-           post (tmpfil, 0, verbose, envelope);
+           post (tmpfil, 0, verbose, eai, envelope, oauth_flag, auth_svc);
        }
-       post (bccfil, 1, verbose, envelope);
+       post (bccfil, 1, verbose, eai, envelope, oauth_flag, auth_svc);
        (void) m_unlink (bccfil);
     } else {
-       post (tmpfil, 0, isatty (1), envelope);
+       post (tmpfil, 0, isatty (1), eai, envelope, oauth_flag, auth_svc);
     }
 
     p_refile (tmpfil);
@@ -669,7 +791,7 @@ main (int argc, char **argv)
        if (partno)
            printf ("Partial Message #%s Processed\n", partno);
        else
-           printf ("Message Processed\n");
+           puts("Message Processed");
     }
 
     done (0);
@@ -682,11 +804,15 @@ 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;
+    int count;
+    bool grp;
+    int i, keep;
     char *cp, *pp, *qp;
     char namep[BUFSIZ], error[BUFSIZ];
+    char *savehdr = NULL;
+    unsigned int savehdrlen = 0;
     struct mailname *mp = NULL, *np = NULL;
     struct headers *hdr;
 
@@ -694,23 +820,38 @@ putfmt (char *name, char *str, FILE *out)
        str++;
 
     if (msgstate == NORMAL && uprf (name, "resent")) {
-       advise (NULL, "illegal header line -- %s:", name);
-       badmsg++;
+       inform("illegal header line -- %s:", name);
+       badmsg = true;
        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) {
-       if (strncasecmp (name, "nmh-", 4)) {
+        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")) {
-               char *newline = strchr (str, '\n');
-               if (newline) *newline = '\0';
+                trim_suffix_c(str, '\n');
                if (! whomsw) {
-                   advise (NULL, "ignoring header line -- %s: %s", name, str);
+                   inform("ignoring header line -- %s: %s", name, str);
                }
            }
        }
@@ -723,14 +864,14 @@ putfmt (char *name, char *str, FILE *out)
        return;
     }
     if (hdr->flags & HBAD) {
-       advise (NULL, "illegal header line -- %s:", name);
-       badmsg++;
+       inform("illegal header line -- %s:", name);
+       badmsg = true;
        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 ((cp = strrchr(str, '\n')))
            *cp = 0;
@@ -741,14 +882,36 @@ putfmt (char *name, char *str, FILE *out)
        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++)
+
+    for (count = 0; (cp = getname (str)); count++) {
        if ((mp = getm (cp, NULL, 0, error, sizeof(error)))) {
            if (tmpaddrs.m_next)
                np->m_next = mp;
@@ -761,8 +924,9 @@ putfmt (char *name, char *str, FILE *out)
            if (hdr->flags & HTRY)
                badadr++;
            else
-               badmsg++;
+               badmsg = true;
        }
+    }
 
     if (count < 1) {
        if (hdr->flags & HNIL)
@@ -773,20 +937,20 @@ putfmt (char *name, char *str, FILE *out)
             */
            if ((msgstate == RESENT) ? (hdr->set & MRSN)
                                        : (hdr->set & MSND)) {
-               advise (NULL, "%s: field requires one address", name);
-               badmsg++;
+               inform("%s: field requires one address", name);
+               badmsg = true;
            }
 #ifdef notdef
-           advise (NULL, "%s: field requires at least one address", name);
-           badmsg++;
+           inform("%s: field requires at least one address", name);
+           badmsg = true;
 #endif /* notdef */
        }
        return;
     }
 
     if (count > 1 && (hdr->flags & HONE)) {
-       advise (NULL, "%s: field only permits one address", name);
-       badmsg++;
+       inform("%s: field only permits one address", name);
+       badmsg = true;
        return;
     }
 
@@ -794,7 +958,7 @@ putfmt (char *name, char *str, FILE *out)
     snprintf (namep, sizeof(namep), "%s%s",
                (hdr->flags & HMNG) ? "Original-" : "", name);
 
-    for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np)
+    for (grp = false, mp = tmpaddrs.m_next; mp; mp = np)
        if (mp->m_nohost) {     /* also used to test (hdr->flags & HTRY) */
            /* The address doesn't include a host, so it might be an alias. */
            pp = akvalue (mp->m_mbox);  /* do mh alias substitution */
@@ -829,7 +993,7 @@ putfmt (char *name, char *str, FILE *out)
                                                : (hdr->set & MSND)) {
                    strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1);
                    sender[sizeof(sender) - 1] = '\0';
-                   seensender++;
+                   seensender = true;
                }
 
                /*
@@ -845,9 +1009,8 @@ putfmt (char *name, char *str, FILE *out)
                    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);
+               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:
@@ -857,14 +1020,14 @@ putfmt (char *name, char *str, FILE *out)
                           aliases and put them in Bcc:, but then
                           they'd have the Blind-Carbon-Copy
                           indication. */
-                       adios (NULL,
-                              "blind lists not compatible with"
+                       die(                           "blind lists not compatible with"
                               " sendmail/pipe");
                    }
 
-                   grp++;
+                   grp = true;
                }
-               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);
@@ -895,7 +1058,7 @@ putfmt (char *name, char *str, FILE *out)
                                            : (hdr->set & MSND)) {
                strncpy(sender, auxformat(mp, 0), sizeof(sender) - 1);
                sender[sizeof(sender) - 1] = '\0';
-               seensender++;
+               seensender = true;
            }
 
            /*
@@ -912,8 +1075,8 @@ putfmt (char *name, char *str, FILE *out)
            if (mp->m_gname)
                putgrp (namep, mp->m_gname, out, hdr->flags);
            if (mp->m_ingrp)
-               grp++;
-           keep = putadr (namep, "", mp, out, hdr->flags);
+               grp = true;
+           keep = putadr (namep, "", mp, out, hdr->flags, savehdr, savehdrlen);
            np = mp->m_next;
            if (keep) {
                mp->m_next = NULL;
@@ -924,25 +1087,19 @@ putfmt (char *name, char *str, FILE *out)
        }
 
     /*
-     * 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
+     * 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)) {
-       strncpy(fullfrom, str, sizeof(fullfrom));
-       fullfrom[sizeof(fullfrom) - 1] = 0;
-       /*
-        * Strip off any trailing newlines
-        */
-
-       while (strlen(fullfrom) > 0 && fullfrom[strlen(fullfrom) - 1] == '\n') {
+       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);
-       badmsg++;
+    if (grp && (hdr->flags & HNGR)) {
+       inform("%s: field does not allow groups", name);
+       badmsg = true;
     }
     if (linepos) {
        putc ('\n', out);
@@ -981,16 +1138,16 @@ finish_headers (FILE *out)
                /*
                 * 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++;
+               inform("message has no From: header");
+               inform("See default components files for examples");
+               badmsg = true;
                break;
            }
 
-           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
-               advise (NULL, "A Sender: or Envelope-From: header is required "
+           if (fromcount > 1 && (!seensender && !(msgflags & MEFM))) {
+               inform("A Sender: or Envelope-From: header is required "
                        "with multiple\nFrom: addresses");
-               badmsg++;
+               badmsg = true;
                break;
            }
 
@@ -1006,12 +1163,12 @@ finish_headers (FILE *out)
             * from Envelope-From: (which in this case, cannot be blank)
             */
 
-           if (fromcount > 1 && seensender == 0) {
+           if (fromcount > 1 && !seensender) {
                if (efrom[0] == '\0') {
-                   advise (NULL, "Envelope-From cannot be blank when there "
+                   inform("Envelope-From cannot be blank when there "
                            "is multiple From: addresses\nand no Sender: "
                            "header");
-                   badmsg++;
+                   badmsg = true;
                } else {
                    fprintf (out, "Sender: %s\n", efrom);
                }
@@ -1023,23 +1180,23 @@ finish_headers (FILE *out)
 
        case RESENT: 
            if (!(msgflags & MDAT)) {
-               advise (NULL, "message has no Date: header");
-               badmsg++;
+               inform("message has no Date: header");
+               badmsg = true;
            }
            if (!(msgflags & MFRM)) {
-               advise (NULL, "message has no From: header");
-               badmsg++;
+               inform("message has no From: header");
+               badmsg = true;
            }
            if (!(msgflags & MRFM)) {
-               advise (NULL, "message has no Resent-From: header");
-               advise (NULL, "See default components files for examples");
-               badmsg++;
+               inform("message has no Resent-From: header");
+               inform("See default components files for examples");
+               badmsg = true;
                break;
            }
-           if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) {
-               advise (NULL, "A Resent-Sender: or Envelope-From: header is "
+           if (fromcount > 1 && (!seensender && !(msgflags & MEFM))) {
+               inform("A Resent-Sender: or Envelope-From: header is "
                        "required with multiple\nResent-From: addresses");
-               badmsg++;
+               badmsg = true;
                break;
            }
 
@@ -1056,12 +1213,12 @@ finish_headers (FILE *out)
             * from Envelope-From (which in this case, cannot be blank)
             */
 
-           if (fromcount > 1 && seensender == 0) {
+           if (fromcount > 1 && !seensender) {
                if (efrom[0] == '\0') {
-                   advise (NULL, "Envelope-From cannot be blank when there "
+                   inform("Envelope-From cannot be blank when there "
                            "is multiple Resent-From: addresses and no "
                            "Resent-Sender: header");
-                   badmsg++;
+                   badmsg = true;
                } else {
                    fprintf (out, "Resent-Sender: %s\n", efrom);
                }
@@ -1073,9 +1230,9 @@ finish_headers (FILE *out)
     }
 
     if (badmsg)
-       adios (NULL, "re-format message and try again");
+       die("re-format message and try again");
     if (!recipients)
-       adios (NULL, "no addressees");
+       die("no addressees");
 }
 
 
@@ -1084,18 +1241,22 @@ get_header (char *header, struct headers *table)
 {
     struct headers *h;
 
+    header = FENDNULL(header);
     for (h = table; h->value; h++)
-       if (!strcasecmp (header ? header : "", h->value ? h->value : ""))
-           return (h - table);
+       if (!strcasecmp(FENDNULL(h->value), header))
+           return h - table;
 
     return NOTOK;
 }
 
 
 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;
+    bool saveappend = false;
+    unsigned int shlen;
     char *cp;
     char buffer[BUFSIZ];
 
@@ -1110,8 +1271,13 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
        linepos += (nameoutput = strlen (name) + 2);
     }
 
+    if (savehdr) {
+       shlen = strlen(savehdr);
+       saveappend = true;
+    }
+
     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) {
            snprintf (buffer, sizeof(buffer), "%s;", mp->m_gname);
@@ -1125,18 +1291,37 @@ 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 = false;
+               } else {
+                   snprintf(savehdr + shlen, savehdrsize - shlen, ",\n%*s",
+                            linepos, "");
+               }
+           }
+       } else {
            fputs (", ", out);
            linepos += 2;
+           if (saveappend) {
+               if (shlen + 2 + len >= savehdrsize) {
+                   saveappend = false;
+               } else {
+                   strncat(savehdr, ", ", savehdrsize - shlen);
+               }
+           }
        }
     }
 
     fputs (cp, out);
+
+    if (saveappend && shlen + len < savehdrsize)
+       strncat(savehdr, cp, savehdrsize - shlen + len);
+
     linepos += len;
 
-    return (flags & HTRY);
+    return flags & HTRY;
 }
 
 
@@ -1186,15 +1371,15 @@ insert (struct mailname *np)
            : &netaddrs;
            mp->m_next;
            mp = mp->m_next)
-       if (!strcasecmp (np->m_host ? np->m_host : "",
-                        mp->m_next->m_host ? mp->m_next->m_host : "") &&
-           !strcasecmp (np->m_mbox ? np->m_mbox : "",
-                        mp->m_next->m_mbox ? mp->m_next->m_mbox : "") &&
+       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;
-    recipients++;
+    recipients = true;
     return 1;
 }
 
@@ -1205,29 +1390,29 @@ pl (void)
     int i;
     struct mailname *mp;
 
-    printf ("-------\n\t-- Addresses --\nlocal:\t");
+    fputs("-------\n\t-- Addresses --\nlocal:\t", stdout);
     for (mp = localaddrs.m_next; mp; mp = mp->m_next)
        printf ("%s%s%s", mp->m_mbox,
                mp->m_bcc ? "[BCC]" : "",
                mp->m_next ? ",\n\t" : "");
 
-    printf ("\nnet:\t");
+    fputs("\nnet:\t", stdout);
     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" : "");
 
-    printf ("\nuucp:\t");
+    fputs("\nuucp:\t", stdout);
     for (mp = uuaddrs.m_next; mp; mp = mp->m_next)
        printf ("%s!%s%s%s", mp->m_host, mp->m_mbox,
                mp->m_bcc ? "[BCC]" : "",
                mp->m_next ? ",\n\t" : "");
 
-    printf ("\n\t-- Folder Copies --\nfcc:\t");
+    fputs("\n\t-- Folder Copies --\nfcc:\t", stdout);
     for (i = 0; i < fccind; i++)
        printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : "");
-    printf ("\n");
+    putchar('\n');
 }
 
 
@@ -1263,7 +1448,7 @@ annoaux (struct mailname *mp)
     snprintf (buffer, sizeof(buffer), "%s\n", adrformat (mp));
     i = strlen (buffer);
 
-    return (write (pfd, buffer, i) == i ? OK : NOTOK);
+    return write(pfd, buffer, i) == i ? OK : NOTOK;
 }
 
 
@@ -1282,8 +1467,8 @@ insert_fcc (struct headers *hdr, char *pp)
        return;
 
     if (fccind >= FCCS)
-       adios (NULL, "too many %ss", hdr->value);
-    fccfold[fccind++] = getcpy (cp);
+       die("too many %ss", hdr->value);
+    fccfold[fccind++] = mh_xstrdup(cp);
 }
 
 /*
@@ -1300,7 +1485,7 @@ make_bcc_file (int dashstuff)
     char *tfile = NULL, *program;
 
     if ((tfile = m_mktemp2(NULL, "bccs", NULL, &out)) == NULL) {
-       adios(NULL, "unable to create temporary file in %s", get_temp_dir());
+       die("unable to create temporary file in %s", get_temp_dir());
     }
     strncpy (bccfil, tfile, sizeof(bccfil));
 
@@ -1325,15 +1510,14 @@ make_bcc_file (int dashstuff)
         * prefix and check again.
         */
        if ((cp = strchr(prefix, 'a')) == NULL)
-           adios (NULL, "lost prefix start");
+           die("lost prefix start");
        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)
+                die("can't find a unique delimiter string");
+            else
+                (*cp)++;
        }
 
        fprintf (out, "%s: %s\n%s: multipart/digest; boundary=\"",
@@ -1350,8 +1534,7 @@ make_bcc_file (int dashstuff)
      * of MIME encapsulation.
      */
     if (filter != NULL) {
-       for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
-           sleep (5);
+       child_id = fork();
        switch (child_id) {
            case NOTOK: 
                adios ("fork", "unable to");
@@ -1375,7 +1558,7 @@ make_bcc_file (int dashstuff)
                execvp (program, vec);
                fprintf (stderr, "unable to exec ");
                perror (mhlproc);
-               _exit (-1);
+               _exit(1);
 
            default: 
                pidXwait (child_id, mhlproc);
@@ -1421,7 +1604,7 @@ find_prefix (void)
     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] == '-') {
            char *cp;
 
@@ -1440,18 +1623,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));
 }
 
 
@@ -1466,7 +1647,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++;
        }
@@ -1475,7 +1656,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++;
        }
@@ -1484,7 +1665,7 @@ 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++;
        }
@@ -1492,7 +1673,7 @@ do_addresses (int bccque, int talk)
     chkadr ();
 
     if (rp_isbad (retval = sm_waend ()))
-       die (NULL, "problem ending addresses; %s", rp_string (retval));
+       fatal (NULL, "problem ending addresses; %s", rp_string (retval));
 }
 
 
@@ -1506,10 +1687,10 @@ do_addresses (int bccque, int talk)
  */
 
 static void
-post (char *file, int bccque, int talk, char *envelope)
+post (char *file, int bccque, int talk, int eai, char *envelope,
+      int oauth_flag, char *auth_svc)
 {
-    int fd;
-    int        retval, i;
+    int retval;
     pid_t child_id;
 
     if (verbose) {
@@ -1517,7 +1698,7 @@ post (char *file, int bccque, int talk, char *envelope)
            printf (" -- Posting for %s Recipients --\n",
                    bccque ? "Blind" : "Sighted");
        else
-           printf (" -- Posting for All Recipients --\n");
+           puts(" -- Posting for All Recipients --");
     }
 
     sigon ();
@@ -1526,8 +1707,7 @@ post (char *file, int bccque, int talk, char *envelope)
        char **argp, *program;
        int argc;
 
-       for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
-           sleep (5);
+       child_id = fork();
        switch (child_id) {
            case NOTOK: 
                adios ("fork", "unable to");
@@ -1554,15 +1734,33 @@ post (char *file, int bccque, int talk, char *envelope)
                break;
        }
     } else {
-        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
-                                        verbose, snoop, sasl, saslssf,
-                                       saslmech, user, tls))  ||
-            rp_isbad (retval = sm_winit (envelope)))
-           die (NULL, "problem initializing server; %s", rp_string (retval));
+        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);
-        if ((fd = open (file, O_RDONLY)) == NOTOK)
-          die (file, "unable to re-open");
         do_text (file, fd);
         close (fd);
         fflush (stdout);
@@ -1575,7 +1773,7 @@ post (char *file, int bccque, int talk, char *envelope)
                printf (" -- %s Recipient Copies Posted --\n",
                        bccque ? "Blind" : "Sighted");
             else
-               printf (" -- Recipient Copies Posted --\n");
+               puts(" -- Recipient Copies Posted --");
         }
 
         fflush (stdout);
@@ -1586,43 +1784,49 @@ post (char *file, int bccque, int talk, char *envelope)
 /* Address Verification */
 
 static void
-verify_all_addresses (int talk, char *envelope)
+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, sasl, saslssf,
-                                       saslmech, user, tls))
-               || rp_isbad (retval = sm_winit (envelope)))
-           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 ();
@@ -1664,14 +1868,14 @@ do_an_address (struct mailname *lp, int talk)
        return;
     }
     if (talk)
-       printf (": ");
+       fputs(": ", stdout);
     fflush (stdout);
 
     switch (retval = sm_wadr (mbox, host,
                         lp->m_type != UUCPHOST ? lp->m_path : NULL)) {
        case RP_OK: 
            if (talk)
-               printf ("address ok\n");
+               puts("address ok");
            break;
 
        case RP_NO: 
@@ -1686,7 +1890,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);
@@ -1699,15 +1903,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: 
@@ -1715,10 +1919,11 @@ 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));
     }
 }
 
@@ -1781,11 +1986,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 --");
 }
 
 
@@ -1797,7 +2002,7 @@ static void
 fcc (char *file, char *folder)
 {
     pid_t child_id;
-    int i, status, argp;
+    int status, argp;
     char fold[BUFSIZ];
     char **arglist, *program;
 
@@ -1805,9 +2010,7 @@ fcc (char *file, char *folder)
        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)
@@ -1830,17 +2033,17 @@ fcc (char *file, char *folder)
            arglist[argp++] = fold;
            arglist[argp] = NULL;
            execvp (program, arglist);
-           _exit (-1);
+           _exit(1);
 
        default: 
            if ((status = pidwait (child_id, OK))) {
                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");
            }
     }
 
@@ -1852,10 +2055,13 @@ fcc (char *file, char *folder)
  */
 
 static void
-die (char *what, char *fmt, ...)
+fatal (char *what, char *fmt, ...)
 {
+    int err;
     va_list ap;
 
+    err = errno;
+
     (void) m_unlink (tmpfil);
     if (msgflags & MINV)
        (void) m_unlink (bccfil);
@@ -1864,6 +2070,7 @@ die (char *what, char *fmt, ...)
        sm_end (NOTOK);
 
     va_start(ap, fmt);
+    errno = err;
     advertise (what, NULL, fmt, ap);
     va_end(ap);
     done (1);