Add "Default-From" config option
[mmh] / uip / spost.c
index 093bad5..48f9797 100644 (file)
 #include <h/dropsbr.h>
 #include <h/tws.h>
 #include <h/utils.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sysexits.h>
 
 #define MAX_SM_FIELD 1476  /* < largest hdr field sendmail will accept */
 
-struct swit switches[] = {
+static struct swit switches[] = {
 #define VERBSW  0
        { "verbose", 0 },
 #define NVERBSW  1
-       { "noverbose", 0 },
-#define WATCSW  2
-       { "watch", 0 },
-#define NWATCSW  3
-       { "nowatch", 0 },
-#define ALIASW  4
-       { "alias aliasfile", 0 },
-#define NALIASW  5
-       { "noalias", 0 },
-#define VERSIONSW  6
-       { "version", 0 },
-#define HELPSW  7
+       { "noverbose", 2 },
+#define VERSIONSW  2
+       { "Version", 0 },
+#define HELPSW  3
        { "help", 0 },
-#define DEBUGSW  8
+#define DEBUGSW  4
        { "debug", -5 },
-#define DISTSW  9
+#define DISTSW  5
        { "dist", -4 },  /* interface from dist */
-#define LIBSW  10
-       { "library directory", -7 },
        { NULL, 0 }
 };
 
@@ -63,6 +56,7 @@ struct swit switches[] = {
 #define MVIS  0x0008  /* we've seen sighted addrs */
 #define MINV  0x0010  /* we've seen blind addrs */
 #define MRDT  0x0020  /* we've seen a Resent-Date: */
+#define MFMM  0x0040  /* The Mail is From a Alternative-Mailbox Addresse */
 
 struct headers {
        char *value;
@@ -105,10 +99,9 @@ static struct headers RHeaders[] = {
 };
 
 
-static int badmsg = 0;  /* message has bad semantics */
-static int verbose = 0;  /* spell it out */
-static int debug = 0;  /* debugging post */
-static int watch = 0;  /* watch the delivery process */
+static int badmsg = 0;
+static int verbose = 0;
+static int debug = 0;
 static int aliasflg = 0;  /* if going to process aliases */
 
 static unsigned msgflags = 0;  /* what we've seen */
@@ -147,14 +140,10 @@ main(int argc, char **argv)
        char *sargv[16], buf[BUFSIZ], name[NAMESZ];
        FILE *in;
 
-#ifdef LOCALE
        setlocale(LC_ALL, "");
-#endif
        invo_name = mhbasename(argv[0]);
 
-       /* foil search of user profile/context */
-       if (context_foil(NULL) == -1)
-               done(1);
+       context_read();
 
        arguments = getarguments(invo_name, argc, argv, 0);
        argp = arguments;
@@ -164,19 +153,19 @@ main(int argc, char **argv)
                        switch (smatch(++cp, switches)) {
                        case AMBIGSW:
                                ambigsw(cp, switches);
-                               done(1);
+                               exit(EX_USAGE);
                        case UNKWNSW:
-                               adios(NULL, "-%s unknown", cp);
+                               adios(EX_USAGE, NULL, "-%s unknown", cp);
 
                        case HELPSW:
                                snprintf(buf, sizeof(buf),
                                                "%s [switches] file",
                                                invo_name);
                                print_help(buf, switches, 1);
-                               done(1);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
                        case VERSIONSW:
                                print_version(invo_name);
-                               done(1);
+                               exit(argc == 2 ? EX_OK : EX_USAGE);
 
                        case DEBUGSW:
                                debug++;
@@ -192,47 +181,19 @@ main(int argc, char **argv)
                        case NVERBSW:
                                verbose = 0;
                                continue;
-
-                       case WATCSW:
-                               watch++;
-                               continue;
-                       case NWATCSW:
-                               watch = 0;
-                               continue;
-
-                       case ALIASW:
-                               if (!(cp = *argp++) || *cp == '-')
-                                       adios(NULL, "missing argument to %s",
-                                                       argp[-2]);
-                               aliasflg = 1;
-                               if ((state = alias(cp)) != AK_OK)
-                                       adios(NULL, "aliasing error in file %s - %s", cp, akerror(state));
-                               continue;
-                       case NALIASW:
-                               aliasflg = 0;
-                               continue;
-
-                       case LIBSW:
-                               if (!(cp = *argp++) || *cp == '-')
-                                       adios(NULL, "missing argument to %s",
-                                                       argp[-2]);
-                               /* create a minimal context */
-                               if (context_foil(cp) == -1)
-                                       done(1);
-                               continue;
                        }
                }
                if (msg)
-                       adios(NULL, "only one message at a time!");
+                       adios(EX_USAGE, NULL, "only one message at a time!");
                else
                        msg = cp;
        }
 
        if (!msg)
-               adios(NULL, "usage: %s [switches] file", invo_name);
+               adios(EX_USAGE, NULL, "usage: %s [switches] file", invo_name);
 
        if ((in = fopen(msg, "r")) == NULL)
-               adios(msg, "unable to open");
+               adios(EX_IOERR, msg, "unable to open");
 
        if (debug) {
                verbose++;
@@ -241,6 +202,21 @@ main(int argc, char **argv)
                tmpfil = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out));
        }
 
+       /* check for "Aliasfile:" profile entry */
+       if ((cp = context_find("Aliasfile"))) {
+               char *dp, **ap; 
+
+               aliasflg = 1;
+               for (ap=brkstring(dp=getcpy(cp), " ", "\n"); ap && *ap;
+                               ap++) {
+                       if ((state = alias(etcpath(*ap))) != AK_OK) {
+                               adios(EX_IOERR, NULL, "aliasing error in file %s: %s",
+                                               *ap, akerror(state));
+                       }
+               }
+       }
+
+
        hdrtab = (msgstate == normal) ? NHeaders : RHeaders;
 
        for (compnum = 1, state = FLD;;) {
@@ -278,11 +254,11 @@ main(int argc, char **argv)
 
                case LENERR:
                case FMTERR:
-                       adios(NULL, "message format error in component #%d",
+                       adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);
 
                default:
-                       adios(NULL, "getfld() returned %d", state);
+                       adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
                break;
        }
@@ -290,7 +266,7 @@ main(int argc, char **argv)
 
        if (debug) {
                /* stop here */
-               done(0);
+               exit(EX_OK);
        }
 
        fclose(out);
@@ -300,22 +276,12 @@ main(int argc, char **argv)
                fcc(tmpfil, fccs);
        }
 
-       argp = sargv;
-       *argp++ = "send-mail";
-       *argp++ = "-m";  /* send to me too */
-       *argp++ = "-t";  /* read msg for recipients */
-       *argp++ = "-i";  /* don't stop on "." */
-       if (watch || verbose) {
-               *argp++ = "-v";
-       }
-       *argp = NULL;
-
        if (bccs) {
                process_bccs(tmpfil);
                if (!(msgflags & MVIS)) {
                        /* only Bcc rcpts: we're finished here */
                        unlink(tmpfil);
-                       exit(0);
+                       exit(EX_OK);
                }
        }
 
@@ -324,12 +290,21 @@ main(int argc, char **argv)
        ** the msg temp file as std in.
        */
        if (!freopen(tmpfil, "r", stdin)) {
-               adios(tmpfil, "can't reopen for sendmail");
+               adios(EX_IOERR, tmpfil, "can't reopen for sendmail");
        }
        unlink(tmpfil);
 
+       argp = sargv;
+       *argp++ = "send-mail";
+       *argp++ = "-m";  /* send to me too */
+       *argp++ = "-t";  /* read msg for recipients */
+       *argp++ = "-i";  /* don't stop on "." */
+       if (verbose) {
+               *argp++ = "-v";
+       }
+       *argp = NULL;
        execv(sendmail, sargv);
-       adios(sendmail, "can't exec");
+       adios(EX_OSERR, sendmail, "can't exec");
        return -1;
 }
 
@@ -343,20 +318,25 @@ putfmt(char *name, char *str, FILE *out)
        char *cp;
        struct headers *hdr;
 
-       /* remove all leading whitespace (even newlines) */
-       while (*str==' ' || *str=='\t' || *str=='\n') {
+       /* remove leading whitespace */
+       while (*str==' ' || *str=='\t') {
                str++;
        }
 
        if ((i = get_header(name, hdrtab)) == NOTOK) {
-               /* no header we would care for: push it through */
-               fprintf(out, "%s: %s", name, str);
+               /* no header we would care for */
+               if (mh_strcasecmp(name, attach_hdr)!=0 &&
+                               mh_strcasecmp(name, sign_hdr)!=0 &&
+                               mh_strcasecmp(name, enc_hdr)!=0) {
+                       /* push it through */
+                       fprintf(out, "%s: %s", name, str);
+               }
                return;
        }
        /* it's one of the interesting headers */
        hdr = &hdrtab[i];
 
-       if (hdr->flags & HIGN || !*str) {
+       if (hdr->flags & HIGN || strcmp(str, "\n")==0) {
                return;
        }
 
@@ -432,6 +412,21 @@ putfmt(char *name, char *str, FILE *out)
        ** -- meillo@marmaro.de  2012-02
        */
 
+       if (hdr->set & MFRM) {
+
+               struct mailname *mp = NULL;
+
+               /* This is need because the addresse parser hold global state */
+               ismymbox(NULL);
+
+               while ((cp = getname(str)) != NULL) {
+                       mp = getm(cp, NULL, 0, AD_NAME, NULL);
+                       if (ismymbox(mp)) {
+                               msgflags |= MFMM;
+                       }
+               }
+       }
+
        if (hdr->flags & HSUB) {
                subject = getcpy(str);
        }
@@ -454,24 +449,33 @@ finish_headers(FILE *out)
                fprintf(out, "%sDate: %s\n", resentstr, dtimenow());
        }
 
-       strncpy(from, getusername(), sizeof(from));
-       if ((cp = getfullname()) && *cp) {
-               snprintf(signature, sizeof(signature), "%s <%s>", cp, from);
+       if ((cp = context_find("Default-From")) != NULL) {
+               snprintf(signature, sizeof(signature), "%s", cp);
        } else {
-               snprintf(signature, sizeof(signature), "%s", from);
+               snprintf(from, sizeof(from), "%s@%s", getusername(), LocalName());
+               if ((cp = getfullname()) && *cp) {
+                       snprintf(signature, sizeof(signature), "%s <%s>", cp, from);
+               } else {
+                       snprintf(signature, sizeof(signature), "%s", from);
+               }
        }
        if (!(msgflags & MFRM)) {
                fprintf(out, "%sFrom: %s\n", resentstr, signature);
        } else {
-               /* In case the From: header contains multiple addresses. */
-               fprintf(out, "%sSender: %s\n", resentstr, from);
+               /*
+               ** Add a Sender: header because the From: header could
+               ** be fake or contain multiple addresses.
+               */
+               if (!(msgflags & MFMM)) {
+                       fprintf(out, "%sSender: %s\n", resentstr, signature);
+               }
        }
        if (!(msgflags & MVIS)) {
-               fprintf(out, "%sBcc: Blind Distribution List: ;\n", resentstr);
+               fprintf(out, "%sBcc: undisclosed-recipients:;\n", resentstr);
        }
        if (badmsg) {
                unlink(tmpfil);
-               adios(NULL, "re-format message and try again");
+               adios(EX_DATAERR, NULL, "re-format message and try again");
        }
 }
 
@@ -584,7 +588,7 @@ process_fcc(char *str)
        int state = 0;
 
        if (strlen(str)+strlen(fccs) > sizeof fccs /2) {
-               adios(NULL, "Too much Fcc data");
+               adios(EX_DATAERR, NULL, "Too much Fcc data");
        }
        /* todo: better have three states: SEPARATOR, PLUS, WORD */
        for (cp=pp=str; *cp; cp++) {
@@ -627,7 +631,7 @@ fcc(char *file, char *folders)
                fflush(stdout);
        }
        if (100+strlen(file)+strlen(folders) > sizeof cmd) {
-               adios(NULL, "Too much Fcc data");
+               adios(EX_DATAERR, NULL, "Too much Fcc data");
        }
        /* hack: read from /dev/null and refile(1) won't question us */
        snprintf(cmd, sizeof cmd, "</dev/null refile -link -file '%s' %s",
@@ -649,16 +653,10 @@ static void
 process_bccs(char *origmsg)
 {
        char *bccdraft = NULL;
-       char buf[BUFSIZ];
        struct mailname *mp = NULL;
        FILE *out = NULL;
 
        for (mp=bccs; mp; mp=mp->m_next) {
-               /*
-               ** Note: This draft file will be left existing by send(1),
-               ** although renamed with backup prefix.
-               ** TODO: We should have it removed eventually.
-               */
                bccdraft = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out));
                fprintf(out, "To: %s\n", mp->m_text);
                fprintf(out, "Subject: [BCC] %s", subject ? subject : "");
@@ -666,12 +664,10 @@ process_bccs(char *origmsg)
                fprintf(out, "------------\n");
                fclose(out);
 
-               snprintf(buf, sizeof buf, "send %s", bccdraft);
-               if (system(buf) != 0) {
+               if (execprogl("send", "send", bccdraft, (char *)NULL) != 0) {
                        admonish(invo_name, "Problems to send Bcc to %s",
                                        mp->m_text);
                        unlink(bccdraft);
                }
-               /* TODO: unlink renamed bcc draft after send(1) */
        }
 }