Is anyone out there using VERH with their mailing lists under qmail-ldap? The patch for stock qmail is available here: http://www.ezmlm.org/pub/patches/qmail-verh-0.02.tar.gz (from qmail.org) but had to be modified slightly to fit in with qmail-ldap. I see there's a 0.07 release "for boundary conditions" but I can't get to that patch's website.
In a nutshell VERH allows you to put in To: [EMAIL PROTECTED] into your ezmlm's headeradd file so that email on mailing lists will have that person's email address in the To: line. I needed this functionality after a user complained that he never signed up for a mailing list and it was near impossible to figure out, through his webtv console, what his username was. The updated patch was made by just modifying the patch so that it could be applied as it was only slightly off in places. It is against the latest release, 20040101. The patch follows and can be picked up here: http://ladro.com/qmail/qmail-ldap-1.03-20040101-verh.patch.gz Please let me know if you see any obvious errors, so far it is working fine on my box. Chris --- qmail-local.c.orig 2004-01-10 13:06:00.000000000 -0800 +++ qmail-local.c 2004-01-10 13:05:36.000000000 -0800 @@ -76,6 +76,50 @@ stralloc cmds = {0}; stralloc messline = {0}; stralloc foo = {0}; +stralloc qsender = {0}; +stralloc tmpline = {0}; +char *verhhost = (char *)0; +char *verhlocal = (char *)0; + +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; + } else + return 0; /* ##x => suppr subs */ + } + 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; + } + } +} stralloc qapp = {0}; char buf[1024]; @@ -96,6 +140,8 @@ char hostname[64]; char *s; int loop; + int flagheader; + int match; struct stat st; int fd; substdio ss; @@ -134,12 +180,17 @@ substdio_fdbuf(&ssout,subwrite,fd,outbuf,sizeof(outbuf)); if (substdio_put(&ssout,rpline.s,rpline.len) == -1) goto fail; if (substdio_put(&ssout,dtline.s,dtline.len) == -1) goto fail; + flagheader = 1; - switch(substdio_copy(&ssout,&ss)) - { - case -2: tryunlinktmp(); _exit(4); - case -3: goto fail; - } + do { /* for VERH */ + if (getln(&ss,&messline,&match,'\n') != 0) + { tryunlinktmp(); _exit(4); } + if (match && messline.len == 1) + flagheader = 0; + if (flagheader) + 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; @@ -309,6 +360,7 @@ substdio ss; substdio ssout; int match; + int flagheader; seek_pos pos; int flaglocked; @@ -355,6 +407,7 @@ substdio_fdbuf(&ss,subread,0,buf,sizeof(buf)); substdio_fdbuf(&ssout,subwrite,fd,outbuf,sizeof(outbuf)); + flagheader = 1; 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; @@ -369,6 +422,9 @@ if (!match && !messline.len) break; if (gfrom(messline.s,messline.len)) if (substdio_bput(&ssout,">",1)) goto writeerrs; + if (messline.len == 1) flagheader = 0; + if (flagheader) + if (verhline(&messline) == -1) goto writeerrs; if (substdio_bput(&ssout,messline.s,messline.len)) goto writeerrs; if (!match) { @@ -432,6 +488,7 @@ const char *qqx; substdio ss; int match; + int flagheader; if (seek_begin(0) == -1) temp_rewind(); substdio_fdbuf(&ss,subread,0,buf,sizeof(buf)); @@ -440,6 +497,7 @@ mailforward_qp = qmail_qp(&qqt); qmail_put(&qqt,dtline.s,dtline.len); + flagheader = 1; if (recips[1]) qmail_puts(&qqt,"Precedence: bulk\n"); @@ -447,6 +505,9 @@ do { if (getln(&ss,&messline,&match,'\n') != 0) { qmail_fail(&qqt); break; } + if (match && messline.len == 1) flagheader = 0; + if (flagheader) + if (verhline(&messline) == -1) { qmail_fail(&qqt); break; } qmail_put(&qqt,messline.s,messline.len); } while (match); @@ -640,6 +701,7 @@ datetime_sec starttime; int flagforwardonly; char *x; + char *cplast; /* set up the variables for qmail-ldap */ int slen; @@ -711,9 +773,9 @@ 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(); @@ -721,6 +783,33 @@ 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) { --- qmail-remote.c.orig 2004-01-10 13:07:46.000000000 -0800 +++ qmail-remote.c 2004-01-10 13:06:32.000000000 -0800 @@ -404,19 +404,60 @@ zerodie(); } +stralloc verh = {0}; /* quoted recipient */ +int flagverh; /* argc */ +char *vp; /* argv[3] */ + void blast() { int r; + unsigned int posat, i; char ch; + int flagheader,flagdo; + flagdo = 1; + posat = 0; /* stays 0 if no VERH */ + flagheader = 1; /* => 0 at first blank line */ + if (flagverh == 4) { /* only if single recipient */ + if (!quote2(&verh,vp)) temp_nomem(); /* non-canonicalized */ + for (i = 0; i < verh.len; i++) /* \n would destroy message */ + if (verh.s[i] == '\n') verh.s[i] = '_'; + posat = byte_rchr(verh.s,verh.len,'@'); /* posat=0 if no VERH */ + if (posat == verh.len) posat = 0; + } for (;;) { r = substdio_get(&ssin,&ch,1); if (r == 0) break; if (r == -1) temp_read(); + if (ch == '\n') flagheader = 0; /* end of header */ if (ch == '.') substdio_put(&smtpto,".",1); while (ch != '\n') { - substdio_put(&smtpto,&ch,1); + if (flagheader && ch == '#' && posat && flagdo) { /* ... # */ + r = substdio_get(&ssin,&ch,1); + if (r == 0) perm_partialline(); + if (r == -1) temp_read(); + if (ch == '#') { /* ... ## */ + r = substdio_get(&ssin,&ch,1); + if (r == 0) perm_partialline(); + if (r == -1) temp_read(); + if (ch == 'L') { /* ... ##L */ + substdio_put(&smtpto,verh.s,posat); + } else if (ch == 'H') { /* ... ##H */ + substdio_put(&smtpto,verh.s + posat + 1,verh.len - posat - 1); + } else { + flagdo = 0; /* ... ##x suppress subst */ + substdio_put(&smtpto,"##",2); + if (ch == '\n') break; + substdio_put(&smtpto,&ch,1); + } + } else { + substdio_put(&smtpto,"#",1); + if (ch == '\n') break; + substdio_put(&smtpto,&ch,1); + } + } else + substdio_put(&smtpto,&ch,1); r = substdio_get(&ssin,&ch,1); if (r == 0) perm_partialline(); if (r == -1) temp_read(); @@ -821,6 +862,8 @@ #endif sig_pipeignore(); if (argc < 4) perm_usage(); + flagverh = argc; + vp = argv[3]; if (chdir(auto_qmail) == -1) temp_chdir(); getcontrols();
