-
/*
* post.c -- enter messages into the mail transport system
*
# define TLSminc(a) 0
#endif /* TLS_SUPPORT */
+#ifndef OAUTH_SUPPORT
+# define OAUTHminc(a) (a)
+#else /* OAUTH_SUPPORT */
+# define OAUTHminc(a) 0
+#endif /* OAUTH_SUPPORT */
+
#define FCCS 10 /* max number of fccs allowed */
/* In the following array of structures, the numeric second field of the
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("authservice", SASLminc(0), AUTHSERVICESW) \
X("user", SASLminc(-4), USERSW) \
X("port server submission port name/number", 4, PORTSW) \
X("tls", TLSminc(-3), TLSSW) \
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
+/*
+ * Mapping between command-line switches and profile entries, communicated
+ * from 'send'. We use a service name of 'post' internally.
+ */
+
+static struct oauth_profile {
+ 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;
#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 MSND 0x0020 /* we've seen a Sender: */
#define MRSN 0x0040 /* We've seen a Resent-Sendr:*/
#define MEFM 0x0080 /* We've seen Envelope-From: */
-
+#define MMIM 0x0100 /* We've seen Mime-Version: */
static struct headers NHeaders[] = {
{ "Return-Path", HBAD, 0 },
{ "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 }
};
{ "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 int linepos=0; /* putadr()'s position on the line */
static int nameoutput=0; /* putadr() has output header name */
static int sasl=0; /* Use SASL auth for SMTP */
-static int saslssf=-1; /* Our maximum SSF for SASL */
static char *saslmech=NULL; /* Force use of particular SASL mech */
static char *user=NULL; /* Authenticate as this user */
static char *port="submission"; /* Name of server port for SMTP submission */
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 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 annoaux (struct mailname *);
static void insert_fcc (struct headers *, char *);
static void make_bcc_file (int);
-static void verify_all_addresses (int, char *, const 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 *, const char *);
+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;
+ int state, compnum, dashstuff = 0, swnum, oauth_flag = 0;
+ int eai = 0; /* use Email Address Internationalization (EAI) (SMTPUTF8) */
char *cp, *msg = NULL, **argp, **arguments, *envelope;
- char buf[BUFSIZ], name[NAMESZ];
+ char buf[BUFSIZ], name[NAMESZ], *auth_svc = NULL;
FILE *in, *out;
m_getfld_state_t gstate = 0;
- char *xoauth_client_res = NULL;
if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
- mts_init (invo_name);
+ mts_init ();
arguments = getarguments (invo_name, argc, argv, 0);
argp = arguments;
while ((cp = *argp++)) {
if (*cp == '-') {
- switch (smatch (++cp, switches)) {
+ switch ((swnum = smatch (++cp, switches))) {
case AMBIGSW:
ambigsw (cp, switches);
done (1);
sasl = 0;
continue;
- case SASLMXSSFSW:
- if (!(cp = *argp++) || *cp == '-')
- adios (NULL, "missing argument to %s", argp[-2]);
- saslssf = atoi(cp);
- continue;
-
case SASLMECHSW:
if (!(saslmech = *argp++) || *saslmech == '-')
adios (NULL, "missing argument to %s", argp[-2]);
continue;
case AUTHSERVICESW:
-#ifdef OAUTH_SUPPORT
- if (!(xoauth_client_res = *argp++) || *xoauth_client_res == '-')
+ if (!(auth_svc = *argp++) || *auth_svc == '-')
adios (NULL, "missing argument to %s", argp[-2]);
-#else
- adios (NULL, "not built with OAuth support");
-#endif
+ 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 == '-')
switch (state = m_getfld (&gstate, name, buf, &bufsz, in)) {
case FLD:
case FLDPLUS:
- compnum++;
+ compnum++;
cp = add (buf, NULL);
while (state == FLDPLUS) {
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);
continue;
#endif /* ! TLS_SUPPORT */
}
+ /*
+ * 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) {
/* This won't work with MTS_SENDMAIL_PIPE. */
- verify_all_addresses (1, envelope, xoauth_client_res);
+ verify_all_addresses (1, eai, envelope, oauth_flag, auth_svc);
done (0);
}
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, xoauth_client_res);
+ verify_all_addresses (verbose, eai, envelope, oauth_flag,
+ auth_svc);
}
- post (tmpfil, 0, verbose, envelope, xoauth_client_res);
+ post (tmpfil, 0, verbose, eai, envelope, oauth_flag, auth_svc);
}
- post (bccfil, 1, verbose, envelope, xoauth_client_res);
+ post (bccfil, 1, verbose, eai, envelope, oauth_flag, auth_svc);
(void) m_unlink (bccfil);
} else {
- post (tmpfil, 0, isatty (1), envelope, xoauth_client_res);
+ post (tmpfil, 0, isatty (1), eai, envelope, oauth_flag, auth_svc);
}
p_refile (tmpfil);
*/
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;
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) {
+ printf ("EAI/SMTPUTF8 enabled\n");
+ }
+
+ /* 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';
+ TrimSuffixC(str, '\n');
if (! whomsw) {
advise (NULL, "ignoring header line -- %s: %s", name, str);
}
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;
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++)
+
+ 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
badmsg++;
}
+ }
if (count < 1) {
if (hdr->flags & HNIL)
}
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);
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');
}
if (fccind >= FCCS)
adios (NULL, "too many %ss", hdr->value);
- fccfold[fccind++] = getcpy (cp);
+ fccfold[fccind++] = mh_xstrdup(cp);
}
/*
*/
static void
-post (char *file, int bccque, int talk, char *envelope,
- const char *xoauth_client_res)
+post (char *file, int bccque, int talk, int eai, char *envelope,
+ int oauth_flag, char *auth_svc)
{
- int fd;
int retval, i;
pid_t child_id;
break;
}
} else {
- if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
- verbose, snoop, sasl, saslssf,
- saslmech, user, xoauth_client_res, tls))
- || rp_isbad (retval = sm_winit (envelope)))
+ 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, tls))
+ || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
+ close (fd);
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);
/* Address Verification */
static void
-verify_all_addresses (int talk, char *envelope, const char *xoauth_client_res)
+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, xoauth_client_res, tls))
- || rp_isbad (retval = sm_winit (envelope)))
+ verbose, snoop, sasl, saslmech, user,
+ oauth_flag ? auth_svc : NULL, tls))
+ || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
die (NULL, "problem initializing server; %s", rp_string (retval));
+ }
+ }
if (talk && !whomsw)
printf (" -- Address Verification --\n");