X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/aaf014c77a4fb19bdc33370f5b6af5b8497decf8..7eecb2dcc4a30573ee644491a04e18d1acd7ec81:/uip/post.c diff --git a/uip/post.c b/uip/post.c index db9c0298..81bd7b4a 100644 --- a/uip/post.c +++ b/uip/post.c @@ -1,5 +1,4 @@ -/* - * post.c -- enter messages into the mail transport system +/* post.c -- enter messages into the mail transport system * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -16,6 +15,8 @@ #include #include #include +#include "../sbr/m_mktemp.h" +#include "../sbr/message_id.h" #ifdef HAVE_SYS_TIME_H # include @@ -89,6 +90,8 @@ 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) \ @@ -118,7 +121,7 @@ DEFINE_SWITCH_ARRAY(POST, switches); * from 'send'. We use a service name of 'post' internally. */ -static struct oauth_profile { +static struct { const char *profname; int switchnum; const char *value; @@ -156,6 +159,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 @@ -166,9 +171,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 }, @@ -185,6 +190,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 } }; @@ -208,6 +215,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 } }; @@ -233,7 +242,7 @@ 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="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? */ @@ -257,6 +266,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 */ @@ -305,10 +316,11 @@ static int find_prefix (void); int main (int argc, char **argv) { - int state, compnum, dashstuff = 0, swnum, oauth_flag = 0; + 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[BUFSIZ], name[NAMESZ], *auth_svc = NULL; + char buf[NMH_BUFSIZ], name[NAMESZ], *auth_svc = NULL; FILE *in, *out; m_getfld_state_t gstate = 0; @@ -522,6 +534,14 @@ main (int argc, char **argv) tls = 0; continue; + case CERTVERSW: + noverify = 0; + continue; + + case NOCERTVERSW: + noverify++; + continue; + case FILEPROCSW: if (!(cp = *argp++) || *cp == '-') adios (NULL, "missing argument to %s", argp[-2]); @@ -604,7 +624,7 @@ main (int argc, char **argv) case FLD: case FLDPLUS: compnum++; - cp = add (buf, NULL); + cp = mh_xstrdup(buf); while (state == FLDPLUS) { bufsz = sizeof buf; state = m_getfld (&gstate, name, buf, &bufsz, in); @@ -684,6 +704,16 @@ 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 @@ -742,7 +772,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); @@ -767,7 +797,7 @@ putfmt (char *name, char *str, int *eai, FILE *out) str++; if (msgstate == NORMAL && uprf (name, "resent")) { - advise (NULL, "illegal header line -- %s:", name); + inform("illegal header line -- %s:", name); badmsg++; return; } @@ -777,7 +807,7 @@ putfmt (char *name, char *str, int *eai, FILE *out) If it does, enable EAI support. */ if (contains8bit(str, NULL)) { if (verbose) { - printf ("EAI/SMTPUTF8 enabled\n"); + puts("EAI/SMTPUTF8 enabled"); } /* Enable SMTPUTF8. */ @@ -796,10 +826,9 @@ putfmt (char *name, char *str, int *eai, FILE *out) 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); } } } @@ -812,14 +841,14 @@ putfmt (char *name, char *str, int *eai, FILE *out) return; } if (hdr->flags & HBAD) { - advise (NULL, "illegal header line -- %s:", name); + 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 ((cp = strrchr(str, '\n'))) *cp = 0; @@ -830,7 +859,15 @@ putfmt (char *name, char *str, int *eai, 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; @@ -864,11 +901,11 @@ putfmt (char *name, char *str, int *eai, FILE *out) */ if ((msgstate == RESENT) ? (hdr->set & MRSN) : (hdr->set & MSND)) { - advise (NULL, "%s: field requires one address", name); + 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 */ } @@ -876,7 +913,7 @@ putfmt (char *name, char *str, int *eai, FILE *out) } if (count > 1 && (hdr->flags & HONE)) { - advise (NULL, "%s: field only permits one address", name); + inform("%s: field only permits one address", name); badmsg++; return; } @@ -1026,13 +1063,13 @@ putfmt (char *name, char *str, int *eai, FILE *out) * 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); + inform("%s: field does not allow groups", name); badmsg++; } if (linepos) { @@ -1072,14 +1109,14 @@ 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"); + inform("message has no From: header"); + inform("See default components files for examples"); badmsg++; break; } if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) { - advise (NULL, "A Sender: or Envelope-From: header is required " + inform("A Sender: or Envelope-From: header is required " "with multiple\nFrom: addresses"); badmsg++; break; @@ -1099,7 +1136,7 @@ finish_headers (FILE *out) if (fromcount > 1 && seensender == 0) { 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++; @@ -1114,21 +1151,21 @@ finish_headers (FILE *out) case RESENT: if (!(msgflags & MDAT)) { - advise (NULL, "message has no Date: header"); + inform("message has no Date: header"); badmsg++; } if (!(msgflags & MFRM)) { - advise (NULL, "message has no From: header"); + inform("message has no From: header"); badmsg++; } if (!(msgflags & MRFM)) { - advise (NULL, "message has no Resent-From: header"); - advise (NULL, "See default components files for examples"); + inform("message has no Resent-From: header"); + inform("See default components files for examples"); badmsg++; break; } if (fromcount > 1 && (seensender == 0 && !(msgflags & MEFM))) { - advise (NULL, "A Resent-Sender: or Envelope-From: header is " + inform("A Resent-Sender: or Envelope-From: header is " "required with multiple\nResent-From: addresses"); badmsg++; break; @@ -1149,7 +1186,7 @@ finish_headers (FILE *out) if (fromcount > 1 && seensender == 0) { 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++; @@ -1176,7 +1213,7 @@ get_header (char *header, struct headers *table) struct headers *h; for (h = table; h->value; h++) - if (!strcasecmp (header ? header : "", h->value ? h->value : "")) + if (!strcasecmp (FENDNULL(header), FENDNULL(h->value))) return (h - table); return NOTOK; @@ -1202,7 +1239,7 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag } 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); @@ -1277,10 +1314,10 @@ 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; @@ -1304,7 +1341,7 @@ pl (void) printf ("\nnet:\t"); for (mp = netaddrs.m_next; mp; mp = mp->m_next) - printf ("%s%s@%s%s%s", mp->m_path ? mp->m_path : "", + printf ("%s%s@%s%s%s", FENDNULL(mp->m_path), mp->m_mbox, mp->m_host, mp->m_bcc ? "[BCC]" : "", mp->m_next ? ",\n\t" : ""); @@ -1318,7 +1355,7 @@ pl (void) printf ("\n\t-- Folder Copies --\nfcc:\t"); for (i = 0; i < fccind; i++) printf ("%s%s", fccfold[i], i + 1 < fccind ? ",\n\t" : ""); - printf ("\n"); + putchar('\n'); } @@ -1374,7 +1411,7 @@ insert_fcc (struct headers *hdr, char *pp) if (fccind >= FCCS) adios (NULL, "too many %ss", hdr->value); - fccfold[fccind++] = getcpy (cp); + fccfold[fccind++] = mh_xstrdup(cp); } /* @@ -1512,7 +1549,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; @@ -1531,18 +1568,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)); + 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)); } @@ -1557,7 +1592,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++; } @@ -1566,7 +1601,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++; } @@ -1575,7 +1610,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++; } @@ -1600,7 +1635,6 @@ static void 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; @@ -1609,7 +1643,7 @@ post (char *file, int bccque, int talk, int eai, char *envelope, printf (" -- Posting for %s Recipients --\n", bccque ? "Blind" : "Sighted"); else - printf (" -- Posting for All Recipients --\n"); + puts(" -- Posting for All Recipients --"); } sigon (); @@ -1646,16 +1680,33 @@ post (char *file, int bccque, int talk, int eai, char *envelope, 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, tls)) - || rp_isbad (retval = sm_winit (envelope, eai))) { + 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); - if ((fd = open (file, O_RDONLY)) == NOTOK) - die (file, "unable to re-open"); do_text (file, fd); close (fd); fflush (stdout); @@ -1668,7 +1719,7 @@ post (char *file, int bccque, int talk, int eai, char *envelope, printf (" -- %s Recipient Copies Posted --\n", bccque ? "Blind" : "Sighted"); else - printf (" -- Recipient Copies Posted --\n"); + puts(" -- Recipient Copies Posted --"); } fflush (stdout); @@ -1688,34 +1739,37 @@ verify_all_addresses (int talk, int eai, char *envelope, int oauth_flag, sigon (); 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, saslmech, user, - oauth_flag ? auth_svc : NULL, tls)) - || rp_isbad (retval = sm_winit (envelope, eai))) { + 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); @@ -1767,7 +1821,7 @@ do_an_address (struct mailname *lp, int talk) lp->m_type != UUCPHOST ? lp->m_path : NULL)) { case RP_OK: if (talk) - printf ("address ok\n"); + puts("address ok"); break; case RP_NO: @@ -1795,7 +1849,7 @@ 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))) @@ -1812,6 +1866,7 @@ do_text (char *file, int fd) case RP_NO: case RP_NDEL: die (NULL, "posting failed; %s", rp_string (retval)); + break; default: die (NULL, "unexpected response; %s", rp_string (retval)); @@ -1877,11 +1932,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 --"); } @@ -1933,10 +1988,10 @@ fcc (char *file, char *folder) if (!verbose) fprintf (stderr, " %sFcc %s: ", msgstate == RESENT ? "Resent-" : "", folder); - pidstatus (status, verbose ? stdout : stderr, NULL); + pidstatus (status, verbose ? stdout : stderr, fileproc); } else { if (verbose) - printf ("folder ok\n"); + puts("folder ok"); } } @@ -1950,8 +2005,11 @@ fcc (char *file, char *folder) static void die (char *what, char *fmt, ...) { + int err; va_list ap; + err = errno; + (void) m_unlink (tmpfil); if (msgflags & MINV) (void) m_unlink (bccfil); @@ -1960,6 +2018,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);