X-Git-Url: https://git.distorted.org.uk/~mdw/qmail/blobdiff_plain/853cc1fedbca626ecc7ec56772184d782f13e864..3720dd680be25cf0322d9eccf49b0b504add4411:/qmail-local.c diff --git a/qmail-local.c b/qmail-local.c index cd01602..ec4e5e7 100644 --- a/qmail-local.c +++ b/qmail-local.c @@ -63,6 +63,51 @@ stralloc ueo = {0}; stralloc cmds = {0}; stralloc messline = {0}; stralloc foo = {0}; +stralloc qsender = {0}; +stralloc tmpline = {0}; +char *verhhost = (char *)0; +char *verhlocal = (char *)0; +int flagheader,flagdobody; +unsigned int i; + +int verhline(sa) +stralloc *sa; +/* substitutes ##L => recipient local, ##H => recipient host if VERP sender */ +/* returns 0 normally, -1 on out-of-memory */ +{ + register char *cp; + char *cpnext,*cpafter; + + if (!verhlocal) return 0; /* no VERP SENDER */ + cp = sa->s; + cpnext = sa->s; + cpafter = cp + sa->len; + tmpline.len = 0; /* clear */ + for (;;) { + while (cp < cpafter && *cp++ != '#'); + if (cp + 1 < cpafter && *cp == '#') { /* found '##' */ + cp++; + if (*cp == 'L') { /* ##L */ + if (!stralloc_catb(&tmpline,cpnext,cp - cpnext - 2)) return -1; + cp++; + cpnext = cp; + if (!stralloc_cats(&tmpline,verhlocal)) return -1; + } else if (*cp == 'H') { /* ##H */ + if (!stralloc_catb(&tmpline,cpnext,cp - cpnext - 2)) return -1; + cp++; + cpnext = cp; + if (!stralloc_cats(&tmpline,verhhost)) return -1; + } + } + if (cp >= cpafter) { + if (tmpline.len) { /* true if we've done any substitutions */ + if (!stralloc_catb(&tmpline,cpnext,cpafter - cpnext)) return -1; + if (!stralloc_copy(sa,&tmpline)) return -1; + } + return 0; + } + } +} char buf[1024]; char outbuf[1024]; @@ -82,6 +127,7 @@ char *dir; char host[64]; char *s; int loop; + int match; struct stat st; int fd; substdio ss; @@ -117,11 +163,27 @@ char *dir; if (substdio_put(&ssout,rpline.s,rpline.len) == -1) goto fail; if (substdio_put(&ssout,dtline.s,dtline.len) == -1) goto fail; - switch(substdio_copy(&ssout,&ss)) - { - case -2: tryunlinktmp(); _exit(4); - case -3: goto fail; - } + flagheader = 1; + flagdobody = 0; + do { /* for VERH */ + if (getln(&ss,&messline,&match,'\n') != 0) + { tryunlinktmp(); _exit(4); } + if (flagheader) { + if (match && messline.len == 1) { + flagheader = 0; + if (!flagdobody) verhlocal = (char *)0; + } + if (messline.s[0] == '#') { /* continue in body */ + flagdobody = 1; /* remove leading '#' */ + for (i = 1; i < messline.len; i++) + messline.s[i - 1] = messline.s[i]; + messline.len--; /* always >= 1 from \n */ + } + } + if (verhlocal) + if (verhline(&messline) == -1) goto fail; + if (substdio_put(&ssout,messline.s,messline.len) == -1) goto fail; + } while (match); if (substdio_flush(&ssout) == -1) goto fail; if (fsync(fd) == -1) goto fail; @@ -193,6 +255,8 @@ char *fn; substdio_fdbuf(&ss,read,0,buf,sizeof(buf)); substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf)); + flagheader = 1; + flagdobody = 0; if (substdio_put(&ssout,ufline.s,ufline.len)) goto writeerrs; if (substdio_put(&ssout,rpline.s,rpline.len)) goto writeerrs; if (substdio_put(&ssout,dtline.s,dtline.len)) goto writeerrs; @@ -207,6 +271,20 @@ char *fn; if (!match && !messline.len) break; if (gfrom(messline.s,messline.len)) if (substdio_bput(&ssout,">",1)) goto writeerrs; + if (flagheader) { + if (match && messline.len == 1) { + if (!flagdobody) verhlocal = (char *)0; + flagheader = 0; + } + if (messline.s[0] == '#') { /* continue in body */ + flagdobody = 1; /* remove leading '#' */ + for (i = 1; i < messline.len; i++) + messline.s[i - 1] = messline.s[i]; + messline.len--; + } + } + if (verhlocal) + if (verhline(&messline) == -1) goto writeerrs; if (substdio_bput(&ssout,messline.s,messline.len)) goto writeerrs; if (!match) { @@ -276,9 +354,24 @@ char **recips; if (qmail_open(&qqt) == -1) temp_fork(); mailforward_qp = qmail_qp(&qqt); qmail_put(&qqt,dtline.s,dtline.len); + flagheader = 1; do { if (getln(&ss,&messline,&match,'\n') != 0) { qmail_fail(&qqt); break; } + if (flagheader) { + if (match && messline.len == 1) { + flagheader = 0; + if (!flagdobody) verhlocal = (char *)0; + } + if (messline.s[0] == '#') { /* continue in body */ + flagdobody = 1; /* remove leading '#' */ + for (i = 1; i < messline.len; i++) + messline.s[i - 1] = messline.s[i]; + messline.len--; + } + } + if (verhlocal) + if (verhline(&messline) == -1) { qmail_fail(&qqt); break; } qmail_put(&qqt,messline.s,messline.len); } while (match); @@ -458,6 +551,7 @@ char **argv; datetime_sec starttime; int flagforwardonly; char *x; + char *cplast; umask(077); sig_pipeignore(); @@ -518,9 +612,9 @@ char **argv; if (!env_put2("SENDER",sender)) temp_nomem(); - if (!quote2(&foo,sender)) temp_nomem(); + if (!quote2(&qsender,sender)) temp_nomem(); if (!stralloc_copys(&rpline,"Return-Path: <")) temp_nomem(); - if (!stralloc_cat(&rpline,&foo)) temp_nomem(); + if (!stralloc_cat(&rpline,&qsender)) temp_nomem(); for (i = 0;i < rpline.len;++i) if (rpline.s[i] == '\n') rpline.s[i] = '_'; if (!stralloc_cats(&rpline,">\n")) temp_nomem(); @@ -528,6 +622,33 @@ char **argv; if (!stralloc_0(&foo)) temp_nomem(); if (!env_put2("RPLINE",foo.s)) temp_nomem(); + i = byte_rchr(qsender.s,qsender.len,'@'); /* for VERH */ + if (i != qsender.len) { /* got @ */ + cplast = qsender.s + i; + *cplast = '\0'; + if (qsender.s[i = str_rchr(qsender.s,'=')]) { /* got = */ + qsender.s[i] = '\0'; + cplast = qsender.s + i; + verhhost = qsender.s + i + 1; + i = str_rchr(qsender.s,'-'); + if (qsender.s[i] == '-') { + for (;;) { + if (case_starts(qsender.s + i + 1,"return-")) { + verhlocal = qsender.s + i + 9 + str_chr(qsender.s + i + 8,'-'); + /* here to avoid work if not VERP */ + /* verhhost not used if verhlocal=0 */ + for (x = verhlocal; x < cplast; x++) + if (*x == '\n') *x = '_'; /* \n would ruin */ + break; + } + j = byte_rchr(qsender.s,i,'-'); + if (j == i) break; + i = j; + } + } + } + } + if (!stralloc_copys(&ufline,"From ")) temp_nomem(); if (*sender) {