Merge branches 'idx/verh' and 'idx/qmqpc'
authorMark Wooding <mdw@distorted.org.uk>
Tue, 14 Feb 2006 15:55:38 +0000 (15:55 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 14 Feb 2006 15:55:38 +0000 (15:55 +0000)
* idx/verh:
  [PATCH] Rewrite ##X tags in headers of incoming messages

* idx/qmqpc:
  [PATCH] qmqpc: Read servers from the command line.

qmail-local.c
qmail-qmqpc.8
qmail-qmqpc.c
qmail-remote.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)
   {
index e11a15e..d8fbbb5 100644 (file)
@@ -3,6 +3,9 @@
 qmail-qmqpc \- queue a mail message via QMQP
 .SH SYNOPSIS
 .B qmail-qmqpc
+[
+.I server
+[...] ]
 .SH DESCRIPTION
 .B qmail-qmqpc
 offers the same interface as
@@ -16,6 +19,13 @@ installation,
 .B qmail-queue
 is replaced with a symbolic link to
 .BR qmail-qmqpc .
+
+If one or more server IP addresses 
+are specified on the command line,
+.B qmail-qmqpc
+will ignore the control files and instead use the QMQP servers specified on the
+command line.
+
 .SH "CONTROL FILES"
 .TP 5
 .I qmqpservers
@@ -23,6 +33,7 @@ IP addresses of QMQP servers, one address per line.
 .B qmail-qmqpc
 will try each address in turn until it establishes a QMQP connection
 or runs out of addresses.
+
 .SH "SEE ALSO"
 qmail-control(5),
 qmail-queue(8),
index d5adf05..88de856 100644 (file)
@@ -135,25 +135,36 @@ char *server;
 
 stralloc servers = {0};
 
-main()
+main(argc,argv)
+int argc;
+char **argv;
 {
   int i;
   int j;
 
   sig_pipeignore();
 
-  if (chdir(auto_qmail) == -1) die_home();
-  if (control_init() == -1) die_control();
-  if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control();
+  if (!argv[1]) {              /* std behavior */
+    if (chdir(auto_qmail) == -1) die_home();
+    if (control_init() == -1) die_control();
+    if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control();
 
-  getmess();
+    getmess();
 
-  i = 0;
-  for (j = 0;j < servers.len;++j)
-    if (!servers.s[j]) {
-      doit(servers.s + i);
-      i = j + 1;
-    }
+    i = 0;
+    for (j = 0;j < servers.len;++j)
+      if (!servers.s[j]) {
+       doit(servers.s + i);
+       i = j + 1;
+      }
+  } else {                     /* servers on cmd line */
+
+    getmess();
+
+    i = 1;
+    while (argv[i])
+      doit(argv[i++]);
+  }
 
   _exit(lasterror);
 }
index 7d65473..864dee2 100644 (file)
@@ -189,19 +189,68 @@ char *append;
   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();
@@ -341,6 +390,8 @@ char **argv;
  
   sig_pipeignore();
   if (argc < 4) perm_usage();
+  flagverh = argc;
+  vp = argv[3];
   if (chdir(auto_qmail) == -1) temp_chdir();
   getcontrols();