X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fspost.c;h=39d8ada53dfb99f8b35888ac62d290e53d7ed978;hp=48f97978dbd3319f66df156cd91c494a0687c2d4;hb=6e9577f324bef90765a5edc02044eb111ec48072;hpb=eda302e1f049eae6b429a12c5526600eea6a02e1 diff --git a/uip/spost.c b/uip/spost.c index 48f9797..39d8ada 100644 --- a/uip/spost.c +++ b/uip/spost.c @@ -19,6 +19,7 @@ #include #include #include +#include #define MAX_SM_FIELD 1476 /* < largest hdr field sendmail will accept */ @@ -38,6 +39,7 @@ static struct swit switches[] = { { NULL, 0 } }; +char *version=VERSION; /* flags for headers->flags */ #define HNOP 0x0000 /* just used to keep .set around */ @@ -48,6 +50,7 @@ static struct swit switches[] = { #define HBCC 0x0010 /* don't output this header */ #define HFCC 0x0020 /* FCC: type header */ #define HIGN 0x0040 /* ignore this header */ +#define HDCC 0x0080 /* DCC: type header */ /* flags for headers->set */ #define MFRM 0x0001 /* we've seen a From: */ @@ -74,6 +77,7 @@ static struct headers NHeaders[] = { { "Subject", HSUB, 0 }, { "To", HADR|HTRY, MVIS }, { "Cc", HADR|HTRY, MVIS }, + { "Dcc", HADR|HTRY|HDCC, MINV }, { "Bcc", HADR|HTRY|HBCC, MINV }, { "Message-Id", HBAD, 0 }, { "Fcc", HFCC, 0 }, @@ -89,6 +93,7 @@ static struct headers RHeaders[] = { { "Resent-Subject", HSUB, 0 }, { "Resent-To", HADR|HTRY, MVIS }, { "Resent-Cc", HADR|HTRY, MVIS }, + { "Resent-Dcc", HADR|HTRY|HDCC, MINV }, { "Resent-Bcc", HADR|HTRY|HBCC, MINV }, { "Resent-Message-Id", HBAD, 0 }, { "Resent-Fcc", HFCC, 0 }, @@ -113,8 +118,12 @@ static enum { static char *tmpfil; static char *subject = NULL; /* the subject field for BCC'ing */ +static struct mailname *from = NULL; /* the from 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 */ static FILE *out; /* output (temp) file */ @@ -130,14 +139,17 @@ 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 main(int argc, char **argv) { - int state, compnum; + enum state state; + struct field f = {{0}}; + int compnum; char *cp, *msg = NULL, **argp, **arguments; - char *sargv[16], buf[BUFSIZ], name[NAMESZ]; + char **sargv, buf[BUFSIZ]; FILE *in; setlocale(LC_ALL, ""); @@ -183,23 +195,26 @@ main(int argc, char **argv) continue; } } - if (msg) + if (msg) { adios(EX_USAGE, NULL, "only one message at a time!"); - else + } else { msg = cp; + } } - if (!msg) + if (!msg) { adios(EX_USAGE, NULL, "usage: %s [switches] file", invo_name); + } - if ((in = fopen(msg, "r")) == NULL) + if ((in = fopen(msg, "r")) == NULL) { adios(EX_IOERR, msg, "unable to open"); + } if (debug) { verbose++; out = stdout; } else { - tmpfil = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out)); + tmpfil = mh_xstrdup(m_mktemp2("/tmp/", invo_name, NULL, &out)); } /* check for "Aliasfile:" profile entry */ @@ -207,7 +222,7 @@ main(int argc, char **argv) char *dp, **ap; aliasflg = 1; - for (ap=brkstring(dp=getcpy(cp), " ", "\n"); ap && *ap; + for (ap=brkstring(dp=mh_xstrdup(cp), " ", "\n"); ap && *ap; ap++) { if ((state = alias(etcpath(*ap))) != AK_OK) { adios(EX_IOERR, NULL, "aliasing error in file %s: %s", @@ -219,41 +234,31 @@ main(int argc, char **argv) hdrtab = (msgstate == normal) ? NHeaders : RHeaders; - for (compnum = 1, state = FLD;;) { - switch (state = m_getfld(state, name, buf, sizeof(buf), in)) { - case FLD: + for (compnum = 1, state = FLD2;;) { + switch (state = m_getfld2(state, &f, in)) { + case FLD2: compnum++; - putfmt(name, buf, out); + putfmt(f.name, f.value, out); continue; - case FLDPLUS: - compnum++; - cp = add(buf, cp); - while (state == FLDPLUS) { - state = m_getfld(state, name, buf, - sizeof(buf), in); - cp = add(buf, cp); - } - putfmt(name, cp, out); - free(cp); - continue; - - case BODY: + case BODY2: finish_headers(out); - fprintf(out, "\n%s", buf); - while (state == BODY) { - state = m_getfld(state, name, buf, - sizeof(buf), in); - fputs(buf, out); + fprintf(out, "\n%s", f.value); + while ((state = m_getfld2(state, &f, in)) == BODY2) { + if (f.valuelen >= NAMESZ) { + adios(EX_DATAERR, NULL, "Body contains a to long line"); + } + fputs(f.value, out); } break; - case FILEEOF: + case FILEEOF2: finish_headers(out); break; - case LENERR: - case FMTERR: + case LENERR2: + case FMTERR2: + case IOERR2: adios(EX_DATAERR, NULL, "message format error in component #%d", compnum); @@ -264,8 +269,25 @@ main(int argc, char **argv) } fclose(in); + if (state != FILEEOF2) { + adios(EX_IOERR, "m_getfld2", "Error while reading body"); + } + 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 +316,36 @@ main(int argc, char **argv) } unlink(tmpfil); + if (recipientsc == 0) { + adios(EX_DATAERR, NULL, "message has no recipients"); + } + + sargv = mh_xcalloc(recipientsc + 4, sizeof(char **)); + 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 = mh_xstrdup(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 +357,13 @@ 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 = 0; + ssize_t ret; + + addr_end = &addr_start; + addr_end->m_next = NULL; /* remove leading whitespace */ while (*str==' ' || *str=='\t') { @@ -325,12 +372,17 @@ putfmt(char *name, char *str, FILE *out) if ((i = get_header(name, hdrtab)) == NOTOK) { /* 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); + if (mh_strcasecmp(name, attach_hdr)==0) { + return; + } + if (mh_strcasecmp(name, sign_hdr)==0) { + return; } + if (mh_strcasecmp(name, enc_hdr)==0) { + return; + } + /* push it through */ + fprintf(out, "%s: %s", name, str); return; } /* it's one of the interesting headers */ @@ -353,84 +405,61 @@ putfmt(char *name, char *str, FILE *out) return; } - if (hdr->flags & HBCC) { - struct mailname *mp = NULL; + if (hdr->flags & HSUB) { + subject = mh_xstrdup(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; + if ((ret = getmboxes(str, &addr_end)) < 0) { + adios(EX_DATAERR, NULL, "can't parse address: %s", str); + } - 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; + addrc += ret; + + 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 - */ - /* - ** 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; + struct mailname *my = NULL; - /* This is need because the addresse parser hold global state */ + /* needed because the address parser holds global state */ ismymbox(NULL); - while ((cp = getname(str)) != NULL) { - 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) { + from = my = mp; + } } } + + if (addrc > 1) { + sender = my; + } } - if (hdr->flags & HSUB) { - subject = getcpy(str); + if (!(hdr->flags & HDCC)) { + 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); } @@ -449,7 +478,9 @@ finish_headers(FILE *out) fprintf(out, "%sDate: %s\n", resentstr, dtimenow()); } - if ((cp = context_find("Default-From")) != NULL) { + if (sender != NULL) { + snprintf(signature, sizeof(signature), "%s", sender->m_text); + } else if ((cp = context_find("Default-From")) != NULL) { snprintf(signature, sizeof(signature), "%s", cp); } else { snprintf(from, sizeof(from), "%s@%s", getusername(), LocalName()); @@ -466,7 +497,7 @@ finish_headers(FILE *out) ** Add a Sender: header because the From: header could ** be fake or contain multiple addresses. */ - if (!(msgflags & MFMM)) { + if (!(msgflags & MFMM) || sender != NULL) { fprintf(out, "%sSender: %s\n", resentstr, signature); } } @@ -493,7 +524,6 @@ get_header(char *header, struct headers *table) return (h - table); } } - return NOTOK; } @@ -506,9 +536,9 @@ get_header(char *header, struct headers *table) static void putadr(char *name, struct mailname *nl) { - struct mailname *mp, *mp2; - int linepos; + struct mailname *mp; char *cp; + int linepos; int namelen; fprintf(out, "%s: ", name); @@ -520,38 +550,18 @@ 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 what the user typed */ - 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); - } + if (mp->m_ingrp) { + if (mp->m_gname != NULL) { + cp = mh_xstrdup(mp->m_gname); + cp = add(";", cp); + linepos = putone(cp, linepos, namelen); + mh_free0(&cp); + cp = NULL; } } else { - /* not a local name - use what the user typed */ linepos = putone(mp->m_text, linepos, namelen); } - mp2 = mp; mp = mp->m_next; - mnfree(mp2); } putc('\n', out); } @@ -559,13 +569,13 @@ putadr(char *name, struct mailname *nl) static int putone(char *adr, int pos, int indent) { - register int len; + int len; static int linepos; len = strlen(adr); - if (pos == indent) + if (pos == indent) { linepos = pos; - else if (linepos+len > OUTPUTLINELEN) { + } else if (linepos+len > OUTPUTLINELEN) { fprintf(out, ",\n%*s", indent, ""); linepos = indent; pos += indent + 2; @@ -641,7 +651,7 @@ fcc(char *file, char *folders) fprintf(stderr, "Skipped %sFcc %s: unable to system().\n", msgstate == resent ? "Resent-" : "", folders); } else if (status != 0) { - fprintf(stderr, "%sFcc %s: Problems occured.\n", + fprintf(stderr, "%sFcc %s: Problems occurred.\n", msgstate == resent ? "Resent-" : "", folders); } } @@ -657,8 +667,11 @@ process_bccs(char *origmsg) FILE *out = NULL; for (mp=bccs; mp; mp=mp->m_next) { - bccdraft = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out)); + bccdraft = mh_xstrdup(m_mktemp2("/tmp/", invo_name, NULL, &out)); fprintf(out, "To: %s\n", mp->m_text); + if (from) { + fprintf(out, "From: %s\n", from->m_text); + } fprintf(out, "Subject: [BCC] %s", subject ? subject : ""); fprintf(out, "%s: %s\n", attach_hdr, origmsg); fprintf(out, "------------\n"); @@ -671,3 +684,48 @@ 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; + ssize_t e; + + 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; + if ((e = getmboxes(cp, &prev)) < 0) { + goto error; + } + i += e; + i -= 1; + mnfree(cur); + } else { + prev = cur; + } + } else { + prev = cur; + } + cur = prev->m_next; + } + *end = prev; + return i; +error: + adios(EX_CONFIG, NULL, "can't parse alias %s: %s", cur->m_mbox, cp); + return 0; /* not reached */ +}