X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/6170b76c7d080efb5e980260d8fb7a33e0512f61..ddf3a8574f657dcb8c53fc5908e7bebbde1994b5:/uip/inc.c diff --git a/uip/inc.c b/uip/inc.c index f3888394..c34d28ae 100644 --- a/uip/inc.c +++ b/uip/inc.c @@ -30,19 +30,43 @@ */ #endif -#include -#include +#include "h/mh.h" +#include "sbr/fmt_new.h" +#include "sbr/dtime.h" +#include "scansbr.h" +#include "sbr/m_name.h" +#include "sbr/m_gmprot.h" +#include "sbr/getarguments.h" +#include "sbr/concat.h" +#include "sbr/seq_setunseen.h" +#include "sbr/seq_setcur.h" +#include "sbr/seq_save.h" +#include "sbr/smatch.h" +#include "sbr/getfolder.h" +#include "sbr/ext_hook.h" +#include "sbr/folder_read.h" +#include "sbr/folder_realloc.h" +#include "sbr/folder_free.h" +#include "sbr/context_save.h" +#include "sbr/context_replace.h" +#include "sbr/context_find.h" +#include "sbr/ambigsw.h" +#include "sbr/path.h" +#include "sbr/print_version.h" +#include "sbr/print_help.h" +#include "sbr/error.h" +#include "h/utils.h" #include -#include -#include -#include -#include -#include -#include -#include -#include "../sbr/lock_file.h" -#include "../sbr/m_maildir.h" -#include "../sbr/m_mktemp.h" +#include "h/dropsbr.h" +#include "popsbr.h" +#include "h/fmt_scan.h" +#include "h/signals.h" +#include "h/tws.h" +#include "h/mts.h" +#include "h/done.h" +#include "sbr/lock_file.h" +#include "sbr/m_maildir.h" +#include "sbr/m_mktemp.h" #ifndef TLS_SUPPORT # define TLSminc(a) (a) @@ -72,6 +96,7 @@ X("sasl", 0, SASLSW) \ X("nosasl", 0, NOSASLSW) \ X("saslmech", 0, SASLMECHSW) \ + X("tls", TLSminc(-3), TLSSW) \ X("initialtls", TLSminc(-10), INITTLSSW) \ X("notls", TLSminc(-5), NOTLSSW) \ X("certverify", TLSminc(-10), CERTVERSW) \ @@ -93,20 +118,19 @@ DEFINE_SWITCH_ARRAY(INC, switches); #define INC_FILE 0 #define INC_POP 1 -static int inc_type; static struct Maildir_entry { char *filename; time_t mtime; } *Maildir = NULL; static int num_maildir_entries = 0; -static int snoop = 0; +static bool snoop; -extern char response[]; - -static long start; -static long stop; +typedef struct { + FILE *mailout; + long written; +} pop_closure; -static FILE *pf = NULL; +extern char response[]; /* This is an attempt to simplify things by putting all the * privilege ops into macros. @@ -150,17 +174,18 @@ static gid_t return_gid; #endif /* not MAILGROUP */ /* these variables have to be globals so that done() can correctly clean up the lockfile */ -static int locked = 0; +static bool locked; static char *newmail; static FILE *in; /* * prototypes */ +static int maildir_srt(const void *va, const void *vb) PURE; static void inc_done(int) NORETURN; -static int pop_action(char *); +static int pop_action(void *closure, char *); -int +static int maildir_srt(const void *va, const void *vb) { const struct Maildir_entry *a = va, *b = vb; @@ -174,12 +199,15 @@ maildir_srt(const void *va, const void *vb) int main (int argc, char **argv) { + static int inc_type; bool chgflag; int trnflag = 1; bool noisy; int width = -1; int hghnum = 0, msgnum = 0; - bool sasl, tls, noverify; + FILE *pf = NULL; + bool sasl, noverify; + int tls = 0; int incerr = 0; /* <0 if inc hits an error which means it should not truncate mailspool */ char *cp, *maildir = NULL, *folder = NULL; char *format = NULL, *form = NULL; @@ -191,10 +219,11 @@ main (int argc, char **argv) FILE *aud = NULL; char b[PATH_MAX + 1]; char *maildir_copy = NULL; /* copy of mail directory because the static gets overwritten */ + charstring_t scanl = NULL; int nmsgs, nbytes; char *MAILHOST_env_variable; - done=inc_done; + set_done(inc_done); /* absolutely the first thing we do is save our privileges, * and drop them if we can. @@ -202,7 +231,7 @@ main (int argc, char **argv) SAVEGROUPPRIVS(); TRYDROPGROUPPRIVS(); - if (nmh_init(argv[0], 1)) { return 1; } + if (nmh_init(argv[0], true, true)) { return 1; } mts_init (); arguments = getarguments (invo_name, argc, argv, 1); @@ -224,7 +253,7 @@ main (int argc, char **argv) if (pophost && *pophost) host = pophost; - sasl = tls = false; + sasl = false; chgflag = noisy = noverify = true; while ((cp = *argp++)) { if (*cp == '-') { @@ -233,7 +262,7 @@ main (int argc, char **argv) ambigsw (cp, switches); done (1); case UNKWNSW: - adios (NULL, "-%s unknown", cp); + die("-%s unknown", cp); case HELPSW: snprintf (buf, sizeof(buf), "%s [+folder] [switches]", invo_name); @@ -245,8 +274,8 @@ main (int argc, char **argv) case AUDSW: if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); - audfile = getcpy (m_maildir (cp)); + die("missing argument to %s", argp[-2]); + audfile = mh_xstrdup(m_maildir(cp)); continue; case NAUDSW: audfile = NULL; @@ -275,7 +304,7 @@ main (int argc, char **argv) case FILESW: if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); from = path (cp, TFILE); /* @@ -295,38 +324,38 @@ main (int argc, char **argv) case FORMSW: if (!(form = *argp++) || *form == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); format = NULL; continue; case FMTSW: if (!(format = *argp++) || *format == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); form = NULL; continue; case WIDTHSW: if (!(cp = *argp++) || *cp == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); width = atoi (cp); continue; case HOSTSW: if (!(host = *argp++) || *host == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); continue; case PORTSW: if (!(port = *argp++) || *port == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); continue; case USERSW: if (!(user = *argp++) || *user == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); continue; case SNOOPSW: - snoop++; + snoop = true; continue; case SASLSW: @@ -338,15 +367,19 @@ main (int argc, char **argv) case SASLMECHSW: if (!(saslmech = *argp++) || *saslmech == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); + continue; + + case TLSSW: + tls = 1; continue; case INITTLSSW: - tls = true; + tls = 2; continue; case NOTLSSW: - tls = false; + tls = 0; continue; case CERTVERSW: @@ -360,25 +393,24 @@ main (int argc, char **argv) case AUTHSERVICESW: #ifdef OAUTH_SUPPORT if (!(auth_svc = *argp++) || *auth_svc == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); #else - adios (NULL, "not built with OAuth support"); + die("not built with OAuth support"); #endif continue; case PROXYSW: if (!(proxy = *argp++) || *proxy == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); continue; } } if (*cp == '+' || *cp == '@') { if (folder) - adios (NULL, "only one folder at a time!"); - else - folder = pluspath (cp); + die("only one folder at a time!"); + folder = pluspath (cp); } else { - adios (NULL, "usage: %s [+folder] [switches]", invo_name); + die("usage: %s [+folder] [switches]", invo_name); } } @@ -391,35 +423,27 @@ main (int argc, char **argv) /* guarantee dropping group privileges; we might not have done so earlier */ DROPGROUPPRIVS(); - /* - * Where are we getting the new mail? - */ - if (from) - inc_type = INC_FILE; - else if (host) - inc_type = INC_POP; - else - inc_type = INC_FILE; + /* Source of mail; -from overrides any -host. */ + inc_type = host && !from ? INC_POP : INC_FILE; - /* - * Are we getting the mail from - * a POP server? - */ if (inc_type == INC_POP) { + /* Mail from a POP server. */ int tlsflag = 0; if (auth_svc == NULL) { if (saslmech && ! strcasecmp(saslmech, "xoauth2")) { - adios (NULL, "must specify -authservice with -saslmech xoauth2"); + die("must specify -authservice with -saslmech xoauth2"); } } else { if (user == NULL) { - adios (NULL, "must specify -user with -saslmech xoauth2"); + die("must specify -user with -saslmech xoauth2"); } } - if (tls) - tlsflag |= P_INITTLS; + if (tls == 1) + tlsflag = P_STARTTLS; + else if (tls == 2) + tlsflag = P_INITTLS; if (noverify) tlsflag |= P_NOVERIFY; @@ -429,24 +453,19 @@ main (int argc, char **argv) */ if (pop_init (host, port, user, proxy, snoop, sasl, saslmech, tlsflag, auth_svc) == NOTOK) - adios (NULL, "%s", response); + die("%s", response); /* Check if there are any messages */ if (pop_stat (&nmsgs, &nbytes) == NOTOK) - adios (NULL, "%s", response); + die("%s", response); if (nmsgs == 0) { pop_quit(); - adios (NULL, "no mail to incorporate"); + die("no mail to incorporate"); } - } - - /* - * We will get the mail from a file - * (typically the standard maildrop) - */ - if (inc_type == INC_FILE) { + } else if (inc_type == INC_FILE) { + /* Mail from a spool file, or Maildir. */ if (from) newmail = from; else if ((newmail = getenv ("MAILDROP")) && *newmail) @@ -457,56 +476,56 @@ main (int argc, char **argv) newmail = concat (MAILDIR, "/", MAILFIL, NULL); } if (stat (newmail, &s1) == NOTOK || s1.st_size == 0) - adios (NULL, "no mail to incorporate"); - if (s1.st_mode & S_IFDIR) { - DIR *md; - struct dirent *de; - struct stat ms; - int i; - i = 0; - cp = concat (newmail, "/new", NULL); - if ((md = opendir(cp)) == NULL) - adios (NULL, "unable to open %s", cp); - while ((de = readdir (md)) != NULL) { - if (de->d_name[0] == '.') - continue; - if (i >= num_maildir_entries) { - if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL) - adios(NULL, "not enough memory for %d messages", 2*i+16); - num_maildir_entries = 2*i+16; - } - Maildir[i].filename = concat (cp, "/", de->d_name, NULL); - if (stat(Maildir[i].filename, &ms) != 0) - adios (Maildir[i].filename, "couldn't get delivery time"); - Maildir[i].mtime = ms.st_mtime; - i++; - } - free (cp); - closedir (md); - cp = concat (newmail, "/cur", NULL); - if ((md = opendir(cp)) == NULL) - adios (NULL, "unable to open %s", cp); - while ((de = readdir (md)) != NULL) { - if (de->d_name[0] == '.') - continue; - if (i >= num_maildir_entries) { - if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL) - adios(NULL, "not enough memory for %d messages", 2*i+16); - num_maildir_entries = 2*i+16; - } - Maildir[i].filename = concat (cp, "/", de->d_name, NULL); - if (stat(Maildir[i].filename, &ms) != 0) - adios (Maildir[i].filename, "couldn't get delivery time"); - Maildir[i].mtime = ms.st_mtime; - i++; - } - free (cp); - closedir (md); - if (i == 0) - adios (NULL, "no mail to incorporate"); - num_maildir_entries = i; - qsort (Maildir, num_maildir_entries, sizeof(*Maildir), maildir_srt); - } + die("no mail to incorporate"); + if (s1.st_mode & S_IFDIR) { + DIR *md; + struct dirent *de; + struct stat ms; + int i; + i = 0; + cp = concat (newmail, "/new", NULL); + if ((md = opendir(cp)) == NULL) + die("unable to open %s", cp); + while ((de = readdir (md)) != NULL) { + if (de->d_name[0] == '.') + continue; + if (i >= num_maildir_entries) { + if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL) + die("not enough memory for %d messages", 2*i+16); + num_maildir_entries = 2*i+16; + } + Maildir[i].filename = concat (cp, "/", de->d_name, NULL); + if (stat(Maildir[i].filename, &ms) != 0) + adios (Maildir[i].filename, "couldn't get delivery time"); + Maildir[i].mtime = ms.st_mtime; + i++; + } + free (cp); + closedir (md); + cp = concat (newmail, "/cur", NULL); + if ((md = opendir(cp)) == NULL) + die("unable to open %s", cp); + while ((de = readdir (md)) != NULL) { + if (de->d_name[0] == '.') + continue; + if (i >= num_maildir_entries) { + if ((Maildir = realloc(Maildir, sizeof(*Maildir) * (2*i+16))) == NULL) + die("not enough memory for %d messages", 2*i+16); + num_maildir_entries = 2*i+16; + } + Maildir[i].filename = concat (cp, "/", de->d_name, NULL); + if (stat(Maildir[i].filename, &ms) != 0) + adios (Maildir[i].filename, "couldn't get delivery time"); + Maildir[i].mtime = ms.st_mtime; + i++; + } + free (cp); + closedir (md); + if (i == 0) + die("no mail to incorporate"); + num_maildir_entries = i; + qsort (Maildir, num_maildir_entries, sizeof(*Maildir), maildir_srt); + } cp = mh_xstrdup(newmail); newmail = cp; @@ -534,11 +553,13 @@ main (int argc, char **argv) /* read folder and create message structure */ if (!(mp = folder_read (folder, 0))) - adios (NULL, "unable to read folder %s", folder); + die("unable to read folder %s", folder); if (inc_type == INC_FILE && Maildir == NULL) { + /* Mail from a spool file. */ + if (access (newmail, W_OK) != NOTOK) { - locked++; + locked = true; if (trnflag) { SIGNAL (SIGHUP, SIG_IGN); SIGNAL (SIGINT, SIG_IGN); @@ -550,7 +571,7 @@ main (int argc, char **argv) in = lkfopenspool (newmail, "r"); DROPGROUPPRIVS(); if (in == NULL) - adios (NULL, "unable to lock and fopen %s", newmail); + die("unable to lock and fopen %s", newmail); fstat (fileno(in), &s1); } else { trnflag = 0; @@ -568,14 +589,14 @@ main (int argc, char **argv) inform("Creating Receive-Audit: %s", audfile); if ((aud = fopen (audfile, "a")) == NULL) adios (audfile, "unable to append to"); - else if (i == NOTOK) + if (i == NOTOK) chmod (audfile, m_gmprot ()); if (from) fprintf (aud, "<> %s -ms %s\n", dtimenow(0), from); else { if (host) - fprintf (aud, "<> %s -host %s -user %s\n", dtimenow(0), + fprintf (aud, "<> %s -host %s -user %s\n", dtimenow(0), host, user); else fprintf (aud, "<> %s\n", dtimenow (0)); @@ -595,35 +616,37 @@ main (int argc, char **argv) * Get the mail from a POP server */ if (inc_type == INC_POP) { + /* Mail from a POP server. */ int i; + pop_closure pc; hghnum = msgnum = mp->hghmsg; for (i = 1; i <= nmsgs; i++) { - charstring_t scanl = NULL; msgnum++; cp = mh_xstrdup(m_name (msgnum)); if ((pf = fopen (cp, "w+")) == NULL) adios (cp, "unable to write"); chmod (cp, m_gmprot ()); - start = stop = 0L; - if (pop_retr (i, pop_action) == NOTOK) - adios (NULL, "%s", response); + pc.written = 0; + pc.mailout = pf; + if (pop_retr(i, pop_action, &pc) == NOTOK) + die("%s", response); if (fflush (pf)) adios (cp, "write error on"); fseek (pf, 0L, SEEK_SET); switch (incerr = scan (pf, msgnum, 0, nfs, width, msgnum == mp->hghmsg + 1 && chgflag, - 1, NULL, stop - start, noisy, &scanl)) { + 1, NULL, pc.written, noisy, &scanl)) { case SCNEOF: printf ("%*d empty\n", DMAXFOLDER, msgnum); break; case SCNFAT: trnflag = 0; - noisy++; + noisy = true; /* advise (cp, "unable to read"); already advised */ break; @@ -632,7 +655,6 @@ main (int argc, char **argv) break; case SCNMSG: - case SCNENC: default: if (aud) fputs (charstring_buffer (scanl), aud); @@ -640,7 +662,9 @@ main (int argc, char **argv) fflush (stdout); break; } - charstring_free (scanl); + + if (scanl) + charstring_clear (scanl); if (ferror(pf) || fclose (pf)) { int e = errno; @@ -652,24 +676,23 @@ main (int argc, char **argv) free (cp); if (trnflag && pop_dele (i) == NOTOK) - adios (NULL, "%s", response); + die("%s", response); scan_finished(); } + charstring_free (scanl); + scanl = NULL; + if (pop_quit () == NOTOK) - adios (NULL, "%s", response); - } + die("%s", response); + + } else if (inc_type == INC_FILE && Maildir == NULL) { + /* Mail from a spool file. */ - /* - * Get the mail from file (usually mail spool) - */ - if (inc_type == INC_FILE && Maildir == NULL) { scan_detect_mbox_style (in); /* the MAGIC invocation... */ hghnum = msgnum = mp->hghmsg; for (;;) { - charstring_t scanl = NULL; - /* create scanline for new message */ switch (incerr = scan (in, msgnum + 1, msgnum + 1, nfs, width, msgnum == hghnum && chgflag, 1, NULL, 0L, noisy, @@ -693,7 +716,6 @@ main (int argc, char **argv) break; case SCNMSG: - case SCNENC: /* * Run the external program hook on the message. */ @@ -706,25 +728,27 @@ main (int argc, char **argv) if (noisy) fflush (stdout); + charstring_clear (scanl); msgnum++; continue; } - charstring_free (scanl); /* If we get here there was some sort of error from scan(), * so stop processing anything more from the spool. */ break; } - } else if (inc_type == INC_FILE) { /* Maildir inbox to process */ + charstring_free (scanl); + scanl = NULL; + + } else { + /* Mail from Maildir. */ char *sp; FILE *sf; int i; hghnum = msgnum = mp->hghmsg; for (i = 0; i < num_maildir_entries; i++) { - charstring_t scanl = NULL; - msgnum++; sp = Maildir[i].filename; @@ -735,7 +759,7 @@ main (int argc, char **argv) size_t nrd; if ((sf = fopen (sp, "r")) == NULL) - adios (sp, "unable to read for copy"); + adios (sp, "unable to read for copy"); if ((pf = fopen (cp, "w+")) == NULL) adios (cp, "unable to write for copy"); while ((nrd = fread(buf, 1, sizeof(buf), sf)) > 0) @@ -757,14 +781,14 @@ main (int argc, char **argv) fseek (pf, 0L, SEEK_SET); switch (incerr = scan (pf, msgnum, 0, nfs, width, msgnum == mp->hghmsg + 1 && chgflag, - 1, NULL, stop - start, noisy, &scanl)) { + 1, NULL, 0, noisy, &scanl)) { case SCNEOF: printf ("%*d empty\n", DMAXFOLDER, msgnum); break; case SCNFAT: trnflag = 0; - noisy++; + noisy = true; /* advise (cp, "unable to read"); already advised */ break; @@ -773,7 +797,6 @@ main (int argc, char **argv) break; case SCNMSG: - case SCNENC: default: /* * Run the external program hook on the message. @@ -788,7 +811,7 @@ main (int argc, char **argv) fflush (stdout); break; } - charstring_free (scanl); + charstring_clear (scanl); if (ferror(pf) || fclose (pf)) { int e = errno; @@ -806,6 +829,8 @@ main (int argc, char **argv) scan_finished(); } free (Maildir); /* From now on Maildir is just a flag - don't dref! */ + charstring_free (scanl); + scanl = NULL; } scan_finished (); @@ -818,7 +843,7 @@ main (int argc, char **argv) } else { fclose (in); in = NULL; } - adios (NULL, "failed"); + die("failed"); } if (aud) @@ -827,10 +852,9 @@ main (int argc, char **argv) if (noisy) fflush (stdout); - /* - * truncate file we are incorporating from - */ if (inc_type == INC_FILE && Maildir == NULL) { + /* Mail from a spool file; truncate it. */ + if (trnflag) { if (stat (newmail, &st) != NOTOK && s1.st_mtime != st.st_mtime) inform("new messages have arrived!\007"); @@ -850,7 +874,7 @@ main (int argc, char **argv) if (msgnum == hghnum) { inform("no messages incorporated, continuing..."); } else { - /* + /* * Lock the sequence file now, and loop to set the right flags * in the folder structure */ @@ -894,12 +918,11 @@ main (int argc, char **argv) seq_save(mp2); /* Save the sequence file */ folder_free(mp2); } -skip: - /* - * unlock the mail spool - */ +skip: if (inc_type == INC_FILE && Maildir == NULL) { + /* Mail from a spool file; unlock it. */ + if (locked) { GETGROUPPRIVS(); /* Be sure we can unlock mail file */ (void) lkfclosespool (in, newmail); in = NULL; @@ -918,7 +941,7 @@ skip: static void NORETURN inc_done (int status) { - done = exit; + set_done(exit); if (locked) { GETGROUPPRIVS(); @@ -929,9 +952,16 @@ inc_done (int status) } static int -pop_action (char *s) +pop_action(void *closure, char *s) { - fprintf (pf, "%s\n", s); - stop += strlen (s) + 1; - return 0; /* Is return value used? This was missing before 1999-07-15. */ + pop_closure *pc; + int n; + + pc = closure; + n = fprintf(pc->mailout, "%s\n", s); + if (n < 0) + return NOTOK; + pc->written += n; /* Count linefeed too. */ + + return OK; }