-
-/*
- * 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 <errno.h>
-#include <setjmp.h>
-#include <signal.h>
+#include "../sbr/m_mktemp.h"
+#include "../sbr/message_id.h"
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#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) },
-#define FILEPROCSW 42
- { "fileproc", -4 },
-#define MHLPROCSW 43
- { "mhlproc", -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;
unsigned int flags;
/*
* 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 },
{ "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 }
};
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 */
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 */
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 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 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);
+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);
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 = 0;
-#ifdef LOCALE
- setlocale(LC_ALL, "");
-#endif
- invo_name = r1bindex (argv[0], '/');
+ if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
- /* foil search of user profile/context */
- if (context_foil (NULL) == -1)
- done (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 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 == '-')
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]);
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]);
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:
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)
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)) {
+ for (compnum = 1;;) {
+ int bufsz = sizeof buf;
+ switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) {
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_getfld (&gstate, name, buf, &bufsz, in);
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_getfld (&gstate, name, buf, &bufsz, in);
fputs (buf, out);
}
break;
}
break;
}
+ m_getfld_state_destroy (&gstate);
if (pfd != NOTOK)
anno ();
fclose (out);
}
+ /*
+ * Here's how we decide which address to use as the envelope-from
+ * address for SMTP.
+ *
+ * - If we were given an Envelope-From header, use that.
+ * - If we were given a Sender: address, use that.
+ * - Otherwise, use the address on the From: line
+ */
+
+ if (msgflags & MEFM) {
+ envelope = efrom;
+ } else if (seensender) {
+ envelope = sender;
+ } else {
+ envelope = from;
+ }
+
+ if (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;
}
*/
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];
struct mailname *mp = NULL, *np = NULL;
struct headers *hdr;
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;
}
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) */
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++;
else
if (mp->m_gname)
putgrp (namep, mp->m_gname, out, hdr->flags);
- if (mp->m_ingrp)
+ 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))
msgflags |= (hdr->set & (MVIS | MINV));
else
}
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++;
mnfree (mp);
}
+ /*
+ * 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 ((msgstate == RESENT) ? (hdr->set & MRFM) : (hdr->set & MFRM)) {
+ strncpy(fullfrom, str, sizeof(fullfrom));
+ fullfrom[sizeof(fullfrom) - 1] = 0;
+ /*
+ * Strip off any trailing newlines
+ */
+
+ 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);
}
}
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';
}
{
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 (whomsw && !fill_up)
+ 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)
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;
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;
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) {
}
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 {
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) {
: &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;
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" : "");
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');
}
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;
if (fccind >= FCCS)
adios (NULL, "too many %ss", hdr->value);
- fccfold[fccind++] = getcpy (cp);
+ fccfold[fccind++] = mh_xstrdup(cp);
}
/*
{
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");
* of MIME encapsulation.
*/
if (filter != NULL) {
- vec[0] = r1bindex (mhlproc, '/');
-
for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
sleep (5);
switch (child_id) {
case OK:
dup2 (fileno (out), 1);
- i = 1;
+ vec = argsplit(mhlproc, &program, &i);
vec[i++] = "-forward";
vec[i++] = "-form";
vec[i++] = filter;
vec[i++] = "-nodashstuffing";
vec[i] = NULL;
- execvp (mhlproc, vec);
+ execvp (program, vec);
fprintf (stderr, "unable to exec ");
perror (mhlproc);
_exit (-1);
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) {
}
-#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));
+ badadr, PLURALS(badadr), unkadr, PLURALS(badadr));
if (badadr)
- die (NULL, "%d address%s unparsable", badadr, plural (badadr));
+ die (NULL, "%d address%s unparsable", badadr, PLURALS(badadr));
if (unkadr)
- die (NULL, "%d addressee%s undeliverable", unkadr, plural (unkadr));
+ die (NULL, "%d addressee%s undeliverable", unkadr, PLURALS(unkadr));
}
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++;
}
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++;
}
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 */
}
* 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, i;
+ 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 ();
+ for (i = 0; (child_id = fork()) == NOTOK && i < 5; i++)
+ sleep (5);
+ switch (child_id) {
+ case NOTOK:
+ adios ("fork", "unable to");
- if (verbose) {
- if (msgflags & MINV)
- printf (" -- %s Recipient Copies Posted --\n",
- bccque ? "Blind" : "Sighted");
- else
- printf (" -- Recipient Copies Posted --\n");
- }
+ case OK:
+ if (freopen( file, "r", stdin) == NULL) {
+ adios (file, "can't reopen for sendmail");
+ }
- fflush (stdout);
+ argp = 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) {
+ die (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);
+ die (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);
+ die (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)))
+ verbose, snoop, sasl, saslmech, user,
+ oauth_flag ? auth_svc : NULL, tlsflag))
+ || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
die (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);
lp->m_type != UUCPHOST ? lp->m_path : NULL)) {
case RP_OK:
if (talk)
- printf ("address ok\n");
+ puts("address ok");
break;
case RP_NO:
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)))
case RP_NO:
case RP_NDEL:
die (NULL, "posting failed; %s", rp_string (retval));
+ break;
default:
die (NULL, "unexpected response; %s", rp_string (retval));
}
}
-#endif /* SMTPMTS */
-
/*
* SIGNAL HANDLING
{
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);
}
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 --");
}
fcc (char *file, char *folder)
{
pid_t child_id;
- int i, status;
+ int i, status, argp;
char fold[BUFSIZ];
+ char **arglist, *program;
if (verbose)
printf (" %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", 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:
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");
}
}
static void
die (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);