Merge branches 'idx/verh' and 'idx/qmqpc'
[qmail] / qmail-local.c
index cd01602..ec4e5e7 100644 (file)
@@ -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)
   {