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];
char host[64];
char *s;
int loop;
+ int match;
struct stat st;
int fd;
substdio ss;
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;
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;
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)
{
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);
datetime_sec starttime;
int flagforwardonly;
char *x;
+ char *cplast;
umask(077);
sig_pipeignore();
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();
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)
{
zerodie();
}
+stralloc verh = {0}; /* quoted recipient */
+int flagverh; /* argc */
+char *vp; /* argv[3] */
+
void blast()
{
+ unsigned int posat, i;
+ int flagdobody,flagheader;
int r;
char ch;
+ posat = 0; /* stays 0 if no VERH */
+ flagdobody = 0; /* => 0 at first blank line */
+ flagheader = 1;
+ 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 == '.')
substdio_put(&smtpto,".",1);
+ if (flagheader) {
+ if (ch == '\n') { /* header ends */
+ flagheader = 0;
+ if (!flagdobody) posat = 0;
+ } else if (ch == '#') { /* # starting line => VERH ... */
+ flagdobody = 1; /* continues in body and ... */
+ continue; /* character is suppressed. */
+ }
+ }
while (ch != '\n') {
- substdio_put(&smtpto,&ch,1);
+ if (ch == '#' && posat) { /* ... # */
+ r = substdio_get(&ssin,&ch,1);
+ if (r == 0) perm_partialline();
+ if (r == -1) temp_read();
+ if (ch == '#') { /* ... ## */
+ register char ch1;
+ ch1 = *substdio_peek(&ssin);
+ if (ch1 != 'L' && ch1 != 'H') { /* ... ##x x!=L x!=H */
+ substdio_put(&smtpto,"#",1);
+ continue;
+ }
+ 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 /* ... ##H */
+ substdio_put(&smtpto,verh.s + posat + 1,verh.len - posat - 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();
sig_pipeignore();
if (argc < 4) perm_usage();
+ flagverh = argc;
+ vp = argv[3];
if (chdir(auto_qmail) == -1) temp_chdir();
getcontrols();