find recipients for sendmail
[mmh] / uip / spost.c
index 4d0b48a..3a70f36 100644 (file)
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <locale.h>
 #include <sysexits.h>
+#include <errno.h>
 
 #define MAX_SM_FIELD 1476  /* < largest hdr field sendmail will accept */
 
@@ -115,6 +116,8 @@ static char *tmpfil;
 static char *subject = NULL;  /* the subject field for BCC'ing */
 static char fccs[BUFSIZ] = "";
 struct mailname *bccs = NULL;  /* list of the bcc recipients */
+struct mailname *recipients = NULL;  /* list of the recipients */
+size_t recipientsc = 0;
 struct mailname *sender = NULL;
 
 static struct headers *hdrtab;  /* table for the message we're doing */
@@ -131,6 +134,7 @@ static int putone(char *, int, int);
 static void process_fcc(char *);
 static void fcc(char *, char *);
 static void process_bccs(char *);
+static size_t do_aliasing(struct mailname *, struct mailname **);
 
 
 int
@@ -138,7 +142,7 @@ main(int argc, char **argv)
 {
        int state, compnum;
        char *cp, *msg = NULL, **argp, **arguments;
-       char *sargv[16], buf[BUFSIZ], name[NAMESZ];
+       char **sargv, buf[BUFSIZ], name[NAMESZ];
        FILE *in;
 
        setlocale(LC_ALL, "");
@@ -265,7 +269,20 @@ main(int argc, char **argv)
        fclose(in);
 
        if (debug) {
+               struct mailname *i = recipients;
                /* stop here */
+               puts("----EOM----");
+               while (i) {
+                       fputs(i->m_mbox, stdout);
+                       if (i->m_host) {
+                               fputs("@", stdout);
+                               fputs(i->m_host, stdout);
+                       }
+                       fputs("\n", stdout);
+                       i = i->m_next;
+                       mnfree(recipients);
+                       recipients = i;
+               }
                exit(EX_OK);
        }
 
@@ -294,16 +311,36 @@ main(int argc, char **argv)
        }
        unlink(tmpfil);
 
+       if (recipientsc == 0) {
+               adios(EX_DATAERR, NULL, "message has no recipients");
+       }
+
+       sargv = mh_xmalloc(sizeof(char **) * (recipientsc + 4));
+
        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";
        }
+
+       while (recipients != NULL) {
+               cp = getcpy(recipients->m_mbox);
+               if (recipients->m_host) {
+                       cp = add("@", cp);
+                       cp = add(recipients->m_host, cp);
+               }
+               *argp++ = cp;
+               cp = NULL;
+               recipients = recipients->m_next;
+       }
        *argp = NULL;
-       execv(sendmail, sargv);
+       execvp(sendmail, sargv);
+
+       if (errno == E2BIG) {
+               adios(EX_DATAERR, sendmail, "too much arguments, probably to much recipients");
+       }
+
        adios(EX_OSERR, sendmail, "can't exec");
        return -1;
 }
@@ -315,8 +352,12 @@ static void
 putfmt(char *name, char *str, FILE *out)
 {
        int i;
-       char *cp;
        struct headers *hdr;
+       struct mailname addr_start, *addr_end;
+       size_t addrc;
+
+       addr_end = &addr_start;
+       addr_end->m_next = NULL;
 
        /* remove leading whitespace */
        while (*str==' ' || *str=='\t') {
@@ -358,64 +399,26 @@ putfmt(char *name, char *str, FILE *out)
                return;
        }
 
-       if (hdr->flags & HBCC) {
-               struct mailname *mp = NULL;
+       if (hdr->flags & HSUB) {
+               subject = getcpy(str);
+       }
 
-               /* Create list of Bcc addrs. */
-               while ((cp = getname(str))) {
-                       mp = getm(cp, NULL, 0, AD_HOST, NULL);
-                       mp->m_next = bccs;  /* push */
-                       bccs = mp;
-               }
+       if (!(hdr->flags & HADR)) {
+               fprintf(out, "%s: %s", name, str);
                return;
        }
 
-       if (aliasflg && hdr->flags & HTRY) {
-               /*
-               ** This header contains address(es) that we have to do
-               ** alias expansion on.  Because of the saved state in
-               ** getname we have to put all the addresses into a list.
-               **/
-               struct mailname *f = NULL;
-               struct mailname *mp = NULL;
+       addrc = getmboxes(str, &addr_end);
 
-               while ((cp = getname(str))) {
-                       mp = getm(cp, NULL, 0, AD_HOST, NULL);
-                       if (!f) {
-                               f = mp;
-                               mp->m_next = mp;
-                       } else {
-                               mp->m_next = f->m_next;
-                               f->m_next = mp;
-                               f = mp;
-                       }
-               }
-               f = mp->m_next;
-               mp->m_next = NULL;
-               /* Now munch on the list, possibly expanding aliases */
-               putadr(name, f);
-               return;
+       if (aliasflg) {
+               addrc += do_aliasing(&addr_start, &addr_end);
        }
 
-       /*
-       ** The author(s) of spost decided that alias substitution wasn't
-       ** necessary for the non-HTRY headers.  Unfortunately, one of
-       ** those headers is "From:", and having alias substitution work on
-       ** that is extremely useful for someone with a lot of POP3 email
-       ** accounts or aliases.  post supports aliasing of "From:"...
-       **
-       ** Since "From:"-processing is incompletely implemented in this
-       ** unsupported and undocumented spost backend, I'm not going
-       ** to take the time to implement my new draft-From:-based email
-       ** address masquerading.  If I do ever implement it here, I'd almost
-       ** certainly want to implement "From:" line alias processing as well.
-       ** -- Dan Harkless <dan-nmh@dilvish.speed.net>
-       */
-       /*
-       ** Although there is no masquerading anymore in mmh, we might want
-       ** to have aliasing of From: addresses. Think about it.
-       ** -- meillo@marmaro.de  2012-02
-       */
+       if (hdr->flags & HBCC) {
+               addr_end->m_next = bccs;
+               bccs = addr_start.m_next;
+               return;
+       }
 
        if (hdr->set & MFRM) {
                struct mailname *mp = NULL;
@@ -425,38 +428,28 @@ putfmt(char *name, char *str, FILE *out)
                /* needed because the address parser holds global state */
                ismymbox(NULL);
 
-               while ((cp = getname(str)) != NULL) {
-                       fromcnt++;
-                       mp = getm(cp, NULL, 0, AD_NAME, NULL);
+               for ( mp = addr_start.m_next; mp; mp = mp->m_next) {
                        if (ismymbox(mp)) {
                                msgflags |= MFMM;
                                if (my == NULL) {
                                        my = mp;
-                               } else {
-                                       mnfree(mp);
-                                       mp = NULL;
                                }
-                       } else {
-                               mnfree(mp);
-                               mp = NULL;
                        }
+                       fromcnt++;
                }
 
                if (fromcnt > 1) {
                        sender = my;
-               } else {
-                       mnfree(my);
                }
-
-               free(cp);
-               cp = NULL;
-
        }
 
-       if (hdr->flags & HSUB) {
-               subject = getcpy(str);
+       putadr(name, addr_start.m_next);
+
+       if (hdr->flags & HTRY) {
+               addr_end->m_next = recipients;
+               recipients = addr_start.m_next;
+               recipientsc += i;
        }
-       fprintf(out, "%s: %s", name, str);
 }
 
 
@@ -535,7 +528,6 @@ putadr(char *name, struct mailname *nl)
 {
        struct mailname *mp, *mp2;
        int linepos;
-       char *cp;
        int namelen;
 
        fprintf(out, "%s: ", name);
@@ -547,38 +539,9 @@ putadr(char *name, struct mailname *nl)
                        fprintf(out, "\n%s: ", name);
                        linepos = namelen;
                }
-               if (mp->m_nohost) {
-                       /* a local name - see if it's an alias */
-                       cp = akvalue(mp->m_mbox);
-                       if (cp == mp->m_mbox) {
-                               /* wasn't an alias - use it unchanged */
-                               linepos = putone(mp->m_text, linepos, namelen);
-                       } else {
-                               /* an alias - expand it */
-                               while ((cp = getname(cp))) {
-                                       if (linepos > MAX_SM_FIELD) {
-                                               fprintf(out, "\n%s: ", name);
-                                               linepos = namelen;
-                                       }
-                                       mp2 = getm(cp, NULL, 0, AD_HOST, NULL);
-                                       if (akvisible()) {
-                                               mp2->m_pers = getcpy(mp->m_mbox);
-                                               linepos = putone(adrformat(mp2), linepos, namelen);
-                                       } else {
-                                               linepos = putone(mp2->m_text,
-                                                               linepos,
-                                                               namelen);
-                                       }
-                                       mnfree(mp2);
-                               }
-                       }
-               } else {
-                       /* not a local name - use it unchanged */
-                       linepos = putone(mp->m_text, linepos, namelen);
-               }
+               linepos = putone(mp->m_text, linepos, namelen);
                mp2 = mp;
                mp = mp->m_next;
-               mnfree(mp2);
        }
        putc('\n', out);
 }
@@ -698,3 +661,41 @@ process_bccs(char *origmsg)
                }
        }
 }
+
+/*
+ * Do aliasing on a mailname linked list
+ * Begin at start->m_next
+ * End if m_next == NULL
+ * **end is set to the new end.
+ * Return the number of new mainames in the list
+ */
+
+static size_t
+do_aliasing(struct mailname *start, struct mailname **end)
+{
+       struct mailname *prev, *cur;
+       char *cp;
+       size_t i = 0;
+
+       prev = start;
+       cur = prev->m_next;
+
+       while (cur != NULL) {
+               if (cur->m_nohost) {
+                       cp = akvalue(cur->m_mbox);
+                       if (strcmp(cp, cur->m_mbox) != 0) {
+                               prev->m_next = cur->m_next;
+                               i += getmboxes(cp, &prev);
+                               i -= 1;
+                               mnfree(cur);
+                       } else {
+                               prev = cur;
+                       }
+               } else {
+                       prev = cur;
+               }
+               cur = prev->m_next;
+       }
+       *end = prev;
+       return i;
+}