* post.c -- enter messages into the mail transport system
*
* $Id$
+ *
+ * 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/aliasbr.h>
#include <h/dropsbr.h>
#include <h/mime.h>
+#include <h/utils.h>
-#include <zotnet/tws/tws.h>
-#include <zotnet/mts/mts.h>
+#include <h/tws.h>
+#include <h/mts.h>
#include <errno.h>
#include <setjmp.h>
# endif
#endif
-#ifdef MMDFMTS
-# include <mts/mmdf/util.h>
-# include <mts/mmdf/mmdf.h>
-#endif
-
-/*
- * Currently smtp and sendmail use
- * the same interface for posting.
- */
#ifdef SMTPMTS
-# define SENDMTS
-#endif
-
-#ifdef SENDMTS
# include <mts/smtp/smtp.h>
#endif
-#ifndef MMDFMTS
-# define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : (c))
-#endif
+#ifndef CYRUS_SASL
+# define SASLminc(a) (a)
+#else /* CYRUS_SASL */
+# define SASLminc(a) 0
+#endif /* CYRUS_SASL */
#define FCCS 10 /* max number of fccs allowed */
+#define uptolow(c) ((isalpha(c) && isupper (c)) ? tolower (c) : c)
+
+/* In the following array of structures, the numeric second field of the
+ structures (minchars) is apparently used like this:
+
+ -# : Switch can be abbreviated to # characters; switch hidden in -help.
+ 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 VERSIONSW 20
{ "version", 0 },
#define HELPSW 21
- { "help", 4 },
+ { "help", 0 },
#define BITSTUFFSW 22
{ "dashstuffing", -12 }, /* should we dashstuff BCC messages? */
#define NBITSTUFFSW 23
{ "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) },
{ NULL, 0 }
};
{ "Resent-Fcc", HFCC, 0 },
{ "Reply-To", HADR, 0 },
{ "From", HADR|HNGR, MFRM },
-#ifdef MMDFI
- { "Sender", HADR|HNGR|HMNG, 0 },
-#else
{ "Sender", HADR|HNGR, 0 },
-#endif
{ "Date", HNOP, MDAT },
{ "To", HADR|HNIL, 0 },
{ "cc", HADR|HNIL, 0 },
static int checksw = 0; /* whom -check */
static int linepos=0; /* putadr()'s position on the line */
static int nameoutput=0; /* putadr() has output header name */
+static int sasl=0; /* Use SASL auth for SMTP */
+static char *saslmech=NULL; /* Force use of particular SASL mech */
+static char *user=NULL; /* Authenticate as this user */
static unsigned msgflags = 0; /* what we've seen */
static struct mailname uuaddrs={NULL}; /* uucp addrs */
static struct mailname tmpaddrs={NULL}; /* temporary queue */
-#ifdef MMDFMTS
-static char *submitmode = "m"; /* deliver to mailbox only */
-static char submitopts[6] = "vl"; /* initial options for submit */
-#endif /* MMDFMTS */
-
-#ifdef SENDMTS
+#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 /* SENDMTS */
+#endif /* SMTPMTS */
static char prefix[] = "----- =_aaaaaaaaaa";
static char *partno = NULL;
static int queued = 0;
+extern boolean draft_from_masquerading; /* defined in mts.c */
+
/*
* static prototypes
*/
static void pl (void);
static void anno (void);
static int annoaux (struct mailname *);
-static void insert_fcc (struct headers *, char *);
+static void insert_fcc (struct headers *, unsigned char *);
static void make_bcc_file (int);
static void verify_all_addresses (int);
static void chkadr (void);
arguments = getarguments (invo_name, argc, argv, 0);
argp = arguments;
-#if defined(MMDFMTS) && defined(MMDFII)
- mmdf_init (invo_name);
-#endif /* MMDFMTS and MMDFII */
-
while ((cp = *argp++)) {
if (*cp == '-') {
switch (smatch (++cp, switches)) {
adios (NULL, "bad argument %s %s", argp[-2], cp);
continue;
-#ifdef MMDFMTS
- case MAILSW:
- submitmode = "m";
- continue;
- case SOMLSW: /* for right now, sigh... */
- case SAMLSW:
- submitmode = "b";
- continue;
- case SENDSW:
- submitmode = "y";
- continue;
-#endif /* MMDFMTS */
-
case DLVRSW:
if (!(cp = *argp++) || *cp == '-')
adios (NULL, "missing argument to %s", argp[-2]);
continue;
-#ifndef SENDMTS
+#ifndef SMTPMTS
case CLIESW:
case SERVSW:
if (!(cp = *argp++) || *cp == '-')
case SNOOPSW:
continue;
-#else /* SENDMTS */
+#else /* SMTPMTS */
case MAILSW:
smtpmode = S_MAIL;
continue;
case SNOOPSW:
snoop++;
continue;
-#endif /* SENDMTS */
+#endif /* SMTPMTS */
case FILLSW:
if (!(fill_in = *argp++) || *fill_in == '-')
case QUEUESW:
queued++;
continue;
+
+ case SASLSW:
+ sasl++;
+ continue;
+
+ case SASLMECHSW:
+ if (!(saslmech = *argp++) || *saslmech == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ continue;
+
+ case USERSW:
+ if (!(user = *argp++) || *user == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ continue;
}
}
if (msg)
done (0);
}
-#ifdef MMDFMTS
- strcat (submitopts, submitmode);
- if (watch)
- strcat (submitopts, "nw");
-#endif /* MMDFMTS */
-
if (msgflags & MINV) {
make_bcc_file (dashstuff);
if (msgflags & MVIS) {
if (verbose)
printf (partno ? "Partial Message #%s Processed\n" : "Message Processed\n",
partno);
- return done (0);
+ done (0);
+ return 1;
}
for (grp = 0, mp = tmpaddrs.m_next; mp; mp = np)
if (mp->m_nohost) { /* also used to test (hdr->flags & HTRY) */
- pp = akvalue (mp->m_mbox);
+ /* The address doesn't include a host, so it might be an alias. */
+ pp = akvalue (mp->m_mbox); /* do mh alias substitution */
qp = akvisible () ? mp->m_mbox : "";
np = mp;
if (np->m_gname)
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:. */
+ strncpy(from, auxformat(mp, 0), sizeof(from) - 1);
+
if (hdr->flags & HBCC)
mp->m_bcc++;
if (np->m_ingrp)
mnfree (mp);
}
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:. */
+ strncpy(from, auxformat(mp, 0), sizeof(from) - 1);
+
if (hdr->flags & HBCC)
mp->m_bcc++;
if (mp->m_gname)
static void
start_headers (void)
{
- char *cp;
+ unsigned char *cp;
char myhost[BUFSIZ], sigbuf[BUFSIZ];
struct mailname *mp;
if (msgid)
fprintf (out, "Message-ID: <%d.%ld@%s>\n",
(int) getpid (), (long) tclock, LocalName ());
- if (msgflags & MFRM)
- fprintf (out, "Sender: %s\n", from);
+ 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);
if (whomsw)
break;
if (whomsw && !fill_up)
break;
-#ifdef MMDFI /* sigh */
- fprintf (out, "Sender: %s\n", from);
-#endif /* MMDFI */
-
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)
- fprintf (out, "Resent-Sender: %s\n", from);
+ 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);
+ }
else
+ /* Construct a Resent-From: header. */
fprintf (out, "Resent-From: %s\n", signature);
if (whomsw)
break;
struct headers *h;
for (h = table; h->value; h++)
- if (!strcasecmp (header, h->value))
+ if (!mh_strcasecmp (header, h->value))
return (h - table);
return NOTOK;
: &netaddrs;
mp->m_next;
mp = mp->m_next)
- if (!strcasecmp (np->m_host, mp->m_next->m_host)
- && !strcasecmp (np->m_mbox, mp->m_next->m_mbox)
+ 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)
return 0;
static void
-insert_fcc (struct headers *hdr, char *pp)
+insert_fcc (struct headers *hdr, unsigned char *pp)
{
- char *cp;
+ unsigned char *cp;
for (cp = pp; isspace (*cp); cp++)
continue;
if (msgid)
fprintf (out, "Message-ID: <%d.%ld@%s>\n",
(int) getpid (), (long) tclock, LocalName ());
- fprintf (out, "From: %s\n", signature);
+ 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);
if (subject)
fprintf (out, "Subject: %s", subject);
fprintf (out, "BCC:\n");
find_prefix (void)
{
int len, result;
- char buffer[BUFSIZ];
+ unsigned char buffer[BUFSIZ];
FILE *in;
if ((in = fopen (tmpfil, "r")) == NULL)
result = OK;
while (fgets (buffer, sizeof(buffer) - 1, in))
if (buffer[0] == '-' && buffer[1] == '-') {
- char *cp;
+ unsigned char *cp;
for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
if (!isspace (*cp))
chkadr ();
-#ifdef MMDFMTS
- if (rp_isbad (retval = mm_waend ()))
- die (NULL, "problem ending addresses [%s]\n", rp_valstr (retval));
-#endif /* MMDFMTS */
-
-#ifdef SENDMTS
+#ifdef SMTPMTS
if (rp_isbad (retval = sm_waend ()))
die (NULL, "problem ending addresses; %s", rp_string (retval));
-#endif /* SENDMTS */
+#endif /* SMTPMTS */
}
* SENDMAIL/SMTP routines
*/
-#ifdef SENDMTS
+#ifdef SMTPMTS
static void
post (char *file, int bccque, int talk)
sigon ();
if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose,
- snoop, onex, queued))
+ snoop, onex, queued, sasl, saslmech,
+ user))
|| rp_isbad (retval = sm_winit (smtpmode, from)))
die (NULL, "problem initializing server; %s", rp_string (retval));
sigon ();
if (!whomsw || checksw)
- if (rp_isbad (retval = sm_init (clientsw, serversw, 0, 0, snoop, 0, 0))
+ if (rp_isbad (retval = sm_init (clientsw, serversw, watch, verbose, snoop, 0,
+ queued, sasl, saslmech, user))
|| rp_isbad (retval = sm_winit (smtpmode, from)))
die (NULL, "problem initializing server; %s", rp_string (retval));
}
}
-#endif /* SENDMTS */
-
-/*
- * MMDF routines
- */
-
-#ifdef MMDFMTS
-
-static void
-post (char *file, int bccque, int talk)
-{
- int fd, onex;
- int retval;
-#ifdef RP_NS
- int len;
- struct rp_bufstruct reply;
-#endif /* RP_NS */
-
- 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");
- }
-
- sigon ();
-
- if (rp_isbad (retval = mm_init ())
- || rp_isbad (retval = mm_sbinit ())
- || rp_isbad (retval = mm_winit (NULL, submitopts, from)))
- die (NULL, "problem initializing MMDF system [%s]",
- rp_valstr (retval));
-#ifdef RP_NS
- if (rp_isbad (retval = mm_rrply (&reply, &len)))
- die (NULL, "problem with sender address [%s]",
- rp_valstr (retval));
-#endif /* RP_NS */
-
- 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);
-
- mm_sbend ();
- mm_end (OK);
- sigoff ();
-
- if (verbose)
- if (msgflags & MINV)
- printf (" -- %s Recipient Copies Posted --\n",
- bccque ? "Blind" : "Sighted");
- else
- printf (" -- Recipient Copies Posted --\n");
- fflush (stdout);
-}
-
-
-/* Address Verification */
-
-static void
-verify_all_addresses (int talk)
-{
- int retval;
- struct mailname *lp;
-
-#ifdef RP_NS
- int len;
- struct rp_bufstruct reply;
-#endif /* RP_NS */
-
- sigon ();
-
- if (!whomsw || checksw) {
- if (rp_isbad (retval = mm_init ())
- || rp_isbad (retval = mm_sbinit ())
- || rp_isbad (retval = mm_winit (NULL, submitopts, from)))
- die (NULL, "problem initializing MMDF system [%s]",
- rp_valstr (retval));
-#ifdef RP_NS
- if (rp_isbad (retval = mm_rrply (&reply, &len)))
- die (NULL, "problem with sender address [%s]", rp_valstr (retval));
-#endif /* RP_NS */
- }
-
- if (talk && !whomsw)
- printf (" -- Address Verification --\n");
- if (talk && localaddrs.m_next)
- printf (" -- Local Recipients --\n");
- for (lp = localaddrs.m_next; lp; lp = lp->m_next)
- do_an_address (lp, talk);
-
- if (talk && uuaddrs.m_next)
- printf (" -- UUCP Recipients --\n");
- for (lp = uuaddrs.m_next; lp; lp = lp->m_next)
- do_an_address (lp, talk);
-
- if (talk && netaddrs.m_next)
- printf (" -- Network Recipients --\n");
- for (lp = netaddrs.m_next; lp; lp = lp->m_next)
- do_an_address (lp, talk);
-
- chkadr ();
- if (talk && !whomsw)
- printf (" -- Address Verification Successful --\n");
-
- if (!whomsw || checksw)
- mm_end (NOTOK);
-
- fflush (stdout);
- sigoff ();
-}
-
-
-static void
-do_an_address (struct mailname *lp, int talk)
-{
- int len, retval;
- char *mbox, *host, *text, *path;
- char addr[BUFSIZ];
- struct rp_bufstruct reply;
-
- switch (lp->m_type) {
- case LOCALHOST:
- mbox = lp->m_mbox;
- host = LocalName ();
- strncpy (addr, mbox, sizeof(addr));
- break;
-
- case UUCPHOST:
- fprintf (talk ? stdout : stderr, " %s!%s: %s\n",
- lp->m_host, lp->m_mbox, "not supported; UUCP address");
- unkadr++;
- fflush (stdout);
- return;
-
- default: /* let MMDF decide if the host is bad */
- mbox = lp->m_mbox;
- host = lp->m_host;
- snprintf (addr, sizeof(addr), "%s at %s", mbox, host);
- break;
- }
-
- if (talk)
- printf (" %s%s", addr, whomsw && lp->m_bcc ? "[BCC]" : "");
-
- if (whomsw && !checksw) {
- putchar ('\n');
- return;
- }
- if (talk)
- printf (": ");
- fflush (stdout);
-
-#ifdef MMDFII
- if (lp->m_path)
- path = concat (lp->m_path, mbox, "@", host, NULL);
- else
-#endif /* MMDFII */
- path = NULL;
- if (rp_isbad (retval = mm_wadr (path ? NULL : host, path ? path : mbox))
- || rp_isbad (retval = mm_rrply (&reply, &len)))
- die (NULL, "problem submitting address [%s]", rp_valstr (retval));
-
- switch (rp_gval (reply.rp_val)) {
- case RP_AOK:
- if (talk)
- printf ("address ok\n");
- fflush (stdout);
- return;
-
-#ifdef RP_DOK
- case RP_DOK:
- if (talk)
- printf ("nameserver timeout - queued for checking\n");
- fflush (stdout);
- return;
-#endif /* RP_DOK */
-
- case RP_NO:
- text = "you lose";
- break;
-
-#ifdef RP_NS
- case RP_NS:
- text = "temporary nameserver failure";
- break;
-
-#endif /* RP_NS */
-
- case RP_USER:
- case RP_NDEL:
- text = "not deliverable";
- break;
-
- case RP_AGN:
- text = "try again later";
- break;
-
- case RP_NOOP:
- text = "nothing done";
- break;
-
- default:
- if (!talk)
- fprintf (stderr, " %s: ", addr);
- text = "unexpected response";
- die (NULL, "%s;\n [%s] -- %s", text,
- rp_valstr (reply.rp_val), reply.rp_line);
- }
-
- if (!talk)
- fprintf (stderr, " %s: ", addr);
- fprintf (talk ? stdout : stderr, "%s;\n %s\n", text, reply.rp_line);
- unkadr++;
-
- fflush (stdout);
-}
-
-
-static void
-do_text (char *file, int fd)
-{
- int retval, state;
- char buf[BUFSIZ];
- struct rp_bufstruct reply;
-
- lseek (fd, (off_t) 0, SEEK_SET);
-
- while ((state = read (fd, buf, sizeof(buf))) > 0) {
- if (rp_isbad (mm_wtxt (buf, state)))
- die (NULL, "problem writing text [%s]\n", rp_valstr (retval));
- }
-
- if (state == NOTOK)
- die (file, "problem reading from");
-
- if (rp_isbad (retval = mm_wtend ()))
- die (NULL, "problem ending text [%s]\n", rp_valstr (retval));
-
- if (rp_isbad (retval = mm_rrply (&reply, &state)))
- die (NULL, "problem getting submission status [%s]\n",
- rp_valstr (retval));
-
- switch (rp_gval (reply.rp_val)) {
- case RP_OK:
- case RP_MOK:
- break;
-
- case RP_NO:
- die (NULL, "you lose; %s", reply.rp_line);
-
- case RP_NDEL:
- die (NULL, "no delivery occurred; %s", reply.rp_line);
-
- case RP_AGN:
- die (NULL, "try again later; %s", reply.rp_line);
-
- case RP_NOOP:
- die (NULL, "nothing done; %s", reply.rp_line);
-
- default:
- die (NULL, "unexpected response;\n\t[%s] -- %s",
- rp_valstr (reply.rp_val), reply.rp_line);
- }
-}
-
-#endif /* MMDFMTS */
+#endif /* SMTPMTS */
/*
if (msgflags & MINV)
unlink (bccfil);
-#ifdef MMDFMTS
- if (!whomsw || checksw)
- mm_end (NOTOK);
-#endif /* MMDFMTS */
-
-#ifdef SENDMTS
+#ifdef SMTPMTS
if (!whomsw || checksw)
sm_end (NOTOK);
-#endif /* SENDMTS */
+#endif /* SMTPMTS */
done (1);
}
if (msgflags & MINV)
unlink (bccfil);
-#ifdef MMDFMTS
- if (!whomsw || checksw)
- mm_end (NOTOK);
-#endif /* MMDFMTS */
-
-#ifdef SENDMTS
+#ifdef SMTPMTS
if (!whomsw || checksw)
sm_end (NOTOK);
-#endif /* SENDMTS */
+#endif /* SMTPMTS */
va_start(ap, fmt);
advertise (what, NULL, fmt, ap);
va_end(ap);
done (1);
}
-
-
-#ifdef MMDFMTS
-/*
- * err_abrt() is used by the mm_ routines
- * do not, under *ANY* circumstances, remove it from post,
- * or you will lose *BIG*
- */
-
-void
-err_abrt (int code, char *fmt, ...)
-{
- char buffer[BUFSIZ];
- va_list ap;
-
- snprintf (buffer, sizeof(buffer), "[%s]", rp_valstr (code));
-
- va_start(ap, fmt);
- advertise (buffer, NULL, fmt, ap);
- va_end(ap);
-
- done (1);
-}
-#endif /* MMDFMTS */