]> diplodocus.org Git - nmh/blobdiff - uip/post.c
Update instruction output to be a bit more cleaner
[nmh] / uip / post.c
index c9b4c05162c323ea40242e6f98909e55135afa88..f6f7924c01fe476f4d09dbed1c9d57a0007fd09b 100644 (file)
    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        ANNOSW                   24
-    { "idanno number", -6 },           /* interface from send    */
-#define        CLIESW                   25
-    { "client host", -6 },
-#define        SERVSW                   26
-    { "server host", 6 },              /* specify alternate SMTP server */
-#define        SNOOPSW                  27
-    { "snoop", -5 },                   /* snoop the SMTP transaction */
-#define        PARTSW                   28
-    { "partno", -6 },
-#define        QUEUESW                  29
-    { "queued", -6 },
-#define SASLSW                   30
-    { "sasl", SASLminc(-4) },
-#define NOSASLSW                 31
-    { "nosasl", SASLminc(-6) },
-#define SASLMXSSFSW              32
-    { "saslmaxssf", SASLminc(-10) },
-#define SASLMECHSW               33
-    { "saslmech", SASLminc(-5) },
-#define USERSW                   34
-    { "user", SASLminc(-4) },
-#define PORTSW                  35
-    { "port server port name/number", 4 },
-#define TLSSW                   36
-    { "tls", TLSminc(-3) },
-#define NTLSSW                   37
-    { "notls", TLSminc(-5) },
-#define FILEPROCSW              38
-    { "fileproc", -4 },
-#define MHLPROCSW               39
-    { "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("queued", -6, QUEUESW) \
+    X("sasl", SASLminc(-4), SASLSW) \
+    X("nosasl", SASLminc(-6), NOSASLSW) \
+    X("saslmaxssf", SASLminc(-10), SASLMXSSFSW) \
+    X("saslmech", SASLminc(-5), SASLMECHSW) \
+    X("user", SASLminc(-4), USERSW) \
+    X("port server port name/number", 4, PORTSW) \
+    X("tls", TLSminc(-3), TLSSW) \
+    X("notls", TLSminc(-5), NTLSSW) \
+    X("fileproc", -4, FILEPROCSW) \
+    X("mhlproc", -3, MHLPROCSW) \
+    X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
+    X("messageid localname|random", 2, MESSAGEIDSW) \
+
+#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
 
 
 struct headers {
@@ -144,32 +112,32 @@ struct headers {
 /*
  * 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 HONE  0x0800           /* Only (zero or) one address allowed     */
-#define HEFM  0x1000           /* Envelope-From: header                  */
+#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                              */
 
 /*
  * 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 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        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-Sendr:*/
+#define MEFM  0x0080   /* We've seen Envelope-From: */
 
 
 static struct headers NHeaders[] = {
@@ -258,6 +226,7 @@ static char bccfil[BUFSIZ];
 static char from[BUFSIZ];      /* my network address            */
 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 signature[BUFSIZ]; /* my signature                  */
 static char *filter = NULL;    /* the filter for BCC'ing        */
 static char *subject = NULL;   /* the subject field for BCC'ing */
@@ -343,10 +312,10 @@ main (int argc, char **argv)
                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 == '-')
@@ -518,6 +487,19 @@ main (int argc, char **argv)
                        adios (NULL, "missing argument to %s", argp[-2]);
                    mhlproc = cp;
                    continue;
+
+               case MTSSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    save_mts_method (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)
@@ -634,6 +616,7 @@ main (int argc, char **argv)
 
     /* If we are doing a "whom" check */
     if (whomsw) {
+       /* This won't work with MTS_SENDMAIL_PIPE. */
        verify_all_addresses (1, envelope);
        done (0);
     }
@@ -641,7 +624,13 @@ main (int argc, char **argv)
     if (msgflags & MINV) {
        make_bcc_file (dashstuff);
        if (msgflags & MVIS) {
-           verify_all_addresses (verbose, envelope);
+           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, envelope);
+           }
            post (tmpfil, 0, verbose, envelope);
        }
        post (bccfil, 1, verbose, envelope);
@@ -684,7 +673,21 @@ putfmt (char *name, char *str, FILE *out)
     }
 
     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")) {
+               char *newline = strchr (str, '\n');
+               if (newline) *newline = '\0';
+               if (! whomsw) {
+                   advise (NULL, "ignoring header line -- %s: %s", name, str);
+               }
+           }
+       }
+
        return;
     }
 
@@ -815,8 +818,22 @@ putfmt (char *name, char *str, FILE *out)
                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
@@ -876,6 +893,23 @@ putfmt (char *name, char *str, FILE *out)
                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 (strlen(fullfrom) > 0 && 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);
        badmsg++;
@@ -904,6 +938,7 @@ start_headers (void)
     from[0] = '\0';
     efrom[0] = '\0';
     sender[0] = '\0';
+    fullfrom[0] = '\0';
 
     if ((cp = getfullname ()) && *cp) {
        strncpy (sigbuf, cp, sizeof(sigbuf));
@@ -955,8 +990,7 @@ finish_headers (FILE *out)
 
            fprintf (out, "Date: %s\n", dtime (&tclock, 0));
            if (msgid)
-               fprintf (out, "Message-ID: <%d.%ld@%s>\n",
-                       (int) getpid (), (long) tclock, LocalName (1));
+               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
@@ -1005,8 +1039,8 @@ finish_headers (FILE *out)
 
            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 (1));
+               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
@@ -1058,7 +1092,8 @@ putadr (char *name, char *aka, struct mailname *mp, FILE *out, unsigned int flag
 
     if (mp->m_mbox == NULL || ((flags & HTRY) && !insert (mp)))
        return 0;
-    if ((flags & (HBCC | HDCC | HEFM)) || mp->m_ingrp)
+    if (sm_mts != MTS_SENDMAIL_PIPE &&
+        ((flags & (HBCC | HDCC | HEFM)) || mp->m_ingrp))
        return 1;
 
     if (!nameoutput) {
@@ -1102,7 +1137,7 @@ putgrp (char *name, char *group, FILE *out, unsigned int flags)
     int len;
     char *cp;
 
-    if (flags & HBCC)
+    if (sm_mts != MTS_SENDMAIL_PIPE && (flags & HBCC))
        return;
 
     if (!nameoutput) {
@@ -1255,13 +1290,12 @@ make_bcc_file (int dashstuff)
 
     tfile = m_mktemp2(NULL, "bccs", NULL, &out);
     if (tfile == NULL) adios("bcc", "unable to create temporary file");
-    chmod (bccfil, 0600);
     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 (1));
+       fprintf (out, "Message-ID: %s\n", message_id (tclock, 0));
     if (subject)
        fprintf (out, "Subject: %s", subject);
     fprintf (out, "BCC:\n");
@@ -1464,10 +1498,10 @@ do_addresses (int bccque, int talk)
 static void
 post (char *file, int bccque, int talk, char *envelope)
 {
-    int fd, onex;
-    int        retval;
+    int fd;
+    int        retval, i;
+    pid_t child_id;
 
-    onex = !(msgflags & MINV) || bccque;
     if (verbose) {
        if (msgflags & MINV)
            printf (" -- Posting for %s Recipients --\n",
@@ -1478,31 +1512,64 @@ post (char *file, int bccque, int talk, char *envelope)
 
     sigon ();
 
-    if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch, verbose,
-                                   snoop, onex, queued, sasl, saslssf,
-                                   saslmech, user, tls))
-           || rp_isbad (retval = sm_winit (envelope)))
-       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 *sargv[16], **argp;
 
-    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 = sargv;
+               *argp++ = "sendmail";
+               *argp++ = "-t"; /* read msg for recipients */
+               *argp++ = "-i"; /* don't stop on "." */
+               if (whomsw)
+                   *argp++ = "-bv";
+               if (snoop)
+                   *argp++ = "-v";
+               *argp = NULL;
+
+               execv (sendmail, sargv);
+               adios (sendmail, "can't exec");
+
+           default: 
+               pidXwait (child_id, NULL);
+               break;
+       }
+    } else {
+        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
+                                        verbose, snoop, queued, sasl,
+                                        saslssf, saslmech, user, tls))  ||
+            rp_isbad (retval = sm_winit (envelope)))
+           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);
+
+        sm_end (!(msgflags & MINV) || bccque ? OK : DONE);
+        sigoff ();
+
+        if (verbose) {
+            if (msgflags & MINV)
+               printf (" -- %s Recipient Copies Posted --\n",
+                       bccque ? "Blind" : "Sighted");
+            else
+               printf (" -- Recipient Copies Posted --\n");
+        }
+
+        fflush (stdout);
+    }
 }
 
 
@@ -1518,7 +1585,7 @@ verify_all_addresses (int talk, char *envelope)
 
     if (!whomsw || checksw)
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
-                                       verbose, snoop, 0, queued, sasl,
+                                       verbose, snoop, queued, sasl,
                                        saslssf, saslmech, user, tls))
                || rp_isbad (retval = sm_winit (envelope)))
            die (NULL, "problem initializing server; %s", rp_string (retval));