diff -urN qmail-1.03-vanilla/alloc.c qmail-1.03-md24/alloc.c
--- qmail-1.03-vanilla/alloc.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/alloc.c	2007-07-19 22:04:02.000000000 +0200
@@ -1,7 +1,7 @@
 #include "alloc.h"
 #include "error.h"
-extern char *malloc();
-extern void free();
+
+#include <stdlib.h>
 
 #define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
 #define SPACE 4096 /* must be multiple of ALIGNMENT */
diff -urN qmail-1.03-vanilla/auto-gid.c qmail-1.03-md24/auto-gid.c
--- qmail-1.03-vanilla/auto-gid.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/auto-gid.c	2007-07-19 20:56:22.000000000 +0200
@@ -16,7 +16,7 @@
   if (substdio_puts(&ss1,s) == -1) _exit(111);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -47,5 +47,5 @@
   outs(strnum);
   outs(";\n");
   if (substdio_flush(&ss1) == -1) _exit(111);
-  _exit(0);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/auto-int8.c qmail-1.03-md24/auto-int8.c
--- qmail-1.03-vanilla/auto-int8.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/auto-int8.c	2007-07-19 20:56:22.000000000 +0200
@@ -7,13 +7,13 @@
 char buf1[256];
 substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1));
 
-void puts(s)
+void out(s)
 char *s;
 {
   if (substdio_puts(&ss1,s) == -1) _exit(111);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -30,11 +30,11 @@
   scan_8long(value,&num);
   strnum[fmt_ulong(strnum,num)] = 0;
 
-  puts("int ");
-  puts(name);
-  puts(" = ");
-  puts(strnum);
-  puts(";\n");
+  out("int ");
+  out(name);
+  out(" = ");
+  out(strnum);
+  out(";\n");
   if (substdio_flush(&ss1) == -1) _exit(111);
-  _exit(0);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/auto-int.c qmail-1.03-md24/auto-int.c
--- qmail-1.03-vanilla/auto-int.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/auto-int.c	2007-07-19 20:56:22.000000000 +0200
@@ -7,13 +7,13 @@
 char buf1[256];
 substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1));
 
-void puts(s)
+void out(s)
 char *s;
 {
   if (substdio_puts(&ss1,s) == -1) _exit(111);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -30,11 +30,11 @@
   scan_ulong(value,&num);
   strnum[fmt_ulong(strnum,num)] = 0;
 
-  puts("int ");
-  puts(name);
-  puts(" = ");
-  puts(strnum);
-  puts(";\n");
+  out("int ");
+  out(name);
+  out(" = ");
+  out(strnum);
+  out(";\n");
   if (substdio_flush(&ss1) == -1) _exit(111);
-  _exit(0);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/auto-str.c qmail-1.03-md24/auto-str.c
--- qmail-1.03-vanilla/auto-str.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/auto-str.c	2007-07-19 20:56:22.000000000 +0200
@@ -5,13 +5,13 @@
 char buf1[256];
 substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1));
 
-void puts(s)
+void out(s)
 char *s;
 {
   if (substdio_puts(&ss1,s) == -1) _exit(111);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -25,20 +25,20 @@
   value = argv[2];
   if (!value) _exit(100);
 
-  puts("char ");
-  puts(name);
-  puts("[] = \"\\\n");
+  out("char ");
+  out(name);
+  out("[] = \"\\\n");
 
-  while (ch = *value++) {
-    puts("\\");
+  while ((ch = *value++)) {
+    out("\\");
     octal[3] = 0;
     octal[2] = '0' + (ch & 7); ch >>= 3;
     octal[1] = '0' + (ch & 7); ch >>= 3;
     octal[0] = '0' + (ch & 7);
-    puts(octal);
+    out(octal);
   }
 
-  puts("\\\n\";\n");
+  out("\\\n\";\n");
   if (substdio_flush(&ss1) == -1) _exit(111);
-  _exit(0);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/auto-uid.c qmail-1.03-md24/auto-uid.c
--- qmail-1.03-vanilla/auto-uid.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/auto-uid.c	2007-07-19 20:56:22.000000000 +0200
@@ -16,7 +16,7 @@
   if (substdio_puts(&ss1,s) == -1) _exit(111);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/base64.c qmail-1.03-md24/base64.c
--- qmail-1.03-vanilla/base64.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/base64.c	2007-08-12 10:22:00.000000000 +0200
@@ -0,0 +1,79 @@
+#include "base64.h"
+#include "stralloc.h"
+#include "str.h"
+
+const char base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+static inline int dec(unsigned char x) {
+  if (x>='A' && x<='Z') return x-'A';
+  if (x>='a' && x<='z') return x-'a'+26;
+  if (x>='0' && x<='9') return x-'0'+26+26;
+  switch (x) {
+  case '+': return 62;
+  case '/': return 63;
+  default: return -1;
+  }
+}
+
+unsigned long scan_base64(const char *src,char *dest,unsigned long *destlen) {
+  unsigned short tmp=0,bits=0;
+  register const unsigned char* s=(const unsigned char*) src;
+  const char* orig=dest;
+  for (;;) {
+    int a=dec(*s);
+    if (a<0) {
+      while (*s=='=') ++s;
+      break;
+    }
+    tmp=(tmp<<6)|a; bits+=6;
+    ++s;
+    if (bits>=8) {
+      *dest=(tmp>>(bits-=8));
+      ++dest;
+    }
+  }
+  *destlen=dest-orig;
+  return (const char*)s-src;
+}
+
+unsigned long fmt_base64(char* dest,const char* src,unsigned long len) {
+  register const unsigned char* s=(const unsigned char*) src;
+  unsigned short bits=0,temp=0;
+  unsigned long written=0,i;
+  if (!dest) return ((len+2)/3)*4;
+  for (i=0; i<len; ++i) {
+    temp<<=8; temp+=s[i]; bits+=8;
+    while (bits>6) {
+      dest[written]=base64[((temp>>(bits-6))&63)];
+      ++written; bits-=6;
+    }
+  }
+  if (bits) {
+    temp<<=(6-bits);
+    dest[written]=base64[temp&63];
+    ++written;
+  }
+  while (written&3) { dest[written]='='; ++written; }
+  return written;
+}
+
+/* returns 0 ok, 1 illegal */
+int b64decode(stralloc *out, const char *in, int l)
+{
+  if (!stralloc_readyplus(out, str_len(in))) return 1;
+  scan_base64(in, out->s, &out->len);
+
+  return 0;
+}
+
+
+/* returns 0 ok, 1 illegal */
+int b64encode(stralloc *out, stralloc *in)
+{
+  if (stralloc_readyplus(out, fmt_base64(0,in->s,in->len))) {
+    out->len+=fmt_base64(out->s+out->len,in->s,in->len);
+    return 0;
+  }
+
+  return 1;
+}
diff -urN qmail-1.03-vanilla/base64.h qmail-1.03-md24/base64.h
--- qmail-1.03-vanilla/base64.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/base64.h	2007-08-12 10:02:00.000000000 +0200
@@ -0,0 +1,12 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+#include "stralloc.h"
+
+extern unsigned long scan_base64(const char *src,char *dest,unsigned long *destlen);
+extern unsigned long fmt_base64(char* dest,const char* src,unsigned long len);
+
+extern int b64decode(stralloc *out, const char *in, int l);
+extern int b64encode(stralloc *out, stralloc *in);
+
+#endif
diff -urN qmail-1.03-vanilla/bouncesaying.c qmail-1.03-md24/bouncesaying.c
--- qmail-1.03-vanilla/bouncesaying.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/bouncesaying.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "fork.h"
 #include "strerr.h"
 #include "error.h"
@@ -7,7 +9,7 @@
 
 #define FATAL "bouncesaying: fatal: "
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -38,4 +40,5 @@
   }
 
   strerr_die1x(100,argv[1]);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/byte_cspn.c qmail-1.03-md24/byte_cspn.c
--- qmail-1.03-vanilla/byte_cspn.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/byte_cspn.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,11 @@
+#include "byte.h"
+
+unsigned int byte_cspn(s,n,c)
+register char *s;
+register unsigned int n;
+register char *c;
+{
+  while(*c)
+    n = byte_chr(s,n,*c++);
+  return n;
+}
diff -urN qmail-1.03-vanilla/byte.h qmail-1.03-md24/byte.h
--- qmail-1.03-vanilla/byte.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/byte.h	2007-07-19 20:56:22.000000000 +0200
@@ -3,9 +3,12 @@
 
 extern unsigned int byte_chr();
 extern unsigned int byte_rchr();
+extern unsigned int byte_cspn();
+extern unsigned int byte_rcspn();
+
+extern int byte_diff();
 extern void byte_copy();
 extern void byte_copyr();
-extern int byte_diff();
 extern void byte_zero();
 
 #define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
diff -urN qmail-1.03-vanilla/byte_rcspn.c qmail-1.03-md24/byte_rcspn.c
--- qmail-1.03-vanilla/byte_rcspn.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/byte_rcspn.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,17 @@
+#include "byte.h"
+
+unsigned int byte_rcspn(s,n,c)
+register char *s;
+register unsigned int n;
+register char *c;
+{
+  unsigned int ret,pos,i;
+
+  for(ret = n,pos = 0;*c;++c) {
+    i = byte_rchr(s + pos,n - pos,*c) + pos;
+    if (i < n) ret = pos = i;
+  }
+
+  return ret;
+}
+
diff -urN qmail-1.03-vanilla/case_lowers.c qmail-1.03-md24/case_lowers.c
--- qmail-1.03-vanilla/case_lowers.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/case_lowers.c	2007-07-19 20:56:22.000000000 +0200
@@ -4,7 +4,7 @@
 char *s;
 {
   unsigned char x;
-  while (x = *s) {
+  while ((x = *s)) {
     x -= 'A';
     if (x <= 'Z' - 'A') *s = x + 'a';
     ++s;
diff -urN qmail-1.03-vanilla/cdb.h qmail-1.03-md24/cdb.h
--- qmail-1.03-vanilla/cdb.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/cdb.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,8 @@
 #ifndef CDB_H
 #define CDB_H
 
+#include <sys/types.h>
+#include <unistd.h>
 #include "uint32.h"
 
 extern uint32 cdb_hash();
diff -urN qmail-1.03-vanilla/cdbmss.h qmail-1.03-md24/cdbmss.h
--- qmail-1.03-vanilla/cdbmss.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/cdbmss.h	2007-07-19 20:56:22.000000000 +0200
@@ -4,6 +4,10 @@
 #include "cdbmake.h"
 #include "substdio.h"
 
+extern int cdbmss_start();
+extern int cdbmss_add();
+extern int cdbmss_finish();
+
 struct cdbmss {
   char ssbuf[1024];
   struct cdbmake cdbm;
@@ -11,6 +15,8 @@
   char packbuf[8];
   uint32 pos;
   int fd;
-} ;
+};
 
 #endif
+
+
diff -urN qmail-1.03-vanilla/cdb_seek.c qmail-1.03-md24/cdb_seek.c
--- qmail-1.03-vanilla/cdb_seek.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/cdb_seek.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,5 @@
-#include <sys/types.h>
-#include <errno.h>
-extern int errno;
 #include "cdb.h"
+#include "error.h"
 
 #ifndef SEEK_SET
 #define SEEK_SET 0
diff -urN qmail-1.03-vanilla/chkshsgr.c qmail-1.03-md24/chkshsgr.c
--- qmail-1.03-vanilla/chkshsgr.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/chkshsgr.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,9 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
 #include "exit.h"
-void main()
+int main()
 {
  short x[4];
 
diff -urN qmail-1.03-vanilla/chkspawn.c qmail-1.03-md24/chkspawn.c
--- qmail-1.03-vanilla/chkspawn.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/chkspawn.c	2007-07-19 20:56:22.000000000 +0200
@@ -8,7 +8,7 @@
 char num[FMT_ULONG];
 fd_set fds;
 
-void main()
+int main()
 {
   unsigned long hiddenlimit;
   unsigned long maxnumd;
@@ -22,8 +22,8 @@
     _exit(1);
   }
 
-  if (auto_spawn > 255) {
-    substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 255.\n");
+  if (auto_spawn > 65000) {
+    substdio_puts(subfderr,"Oops. You have set conf-spawn higher than 65000.\n");
     substdio_flush(subfderr);
     _exit(1);
   }
diff -urN qmail-1.03-vanilla/commands.c qmail-1.03-md24/commands.c
--- qmail-1.03-vanilla/commands.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/commands.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,13 +1,33 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "commands.h"
 #include "substdio.h"
 #include "stralloc.h"
 #include "str.h"
+#include "fmt.h"
 #include "case.h"
 
 static stralloc cmd = {0};
 
-int commands(ss,c)
+static void logit(substdio *ll, char *str)
+{
+  static int pid=0;
+  char pidstr[FMT_ULONG];
+
+  if (!pid) { pid=getpid(); }
+  pidstr[fmt_ulong(pidstr,pid)] = 0;
+  substdio_puts(ll,name);
+  substdio_puts(ll,": pid ");
+  substdio_puts(ll,pidstr);
+  substdio_puts(ll," C: ");
+  substdio_puts(ll,str);
+  substdio_puts(ll,"\n");
+  substdio_flush(ll);
+}
+
+int commands(ss,ll,c)
 substdio *ss;
+substdio *ll;
 struct commands *c;
 {
   int i;
@@ -22,12 +42,21 @@
       if (i != 1) return i;
       if (cmd.s[cmd.len] == '\n') break;
       ++cmd.len;
+  
+      if (ctl_maxcmdlen)
+        if (cmd.len > ctl_maxcmdlen) {
+	  die_lcmd(); /* long command detected! ... 
+	  we also don't log such things! */
+	}
     }
 
     if (cmd.len > 0) if (cmd.s[cmd.len - 1] == '\r') --cmd.len;
-
     cmd.s[cmd.len] = 0;
 
+    if (ctl_log_in > 0)
+      if (ll->fd>0)
+        logit(ll,cmd.s);
+
     i = str_chr(cmd.s,' ');
     arg = cmd.s + i;
     while (*arg == ' ') ++arg;
@@ -35,6 +64,7 @@
 
     for (i = 0;c[i].text;++i) if (case_equals(c[i].text,cmd.s)) break;
     c[i].fun(arg);
+
     if (c[i].flush) c[i].flush();
   }
 }
diff -urN qmail-1.03-vanilla/commands.h qmail-1.03-md24/commands.h
--- qmail-1.03-vanilla/commands.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/commands.h	2007-07-19 20:56:22.000000000 +0200
@@ -4,9 +4,14 @@
 struct commands {
   char *text;
   void (*fun)();
-  void (*flush)();
-} ;
+  int  (*flush)();
+};
+
+extern char *name; /* the name of the prog, which uses commands() */
+extern int ctl_log_in;
+extern int ctl_maxcmdlen; /* max length a smtp command may have */
 
 extern int commands();
+extern void die_lcmd();   /* we call this function, when the command is too long */
 
 #endif
diff -urN qmail-1.03-vanilla/condredirect.c qmail-1.03-md24/condredirect.c
--- qmail-1.03-vanilla/condredirect.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/condredirect.c	2007-07-19 20:56:22.000000000 +0200
@@ -28,7 +28,7 @@
 
 char num[FMT_ULONG];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -82,4 +82,5 @@
   qqx = qmail_close(&qqt);
   if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
   strerr_die2x(99,"condredirect: qp ",num);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/control.c qmail-1.03-md24/control.c
--- qmail-1.03-vanilla/control.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/control.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,17 +1,9 @@
-#include "readwrite.h"
-#include "open.h"
-#include "getln.h"
-#include "stralloc.h"
-#include "substdio.h"
-#include "error.h"
 #include "control.h"
-#include "alloc.h"
-#include "scan.h"
 
 static char inbuf[64];
 static stralloc line = {0};
-static stralloc me = {0};
-static int meok = 0;
+stralloc me = {0};
+int meok = 0;
 
 static void striptrailingwhitespace(sa)
 stralloc *sa;
@@ -74,7 +66,7 @@
 char *fn;
 {
  unsigned long u;
- switch(control_readline(&line,fn))
+ switch (control_readline(&line,fn))
   {
    case 0: return 0;
    case -1: return -1;
diff -urN qmail-1.03-vanilla/control.h qmail-1.03-md24/control.h
--- qmail-1.03-vanilla/control.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/control.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,20 @@
 #ifndef CONTROL_H
 #define CONTROL_H
 
+#include <sys/types.h>
+#include <unistd.h>
+#include "readwrite.h"
+#include "open.h"
+#include "getln.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "error.h"
+#include "alloc.h"
+#include "scan.h"
+
+extern int meok;
+extern stralloc me;
+
 extern int control_init();
 extern int control_readline();
 extern int control_rldef();
diff -urN qmail-1.03-vanilla/dns.c qmail-1.03-md24/dns.c
--- qmail-1.03-vanilla/dns.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dns.c	2007-07-19 20:56:22.000000000 +0200
@@ -4,13 +4,15 @@
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
-#include <errno.h>
+
 extern int res_query();
 extern int res_search();
-extern int errno;
 extern int h_errno;
+
+#include "error.h"
 #include "ip.h"
 #include "ipalloc.h"
+#include "strsalloc.h"
 #include "fmt.h"
 #include "alloc.h"
 #include "str.h"
@@ -18,17 +20,22 @@
 #include "dns.h"
 #include "case.h"
 
+#define MAXTXT 256
+
 static unsigned short getshort(c) unsigned char *c;
 { unsigned short u; u = c[0]; return (u << 8) + c[1]; }
 
-static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response;
+static struct { unsigned char *buf; } response;
+static int responsebuflen = 0;
 static int responselen;
 static unsigned char *responseend;
 static unsigned char *responsepos;
+static unsigned long saveresoptions;
 
 static int numanswers;
 static char name[MAXDNAME];
 static struct ip_address ip;
+static char txt[MAXTXT];
 unsigned short pref;
 
 static stralloc glue = {0};
@@ -45,18 +52,32 @@
  errno = 0;
  if (!stralloc_copy(&glue,domain)) return DNS_MEM;
  if (!stralloc_0(&glue)) return DNS_MEM;
- responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response));
+ if (!responsebuflen) response.buf = (unsigned char *)alloc(PACKETSZ+1);
+ if (response.buf) responsebuflen = PACKETSZ+1;
+ else return DNS_MEM;
+
+ responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen);
+ if ((responselen >= responsebuflen) ||
+     (responselen > 0 && (((HEADER *)response.buf)->tc)))
+  {
+   if (responsebuflen < 65536) {
+    if (alloc_re(&response.buf, responsebuflen, 65536))
+     responsebuflen = 65536;
+   } else return DNS_MEM;
+    saveresoptions = _res.options;
+    _res.options |= RES_USEVC;
+    responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen);
+    _res.options = saveresoptions;
+  }
  if (responselen <= 0)
   {
    if (errno == ECONNREFUSED) return DNS_SOFT;
    if (h_errno == TRY_AGAIN) return DNS_SOFT;
    return DNS_HARD;
   }
- if (responselen >= sizeof(response))
-   responselen = sizeof(response);
  responseend = response.buf + responselen;
  responsepos = response.buf + sizeof(HEADER);
- n = ntohs(response.hdr.qdcount);
+ n = ntohs(((HEADER *)response.buf)->qdcount);
  while (n-- > 0)
   {
    i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
@@ -66,7 +87,7 @@
    if (i < QFIXEDSZ) return DNS_SOFT;
    responsepos += QFIXEDSZ;
   }
- numanswers = ntohs(response.hdr.ancount);
+ numanswers = ntohs(((HEADER *)response.buf)->ancount);
  return 0;
 }
 
@@ -179,6 +200,38 @@
  return 0;
 }
 
+static int findtxt(wanttype)
+int wanttype;
+{
+ unsigned short rrtype;
+ unsigned short rrdlen;
+ int i;
+
+ if (numanswers <= 0) return 2;
+ --numanswers;
+ if (responsepos == responseend) return DNS_SOFT;
+
+ i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME);
+ if (i < 0) return DNS_SOFT;
+ responsepos += i;
+
+ i = responseend - responsepos;
+ if (i < 4 + 3 * 2) return DNS_SOFT;
+
+ rrtype = getshort(responsepos);
+ rrdlen = getshort(responsepos + 8);
+ responsepos += 10;
+
+ if (rrtype == wanttype) {
+  str_copyb(txt, responsepos, rrdlen);
+  responsepos += rrdlen;
+  return 1;
+ }
+
+ responsepos += rrdlen;
+ return 0;
+}
+
 void dns_init(flagsearch)
 int flagsearch;
 {
@@ -237,15 +290,18 @@
  return len;
 }
 
-int dns_ptr(sa,ip)
-stralloc *sa;
+static int dns_ptrplus(ssa,ip)
+strsalloc *ssa;
 struct ip_address *ip;
 {
+ stralloc sa = {0};
  int r;
 
- if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM;
- sa->len = iaafmt(sa->s,ip);
- switch(resolve(sa,T_PTR))
+ if (!stralloc_ready(&sa,iaafmt((char *) 0,ip))) return DNS_MEM;
+ sa.len = iaafmt(sa.s,ip);
+ r = resolve(&sa,T_PTR);
+ alloc_free(sa.s);
+ switch(r)
   {
    case DNS_MEM: return DNS_MEM;
    case DNS_SOFT: return DNS_SOFT;
@@ -256,25 +312,46 @@
    if (r == DNS_SOFT) return DNS_SOFT;
    if (r == 1)
     {
-     if (!stralloc_copys(sa,name)) return DNS_MEM;
-     return 0;
+     stralloc sa2 = {0};
+     if (!stralloc_copys(&sa2,name)) return DNS_MEM;
+     if (!strsalloc_append(ssa,&sa2)) return DNS_MEM;
     }
   }
+ if (ssa->len) return 0;
  return DNS_HARD;
 }
 
+int dns_ptr(ssa,ip)
+strsalloc *ssa;
+struct ip_address *ip;
+{
+ int r;
+ int j;
+
+ if (!strsalloc_readyplus(ssa,0)) return DNS_MEM;
+ ssa->len = 0;
+ r = dns_ptrplus(ssa,ip);
+ if (r < 0)
+  {
+   for (j = 0;j < ssa->len;++j)
+    alloc_free(ssa->sa[j].s);
+   ssa->len = 0;
+  }
+ return r;
+}
+
+
 static int dns_ipplus(ia,sa,pref)
 ipalloc *ia;
 stralloc *sa;
 int pref;
 {
  int r;
- struct ip_mx ix;
+ struct ip_mx ix = {0};
 
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  if (!stralloc_0(&glue)) return DNS_MEM;
  if (glue.s[0]) {
-   ix.pref = 0;
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
     {
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
@@ -293,9 +370,12 @@
    ix.ip = ip;
    ix.pref = pref;
    if (r == DNS_SOFT) return DNS_SOFT;
-   if (r == 1)
+   if (r == 1) {
+     ix.fqdn = glue.s;
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
   }
+  }
+ glue.s = 0;
  return 0;
 }
 
@@ -315,7 +395,7 @@
 {
  int r;
  struct mx { stralloc sa; unsigned short p; } *mx;
- struct ip_mx ix;
+ struct ip_mx ix = {0};
  int nummx;
  int i;
  int j;
@@ -327,7 +407,6 @@
  if (!stralloc_copy(&glue,sa)) return DNS_MEM;
  if (!stralloc_0(&glue)) return DNS_MEM;
  if (glue.s[0]) {
-   ix.pref = 0;
    if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)])
     {
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
@@ -398,3 +477,49 @@
  alloc_free(mx);
  return flagsoft;
 }
+
+
+static int dns_txtplus(ssa,sa)
+strsalloc *ssa;
+stralloc *sa;
+{
+ int r;
+
+ switch(resolve(sa,T_TXT)) 
+  {
+   case DNS_MEM: return DNS_MEM;
+   case DNS_SOFT: return DNS_SOFT;
+   case DNS_HARD: return DNS_HARD;
+  }
+ while ((r = findtxt(T_TXT)) != 2)
+  {
+   if (r == DNS_SOFT) return DNS_SOFT;
+   if (r == 1)
+    {
+     stralloc sa = {0};
+     if (!stralloc_copyb(&sa,txt+1,(unsigned char)txt[0])) return DNS_MEM;
+     if (!strsalloc_append(ssa,&sa)) return DNS_MEM;
+    }
+  }
+ if (ssa->len) return 0;
+ return DNS_HARD;
+}
+
+int dns_txt(ssa,sa)
+strsalloc *ssa;
+stralloc *sa;
+{
+ int r;
+ int j;
+
+ if (!strsalloc_readyplus(ssa,0)) return DNS_MEM;
+ ssa->len = 0;
+ r = dns_txtplus(ssa,sa);
+ if (r < 0)
+  {
+   for (j = 0;j < ssa->len;++j)
+    alloc_free(ssa->sa[j].s);
+   ssa->len = 0;
+  }
+ return r;
+}
diff -urN qmail-1.03-vanilla/dnscname.c qmail-1.03-md24/dnscname.c
--- qmail-1.03-vanilla/dnscname.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dnscname.c	2007-07-19 20:56:22.000000000 +0200
@@ -8,7 +8,7 @@
 
 stralloc sa = {0};
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/dnsfq.c qmail-1.03-md24/dnsfq.c
--- qmail-1.03-vanilla/dnsfq.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dnsfq.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,7 @@
 #include "substdio.h"
 #include "subfd.h"
 #include "stralloc.h"
+#include "strsalloc.h"
 #include "dns.h"
 #include "dnsdoe.h"
 #include "ip.h"
@@ -8,12 +9,15 @@
 #include "exit.h"
 
 stralloc sa = {0};
+strsalloc ssa = {0};
 ipalloc ia = {0};
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
+ int j;
+
  if (!argv[1]) _exit(100);
 
  if (!stralloc_copys(&sa,argv[1]))
@@ -25,8 +29,11 @@
   {
    substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100);
   }
- dnsdoe(dns_ptr(&sa,&ia.ix[0].ip));
- substdio_putflush(subfdout,sa.s,sa.len);
- substdio_putsflush(subfdout,"\n");
+ dnsdoe(dns_ptr(&ssa,&ia.ix[0].ip));
+ for(j = 0;j < ssa.len;++j)
+  {
+   substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
+   substdio_putsflush(subfdout,"\n");
+  }
  _exit(0);
 }
diff -urN qmail-1.03-vanilla/dns.h qmail-1.03-md24/dns.h
--- qmail-1.03-vanilla/dns.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dns.h	2007-07-19 20:56:22.000000000 +0200
@@ -3,12 +3,13 @@
 
 #define DNS_SOFT -1
 #define DNS_HARD -2
-#define DNS_MEM -3
+#define DNS_MEM  -3
 
 void dns_init();
 int dns_cname();
 int dns_mxip();
 int dns_ip();
 int dns_ptr();
+int dns_txt();
 
 #endif
diff -urN qmail-1.03-vanilla/dnsip.c qmail-1.03-md24/dnsip.c
--- qmail-1.03-vanilla/dnsip.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dnsip.c	2007-07-19 20:56:22.000000000 +0200
@@ -12,7 +12,7 @@
 stralloc sa = {0};
 ipalloc ia = {0};
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/dnsmxip.c qmail-1.03-md24/dnsmxip.c
--- qmail-1.03-vanilla/dnsmxip.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dnsmxip.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "subfd.h"
 #include "stralloc.h"
@@ -14,7 +16,7 @@
 stralloc sa = {0};
 ipalloc ia = {0};
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/dnsptr.c qmail-1.03-md24/dnsptr.c
--- qmail-1.03-vanilla/dnsptr.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/dnsptr.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,7 @@
 #include "substdio.h"
 #include "subfd.h"
 #include "stralloc.h"
+#include "strsalloc.h"
 #include "str.h"
 #include "scan.h"
 #include "dns.h"
@@ -8,20 +9,25 @@
 #include "ip.h"
 #include "exit.h"
 
-stralloc sa = {0};
+strsalloc ssa = {0};
 struct ip_address ip;
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
+ int j;
+
  if (!argv[1]) _exit(100);
 
  ip_scan(argv[1],&ip);
 
  dns_init(0);
- dnsdoe(dns_ptr(&sa,&ip));
- substdio_putflush(subfdout,sa.s,sa.len);
- substdio_putsflush(subfdout,"\n");
+ dnsdoe(dns_ptr(&ssa,&ip));
+ for(j = 0;j < ssa.len;++j)
+  {
+   substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len);
+   substdio_putsflush(subfdout,"\n");
+  }
  _exit(0);
 }
diff -urN qmail-1.03-vanilla/dnstxt.c qmail-1.03-md24/dnstxt.c
--- qmail-1.03-vanilla/dnstxt.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/dnstxt.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,32 @@
+#include "substdio.h"
+#include "subfd.h"
+#include "stralloc.h"
+#include "str.h"
+#include "scan.h"
+#include "dns.h"
+#include "dnsdoe.h"
+#include "strsalloc.h"
+#include "exit.h"
+
+strsalloc ssa = {0};
+stralloc sa = {0};
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+ int j;
+
+ if (!argv[1]) _exit(100);
+
+ if (!stralloc_copys(&sa, argv[1]))
+  { substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
+ dns_init(0);
+ dnsdoe(dns_txt(&ssa,&sa));
+ for (j = 0;j < ssa.len;++j)
+  {
+   substdio_put(subfdout,ssa.sa[j].s,ssa.sa[j].len);
+   substdio_putsflush(subfdout,"\n");
+  }
+ _exit(0);
+}
diff -urN qmail-1.03-vanilla/envread.c qmail-1.03-md24/envread.c
--- qmail-1.03-vanilla/envread.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/envread.c	2007-07-19 20:56:22.000000000 +0200
@@ -9,7 +9,7 @@
   char *envi;
  
   slen = str_len(s);
-  for (i = 0;envi = environ[i];++i)
+  for (i = 0; (envi = environ[i]); ++i)
     if ((!str_diffn(s,envi,slen)) && (envi[slen] == '='))
       return envi + slen + 1;
   return 0;
diff -urN qmail-1.03-vanilla/error.c qmail-1.03-md24/error.c
--- qmail-1.03-vanilla/error.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/error.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <errno.h>
 #include "error.h"
 
 /* warning: as coverage improves here, should update error_{str,temp} */
@@ -93,3 +92,10 @@
 #else
 -13;
 #endif
+
+int error_dquot =
+#ifdef EDQUOT
+EDQUOT;
+#else
+-14;
+#endif
diff -urN qmail-1.03-vanilla/error.h qmail-1.03-md24/error.h
--- qmail-1.03-vanilla/error.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/error.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,7 @@
 #ifndef ERROR_H
 #define ERROR_H
 
-extern int errno;
+#include <errno.h>
 
 extern int error_intr;
 extern int error_nomem;
@@ -16,6 +16,7 @@
 extern int error_pipe;
 extern int error_perm;
 extern int error_acces;
+extern int error_dquot;
 
 extern char *error_str();
 extern int error_temp();
diff -urN qmail-1.03-vanilla/error_str.c qmail-1.03-md24/error_str.c
--- qmail-1.03-vanilla/error_str.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/error_str.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <errno.h>
 #include "error.h"
 
 #define X(e,s) if (i == e) return s;
diff -urN qmail-1.03-vanilla/error_temp.c qmail-1.03-md24/error_temp.c
--- qmail-1.03-vanilla/error_temp.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/error_temp.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <errno.h>
 #include "error.h"
 
 #define X(n) if (e == n) return 1;
diff -urN qmail-1.03-vanilla/except.c qmail-1.03-md24/except.c
--- qmail-1.03-vanilla/except.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/except.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "fork.h"
 #include "strerr.h"
 #include "wait.h"
@@ -6,7 +8,7 @@
 
 #define FATAL "except: fatal: "
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/fd_copy.c qmail-1.03-md24/fd_copy.c
--- qmail-1.03-vanilla/fd_copy.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/fd_copy.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,5 @@
-#include <fcntl.h>
 #include "fd.h"
+#include <fcntl.h>
 
 int fd_copy(to,from)
 int to;
diff -urN qmail-1.03-vanilla/fd.h qmail-1.03-md24/fd.h
--- qmail-1.03-vanilla/fd.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/fd.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,9 @@
 #ifndef FD_H
 #define FD_H
 
+#include <sys/types.h>
+#include <unistd.h>
+
 extern int fd_copy();
 extern int fd_move();
 
diff -urN qmail-1.03-vanilla/FILES qmail-1.03-md24/FILES
--- qmail-1.03-vanilla/FILES	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/FILES	2007-07-19 23:13:50.000000000 +0200
@@ -1,9 +1,12 @@
+BIN.Makefile
+BIN.README
 BLURB
 BLURB2
 BLURB3
 BLURB4
-README
+CHANGES
 FAQ
+FILES
 INSTALL
 INSTALL.alias
 INSTALL.ctl
@@ -11,18 +14,8 @@
 INSTALL.maildir
 INSTALL.mbox
 INSTALL.vsm
-REMOVE.sendmail
-REMOVE.binmail
-TEST.deliver
-TEST.receive
-UPGRADE
-THOUGHTS
-TODO
-THANKS
-CHANGES
-SECURITY
 INTERNALS
-SENDMAIL
+Makefile
 PIC.local2alias
 PIC.local2ext
 PIC.local2local
@@ -32,402 +25,444 @@
 PIC.relaybad
 PIC.relaygood
 PIC.rem2local
-FILES
-VERSION
+README
+REMOVE.binmail
+REMOVE.sendmail
+SECURITY
+SENDMAIL
 SYSDEPS
 TARGETS
-Makefile
-BIN.README
-BIN.Makefile
-idedit.c
-conf-break
+TEST.deliver
+TEST.receive
+THANKS
+THOUGHTS
+TODO
+UPGRADE
+VERSION
+addresses.5
+alloc.3
+alloc.c
+alloc.h
+alloc_re.c
+auto-gid.c
+auto-int.c
+auto-int8.c
+auto-str.c
+auto-uid.c
 auto_break.h
-conf-spawn
+auto_patrn.h
+auto_qmail.h
 auto_spawn.h
-chkspawn.c
-conf-split
 auto_split.h
-conf-patrn
-auto_patrn.h
-conf-users
-conf-groups
 auto_uids.h
 auto_usera.h
-extra.h
-addresses.5
-except.1
+base64.c
+base64.h
+binm1+df.sh
+binm1.sh
+binm2+df.sh
+binm2.sh
+binm3+df.sh
+binm3.sh
 bouncesaying.1
+bouncesaying.c
+byte.h
+byte_chr.c
+byte_copy.c
+byte_cr.c
+byte_cspn.c
+byte_diff.c
+byte_rchr.c
+byte_rcspn.c
+byte_zero.c
+case.3
+case.h
+case_diffb.c
+case_diffs.c
+case_lowerb.c
+case_lowers.c
+case_starts.c
+cdb.3
+cdb.h
+cdb_hash.c
+cdb_seek.c
+cdb_unpack.c
+cdbmake.h
+cdbmake_add.c
+cdbmake_hash.c
+cdbmake_pack.c
+cdbmss.c
+cdbmss.h
+chkshsgr.c
+chkspawn.c
+coe.3
+coe.c
+coe.h
+commands.c
+commands.h
 condredirect.1
+condredirect.c
+conf-break
+conf-cc
+conf-groups
+conf-ld
+conf-patrn
+conf-qmail
+conf-spawn
+conf-split
+conf-users
+config-fast.sh
+config.sh
+constmap.c
+constmap.h
+control.c
+control.h
+date822fmt.c
+date822fmt.h
+datemail.sh
+datetime.3
+datetime.c
+datetime.h
+datetime_un.c
+direntry.3
+direntry.h1
+direntry.h2
+dns.c
+dns.h
+dnscname.c
+dnsdoe.c
+dnsdoe.h
+dnsfq.c
+dnsip.c
+dnsmxip.c
+dnsptr.c
+dnstxt.c
 dot-qmail.9
+elq.sh
+env.3
+env.c
+env.h
 envelopes.5
+envread.c
+error.3
+error.c
+error.h
+error_str.3
+error_str.c
+error_temp.3
+error_temp.c
+except.1
+except.c
+exit.h
+extra.h
+fd.h
+fd_copy.3
+fd_copy.c
+fd_move.3
+fd_move.c
+fifo.c
+fifo.h
+fifo_make.3
+find-systype.sh
+fmt.h
+fmt_str.c
+fmt_strn.c
+fmt_uint.c
+fmt_uint0.c
+fmt_ulong.c
+fmtqfn.c
+fmtqfn.h
 forgeries.7
+fork.h1
+fork.h2
 forward.1
+forward.c
+gen_alloc.h
+gen_allocdefs.h
+getln.3
+getln.c
+getln.h
+getln2.3
+getln2.c
+gfrom.c
+gfrom.h
+headerbody.c
+headerbody.h
+hfield.c
+hfield.h
+hier.c
+hmac.h
+hmac_md5.c
+hmac_md5.o
+hmac_ripemd.c
+hmac_ripemd.o
+hmac_sha1.c
+hmac_sha1.h
+home+df.sh
+home.sh
+hostname.c
+idedit.c
+install-big.c
+install.c
+install.h
+instcheck.c
+ip.c
+ip.h
+ipalloc.c
+ipalloc.h
+ipme.c
+ipme.h
+ipmeprint.c
+lock.h
+lock_ex.c
+lock_exnb.c
+lock_un.c
+maildir.5
+maildir.c
+maildir.h
 maildir2mbox.1
+maildir2mbox.c
 maildirmake.1
+maildirmake.c
 maildirwatch.1
+maildirwatch.c
 mailsubj.1
+mailsubj.sh
+make-compile.sh
+make-load.sh
+make-makelib.sh
 mbox.5
+md5.c
+md5.h
+md5.o
+myctime.c
+myctime.h
+ndelay.c
+ndelay.h
+ndelay_off.c
+newfield.c
+newfield.h
+now.3
+now.c
+now.h
+open.h
+open_append.c
+open_excl.c
+open_read.c
+open_trunc.c
+open_write.c
+out_log.c
+out_log.h
+pinq.sh
+predate.c
 preline.1
+preline.c
+prioq.c
+prioq.h
+proc+df.sh
+proc.sh
+prot.c
+prot.h
+qail.sh
 qbiff.1
+qbiff.c
+qlx.h
 qmail-clean.8
+qmail-clean.c
 qmail-command.8
 qmail-control.9
 qmail-getpw.9
+qmail-getpw.c
 qmail-header.5
 qmail-inject.8
+qmail-inject.c
 qmail-limits.9
 qmail-local.8
+qmail-local.c
 qmail-log.5
 qmail-lspawn.8
+qmail-lspawn.c
 qmail-newmrh.9
+qmail-newmrh.c
 qmail-newu.9
+qmail-newu.c
+qmail-p0f.c
+qmail-p0f.h
+qmail-p0f.o
 qmail-pop3d.8
+qmail-pop3d.c
 qmail-popup.8
+qmail-popup.c
 qmail-pw2u.9
+qmail-pw2u.c
 qmail-qmqpc.8
+qmail-qmqpc.c
 qmail-qmqpd.8
+qmail-qmqpd.c
 qmail-qmtpd.8
+qmail-qmtpd.c
 qmail-qread.8
+qmail-qread.c
 qmail-qstat.8
+qmail-qstat.sh
 qmail-queue.8
+qmail-queue.c
 qmail-remote.8
+qmail-remote.c
 qmail-rspawn.8
+qmail-rspawn.c
+qmail-sasl.c
+qmail-sasl.h
 qmail-send.9
+qmail-send.c
 qmail-showctl.8
+qmail-showctl.c
 qmail-smtpd.8
+qmail-smtpd.c
 qmail-start.9
+qmail-start.c
 qmail-tcpok.8
+qmail-tcpok.c
 qmail-tcpto.8
+qmail-tcpto.c
+qmail-upq.sh
 qmail-users.9
 qmail.7
+qmail.c
+qmail.h
 qreceipt.1
-splogger.8
-tcp-env.1
-config.sh
-config-fast.sh
-qmail-clean.c
-qmail-getpw.c
-qmail-inject.c
-qmail-local.c
-qmail-lspawn.c
-qmail-newmrh.c
-qmail-newu.c
-qmail-pop3d.c
-qmail-popup.c
-qmail-pw2u.c
-qmail-qmqpc.c
-qmail-qmqpd.c
-qmail-qmtpd.c
-qmail-qread.c
-qmail-qstat.sh
-qmail-queue.c
-qmail-remote.c
-qmail-rspawn.c
-qmail-send.c
-qmail-showctl.c
-qmail-smtpd.c
-qmail-start.c
-qmail-tcpok.c
-qmail-tcpto.c
-spawn.c
-dnscname.c
-dnsfq.c
-dnsip.c
-dnsmxip.c
-dnsptr.c
-hostname.c
-ipmeprint.c
-tcp-env.c
-sendmail.c
 qreceipt.c
 qsmhook.c
-qbiff.c
-forward.c
-preline.c
-predate.c
-except.c
-bouncesaying.c
-condredirect.c
-maildirmake.c
-maildir2mbox.c
-maildirwatch.c
-splogger.c
-qail.sh
-elq.sh
-pinq.sh
-qmail-upq.sh
-datemail.sh
-mailsubj.sh
-qlx.h
-rcpthosts.h
-rcpthosts.c
-commands.h
-commands.c
-dnsdoe.h
-dnsdoe.c
-fmtqfn.h
-fmtqfn.c
-gfrom.h
-gfrom.c
-myctime.h
-myctime.c
-newfield.h
-newfield.c
-qsutil.h
 qsutil.c
-readsubdir.h
+qsutil.h
+quote.c
+quote.h
+rcpthosts.c
+rcpthosts.h
 readsubdir.c
-received.h
+readsubdir.h
+readwrite.h
+realrcptto.c
+realrcptto.o
 received.c
-tcpto.h
-tcpto.c
-tcpto_clean.c
-trigger.h
-trigger.c
-triggerpull.h
-triggerpull.c
-trynpbg1.c
-trysyslog.c
-conf-cc
-conf-ld
-home.sh
-home+df.sh
-proc.sh
-proc+df.sh
-binm1.sh
-binm2.sh
-binm3.sh
-binm1+df.sh
-binm2+df.sh
-binm3+df.sh
-find-systype.sh
-make-compile.sh
-make-load.sh
-make-makelib.sh
-trycpp.c
-warn-auto.sh
-auto-str.c
-auto-int.c
-auto-int8.c
-auto-gid.c
-auto-uid.c
-hier.c
-install.c
-instcheck.c
-install-big.c
-alloc.3
-alloc.h
-alloc.c
-alloc_re.c
-case.3
-case.h
-case_diffb.c
-case_diffs.c
-case_lowerb.c
-case_lowers.c
-case_starts.c
-cdb.3
-cdb.h
-cdb_hash.c
-cdb_seek.c
-cdb_unpack.c
-cdbmake.h
-cdbmake_add.c
-cdbmake_hash.c
-cdbmake_pack.c
-cdbmss.h
-cdbmss.c
-coe.3
-coe.h
-coe.c
-fd.h
-fd_copy.3
-fd_copy.c
-fd_move.3
-fd_move.c
-fifo_make.3
-fifo.h
-fifo.c
-trymkffo.c
-fork.h1
-fork.h2
-tryvfork.c
-now.3
-now.h
-now.c
-open.h
-open_append.c
-open_excl.c
-open_read.c
-open_trunc.c
-open_write.c
+received.h
+remoteinfo.c
+remoteinfo.h
+ripemd.c
+ripemd.h
+ripemd.o
+scan.h
+scan_8long.c
+scan_ulong.c
 seek.h
 seek_cur.c
 seek_end.c
 seek_set.c
 seek_trunc.c
-conf-qmail
-auto_qmail.h
-qmail.h
-qmail.c
-gen_alloc.h
-gen_allocdefs.h
-stralloc.3
-stralloc.h
-stralloc_eady.c
-stralloc_pend.c
-stralloc_copy.c
-stralloc_opyb.c
-stralloc_opys.c
-stralloc_cat.c
-stralloc_catb.c
-stralloc_cats.c
-stralloc_arts.c
-strerr.h
-strerr_sys.c
-strerr_die.c
-substdio.h
-substdio.c
-substdi.c
-substdo.c
-substdio_copy.c
-subfd.h
-subfderr.c
-subfdouts.c
-subfdout.c
-subfdins.c
-subfdin.c
-readwrite.h
-exit.h
-timeoutconn.h
-timeoutconn.c
-timeoutread.h
-timeoutread.c
-timeoutwrite.h
-timeoutwrite.c
-remoteinfo.h
-remoteinfo.c
-uint32.h1
-uint32.h2
-tryulong32.c
-wait.3
-wait.h
-wait_pid.c
-wait_nohang.c
-trywaitp.c
+select.h1
+select.h2
+sendmail.c
+sgetopt.3
+sgetopt.c
+sgetopt.h
+sha1.c
+sha1.h
+sha1.o
 sig.h
 sig_alarm.c
 sig_block.c
+sig_bug.c
 sig_catch.c
-sig_pause.c
-sig_pipe.c
 sig_child.c
-sig_term.c
 sig_hup.c
 sig_misc.c
-sig_bug.c
-trysgact.c
-trysgprm.c
-env.3
-env.h
-env.c
-envread.c
-byte.h
-byte_chr.c
-byte_copy.c
-byte_cr.c
-byte_diff.c
-byte_rchr.c
-byte_zero.c
+sig_pause.c
+sig_pipe.c
+sig_term.c
+slurpclose.c
+slurpclose.h
+spawn.c
+splogger.8
+splogger.c
 str.h
 str_chr.c
 str_cpy.c
+str_cpyb.c
 str_diff.c
 str_diffn.c
 str_len.c
 str_rchr.c
 str_start.c
-lock.h
-lock_ex.c
-lock_exnb.c
-lock_un.c
-tryflock.c
-getln.3
-getln.h
-getln.c
-getln2.3
-getln2.c
-sgetopt.3
-sgetopt.h
-sgetopt.c
+stralloc.3
+stralloc.h
+stralloc_arts.c
+stralloc_cat.c
+stralloc_catb.c
+stralloc_cats.c
+stralloc_copy.c
+stralloc_eady.c
+stralloc_opyb.c
+stralloc_opys.c
+stralloc_pend.c
+strerr.h
+strerr_die.c
+strerr_sys.c
+strsalloc.c
+strsalloc.h
+subfd.h
+subfderr.c
+subfdin.c
+subfdins.c
+subfdout.c
+subfdouts.c
 subgetopt.3
-subgetopt.h
 subgetopt.c
-error.3
-error_str.3
-error_temp.3
-error.h
-error.c
-error_str.c
-error_temp.c
-fmt.h
-fmt_str.c
-fmt_strn.c
-fmt_uint.c
-fmt_uint0.c
-fmt_ulong.c
-scan.h
-scan_ulong.c
-scan_8long.c
-slurpclose.h
-slurpclose.c
-quote.h
-quote.c
-hfield.h
-hfield.c
-headerbody.h
-headerbody.c
-token822.h
+subgetopt.h
+substdi.c
+substdio.c
+substdio.h
+substdio_copy.c
+substdo.c
+tcp-env.1
+tcp-env.c
+tcp-environ.5
+tcpto.c
+tcpto.h
+tcpto_clean.c
+timeoutconn.c
+timeoutconn.h
+timeoutread.c
+timeoutread.h
+timeoutwrite.c
+timeoutwrite.h
 token822.c
-control.h
-control.c
-datetime.3
-datetime.h
-datetime.c
-datetime_un.c
-prioq.h
-prioq.c
-date822fmt.h
-date822fmt.c
-dns.h
-dns.c
+token822.h
+trigger.c
+trigger.h
+triggerpull.c
+triggerpull.h
+trycpp.c
+trydrent.c
+tryflock.c
 trylsock.c
+trymkffo.c
+trynpbg1.c
 tryrsolv.c
-ip.h
-ip.c
-ipalloc.h
-ipalloc.c
-select.h1
-select.h2
+trysalen.c
+trysgact.c
+trysgprm.c
+tryshsgr.c
 trysysel.c
-ndelay.h
-ndelay.c
-ndelay_off.c
-direntry.3
-direntry.h1
-direntry.h2
-trydrent.c
-prot.h
-prot.c
-chkshsgr.c
+trysyslog.c
+tryulong32.c
+tryvfork.c
+trywaitp.c
+typesx.h
+uint32.h1
+uint32.h2
+wait.3
+wait.h
+wait_nohang.c
+wait_pid.c
+warn-auto.sh
 warn-shsgr
-tryshsgr.c
-ipme.h
-ipme.c
-trysalen.c
-maildir.5
-maildir.h
-maildir.c
-tcp-environ.5
-constmap.h
-constmap.c
diff -urN qmail-1.03-vanilla/fmt_str.c qmail-1.03-md24/fmt_str.c
--- qmail-1.03-vanilla/fmt_str.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/fmt_str.c	2007-07-19 20:56:22.000000000 +0200
@@ -6,7 +6,7 @@
   register unsigned int len;
   char ch;
   len = 0;
-  if (s) { while (ch = t[len]) s[len++] = ch; }
+  if (s) { while ((ch = t[len])) s[len++] = ch; }
   else while (t[len]) len++;
   return len;
 }
diff -urN qmail-1.03-vanilla/forward.c qmail-1.03-md24/forward.c
--- qmail-1.03-vanilla/forward.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/forward.c	2007-07-19 20:56:22.000000000 +0200
@@ -26,7 +26,7 @@
 
 char num[FMT_ULONG];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -57,4 +57,5 @@
   qqx = qmail_close(&qqt);
   if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
   strerr_die2x(0,"forward: qp ",num);
+  return 0;
 }
diff -urN qmail-1.03-vanilla/hfield.c qmail-1.03-md24/hfield.c
--- qmail-1.03-vanilla/hfield.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/hfield.c	2007-07-19 20:56:22.000000000 +0200
@@ -41,7 +41,7 @@
  int i;
  char ch;
 
- for (i = 0;ch = t[i];++i)
+ for (i = 0;(ch = t[i]);++i)
   {
    if (i >= len) return 0;
    if (ch != s[i])
@@ -67,7 +67,7 @@
  int i;
  char *t;
 
- for (i = 1;t = hname[i];++i)
+ for (i = 1;(t = hname[i]);++i)
    if (hmatch(s,len,t))
      return i;
  return 0;
diff -urN qmail-1.03-vanilla/hier.c qmail-1.03-md24/hier.c
--- qmail-1.03-vanilla/hier.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/hier.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,4 @@
+#include "install.h"
 #include "auto_qmail.h"
 #include "auto_split.h"
 #include "auto_uids.h"
@@ -55,6 +56,8 @@
   d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700);
 
   dsplit("queue/mess",auto_uidq,0750);
+  dsplit("queue/todo",auto_uidq,0750);
+  dsplit("queue/intd",auto_uidq,0700);
   dsplit("queue/info",auto_uids,0700);
   dsplit("queue/local",auto_uids,0700);
   dsplit("queue/remote",auto_uids,0700);
@@ -145,108 +148,57 @@
   c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644);
 }
diff -urN qmail-1.03-vanilla/hmac.h qmail-1.03-md24/hmac.h
--- qmail-1.03-vanilla/hmac.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/hmac.h	2007-07-19 22:20:45.000000000 +0200
@@ -0,0 +1,4 @@
+
+extern void hmac_md5();
+extern void hmac_ripemd();
+extern void hmac_sha1();
diff -urN qmail-1.03-vanilla/hmac_md5.c qmail-1.03-md24/hmac_md5.c
--- qmail-1.03-vanilla/hmac_md5.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/hmac_md5.c	2007-07-19 22:08:00.000000000 +0200
@@ -0,0 +1,56 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "typesx.h"
+#include "md5.h"
+
+#define PAD 64
+#define TK  16
+
+void hmac_md5(text, key, digest)
+	u8 *text;   /* pointer to data stream */
+	u8 *key;    /* pointer to authentication key */
+	u8 *digest; /* caller digest to be filled in */
+{
+	MD5_CTX ctx;
+	u8 k_ipad[PAD+1]; /* inner padding - key XORd with ipad */
+	u8 k_opad[PAD+1]; /* outer padding - key XORd with opad */
+	u8 tk[TK];
+	size_t text_len=strlen(text);
+	size_t key_len=strlen(key);
+	int i;
+
+	if (key_len > PAD) {
+		MD5_CTX tctx;
+		MD5_Init(&tctx);
+		MD5_Update(&tctx, key, key_len);
+		MD5_Final(tk, &tctx);
+		key = tk;
+		key_len = TK;
+	}
+
+	/* start out by storing key in pads */
+	memset(k_ipad, 0, PAD);
+	memcpy(k_ipad, key, key_len);
+	memset(k_opad, 0, PAD);
+	memcpy(k_opad, key, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i=0; i<PAD; i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	/* perform inner MD5 */
+	MD5_Init(&ctx);                   /* init ctx for 1st pass */
+	MD5_Update(&ctx, k_ipad, PAD);    /* start with inner pad */
+	MD5_Update(&ctx, text, text_len); /* then text of datagram */
+	MD5_Final(digest, &ctx);          /* finish up 1st pass */
+
+	/* perform outer MD5 */
+	MD5_Init(&ctx);                   /* init ctx for 2nd pass */
+	MD5_Update(&ctx, k_opad, PAD);    /* start with outer pad */
+	MD5_Update(&ctx, digest, TK);     /* then results of 1st hash */
+	MD5_Final(digest, &ctx);          /* finish up 2nd pass */
+}
diff -urN qmail-1.03-vanilla/hmac_ripemd.c qmail-1.03-md24/hmac_ripemd.c
--- qmail-1.03-vanilla/hmac_ripemd.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/hmac_ripemd.c	2007-07-19 22:08:05.000000000 +0200
@@ -0,0 +1,56 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "typesx.h"
+#include "ripemd.h"
+
+#define PAD 64
+#define TK  20
+
+void hmac_ripemd(text, key, digest)
+	u8 *text;   /* pointer to data stream */
+	u8 *key;    /* pointer to authentication key */
+	u8 *digest; /* caller digest to be filled in */
+{
+	RIPEMD160_CTX ctx;
+	u8 k_ipad[PAD+1]; /* inner padding - key XORd with ipad */
+	u8 k_opad[PAD+1]; /* outer padding - key XORd with opad */
+	u8 tk[TK];
+	size_t text_len=strlen(text);
+	size_t key_len=strlen(key);
+	int i;
+
+	if (key_len > PAD) {
+		RIPEMD160_CTX tctx;
+		RIPEMD160_Init(&tctx);
+		RIPEMD160_Update(&tctx, key, key_len);
+		RIPEMD160_Final(tk, &tctx);
+		key = tk;
+		key_len = TK;
+	}
+
+	/* start out by storing key in pads */
+	memset(k_ipad, 0, PAD);
+	memcpy(k_ipad, key, key_len);
+	memset(k_opad, 0, PAD);
+	memcpy(k_opad, key, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i=0; i<PAD; i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	/* perform inner RIPEMD160 */
+	RIPEMD160_Init(&ctx);                   /* init ctx for 1st pass */
+	RIPEMD160_Update(&ctx, k_ipad, PAD);    /* start with inner pad */
+	RIPEMD160_Update(&ctx, text, text_len); /* then text of datagram */
+	RIPEMD160_Final(digest, &ctx);          /* finish up 1st pass */
+
+	/* perform outer RIPEMD160 */
+	RIPEMD160_Init(&ctx);                   /* init ctx for 2nd pass */
+	RIPEMD160_Update(&ctx, k_opad, PAD);    /* start with outer pad */
+	RIPEMD160_Update(&ctx, digest, TK);     /* then results of 1st hash */
+	RIPEMD160_Final(digest, &ctx);          /* finish up 2nd pass */
+}
diff -urN qmail-1.03-vanilla/hmac_sha1.c qmail-1.03-md24/hmac_sha1.c
--- qmail-1.03-vanilla/hmac_sha1.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/hmac_sha1.c	2007-07-19 22:30:54.000000000 +0200
@@ -0,0 +1,56 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "typesx.h"
+#include "sha1.h"
+
+#define PAD 64
+#define TK  20
+
+void hmac_sha1(text, key, digest)
+	u8 *text;   /* pointer to data stream */
+	u8 *key;    /* pointer to authentication key */
+	u8 *digest; /* caller digest to be filled in */
+{
+	SHA1_CTX ctx;
+	u8 k_ipad[PAD+1]; /* inner padding - key XORd with ipad */
+	u8 k_opad[PAD+1]; /* outer padding - key XORd with opad */
+	u8 tk[TK];
+	size_t text_len=strlen(text);
+	size_t key_len=strlen(key);
+	int i;
+
+	if (key_len > PAD) {
+		SHA1_CTX tctx;
+		SHA1_Init(&tctx);
+		SHA1_Update(&tctx, key, key_len);
+		SHA1_Final(tk, &tctx);
+		key = tk;
+		key_len = TK;
+	}
+
+	/* start out by storing key in pads */
+	memset(k_ipad, 0, PAD);
+	memcpy(k_ipad, key, key_len);
+	memset(k_opad, 0, PAD);
+	memcpy(k_opad, key, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i=0; i<PAD; i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	/* perform inner SHA1 */
+	SHA1_Init(&ctx);                   /* init ctx for 1st pass */
+	SHA1_Update(&ctx, k_ipad, PAD);    /* start with inner pad */
+	SHA1_Update(&ctx, text, text_len); /* then text of datagram */
+	SHA1_Final(digest, &ctx);          /* finish up 1st pass */
+
+	/* perform outer SHA1 */
+	SHA1_Init(&ctx);                   /* init ctx for 2nd pass */
+	SHA1_Update(&ctx, k_opad, PAD);    /* start with outer pad */
+	SHA1_Update(&ctx, digest, TK);     /* then results of 1st hash */
+	SHA1_Final(digest, &ctx);          /* finish up 2nd pass */
+}
diff -urN qmail-1.03-vanilla/hmac_sha1.h qmail-1.03-md24/hmac_sha1.h
--- qmail-1.03-vanilla/hmac_sha1.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/hmac_sha1.h	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,2 @@
+
+extern void hmac_sha1();
diff -urN qmail-1.03-vanilla/hostname.c qmail-1.03-md24/hostname.c
--- qmail-1.03-vanilla/hostname.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/hostname.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "subfd.h"
 #include "readwrite.h"
@@ -5,7 +7,7 @@
 
 char host[256];
 
-void main()
+int main()
 {
  host[0] = 0; /* sigh */
  gethostname(host,sizeof(host));
diff -urN qmail-1.03-vanilla/idedit.c qmail-1.03-md24/idedit.c
--- qmail-1.03-vanilla/idedit.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/idedit.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,5 @@
 #include <sys/types.h>
+#include <unistd.h>
 #include <pwd.h>
 #include <grp.h>
 #include "readwrite.h"
@@ -9,6 +10,7 @@
 #include "open.h"
 #include "seek.h"
 #include "fork.h"
+#include "wait.h"
 
 #define FATAL "idedit: fatal: "
 #define WARNING "idedit: warning: "
@@ -120,7 +122,7 @@
     strerr_die3x(111,FATAL,"excessively large gid for ",group);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/install-big.c qmail-1.03-md24/install-big.c
--- qmail-1.03-vanilla/install-big.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/install-big.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,4 @@
+#include "install.h"
 #include "auto_qmail.h"
 #include "auto_split.h"
 #include "auto_uids.h"
@@ -145,115 +146,63 @@
   c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"bin","dot-forward",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"man/man1","dot-forward.1",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","dot-forward.0",auto_uido,auto_gidq,0644);
 
   d(auto_qmail,"doc/fastforward",auto_uido,auto_gidq,0755);
 
@@ -275,11 +224,4 @@
   c(auto_qmail,"man/man1","setmaillist.1",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man1","newinclude.1",auto_uido,auto_gidq,0644);
 
-  c(auto_qmail,"man/cat1","fastforward.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","printforward.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","setforward.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","newaliases.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","printmaillist.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","setmaillist.0",auto_uido,auto_gidq,0644);
-  c(auto_qmail,"man/cat1","newinclude.0",auto_uido,auto_gidq,0644);
 }
diff -urN qmail-1.03-vanilla/install.c qmail-1.03-md24/install.c
--- qmail-1.03-vanilla/install.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/install.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,9 +1,11 @@
+#include "install.h"
 #include "substdio.h"
 #include "strerr.h"
 #include "error.h"
 #include "open.h"
 #include "readwrite.h"
 #include "exit.h"
+#include "fifo.h"
 
 extern void hier();
 
@@ -152,7 +154,7 @@
     strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",file,": ");
 }
 
-void main()
+int main()
 {
   fdsourcedir = open_read(".");
   if (fdsourcedir == -1)
diff -urN qmail-1.03-vanilla/install.h qmail-1.03-md24/install.h
--- qmail-1.03-vanilla/install.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/install.h	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,11 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern void hier();
+extern void perm();
+extern void h();
+extern void d();
+extern void p();
+extern void c();
+extern void z();
diff -urN qmail-1.03-vanilla/instcheck.c qmail-1.03-md24/instcheck.c
--- qmail-1.03-vanilla/instcheck.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/instcheck.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "strerr.h"
 #include "error.h"
 #include "readwrite.h"
@@ -101,7 +102,7 @@
   perm("",home,"/",file,S_IFREG,uid,gid,mode);
 }
 
-void main()
+int main()
 {
   hier();
   _exit(0);
diff -urN qmail-1.03-vanilla/ipalloc.h qmail-1.03-md24/ipalloc.h
--- qmail-1.03-vanilla/ipalloc.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/ipalloc.h	2007-07-19 20:56:22.000000000 +0200
@@ -2,8 +2,7 @@
 #define IPALLOC_H
 
 #include "ip.h"
-
-struct ip_mx { struct ip_address ip; int pref; } ;
+struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
 
 #include "gen_alloc.h"
 
diff -urN qmail-1.03-vanilla/ip.c qmail-1.03-md24/ip.c
--- qmail-1.03-vanilla/ip.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/ip.c	2007-07-19 20:56:22.000000000 +0200
@@ -8,7 +8,7 @@
 {
   unsigned int len;
   unsigned int i;
- 
+
   len = 0;
   i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
   i = fmt_str(s,"."); len += i; if (s) s += i;
@@ -27,7 +27,7 @@
   unsigned int i;
   unsigned int len;
   unsigned long u;
- 
+
   len = 0;
   i = scan_ulong(s,&u); if (!i) return 0; ip->d[0] = u; s += i; len += i;
   if (*s != '.') return 0; ++s; ++len;
@@ -44,7 +44,7 @@
 struct ip_address *ip;
 {
   unsigned int len;
- 
+
   if (*s != '[') return 0;
   len = ip_scan(s + 1,ip);
   if (!len) return 0;
diff -urN qmail-1.03-vanilla/ipme.c qmail-1.03-md24/ipme.c
--- qmail-1.03-vanilla/ipme.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/ipme.c	2007-07-19 20:56:22.000000000 +0200
@@ -4,6 +4,7 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
+#include <unistd.h>
 #include <netinet/in.h>
 #ifndef SIOCGIFCONF /* whatever works */
 #include <sys/sockio.h>
@@ -46,6 +47,11 @@
   ipme.len = 0;
   ix.pref = 0;
  
+  /* 0.0.0.0 is a special address which always refers to 
+   * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a.
+  */
+  byte_copy(&ix.ip,4,"\0\0\0\0");
+  if (!ipalloc_append(&ipme,&ix)) { return 0; }
   if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1;
  
   len = 256;
diff -urN qmail-1.03-vanilla/ipmeprint.c qmail-1.03-md24/ipmeprint.c
--- qmail-1.03-vanilla/ipmeprint.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/ipmeprint.c	2007-07-19 20:56:22.000000000 +0200
@@ -6,7 +6,7 @@
 
 char temp[IPFMT];
 
-void main()
+int main()
 {
  int j;
  switch(ipme_init())
diff -urN qmail-1.03-vanilla/maildir2mbox.c qmail-1.03-md24/maildir2mbox.c
--- qmail-1.03-vanilla/maildir2mbox.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/maildir2mbox.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "readwrite.h"
 #include "prioq.h"
 #include "env.h"
@@ -33,7 +35,7 @@
 
 void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
 
-void main()
+int main()
 {
  substdio ssin;
  substdio ssout;
diff -urN qmail-1.03-vanilla/maildir.c qmail-1.03-md24/maildir.c
--- qmail-1.03-vanilla/maildir.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/maildir.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "prioq.h"
 #include "env.h"
 #include "stralloc.h"
@@ -36,8 +37,7 @@
  dir = opendir("tmp");
  if (!dir) return;
 
- while (d = readdir(dir))
-  {
+ while ((d = readdir(dir))) {
    if (d->d_name[0] == '.') continue;
    if (!stralloc_copys(tmpname,"tmp/")) break;
    if (!stralloc_cats(tmpname,d->d_name)) break;
@@ -45,7 +45,7 @@
    if (stat(tmpname->s,&st) == 0)
      if (time > st.st_atime + 129600)
        unlink(tmpname->s);
-  }
+ }
  closedir(dir);
 }
 
@@ -65,8 +65,7 @@
  if (!dir)
    STRERR_SYS3(-1,maildir_scan_err,"unable to scan $MAILDIR/",subdir,": ")
 
- while (d = readdir(dir))
-  {
+ while ((d = readdir(dir))) {
    if (d->d_name[0] == '.') continue;
    pos = filenames->len;
    if (!stralloc_cats(filenames,subdir)) break;
@@ -80,7 +79,7 @@
        pe.id = pos;
        if (!prioq_insert(pq,&pe)) break;
       }
-  }
+ }
 
  closedir(dir);
  if (d) STRERR_SYS3(-1,maildir_scan_err,"unable to read $MAILDIR/",subdir,": ")
@@ -95,7 +94,6 @@
 {
  struct prioq_elt pe;
  datetime_sec time;
- int r;
 
  if (!stralloc_copys(filenames,"")) return 0;
  while (prioq_min(pq,&pe)) prioq_delmin(pq);
diff -urN qmail-1.03-vanilla/maildirmake.c qmail-1.03-md24/maildirmake.c
--- qmail-1.03-vanilla/maildirmake.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/maildirmake.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,9 +1,11 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "strerr.h"
 #include "exit.h"
 
 #define FATAL "maildirmake: fatal: "
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/maildirwatch.c qmail-1.03-md24/maildirwatch.c
--- qmail-1.03-vanilla/maildirwatch.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/maildirwatch.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "getln.h"
 #include "substdio.h"
 #include "subfd.h"
@@ -58,7 +60,7 @@
 char inbuf[SUBSTDIO_INSIZE];
 substdio ssin;
 
-void main()
+int main()
 {
  struct prioq_elt pe;
  int fd;
diff -urN qmail-1.03-vanilla/Makefile qmail-1.03-md24/Makefile
--- qmail-1.03-vanilla/Makefile	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/Makefile	2007-08-12 10:09:00.000000000 +0200
@@ -408,10 +408,10 @@
 
 dnscname: \
 load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
-substdio.a error.a str.a fs.a dns.lib socket.lib
+substdio.a error.a str.a fs.a strsalloc.o dns.lib socket.lib
 	./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
-	socket.lib`
+	alloc.a substdio.a error.a str.a fs.a strsalloc.o \
+	`cat dns.lib` `cat socket.lib`
 
 dnscname.o: \
 compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \
@@ -424,10 +424,10 @@
 
 dnsfq: \
 load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
-substdio.a error.a str.a fs.a dns.lib socket.lib
+substdio.a error.a str.a fs.a strsalloc.o dns.lib socket.lib
 	./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
-	socket.lib`
+	alloc.a substdio.a error.a str.a fs.a strsalloc.o `cat dns.lib` \
+	`cat socket.lib`
 
 dnsfq.o: \
 compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
@@ -436,10 +436,10 @@
 
 dnsip: \
 load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
-substdio.a error.a str.a fs.a dns.lib socket.lib
+substdio.a error.a str.a fs.a strsalloc.o dns.lib socket.lib
 	./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
-	socket.lib`
+	alloc.a substdio.a error.a str.a fs.a strsalloc.o \
+	`cat dns.lib` `cat socket.lib`
 
 dnsip.o: \
 compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
@@ -448,10 +448,10 @@
 
 dnsmxip: \
 load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o now.o stralloc.a alloc.a \
-substdio.a error.a str.a fs.a dns.lib socket.lib
+substdio.a error.a str.a fs.a strsalloc.o dns.lib socket.lib
 	./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \
-	stralloc.a alloc.a substdio.a error.a str.a fs.a  `cat \
-	dns.lib` `cat socket.lib`
+	stralloc.a alloc.a substdio.a error.a str.a fs.a strsalloc.o \
+	`cat dns.lib` `cat socket.lib`
 
 dnsmxip.o: \
 compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \
@@ -461,10 +461,10 @@
 
 dnsptr: \
 load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
-substdio.a error.a str.a fs.a dns.lib socket.lib
+substdio.a error.a str.a fs.a strsalloc.o dns.lib socket.lib
 	./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
-	socket.lib`
+	alloc.a substdio.a error.a str.a fs.a strsalloc.o \
+	`cat dns.lib` `cat socket.lib`
 
 dnsptr.o: \
 compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
@@ -1269,9 +1269,11 @@
 qmail-pop3d: \
 load qmail-pop3d.o commands.o case.a timeoutread.o timeoutwrite.o \
 maildir.o prioq.o now.o env.a strerr.a sig.a open.a getln.a \
+out_log.o control.o base64.o auto_qmail.o \
 stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib
 	./load qmail-pop3d commands.o case.a timeoutread.o \
 	timeoutwrite.o maildir.o prioq.o now.o env.a strerr.a sig.a \
+	out_log.o control.o base64.o auto_qmail.o \
 	open.a getln.a stralloc.a alloc.a substdio.a error.a str.a \
 	fs.a  `cat socket.lib`
 
@@ -1288,11 +1290,13 @@
 
 qmail-popup: \
 load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \
+control.o out_log.o qmail-sasl.o base64.o env.a getln.a open.a \
 case.a fd.a sig.a wait.a stralloc.a alloc.a substdio.a error.a str.a \
-fs.a socket.lib
-	./load qmail-popup commands.o timeoutread.o timeoutwrite.o \
-	now.o case.a fd.a sig.a wait.a stralloc.a alloc.a \
-	substdio.a error.a str.a fs.a  `cat socket.lib`
+fs.a socket.lib auto_qmail.o sha1.o hmac_sha1.o ucspitls.o
+	./load qmail-popup commands.o timeoutread.o timeoutwrite.o ucspitls.o \
+	control.o out_log.o qmail-sasl.o base64.o env.a getln.a open.a \
+	now.o case.a fd.a sig.a wait.a stralloc.a alloc.a auto_qmail.o \
+	substdio.a error.a str.a fs.a sha1.o hmac_sha1.o `cat socket.lib`
 
 qmail-popup.0: \
 qmail-popup.8
@@ -1368,13 +1372,15 @@
 
 qmail-qmtpd: \
 load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \
+realrcptto.o auto_break.o auto_usera.o \
 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \
 getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \
-str.a fs.a auto_qmail.o
+str.a fs.a auto_qmail.o 
 	./load qmail-qmtpd rcpthosts.o control.o constmap.o \
+	realrcptto.o auto_break.o auto_usera.o \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a open.a getln.a sig.a case.a env.a stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a auto_qmail.o 
+	alloc.a substdio.a error.a str.a fs.a auto_qmail.o
 
 qmail-qmtpd.0: \
 qmail-qmtpd.8
@@ -1421,11 +1427,13 @@
 qmail-queue: \
 load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \
 datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
-str.a fs.a auto_qmail.o auto_split.o auto_uids.o
+str.a fs.a auto_qmail.o auto_split.o auto_uids.o control.o stralloc.a \
+constmap.o open.a getln.a case.a alloc.a
 	./load qmail-queue triggerpull.o fmtqfn.o now.o \
 	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
 	alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
-	auto_split.o auto_uids.o 
+	auto_split.o auto_uids.o control.o stralloc.a constmap.o \
+	open.a getln.a case.a alloc.a
 
 qmail-queue.0: \
 qmail-queue.8
@@ -1439,35 +1447,38 @@
 
 qmail-remote: \
 load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
-timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
+timeoutconn.o tcpto.o now.o dns.o ip.o strsalloc.o ipalloc.o ipme.o quote.o \
 ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
+md5.o sha1.o ripemd.o hmac_ripemd.o hmac_md5.o hmac_sha1.o base64.o \
 substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib
 	./load qmail-remote control.o constmap.o timeoutread.o \
-	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \
-	ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
+	timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o strsalloc.o \
+	md5.o sha1.o ripemd.o hmac_ripemd.o hmac_md5.o hmac_sha1.o \
+	ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a base64.o \
 	lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \
-	str.a fs.a auto_qmail.o  `cat dns.lib` `cat socket.lib`
+	str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
 
 qmail-remote.0: \
 qmail-remote.8
 	nroff -man qmail-remote.8 > qmail-remote.0
 
 qmail-remote.o: \
-compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h \
+compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.h control.h \
 subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \
-alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \
-gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \
-tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
+alloc.h quote.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h ipme.h ip.h \
+ipalloc.h strsalloc.h gen_alloc.h gen_allocdefs.h str.h now.h datetime.h \
+exit.h constmap.h tcpto.h readwrite.h timeoutconn.h timeoutread.h \
+timeoutwrite.h
 	./compile qmail-remote.c
 
 qmail-rspawn: \
 load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \
 seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \
-auto_qmail.o auto_uids.o auto_spawn.o
+auto_qmail.o auto_uids.o auto_spawn.o fmt_ulong.o
 	./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \
 	sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \
 	substdio.a error.a str.a auto_qmail.o auto_uids.o \
-	auto_spawn.o 
+	auto_spawn.o fmt_ulong.o
 
 qmail-rspawn.0: \
 qmail-rspawn.8
@@ -1483,12 +1494,12 @@
 trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \
 datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \
 lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
-auto_split.o
+auto_split.o env.a
 	./load qmail-send qsutil.o control.o constmap.o newfield.o \
 	prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \
 	qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \
 	wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \
-	substdio.a error.a str.a fs.a auto_qmail.o auto_split.o 
+	substdio.a error.a str.a fs.a auto_qmail.o auto_split.o env.a
 
 qmail-send.0: \
 qmail-send.8
@@ -1533,15 +1544,21 @@
 
 qmail-smtpd: \
 load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
+out_log.o timeoutconn.o qmail-p0f.o qmail-sasl.o base64.o dns.o \
+realrcptto.o strsalloc.o ndelay.a auto_break.o auto_usera.o \
+sha1.o hmac_sha1.o ucspitls.o \
 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
 open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
 fs.a auto_qmail.o socket.lib
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
+	out_log.o timeoutconn.o qmail-p0f.o qmail-sasl.o base64.o \
+	dns.o realrcptto.o strsalloc.o ndelay.a auto_break.o \
+	auto_usera.o sha1.o hmac_sha1.o ucspitls.o  \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
+	alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \
 	socket.lib`
 
 qmail-smtpd.0: \
@@ -1914,10 +1931,10 @@
 str.a: \
 makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_chr.o \
 str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_diff.o byte_copy.o \
-byte_cr.o byte_zero.o
+byte_cr.o byte_zero.o str_cpyb.o
 	./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o \
 	str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o \
-	byte_diff.o byte_copy.o byte_cr.o byte_zero.o
+	byte_diff.o byte_copy.o byte_cr.o byte_zero.o str_cpyb.o
 
 str_chr.o: \
 compile str_chr.c str.h
@@ -2066,9 +2083,10 @@
 
 tcp-env: \
 load tcp-env.o dns.o remoteinfo.o timeoutread.o timeoutwrite.o \
+strsalloc.o \
 timeoutconn.o ip.o ipalloc.o case.a ndelay.a sig.a env.a getopt.a \
 stralloc.a alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
-	./load tcp-env dns.o remoteinfo.o timeoutread.o \
+	./load tcp-env dns.o remoteinfo.o timeoutread.o strsalloc.o \
 	timeoutwrite.o timeoutconn.o ip.o ipalloc.o case.a ndelay.a \
 	sig.a env.a getopt.a stralloc.a alloc.a substdio.a error.a \
 	str.a fs.a  `cat dns.lib` `cat socket.lib`
@@ -2139,3 +2157,60 @@
 wait_pid.o: \
 compile wait_pid.c error.h haswaitp.h
 	./compile wait_pid.c
+
+# new targets
+strsalloc.o: \
+compile strsalloc.c
+	./compile strsalloc.c
+
+str_cpyb.o: \
+compile str_cpyb.c
+	./compile str_cpyb.c
+
+md5.o: \
+compile md5.c md5.h
+	./compile md5.c
+
+sha1.o: \
+compile sha1.c sha1.h
+	./compile sha1.c
+
+ripemd.o: \
+compile ripemd.c ripemd.h
+	./compile ripemd.c
+
+hmac_ripemd.o: \
+compile hmac_ripemd.c hmac.h
+	./compile hmac_ripemd.c
+
+hmac_md5.o: \
+compile hmac_md5.c hmac.h
+	./compile hmac_md5.c
+
+hmac_sha1.o: \
+compile hmac_sha1.c hmac.h
+	./compile hmac_sha1.c
+
+base64.o: \
+compile base64.c base64.h
+	./compile base64.c
+
+out_log.o: \
+compile out_log.c out_log.h
+	./compile out_log.c
+
+qmail-sasl.o: \
+compile qmail-sasl.c qmail-sasl.h
+	./compile qmail-sasl.c
+
+realrcptto.o: \
+compile realrcptto.c
+	./compile realrcptto.c
+
+qmail-p0f.o: \
+compile qmail-p0f.c qmail-p0f.h
+	./compile qmail-p0f.c
+
+ucspitls.o: \
+compile ucspitls.c ucspitls.h
+	./compile ucspitls.c
diff -urN qmail-1.03-vanilla/md5.c qmail-1.03-md24/md5.c
--- qmail-1.03-vanilla/md5.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/md5.c	2006-09-12 19:51:33.000000000 +0200
@@ -0,0 +1,259 @@
+
+/**
+ * Copyright (C) 2005-2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Written by Solar Designer in 2001 and placed in the public domain.
+ * There's absolutely no warranty.
+ */
+
+#include "md5.h"
+
+/**
+ * MD5 Message-Digest Algorithm - rfc 1321
+ */
+
+#define F(x, y, z)	((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z)	((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z)	((x) ^ (y) ^ (z))
+#define I(x, y, z)	((y) ^ ((x) | ~(z)))
+#define STEP(f, a, b, c, d, x, t, s) \
+	(a) += f((b), (c), (d)) + (x) + (t); \
+	(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+	(a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures which tolerate unaligned
+ * memory accesses is just an optimization.  Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__vax__)
+#define SET(n) (*(u32 *)&ptr[(n) * 4])
+#define GET(n) SET(n)
+#else
+#define SET(n) \
+	(ctx->block[(n)] = \
+	(u32)ptr[(n) * 4] | \
+	((u32)ptr[(n) * 4 + 1] << 8) | \
+	((u32)ptr[(n) * 4 + 2] << 16) | \
+	((u32)ptr[(n) * 4 + 3] << 24))
+#define GET(n) (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters.  There're no alignment requirements.
+ */
+static void *body(MD5_CTX *ctx, void *data, u32 size)
+{
+	u8 *ptr=data;
+	u32 a,b,c,d;
+	u32 saved_a, saved_b, saved_c, saved_d;
+
+	ptr = data;
+
+	a = ctx->a;
+	b = ctx->b;
+	c = ctx->c;
+	d = ctx->d;
+
+	do {
+		saved_a = a;
+		saved_b = b;
+		saved_c = c;
+		saved_d = d;
+/* Round 1 */
+		STEP(F, a, b, c, d, SET(0),  0xd76aa478, 7)
+		STEP(F, d, a, b, c, SET(1),  0xe8c7b756, 12)
+		STEP(F, c, d, a, b, SET(2),  0x242070db, 17)
+		STEP(F, b, c, d, a, SET(3),  0xc1bdceee, 22)
+		STEP(F, a, b, c, d, SET(4),  0xf57c0faf, 7)
+		STEP(F, d, a, b, c, SET(5),  0x4787c62a, 12)
+		STEP(F, c, d, a, b, SET(6),  0xa8304613, 17)
+		STEP(F, b, c, d, a, SET(7),  0xfd469501, 22)
+		STEP(F, a, b, c, d, SET(8),  0x698098d8, 7)
+		STEP(F, d, a, b, c, SET(9),  0x8b44f7af, 12)
+		STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+		STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+		STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+		STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+		STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+		STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+/* Round 2 */
+		STEP(G, a, b, c, d, GET(1),  0xf61e2562, 5)
+		STEP(G, d, a, b, c, GET(6),  0xc040b340, 9)
+		STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+		STEP(G, b, c, d, a, GET(0),  0xe9b6c7aa, 20)
+		STEP(G, a, b, c, d, GET(5),  0xd62f105d, 5)
+		STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+		STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+		STEP(G, b, c, d, a, GET(4),  0xe7d3fbc8, 20)
+		STEP(G, a, b, c, d, GET(9),  0x21e1cde6, 5)
+		STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+		STEP(G, c, d, a, b, GET(3),  0xf4d50d87, 14)
+		STEP(G, b, c, d, a, GET(8),  0x455a14ed, 20)
+		STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+		STEP(G, d, a, b, c, GET(2),  0xfcefa3f8, 9)
+		STEP(G, c, d, a, b, GET(7),  0x676f02d9, 14)
+		STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+/* Round 3 */
+		STEP(H, a, b, c, d, GET(5),  0xfffa3942, 4)
+		STEP(H, d, a, b, c, GET(8),  0x8771f681, 11)
+		STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+		STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
+		STEP(H, a, b, c, d, GET(1),  0xa4beea44, 4)
+		STEP(H, d, a, b, c, GET(4),  0x4bdecfa9, 11)
+		STEP(H, c, d, a, b, GET(7),  0xf6bb4b60, 16)
+		STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
+		STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+		STEP(H, d, a, b, c, GET(0),  0xeaa127fa, 11)
+		STEP(H, c, d, a, b, GET(3),  0xd4ef3085, 16)
+		STEP(H, b, c, d, a, GET(6),  0x04881d05, 23)
+		STEP(H, a, b, c, d, GET(9),  0xd9d4d039, 4)
+		STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
+		STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+		STEP(H, b, c, d, a, GET(2),  0xc4ac5665, 23)
+/* Round 4 */
+		STEP(I, a, b, c, d, GET(0),  0xf4292244, 6)
+		STEP(I, d, a, b, c, GET(7),  0x432aff97, 10)
+		STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+		STEP(I, b, c, d, a, GET(5),  0xfc93a039, 21)
+		STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+		STEP(I, d, a, b, c, GET(3),  0x8f0ccc92, 10)
+		STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+		STEP(I, b, c, d, a, GET(1),  0x85845dd1, 21)
+		STEP(I, a, b, c, d, GET(8),  0x6fa87e4f, 6)
+		STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+		STEP(I, c, d, a, b, GET(6),  0xa3014314, 15)
+		STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+		STEP(I, a, b, c, d, GET(4),  0xf7537e82, 6)
+		STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+		STEP(I, c, d, a, b, GET(2),  0x2ad7d2bb, 15)
+		STEP(I, b, c, d, a, GET(9),  0xeb86d391, 21)
+
+		a += saved_a;
+		b += saved_b;
+		c += saved_c;
+		d += saved_d;
+
+		ptr += 64;
+	} while (size -= 64);
+
+	ctx->a = a; ctx->b = b; ctx->c = c; ctx->d = d;
+
+	return ptr;
+}
+
+void MD5_Init(MD5_CTX *ctx)
+{
+	ctx->a = 0x67452301;
+	ctx->b = 0xefcdab89;
+	ctx->c = 0x98badcfe;
+	ctx->d = 0x10325476;
+
+	ctx->lo = 0; ctx->hi = 0;
+}
+
+void MD5_Update(MD5_CTX *ctx, void *data, u32 size)
+{
+	u32 saved_lo, used, free;
+
+	saved_lo = ctx->lo;
+	if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
+		ctx->hi++;
+	ctx->hi += size >> 29;
+
+	used = saved_lo & 0x3f;
+
+	if (used) {
+		free = 64 - used;
+
+		if (size < free) {
+			memcpy(&ctx->buffer[used], data, size);
+			return;
+		}
+
+		memcpy(&ctx->buffer[used], data, free);
+		data = (u8 *)data + free;
+		size -= free;
+		body(ctx, ctx->buffer, 64);
+	}
+
+	if (size >= 64) {
+		data = body(ctx, data, size & ~(u32)0x3f);
+		size &= 0x3f;
+	}
+
+	memcpy(ctx->buffer, data, size);
+}
+
+void MD5_Final(u8 *result, MD5_CTX *ctx)
+{
+	u32 used, free;
+
+	used = ctx->lo & 0x3f;
+	ctx->buffer[used++] = 0x80;
+	free = 64 - used;
+
+	if (free < 8) {
+		memset(&ctx->buffer[used], 0, free);
+		body(ctx, ctx->buffer, 64);
+		used = 0;
+		free = 64;
+	}
+
+	memset(&ctx->buffer[used], 0, free - 8);
+
+	ctx->lo <<= 3;
+	ctx->buffer[56] = ctx->lo;
+	ctx->buffer[57] = ctx->lo >> 8;
+	ctx->buffer[58] = ctx->lo >> 16;
+	ctx->buffer[59] = ctx->lo >> 24;
+	ctx->buffer[60] = ctx->hi;
+	ctx->buffer[61] = ctx->hi >> 8;
+	ctx->buffer[62] = ctx->hi >> 16;
+	ctx->buffer[63] = ctx->hi >> 24;
+
+	body(ctx, ctx->buffer, 64);
+
+	result[0]  = ctx->a;
+	result[1]  = ctx->a >> 8;
+	result[2]  = ctx->a >> 16;
+	result[3]  = ctx->a >> 24;
+	result[4]  = ctx->b;
+	result[5]  = ctx->b >> 8;
+	result[6]  = ctx->b >> 16;
+	result[7]  = ctx->b >> 24;
+	result[8]  = ctx->c;
+	result[9]  = ctx->c >> 8;
+	result[10] = ctx->c >> 16;
+	result[11] = ctx->c >> 24;
+	result[12] = ctx->d;
+	result[13] = ctx->d >> 8;
+	result[14] = ctx->d >> 16;
+	result[15] = ctx->d >> 24;
+
+	memset(ctx, 0, sizeof(ctx));
+}
+#undef F
+#undef G
+#undef H
+#undef I
+#undef SET
+#undef GET
+#undef STEP
diff -urN qmail-1.03-vanilla/md5.h qmail-1.03-md24/md5.h
--- qmail-1.03-vanilla/md5.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/md5.h	2007-07-19 22:06:45.000000000 +0200
@@ -0,0 +1,38 @@
+#ifndef SW_MD5_H
+#define SW_MD5_H
+
+/**
+ * Copyright (C) 2005-2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Written by Solar Designer in 2001 and placed in the public domain.
+ * There's absolutely no warranty.
+ */
+
+#include "typesx.h"
+#include <string.h>
+
+typedef struct {
+	u32 lo, hi;
+	u32 a,b,c,d;
+	u32 block[16];
+	u8 buffer[64];
+} MD5_CTX;
+
+extern void MD5_Init(MD5_CTX *ctx);
+extern void MD5_Update(MD5_CTX *ctx, void *data, u32 size);
+extern void MD5_Final(u8 *result, MD5_CTX *ctx);
+
+#endif
diff -urN qmail-1.03-vanilla/newfield.c qmail-1.03-md24/newfield.c
--- qmail-1.03-vanilla/newfield.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/newfield.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "fmt.h"
 #include "datetime.h"
 #include "stralloc.h"
diff -urN qmail-1.03-vanilla/out_log.c qmail-1.03-md24/out_log.c
--- qmail-1.03-vanilla/out_log.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/out_log.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,72 @@
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "substdio.h"
+#include "now.h"
+#include "fmt.h"
+#include "out_log.h"
+
+void Out(char *s)
+{ substdio_puts(&ssout,s); return;}
+
+void Outn(char *s, int len)
+{ substdio_put(&ssout,s,len); return; }
+
+void Log(char *s)
+{ if (ctl_log_out > 0) if (sserr.fd>0) substdio_puts(&sserr,s); return; }
+
+void Logn(char *s, int len)
+{ if (ctl_log_out > 0) if (sserr.fd>0) substdio_put(&sserr,s,len); return; }
+
+void out(char *s) { Out(s); Log(s); return; }
+void outn(char *s, int len) { Outn(s,len); Logn(s,len); return; }
+
+int flush(void)
+{
+  int r1,r2;
+  r1=substdio_flush(&ssout);
+  r2=substdio_flush(&sserr);
+  if (r1 == -1 || r2 == -1) return -1;
+  return 0;
+}
+
+void doname(void)
+{
+  static int pid=0;
+  char pidstr[FMT_ULONG];
+
+  if (!pid) { pid=getpid(); }
+  pidstr[fmt_ulong(pidstr,pid)] = 0;
+  Log(name);Log(": pid ");Log(pidstr);Log(" ");
+  return;
+}
+
+void doserv(void)
+{
+  doname(); Log("S: ");
+  return;
+}
+
+void doeol(void)
+{
+  Out("\r"); out("\n");
+  return;
+}
+
+void out_err(char *s)
+{
+  doserv(); out(s); doeol(); flush();
+  return;
+}
+
+void dounique(void)
+{
+  char *s=unique;
+
+  s += fmt_uint(s,getpid());
+  s += fmt_str(s,".");
+  s += fmt_ulong(s,(unsigned long) now());
+  s += fmt_str(s,"@");
+  s = 0;
+  return;
+}
diff -urN qmail-1.03-vanilla/out_log.h qmail-1.03-md24/out_log.h
--- qmail-1.03-vanilla/out_log.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/out_log.h	2007-07-28 15:54:54.000000000 +0200
@@ -0,0 +1,37 @@
+#include "substdio.h"
+#include "fmt.h"
+
+#define VERSION "md24"
+
+/* have to be provided by qmail-smtpd, qmail-popup and qmail-remote */
+extern char *name;
+extern char unique[];
+extern char ssinbuf[];
+extern char ssoutbuf[];
+extern char sserrbuf[];
+
+extern int ctl_log_out;
+
+extern substdio ssin;
+extern substdio ssout;
+extern substdio sserr;
+
+/* overview:
+ * Log()   = append to logfile
+ * Out()   = append to server output
+ * out()   = append to logfile+server output
+ * flush() = flush logfile+server buffers
+ */
+extern void Log(char *s);
+extern void Out(char *s);
+extern void out(char *s);
+extern void Logn(char *s, int len);
+extern void Outn(char *s, int len);
+extern void outn(char *s, int len);
+
+extern int  flush(void);
+extern void doname(void);     /* logs 'name of prog' */
+extern void doserv(void);     /* logs 'name: S: ' */
+extern void doeol(void);      /* logs a <NL>, but write <CRNL> to stdout */
+extern void dounique(void);   /* fill unique */
+extern void out_err(char *s); /* name: S: *s EOL + flush() */
diff -urN qmail-1.03-vanilla/predate.c qmail-1.03-md24/predate.c
--- qmail-1.03-vanilla/predate.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/predate.c	2007-07-19 20:56:22.000000000 +0200
@@ -10,6 +10,7 @@
 #include "subfd.h"
 #include "readwrite.h"
 #include "exit.h"
+#include "sig.h"
 
 #define FATAL "predate: fatal: "
 
@@ -20,7 +21,7 @@
 char num[FMT_ULONG];
 char outbuf[1024];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/preline.1 qmail-1.03-md24/preline.1
--- qmail-1.03-vanilla/preline.1	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/preline.1	2007-07-19 20:56:22.000000000 +0200
@@ -52,6 +52,9 @@
 Do not include the
 .B Return-Path
 line.
+.TP
+.B \-p
+Ignore a possible errno = EPIPE!
 .SH "SEE ALSO"
 mbox(5),
 qmail-command(8)
diff -urN qmail-1.03-vanilla/preline.c qmail-1.03-md24/preline.c
--- qmail-1.03-vanilla/preline.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/preline.c	2007-07-19 20:56:22.000000000 +0200
@@ -20,13 +20,14 @@
 int flagufline = 1; char *ufline;
 int flagrpline = 1; char *rpline;
 int flagdtline = 1; char *dtline;
+int flagpipe = 0;
 
 char outbuf[SUBSTDIO_OUTSIZE];
 char inbuf[SUBSTDIO_INSIZE];
 substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,sizeof outbuf);
 substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -41,7 +42,7 @@
   if (!(rpline = env_get("RPLINE"))) die_usage();
   if (!(dtline = env_get("DTLINE"))) die_usage();
  
-  while ((opt = getopt(argc,argv,"frdFRD")) != opteof)
+  while ((opt = getopt(argc,argv,"frdFRDp")) != opteof)
     switch(opt) {
       case 'f': flagufline = 0; break;
       case 'r': flagrpline = 0; break;
@@ -49,6 +50,7 @@
       case 'F': flagufline = 1; break;
       case 'R': flagrpline = 1; break;
       case 'D': flagdtline = 1; break;
+      case 'p': flagpipe = 1; break;
       default: die_usage();
     }
   argc -= optind;
@@ -77,8 +79,10 @@
   if (flagufline) substdio_bputs(&ssout,ufline);
   if (flagrpline) substdio_bputs(&ssout,rpline);
   if (flagdtline) substdio_bputs(&ssout,dtline);
-  if (substdio_copy(&ssout,&ssin) != 0)
-    strerr_die2sys(111,FATAL,"unable to copy input: ");
+  if (substdio_copy(&ssout,&ssin) != 0) {
+    if (errno!=error_pipe || !flagpipe)
+      strerr_die2sys(111,FATAL,"unable to copy input: ");
+  }
   substdio_flush(&ssout);
   close(1);
  
diff -urN qmail-1.03-vanilla/prot.c qmail-1.03-md24/prot.c
--- qmail-1.03-vanilla/prot.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/prot.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,16 +1,20 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
 #include "hasshsgr.h"
 #include "prot.h"
 
 /* XXX: there are more portability problems here waiting to leap out at me */
 
-int prot_gid(gid) int gid;
+int prot_gid(int gid)
 {
 #ifdef HASSHORTSETGROUPS
   short x[2];
   x[0] = gid; x[1] = 73; /* catch errors */
   if (setgroups(1,x) == -1) return -1;
 #else
-  if (setgroups(1,&gid) == -1) return -1;
+  const gid_t G=gid; /* fix warning of gcc */
+  if (setgroups(1,&G) == -1) return -1;
 #endif
   return setgid(gid); /* _should_ be redundant, but on some systems it isn't */
 }
diff -urN qmail-1.03-vanilla/qbiff.c qmail-1.03-md24/qbiff.c
--- qmail-1.03-vanilla/qbiff.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qbiff.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include <utmp.h>
 #ifndef UTMP_FILE
 #ifdef _PATH_UTMP
@@ -50,7 +51,7 @@
 }
 void finishheader() { ; }
 
-void main()
+int main()
 {
  char *user;
  char *sender;
diff -urN qmail-1.03-vanilla/qmail.c qmail-1.03-md24/qmail.c
--- qmail-1.03-vanilla/qmail.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "readwrite.h"
 #include "wait.h"
@@ -6,8 +8,17 @@
 #include "fd.h"
 #include "qmail.h"
 #include "auto_qmail.h"
+#include "env.h"
 
-static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
+static char *binqqargs[2] = { 0, 0 } ;
+
+static void setup_qqargs()
+{
+  if(!binqqargs[0])
+    binqqargs[0] = env_get("QMAILQUEUE");
+  if(!binqqargs[0])
+    binqqargs[0] = "bin/qmail-queue";
+}
 
 int qmail_open(qq)
 struct qmail *qq;
@@ -15,6 +26,8 @@
   int pim[2];
   int pie[2];
 
+  setup_qqargs();
+
   if (pipe(pim) == -1) return -1;
   if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
  
@@ -88,38 +101,38 @@
   close(qq->fde);
 
   if (wait_pid(&wstat,qq->pid) != qq->pid)
-    return "Zqq waitpid surprise (#4.3.0)";
+    return "Z4.3.0 qq waitpid surprise";
   if (wait_crashed(wstat))
-    return "Zqq crashed (#4.3.0)";
+    return "Z4.3.0 qq crashed";
   exitcode = wait_exitcode(wstat);
 
   switch(exitcode) {
     case 115: /* compatibility */
-    case 11: return "Denvelope address too long for qq (#5.1.3)";
-    case 31: return "Dmail server permanently rejected message (#5.3.0)";
-    case 51: return "Zqq out of memory (#4.3.0)";
-    case 52: return "Zqq timeout (#4.3.0)";
-    case 53: return "Zqq write error or disk full (#4.3.0)";
+    case 11: return "D5.1.3 envelope address too long for qq";
+    case 31: return "D5.3.0 mail server permanently rejected message";
+    case 51: return "Z4.3.0 qq out of memory";
+    case 52: return "Z4.3.0 qq timeout";
+    case 53: return "Z4.3.0 qq write error or disk full";
     case 0: if (!qq->flagerr) return ""; /* fall through */
-    case 54: return "Zqq read error (#4.3.0)";
-    case 55: return "Zqq unable to read configuration (#4.3.0)";
-    case 56: return "Zqq trouble making network connection (#4.3.0)";
-    case 61: return "Zqq trouble in home directory (#4.3.0)";
+    case 54: return "Z4.3.0 qq read error";
+    case 55: return "Z4.3.0 qq unable to read configuration";
+    case 56: return "Z4.3.0 qq trouble making network connection";
+    case 61: return "Z4.3.0 qq trouble in home directory";
     case 63:
     case 64:
     case 65:
     case 66:
-    case 62: return "Zqq trouble creating files in queue (#4.3.0)";
-    case 71: return "Zmail server temporarily rejected message (#4.3.0)";
-    case 72: return "Zconnection to mail server timed out (#4.4.1)";
-    case 73: return "Zconnection to mail server rejected (#4.4.1)";
-    case 74: return "Zcommunication with mail server failed (#4.4.2)";
+    case 62: return "Z4.3.0 qq trouble creating files in queue";
+    case 71: return "Z4.3.0 mail server temporarily rejected message";
+    case 72: return "Z4.4.1 connection to mail server timed out";
+    case 73: return "Z4.4.1 connection to mail server rejected";
+    case 74: return "Z4.4.2 communication with mail server failed";
     case 91: /* fall through */
-    case 81: return "Zqq internal bug (#4.3.0)";
-    case 120: return "Zunable to exec qq (#4.3.0)";
+    case 81: return "Z4.3.0 qq internal bug";
+    case 120:return "Z4.3.0 unable to exec qq";
     default:
       if ((exitcode >= 11) && (exitcode <= 40))
-	return "Dqq permanent problem (#5.3.0)";
-      return "Zqq temporary problem (#4.3.0)";
+        return "D5.3.0 qq permanent problem";
+      return "Z4.3.0 qq temporary problem";
   }
 }
diff -urN qmail-1.03-vanilla/qmail-clean.c qmail-1.03-md24/qmail-clean.c
--- qmail-1.03-vanilla/qmail-clean.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-clean.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "readwrite.h"
 #include "sig.h"
 #include "now.h"
@@ -31,7 +32,7 @@
  time = now();
  dir = opendir("pid");
  if (!dir) return;
- while (d = readdir(dir))
+ while ((d = readdir(dir)))
   {
    if (str_equal(d->d_name,".")) continue;
    if (str_equal(d->d_name,"..")) continue;
@@ -49,7 +50,7 @@
 
 void respond(s) char *s; { if (substdio_putflush(subfdoutsmall,s,1) == -1) _exit(100); }
 
-void main()
+int main()
 {
  int i;
  int match;
@@ -73,22 +74,26 @@
    if (line.len < 7) { respond("x"); continue; }
    if (line.len > 100) { respond("x"); continue; }
    if (line.s[line.len - 1]) { respond("x"); continue; } /* impossible */
-   for (i = 5;i < line.len - 1;++i)
+   for (i = line.len - 2;i > 4;--i)
+    {
+     if (line.s[i] == '/') break;
      if ((unsigned char) (line.s[i] - '0') > 9)
       { respond("x"); continue; }
-   if (!scan_ulong(line.s + 5,&id)) { respond("x"); continue; }
+    }
+   if (line.s[i] == '/')
+     if (!scan_ulong(line.s + i + 1,&id)) { respond("x"); continue; }
    if (byte_equal(line.s,5,"foop/"))
     {
 #define U(prefix,flag) fmtqfn(fnbuf,prefix,id,flag); \
 if (unlink(fnbuf) == -1) if (errno != error_noent) { respond("!"); continue; }
-     U("intd/",0)
+     U("intd/",1)
      U("mess/",1)
      respond("+");
     }
    else if (byte_equal(line.s,4,"todo/"))
     {
-     U("intd/",0)
-     U("todo/",0)
+     U("intd/",1)
+     U("todo/",1)
      respond("+");
     }
    else
diff -urN qmail-1.03-vanilla/qmail-control.9 qmail-1.03-md24/qmail-control.9
--- qmail-1.03-vanilla/qmail-control.9	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-control.9	2007-07-19 20:56:22.000000000 +0200
@@ -21,6 +21,7 @@
 Comments are allowed
 in
 .IR badmailfrom ,
+.IR badmailto ,
 .IR locals ,
 .IR percenthack ,
 .IR qmqpservers ,
@@ -30,6 +31,13 @@
 .IR virtualdomains .
 Trailing spaces and tabs are allowed in any control file.
 
+Regular expressions are allowed in
+.IR badmailfrom
+and
+.IR badmailto .
+This can be used for filtering out some spam, see
+QMAIL/doc/README.qregex for more details!
+
 The following table lists all control files
 other than
 .IR me .
@@ -40,7 +48,9 @@
 .ta 5c 10c
 control	default	used by
 
-.I badmailfrom	\fR(none)	\fRqmail-smtpd
+.I badmailfrom	\fR(none)	\fRqmail-smtpd ($BADMAILFROM)
+.I badmailto	\fR(none)	\fRqmail-smtpd ($BADMAILTO)
+.I badhelo	\fR(none)	\fRqmail-smtpd ($BADHELO)
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
 .I bouncehost	\fIme	\fRqmail-send
 .I concurrencylocal	\fR10	\fRqmail-send
@@ -55,7 +65,9 @@
 .I idhost	\fIme	\fRqmail-inject
 .I localiphost	\fIme	\fRqmail-smtpd
 .I locals	\fIme	\fRqmail-send
+.I mfcheck	\fR(none)	\fRqmail-smtpd ($MFCHECK)
 .I morercpthosts	\fR(none)	\fRqmail-smtpd
+.I outgoingip	\fR0.0.0.0	\fRqmail-remote
 .I percenthack	\fR(none)	\fRqmail-send
 .I plusdomain	\fIme	\fRqmail-inject
 .I qmqpservers	\fR(none)	\fRqmail-qmqpc
@@ -63,10 +75,25 @@
 .I rcpthosts	\fR(none)	\fRqmail-smtpd
 .I smtpgreeting	\fIme	\fRqmail-smtpd
 .I smtproutes	\fR(none)	\fRqmail-remote
+.I spfbehavior	\fR0	\fRqmail-smtpd
+.I spfexp	\fR(default)	\fRqmail-smtpd
+.I spfguess	\fR(none)	\fRqmail-smtpd
+.I spfrules	\fR(none)	\fRqmail-smtpd
 .I timeoutconnect	\fR60	\fRqmail-remote
 .I timeoutremote	\fR1200	\fRqmail-remote
 .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
+.I tarpitcount	\fR(none)	\fRqmail-smtpd ($TARPITCOUNT)
+.I tarpitdelay	\fR(none)	\fRqmail-smtpd ($TARPITDELAY)
 .I virtualdomains	\fR(none)	\fRqmail-send
+
+.I clientcert.pem	\fR(none)	\fRqmail-remote
+.I tlsclientciphers	\fR(none)	\fRqmail-remote
+.I tlshosts/FQDN.pem	\fR(none)	\fRqmail-remote
+.I clientca.pem	\fR(none)	\fRqmail-smtpd
+.I rsa512.pem	\fR(none)	\fRqmail-smtpd
+.I servercert.pem	\fR(none)	\fRqmail-smtpd
+.I tlsclients	\fR(none)	\fRqmail-smtpd
+.I tlsserverciphers	\fR(none)	\fRqmail-smtpd
 .fi
 .RE
 .SH "SEE ALSO"
diff -urN qmail-1.03-vanilla/qmail-getpw.c qmail-1.03-md24/qmail-getpw.c
--- qmail-1.03-vanilla/qmail-getpw.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-getpw.c	2007-07-19 20:56:22.000000000 +0200
@@ -36,17 +36,19 @@
 	errno = 0;
 	pw = getpwnam(username);
 	if (errno == error_txtbsy) _exit(QLX_SYS);
-	if (pw)
-	  if (pw->pw_uid)
+	if (pw) {
+	  if (pw->pw_uid) {
 	    if (stat(pw->pw_dir,&st) == 0) {
 	      if (st.st_uid == pw->pw_uid) {
 		dash = "";
 		if (*extension) { ++extension; dash = "-"; }
 		return 1;
 	      }
-	    }
-	    else
+	    } else {
 	      if (error_temp(errno)) _exit(QLX_NFS);
+	    }
+	  }
+	}
       }
     if (extension == local) return 0;
     --extension;
@@ -55,7 +57,7 @@
 
 char num[FMT_ULONG];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/qmail-inject.c qmail-1.03-md24/qmail-inject.c
--- qmail-1.03-vanilla/qmail-inject.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-inject.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "sig.h"
 #include "substdio.h"
 #include "stralloc.h"
@@ -55,7 +57,7 @@
 
 void put(s,len) char *s; int len;
 { if (flagqueue) qmail_put(&qqt,s,len); else substdio_put(subfdout,s,len); }
-void puts(s) char *s; { put(s,str_len(s)); }
+void out(s) char *s; { put(s,str_len(s)); }
 
 void perm() { _exit(100); }
 void temp() { _exit(111); }
@@ -94,8 +96,7 @@
 
  if (!flagqueue) substdio_flush(subfdout);
 
- if (flagqueue)
-  {
+ if (flagqueue) {
    int i;
 
    if (!stralloc_0(&sender)) die_nomem();
@@ -106,7 +107,7 @@
      if (!stralloc_0(&reciplist.sa[i])) die_nomem();
      qmail_to(&qqt,reciplist.sa[i].s);
     }
-   if (flagrh)
+   if (flagrh) {
      if (flagresent)
        for (i = 0;i < hrrlist.len;++i)
 	{
@@ -119,23 +120,24 @@
          if (!stralloc_0(&hrlist.sa[i])) die_nomem();
 	 qmail_to(&qqt,hrlist.sa[i].s);
 	}
+   }
 
    qqx = qmail_close(&qqt);
-   if (*qqx)
+   if (*qqx) {
      if (*qqx == 'D') {
        substdio_puts(subfderr,"qmail-inject: fatal: ");
        substdio_puts(subfderr,qqx + 1);
        substdio_puts(subfderr,"\n");
        substdio_flush(subfderr);
        perm();
-     }
-     else {
+     } else {
        substdio_puts(subfderr,"qmail-inject: fatal: ");
        substdio_puts(subfderr,qqx + 1);
        substdio_puts(subfderr,"\n");
        substdio_flush(subfderr);
        temp();
      }
+   }
   }
 
  _exit(0);
@@ -477,12 +479,11 @@
 void dodefaultreturnpath()
 {
  if (!stralloc_copys(&hackedruser,mailruser)) die_nomem();
- if (flaghackmess)
-  {
+ if (flaghackmess) {
    if (!stralloc_cats(&hackedruser,"-")) die_nomem();
-   if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) starttime))) die_nomem();
+   if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long)starttime))) die_nomem();
    if (!stralloc_cats(&hackedruser,".")) die_nomem();
-   if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+   if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long)getpid()))) die_nomem();
   }
  if (flaghackrecip)
    if (!stralloc_cats(&hackedruser,"-")) die_nomem();
@@ -549,16 +550,16 @@
 
   if (i == tocclist.len) return;
 
-  puts("Mail-Followup-To: ");
+  out("Mail-Followup-To: ");
   i = tocclist.len;
   while (i--) {
     if (!stralloc_copy(&sa,&tocclist.sa[i])) die_nomem();
     if (!stralloc_0(&sa)) die_nomem();
     if (!quote2(&sa2,sa.s)) die_nomem();
     put(sa2.s,sa2.len);
-    if (i) puts(",\n  ");
+    if (i) out(",\n  ");
   }
-  puts("\n");
+  out("\n");
 }
 
 void finishheader()
@@ -580,9 +581,9 @@
    if (!stralloc_0(&sa)) die_nomem();
    if (!quote2(&sa2,sa.s)) die_nomem();
 
-   puts("Return-Path: <");
+   out("Return-Path: <");
    put(sa2.s,sa2.len);
-   puts(">\n");
+   out(">\n");
   }
 
  /* could check at this point whether there are any recipients */
@@ -594,23 +595,23 @@
    if (!htypeseen[H_R_DATE])
     {
      if (!newfield_datemake(starttime)) die_nomem();
-     puts("Resent-");
+     out("Resent-");
      put(newfield_date.s,newfield_date.len);
     }
    if (!htypeseen[H_R_MESSAGEID])
     {
      if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
-     puts("Resent-");
+     out("Resent-");
      put(newfield_msgid.s,newfield_msgid.len);
     }
    if (!htypeseen[H_R_FROM])
     {
      defaultfrommake();
-     puts("Resent-");
+     out("Resent-");
      put(defaultfrom.s,defaultfrom.len);
     }
    if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC])
-     puts("Resent-Cc: recipient list not shown: ;\n");
+     out("Resent-Cc: recipient list not shown: ;\n");
   }
  else
   {
@@ -630,7 +631,7 @@
      put(defaultfrom.s,defaultfrom.len);
     }
    if (!htypeseen[H_TO] && !htypeseen[H_CC])
-     puts("Cc: recipient list not shown: ;\n");
+     out("Cc: recipient list not shown: ;\n");
    finishmft();
   }
 
@@ -682,7 +683,7 @@
 #define RECIP_HEADER 3
 #define RECIP_AH 4
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -770,4 +771,5 @@
  if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1)
    die_read();
  exitnicely();
+ return 0; /* gcc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-local.c qmail-1.03-md24/qmail-local.c
--- qmail-1.03-vanilla/qmail-local.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-local.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include "readwrite.h"
 #include "sig.h"
 #include "env.h"
@@ -29,17 +31,18 @@
 #include "gfrom.h"
 #include "auto_patrn.h"
 
-void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
+char *overquota = "5.2.2 Recipient's mailbox is full, message returned to sender.";
 
-void temp_nomem() { strerr_die1x(111,"Out of memory. (#4.3.0)"); }
-void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (#4.3.0)"); }
-void temp_childcrashed() { strerr_die1x(111,"Aack, child crashed. (#4.3.0)"); }
-void temp_fork() { strerr_die3x(111,"Unable to fork: ",error_str(errno),". (#4.3.0)"); }
-void temp_read() { strerr_die3x(111,"Unable to read message: ",error_str(errno),". (#4.3.0)"); }
-void temp_slowlock()
-{ strerr_die1x(111,"File has been locked for 30 seconds straight. (#4.3.0)"); }
-void temp_qmail(fn) char *fn;
-{ strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.3.0)"); }
+void usage()
+{ strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
+
+void temp_nomem() { strerr_die1x(111,"4.3.0 out of memory"); }
+void temp_rewind() { strerr_die1x(111,"4.3.0 unable to rewind message"); }
+void temp_childcrashed() { strerr_die1x(111,"4.3.0 aack, child crashed"); }
+void temp_fork() { strerr_die2x(111,"4.3.0 unable to fork: ",error_str(errno)); }
+void temp_read() { strerr_die2x(111,"4.3.0 unable to read message: ",error_str(errno)); }
+void temp_slowlock() { strerr_die1x(111,"4.3.0 file has been locked for 30 seconds straight"); }
+void temp_qmail(fn) char *fn; { strerr_die4x(111,"4.3.0 unable to open ",fn,": ",error_str(errno)); }
 
 int flagdoit;
 int flag99;
@@ -110,7 +113,10 @@
 
  alarm(86400);
  fd = open_excl(fntmptph);
- if (fd == -1) _exit(1);
+ if (fd == -1) {
+   if (errno == error_dquot) _exit(5);
+   else _exit(1);
+ }
 
  substdio_fdbuf(&ss,read,0,buf,sizeof(buf));
  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
@@ -128,10 +134,17 @@
  if (close(fd) == -1) goto fail; /* NFS dorks */
 
  if (link(fntmptph,fnnewtph) == -1) goto fail;
+ if ((fd = open(fnnewtph, O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd) < 0)
+   goto fail;
    /* if it was error_exist, almost certainly successful; i hate NFS */
  tryunlinktmp(); _exit(0);
 
- fail: tryunlinktmp(); _exit(1);
+ fail: 
+   if (errno == error_dquot) {
+     tryunlinktmp(); _exit(5);
+   } else {
+     tryunlinktmp(); _exit(1);
+   }
 }
 
 /* end child process */
@@ -159,10 +172,11 @@
  switch(wait_exitcode(wstat))
   {
    case 0: break;
-   case 2: strerr_die1x(111,"Unable to chdir to maildir. (#4.2.1)");
-   case 3: strerr_die1x(111,"Timeout on maildir delivery. (#4.3.0)");
-   case 4: strerr_die1x(111,"Unable to read message. (#4.3.0)");
-   default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)");
+   case 2: strerr_die1x(111,"4.2.1 unable to chdir to maildir");
+   case 3: strerr_die1x(111,"4.3.0 timeout on maildir delivery");
+   case 4: strerr_die1x(111,"4.3.0 unable to read message");
+   case 5: strerr_die1x(100,overquota);
+   default: strerr_die1x(111,"4.3.0 temporary error on maildir delivery");
   }
 }
 
@@ -180,7 +194,7 @@
 
  fd = open_append(fn);
  if (fd == -1)
-   strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.2.1)");
+   strerr_die4x(111,"4.2.1 unable to open ",fn,": ",error_str(errno));
 
  sig_alarmcatch(temp_slowlock);
  alarm(30);
@@ -200,7 +214,7 @@
   {
    if (getln(&ss,&messline,&match,'\n') != 0) 
     {
-     strerr_warn3("Unable to read message: ",error_str(errno),". (#4.3.0)",0);
+     strerr_warn2("4.3.0 unable to read message: ",error_str(errno),0);
      if (flaglocked) seek_trunc(fd,pos); close(fd);
      _exit(111);
     }
@@ -221,7 +235,12 @@
  return;
 
  writeerrs:
- strerr_warn5("Unable to write ",fn,": ",error_str(errno),". (#4.3.0)",0);
+ if (errno == error_dquot) { 
+   if (flaglocked) seek_trunc(fd,pos);
+   close(fd);
+   strerr_die1x(100,overquota);
+ } else
+ strerr_warn4("4.3.0 unable to write ",fn,": ",error_str(errno),0);
  if (flaglocked) seek_trunc(fd,pos);
  close(fd);
  _exit(111);
@@ -244,7 +263,7 @@
      args[0] = "/bin/sh"; args[1] = "-c"; args[2] = prog; args[3] = 0;
      sig_pipedefault();
      execv(*args,args);
-     strerr_die3x(111,"Unable to run /bin/sh: ",error_str(errno),". (#4.3.0)");
+     strerr_die2x(111,"4.3.0 unable to run /bin/sh: ",error_str(errno));
   }
 
  wait_pid(&wstat,child);
@@ -304,7 +323,7 @@
      break;
    if (messline.len == dtline.len)
      if (!str_diffn(messline.s,dtline.s,dtline.len))
-       strerr_die1x(100,"This message is looping: it already has my Delivered-To line. (#5.4.6)");
+       strerr_die1x(100,"5.4.6 this message is looping: it already has my Delivered-To line");
   }
 }
 
@@ -313,14 +332,16 @@
  struct stat st;
 
  if (stat(".",&st) == -1)
-   strerr_die3x(111,"Unable to stat home directory: ",error_str(errno),". (#4.3.0)");
+   strerr_die2x(111,"4.3.0 unable to stat home directory: ",error_str(errno));
  if (st.st_mode & auto_patrn)
-   strerr_die1x(111,"Uh-oh: home directory is writable. (#4.7.0)");
- if (st.st_mode & 01000)
-   if (flagdoit)
-     strerr_die1x(111,"Home directory is sticky: user is editing his .qmail file. (#4.2.1)");
-   else
+   strerr_die1x(111,"4.7.0 uh-oh: home directory is writable");
+ if (st.st_mode & 01000) {
+   if (flagdoit) {
+     strerr_die1x(111,"4.2.1 home directory is sticky: user is editing his .qmail file");
+   } else {
      strerr_warn1("Warning: home directory is sticky.",0);
+   }
+ }
 }
 
 int qmeox(dashowner)
@@ -360,7 +381,7 @@
   if (fstat(*fd,&st) == -1) temp_qmail(qme.s);
   if ((st.st_mode & S_IFMT) == S_IFREG) {
     if (st.st_mode & auto_patrn)
-      strerr_die1x(111,"Uh-oh: .qmail file is writable. (#4.7.0)");
+      strerr_die1x(111,"4.7.0 uh-oh: .qmail file is writable");
     *cutable = !!(st.st_mode & 0100);
     return 1;
   }
@@ -444,7 +465,7 @@
  substdio_putsflush(subfdoutsmall,"\n");
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -488,7 +509,7 @@
 
  if (homedir[0] != '/') usage();
  if (chdir(homedir) == -1)
-   strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno),". (#4.3.0)");
+   strerr_die4x(111,"4.3.0 unable to switch to ",homedir,": ",error_str(errno));
  checkhome();
 
  if (!env_put2("HOST",host)) temp_nomem();
@@ -586,7 +607,7 @@
  qmesearch(&fd,&flagforwardonly);
  if (fd == -1)
    if (*dash)
-     strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
+     strerr_die1x(100,"5.1.1 sorry, no mailbox here by that name");
 
  if (!stralloc_copys(&ueo,sender)) temp_nomem();
  if (str_diff(sender,""))
@@ -645,19 +666,20 @@
     {
      cmds.s[j] = 0;
      k = j;
-     while ((k > i) && (cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t'))
+     while ((k > i) && ((cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')))
        cmds.s[--k] = 0;
      switch(cmds.s[i])
       {
        case 0: /* k == i */
 	 if (i) break;
-         strerr_die1x(111,"Uh-oh: first line of .qmail file is blank. (#4.2.1)");
+         strerr_die1x(111,"4.2.1 uh-oh: first line of .qmail file is blank");
        case '#':
+       case ':':
          break;
        case '.':
        case '/':
 	 ++count_file;
-	 if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)");
+	 if (flagforwardonly) strerr_die1x(111,"4.7.0 uh-oh: .qmail has file delivery but has x bit set");
 	 if (cmds.s[k - 1] == '/')
            if (flagdoit) maildir(cmds.s + i);
            else sayit("maildir ",cmds.s + i,k - i);
@@ -667,10 +689,50 @@
          break;
        case '|':
 	 ++count_program;
-	 if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)");
+	 if (flagforwardonly) strerr_die1x(111,"4.7.0 uh-oh: .qmail has prog delivery but has x bit set");
          if (flagdoit) mailprogram(cmds.s + i + 1);
          else sayit("program ",cmds.s + i + 1,k - i - 1);
          break;
+       case '?':
+         ++i;
+         {
+           int l;
+           for (l = i;l < k;++l)
+             if (cmds.s[l] == ' ' || cmds.s[l] == '\t') {
+               cmds.s[l] = 0;
+               for (++l;l < k;++l)
+                 if (cmds.s[l] != ' ' && cmds.s[l] != '\t') {
+                   ++count_program;
+                   if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)");
+                   if (flagdoit) mailprogram(cmds.s + l);
+                   else sayit("program ",cmds.s + l,k - l);
+                   break;
+                 }
+               break;
+             }
+           if (l == k || flag99) {
+             flag99 = 0;
+             cmds.s[j] = '\n';
+             for (;j + 1 < cmds.len;++j)
+               if (cmds.s[j] == '\n' && cmds.s[j + 1] == ':') {
+                 j += 2;
+                 l = j;
+                 for (; j < cmds.len;++j) {
+                   if (cmds.s[j] == 0) break;
+                   if (cmds.s[j] == '\t') break;
+                   if (cmds.s[j] == '\n') break;
+                   if (cmds.s[j] == ' ') break;
+                 }
+                 if (!str_diffn(cmds.s + i,cmds.s + l,j - l)) {
+                   for (; j < cmds.len;++j)
+                     if (cmds.s[j] == '\n') break;
+                   break;
+                 }
+                 --j;
+               }
+           }
+         }
+         break;
        case '+':
 	 if (str_equal(cmds.s + i + 1,"list"))
 	   flagforwardonly = 1;
diff -urN qmail-1.03-vanilla/qmail-lspawn.c qmail-1.03-md24/qmail-lspawn.c
--- qmail-1.03-vanilla/qmail-lspawn.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-lspawn.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "fd.h"
 #include "wait.h"
 #include "prot.h"
@@ -13,6 +15,8 @@
 #include "auto_qmail.h"
 #include "auto_uids.h"
 #include "qlx.h"
+#include "byte.h"
+#include "open.h"
 
 char *aliasempty;
 
@@ -165,9 +169,8 @@
   }
 }
 
-int spawn(fdmess,fdout,s,r,at)
-int fdmess; int fdout;
-char *s; char *r; int at;
+int
+spawn(int fdmess, int fdout, unsigned long msgsize, char *s, char *r, int at)
 {
  int f;
 
diff -urN qmail-1.03-vanilla/qmail-newmrh.c qmail-1.03-md24/qmail-newmrh.c
--- qmail-1.03-vanilla/qmail-newmrh.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-newmrh.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,9 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "strerr.h"
 #include "stralloc.h"
 #include "substdio.h"
+#include "case.h"
 #include "getln.h"
 #include "exit.h"
 #include "readwrite.h"
@@ -29,7 +32,7 @@
 stralloc line = {0};
 int match;
 
-void main()
+int main()
 {
   umask(033);
   if (chdir(auto_qmail) == -1)
diff -urN qmail-1.03-vanilla/qmail-newu.c qmail-1.03-md24/qmail-newu.c
--- qmail-1.03-vanilla/qmail-newu.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-newu.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,9 +1,12 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "stralloc.h"
 #include "subfd.h"
 #include "getln.h"
 #include "substdio.h"
 #include "cdbmss.h"
 #include "exit.h"
+#include "byte.h"
 #include "readwrite.h"
 #include "open.h"
 #include "error.h"
@@ -68,7 +71,7 @@
 
 stralloc wildchars = {0};
 
-void main()
+int main()
 {
   int i;
   int numcolons;
diff -urN qmail-1.03-vanilla/qmail-p0f.c qmail-1.03-md24/qmail-p0f.c
--- qmail-1.03-vanilla/qmail-p0f.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/qmail-p0f.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,90 @@
+#include "qmail-p0f.h"
+
+char *p0fos, *p0fdetails, *p0flink;
+char p0fdistance;
+signed int p0fuptime;
+char p0ffw,p0fnat;
+
+void p0f_received(struct qmail *qqt, char *remoteip)
+{
+  char buf[FMT_ULONG];
+  if (!p0fos) return;
+  qmail_puts(qqt,"X-P0F-Info: ");
+  safeput(qqt,remoteip?remoteip:"unknown");
+  qmail_puts(qqt," is-a ");
+  if (p0ffw) qmail_puts(qqt,"firewalled ");
+  if (p0fnat) qmail_puts(qqt,"NATted ");
+  safeput(qqt,p0fos);
+  qmail_puts(qqt," [");
+  if (p0fdetails) {
+    int i;
+    for (i=0; p0fdetails[i]; ++i) {
+      if (p0fdetails[i]<' ') p0fdetails[i]='?';
+      if (p0fdetails[i]=='[') p0fdetails[i]='(';
+      if (p0fdetails[i]==']') p0fdetails[i]=')';
+    }
+  } else p0fdetails="unknown";
+  qmail_puts(qqt,p0fdetails);
+  qmail_puts(qqt,"]");
+  if (p0flink) {
+    qmail_puts(qqt,", link \"");
+    qmail_puts(qqt,p0flink);
+    qmail_puts(qqt,"\"");
+  }
+  if (p0fdistance) {
+    qmail_puts(qqt,", ");
+    qmail_put(qqt,buf,fmt_ulong(buf,p0fdistance));
+    qmail_puts(qqt," hops away");
+  }
+  if (p0fuptime>-1) {
+    qmail_puts(qqt,", uptime ");
+    qmail_put(qqt,buf,fmt_ulong(buf,p0fuptime));
+  }
+  qmail_puts(qqt,"\n");
+}
+
+/* xxx: prove this */
+void p0f_query(void)
+{
+  int sock;
+  struct sockaddr_un x;
+  struct p0f_query p;
+  struct p0f_response r;
+  char* tmp;
+
+  if (!ctl_p0fsock) return;
+
+  p0fos=p0fdetails=0;
+  p0fdistance=p0ffw=p0fnat=0;
+  p0fuptime=0;
+
+  if (strlen(ctl_p0fsock)+1>sizeof(x.sun_path)) return;
+
+  p.magic=QUERY_MAGIC;
+  p.id=getpid();
+  p.src_ad=(tmp=env_get("TCPREMOTEIP"))?inet_addr(tmp):-1;
+  p.dst_ad=(tmp=env_get("TCPLOCALIP"))?inet_addr(tmp):-1;
+  p.src_port=atoi((tmp=env_get("TCPREMOTEPORT"))?tmp:"0");
+  p.dst_port=atoi((tmp=env_get("TCPLOCALPORT"))?tmp:"0");
+  if (p.src_ad==-1 || p.dst_ad==-1 || !p.src_port || !p.dst_port) return;
+
+  sock=socket(PF_UNIX,SOCK_STREAM,0);
+  if (sock == -1) return;
+  x.sun_family=AF_UNIX;
+  str_copy(x.sun_path, ctl_p0fsock);
+  if (connect(sock,(struct sockaddr*)&x,sizeof(x))) {close(sock);return;}
+  if (write(sock,&p,sizeof(p)) != sizeof(p)) {close(sock);return;}
+  if (read(sock,&r,sizeof(r)) != sizeof(r)) {close(sock);return;}
+  close(sock);
+  if (r.magic != QUERY_MAGIC) return;
+  if (r.type == RESP_BADQUERY || r.type == RESP_NOMATCH) return;
+  if (!r.genre[0]) { p0fos="unknown"; return; }
+
+  p0fos=strdup(r.genre);
+  p0fdetails=strdup(r.detail);
+  p0flink=strdup(r.link);
+  p0fdistance=r.dist;
+  p0fuptime=r.uptime;
+  p0fnat=r.nat;
+  p0ffw=r.fw;
+}
diff -urN qmail-1.03-vanilla/qmail-p0f.h qmail-1.03-md24/qmail-p0f.h
--- qmail-1.03-vanilla/qmail-p0f.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/qmail-p0f.h	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,75 @@
+#ifndef P0F_H
+#define P0F_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/unistd.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "received.h"
+#include "uint32.h"
+#include "qmail.h"
+#include "fmt.h"
+#include "env.h"
+#include "str.h"
+
+/* from p0f-query.h */
+#define QUERY_MAGIC	0x0defaced
+#define NO_SCORE	-100
+
+/* Masquerade detection flags: */
+#define D_GENRE   0x0001
+#define D_DETAIL  0x0002
+#define D_LINK    0x0004
+#define D_DIST    0x0008
+#define D_NAT     0x0010
+#define D_FW      0x0020
+#define D_NAT2_1  0x0040
+#define D_FW2_1   0x0080
+#define D_NAT2_2  0x0100
+#define D_FW2_2   0x0200
+#define D_FAST    0x0400
+#define D_TNEG    0x0800
+
+#define D_TIME    0x4000
+#define D_FAR     0x8000
+
+struct p0f_query {
+  uint32 magic;			/* must be set to QUERY_MAGIC */
+  uint32 id;			/* Unique query ID */
+  uint32 src_ad,dst_ad;		/* src address, local dst addr */
+  unsigned short src_port,dst_port;	/* src and dst ports */
+};
+
+#define RESP_OK		0	/* Response OK */
+#define RESP_BADQUERY	1	/* Query malformed */
+#define RESP_NOMATCH	2	/* No match for src-dst data */
+
+struct p0f_response {
+  uint32 magic;			/* QUERY_MAGIC */
+  uint32 id;			/* Query ID (copied from p0f_query) */
+  unsigned char  type;		/* RESP_* */
+  unsigned char  genre[20];	/* OS genre (empty if no match) */
+  unsigned char  detail[40];	/* OS version (empty if no match) */
+  char  dist;			/* Distance (-1 if unknown ) */
+  unsigned char  link[30];	/* Link type (empty if unknown) */
+  unsigned char  tos[30];	/* Traffic type (empty if unknown) */
+  unsigned char  fw,nat;	/* firewall and NAT flags flags */
+  unsigned char  real;		/* A real operating system? */
+  signed short score;		/* Masquerade score (or NO_SCORE) */
+  unsigned short mflags;	/* Masquerade flags (D_*) */
+  signed int uptime;		/* Uptime in hours (-1 = unknown) */
+};
+
+extern char *ctl_p0fsock; /* from qmail-smtpd */
+extern char *p0fos, *p0fdetails, *p0flink;
+extern char p0fdistance;
+extern signed int p0fuptime;
+extern char p0ffw,p0fnat;
+
+extern void p0f_received(struct qmail *qqt, char *remoteip);
+extern void p0f_query(void);
+
+#endif /* P0F_H */
diff -urN qmail-1.03-vanilla/qmail-pop3d.c qmail-1.03-md24/qmail-pop3d.c
--- qmail-1.03-vanilla/qmail-pop3d.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-pop3d.c	2007-07-28 18:06:30.000000000 +0200
@@ -1,6 +1,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "commands.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include "auto_qmail.h"
 #include "sig.h"
 #include "getln.h"
 #include "stralloc.h"
@@ -9,6 +11,7 @@
 #include "open.h"
 #include "prioq.h"
 #include "scan.h"
+#include "base64.h"
 #include "fmt.h"
 #include "str.h"
 #include "exit.h"
@@ -16,8 +19,26 @@
 #include "readwrite.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "out_log.h"
+#include "case.h"
+#include "env.h"
+#include "commands.h"
+#include "control.h"
+#include "scan.h"
+#include "fd.h"
+#include "wait.h"
+#include "byte.h"
+#include "now.h"
+
+char *name="qmail-pop3d";
+char unique[FMT_ULONG + FMT_ULONG + 3];
+
+int ctl_log_in=0;
+int ctl_log_out=0;
+int ctl_log_fd=2;
+int ctl_maxcmdlen;
 
-void die() { _exit(0); }
+void die() { _exit(1); }
 
 int saferead(fd,buf,len) int fd; char *buf; int len;
 {
@@ -35,78 +56,65 @@
   return r;
 }
 
+char ssinbuf[1024];
 char ssoutbuf[1024];
-substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
-
-char ssinbuf[128];
+char sserrbuf[1024];
+char strnum[FMT_ULONG];
+stralloc line = {0};
 substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
+substdio sserr = SUBSTDIO_FDBUF(safewrite,-1,sserrbuf,sizeof sserrbuf);
 
-void put(buf,len) char *buf; int len;
-{
-  substdio_put(&ssout,buf,len);
-}
-void puts(s) char *s;
-{
-  substdio_puts(&ssout,s);
-}
-void flush()
+void err(char *s)
 {
-  substdio_flush(&ssout);
+  doserv();
+  out("-ERR");
+  if (s) { out(" "); out(s); }
+  doeol(); flush();
 }
-void err(s) char *s;
-{
-  puts("-ERR ");
-  puts(s);
-  puts("\r\n");
-  flush();
-}
-
-void die_nomem() { err("out of memory"); die(); }
-void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); }
-void die_scan() { err("unable to scan $HOME/Maildir"); die(); }
-
-void err_syntax() { err("syntax error"); }
-void err_unimpl() { err("unimplemented"); }
-void err_deleted() { err("already deleted"); }
-void err_nozero() { err("messages are counted from 1"); }
-void err_toobig() { err("not that many messages"); }
-void err_nosuch() { err("unable to open that message"); }
-void err_nounlink() { err("unable to unlink all deleted messages"); }
 
-void okay() { puts("+OK \r\n"); flush(); }
-
-void printfn(fn) char *fn;
+void err_die(char *s)
 {
-  fn += 4;
-  put(fn,str_chr(fn,':'));
+  err(s);die();
 }
 
-char strnum[FMT_ULONG];
-stralloc line = {0};
+void die_nomaildir() { err_die("[SYS/TEMP] this user has no $HOME/Maildir"); }
+void die_nomem()     { err_die("[SYS/TEMP] out of memory"); }
+void die_scan()      { err_die("[SYS/TEMP] unable to scan $HOME/Maildir"); }
+void die_control()   { err_die("[SYS/TEMP] unable to read controls"); }
+void die_lcmd()      { err_die("[SYS/TEMP] the given command is too long!"); }
+
+void err_noargs()    { err("don't need any arguments"); }
+void err_syntax()    { err("syntax error"); }
+void err_unimpl()    { err("unimplemented"); }
+void err_deleted()   { err("already deleted"); }
+void err_nozero()    { err("messages are counted from 1"); }
+void err_toobig()    { err("not that many messages"); }
+void err_nosuch()    { err("unable to open that message"); }
+void err_nounlink()  { err("unable to unlink all deleted messages"); }
 
 void blast(ssfrom,limit)
-substdio *ssfrom;
-unsigned long limit;
+  substdio *ssfrom;
+  unsigned long limit;
 {
   int match;
   int inheaders = 1;
- 
+
   for (;;) {
     if (getln(ssfrom,&line,&match,'\n') != 0) die();
     if (!match && !line.len) break;
     if (match) --line.len; /* no way to pass this info over POP */
     if (limit) if (!inheaders) if (!--limit) break;
-    if (!line.len)
+    if (!line.len) {
       inheaders = 0;
-    else
-      if (line.s[0] == '.')
-        put(".",1);
-    put(line.s,line.len);
-    put("\r\n",2);
+    } else if (line.s[0] == '.') {
+      Out(".");
+    }
+    Outn(line.s,line.len);Out("\r\n");
     if (!match) break;
   }
-  put("\r\n.\r\n",5);
-  flush();
+  doserv(); Log("[...]"); Out(".");
+  doeol(); flush();
 }
 
 stralloc filenames = {0};
@@ -114,89 +122,127 @@
 
 struct message {
   int flagdeleted;
+  int read;
   unsigned long size;
   char *fn;
 } *m;
 int numm;
 
-int last = 0;
+int last=0;
 
 void getlist()
 {
   struct prioq_elt pe;
   struct stat st;
   int i;
- 
+
   maildir_clean(&line);
   if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan();
- 
+
   numm = pq.p ? pq.len : 0;
   m = (struct message *) alloc(numm * sizeof(struct message));
   if (!m) die_nomem();
- 
-  for (i = 0;i < numm;++i) {
+
+  for (i=0; i<numm; ++i) {
     if (!prioq_min(&pq,&pe)) { numm = i; break; }
     prioq_delmin(&pq);
     m[i].fn = filenames.s + pe.id;
     m[i].flagdeleted = 0;
-    if (stat(m[i].fn,&st) == -1)
-      m[i].size = 0;
-    else
-      m[i].size = st.st_size;
+    m[i].read = 0;
+    if (stat(m[i].fn,&st) == -1) m[i].size = 0;
+    else m[i].size = st.st_size;
   }
 }
 
-void pop3_stat()
+void pop3_noop(char *arg) {
+  if (*arg) { err_noargs(); return; }
+  out_err("+OK");
+}
+
+void pop3_stat(char *arg)
 {
   int i;
-  unsigned long total;
- 
-  total = 0;
-  for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size;
-  puts("+OK ");
-  put(strnum,fmt_uint(strnum,numm));
-  puts(" ");
-  put(strnum,fmt_ulong(strnum,total));
-  puts("\r\n");
-  flush();
+  unsigned long total=0, n=0;
+
+  if (*arg) { err_noargs(); return; }
+  for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size, n++;
+  doserv(); out("+OK ");
+  strnum[fmt_uint(strnum,n)]=0;out(strnum);
+  out(" ");
+  strnum[fmt_ulong(strnum,total)]=0;out(strnum);
+  doeol();flush();
 }
 
-void pop3_rset()
+void pop3_rset(char *arg)
 {
   int i;
+
+  if (*arg) { err_noargs(); return; }
   for (i = 0;i < numm;++i) m[i].flagdeleted = 0;
   last = 0;
-  okay();
+  out_err("+OK");
 }
 
-void pop3_last()
+/* rfc1460
+ *
+ * The POP3 server issues a positive response with a line containing the highest
+ * message number which accessed.
+ * Zero is returned in case no message in the maildrop has been accessed during
+ * previous transactions.
+ * A client may thereafter infer that messages, if any, numbered greater than
+ * the response to the LAST command are messages not yet accessed by the
+ * client.
+ */
+void pop3_last(char *arg)
 {
-  puts("+OK ");
-  put(strnum,fmt_uint(strnum,last));
-  puts("\r\n");
-  flush();
+  int i;
+  char *p;
+
+  if (*arg) { err_noargs(); return; }
+  last = 0;
+  for (i=0; i<numm; i++) {
+    p = m[i].fn;
+    if (m[i].read) last = i + 1;
+    else {
+      int j = str_rchr(p,',');
+      if (p[j]==',')
+       if (p[j + str_chr(p + j,'S')])
+        last = i + 1;
+    }
+  }
+  doserv(); out("+OK ");
+  outn(strnum,fmt_uint(strnum,last));
+  doeol();flush();
 }
 
-void pop3_quit()
+void pop3_quit(char *arg)
 {
   int i;
-  for (i = 0;i < numm;++i)
+
+  if (*arg) { err_noargs(); return; }
+  for (i = 0;i < numm;++i) {
     if (m[i].flagdeleted) {
+      /* if deleted */
       if (unlink(m[i].fn) == -1) err_nounlink();
-    }
-    else
+    } else {
+      /* all other */
       if (str_start(m[i].fn,"new/")) {
-	if (!stralloc_copys(&line,"cur/")) die_nomem();
-	if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem();
-	if (!stralloc_cats(&line,":2,")) die_nomem();
-	if (!stralloc_0(&line)) die_nomem();
-	rename(m[i].fn,line.s); /* if it fails, bummer */
+        if (!stralloc_copys(&line,"cur/")) die_nomem();
+        if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem();
+        if (m[i].read) {
+	  if (!stralloc_cats(&line,":2,S")) die_nomem(); /* seen flag is set */
+	} else {
+	  if (!stralloc_cats(&line,":2,")) die_nomem();
+	}
+        if (!stralloc_0(&line)) die_nomem();
+        rename(m[i].fn,line.s); /* if it fails, bummer */
       }
-  okay();
-  die();
+    }
+  } /* for(all) */
+  out_err("+OK good bye"); _exit(0);
 }
 
-int msgno(arg) char *arg;
+int msgno(char *arg)
 {
   unsigned long u;
   if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
@@ -207,99 +253,197 @@
   return u;
 }
 
-void pop3_dele(arg) char *arg;
+void pop3_dele(char *arg)
 {
   int i;
   i = msgno(arg);
   if (i == -1) return;
   m[i].flagdeleted = 1;
   if (i + 1 > last) last = i + 1;
-  okay();
+  out_err("+OK");
 }
 
-void list(i,flaguidl)
-int i;
-int flaguidl;
+void printfn(char *fn, int log)
 {
-  put(strnum,fmt_uint(strnum,i + 1));
-  puts(" ");
-  if (flaguidl) printfn(m[i].fn);
-  else put(strnum,fmt_ulong(strnum,m[i].size));
-  puts("\r\n");
+  fn += 4;
+  if (log) outn(fn,str_chr(fn,':'));
+  else Outn(fn,str_chr(fn,':'));
 }
 
-void dolisting(arg,flaguidl) char *arg; int flaguidl;
+void list(int i, int flaguidl, int log)
+{
+  if (log) {
+    outn(strnum,fmt_uint(strnum,i + 1)); out(" ");
+    if (flaguidl) printfn(m[i].fn, log);
+    else outn(strnum,fmt_ulong(strnum,m[i].size));
+    doeol();
+  } else {
+    /* big listings are not logged! */
+    Outn(strnum,fmt_uint(strnum,i + 1)); Out(" ");
+    if (flaguidl) printfn(m[i].fn, log);
+    else Outn(strnum,fmt_ulong(strnum,m[i].size));
+    Out("\r\n");
+  }
+  flush();
+}
+
+/* +OK 2 messages (320 octets) */
+void dolisting(char *arg, int flaguidl)
 {
   unsigned int i;
+
   if (*arg) {
     i = msgno(arg);
     if (i == -1) return;
-    puts("+OK ");
-    list(i,flaguidl);
-  }
-  else {
-    okay();
-    for (i = 0;i < numm;++i)
-      if (!m[i].flagdeleted)
-	list(i,flaguidl);
-    puts(".\r\n");
+    doserv(); out("+OK "); list(i,flaguidl,1);
+  } else {
+    unsigned long total=0,n=0;
+    for (i=0; i<numm; ++i) if (!m[i].flagdeleted) total += m[i].size, n++;
+    doserv(); out("+OK ");
+    strnum[fmt_uint(strnum,n)]=0;out(strnum);
+    out(" messages (");
+    strnum[fmt_ulong(strnum,total)]=0;out(strnum);
+    out(" octets)"); doeol();
+    for (i=0; i<numm; ++i) if (!m[i].flagdeleted) list(i,flaguidl,0);
+    doserv(); Log("[...]"); Out(".");
+    doeol();
   }
   flush();
 }
 
-void pop3_uidl(arg) char *arg; { dolisting(arg,1); }
-void pop3_list(arg) char *arg; { dolisting(arg,0); }
+void pop3_uidl(char *arg) { dolisting(arg,1); }
+void pop3_list(char *arg) { dolisting(arg,0); }
 
 substdio ssmsg; char ssmsgbuf[1024];
 
-void pop3_top(arg) char *arg;
+void pop3_top(char *arg)
 {
   int i;
   unsigned long limit;
   int fd;
- 
+
   i = msgno(arg);
   if (i == -1) return;
- 
+
   arg += scan_ulong(arg,&limit);
   while (*arg == ' ') ++arg;
   if (scan_ulong(arg,&limit)) ++limit; else limit = 0;
- 
+
   fd = open_read(m[i].fn);
   if (fd == -1) { err_nosuch(); return; }
-  okay();
+  doserv();
+  out("+OK (");outn(strnum, fmt_ulong(strnum,m[i].size));out(" octets)");
+  doeol();flush();
   substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf));
   blast(&ssmsg,limit);
+  m[i].read = 1;
   close(fd);
 }
 
+void pop3_capa(arg) char *arg;
+{
+  out_err("+OK Capability list follows");
+  out_err("TOP");
+  out_err("UIDL");
+  out_err("LAST");
+  out_err("PIPELINING");
+  out_err("RESP-CODES");
+  out_err("IMPLEMENTATION qmail patched " VERSION);
+  out_err(".");
+  flush();
+}
+
 struct commands pop3commands[] = {
   { "quit", pop3_quit, 0 }
+, { "capa", pop3_capa, 0 }
 , { "stat", pop3_stat, 0 }
 , { "list", pop3_list, 0 }
 , { "uidl", pop3_uidl, 0 }
 , { "dele", pop3_dele, 0 }
-, { "retr", pop3_top, 0 }
 , { "rset", pop3_rset, 0 }
 , { "last", pop3_last, 0 }
-, { "top", pop3_top, 0 }
-, { "noop", okay, 0 }
+, { "retr", pop3_top,  0 }
+, { "top",  pop3_top,  0 }
+, { "noop", pop3_noop, 0 }
 , { 0, err_unimpl, 0 }
-} ;
+};
+
+void setup(void) {
+  int fd=open(".", O_RDONLY);
+
+  /* logging */
+  if (chdir(auto_qmail) == -1) die_control();
+  if (control_readint(&ctl_log_in,"control/log/pop3_in") == -1)
+    die_control();
+  if (control_readint(&ctl_log_out,"control/log/pop3_out") == -1)
+    die_control();
+  if (control_readint(&ctl_log_fd,"control/log/pop3_fd") == -1)
+    die_control();
+
+  if (ctl_log_in  < 0) ctl_log_in=0;
+  if (ctl_log_out < 0) ctl_log_out=0;
+  if (ctl_log_fd  < 0) ctl_log_fd=0;
+  sserr.fd = ctl_log_fd;
 
-void main(argc,argv)
-int argc;
-char **argv;
+  /* buffer limit for commands */
+  if (control_readint(&ctl_maxcmdlen, "control/maxcmdlen") == -1) die_control();
+  if (ctl_maxcmdlen < 0) ctl_maxcmdlen=0;
+
+  fchdir(fd); close(fd);
+}
+
+int main(int argc, char **argv)
 {
+  char *resp;
+
   sig_alarmcatch(die);
   sig_pipeignore();
- 
+  sserr.fd=0;
+
+  setup();
   if (!argv[1]) die_nomaildir();
   if (chdir(argv[1]) == -1) die_nomaildir();
- 
+
   getlist();
+  /* sorry for this bloat - but we need this for digest-md5 :( */
+  resp=env_get("DIGEST_RESPONSE");
+  if (!resp) {
+    out_err("+OK");
+  } else {
+    stralloc slop = {0};
+    stralloc temp = {0};
+    char tmp[44];
+    int fd=open_read(resp);
+    if (read(fd, &tmp, 33) != 32) {
+      close(fd);
+      out_err("-ERR digest auth failed!");
+      die();
+    }
+    tmp[32]=0;
+    close(fd); unlink(resp);
+    stralloc_copys(&slop, "rspauth=");
+    stralloc_cats(&slop, tmp);
+    slop.s[slop.len]=0;
+    b64encode(&temp,&slop);
+    temp.s[temp.len]=0;
+    doserv();out("+ ");out(temp.s);doeol();flush();
+    if (!stralloc_copys(&temp,"")) return -1;
+    /* xxx: was not tested!!! */
+    for (;;) {
+      int i;
+      if (!stralloc_readyplus(&temp,1)) return -1;
+      i = substdio_get(ssin,temp.s + temp.len,1);
+      if (i != 1) err_syntax();
+      if (temp.s[temp.len] == '\n') break;
+      ++temp.len;
+    }
+    if (temp.len > 0) if (temp.s[temp.len - 1] == '\r') --temp.len;
+    temp.s[temp.len] = 0;
+    doname();out("C: ");out(temp.s);Log("\n");
+    out_err("+OK digest auth was good!");
+  }
+  commands(&ssin,&sserr,pop3commands);
 
-  okay();
-  commands(&ssin,pop3commands);
   die();
+  return 0; /* gcc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-popup.c qmail-1.03-md24/qmail-popup.c
--- qmail-1.03-vanilla/qmail-popup.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-popup.c	2007-08-13 21:27:10.000000000 +0200
@@ -1,4 +1,20 @@
+/*
+ * mtime: TR 2007-07-28
+ *
+ * control/log/pop3_fd     -> the logging file desciptor
+ * control/log/pop3_in     -> enable/disable logging of incoming cmd's from client
+ * control/log/pop3_out    -> enable/disable logging of outgoing server resonses
+ *
+ * + sasl authentication (rfc1734)
+ *   - methods: plain, login, cram-md5, cram-sha1, cram-ripemd, digest-md5
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "auto_qmail.h"
 #include "commands.h"
+#include "control.h"
+#include "scan.h"
 #include "fd.h"
 #include "sig.h"
 #include "stralloc.h"
@@ -13,93 +29,127 @@
 #include "readwrite.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "stralloc.h"
+#include "case.h"
+#include "env.h"
+#include "out_log.h"
+#include "qmail-sasl.h"
+#include "ucspitls.h"
+
+char ssinbuf[1024];
+char ssoutbuf[1024];
+char sserrbuf[1024];
+
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
+substdio sserr = SUBSTDIO_FDBUF(safewrite,-1,sserrbuf,sizeof sserrbuf);
+
+stralloc username = {0};
+char **childargs;
+char *hostname;
+char *name="qmail-popup";
+
+int ctl_log_in=0;
+int ctl_log_out=0;
+int ctl_log_fd=2;
+int ctl_logindelay=0; /* how can we do this ? */
+int ctl_expire=0;
+int ctl_auth_delay=5;
+int ctl_auth_secure=(1|2|4|8|16); /* sasl methods in TLS mode */
+int ctl_auth_insecure=(4|8|16); /* sasl methods in NON-TLS mode */
+int *ctl_auth_current = &ctl_auth_insecure;
+int ctl_maxcmdlen;
+
+int tls_available = 0;
+int tls_started = 0;
+
+char logindelay[FMT_ULONG+22];
+char expire[FMT_ULONG+22];
+
+int seenuser = 0;
+char upbuf[128];
+substdio ssup;
+
+void die() { flush(); _exit(1); }
+
+void err(char *s)
+{
+  doserv();
+  if (s) {
+    out("-ERR "); out(s);
+  } else {
+    out("-ERR");
+  }
+  doeol();
+  flush();
+}
 
-void die() { _exit(1); }
+void ok(char *s)
+{
+  doserv(); out("+OK");
+  if (s) out(s);
+  doeol(); flush();
+}
+
+void err_die(char *s) { err(s);die(); }
+
+/* rfc: [SYS/PERM] [SYS/TEMP] [AUTH] [IN-USE] */
+void die_read()      { doname();Log("client exited\n");_exit(0); }
+void die_usage()     { err_die("[SYS/TEMP] usage: popup hostname checkprogram subprogram"); }
+void die_nomem()     { err_die("[SYS/TEMP] out of memory"); }
+void die_pipe()      { err_die("[SYS/TEMP] unable to open pipe"); }
+void die_write()     { err_die("[SYS/TEMP] unable to write pipe"); }
+void die_fork()      { err_die("[SYS/TEMP] unable to fork"); }
+void die_child()     { err_die("[SYS/TEMP] aack, child crashed"); }
+void die_control()   { err_die("[SYS/TEMP] unable to read controls"); }
+void die_lcmd()      { err_die("[SYS/TEMP] the given command is too long!"); }
+void die_tls()       { err_die("[SYS/TEMP] TLS startup failed"); }
+
+void err_wantauth()  { err("[SYS/PERM] authorization first"); }
+void err_authfail()  { err("[AUTH] authorization failed"); }
+void err_authin()    { err("[AUTH] invalid authorization input"); }
+int  err_noauth()    { err("auth type unimplemented"); return -1; }
+int  err_authabrt()  { err("auth exchange cancelled"); return -1; }
+void err_wantuser()  { err("USER first"); }
+void err_syntax()    { err("syntax error"); }
+void err_unimpl()    { err("unimplemented"); }
 
-int saferead(fd,buf,len) int fd; char *buf; int len;
+int saferead(int fd, char *buf, int len)
 {
   int r;
   r = timeoutread(1200,fd,buf,len);
-  if (r <= 0) die();
+  if (r <= 0) die_read();
   return r;
 }
 
-int safewrite(fd,buf,len) int fd; char *buf; int len;
+int safewrite(int fd, char *buf, int len)
 {
   int r;
   r = timeoutwrite(1200,fd,buf,len);
-  if (r <= 0) die();
+  if (r <= 0) die_write();
   return r;
 }
 
-char ssoutbuf[128];
-substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
-
-char ssinbuf[128];
-substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
-
-void puts(s) char *s;
-{
-  substdio_puts(&ssout,s);
-}
-void flush()
-{
-  substdio_flush(&ssout);
-}
-void err(s) char *s;
-{
-  puts("-ERR ");
-  puts(s);
-  puts("\r\n");
-  flush();
-}
-
-void die_usage() { err("usage: popup hostname subprogram"); die(); }
-void die_nomem() { err("out of memory"); die(); }
-void die_pipe() { err("unable to open pipe"); die(); }
-void die_write() { err("unable to write pipe"); die(); }
-void die_fork() { err("unable to fork"); die(); }
-void die_childcrashed() { err("aack, child crashed"); }
-void die_badauth() { err("authorization failed"); }
-
-void err_syntax() { err("syntax error"); }
-void err_wantuser() { err("USER first"); }
-void err_authoriz() { err("authorization first"); }
-
-void okay() { puts("+OK \r\n"); flush(); }
-void pop3_quit() { okay(); die(); }
-
-
-char unique[FMT_ULONG + FMT_ULONG + 3];
-char *hostname;
-stralloc username = {0};
-int seenuser = 0;
-char **childargs;
-substdio ssup;
-char upbuf[128];
-
-
 void doanddie(user,userlen,pass)
-char *user;
-unsigned int userlen; /* including 0 byte */
-char *pass;
+  char *user;
+  unsigned int userlen; /* including 0 byte */
+  char *pass;
 {
   int child;
   int wstat;
   int pi[2];
- 
+
   if (fd_copy(2,1) == -1) die_pipe();
   close(3);
   if (pipe(pi) == -1) die_pipe();
   if (pi[0] != 3) die_pipe();
   switch(child = fork()) {
-    case -1:
-      die_fork();
+    case -1: die_fork(); break;
     case 0:
       close(pi[1]);
       sig_pipedefault();
       execvp(*childargs,childargs);
-      _exit(1);
+      _exit(0);
   }
   close(pi[0]);
   substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
@@ -113,71 +163,275 @@
   close(pi[1]);
   byte_zero(pass,str_len(pass));
   byte_zero(upbuf,sizeof upbuf);
-  if (wait_pid(&wstat,child) == -1) die();
-  if (wait_crashed(wstat)) die_childcrashed();
-  if (wait_exitcode(wstat)) die_badauth();
+  if (wait_pid(&wstat,child) == -1) die_child();
+  if (wait_crashed(wstat)) die_child();
+  if (wait_exitcode(wstat)) { err_authfail(); return; }
   die();
 }
+
+void pop3_okay() { ok(0); }
+void pop3_quit() { ok(0);_exit(0); }
+
 void pop3_greet()
 {
-  char *s;
-  s = unique;
-  s += fmt_uint(s,getpid());
-  *s++ = '.';
-  s += fmt_ulong(s,(unsigned long) now());
-  *s++ = '@';
-  *s++ = 0;
-  puts("+OK <");
-  puts(unique);
-  puts(hostname);
-  puts(">\r\n");
-  flush();
+  dounique();
+  doserv(); out("+OK "); out("<"); out(unique); out(hostname); out(">");
+  doeol(); flush();
 }
+
 void pop3_user(arg) char *arg;
 {
   if (!*arg) { err_syntax(); return; }
-  okay();
   seenuser = 1;
-  if (!stralloc_copys(&username,arg)) die_nomem(); 
-  if (!stralloc_0(&username)) die_nomem(); 
+  if (!stralloc_copys(&username,arg)) die_nomem();
+  if (!stralloc_0(&username)) die_nomem();
+  ok(0);
 }
+
 void pop3_pass(arg) char *arg;
 {
   if (!seenuser) { err_wantuser(); return; }
   if (!*arg) { err_syntax(); return; }
+  if (!env_put2("AUTH", "POP3")) die_nomem();
   doanddie(username.s,username.len,arg);
 }
+
 void pop3_apop(arg) char *arg;
 {
   char *space;
   space = arg + str_chr(arg,' ');
   if (!*space) { err_syntax(); return; }
   *space++ = 0;
+  if (!env_put2("AUTH", "APOP")) die_nomem();
   doanddie(arg,space - arg,space);
 }
 
-struct commands pop3commands[] = {
+void dosasl() {
+  int i=0,space=0;
+  while (i<SASL_MAX) {
+    if ((*ctl_auth_current & 1<<i) == 1<<i) {
+      if (space) out(" ");
+      out(sasl[i]);flush();
+      space=1;
+    }
+    i++;
+  }
+}
+
+/*
+ * rfc2449: TOP USER SASL RESP-CODES LOGIN-DELAY
+ *          PIPELINING EXPIRE UIDL IMPLEMENTATION
+ * rfc2595: STLS
+ * rfc3206: AUTH-RESP-CODE
+ */
+void pop3_capa()
+{
+  out_err("+OK list of capabilities follows");
+  if (*ctl_auth_current) {
+    doserv(); out("SASL "); dosasl(); doeol();
+    out_err("AUTH-RESP-CODE");
+  }
+  out_err("TOP");
+  out_err("USER");
+  out_err("UIDL");
+  if (ctl_logindelay) out_err(logindelay); /* xxx: timeout = variable */
+  if (ctl_expire) out_err(expire);
+  if (tls_available && !tls_started) out_err("STLS");
+  out_err("PIPELINING");
+  out_err("RESP-CODES");
+  out_err("IMPLEMENTATION qmail patched " VERSION);
+  out_err(".");
+}
+
+void pop3_stls(arg) char *arg;
+{
+  if (!tls_available || tls_started)
+    return out_err("-ERR STLS not available");
+  out_err("+OK starting TLS negotiation");
+
+  if (!ucspitls())
+    die_tls();
+
+  /* issue new possibilities */
+  *ctl_auth_current = &ctl_auth_secure;
+
+  tls_started = 1;
+  /* reset state */
+  seenuser = 0;
+}
+
+void pop3_help()
+{
+  out_err("+OK list of valid commands follows");
+  out_err("user");
+  out_err("pass");
+  out_err("apop");
+  out_err("capa");
+  out_err("quit");
+  out_err("auth");
+  out_err("noop");
+  out_err("help");
+  out_err(".");
+}
+
+void pop3_auth(char *arg)
+{
+  char *cmd=arg;
+  int i;
+
+  if (!stralloc_copys(&user,"")) die_nomem();
+  if (!stralloc_copys(&pass,"")) die_nomem();
+  if (!stralloc_copys(&resp,"")) die_nomem();
+  if (str_len(arg) == 0 && *ctl_auth_current) {
+    if (!*ctl_auth_current) { err_unimpl(); return; }
+    out_err("+OK list of SASL extensions follows");
+    for (i=0; i<SASL_MAX; i+=1)
+      if ((*ctl_auth_current & 1<<i) == 1<<i)
+        out_err(sasl[i]);
+    out_err(".");
+    return;
+  }
+
+  i = str_chr(cmd,' ');
+  arg = cmd + i;
+  while (*arg == ' ') ++arg;
+  cmd[i] = 0;
+
+  for (i = 0; authcmds[i].text; ++i)
+    if (case_equals(authcmds[i].text,cmd)) break;
+
+  if ((*ctl_auth_current & 1<<i) != 1<<i) { err_noauth(); return; }
+
+  auth_for=MODE_POPUP;
+  switch (authcmds[i].fun(arg)) {
+    case ERR_AUTH_FAILED: err_authfail(); break;
+    case ERR_AUTH_INPUT:  err_authin();   break;
+    case ERR_AUTH_ABORT:  err_authabrt(); break;
+  }
+  flush();
+  _exit(0);
+}
+
+struct commands pop3commands[] =
+{
   { "user", pop3_user, 0 }
 , { "pass", pop3_pass, 0 }
 , { "apop", pop3_apop, 0 }
+, { "capa", pop3_capa, 0 }
 , { "quit", pop3_quit, 0 }
-, { "noop", okay, 0 }
-, { 0, err_authoriz, 0 }
+, { "auth", pop3_auth, 0 }
+, { "noop", pop3_okay, 0 }
+, { "help", pop3_help, 0 }
+, { "stls", pop3_stls, 0 }
+, { "stat", err_wantauth, 0 }
+, { "list", err_wantauth, 0 }
+, { "uidl", err_wantauth, 0 }
+, { "dele", err_wantauth, 0 }
+, { "rset", err_wantauth, 0 }
+, { "last", err_wantauth, 0 }
+, { "retr", err_wantauth, 0 }
+, { "top",  err_wantauth, 0 }
+, { 0,      err_unimpl, 0 }
 } ;
 
-void main(argc,argv)
-int argc;
-char **argv;
+void setup(void) {
+  char *x;
+
+  if (control_init() == -1) die_control();
+
+  /* logging */
+  if (control_readint(&ctl_log_in,"control/log/pop3_in") == -1)
+    die_control();
+  if (control_readint(&ctl_log_out,"control/log/pop3_out") == -1)
+    die_control();
+  if (control_readint(&ctl_log_fd,"control/log/pop3_fd") == -1)
+    die_control();
+
+  if (ctl_log_in  < 0) ctl_log_in=0;
+  if (ctl_log_out < 0) ctl_log_out=0;
+  if (ctl_log_fd  < 0) ctl_log_fd=0;
+  sserr.fd = ctl_log_fd;
+
+  /* login delay */
+  ctl_logindelay=0;
+  if (env_get("NO_LOGINDELAY")) {
+    ctl_logindelay=0;
+  } else {
+    x = env_get("LOGINDELAY");
+    if (x) {
+      if (scan_ulong(x,&ctl_logindelay) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_logindelay,"control/logindelay") == -1)
+        die_control();
+    }
+  }
+  x=logindelay;
+  x+=fmt_str(x,"LOGIN DELAY ");
+  x+=fmt_uint(x,ctl_logindelay);
+  x=0;
+
+  ctl_auth_delay=0;
+  if (env_get("NO_AUTHDELAY")) {
+    ctl_auth_delay=0;
+  } else {
+    x = env_get("AUTHDELAY");
+    if (x) {
+      if (scan_ulong(x,&ctl_auth_delay) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_auth_delay,"control/auth/delay") == -1)
+        die_control();
+    }
+  }
+
+  ctl_expire=0;
+  if (env_get("NO_EXPIRE")) {
+    ctl_expire=0;
+  } else {
+    x = env_get("EXPIRE");
+    if (x) {
+      if (scan_ulong(x,&ctl_expire) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_expire,"control/expire") == -1) die_control();
+    }
+  }
+  x=expire;
+  x+=fmt_str(x,"EXPIRE ");
+  if (ctl_expire <= 0) {
+    x+=fmt_str(x," NEVER");
+  } else {
+    x+=fmt_uint(x,ctl_expire);
+  }
+  x=0;
+
+  if (control_readint(&ctl_auth_delay,    "control/auth/delay") == -1) die_control();
+  if (control_readint(&ctl_auth_secure,   "control/auth/spop3") == -1) die_control();
+  if (control_readint(&ctl_auth_insecure, "control/auth/pop3")  == -1) die_control();
+
+  /* buffer limit for commands */
+  if (control_readint(&ctl_maxcmdlen, "control/maxcmdlen") == -1) die_control();
+  if (ctl_maxcmdlen < 0) ctl_maxcmdlen=0;
+
+  return;
+}
+
+int main(int argc, char **argv)
 {
+  hostname = argv[1];
+  childargs = argv + 2;
+  sserr.fd=0;
+
   sig_alarmcatch(die);
   sig_pipeignore();
- 
-  hostname = argv[1];
+
+  if (chdir(auto_qmail) == -1) die_control();
+  setup();
+
   if (!hostname) die_usage();
-  childargs = argv + 2;
   if (!*childargs) die_usage();
- 
+  tls_available = !!env_get("UCSPITLS");
   pop3_greet();
-  commands(&ssin,pop3commands);
+  commands(&ssin,&sserr,pop3commands);
+
   die();
+  return 0; /* gcc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-pw2u.c qmail-1.03-md24/qmail-pw2u.c
--- qmail-1.03-vanilla/qmail-pw2u.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-pw2u.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "readwrite.h"
 #include "subfd.h"
@@ -11,6 +12,7 @@
 #include "str.h"
 #include "scan.h"
 #include "open.h"
+#include "byte.h"
 #include "error.h"
 #include "getln.h"
 #include "auto_break.h"
@@ -228,7 +230,7 @@
 substdio ss;
 char ssbuf[SUBSTDIO_INSIZE];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/qmail-qmqpc.c qmail-1.03-md24/qmail-qmqpc.c
--- qmail-1.03-vanilla/qmail-qmqpc.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-qmqpc.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,5 @@
 #include <sys/types.h>
+#include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -102,14 +103,16 @@
 char *server;
 {
   struct ip_address ip;
+  struct ip_address outip;
   char ch;
 
+  outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long)0;
   if (!ip_scan(server,&ip)) return;
 
   qmqpfd = socket(AF_INET,SOCK_STREAM,0);
   if (qmqpfd == -1) die_socket();
 
-  if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) {
+  if (timeoutconn(qmqpfd,&ip,&outip,PORT_QMQP,10) != 0) {
     lasterror = 73;
     if (errno == error_timeout) lasterror = 72;
     close(qmqpfd);
@@ -135,10 +138,9 @@
 
 stralloc servers = {0};
 
-main()
+int main(int argc, char **argv)
 {
-  int i;
-  int j;
+  int i,j;
 
   sig_pipeignore();
 
diff -urN qmail-1.03-vanilla/qmail-qmqpd.c qmail-1.03-md24/qmail-qmqpd.c
--- qmail-1.03-vanilla/qmail-qmqpd.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-qmqpd.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "auto_qmail.h"
 #include "qmail.h"
 #include "received.h"
@@ -8,6 +10,9 @@
 #include "now.h"
 #include "fmt.h"
 #include "env.h"
+#include "str.h"
+#include "byte.h"
+#include "scan.h"
 
 void resources() { _exit(111); }
 
@@ -48,7 +53,7 @@
   for (;;) {
     getbyte(&ch);
     if (ch == ':') return len;
-    if (len > 200000000) resources();
+    if (len > 200000000 || ch < '0' || ch > '9') resources();
     len = 10 * len + (ch - '0');
   }
 }
@@ -105,7 +110,7 @@
 
 int flagok = 1;
 
-main()
+int main()
 {
   char *result;
   unsigned long qp;
@@ -163,7 +168,7 @@
   }
 
   if (!flagok)
-    result = "Dsorry, I can't accept addresses like that (#5.1.3)";
+    result = "D5.1.3 sorry, I can't accept addresses like that";
 
   substdio_put(&ssout,strnum,fmt_ulong(strnum,(unsigned long) str_len(result)));
   substdio_puts(&ssout,":");
diff -urN qmail-1.03-vanilla/qmail-qmtpd.c qmail-1.03-md24/qmail-qmtpd.c
--- qmail-1.03-vanilla/qmail-qmtpd.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-qmtpd.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,10 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "stralloc.h"
 #include "substdio.h"
 #include "qmail.h"
 #include "now.h"
+#include "scan.h"
 #include "str.h"
 #include "fmt.h"
 #include "env.h"
@@ -14,6 +17,13 @@
 
 void badproto() { _exit(100); }
 void resources() { _exit(111); }
+void die_nomem() { resources(); }
+void die_control() { resources(); }
+void die_cdb() { resources(); }
+void die_sys() { resources(); }
+
+extern void realrcptto_init();
+extern int realrcptto();
 
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
@@ -74,36 +84,38 @@
 char *relayclient;
 int relayclientlen;
 
-main()
+int main()
 {
   char ch;
   int i;
   unsigned long biglen;
   unsigned long len;
-  int flagdos;
+  int flagdos=0;
   int flagsenderok;
   int flagbother;
   unsigned long qp;
   char *result;
   char *x;
   unsigned long u;
- 
+
   sig_pipeignore();
   sig_alarmcatch(resources);
   alarm(3600);
- 
+
   if (chdir(auto_qmail) == -1) resources();
- 
+
   if (control_init() == -1) resources();
   if (rcpthosts_init() == -1) resources();
   relayclient = env_get("RELAYCLIENT");
   relayclientlen = relayclient ? str_len(relayclient) : 0;
- 
+
+  realrcptto_init();
+
   if (control_readint(&databytes,"control/databytes") == -1) resources();
   x = env_get("DATABYTES");
   if (x) { scan_ulong(x,&u); databytes = u; }
   if (!(databytes + 1)) --databytes;
- 
+
   remotehost = env_get("TCPREMOTEHOST");
   if (!remotehost) remotehost = "unknown";
   remoteinfo = env_get("TCPREMOTEINFO");
@@ -112,28 +124,28 @@
   local = env_get("TCPLOCALHOST");
   if (!local) local = env_get("TCPLOCALIP");
   if (!local) local = "unknown";
- 
+
   for (;;) {
     if (!stralloc_copys(&failure,"")) resources();
     flagsenderok = 1;
- 
+
     len = getlen();
     if (len == 0) badproto();
- 
+
     if (databytes) bytestooverflow = databytes + 1;
     if (qmail_open(&qq) == -1) resources();
     qp = qmail_qp(&qq);
- 
+
     substdio_get(&ssin,&ch,1);
     --len;
     if (ch == 10) flagdos = 0;
     else if (ch == 13) flagdos = 1;
     else badproto();
- 
+
     received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0);
- 
+
     /* XXX: check for loops? only if len is big? */
- 
+
     if (flagdos)
       while (len > 0) {
         substdio_get(&ssin,&ch,1);
@@ -161,9 +173,9 @@
       }
     }
     getcomma();
- 
+
     len = getlen();
- 
+
     if (len >= 1000) {
       buf[0] = 0;
       flagsenderok = 0;
@@ -178,15 +190,15 @@
       buf[len] = 0;
     }
     getcomma();
- 
+
     flagbother = 0;
     qmail_from(&qq,buf);
     if (!flagsenderok) qmail_fail(&qq);
- 
+
     biglen = getlen();
     while (biglen > 0) {
       if (!stralloc_append(&failure,"")) resources();
- 
+
       len = 0;
       for (;;) {
         if (!biglen) badproto();
@@ -208,15 +220,20 @@
           if (!buf[i]) failure.s[failure.len - 1] = 'N';
         }
         buf[len] = 0;
- 
-        if (relayclient)
+
+        if (relayclient) {
           str_copy(buf + len,relayclient);
-        else
+        } else {
           switch(rcpthosts(buf,len)) {
             case -1: resources();
             case 0: failure.s[failure.len - 1] = 'D';
           }
- 
+	}
+
+        if (!failure.s[failure.len - 1])
+          if (!realrcptto(buf))
+            failure.s[failure.len - 1] = 'D';
+
         if (!failure.s[failure.len - 1]) {
           qmail_to(&qq,buf);
           flagbother = 1;
@@ -226,12 +243,12 @@
       biglen -= (len + 1);
     }
     getcomma();
- 
+
     if (!flagbother) qmail_fail(&qq);
     result = qmail_close(&qq);
-    if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)";
-    if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
- 
+    if (!flagsenderok) result = "D5.1.7 unacceptable sender";
+    if (databytes) if (!bytestooverflow) result = "D5.3.4 sorry, that message size exceeds my databytes limit";
+
     if (*result)
       len = str_len(result);
     else {
@@ -244,25 +261,26 @@
       buf2[len] = 0;
       result = buf2;
     }
-      
+
     len = fmt_ulong(buf,len);
     buf[len++] = ':';
     len += fmt_str(buf + len,result);
     buf[len++] = ',';
- 
+
     for (i = 0;i < failure.len;++i)
       switch(failure.s[i]) {
         case 0:
           substdio_put(&ssout,buf,len);
           break;
         case 'D':
-          substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),");
+          substdio_puts(&ssout,"66:D5.7.1 sorry, that domain isn't in my list of allowed rcpthosts,");
           break;
         default:
-          substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),");
+          substdio_puts(&ssout,"46:D5.1.3 sorry, I can't handle that recipient,");
           break;
       }
- 
+
     /* ssout will be flushed when we read from the network again */
   }
+  return 0; /* gcc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-qread.c qmail-1.03-md24/qmail-qread.c
--- qmail-1.03-vanilla/qmail-qread.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-qread.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "stralloc.h"
 #include "substdio.h"
 #include "subfd.h"
@@ -105,7 +106,7 @@
 
 stralloc line = {0};
 
-void main()
+int main()
 {
  int channel;
  int match;
@@ -118,7 +119,7 @@
  if (chdir("queue") == -1) die_chdir();
  readsubdir_init(&rs,"info",die_opendir);
 
- while (x = readsubdir_next(&rs,&id))
+ while ((x = readsubdir_next(&rs,&id)))
    if (x > 0)
     {
      fmtqfn(fnmess,"mess/",id,1);
@@ -172,4 +173,5 @@
     }
 
  die(0);
+ return 0;
 }
diff -urN qmail-1.03-vanilla/qmail-qstat.sh qmail-1.03-md24/qmail-qstat.sh
--- qmail-1.03-vanilla/qmail-qstat.sh	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-qstat.sh	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,7 @@
 cd QMAIL
 messdirs=`echo queue/mess/* | wc -w`
 messfiles=`find queue/mess/* -print | wc -w`
-tododirs=`echo queue/todo | wc -w`
-todofiles=`find queue/todo -print | wc -w`
+tododirs=`echo queue/todo/* | wc -w`
+todofiles=`find queue/todo/* -print | wc -w`
 echo messages in queue: `expr $messfiles - $messdirs`
 echo messages in queue but not yet preprocessed: `expr $todofiles - $tododirs`
diff -urN qmail-1.03-vanilla/qmail-queue.c qmail-1.03-md24/qmail-queue.c
--- qmail-1.03-vanilla/qmail-queue.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-queue.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include "readwrite.h"
 #include "sig.h"
 #include "exit.h"
@@ -16,6 +18,10 @@
 #include "auto_uids.h"
 #include "date822fmt.h"
 #include "fmtqfn.h"
+#include "byte.h"
+#include "constmap.h"
+#include "control.h"
+#include "stralloc.h"
 
 #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
 #define ADDR 1003
@@ -40,6 +46,11 @@
 int flagmademess = 0;
 int flagmadeintd = 0;
 
+int bbon = 0;
+stralloc bbs = {0}; /* control/bigbrother */
+stralloc bba = {0}; /* from/to addr */
+struct constmap mapbb;
+
 void cleanup()
 {
  if (flagmadeintd)
@@ -57,6 +68,7 @@
 void die(e) int e; { _exit(e); }
 void die_write() { cleanup(); die(53); }
 void die_read() { cleanup(); die(54); }
+void die_bb() { cleanup(); die(51); }
 void sigalrm() { /* thou shalt not clean up here */ die(52); }
 void sigbug() { die(81); }
 
@@ -151,14 +163,31 @@
 
 char tmp[FMT_ULONG];
 
-void main()
+int main()
 {
- unsigned int len;
- char ch;
+ unsigned int len, xlen, n;
+ const char *b;
+ char ch, *x;
+ int fd;
 
  sig_blocknone();
  umask(033);
  if (chdir(auto_qmail) == -1) die(61);
+
+ if (control_init() == -1) die(55);
+ switch (control_readfile(&bbs,"control/bigbrother",0)) {
+   case -1:
+     die(55);
+   case 0:
+     bbon = 0;
+     if (!constmap_init(&mapbb,"",0,1)) die(51);
+     break;
+   case 1:
+     bbon = 1;
+     if (!constmap_init(&mapbb,bbs.s,bbs.len,1)) die(51);
+     break;
+ }
+
  if (chdir("queue") == -1) die(62);
 
  mypid = getpid();
@@ -180,10 +209,11 @@
 
  messnum = pidst.st_ino;
  messfn = fnnum("mess/",1);
- todofn = fnnum("todo/",0);
- intdfn = fnnum("intd/",0);
+ todofn = fnnum("todo/",1);
+ intdfn = fnnum("intd/",1);
 
  if (link(pidfn,messfn) == -1) die(64);
+ if ((fd = open(messfn, O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd) < 0) die(64);
  if (unlink(pidfn) == -1) die(63);
  flagmademess = 1;
 
@@ -223,6 +253,7 @@
   {
    if (substdio_get(&ssin,&ch,1) < 1) die_read();
    if (substdio_put(&ssout,&ch,1) == -1) die_write();
+   if (bbon) if (!stralloc_catb(&bba, &ch, 1)) die_bb();
    if (!ch) break;
   }
  if (len >= ADDR) die(11);
@@ -235,20 +266,38 @@
    if (!ch) break;
    if (ch != 'T') die(91);
    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
-   for (len = 0;len < ADDR;++len)
-    {
+   for (len = 0;len < ADDR;++len) {
      if (substdio_get(&ssin,&ch,1) < 1) die_read();
      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+     if (bbon) if (!stralloc_catb(&bba, &ch, 1)) die_bb();
      if (!ch) break;
-    }
+   }
    if (len >= ADDR) die(11);
   }
 
+ if (bbon) {
+   x = bba.s;
+   xlen = bba.len;
+   do {
+     n = byte_chr(x,xlen,0);
+     if ((b = constmap(&mapbb, x, n))) {
+       if (*b) {
+         if (substdio_bput(&ssout,"T", 1) == -1) die_write();
+         if (substdio_bputs(&ssout,b) == -1) die_write();
+         if (substdio_bput(&ssout,"",1) == -1) die_write();
+       }
+     }
+     if (n++ >= xlen) break;
+     x += n; xlen -= n;
+   } while (xlen > 0);
+ }
+
  if (substdio_flush(&ssout) == -1) die_write();
  if (fsync(intdfd) == -1) die_write();
 
  if (link(intdfn,todofn) == -1) die(66);
+ if ((fd = open(todofn, O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd) < 0) die(66);
 
  triggerpull();
- die(0);
+ return 0;
 }
diff -urN qmail-1.03-vanilla/qmail-remote.8 qmail-1.03-md24/qmail-remote.8
--- qmail-1.03-vanilla/qmail-remote.8	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-remote.8	2007-07-19 20:56:22.000000000 +0200
@@ -1,10 +1,11 @@
 .TH qmail-remote 8
 .SH NAME
-qmail-remote \- send mail via SMTP
+qmail-remote \- send mail via SMTP / ESMTP
 .SH SYNOPSIS
 .B qmail-remote
 .I host
 .I sender
+.I size
 .I recip
 [
 .I recip ...
@@ -26,7 +27,7 @@
 or to a mail exchanger for
 .I host
 listed in the Domain Name System,
-via the Simple Mail Transfer Protocol (SMTP).
+via the Simple Mail Transfer Protocol (SMTP / ESMTP).
 .I host
 can be either a fully-qualified domain name:
 
@@ -124,10 +125,23 @@
 .B qmail-remote
 refuses to run.
 .TP 5
+.I outgoingip
+IP address to be used on outgoing connections.
+Default: system-defined.
+The value 
+.IR 0.0.0.0 
+is equivalent to the system default.
+
+.TP 5
+.I smtprelays
+Can be used for auth ... XXX == TODO!!!
+PLAIN / LOGIN / CRAM-MD5 / CRAM-SHA1 / CRAM-RIPEMD mechanism
+
+.TP 5
 .I smtproutes
 Artificial SMTP routes.
 Each route has the form
-.IR domain\fB:\fIrelay ,
+.IR domain relay ,
 without any extra spaces.
 If
 .I domain
@@ -156,6 +170,8 @@
 this tells
 .B qmail-remote
 to look up MX records as usual.
+.I port 
+value of 465 (deprecated smtps port) causes TLS session to be started.
 .I smtproutes
 may include wildcards:
 
@@ -195,6 +211,32 @@
 .B qmail-remote
 will wait for each response from the remote SMTP server.
 Default: 1200.
+
+.SH "ESMTP TLS CLIENT OPTIONS"
+.TP 5
+.I clientcert.pem
+SSL certificate that is used to authenticate with the remote server
+during a TLS session.
+
+.TP 5
+.I tlsclientciphers
+A set of OpenSSL client cipher strings. Multiple ciphers
+contained in a string should be separated by a colon.
+
+.TP 5
+.I tlshosts/<FQDN>.pem
+.B qmail-remote
+requires authentication from servers for which this certificate exists
+.RB ( <FQDN>
+is the fully-qualified domain name of the server). One of the
+.I dNSName
+or the
+.I CommonName
+attributes have to match.
+
+.B WARNING:
+this option may cause mail to be delayed, bounced, doublebounced, or lost.
+
 .SH "SEE ALSO"
 addresses(5),
 envelopes(5),
diff -urN qmail-1.03-vanilla/qmail-remote.c qmail-1.03-md24/qmail-remote.c
--- qmail-1.03-vanilla/qmail-remote.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-remote.c	2007-07-19 23:01:53.000000000 +0200
@@ -1,7 +1,16 @@
+/*
+ * - esmtp size + auth + logging by me: http://www.mcmilk.de/qmail/
+ * - many other improvements
+ */
+
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+
 #include "sig.h"
 #include "stralloc.h"
 #include "substdio.h"
@@ -11,6 +20,7 @@
 #include "error.h"
 #include "auto_qmail.h"
 #include "control.h"
+#include "base64.h"
 #include "dns.h"
 #include "alloc.h"
 #include "quote.h"
@@ -19,7 +29,9 @@
 #include "ipme.h"
 #include "gen_alloc.h"
 #include "gen_allocdefs.h"
+#include "fmt.h"
 #include "str.h"
+#include "hmac.h"
 #include "now.h"
 #include "exit.h"
 #include "constmap.h"
@@ -30,61 +42,155 @@
 #include "timeoutwrite.h"
 
 #define HUGESMTPTEXT 5000
+unsigned long smtp_port = 25;
+unsigned long qmtp_port = 209;
 
-#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */
-unsigned long port = PORT_SMTP;
+char *name="qmail-remote";
+int ctl_log_fd=25; /* logging fd if >0 */
 
 GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
 GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
 static stralloc sauninit = {0};
 
+substdio ssin;
+substdio smtpto;
+substdio smtpfrom;
+
+struct constmap maproutes;
+struct constmap maprelays;
+struct constmap mapqroutes;
+
+stralloc outgoingip = {0};
 stralloc helohost = {0};
+stralloc qroutes = {0};
 stralloc routes = {0};
-struct constmap maproutes;
-stralloc host = {0};
+stralloc relays = {0};
 stralloc sender = {0};
+stralloc host = {0};
 
-saa reciplist = {0};
+stralloc authuser = {0};
+stralloc authpass = {0};
+stralloc authtype = {0};
+stralloc slop = {0};
+stralloc resp = {0};
+stralloc temp = {0};
+
+saa reciplist = {0};  /* list of recipients */
+saa ehlokw = {0};     /* list of EHLO keywords and parameters */
 
 struct ip_address partner;
+struct ip_address outip;
+
+/* auth stuff */
+unsigned char digest[21], encrypted[41];
+char hextab[]="0123456789abcdef";
+char *sasl[] = { "LOGIN","PLAIN","CRAM-MD5","CRAM-SHA1","CRAM-RIPEMD","DIGEST-MD5" };
+#define SASL_MAX 6
+int ehloflags = 0; /* */
+int authflags = 0; /* possible auth types, which are suported by client+server */
+int needauth = 0;  /* is set, when we have to authenticate */
+
+int client_auth_login(char *arg);
+int client_auth_plain(char *arg);
+int client_auth_cram_md5(char *arg);
+int client_auth_cram_rmd(char *arg);
+int client_auth_cram_sha1(char *arg);
+int client_auth_digest_md5(char *arg);
+int client_auth_notsupported(char *arg);
+
+typedef struct {
+  char *text;
+  int  (*fun)();
+} authcmd_t;
+
+authcmd_t authcmds[] = {
+  { "login",       client_auth_login }
+, { "plain",       client_auth_plain }
+, { "cram-md5",    client_auth_cram_md5 }
+, { "cram-ripemd", client_auth_cram_rmd }
+, { "cram-sha1",   client_auth_cram_sha1 }
+/* , { "digest-md5",  client_auth_digest_md5 } */
+, { 0,             client_auth_notsupported }
+};
+
+void quit(char *prepend, char *append);
+
+/* flush all buffers */
+void flush(void)
+{
+  substdio_flush(&smtpto);
+  substdio_flush(subfdoutsmall);
+  if (ctl_log_fd) substdio_flush(subfderr);
+}
 
-void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
-void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
-void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
-void outsafe(sa) stralloc *sa; { int i; char ch;
-for (i = 0;i < sa->len;++i) {
-ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
-if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
-
-void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
-void temp_oserr() { out("Z\
-System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); }
-void temp_noconn() { out("Z\
-Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); }
-void temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); }
-void temp_dnscanon() { out("Z\
-CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); }
-void temp_dns() { out("Z\
-Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie(); }
-void temp_chdir() { out("Z\
-Unable to switch to home directory. (#4.3.0)\n"); zerodie(); }
-void temp_control() { out("Z\
-Unable to read control files. (#4.3.0)\n"); zerodie(); }
-void perm_partialline() { out("D\
-SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); }
-void perm_usage() { out("D\
-I (qmail-remote) was invoked improperly. (#5.3.5)\n"); zerodie(); }
-void perm_dns() { out("D\
-Sorry, I couldn't find any host named ");
-outsafe(&host);
-out(". (#5.1.2)\n"); zerodie(); }
-void perm_nomx() { out("D\
-Sorry, I couldn't find a mail exchanger or IP address. (#5.4.4)\n");
-zerodie(); }
-void perm_ambigmx() { out("D\
-Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
-it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
-zerodie(); }
+void Logn(char *s, int n)
+{
+  if (ctl_log_fd)
+    if (substdio_put(subfderr,s,n) == -1) _exit(0);
+
+  return;
+}
+
+void Log(char *s)
+{
+  if (ctl_log_fd)
+    if (substdio_puts(subfderr,s) == -1) _exit(0);
+
+  return;
+}
+
+void smtp_to(char *s)
+{ if (substdio_puts(&smtpto,s) == -1) _exit(0); Log(s); }
+
+void smtp_nto(char *s, int n)
+{ if (substdio_put(&smtpto,s,n) == -1) _exit(0); Logn(s,n); }
+
+void smtp_eol(void)
+{
+  if (substdio_puts(subfderr, "\n") == -1) _exit(0);
+  if (substdio_puts(&smtpto, "\r\n") == -1) _exit(0);
+  flush();
+}
+
+void out(char *s)
+{
+  if (substdio_puts(subfdoutsmall,s) == -1) _exit(0);
+}
+
+void zero()
+{
+  if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0);
+}
+
+void zerodie() { zero(); flush(); _exit(0); }
+
+void outsafe(stralloc *sa)
+{
+  int i; char ch;
+  for (i = 0;i < sa->len;++i) {
+    ch = sa->s[i]; if (ch < 33) ch = '?';
+    if (ch > 126) ch = '?';
+    if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0);
+  }
+}
+
+void temp_noip()    { out("Z4.3.0 invalid ipaddr in control/outgoingip\n"); zerodie(); }
+void temp_nomem()   { out("Z4.3.0 Out of memory.\n"); zerodie(); }
+void temp_oserr()   { out("Z4.3.0 System resources temporarily unavailable.\n"); zerodie(); }
+void temp_noconn()  { out("Z4.4.1 Sorry, I wasn't able to establish an SMTP connection.\n"); zerodie(); }
+void temp_read()    { out("Z4.3.0 Unable to read message.\n"); zerodie(); }
+void temp_dnscanon(){ out("Z4.4.3 CNAME lookup failed temporarily.\n"); zerodie(); }
+void temp_dns()     { out("Z4.1.2 Sorry, I couldn't find any host by that name.\n"); zerodie(); }
+void temp_chdir()   { out("Z4.3.0 Unable to switch to home directory.\n"); zerodie(); }
+void temp_control() { out("Z4.3.0 Unable to read control files.\n"); zerodie(); }
+void temp_proto()   { out("Z4.3.0 recipient did not talk proper QMTP\n"); zerodie(); }
+
+void perm_pl()      { out("D5.6.2 SMTP cannot transfer messages with partial final lines.\n"); zerodie(); }
+void perm_usage()   { out("D5.3.5 I (qmail-remote) was invoked improperly.\n"); zerodie(); }
+void perm_dns()     { out("D5.1.2 Sorry, I couldn't find any host named ");outsafe(&host);out(".\n"); zerodie(); }
+void perm_nomx()    { out("D5.4.4 Sorry, I couldn't find a mail exchanger or IP address.\n"); zerodie(); }
+void perm_ambigmx() { out("D5.4.6 Sorry. Although I'm listed as a best-preference MX or A for that host,\n"
+                              "it isn't in my control/locals file, so I don't treat it as local.\n"); zerodie(); }
 
 void outhost()
 {
@@ -93,20 +199,17 @@
 }
 
 int flagcritical = 0;
+int timeoutconnect = 60;
+int smtpfd;
+int timeout = 1200;
 
 void dropped() {
-  out("ZConnected to ");
-  outhost();
-  out(" but connection died. ");
+  out("Z4.4.2 Connected to "); outhost(); out(" but connection died. ");
   if (flagcritical) out("Possible duplicate! ");
-  out("(#4.4.2)\n");
+  out("\n");
   zerodie();
 }
 
-int timeoutconnect = 60;
-int smtpfd;
-int timeout = 1200;
-
 int saferead(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
@@ -114,6 +217,7 @@
   if (r <= 0) dropped();
   return r;
 }
+
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
@@ -122,24 +226,44 @@
   return r;
 }
 
-char inbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
-char smtptobuf[1024];
-substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf);
-char smtpfrombuf[128];
+char inbuf[1624];
+char smtptobuf[1624];  /* out */
+char smtpfrombuf[1624]; /* in */
+
+substdio ssin     = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
+substdio smtpto   = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf);
 substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
 
 stralloc smtptext = {0};
 
-void get(ch)
-char *ch;
+void get(char *ch)
 {
   substdio_get(&smtpfrom,ch,1);
-  if (*ch != '\r')
-    if (smtptext.len < HUGESMTPTEXT)
-     if (!stralloc_append(&smtptext,ch)) temp_nomem();
+  if (*ch != '\r') {
+    if (smtptext.len < HUGESMTPTEXT) {
+      if (!stralloc_append(&smtptext,ch)) temp_nomem();
+      Logn(ch, 1);
+    }
+  }
+
+  return;
 }
 
+void doname(void)
+{
+  static int pid=0;
+  char pidstr[FMT_ULONG];
+
+  if (!pid) { pid=getpid(); }
+  pidstr[fmt_ulong(pidstr,pid)] = 0;
+  Log(name);Log(": pid ");Log(pidstr);Log(" ");
+
+  return;
+}
+
+void client(void) { doname(); Log("S: "); }
+void doserv(void) { doname(); Log("C: "); }
+
 unsigned long smtpcode()
 {
   unsigned char ch;
@@ -147,6 +271,7 @@
 
   if (!stralloc_copys(&smtptext,"")) temp_nomem();
 
+  client();
   get(&ch); code = ch - '0';
   get(&ch); code = code * 10 + (ch - '0');
   get(&ch); code = code * 10 + (ch - '0');
@@ -154,18 +279,189 @@
     get(&ch);
     if (ch != '-') break;
     while (ch != '\n') get(&ch);
-    get(&ch);
-    get(&ch);
-    get(&ch);
+    client();
+    get(&ch); get(&ch); get(&ch);
   }
   while (ch != '\n') get(&ch);
+  flush();
 
   return code;
 }
 
+#define ERR_AUTH_FAILED 1
+#define ERR_AUTH_INPUT  2
+#define ERR_AUTH_ABORT  3
+
+/* AUTH LOGIN with long form */
+int client_auth_login(char *arg)
+{
+  doserv(); smtp_to("AUTH LOGIN"); smtp_eol();
+  if (smtpcode() != 334) return ERR_AUTH_FAILED;
+
+  if (!stralloc_copy(&slop, &authuser)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+  doserv(); smtp_nto(temp.s, temp.len); smtp_eol();
+  if (smtpcode() != 334) return ERR_AUTH_FAILED;
+
+  if (!stralloc_copy(&slop, &authpass)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+  doserv(); smtp_nto(temp.s, temp.len); smtp_eol();
+  if (smtpcode() != 235) return ERR_AUTH_FAILED;
+
+  return 0;
+}
+
+/* AUTH PLAIN in short form */
+int client_auth_plain(char *arg)
+{
+  if (!stralloc_0(&slop)) temp_nomem();
+  if (!stralloc_cat(&slop, &authuser)) temp_nomem();
+  if (!stralloc_0(&slop)) temp_nomem();
+  if (!stralloc_cat(&slop, &authpass)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+
+  doserv(); smtp_to("AUTH PLAIN "); smtp_nto(temp.s, temp.len); smtp_eol();
+  if (smtpcode() != 235) return ERR_AUTH_FAILED;
+
+  return 0;
+}
+
+int client_auth_cram_md5(char *arg)
+{
+  unsigned int code;
+  unsigned char *e=encrypted;
+  int i;
+
+  doserv(); smtp_to("AUTH CRAM-MD5"); smtp_eol();
+  code = smtpcode();
+  if (code != 334) return ERR_AUTH_FAILED;
+  if (b64decode(&resp, smtptext.s+4, smtptext.len-5) != 0)
+    return ERR_AUTH_INPUT;
+  resp.s[resp.len]=0;
+
+  hmac_md5(resp.s, authpass.s, digest);
+  for (i=0; i<16; i++) {
+    *e = hextab[digest[i]/16]; ++e;
+    *e = hextab[digest[i]%16]; ++e;
+  } *e=0;
+
+  if (!stralloc_copy(&slop, &authuser)) temp_nomem();
+  if (!stralloc_cats(&slop, " ")) temp_nomem();
+  if (!stralloc_cats(&slop, encrypted)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+
+  doserv(); smtp_nto(temp.s, temp.len); smtp_eol();
+  code = smtpcode();
+  if (code != 235) return ERR_AUTH_FAILED;
+
+  return 0;
+}
+
+int client_auth_cram_sha1(char *arg)
+{
+  unsigned int code;
+  unsigned char *e=encrypted;
+  int i;
+
+  doserv(); smtp_to("AUTH CRAM-SHA1"); smtp_eol();
+  code = smtpcode();
+  if (code != 334) return ERR_AUTH_FAILED;
+  if (b64decode(&resp, smtptext.s+4, smtptext.len-5) != 0)
+    return ERR_AUTH_INPUT;
+  resp.s[resp.len]=0;
+
+  hmac_sha1(resp.s, authpass.s, digest);
+  for (i=0; i<20; i++) {
+    *e = hextab[digest[i]/16]; ++e;
+    *e = hextab[digest[i]%16]; ++e;
+  } *e=0;
+
+  if (!stralloc_copy(&slop, &authuser)) temp_nomem();
+  if (!stralloc_cats(&slop, " ")) temp_nomem();
+  if (!stralloc_cats(&slop, encrypted)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+
+  doserv(); smtp_nto(temp.s, temp.len); smtp_eol();
+  code = smtpcode();
+  if (code != 235) return ERR_AUTH_FAILED;
+
+  return 0;
+}
+
+int client_auth_cram_rmd(char *arg)
+{
+  unsigned int code;
+  unsigned char *e=encrypted;
+  int i;
+
+  doserv(); smtp_to("AUTH CRAM-RIPEMD"); smtp_eol();
+  code = smtpcode();
+  if (code != 334) return ERR_AUTH_FAILED;
+  if (b64decode(&resp, smtptext.s+4, smtptext.len-5) != 0)
+    return ERR_AUTH_INPUT;
+  resp.s[resp.len]=0;
+
+  hmac_ripemd(resp.s, authpass.s, digest);
+  for (i=0; i<20; i++) {
+    *e = hextab[digest[i]/16]; ++e;
+    *e = hextab[digest[i]%16]; ++e;
+  } *e=0;
+
+  if (!stralloc_copy(&slop, &authuser)) temp_nomem();
+  if (!stralloc_cats(&slop, " ")) temp_nomem();
+  if (!stralloc_cats(&slop, encrypted)) temp_nomem();
+  if (b64encode(&temp, &slop) != 0) return ERR_AUTH_INPUT;
+
+  doserv(); smtp_nto(temp.s, temp.len); smtp_eol();
+  code = smtpcode();
+  if (code != 235) return ERR_AUTH_FAILED;
+
+  return 0;
+}
+
+/* XXX */
+int client_auth_digest_md5(char *arg)
+{
+  unsigned int code;
+
+  doserv(); smtp_to("AUTH DIGEST-MD5"); smtp_eol();
+  code = smtpcode();
+  return 0;
+}
+
+int client_auth_notsupported(char *arg)
+{
+  quit("DConnected to "," but can't do authentication with of that type!");
+  return 1;
+}
+
+void doauth(char *arg)
+{
+  int i;
+
+//  doname(); Log("trying auth with: "); Log(arg); Log(" ...\n"); flush();
+  for (i=0; authcmds[i].text; ++i)
+    if (case_equals(authcmds[i].text, arg)) break;
+  if (!stralloc_copys(&resp, "")) temp_nomem();
+  if (!stralloc_copys(&slop, "")) temp_nomem();
+  if (!stralloc_copys(&temp, "")) temp_nomem();
+  switch (authcmds[i].fun(arg)) {
+    case 0: return;
+    case ERR_AUTH_INPUT:
+      quit("DConnected to "," but we got incorrect authentication input!");
+      break;
+    case ERR_AUTH_FAILED:
+      quit("DConnected to "," but authentication failed!");
+      break;
+    case ERR_AUTH_ABORT:
+      quit("DConnected to "," but aborted!");
+      break;
+  }
+}
+
 void outsmtptext()
 {
-  int i; 
+  int i;
   if (smtptext.s) if (smtptext.len) {
     out("Remote host said: ");
     for (i = 0;i < smtptext.len;++i)
@@ -175,16 +471,16 @@
   }
 }
 
-void quit(prepend,append)
-char *prepend;
-char *append;
+void quit(char *prepend, char *append)
 {
-  substdio_putsflush(&smtpto,"QUIT\r\n");
-  /* waiting for remote side is just too ridiculous */
+  doserv();
+  smtp_to("QUIT");
   out(prepend);
   outhost();
   out(append);
   out(".\n");
+  smtp_eol();
+
   outsmtptext();
   zerodie();
 }
@@ -203,47 +499,165 @@
     while (ch != '\n') {
       substdio_put(&smtpto,&ch,1);
       r = substdio_get(&ssin,&ch,1);
-      if (r == 0) perm_partialline();
+      if (r == 0) perm_pl();
       if (r == -1) temp_read();
     }
     substdio_put(&smtpto,"\r\n",2);
   }
- 
+
   flagcritical = 1;
   substdio_put(&smtpto,".\r\n",3);
-  substdio_flush(&smtpto);
+  doserv(); Log("[...]\n"); flush();
 }
 
-stralloc recip = {0};
+char *partner_fqdn = 0;
 
-void smtp()
+#define F_EHLO_AUTH  0x01
+#define F_EHLO_SIZE  0x02
+int maxehlokwlen=0;
+unsigned long ehlo()
 {
+  stralloc *sa;
+  char *s, *e, *p;
   unsigned long code;
-  int flagbother;
-  int i;
- 
-  if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
- 
-  substdio_puts(&smtpto,"HELO ");
-  substdio_put(&smtpto,helohost.s,helohost.len);
-  substdio_puts(&smtpto,"\r\n");
-  substdio_flush(&smtpto);
-  if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
- 
-  substdio_puts(&smtpto,"MAIL FROM:<");
-  substdio_put(&smtpto,sender.s,sender.len);
-  substdio_puts(&smtpto,">\r\n");
-  substdio_flush(&smtpto);
+
+  if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
+  ehlokw.len = 0;
+
+  doserv();
+  smtp_to("EHLO ");
+  smtp_nto(helohost.s, helohost.len);
+  smtp_eol();
+
+  code = smtpcode();
+  if (code != 250) return code;
+
+  s = smtptext.s;
+  while (*s++ != '\n') ; /* skip the first line: contains the domain */
+
+  e = smtptext.s + smtptext.len - 6; /* 250-?\n */
+  while (s <= e)
+  {
+    if (!saa_readyplus(&ehlokw, 1)) temp_nomem();
+    sa = ehlokw.sa + ehlokw.len++;
+    if (ehlokw.len > maxehlokwlen) *sa = sauninit; else sa->len = 0;
+
+    /* smtptext is known to end in a '\n' */
+    for (p = (s += 4); ; ++p)
+      if (*p == '\n' || *p == ' ' || *p == '\t') {
+        if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
+        if (*p++ == '\n') break;
+        while (*p == ' ' || *p == '\t') p++;
+        s = p;
+      }
+    s = p;
+    /* keyword should consist of alpha-num and '-'
+     * broken AUTH might use '=' instead of space */
+    for (p = sa->s; *p; ++p) if (*p == '=') { *p = 0; break; }
+  }
+
+  return 250;
+}
+
+void smtp(char *size)
+{
+  unsigned long code=0;
+  int flagbother, i;
+
+  code = smtpcode();
+  if (code >= 400 && code < 600) return; /* try next MX, see RFC-2821 */
+  if (code != 220) quit("ZConnected to "," but greeting failed");
+
+  //doname(); Log("stelle1"); Log("\n"); flush();
+  code = ehlo();
+  if (code == 250) {
+    if (ehlokw.len)
+    for (i=0; i<ehlokw.len; i++) {
+      char *x=ehlokw.sa[i].s;
+      char f[FMT_ULONG];
+      f[fmt_ulong(f, ehlokw.len)]=0;
+      ehlokw.sa[i].s[ehlokw.sa[i].len]=0;
+      //doname(); Log("stelle2"); Log("\n"); flush();
+      //doname(); Log("ehlokw.len="); Log(f); Log("\n"); flush();
+      switch (strlen(x)) {
+      case 4:
+	/* does the server support ESMTP AUTH? */
+        if (case_equals(x, "AUTH")) {
+	  ehloflags |= F_EHLO_AUTH;
+	  /* scan for possible auth types */
+	  while (x += strlen(x)+1) {
+	    int j;
+	    for (j = 0; authcmds[j].text; ++j) {
+              if (case_equals(authcmds[j].text, x)) {
+	        authflags |= 1<<j; break;
+	      }
+	    }
+	    if (x - ehlokw.sa[i].s >= ehlokw.sa[i].len) break;
+	  }
+	  break;
+	}
+	/* does the server support ESMTP SIZE? */
+        if (case_equals(x, "SIZE")) ehloflags |= F_EHLO_SIZE;
+        break;
+      }
+    }
+  } else {
+    /* EHLO failed, we will try it with HELO */
+    doserv();
+    smtp_to("HELO ");
+    smtp_nto(helohost.s, helohost.len);
+    smtp_eol();
+    if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+  }
+
+  //doname(); Log("stelle3"); Log("\n"); flush();
+
+  /* if needed, we authenticate now */
+  if (needauth) {
+    if (authtype.len) {
+      /* smtprelays gives us a mechanism */
+      authtype.s[authtype.len]=0; doauth(authtype.s);
+    } else if (ehloflags & F_EHLO_AUTH) {
+      for (i=SASL_MAX; i>=0; i--) {
+        if ((authflags & 1<<i) == 1<<i) {
+          doauth(sasl[i]); break;
+        }
+      }
+    } else {
+      /* - server does not support EHLO
+       * - take authtype from smtprelays or NOTHING!
+       */
+      if (!authtype.len) {
+        quit("DConnected to "," but can't do required authentication / give me a hint in control/smtprelays!");
+      }
+      authtype.s[authtype.len]=0; doauth(authtype.s);
+    }
+  }
+
+  //doname(); Log("stelle4"); Log("\n"); flush();
+
+  doserv();
+  smtp_to("MAIL FROM:<");
+  smtp_nto(sender.s,sender.len);
+  smtp_to(">");
+  if (ehloflags & F_EHLO_SIZE) {
+    smtp_to(" SIZE=");
+    smtp_to(size);
+  }
+  smtp_eol();
+
   code = smtpcode();
   if (code >= 500) quit("DConnected to "," but sender was rejected");
   if (code >= 400) quit("ZConnected to "," but sender was rejected");
- 
+
   flagbother = 0;
   for (i = 0;i < reciplist.len;++i) {
-    substdio_puts(&smtpto,"RCPT TO:<");
-    substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len);
-    substdio_puts(&smtpto,">\r\n");
-    substdio_flush(&smtpto);
+    doserv();
+    smtp_to("RCPT TO:<");
+    smtp_nto(reciplist.sa[i].s, reciplist.sa[i].len);
+    smtp_to(">");
+    smtp_eol();
+
     code = smtpcode();
     if (code >= 500) {
       out("h"); outhost(); out(" does not like recipient.\n");
@@ -259,33 +673,142 @@
     }
   }
   if (!flagbother) quit("DGiving up on ","");
- 
-  substdio_putsflush(&smtpto,"DATA\r\n");
+
+  doserv();
+  smtp_to("DATA");
+  smtp_eol();
+
   code = smtpcode();
   if (code >= 500) quit("D"," failed on DATA command");
   if (code >= 400) quit("Z"," failed on DATA command");
- 
+
   blast();
   code = smtpcode();
+
   flagcritical = 0;
   if (code >= 500) quit("D"," failed after I sent the message");
   if (code >= 400) quit("Z"," failed after I sent the message");
   quit("K"," accepted message");
 }
 
+int qmtp_priority(int pref)
+{
+  if (pref < 12800) return 0;
+  if (pref > 13055) return 0;
+  if (pref % 16 == 1) return 1;
+  return 0;
+}
+
+void qmtp()
+{
+  struct stat st;
+  unsigned long len;
+  char *x;
+  int i, n;
+  unsigned char ch;
+  char num[FMT_ULONG];
+  int flagallok;
+
+  if (fstat(0,&st) == -1) quit("Z", " unable to fstat stdin");
+  len = st.st_size;
+
+  num[fmt_ulong(num,len+1)]=0;
+  doserv();
+  smtp_to(num);
+  smtp_to(":\n");
+  while (len > 0) {
+    n = substdio_feed(&ssin);
+    if (n <= 0) _exit(32); /* wise guy again */
+    x = substdio_PEEK(&ssin);
+    smtp_nto(x,n);
+    substdio_SEEK(&ssin,n);
+    len -= n;
+  }
+  smtp_to(",");
+
+  len = sender.len;
+  num[fmt_ulong(num,len)]=0;
+  smtp_to(num);
+  smtp_to(":");
+  smtp_nto(sender.s,sender.len);
+  smtp_to(",");
+
+  len = 0;
+  for (i = 0;i < reciplist.len;++i)
+    len += fmt_ulong(num,reciplist.sa[i].len) + 1 + reciplist.sa[i].len + 1;
+    num[fmt_ulong(num,len)]=0;
+    smtp_to(num);
+    smtp_to(":");
+  for (i = 0;i < reciplist.len;++i) {
+      num[fmt_ulong(num,reciplist.sa[i].len)]=0;
+      smtp_to(num);
+      smtp_to(":");
+      smtp_nto(reciplist.sa[i].s,reciplist.sa[i].len);
+      smtp_to(",");
+  }
+  smtp_to(",");
+  flush();
+
+  flagallok = 1;
+
+  for (i = 0;i < reciplist.len;++i) {
+    len = 0;
+    for (;;) {
+      get(&ch);
+      if (ch == ':') break;
+      if (len > 200000000) temp_proto();
+      if (ch - '0' > 9) temp_proto();
+      len = 10 * len + (ch - '0');
+    }
+    if (!len) temp_proto();
+    get(&ch); --len;
+    if ((ch != 'Z') && (ch != 'D') && (ch != 'K')) temp_proto();
+
+    if (!stralloc_copyb(&smtptext,&ch,1)) temp_proto();
+    if (!stralloc_cats(&smtptext,"qmtp: ")) temp_nomem();
+
+    while (len > 0) { get(&ch); --len; }
+
+    for (len = 0;len < smtptext.len;++len) {
+      ch = smtptext.s[len];
+      if ((ch < 32) || (ch > 126)) smtptext.s[len] = '?';
+    }
+    get(&ch);
+    if (ch != ',') temp_proto();
+    smtptext.s[smtptext.len-1] = '\n';
+
+    if (smtptext.s[0] == 'K') out("r");
+    else if (smtptext.s[0] == 'D') {
+      out("h");
+      flagallok = 0;
+    } else {
+      out("s");
+      flagallok = 0;
+    }
+    smtp_nto(smtptext.s+1, smtptext.len-1);
+    zero();
+  }
+  if (!flagallok) {
+    out("DGiving up on ");outhost();out("\n");
+  } else {
+    out("KAll received okay by ");outhost();out("\n");
+  }
+  zerodie();
+}
+
 stralloc canonhost = {0};
 stralloc canonbox = {0};
 
 void addrmangle(saout,s,flagalias,flagcname)
-stralloc *saout; /* host has to be canonical, box has to be quoted */
-char *s;
-int *flagalias;
-int flagcname;
+  stralloc *saout; /* host has to be canonical, box has to be quoted */
+  char *s;
+  int *flagalias;
+  int flagcname;
 {
   int j;
- 
+
   *flagalias = flagcname;
- 
+
   j = str_rchr(s,'@');
   if (!s[j]) {
     if (!stralloc_copys(saout,s)) temp_nomem();
@@ -295,12 +818,12 @@
   canonbox.len = j;
   if (!quote(saout,&canonbox)) temp_nomem();
   if (!stralloc_cats(saout,"@")) temp_nomem();
- 
+
   if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem();
   if (flagcname)
     switch(dns_cname(&canonhost)) {
       case 0: *flagalias = 0; break;
-      case DNS_MEM: temp_nomem();
+      case DNS_MEM:  temp_nomem();
       case DNS_SOFT: temp_dnscanon();
       case DNS_HARD: ; /* alias loop, not our problem */
     }
@@ -310,118 +833,264 @@
 
 void getcontrols()
 {
-  if (control_init() == -1) temp_control();
-  if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
-  if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
+  if (control_init() == -1)
     temp_control();
-  if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1)
-    temp_control();
-  switch(control_readfile(&routes,"control/smtproutes",0)) {
+
+  if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1) temp_control();
+  if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
+  if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1) temp_control();
+
+  switch (control_readfile(&routes,"control/smtproutes",0)) {
+    case -1:
+      temp_control();
+      break;
+    case 0:
+      if (!constmap_init(&maproutes,"",0,1)) temp_nomem();
+      break;
+    case 1:
+      if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem();
+      break;
+  }
+
+  switch (control_readfile(&relays,"control/smtprelays",0)) {
+    case -1:
+      temp_control();
+      break;
+    case 0:
+      if (!constmap_init(&maprelays,"",0,1)) temp_nomem();
+      break;
+    case 1:
+      if (!constmap_init(&maprelays,relays.s,relays.len,1)) temp_nomem();
+      break;
+  }
+
+  switch (control_readfile(&qroutes,"control/qmtproutes",0)) {
     case -1:
       temp_control();
+      break;
     case 0:
-      if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break;
+      if (!constmap_init(&mapqroutes,"",0,1)) temp_nomem();
+      break;
     case 1:
-      if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
+      if (!constmap_init(&mapqroutes,qroutes.s,qroutes.len,1)) temp_nomem();
+      break;
+  }
+
+  switch (control_readline(&outgoingip,"control/outgoingip")) {
+    case -1:
+      if (errno == error_nomem) temp_nomem();
+      temp_control();
+      break;
+    case 0:
+      if (!stralloc_copys(&outgoingip, "0.0.0.0")) temp_nomem();
+      break;
   }
+  if (str_equal(outgoingip.s, "0.0.0.0")) {
+    outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long)0;
+  } else if (!ip_scan(outgoingip.s, &outip)) temp_noip();
+
+  /* logging */
+  if (control_readint(&ctl_log_fd,"control/log/remote_fd") == -1) temp_control();
+  if (ctl_log_fd  < 0) ctl_log_fd=0;
+  if (ctl_log_fd) subfderr->fd = ctl_log_fd;
+
+  return;
 }
 
-void main(argc,argv)
-int argc;
-char **argv;
+
+int main(int argc, char **argv)
 {
   static ipalloc ip = {0};
-  int i;
-  unsigned long random;
+  unsigned long random, prefme;
   char **recips;
-  unsigned long prefme;
-  int flagallaliases;
-  int flagalias;
-  char *relayhost;
- 
+  char *relayhost=0, *relayuser=0;
+  int flagallaliases, flagalias, flagqmtp=0;
+  int i;
+
   sig_pipeignore();
-  if (argc < 4) perm_usage();
+  if (argc < 5) perm_usage();
   if (chdir(auto_qmail) == -1) temp_chdir();
   getcontrols();
- 
- 
+
   if (!stralloc_copys(&host,argv[1])) temp_nomem();
- 
-  relayhost = 0;
-  for (i = 0;i <= host.len;++i)
+  if (!stralloc_copys(&authuser,"")) temp_nomem();
+  if (!stralloc_copys(&authpass,"")) temp_nomem();
+  if (!stralloc_copys(&authtype,"")) temp_nomem();
+  addrmangle(&sender, argv[2], &flagalias, 0);
+
+/*
+ * smtprelays: mailuser@host.domain:virtual-relay|authuser|authpass|authtype
+ *             mailuser@host.domain:virtual-relay
+ *             mailuser@host.domain:relaysmtp|authuser|authpass|authtype
+ *
+ * smtproutes: virtual-relay:host.domain
+ *             virtual-relay:host.domain:port
+ *             host.domain:host2.domain
+ *
+ * qmtproutes: virtual-relay:host.domain
+ *             virtual-relay:host.domain:port
+ *             host.domain:host2.domain
+ */
+
+  /* control/smtprelays */
+  for (i = 0; i <= sender.len; ++i)
+    if ((i == 0) || (i == sender.len) || (sender.s[i] == '.'))
+      if ((relayuser = constmap(&maprelays, sender.s + i, sender.len - i))) break;
+  if (relayuser && !*relayuser) relayuser = 0;
+
+  if (relayuser) {
+    /* V1|mcmilk|password2 */
+    /* V2|mcmilk|password2|cram-md5 */
+    char *x=relayuser, *y;
+
+    y=x;
+    /* forwards also non password users to virtual servers in smtproutes */
+    while (*++x) if (*x == '|' || !*x) break;
+    if (!stralloc_copyb(&host, y, x-y)) temp_nomem();
+
+    y=x;
+    if (*x == '|') while (*++x) if (*x == '|' || !*x) {
+      if (!stralloc_copyb(&authuser, y+1, x-y-1)) temp_nomem();
+      authuser.s[authuser.len]=0; break;
+    }
+
+    y=x;
+    if (*x == '|') while (*++x) if (*x == '|' || !*x) {
+      if (!stralloc_copyb(&authpass, y+1, x-y-1)) temp_nomem();
+      authpass.s[authpass.len]=0; break;
+    }
+
+    /* authuser is given, so we need a password! */
+    if (authuser.len && !authpass.len) temp_control();
+    if (authuser.len && authpass.len) needauth=1;
+
+    y=x;
+    /* optional authtype, so we don't have to parse the ehlo resp. */
+    if (*x == '|') {
+      while (*++x);
+      if (!stralloc_copyb(&authtype, y+1, x-y-1)) temp_nomem();
+    }
+ }
+#if 0
+    //if (relayhost) { doname(); Log("DEBUG1: relayhost=");  Log(relayhost); Log("\n"); }
+    //if (relayuser) { doname(); Log("DEBUG1: relayuser=");  Log(relayuser); Log("\n"); }
+    doname(); Log("DEBUG1: host=");       Logn(host.s, host.len); Log("\n");
+    doname(); Log("DEBUG1: authuser=");   Logn(authuser.s, authuser.len); Log("\n");
+    doname(); Log("DEBUG1: authpass=");   Logn(authpass.s, authpass.len); Log("\n");
+    doname(); Log("DEBUG1: authtype=");   Logn(authtype.s, authtype.len); Log("\n");
+    flush();
+#endif
+
+  /* control/smtproutes */
+  for (i = 0; i <= host.len; ++i)
     if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
-      if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
-        break;
+      if ((relayhost = constmap(&maproutes,host.s + i,host.len - i))) break;
   if (relayhost && !*relayhost) relayhost = 0;
- 
+
   if (relayhost) {
     i = str_chr(relayhost,':');
     if (relayhost[i]) {
-      scan_ulong(relayhost + i + 1,&port);
+      scan_ulong(relayhost + i + 1, &smtp_port);
       relayhost[i] = 0;
     }
     if (!stralloc_copys(&host,relayhost)) temp_nomem();
+  } else {
+    /* control/qmtproutes */
+    for (i = 0; i <= host.len; ++i)
+      if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
+        if ((relayhost = constmap(&mapqroutes,host.s + i,host.len - i))) break;
+    if (relayhost && !*relayhost) relayhost = 0;
+
+    if (relayhost) {
+      i = str_chr(relayhost,':');
+      if (relayhost[i]) {
+        scan_ulong(relayhost + i + 1, &qmtp_port);
+        relayhost[i] = 0;
+      }
+      if (!stralloc_copys(&host,relayhost)) temp_nomem();
+      flagqmtp=1;
+    }
   }
 
+#if 0
+    //if (relayhost) { doname(); Log("DEBUG2: relayhost=");  Log(relayhost); Log("\n"); }
+    //if (relayuser) { doname(); Log("DEBUG2: relayuser=");  Log(relayuser); Log("\n"); }
+    doname(); Log("DEBUG2: host=");     Logn(host.s, host.len); Log("\n");
+    doname(); Log("DEBUG2: authuser="); Logn(authuser.s, authuser.len); Log("\n");
+    doname(); Log("DEBUG2: authpass="); Logn(authpass.s, authpass.len); Log("\n");
+    doname(); Log("DEBUG2: authtype="); Logn(authtype.s, authtype.len); Log("\n");
+    flush();
+#endif
 
-  addrmangle(&sender,argv[2],&flagalias,0);
- 
   if (!saa_readyplus(&reciplist,0)) temp_nomem();
   if (ipme_init() != 1) temp_oserr();
- 
+
   flagallaliases = 1;
-  recips = argv + 3;
+  recips = argv + 4;
   while (*recips) {
     if (!saa_readyplus(&reciplist,1)) temp_nomem();
     reciplist.sa[reciplist.len] = sauninit;
-    addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost);
+    addrmangle(reciplist.sa + reciplist.len, *recips, &flagalias, !relayhost);
     if (!flagalias) flagallaliases = 0;
     ++reciplist.len;
     ++recips;
   }
 
- 
   random = now() + (getpid() << 16);
-  switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) {
-    case DNS_MEM: temp_nomem();
+  switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip, &host, random)) {
+    case DNS_MEM:  temp_nomem();
     case DNS_SOFT: temp_dns();
     case DNS_HARD: perm_dns();
-    case 1:
-      if (ip.len <= 0) temp_dns();
+    case 1: if (ip.len <= 0) temp_dns();
   }
- 
+
   if (ip.len <= 0) perm_nomx();
- 
+
   prefme = 100000;
   for (i = 0;i < ip.len;++i)
     if (ipme_is(&ip.ix[i].ip))
       if (ip.ix[i].pref < prefme)
         prefme = ip.ix[i].pref;
- 
+
   if (relayhost) prefme = 300000;
   if (flagallaliases) prefme = 500000;
- 
+
   for (i = 0;i < ip.len;++i)
-    if (ip.ix[i].pref < prefme)
-      break;
- 
-  if (i >= ip.len)
-    perm_ambigmx();
- 
-  for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) {
+    if (ip.ix[i].pref < prefme) break;
+  if (i >= ip.len) perm_ambigmx();
+
+  for (i = 0; i < ip.len; ++i)
+  if (ip.ix[i].pref < prefme) {
     if (tcpto(&ip.ix[i].ip)) continue;
- 
+
     smtpfd = socket(AF_INET,SOCK_STREAM,0);
     if (smtpfd == -1) temp_oserr();
- 
-    if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
+
+    /* 1. try qmtp */
+    if (flagqmtp || qmtp_priority(ip.ix[i].pref)) {
+      if (timeoutconn(smtpfd, &ip.ix[i].ip, &outip,
+        (unsigned int) qmtp_port, timeoutconnect) == 0) {
+        tcpto_err(&ip.ix[i].ip,0);
+        partner = ip.ix[i].ip;
+        qmtp(); /* does normally not return */
+      }
+      close(smtpfd);
+      smtpfd = socket(AF_INET,SOCK_STREAM,0);
+      if (smtpfd == -1) temp_oserr();
+    }
+
+    /* 2. try smtp, for all possible mx records! */
+    if (timeoutconn(smtpfd, &ip.ix[i].ip, &outip,
+      (unsigned int) smtp_port, timeoutconnect) == 0) {
       tcpto_err(&ip.ix[i].ip,0);
       partner = ip.ix[i].ip;
-      smtp(); /* does not return */
+      partner_fqdn = ip.ix[i].fqdn;
+      smtp(argv[3]); /* next MX is to be tried */
     }
     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
     close(smtpfd);
   }
-  
+
   temp_noconn();
+  return 111; /* gcc */
 }
diff -urN qmail-1.03-vanilla/qmail-rspawn.c qmail-1.03-md24/qmail-rspawn.c
--- qmail-1.03-vanilla/qmail-rspawn.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-rspawn.c	2007-07-19 20:56:22.000000000 +0200
@@ -4,6 +4,7 @@
 #include "exit.h"
 #include "fork.h"
 #include "error.h"
+#include "fmt.h"
 #include "tcpto.h"
 
 void initialize(argc,argv)
@@ -77,18 +78,20 @@
     }
 }
 
-int spawn(fdmess,fdout,s,r,at)
-int fdmess; int fdout;
-char *s; char *r; int at;
+int
+spawn(int fdmess, int fdout, unsigned long msgsize, char *s, char *r, int at)
 {
  int f;
- char *(args[5]);
+ char *(args[6]);
+ char size_buf[FMT_ULONG];
 
+ size_buf[fmt_ulong(size_buf, msgsize)] = 0;
  args[0] = "qmail-remote";
  args[1] = r + at + 1;
  args[2] = s;
- args[3] = r;
- args[4] = 0;
+ args[3] = size_buf;
+ args[4] = r;
+ args[5] = 0;
 
  if (!(f = vfork()))
   {
diff -urN qmail-1.03-vanilla/qmail-sasl.c qmail-1.03-md24/qmail-sasl.c
--- qmail-1.03-vanilla/qmail-sasl.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/qmail-sasl.c	2007-08-12 10:42:00.000000000 +0200
@@ -0,0 +1,429 @@
+
+#include <string.h>
+#include "qmail-sasl.h"
+
+const char hextab[]="0123456789abcdef";
+char *sasl[] = { "LOGIN","PLAIN","CRAM-MD5","CRAM-SHA1","CRAM-RIPEMD","DIGEST-MD5" };
+char unique[FMT_ULONG + FMT_ULONG + 3];
+
+int auth_for=0; /* MODE_POPUP / MODE_SMTPD */
+
+substdio ssauth;
+stralloc auth = {0}; /* incoming from client */
+stralloc user = {0}; /* username */
+stralloc pass = {0}; /* password */
+stralloc resp = {0}; /* response */
+stralloc slop = {0};
+
+authcmd_t authcmds[] = {
+  { "login",           auth_login }
+, { "plain",           auth_plain }
+, { "cram-md5",        auth_cram_md5 }
+, { "cram-sha1",       auth_cram_sha1 }
+, { "cram-ripemd",     auth_cram_rmd }
+, { "digest-md5",      auth_digest_md5 }
+, { 0,                 err_noauth }
+};
+
+int authgetl(void) {
+  int i;
+
+  if (!stralloc_copys(&auth, "")) die_nomem();
+  for (;;) {
+    if (!stralloc_readyplus(&auth,1)) die_nomem();
+    i = substdio_get(&ssin,auth.s + auth.len,1);
+    if (i != 1) die_read();
+    if (auth.s[auth.len] == '\n') break;
+    ++auth.len;
+  }
+
+  if (auth.len > 0) if (auth.s[auth.len - 1] == '\r') --auth.len;
+  auth.s[auth.len] = 0;
+  doname();Log("C: ");Log(auth.s);Log("\n");
+
+  if (*auth.s == '*' && *(auth.s + 1) == 0) { return ERR_AUTH_ABORT; }
+  if (auth.len == 0) { return ERR_AUTH_INPUT; }
+
+  return auth.len;
+}
+
+/* method:
+ * 0 = login / plain / cram
+ * 1 = digest-md5
+ */
+#define METHOD_DIGEST_MD5 1
+int authenticate(int method)
+{
+  char upbuf[512];
+  int child, wstat, pi[2];
+
+  if (!stralloc_0(&user)) die_nomem();
+  if (!stralloc_0(&pass)) die_nomem();
+  if (!stralloc_0(&resp)) die_nomem();
+
+  if (env_get("DEBUG_AUTH")) {
+    Log("SASL user:");Log(user.s);Log("\n");
+    Log("SASL pass:");Log(pass.s);Log("\n");
+    Log("SASL resp:");Log(resp.s);Log("\n");
+  }
+  flush();
+
+  /* if (fd_copy(2,1) == -1) die_pipe(); */
+  close(3);
+  if (pipe(pi) == -1) die_pipe();
+  if (pi[0] != 3) die_pipe();
+  switch (child = fork()) {
+    case -1:
+      die_fork();
+      break;
+    case 0:
+      close(pi[1]);
+      sig_pipedefault();
+      execvp(*childargs, childargs);
+      break;
+  }
+  close(pi[0]);
+
+  substdio_fdbuf(&ssauth,safewrite,pi[1],upbuf,sizeof upbuf);
+  if (substdio_put(&ssauth,user.s,user.len) == -1) die_write();
+  if (substdio_put(&ssauth,pass.s,pass.len) == -1) die_write();
+  if (substdio_put(&ssauth,resp.s,resp.len) == -1) die_write();
+  if (substdio_flush(&ssauth) == -1) die_write();
+
+  close(pi[1]);
+  byte_zero(pass.s,pass.len);
+  byte_zero(upbuf,sizeof upbuf);
+  if (wait_pid(&wstat,child) == -1) die_child();
+  if (wait_crashed(wstat)) die_child();
+  if (wait_exitcode(wstat)) {
+    sleep(ctl_auth_delay); /* wait seconds, defined @ control/auth/delay */
+    return ERR_AUTH_FAILED;
+  } /* bad auth */
+
+  /* qmail-pop3d handles it self */
+  if (auth_for != MODE_SMTPD) return 0;
+
+  /* qmail-smtpd auth: */
+  if (method == METHOD_DIGEST_MD5) {
+    /* digest-md5 requires a special okay response ... */
+    int fd=open_read(resp.s);
+    if (read(fd, &upbuf, 33) != 32) {
+      close(fd);
+      return ERR_AUTH_FAILED;
+    }
+    close(fd); unlink(resp.s);
+    upbuf[32]=0;
+    stralloc_copys(&slop, "rspauth=");
+    stralloc_cats(&slop, upbuf);
+    slop.s[slop.len]=0;
+    b64encode(&resp,&slop);
+    resp.s[resp.len]=0;
+    doserv();out("334 ");out(resp.s);doeol();flush();
+    if (authgetl() < 0) return ERR_AUTH_INPUT;
+  }
+  doserv(); out("235 2.0.0 auth for "); out(user.s); out(" ok, go ahad");
+  doeol(); flush();
+
+  /* yes, good auth done */
+  return 0;
+}
+
+/* user+pass is set */
+int auth_login(char *arg)
+{
+   /* some clients do: 'auth login b64(username)', some not */
+  if (*arg) {
+    if (b64decode(&user,arg,str_len(arg)) != 0)
+      return ERR_AUTH_INPUT;
+  } else {
+    /* Username: */
+    switch (auth_for) {
+      case MODE_SMTPD: out_err("334 VXNlcm5hbWU6"); break;
+      case MODE_POPUP: out_err("+ VXNlcm5hbWU6"); break;
+    }
+    if (authgetl() < 0) return ERR_AUTH_INPUT;
+    if (b64decode(&user,auth.s,auth.len) != 0)
+      return ERR_AUTH_INPUT;
+  }
+
+  /* Password: */
+  switch (auth_for) {
+    case MODE_SMTPD: out_err("334 UGFzc3dvcmQ6"); break;
+    case MODE_POPUP: out_err("+ UGFzc3dvcmQ6"); break;
+  }
+  if (authgetl() < 0) return ERR_AUTH_INPUT;
+  if (b64decode(&pass,auth.s,auth.len) != 0)
+    return ERR_AUTH_INPUT;
+
+  if (!user.len || !pass.len)
+    return ERR_AUTH_INPUT;
+
+  env_put2("SASL", "LOGIN");
+  return authenticate(0);
+}
+
+/* user+pass is set */
+int auth_plain(char *arg)
+{
+  int i=0;
+  char *r_pass, *r_user, x[123];
+
+  doname(); Log("SASL 1("); Log(arg); Log(")\n"); flush();
+  if (*arg) {
+    if (b64decode(&slop,arg,str_len(arg)) != 0)
+      return ERR_AUTH_INPUT;
+  } else {
+    switch (auth_for) {
+      case MODE_SMTPD: out_err("334 "); break;
+      case MODE_POPUP: out_err("+ "); break;
+    }
+
+    if (authgetl() < 0) return ERR_AUTH_INPUT;
+    if (b64decode(&slop,auth.s,auth.len) != 0)
+      return ERR_AUTH_INPUT;
+  }
+
+  if (!stralloc_0(&slop)) die_nomem();
+  doname(); Log("SASL slop("); Logn(slop.s, slop.len); Log(")\n"); flush();
+
+  /* ignore authorize-id */
+  while (slop.s[i++]) {
+    if (i >= slop.len) {
+      return ERR_AUTH_INPUT;
+    }
+  }
+
+  r_user = slop.s + i;
+  doname(); Log("SASL user("); Log(r_user); Log(")\n"); flush();
+  if (!stralloc_copys(&user, r_user)) die_nomem();
+  while (slop.s[i++]) {
+    if (i >= slop.len) {
+      return ERR_AUTH_INPUT;
+    }
+  }
+
+  r_pass = slop.s + i;
+  doname(); Log("SASL pass("); Log(r_pass); Log(")\n"); flush();
+  if (!stralloc_copys(&pass, r_pass)) die_nomem();
+  while (slop.s[i++]) {
+    if (i >= slop.len) {
+      return ERR_AUTH_INPUT;
+    }
+  }
+
+  if (!pass.len || !user.len)
+    return ERR_AUTH_INPUT;
+
+  env_put2("SASL", "PLAIN");
+  return authenticate(0);
+}
+
+/* user+resp is set */
+int auth_cram(char *arg)
+{
+  int i;
+  char *s;
+
+  dounique();
+  if (!stralloc_copys(&pass,"<")) die_nomem();
+  if (!stralloc_cats(&pass,unique)) die_nomem();
+  if (!stralloc_cats(&pass,hostname)) die_nomem();
+  if (!stralloc_cats(&pass,">")) die_nomem();
+  if (b64encode(&slop,&pass) != 0) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+
+  doserv();
+  switch (auth_for) {
+    case MODE_SMTPD: out("334 "); break;
+    case MODE_POPUP: out("+ "); break;
+  }
+  out(slop.s); doeol(); flush();
+
+  if (authgetl() < 0) return ERR_AUTH_INPUT;
+  if (b64decode(&slop,auth.s,auth.len) != 0) return ERR_AUTH_INPUT;
+  if (!stralloc_0(&slop)) die_nomem();
+
+  i = str_chr(slop.s,' ');
+  s = slop.s + i;
+  while (*s == ' ') ++s;
+  slop.s[i] = 0;
+  if (!stralloc_copys(&user,slop.s)) die_nomem();
+  if (!stralloc_copys(&resp,s)) die_nomem();
+
+  if (!user.len || !resp.len) return ERR_AUTH_INPUT;
+  return authenticate(0);
+}
+
+int auth_cram_md5(char *arg) {
+  env_put2("SASL", "CRAM-MD5");
+  return auth_cram(arg);
+}
+
+int auth_cram_sha1(char *arg) {
+  env_put2("SASL", "CRAM-SHA1");
+  return auth_cram(arg);
+}
+
+int auth_cram_rmd(char *arg) {
+  env_put2("SASL", "CRAM-RIPEMD");
+  return auth_cram(arg);
+}
+
+/* parse digest response */
+unsigned int scan_response(stralloc *dst, stralloc *src, const char *search) {
+  char *x=src->s;
+  int slen=strlen(search);
+  int i, len;
+
+  if (!stralloc_copys(dst,"")) die_nomem();
+  for (i=0; src->len>i+slen; i+=str_chr(x+i, ',')+1) {
+    char *s=x+i;
+    if (case_diffb(s, slen, search) == 0) {
+      s+=slen; /* skip name */
+      if (*s++ != '=') return 0; /* has to be here! */
+      if (*s == '"') { /* var="value" */
+        s++;
+        len=str_chr(s, '"');
+        if (!len) return 0;
+        if (!stralloc_catb(dst, s, len)) die_nomem();
+      } else { /* var=value */
+        len=str_chr(s, ',');
+        if (!len) str_len(s); /* should be the end */
+        if (!stralloc_catb(dst, s, len)) die_nomem();
+      }
+      return dst->len;
+    }
+  }
+  return 0;
+}
+
+/* rfc 2831
+ *
+ * sets all 3 variables: user\0pass\0resp\0
+ */
+#define QOP_AUTH      1
+#define QOP_AUTH_INT  2
+#define QOP_AUTH_CONF 3
+int auth_digest_md5(char *arg)
+{
+  unsigned char digest[20], encrypted[41];
+  char *x=encrypted;
+  int i,fd,qop=1;
+  stralloc tmp = {0};
+  stralloc nonce = {0};
+
+  /* user+pass+resp are allready empty */
+  if (!stralloc_copys(&slop,"")) die_nomem();
+
+  dounique(); /* create nonce */
+  hmac_sha1(unique, unique+3, digest); /* should be enough :) */
+  for (i=0; i<20; i++) {
+    *x = hextab[digest[i]/16]; ++x;
+    *x = hextab[digest[i]%16]; ++x;
+  }
+  *x=0;
+
+  if (!stralloc_copys(&tmp, encrypted)) die_nomem();
+  if (b64encode(&nonce,&tmp) != 0) die_nomem();
+  if (!stralloc_cats(&slop,"realm=\"")) die_nomem();
+  if (!stralloc_cats(&slop,hostname)) die_nomem();
+  if (!stralloc_cats(&slop,"\",nonce=\"")) die_nomem();
+  if (!stralloc_cat(&slop,&nonce)) die_nomem();
+  if (!stralloc_cats(&slop,"\",qop=\"auth\"")) die_nomem();
+  if (!stralloc_cats(&slop,",algorithm=md5-sess")) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+  if (b64encode(&tmp,&slop) != 0) die_nomem();
+
+  /* send digest-challenge */
+  doname(); Log("SASL: we send("); Log(slop.s); Log(")\n"); flush();
+  doserv();
+  switch (auth_for) {
+    case MODE_SMTPD: out("334 "); break;
+    case MODE_POPUP: out("+ "); break;
+  }
+  outn(tmp.s,tmp.len); doeol(); flush();
+
+  /* get digest-response */
+  if (authgetl() < 0) return ERR_AUTH_INPUT;
+  if (b64decode(&slop,auth.s,auth.len) != 0) return ERR_AUTH_INPUT;
+  if (!stralloc_0(&slop)) die_nomem();
+  doname(); Log("SASL we got("); Log(slop.s); Log(")\n"); flush();
+
+  /* scan slop for all required fields, fill resp for later auth.  */
+  if (scan_response(&user,&slop, "username") == 0) return ERR_AUTH_INPUT;
+
+  if (scan_response(&tmp,&slop,  "digest-uri") == 0) return ERR_AUTH_INPUT;
+  if (!stralloc_cats(&resp, "digest-uri=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* check nc field */
+  if (scan_response(&tmp,&slop, "nc") == 0) return ERR_AUTH_INPUT;
+  if (tmp.len != 8) return ERR_AUTH_INPUT;
+  if (case_diffb("00000001", 8, tmp.s) != 0) return ERR_AUTH_INPUT;
+  if (!stralloc_cats(&resp, "\nnc=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* check nonce */
+  if (scan_response(&tmp,&slop, "nonce") == 0) return ERR_AUTH_INPUT;
+  if (tmp.len != nonce.len) return ERR_AUTH_INPUT;
+  if (case_diffb(nonce.s, tmp.len, tmp.s) != 0) return ERR_AUTH_INPUT;
+  if (!stralloc_cats(&resp, "\nnonce=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* check cnonce */
+  if (scan_response(&tmp,&slop,  "cnonce") == 0) return ERR_AUTH_INPUT;
+  if (!stralloc_cats(&resp, "\ncnonce=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* check qop */
+  if (scan_response(&tmp,&slop, "qop") == 0) return ERR_AUTH_INPUT;
+  switch (tmp.len) {
+    case 4: qop=1; if (case_diffb("auth", 4, tmp.s) != 0) return ERR_AUTH_INPUT; break;
+    case 8: qop=2; if (case_diffb("auth-int", 8, tmp.s) != 0) return ERR_AUTH_INPUT; break;
+    case 9: qop=3; if (case_diffb("auth-conf", 9, tmp.s) != 0) return ERR_AUTH_INPUT; break;
+    default: return ERR_AUTH_INPUT;
+  }
+  if (!stralloc_cats(&resp, "\nqop=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* xxx: todo / check realm against control/realms or so ?! */
+  if (scan_response(&tmp,&slop, "realm") == 0) return ERR_AUTH_INPUT;
+//  i=strlen(hostname);
+//  if (tmp.len != i) return ERR_AUTH_INPUT;
+//  if (case_diffb(hostname, i, tmp.s) != 0) return ERR_AUTH_INPUT;
+  if (!stralloc_cats(&resp, "\nrealm=")) die_nomem();
+  if (!stralloc_cat(&resp, &tmp)) die_nomem();
+
+  /* check response */
+  if (scan_response(&pass,&slop, "response") == 0) return ERR_AUTH_INPUT;
+  if (pass.len != 32) return ERR_AUTH_INPUT;
+
+  /* user=username
+   * pass=response (md5 hash = 32)
+   * resp=authfile (with all required vars for the checkpassword utility)
+   *      -> nc,qop,realm,nonce,cnonce,digesturi
+   *
+   *             a1 = md5(user:realm:pass) : nonce : cnonce
+   * qop=auth:   a2 = 'AUTHENTICATE' : digesturi
+   * qop=auth-*: a2 = 'AUTHENTICATE' : digesturi : '00000000000000000000000000000000'
+   * resp = md5(a1) + nonce + nc + conce + qop + md5(a2)
+   */
+
+  if (!stralloc_copys(&tmp,"/var/qmail/authdir/")) die_nomem();
+  if (!stralloc_cat(&tmp, &pass)) die_nomem();
+  if (!stralloc_0(&tmp)) die_nomem();
+
+  if ((fd=open_trunc(tmp.s)) < 0) die_child();
+  if (write(fd, resp.s, resp.len) != resp.len) die_child();
+  if (close(fd) < 0) die_child();
+  if (!stralloc_copy(&resp,&tmp)) die_nomem();
+
+  /* - we call now checkqpasswd
+   * - it reads needed variables from in resp.s given filename
+   * - it checks validity
+   */
+  if (!user.len || !pass.len || !resp.len) return ERR_AUTH_INPUT;
+  env_put2("SASL", "DIGEST-MD5");
+
+  return authenticate(1);
+}
diff -urN qmail-1.03-vanilla/qmail-sasl.h qmail-1.03-md24/qmail-sasl.h
--- qmail-1.03-vanilla/qmail-sasl.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/qmail-sasl.h	2007-07-29 10:18:00.000000000 +0200
@@ -0,0 +1,75 @@
+#include <unistd.h>
+
+#include "byte.h"
+#include "base64.h"
+#include "fd.h"
+#include "fmt.h"
+#include "str.h"
+#include "wait.h"
+#include "substdio.h"
+#include "open.h"
+#include "exit.h"
+#include "fork.h"
+#include "error.h"
+#include "tcpto.h"
+#include "now.h"
+#include "sig.h"
+#include "case.h"
+#include "env.h"
+#include "out_log.h"
+#include "hmac_sha1.h"
+#include "stralloc.h"
+
+/* BEGIN have to be defined from extern */
+extern char unique[];
+extern char *hostname;
+extern char **childargs;
+extern substdio ssin;
+
+extern int ctl_log_err;
+extern int *ctl_auth_current;
+
+extern int auth_for;
+#define MODE_UNKNOWN 0
+#define MODE_POPUP   1
+#define MODE_SMTPD   2
+
+extern int safewrite(int fd, char *buf, int len);
+extern int saferead(int fd, char *buf, int len);
+extern int err_noauth();
+extern void die_nomem();
+extern void die_child();
+extern void die_read();
+extern void die_pipe();
+extern void die_fork();
+extern void die_write();
+/* END OF have to be defined */
+
+/* qmail-sasl.h variables */
+#define ERR_AUTH_FAILED 1
+#define ERR_AUTH_INPUT  2
+#define ERR_AUTH_ABORT  3
+extern int ctl_auth_delay; /* standard = 5 */
+
+extern char upbuf[128];
+extern substdio ssauth;
+extern stralloc auth;
+extern stralloc user;
+extern stralloc pass;
+extern stralloc resp;
+extern stralloc slop;
+
+#define SASL_MAX 6
+extern char *sasl[];
+/*  1 */ extern int auth_login(char *arg);
+/*  2 */ extern int auth_plain(char *arg);
+/*  4 */ extern int auth_cram_md5(char *arg);
+/*  8 */ extern int auth_cram_sha1(char *arg);
+/* 16 */ extern int auth_cram_rmd(char *arg);
+/* 32 */ extern int auth_digest_md5(char *arg);
+
+typedef struct {
+  char *text;
+  int  (*fun)();
+} authcmd_t;
+extern authcmd_t authcmds[];
diff -urN qmail-1.03-vanilla/qmail-send.9 qmail-1.03-md24/qmail-send.9
--- qmail-1.03-vanilla/qmail-send.9	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-send.9	2007-07-19 20:56:22.000000000 +0200
@@ -51,7 +51,9 @@
 .B qmail-send
 receives a HUP signal,
 it will reread
-.I locals
+.IR concurrencylocal ,
+.IR concurrencyremote ,
+.IR locals
 and
 .IR virtualdomains .
 .TP 5
diff -urN qmail-1.03-vanilla/qmail-send.c qmail-1.03-md24/qmail-send.c
--- qmail-1.03-vanilla/qmail-send.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-send.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <utime.h>
+
 #include "readwrite.h"
 #include "sig.h"
 #include "direntry.h"
@@ -96,7 +98,7 @@
 }
 
 void fnmake_info(id) unsigned long id; { fn.len = fmtqfn(fn.s,"info/",id,1); }
-void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,0); }
+void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,1); }
 void fnmake_mess(id) unsigned long id; { fn.len = fmtqfn(fn.s,"mess/",id,1); }
 void fnmake_foop(id) unsigned long id; { fn.len = fmtqfn(fn.s,"foop/",id,0); }
 void fnmake_split(id) unsigned long id; { fn.len = fmtqfn(fn.s,"",id,1); }
@@ -262,6 +264,8 @@
  while (!stralloc_copys(&comm_buf[c],"")) nomem();
  ch = delnum;
  while (!stralloc_append(&comm_buf[c],&ch)) nomem();
+ ch = delnum >> 8;
+ while (!stralloc_append(&comm_buf[c],&ch)) nomem();
  fnmake_split(id);
  while (!stralloc_cats(&comm_buf[c],fn.s)) nomem();
  while (!stralloc_0(&comm_buf[c])) nomem();
@@ -452,15 +456,14 @@
 {
  int c;
  struct prioq_elt pe;
- time_t ut[2]; /* XXX: more portable than utimbuf, but still worrisome */
+ struct utimbuf ut; /* this is correct /TR !!! */
 
  for (c = 0;c < CHANNELS;++c)
-   while (prioq_min(&pqchan[c],&pe))
-    {
+   while (prioq_min(&pqchan[c],&pe)) {
      prioq_delmin(&pqchan[c]);
      fnmake_chanaddr(pe.id,c);
-     ut[0] = ut[1] = pe.dt;
-     if (utime(fn.s,ut) == -1)
+     ut.actime = ut.modtime = pe.dt;
+     if (utime(fn.s,&ut) == -1)
        log3("warning: unable to utime ",fn.s,"; message will be retried too soon\n");
     }
 }
@@ -906,41 +909,42 @@
      dline[c].len = REPORTMAX;
      /* qmail-lspawn and qmail-rspawn are responsible for keeping it short */
      /* but from a security point of view, we don't trust rspawn */
-   if (!ch && (dline[c].len > 1))
+   if (!ch && (dline[c].len > 2))
     {
      delnum = (unsigned int) (unsigned char) dline[c].s[0];
+     delnum += (unsigned int) ((unsigned int) dline[c].s[1]) << 8;
      if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used)
        log1("warning: internal error: delivery report out of range\n");
      else
       {
        strnum3[fmt_ulong(strnum3,d[c][delnum].delid)] = 0;
-       if (dline[c].s[1] == 'Z')
+       if (dline[c].s[2] == 'Z')
 	 if (jo[d[c][delnum].j].flagdying)
 	  {
-	   dline[c].s[1] = 'D';
+	   dline[c].s[2] = 'D';
 	   --dline[c].len;
 	   while (!stralloc_cats(&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
 	   while (!stralloc_0(&dline[c])) nomem();
 	  }
-       switch(dline[c].s[1])
+       switch(dline[c].s[2])
 	{
 	 case 'K':
 	   log3("delivery ",strnum3,": success: ");
-	   logsafe(dline[c].s + 2);
+	   logsafe(dline[c].s + 3);
 	   log1("\n");
 	   markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
 	   --jo[d[c][delnum].j].numtodo;
 	   break;
 	 case 'Z':
 	   log3("delivery ",strnum3,": deferral: ");
-	   logsafe(dline[c].s + 2);
+	   logsafe(dline[c].s + 3);
 	   log1("\n");
 	   break;
 	 case 'D':
 	   log3("delivery ",strnum3,": failure: ");
-	   logsafe(dline[c].s + 2);
+	   logsafe(dline[c].s + 3);
 	   log1("\n");
-	   addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2);
+	   addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 3);
 	   markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
 	   --jo[d[c][delnum].j].numtodo;
 	   break;
@@ -1216,7 +1220,8 @@
 /* this file is too long ---------------------------------------------- TODO */
 
 datetime_sec nexttodorun;
-DIR *tododir; /* if 0, have to opendir again */
+int flagtododir = 0; /* if 0, have to readsubdir_init again */
+readsubdir todosubdir;
 stralloc todoline = {0};
 char todobuf[SUBSTDIO_INSIZE];
 char todobufinfo[512];
@@ -1224,7 +1229,7 @@
 
 void todo_init()
 {
- tododir = 0;
+ flagtododir = 0;
  nexttodorun = now();
  trigger_set();
 }
@@ -1236,7 +1241,7 @@
 {
  if (flagexitasap) return;
  trigger_selprep(nfds,rfds);
- if (tododir) *wakeup = 0;
+ if (flagtododir) *wakeup = 0;
  if (*wakeup > nexttodorun) *wakeup = nexttodorun;
 }
 
@@ -1253,8 +1258,6 @@
  char ch;
  int match;
  unsigned long id;
- unsigned int len;
- direntry *d;
  int c;
  unsigned long uid;
  unsigned long pid;
@@ -1265,32 +1268,26 @@
 
  if (flagexitasap) return;
 
- if (!tododir)
+ if (!flagtododir)
   {
    if (!trigger_pulled(rfds))
      if (recent < nexttodorun)
        return;
    trigger_set();
-   tododir = opendir("todo");
-   if (!tododir)
-    {
-     pausedir("todo");
-     return;
-    }
+   readsubdir_init(&todosubdir, "todo", pausedir);
+   flagtododir = 1;
    nexttodorun = recent + SLEEP_TODO;
   }
 
- d = readdir(tododir);
- if (!d)
+ switch(readsubdir_next(&todosubdir, &id))
   {
-   closedir(tododir);
-   tododir = 0;
-   return;
+    case 1:
+      break;
+    case 0:
+      flagtododir = 0;
+    default:
+      return;
   }
- if (str_equal(d->d_name,".")) return;
- if (str_equal(d->d_name,"..")) return;
- len = scan_ulong(d->d_name,&id);
- if (!len || d->d_name[len]) return;
 
  fnmake_todo(id);
 
@@ -1478,10 +1475,17 @@
 
  if (control_readfile(&newlocals,"control/locals",1) != 1)
   { log1("alert: unable to reread control/locals\n"); return; }
+
  r = control_readfile(&newvdoms,"control/virtualdomains",0);
  if (r == -1)
   { log1("alert: unable to reread control/virtualdomains\n"); return; }
 
+ if (control_readint(&concurrency[0],"control/concurrencylocal") == -1)
+  { log1("alert: unable to reread control/concurrencylocal\n",0); return; }
+
+ if (control_readint(&concurrency[1],"control/concurrencyremote") == -1)
+  { log1("alert: unable to reread control/concurrencyremote\n",0); return; }
+
  constmap_free(&maplocals);
  constmap_free(&mapvdoms);
 
@@ -1512,7 +1516,7 @@
   }
 }
 
-void main()
+int main()
 {
  int fd;
  datetime_sec wakeup;
@@ -1544,7 +1548,7 @@
  numjobs = 0;
  for (c = 0;c < CHANNELS;++c)
   {
-   char ch;
+   char ch, ch1;
    int u;
    int r;
    do
@@ -1552,7 +1556,13 @@
    while ((r == -1) && (errno == error_intr));
    if (r < 1)
     { log1("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); }
+   do
+     r = read(chanfdin[c],&ch1,1);
+   while ((r == -1) && (errno == error_intr));
+   if (r < 1)
+    { log1("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); }
    u = (unsigned int) (unsigned char) ch;
+   u += (unsigned int) ((unsigned char) ch1) << 8;
    if (concurrency[c] > u) concurrency[c] = u;
    numjobs += concurrency[c];
   }
@@ -1608,5 +1618,5 @@
   }
  pqfinish();
  log1("status: exiting\n");
- _exit(0);
+ return 0;
 }
diff -urN qmail-1.03-vanilla/qmail-showctl.c qmail-1.03-md24/qmail-showctl.c
--- qmail-1.03-vanilla/qmail-showctl.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-showctl.c	2007-07-19 23:02:41.000000000 +0200
@@ -1,5 +1,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "subfd.h"
 #include "exit.h"
@@ -16,9 +17,6 @@
 #include "auto_spawn.h"
 #include "auto_split.h"
 
-stralloc me = {0};
-int meok;
-
 stralloc line = {0};
 char num[FMT_ULONG];
 
@@ -136,7 +134,7 @@
   }
 }
 
-void main()
+int main()
 {
   DIR *dir;
   direntry *d;
@@ -215,11 +213,14 @@
   }
 
   do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
+  do_lst("badmailto","Any RCPT TO is allowed.",""," not accepted in RCPT TO.");
+  do_lst("badhelo","Any HELO is allowed.",""," not accepted in HELO.");
   do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
   do_str("bouncehost",1,"bouncehost","Bounce host name is ");
   do_int("concurrencylocal","10","Local concurrency is ","");
   do_int("concurrencyremote","20","Remote concurrency is ","");
   do_int("databytes","0","SMTP DATA limit is "," bytes");
+  do_int("databytes+","5000","MAIL SIZE can differ an about "," bytes");
   do_str("defaultdomain",1,"defaultdomain","Default domain name is ");
   do_str("defaulthost",1,"defaulthost","Default host name is ");
   do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: ");
@@ -230,6 +231,7 @@
   do_str("localiphost",1,"localiphost","Local IP address becomes ");
   do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally.");
   do_str("me",0,"undefined! Uh-oh","My name is ");
+  do_str("outgoingip",0,"0.0.0.0","Outgoing IP address is ");
   do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@",".");
   do_str("plusdomain",1,"plusdomain","Plus domain name is ");
   do_lst("qmqpservers","No QMQP servers.","QMQP server: ",".");
@@ -239,7 +241,6 @@
     do_lst("morercpthosts","No effect.","SMTP clients may send messages to recipients at ",".");
   else
     do_lst("morercpthosts","No rcpthosts; morercpthosts is irrelevant.","No rcpthosts; doesn't matter that morercpthosts has ",".");
-  /* XXX: check morercpthosts.cdb contents */
   substdio_puts(subfdout,"\nmorercpthosts.cdb: ");
   if (stat("morercpthosts",&stmrh) == -1)
     if (stat("morercpthosts.cdb",&stmrhcdb) == -1)
@@ -257,22 +258,35 @@
 
   do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
   do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
+
   do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds");
   do_int("timeoutremote","1200","SMTP client data timeout is "," seconds");
   do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds");
   do_lst("virtualdomains","No virtual domains.","Virtual domain: ","");
 
-  while (d = readdir(dir)) {
+  /* from patches */
+  do_int("mfcheck",     "off (0)", "The FQDN MX or A record check is ","");
+  do_int("maxrcpt",     "off (0)", "The maximum recipients a client may want to use is ","");
+  do_int("maxcmdlen",   "off (0)", "The maximum command length can be ","");
+  do_int("tarpitcount", "0", "The actual tarpitcount is ","");
+  do_int("tarpitdelay", "0", "The tarpitdelay is "," seconds");
+  do_lst("datechecks",  "No datechecks will be done.","mailaddress "," days.");
+
+  while ((d = readdir(dir))) {
     if (str_equal(d->d_name,".")) continue;
     if (str_equal(d->d_name,"..")) continue;
     if (str_equal(d->d_name,"bouncefrom")) continue;
     if (str_equal(d->d_name,"bouncehost")) continue;
     if (str_equal(d->d_name,"badmailfrom")) continue;
+    if (str_equal(d->d_name,"badmailto")) continue;
+    if (str_equal(d->d_name,"badhelo")) continue;
     if (str_equal(d->d_name,"bouncefrom")) continue;
     if (str_equal(d->d_name,"bouncehost")) continue;
     if (str_equal(d->d_name,"concurrencylocal")) continue;
     if (str_equal(d->d_name,"concurrencyremote")) continue;
     if (str_equal(d->d_name,"databytes")) continue;
+    if (str_equal(d->d_name,"databytes+")) continue;
+    if (str_equal(d->d_name,"datechecks")) continue;
     if (str_equal(d->d_name,"defaultdomain")) continue;
     if (str_equal(d->d_name,"defaulthost")) continue;
     if (str_equal(d->d_name,"doublebouncehost")) continue;
@@ -282,7 +296,16 @@
     if (str_equal(d->d_name,"idhost")) continue;
     if (str_equal(d->d_name,"localiphost")) continue;
     if (str_equal(d->d_name,"locals")) continue;
+
+    /* these are directories @ my servers */
+    if (str_equal(d->d_name,"certs")) continue;
+    if (str_equal(d->d_name,"auth")) continue;
+    if (str_equal(d->d_name,"log")) continue;
+
+    if (str_equal(d->d_name,"maxrcpt")) continue;
+    if (str_equal(d->d_name,"maxcmdlen")) continue;
     if (str_equal(d->d_name,"me")) continue;
+    if (str_equal(d->d_name,"mfcheck")) continue;
     if (str_equal(d->d_name,"morercpthosts")) continue;
     if (str_equal(d->d_name,"morercpthosts.cdb")) continue;
     if (str_equal(d->d_name,"percenthack")) continue;
@@ -292,10 +315,31 @@
     if (str_equal(d->d_name,"rcpthosts")) continue;
     if (str_equal(d->d_name,"smtpgreeting")) continue;
     if (str_equal(d->d_name,"smtproutes")) continue;
+
+    if (str_equal(d->d_name,"spfbehavior")) continue;
+    if (str_equal(d->d_name,"spfexp")) continue;
+    if (str_equal(d->d_name,"spfguess")) continue;
+    if (str_equal(d->d_name,"spfrules")) continue;
+
+    if (str_equal(d->d_name,"softlimit")) continue; /* some use this place */
+    if (str_equal(d->d_name,"tarpitcount")) continue;
+    if (str_equal(d->d_name,"tarpitdelay")) continue;
     if (str_equal(d->d_name,"timeoutconnect")) continue;
     if (str_equal(d->d_name,"timeoutremote")) continue;
     if (str_equal(d->d_name,"timeoutsmtpd")) continue;
     if (str_equal(d->d_name,"virtualdomains")) continue;
+
+    /* tls/ssl stuff */
+    if (str_equal(d->d_name,"certs")) continue; /* ignored */
+    if (str_equal(d->d_name,"clientcert.pem")) continue;
+    if (str_equal(d->d_name,"tlsclientciphers")) continue;
+    if (str_equal(d->d_name,"tlshosts")) continue; /* special dir with FQDN.pem's */
+    if (str_equal(d->d_name,"clientca.pem")) continue;
+    if (str_equal(d->d_name,"rsa512.pem")) continue;
+    if (str_equal(d->d_name,"servercert.pem")) continue;
+    if (str_equal(d->d_name,"tlsclients")) continue;
+    if (str_equal(d->d_name,"tlsserverciphers")) continue;
+
     substdio_puts(subfdout,"\n");
     substdio_puts(subfdout,d->d_name);
     substdio_puts(subfdout,": I have no idea what this file does.\n");
diff -urN qmail-1.03-vanilla/qmail-smtpd.8 qmail-1.03-md24/qmail-smtpd.8
--- qmail-1.03-vanilla/qmail-smtpd.8	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-smtpd.8	2007-07-28 17:58:59.000000000 +0200
@@ -1,11 +1,15 @@
 .TH qmail-smtpd 8
 .SH NAME
-qmail-smtpd \- receive mail via SMTP
+qmail-smtpd \- receive mail via SMTP or ESMTP
 .SH SYNOPSIS
 .B qmail-smtpd
+.I checkpassword
+[
+.I args
+]
 .SH DESCRIPTION
 .B qmail-smtpd
-receives mail messages via the Simple Mail Transfer Protocol (SMTP)
+receives mail messages via the Simple Mail Transfer Protocol (SMTP/ESMTP)
 and invokes
 .B qmail-queue
 to deposit them into the outgoing queue.
@@ -15,15 +19,17 @@
 .BR tcp-environ(5) .
 
 .B qmail-smtpd
-is responsible for counting hops.
-It rejects any message with 100 or more 
+is responsible for counting hops. It rejects any message with 100 or more
 .B Received
 or
 .B Delivered-To
-header fields.
+header fields. The Default value of 100 is changeable via the
+.I maxhops
+contrilfile.
 
 .B qmail-smtpd
-supports ESMTP, including the 8BITMIME and PIPELINING options.
+supports ESMTP, including the 8BITMIME, PIPELINING, STARTTLS, AUTH and SIZE
+options.
 .SH TRANSPARENCY
 .B qmail-smtpd
 converts the SMTP newline convention into the UNIX newline convention
@@ -39,30 +45,67 @@
 .TP 5
 .I badmailfrom
 Unacceptable envelope sender addresses.
-.B qmail-smtpd
-will reject every recipient address for a message
-if the envelope sender address is listed in
-.IR badmailfrom .
-A line in
-.I badmailfrom
-may be of the form
-.BR @\fIhost ,
-meaning every address at
-.IR host .
+.br
+This file contains in each line one regular expression. The matching is done
+against the
+.I XYZ
+contents of the SMTP command \fIMAIL FROM:<YXZ>\fR
+.br
+If \fIBADMAILFROM\fR is set, this file will be use instead of
+\fIcontrol/badmailfrom\fR, and if \fINO_BADMAILFROM\fR is set, no badhelo
+checks at all will be done.
+
+.TP 5
+.I badmailto
+Unacceptable recipient addresses.
+.br
+This file contains in each line one regular expression. The matching is done
+against the
+.I XYZ
+contents of the SMTP command \fIRCPT TO:<YXZ>\fR
+.br
+If \fIBADMAILTO\fR is set, this file will be use instead of
+\fIcontrol/badmailto\fR, and if \fINO_BADMAILTO\fR is set, no badmailto checks
+at all will be done.
+
+.TP 5
+.I badhelo
+Unacceptable helohost.
+.br
+This file contains in each line one regular expression. The matching is done
+against the
+.I XYZ
+contents of the SMTP commands \fIHELO YXZ\fR or \fIEHLO XYZ\fR.
+.br
+If \fIBADHELO\fR is set, this file will be use instead of \fIcontrol/badhelo\fR,
+and if \fINO_BADHELO\fR is set, no badhelochecks at all will be done.
+
+.TP 5
+.I datechecks
+A list of string:day pairs, where string means a start of a mailaddress and
+day means a number. It can be used to specify mailaddresses e.g. in the
+usenet, which have only a short lifetime.
+.br
+Here is an example:
+.I datechecks
+has an entry like this \fInews-:6\fR, that means, if today is the 2004-07-02,
+than a mail like \fInews-20040704@some.domain.com\fR will accepted, because it
+is in the 6 day limit. But a mail like \fInews-20040622@some.domain.com\fR
+will be rejected.
+
 .TP 5
 .I databytes
-Maximum number of bytes allowed in a message,
-or 0 for no limit.
+Maximum number of bytes allowed in a message, or 0 for no limit.
 Default: 0.
 If a message exceeds this limit,
 .B qmail-smtpd
-returns a permanent error code to the client;
-in contrast, if
-the disk is full or
+returns a permanent error code to the client; in contrast, if the disk is full
+or
 .B qmail-smtpd
 hits a resource limit,
 .B qmail-smtpd
-returns a temporary error code.
+returns a temporary error code. This value is also used for the ESMTP SIZE
+extension.
 
 .I databytes
 counts bytes as stored on disk, not as transmitted through the network.
@@ -71,11 +114,23 @@
 Received line, the
 .B qmail-queue
 Received line, or the envelope.
-
 If the environment variable
 .B DATABYTES
 is set, it overrides
 .IR databytes .
+
+.TP 5
+.I databytes+
+This integer value is added to the maximum databytes a message can have, when
+the client sends mail via the ESMTP SIZE extension.
+.br
+Sample: if
+.I databytes+
+is 100 and a client sends \fIMAIL FROM:<user@domain.com> SIZE=12345\fR, than the
+maximum data in the DATA transfer can be databytes+100 at most!
+.I databytes+
+defaults to 5000.
+
 .TP 5
 .I localiphost
 Replacement host name for local IP addresses.
@@ -96,6 +151,50 @@
 .IR localiphost .
 This is done before
 .IR rcpthosts .
+
+.TP 5
+.I maxcmdlen
+When a client sends a command which is longer than
+.IR maxcmdlen ,
+than the client gets tarpitted and the connection is closed.
+
+.TP 5
+.I maxaddrlen
+When the client's sender or recipient mailaddress is longer than
+.IR maxaddrlen ,
+the client gets tarpitted and the connection is closed.
+
+.TP 5
+.I maxhops
+The maximum number of hops an email is allowd to have. See above, for a complete
+description of counting hops.
+
+.TP 5
+.I maxrcpt
+When the number of \fIRCPT TO:\fR commands is greater or equal with the number
+which is stored in this file, than qmail will tarpit+close the connection.
+Default: 0, which means no maximum.
+The environment variable \fINO_MAXRCPT\fR and \fIMAXRCPT\fR override the
+contents of \fImaxrcpt\fR.
+
+.TP 5
+.I mfcheck
+If this file exists and contains a non-zero integer, the envelope sender's
+domain must have an MX or A record associated. Temporary failures will result in
+a temporary SMTP error. By setting the \fINO_MFCHECK\fR variable you can
+disable the check, but by setting the \fIMFCHECK\fR variable to an integer, you
+can even enable/disable the mfchecks.
+ 0 - no checking @all (default value)
+ 1 - mx record will be checked
+ 2 - SMTP callback/sender verification will be done ()
+
+.TP 5
+.I mxblacklist
+This file contains one ip per line, which itentifies bad mx adresses for
+mailserver. Spammer use for example some dnsmx, which points to '127.0.0.1',
+which can be forbidden by that file. 
+Maybe someone tries to explain this control file a bit better ;)
+
 .TP 5
 .I morercpthosts
 Extra allowed RCPT domains.
@@ -119,6 +218,11 @@
 .IR rcpthosts ,
 and the rest into
 .IR morercpthosts .
+
+.TP 5
+.I rcptchecks
+xxx todo (interface unclear, any comments??)
+
 .TP 5
 .I rcpthosts
 Allowed RCPT domains.
@@ -140,17 +244,15 @@
 and will append the value of
 .B RELAYCLIENT
 to each incoming recipient address.
-
 .I rcpthosts
 may include wildcards:
-
 .EX
    heaven.af.mil
    .heaven.af.mil
 .EE
-
 Envelope recipient addresses without @ signs are
 always allowed through.
+
 .TP 5
 .I smtpgreeting
 SMTP greeting message.
@@ -163,17 +265,126 @@
 The first word of
 .I smtpgreeting
 should be the current host's name.
+
 .TP 5
 .I timeoutsmtpd
 Number of seconds
 .B qmail-smtpd
 will wait for each new buffer of data from the remote SMTP client.
 Default: 1200.
+
+.TP 5
+.I tarpitcount
+if
+.I NO_TARPITTING
+is not set, than tarpitcount is the number of RCPT TO:
+.B qmail-smtpd
+accepts before it starts tarpitting. Default: 0 which means no tarpitting.
+The environment variable 
+.B TARPITCOUNT
+overrides the default.
+
+.TP 5
+.I tarpitdelay
+if
+.I NO_TARPITTING
+is not set, than tarpitdelay is the time in seconds of delay to be introduced
+after each subsequent RCPT TO:<XYZ> Default: 5. The environment variable
+.B TARPITDELAY
+overrides the default.
+
+.SH "ESMTP STARTTLS"
+.TP 5
+.I clientca.pem
+A list of Certifying Authority (CA) certificates that are used to verify
+the client-presented certificates during a TLS-encrypted session.
+
+.TP 5
+.I tlsclients
+A list of email addresses. When relay rules would reject an incoming message,
+.B qmail-smtpd
+can allow it if the client presents a certificate that can be verified against
+the CA list in
+.I clientca.pem
+and the certificate email address is in
+.IR tlsclients .
+
+.TP 5
+.I tlsserverciphers
+A set of OpenSSL cipher strings. Multiple ciphers contained in a
+string should be separated by a colon. If the environment variable
+.B TLSCIPHERS
+is set to such a string, it takes precedence.
+
+
+.SH "ESMTP AUTH"
+ESMTP Authentication is now fully functional implemented into
+.BR qmail-smtpd .
+Clients can send commands like
+\fIMAIL FROM:<user@host.com> SIZE=1234 AUTH=LOGIN\fR and qmail will know about
+that!
+
+.TP 5
+.I auth/delay
+This file holds the number of seconds
+.B qmail-smtpd
+has to wait, when a user authenticates with a wrong password.
+
+.TP 5
+.I auth/smtp
+This file holds a number, which tells
+.B qmail-smtpd
+what authentication methods for insecure email transfer can be used. THe default
+is 60, which means LOGIN and PLAIN are forbidden!
+
+.TP 5
+.I auth/smtps
+This file holds a number, which tells
+.B qmail-smtpd
+what authentication methods for secure email transfer can be used. The default
+value is 63, which means all currently available methods can be used!
+
+.TP 5
+.I REQUIREAUTH
+When this environment variable is set,
+.B qmail-smtpd
+will refuse to do anything, if the client hasn't authenticated.
+
+.SH "LOGGING OPTIONS"
+.TP 5
+.I log/bmchecks
+Enable or disable logging of badmailfrom, badmailto and badhelo checks.
+
+.TP 5
+.I log/datechecks
+Enable or disable logging of the datechecking.
+
+.TP 5
+.I log/orchecks
+Enable or disable logging of the open relay tests.
+
+.TP 5
+.I log/smtp_in
+Enable or disable logging of the open relay tests.
+
+.TP 5
+.I log/smtp_fd
+You should put in here a valid filedescriptor, which can be used for logging.
+
+.TP 5
+.I log/smtp_out
+Enable or disable logging of the open relay tests.
+
+.TP 5
+.I log/tarpitting
+Enable or disable the logging of some info about the client which gets tarpitted.
+
 .SH "SEE ALSO"
-tcp-env(1),
-tcp-environ(5),
-qmail-control(5),
-qmail-inject(8),
-qmail-newmrh(8),
-qmail-queue(8),
-qmail-remote(8)
+.BR tcp-env (1),
+.BR tcp-environ (5),
+.BR qmail-control (5),
+.BR qmail-inject (8),
+.BR qmail-newmrh (8),
+.BR qmail-queue (8),
+.BR qmail-remote (8),
+.BR rblsmtpd (8)
diff -urN qmail-1.03-vanilla/qmail-smtpd.c qmail-1.03-md24/qmail-smtpd.c
--- qmail-1.03-vanilla/qmail-smtpd.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-smtpd.c	2007-08-13 21:27:36.000000000 +0200
@@ -1,3 +1,18 @@
+
+#define DEFAULT_TIMEOUT   100
+#define DEFAULT_MAXHOPS   100
+#define HUGESMTPTEXT     5000
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <regex.h>
+#include <time.h>
+
 #include "sig.h"
 #include "readwrite.h"
 #include "stralloc.h"
@@ -22,136 +37,612 @@
 #include "rcpthosts.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include "timeoutconn.h"
 #include "commands.h"
+#include "dns.h"
+#include "wait.h"
+#include "fd.h"
+#include "out_log.h"
+#include "qmail-sasl.h"
+#include "qmail-p0f.h"
+#include "ucspitls.h"
+
+/* global /var/qmail/controls */
+int ctl_localiphost;
+int ctl_databytes;      /* default: 0 = no limit */
+int ctl_databytesP;     /* default: 5000  */
+int ctl_timeout;        /* timeout for connection to die */
+int ctl_maxrcpt;        /* max number of recipient we allow */
+int ctl_maxhops;        /* max number of hops we allow */
+int ctl_maxaddrlen;     /* max length a mailaddress can have */
+int ctl_maxcmdlen;      /* max length a smtp command may have */
+int ctl_tarpitcount;    /* when do we want to tarpit */
+int ctl_tarpitdelay;    /* tarpitdelay in seconds */
+int ctl_rcpttofixed;    /* if set, we have a fixed RCPT TO:<addr> */
+int ctl_reqbrackets;    /* enforce <> in the mail from & rcpt to / defaults to YES */
+char *ctl_p0fsock=0;    /* p0f socket, if 0 - no socket is there! */
+
+int tls_available = 0;
+int tls_started = 0;
+
+#define BMCHECK_BMF 1   /* badmailfrom */
+#define BMCHECK_BMT 2   /* badmailto */
+#define BMCHECK_BMH 3   /* badhelo */
+#define GMCHECK_GMF 4   /* goodmailfrom */
+int ctl_bmh, ctl_bmf, ctl_bmt, ctl_gmf;
+
+int ctl_clamd;          /* cheking for viruses via clamd / ip:port */
+int ctl_mfcheck;        /* enable/disable dns mx/a check */
+int ctl_orcheck;        /* enable/disable open relay checks */
+int ctl_rcptchecks;     /* enable/disable rcptchecks via external programs */
+int ctl_datechecks;     /* enable/disable usenet-YYYYMMDD checking */
+int ctl_bigbrother;     /* see TODO */
+int ctl_mxblacklist;    /* mxblacklist */
+stralloc ctl_outgoingip = {0}; /* outgoing ip */
+
+/* logging */
+int ctl_log_fd;         /* fd, where we want to log to */
+int ctl_log_in;         /* enable/disable incoming network traffik (S: ...) */
+int ctl_log_out;        /* enable/disable outgoing network traffik (C: ...) */
+int ctl_log_bmchecks;   /* enable/disable bad mail checks logging */
+int ctl_log_orchecks;   /* enable/disable open relay checks logging */
+int ctl_log_datechecks; /* enable/disable datechecks logging */
+int ctl_log_tarpitting; /* enable/disable tarpitting logging */
+
+/* esmtp auth */
+int ctl_auth_oldauth;   /* if >0, then the old ehlo resp. "AUTH=x1 x2" is also used */
+int ctl_auth_delay;     /* auth-delay is issued, when a password failure has occured */
+int ctl_auth_secure=(1|2|4|8|16); /* sasl methods in TLS mode */
+int ctl_auth_insecure=(4|8|16); /* sasl methods in NON-TLS mode */
+int *ctl_auth_current = &ctl_auth_insecure; /* depends on the current tls state */
+
+stralloc bmf = {0}; /* control/badmailfrom content */
+stralloc bmt = {0}; /* control/badmailto content */
+stralloc bmh = {0}; /* control/badhelo content */
+stralloc gmf = {0}; /* control/goodmailfrom content */
+stralloc dcf = {0}; /* control/datechecks content */
+stralloc bbr = {0}; /* control/bigbrother content */
+
+stralloc mxbl = {0};  /* mx blacklist */
+stralloc clamd = {0};
+unsigned int clamd_port;     /* daemon */
+unsigned int clamd_sport;    /* stream */
+unsigned int clamd_streamok = 0; /* stream state */
+struct ip_address clamd_ip;
+struct ip_address outip;
+
+/* misc variables */
+char *name="qmail-smtpd"; /* for commands.c */
+char smtpsize[FMT_ULONG+10];
+char **childargs;
+char *hostname;
+char *remoteip;
+char *remotehost;
+char *remoteinfo;
+char *local;
+char *relayclient;
+char *fakehelo;
+char *requireauth;
 
-#define MAXHOPS 100
-unsigned int databytes = 0;
+/* counting */
+int seenrcpt=0;      /* "rcpt to:" counting - tarpitting */
+int rcptcount=0;     /* how much rcpt to: we have allready */
+int seenmail=0;      /* "mail from:" counting - tarpitting */
+int authdone=0;      /* if 1, relay mail is okay */
+int auth_available=0;/* 1, if AUTH command can be used */
+int databytes=0;     /* current max size */
+int spamfeed=0;      /* are we getting spm via $BLCKLISTED */
+int timeoutconnect = 3*60;
 int timeout = 1200;
 
-int safewrite(fd,buf,len) int fd; char *buf; int len;
-{
-  int r;
-  r = timeoutwrite(timeout,fd,buf,len);
-  if (r <= 0) _exit(1);
-  return r;
-}
+stralloc addr     = {0};
+stralloc helohost = {0};
+stralloc greeting = {0};
+stralloc mailfrom = {0};
+stralloc rcptto   = {0};
+stralloc liphost  = {0};
+stralloc rcptchk  = {0};
+stralloc proto = {0};
+
+/* function prototypes */
+int addrallowed(void);
+int addrparse(char *arg);
+int bmcheck(int which, char *what); /* badmail* check */
+int mfcheck(void);    /* mail from check */
+int orcheck(void);    /* open relay check */
+int datecheck(void);  /* usenet-YYYYMMDD check */
+int rcptcheck(void);  /* rcpt to: check against external prog */
+int safewrite(int fd, char *buf, int len);
+int saferead(int fd, char *buf, int len);
+void dohelo(char *arg);
+void tarpit(char*,char*,char*);
+void acceptmessage(unsigned long qp);
+
+/* command functions */
+void smtp_rset(void);
+void smtp_quit(void);
+void smtp_noop(void);
+void smtp_vrfy(void);
+void smtp_data(void);
+void smtp_help(void);
+void smtp_rcpt(char *arg);
+void smtp_mail(char *arg);
+void smtp_helo(char *arg);
+void smtp_ehlo(char *arg);
+void smtp_auth(char *arg);
+void smtp_starttls(char *arg);
+
+extern void realrcptto_init();
+extern int realrcptto();
+
+#define DNS_VRFY -4
+
+/* our buffers */
+char clamdbuf[256];
+char clamsbuf[256];
+char ssinbuf[1024];
+char ssoutbuf[1024];
+char sserrbuf[1024];
+char smtpfrombuf[1024];
 
-char ssoutbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
 substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
+substdio sserr = SUBSTDIO_FDBUF(safewrite,-1,sserrbuf,sizeof sserrbuf);
+substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
+substdio clamdsock = SUBSTDIO_FDBUF(saferead, -1, clamdbuf, sizeof clamdbuf);
+substdio clamssock = SUBSTDIO_FDBUF(saferead, -1, clamsbuf, sizeof clamsbuf);
+
+void die() { flush(); _exit(1); }
+void out_die(char *s) { out_err(s); die(); }
+void dogreet(char *s) { doserv(); out(s); out(greeting.s); doeol(); }
+
+/* rfc2554
+ * 530 Authentication required
+ * 534 Authentication mechanism is too weak
+ * 538 Encryption required for requested authentication mechanism
+ * 454 Temporary authentication failure
+ *
+ * rfc3207
+ * 220 Ready to start TLS
+ * 501 Syntax error (no parameters allowed)
+ * 454 TLS not available due to temporary reason
+ *
+ * rfc1893 + rfc2034 + rfc3463
+ * where:  codes must appear in all 2xx, 4xx, and 5xx lines
+ * except: initial greeting and any response to HELO or EHLO
+ * note:   3xx responses are NOT included in this list
+ */
+void (*die_alarm)(void);
+void die_alarm1()   { out_die("451 4.4.2 timeout"); }
+void die_alarm2()   { Log("die_alarm2()"); flush(); }
+
+void die_read()     { doname(); Log("ERROR: eof from client - SPAMMER?\n"); die(); }
+void die_nomem()    { out_die("421 4.3.0 out of memory"); }
+void die_control()  { out_die("421 4.3.0 unable to read controls"); }
+void die_ipme()     { out_die("421 4.3.0 unable to figure out my IP addresses");  }
+void die_newline()  { out_die("451 4.3.0 see http://pobox.com/~djb/docs/smtplf.html."); }
+void die_smf()      { out_die("451 4.3.0 dns temporary failure"); }
+void die_callback() { out_die("451 4.3.0 sender address verification failed"); }
+void die_nosocket() { out_die("454 4.3.0 too much load / unable to create socket"); }
+void die_qqt()      { out_die("451 4.3.0 qqt failure"); }
+void die_child()    { out_die("454 4.3.0 can't do auth (problem with child)"); }
+void die_fork()     { out_die("454 4.3.0 unable to fork()"); }
+void die_pipe()     { out_die("454 4.3.0 can't do auth (unable to open pipe)"); }
+void die_write()    { out_die("454 4.3.0 can't do auth (unable to write pipe)"); }
+void die_cdb()      { out_die("421 4.3.0 unable to read cdb user database"); }
+void die_sys()      { out_die("421 4.3.0 unable to read system user database"); }
+void die_syserr()   { out_die("421 4.3.0 system error"); }
+
+void die_with1()    { out_die("553 5.1.1 sorry, no mailbox here by that name."); }
+void die_with2()    { out_die("421 4.3.0 unable to verify recipient/sender (misuse)"); }
+void die_with3()    { out_die("421 4.3.0 unable to verify recipient/sender (internal)"); }
+void die_with11()   { out_die("451 4.1.1 bad destination mailbox address"); }
+void die_with12()   { out_die("451 4.1.2 bad destination system address"); }
+void die_with13()   { out_die("451 4.1.3 bad destination mailbox address syntax"); }
+void die_with14()   { out_die("451 4.1.4 destination mailbox address ambiguous"); }
+void die_with16()   { out_die("451 4.1.6 mailbox has moved"); }
+void die_with17()   { out_die("451 4.1.7 bad sender's mailbox address syntax"); }
+void die_with18()   { out_die("451 4.1.8 bad sender's system address"); }
+void die_with21()   { out_die("452 4.2.1 mailbox disabled, not accepting messages"); }
+void die_with22()   { out_die("452 4.2.2 mailbox full"); }
+void die_with111()  { out_die("421 4.3.0 unable to verify recipient/sender (temporary)"); }
+void die_with112()  { out_die("421 4.3.0 unable to verify recipient/sender (greylisting)"); }
+
+/* this is stolen from postfix :) */
+void die_wantrcpt() { out_die("221 2.0.0 error: I can break rules, too. goodbye!"); }
+
+void err_unrecog()  { out_err("500 5.5.2 unrecognised command"); }
+void err_authabrt() { out_err("501 5.0.0 auth exchange cancelled"); }
+void err_authdone() { out_err("503 5.5.0 you're already authenticated"); }
+void err_authmail() { out_err("503 5.5.0 no auth during mail transaction"); }
+void err_unimpl()   { out_err("502 5.5.1 unimplemented"); }
+void err_wantmail() { out_err("503 5.5.1 MAIL first"); }
+int  err_noauth()   { out_err("504 5.5.1 auth type unimplemented"); return -1; }
+int  err_authin()   { out_err("501 5.5.1 malformed auth input"); return -1; }
+void err_authreq()  { out_err("503 5.5.1 you must authenticate first"); }
+void err_authnot()  { out_err("503 5.3.3 auth not available"); }
+void err_synsize()  { out_err("501 5.0.0 bad message size syntax"); }
+void err_size()     { out_err("552 5.3.4 sorry, that message size exceeds my limit"); }
+void err_tmh()      { out_err("554 5.4.6 too many hops, this message is looping"); }
+void err_syntax()   { out_err("501 5.5.4 syntax error"); }
+void err_helo()     { out_err("501 5.5.4 syntax error, I need your hostname"); }
+void err_npa()      { out_err("501 5.5.4 syntax error, no parameters allowed"); }
+void err_badaddr()  { out_err("501 5.5.4 syntax error, bad mail address"); }
+void err_authfail() { out_err("535 5.7.0 authorization failed"); }
+void err_authweak() { out_err("534 5.7.0 authentication mechanism is too weak"); }
+void err_badrcpt()  { out_err("553 5.1.1 sorry, no mailbox here by that name."); }
+
+/* we die after tarpitting! */
+void die_bmf()  { tarpit("553", "5.7.1", "sorry, your envelope sender has been denied"); }
+void die_bmt()  { tarpit("553", "5.7.1", "sorry, your envelope recipient has been denied"); }
+void die_bmh()  { tarpit("553", "5.7.1", "sorry, your helo or ehlo is incorrect"); }
+void die_hmf()  { tarpit("553", "5.7.1", "sorry, your envelope sender domain must exist"); }
+void die_tmr()  { tarpit("553", "5.5.3", "sorry, to many recipients"); }
+void die_rbuf() { tarpit("553", "5.5.3", "sorry, my recipients buffer is to small for you"); }
+void die_nogw() { tarpit("553", "5.7.1", "sorry, that domain isn't in my list of allowed rcpthosts"); }
+void die_lcmd() { tarpit("553", "5.5.2", "sorry, the given command is t00 long!"); }
+void die_date() { tarpit("553", "5.7.1", "sorry, this mailaddy is not valid anymore!"); }
+
+/* tarpit 2 logs some extra info + tarpits */
+void tarpit2(char *code, char *ext, char *msg, char *type, stralloc *smtp) {
+  int l=0,i=0;
 
-void flush() { substdio_flush(&ssout); }
-void out(s) char *s; { substdio_puts(&ssout,s); }
+  if (!stralloc_0(smtp)) die_nomem();
+  for (;;) {
+    l=str_chr(smtp->s+i, '\n');
+    if (!smtp->s[i]) break;
+    doname(); Log(type); Logn(smtp->s+i, l); Log("\n");
+    i+=l+1;
+  }
+  tarpit(code, ext, msg);
+}
 
-void die_read() { _exit(1); }
-void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
-void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
-void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
-void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
-void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
-
-void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
-void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
-void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
-void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
-void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
-void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
-void err_noop() { out("250 ok\r\n"); }
-void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
-void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
+void tarpit(char *code, char *ext, char *msg) {
+  int i=ctl_tarpitdelay;
 
+  if (ctl_log_tarpitting) {
+    doname(); Log("TARPIT: ");
+    if (mailfrom.len){ Log("<"); Logn(mailfrom.s, mailfrom.len-1); Log("> to "); }
+    if (addr.len)    { Log("<"); Logn(addr.s, addr.len-1); Log(">"); }
+    if (helohost.s)  { Log(" | helo(");         Log(helohost.s);  Log(")"); }
+    if (remoteinfo)  { Log(" | remoteinfo(");   Log(remoteinfo);  Log(")"); }
+    Log("\n");
+  }
 
-stralloc greeting = {0};
+  doserv();
+  out(code);Out("-");Log(" ");out(ext);out(" ");
+  out(msg);doeol();
+
+  sleep(i*1+1);
+  Out(code);Out("-");Out(ext);Out(" ");
+  Out("hm let me see ...\r\n");
+  if (flush() == -1) die();
+
+  sleep(i*2+1);
+  Out(code);Out("-");Out(ext);Out(" ");
+  Out("hm does it look good ?\r\n");
+  if (flush() == -1) die();
+
+  sleep(i*3+1);
+  Out(code);Out("-");Out(ext);Out(" ");
+  Out("No! You are a bad guy!\r\n");
+  if (flush() == -1) die();
+
+  sleep(i*4+1);
+  Out(code);Out(" ");Out(ext);Out(" ");
+  Out(msg);Out("\r\n");
+  die(); /* die() flushes */
+}
 
-void smtp_greet(code) char *code;
+void smtp_help(void)
 {
-  substdio_puts(&ssout,code);
-  substdio_put(&ssout,greeting.s,greeting.len);
+  out_err("214 2.0.0 qmail patched (version: " VERSION ")!");
 }
-void smtp_help()
+
+void smtp_noop(void)
 {
-  out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");
+  out_err("250 2.0.0 noop okay");
 }
-void smtp_quit()
+
+void smtp_vrfy(void)
 {
-  smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
+  out_err("252 2.0.0 send some mail, I'll try my best");
 }
 
-char *remoteip;
-char *remotehost;
-char *remoteinfo;
-char *local;
-char *relayclient;
+void smtp_quit(void)
+{
+  out_err("221 2.0.0 good bye!");
+  _exit(0);
+}
 
-stralloc helohost = {0};
-char *fakehelo; /* pointer into helohost, or 0 */
+void smtp_helo(char *arg)
+{
+  if (!*arg) { err_helo(); return; }
+  dohelo(arg);
 
-void dohelo(arg) char *arg; {
-  if (!stralloc_copys(&helohost,arg)) die_nomem(); 
-  if (!stralloc_0(&helohost)) die_nomem(); 
-  fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+  if (ctl_bmh) if (bmcheck(BMCHECK_BMH, helohost.s)) die_bmh();
+
+  rcptcount = 0; seenmail = 0;
+  dogreet("250 ");
 }
 
-int liphostok = 0;
-stralloc liphost = {0};
-int bmfok = 0;
-stralloc bmf = {0};
-struct constmap mapbmf;
+void dosasl() {
+  int i=0,space=0;
+  while (i<SASL_MAX) {
+    if ((*ctl_auth_current & 1<<i) == 1<<i) {
+      if (space) out(" ");
+      out(sasl[i]); space=1;
+    }
+    i++;
+  }
+}
 
-void setup()
+void smtp_ehlo(char *arg)
+{
+  if (!*arg) { err_helo(); return; }
+  dohelo(arg);
+
+  if (ctl_bmh) if (bmcheck(BMCHECK_BMH, helohost.s)) die_bmh();
+
+  rcptcount = 0; seenmail = 0;
+  dogreet("250-");
+  if (auth_available) {
+    if (ctl_auth_oldauth) {
+      doserv(); out("250-AUTH=LOGIN"); doeol(); /* for old progs */
+    }
+    doserv(); out("250-AUTH "); dosasl(); doeol(); /* rfc */
+  }
+  out_err("250-ENHANCEDSTATUSCODES");
+  out_err("250-PIPELINING");
+  if (tls_available && !tls_started) out_err("250-STARTTLS");
+  if (ctl_databytes) out_err(smtpsize);
+
+  /* some people claim that this isn't correct ... who cares :) */
+  out_err("250 8BITMIME");
+  flush();
+}
+
+void smtp_rset()
+{
+  seenmail = 0;
+  seenrcpt = 0;
+  out_err("250 2.0.0 flushed");
+}
+
+/* scan for AUTH= or SIZE= oder BODY= ... in MAIL FROM:... line */
+char *argparse(char *arg, char *what) {
+  char *x=arg;
+  int len=strlen(arg),i;
+  int wl=strlen(what);
+
+  for (i=0; len>i+wl; i+=str_chr(x, ' ')+1) {
+    x+=i;
+    while (*x == ' ') x++; /* skip spaces */
+    if (case_diffb(x, wl, what) == 0) return x+wl;
+  }
+
+  return 0;
+}
+
+void smtp_mail(char *arg)
 {
   char *x;
-  unsigned long u;
- 
-  if (control_init() == -1) die_control();
-  if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
-    die_control();
-  liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);
-  if (liphostok == -1) die_control();
-  if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
-  if (timeout <= 0) timeout = 1;
 
-  if (rcpthosts_init() == -1) die_control();
+  if (!addrparse(arg)) { err_badaddr(); return; }
 
-  bmfok = control_readfile(&bmf,"control/badmailfrom",0);
-  if (bmfok == -1) die_control();
-  if (bmfok)
-    if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
- 
-  if (control_readint(&databytes,"control/databytes") == -1) die_control();
-  x = env_get("DATABYTES");
-  if (x) { scan_ulong(x,&u); databytes = u; }
-  if (!(databytes + 1)) --databytes;
- 
-  remoteip = env_get("TCPREMOTEIP");
-  if (!remoteip) remoteip = "unknown";
-  local = env_get("TCPLOCALHOST");
-  if (!local) local = env_get("TCPLOCALIP");
-  if (!local) local = "unknown";
-  remotehost = env_get("TCPREMOTEHOST");
-  if (!remotehost) remotehost = "unknown";
-  remoteinfo = env_get("TCPREMOTEINFO");
-  relayclient = env_get("RELAYCLIENT");
-  dohelo(remotehost);
+  if (spamfeed) {
+    if (!seenmail) {
+      if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
+      if (!stralloc_0(&mailfrom)) die_nomem();
+    }
+    out_err("250 2.1.0 welcome spammer :)");
+    seenmail = 1; return;
+  }
+
+  /* This is the real databytes initialisation.
+   * If spamfeed is set, the maximum is defined by databytes+ :)
+   */
+  databytes=ctl_databytes;
+  if (ctl_databytes) {
+    if ((x=argparse(arg, "SIZE="))) {
+      if (scan_ulong(x, &databytes) == 0) { err_synsize(); return; }
+      if (databytes > ctl_databytes) { err_size(); return; }
+    }
+  }
+
+  if (ctl_gmf) {
+    if (bmcheck(GMCHECK_GMF, addr.s)) {
+      out_err("250 2.1.0 ok!");
+      if (!stralloc_copys(&rcptto,"")) die_nomem();
+      if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
+      if (!stralloc_0(&mailfrom)) die_nomem();
+      seenmail = 1; return;
+    }
+  }
+  if (ctl_bmf) { if (bmcheck(BMCHECK_BMF, addr.s)) die_bmf(); }
+
+  switch (mfcheck()) {
+    case DNS_HARD: die_hmf();
+    case DNS_SOFT: die_smf();
+    case DNS_MEM:  die_nomem();
+    case DNS_VRFY: die_callback();
+  }
+
+  if (requireauth && !authdone) { err_authreq(); return; }
+
+  if (!stralloc_copys(&rcptto,"")) die_nomem();
+  if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
+  if (!stralloc_0(&mailfrom)) die_nomem();
+  out_err("250 2.1.0 ok");
+  seenmail = 1;
+}
+
+void smtp_rcpt(char *arg)
+{
+  static int init_done=0;
+
+  if (!seenmail) {
+    err_wantmail();
+    return;
+  }
+
+  if (spamfeed) {
+    out_err("250 2.1.5 I feed spamassassin now!");
+    seenrcpt = 1;
+    return;
+  }
+
+  if (ctl_rcpttofixed) {
+    out_err("250 2.1.5 ok!"); /* ok! */
+    seenrcpt = 1;
+    return;
+  }
+
+  if (!init_done) {
+    realrcptto_init();
+    init_done=1;
+  }
+
+  if (!addrparse(arg)) { err_badaddr(); return; }
+  if (ctl_bmt) { if (bmcheck(BMCHECK_BMT, addr.s)) die_bmt(); }
+
+  if (relayclient) {
+    --addr.len; /* remove '\0' */
+    if (!stralloc_cats(&addr,relayclient)) die_nomem();
+    if (!stralloc_0(&addr)) die_nomem();
+  } else {
+    if (!addrallowed()) { die_nogw(); return; }
+  }
+
+  if (!realrcptto(addr.s)) {
+    err_badrcpt(); return;
+  }
+
+  if (authdone) {
+    /* if the user is a 'user@host.domain', than only relaying with a
+     * MAIL FROM:<user@host.domain> is allowed!
+     */
+     if (str_chr(remoteinfo, '@') != strlen(remoteinfo)) {
+       if (!str_equal(mailfrom.s, remoteinfo)) {
+         die_bmf(); /* this function does a tarpit! */
+       }
+     }
+  }
+
+  if (ctl_maxrcpt)
+    if (rcptcount > ctl_maxrcpt)
+      if (!authdone) die_tmr();
+
+  if (ctl_tarpitcount)
+    if (rcptcount > ctl_tarpitcount)
+      if (!authdone) while (sleep(ctl_tarpitdelay));
+
+  datecheck();
+
+  if (!authdone)
+    if (rcptcheck() != 0) { err_badrcpt(); return; }
+
+  if (!stralloc_cats(&rcptto,"T")) die_nomem();
+  if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
+  if (!stralloc_0(&rcptto)) die_nomem();
+
+  seenrcpt = 1;
+  rcptcount += 1;
+  out_err("250 2.1.5 ok");
 }
 
+void smtp_auth(char *arg)
+{
+  char *cmd=arg;
+  int i;
+
+  if (!auth_available) { err_unimpl(); return; }
+  if (authdone) { err_authdone(); return; }
+  if (seenmail) { err_authmail(); return; }
+
+  if (!stralloc_copys(&user,"")) die_nomem();
+  if (!stralloc_copys(&pass,"")) die_nomem();
+  if (!stralloc_copys(&resp,"")) die_nomem();
+
+  i = str_chr(cmd,' ');
+  arg = cmd + i;
+  while (*arg == ' ') ++arg;
+  cmd[i] = 0;
+  for (i = 0; authcmds[i].text; ++i)
+    if (case_equals(authcmds[i].text,cmd))
+      break;
+  auth_for=MODE_SMTPD;
+  switch (authcmds[i].fun(arg)) {
+    case 0:
+      authdone = 1;
+      relayclient = "";
+      remoteinfo = user.s;
+      if (!env_unset("TCPREMOTEINFO")) die_read();
+      if (!env_put2("TCPREMOTEINFO", remoteinfo)) die_nomem();
+      /* for user, which have authenticated, $BLACKLISTED will not work! */
+      spamfeed=0;
+      break;
+    case ERR_AUTH_FAILED: err_authfail(); break;
+    case ERR_AUTH_INPUT:  err_authin();   break;
+    case ERR_AUTH_ABORT:  err_authabrt(); break;
+  }
+}
+
+void smtp_starttls(arg) char *arg; {
+
+  if (!tls_available || tls_started)
+    return err_unimpl(arg);
+  out_err("220 2.0.0 Ready to start TLS");
 
-stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+  if (!ucspitls())
+    die_syserr();
 
-int addrparse(arg)
-char *arg;
+  tls_started = 1;
+  /* reset SMTP state */
+  seenmail = 0;
+}
+
+void dohelo(char *arg)
+{
+  if (!stralloc_copys(&helohost,arg)) die_nomem();
+  if (!stralloc_0(&helohost)) die_nomem();
+  fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+}
+
+int safewrite(int fd, char *buf, int len)
+{
+  int r;
+  r = timeoutwrite(ctl_timeout,fd,buf,len);
+  if (r <= 0) die();
+  return r;
+}
+
+int saferead(int fd, char *buf, int len)
+{
+  int r;
+  flush();
+  r = timeoutread(ctl_timeout,fd,buf,len);
+  if (r == -1) if (errno == error_timeout) die_alarm();
+  if (r <= 0) die_read();
+  return r;
+}
+
+int addrparse(char *arg)
 {
   int i;
   char ch;
   char terminator;
   struct ip_address ip;
-  int flagesc;
-  int flagquoted;
- 
+  int flagesc=0;
+  int flagquoted=0;
+
   terminator = '>';
   i = str_chr(arg,'<');
-  if (arg[i])
+  if (arg[i]) {
     arg += i + 1;
-  else { /* partner should go read rfc 821 */
+  } else {
+    if (ctl_reqbrackets) return 0; /* partner should go read rfc 821 */
+    /* old style, without <> */
     terminator = ' ';
     arg += str_chr(arg,':');
     if (*arg == ':') ++arg;
@@ -162,9 +653,7 @@
   if (*arg == '@') while (*arg) if (*arg++ == ':') break;
 
   if (!stralloc_copys(&addr,"")) die_nomem();
-  flagesc = 0;
-  flagquoted = 0;
-  for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */
+  for (i = 0; (ch = arg[i]); ++i) { /* copy arg to addr, stripping quotes */
     if (flagesc) {
       if (!stralloc_append(&addr,&ch)) die_nomem();
       flagesc = 0;
@@ -178,10 +667,11 @@
       }
     }
   }
+
   /* could check for termination failure here, but why bother? */
   if (!stralloc_append(&addr,"")) die_nomem();
 
-  if (liphostok) {
+  if (ctl_localiphost) {
     i = byte_rchr(addr.s,addr.len,'@');
     if (i < addr.len) /* if not, partner should go read rfc 821 */
       if (addr.s[i + 1] == '[')
@@ -193,118 +683,446 @@
           }
   }
 
-  if (addr.len > 900) return 0;
+  if (addr.len > ctl_maxaddrlen) return 0;
   return 1;
 }
 
-int bmfcheck()
+/* return values:
+ *
+ * 0 == not found / no match
+ * 1 == regex matches
+ */
+int bmcheck(int which, char *what)
 {
-  int j;
-  if (!bmfok) return 0;
-  if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
-  j = byte_rchr(addr.s,addr.len,'@');
-  if (j < addr.len)
-    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+  stralloc *bmb=0;
+  char *type=0;
+  int i=0;
+  regex_t r;
+
+  if (!*what) return 0;
+  switch (which) {
+    case BMCHECK_BMF: type="badmailfrom";  bmb=&bmf; break;
+    case BMCHECK_BMT: type="badmailto";    bmb=&bmt; break;
+    case BMCHECK_BMH: type="badmailhelo";  bmb=&bmh; break;
+    case GMCHECK_GMF: type="goodmailfrom"; bmb=&gmf; break;
+    default: die_control();
+  }
+  if (!bmb) return 0;
+
+  for (i=0; i < bmb->len; i+=strlen(bmb->s+i)+1) {
+    if (ctl_log_bmchecks) {
+      doname();Log("checking ");Log(type);Log(": ");
+    }
+    if (regcomp(&r,bmb->s+i,REG_NOSUB|REG_EXTENDED) == 0) {
+      if (ctl_log_bmchecks) {
+        char *buf=alloca(strlen(bmb->s+i)+strlen(what)+100);
+        int j=fmt_str(buf,"\"");
+        j+=fmt_str(buf+j,bmb->s+i);
+        j+=fmt_str(buf+j,"\" / \"");
+        j+=fmt_str(buf+j,what);
+        j+=fmt_str(buf+j,"\"  (");
+        j+=fmt_ulong(buf+j,i);
+        j+=fmt_str(buf+j,"/");
+        j+=fmt_ulong(buf+j,bmb->len);
+        j+=fmt_str(buf+j,")\n");
+        buf[j]=0; Log(buf);
+      }
+      if (regexec(&r,what,0,0,0) == 0) { regfree(&r); return 1; }
+    } else {
+      char *buf=alloca(strlen(bmb->s+i)+strlen(what)+100);
+      int j=fmt_str(buf,"FAILED REGEX: regcomp(\"");
+      j+=fmt_str(buf+j,bmb->s+i);
+      j+=fmt_str(buf+j,"\" / \"");
+      j+=fmt_str(buf+j,what);
+      j+=fmt_str(buf+j,"\") lengths: (");
+      j+=fmt_ulong(buf+j,i);
+      j+=fmt_str(buf+j,"/");
+      j+=fmt_ulong(buf+j,bmb->len);
+      j+=fmt_str(buf+j,")\n");
+      buf[j]=0; Log(buf);
+    }
+  }
   return 0;
 }
 
 int addrallowed()
 {
   int r;
+
   r = rcpthosts(addr.s,str_len(addr.s));
   if (r == -1) die_control();
+
   return r;
 }
 
+/* news-mail-abuse-YYYYMMDD@svc-box.de */
+int datecheck(void)
+{
+  int len=0;
+
+  if (!ctl_datechecks) return 0;
 
-int seenmail = 0;
-int flagbarf; /* defined if seenmail */
-stralloc mailfrom = {0};
-stralloc rcptto = {0};
+  for (;;) {
+    unsigned long days=0;
+    char *start=dcf.s+len, *sep;
+    int slen;
+
+    len+=strlen(start)+1; /* for the next one */
+    sep=start+str_chr(start, ':');
+    if (!*sep) {
+      slen=strlen(start);
+    } else {
+      if (scan_ulong(sep+1, &days) == 0) die_control();
+      slen=sep-start;
+    }
+    if (days <= 0) days=7; /* default is a week */
+    if (slen > addr.len) continue;
 
-void smtp_helo(arg) char *arg;
-{
-  smtp_greet("250 "); out("\r\n");
-  seenmail = 0; dohelo(arg);
+    if (!case_diffb(addr.s, slen, start)) {
+      time_t max=time(0);
+      time_t min=max-60*60*24*days; /* (60sek * 60min * 24h = tage) */
+      unsigned long actual;
+      if (scan_ulong(addr.s+slen,&actual)==8) {
+        char *x=addr.s+slen;
+        time_t check;
+        struct tm t;
+        t.tm_sec=t.tm_min=t.tm_hour=0;
+        t.tm_year=(x[0]-'0')*1000 + (x[1]-'0')*100 + (x[2]-'0')*10 + (x[3]-'0');
+        t.tm_mon= (x[4]-'0')*10 + (x[5]-'0');
+        t.tm_mday=(x[6]-'0')*10 + (x[7]-'0');
+        t.tm_year-=1900; t.tm_mon-=1;
+        check=mktime(&t);
+        if (ctl_log_datechecks) {
+          doname(); Log("doing datecheck: "); Log(start); Log(" / "); Log(addr.s); Log("\n");
+        }
+        if (check<min || check>max) die_date();
+      }
+    }
+
+    if (len >= dcf.len) break;
+  }
+
+  return 0;
 }
-void smtp_ehlo(arg) char *arg;
+
+stralloc smtptext = {0};
+
+void get(char *ch)
 {
-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
-  seenmail = 0; dohelo(arg);
+  substdio_get(&smtpfrom,ch,1);
+  if (*ch != '\r')
+    if (smtptext.len < HUGESMTPTEXT)
+      if (!stralloc_append(&smtptext,ch)) die_nomem();
 }
-void smtp_rset()
+
+unsigned int smtpcode(void)
 {
-  seenmail = 0;
-  out("250 flushed\r\n");
+  char ch;
+  unsigned int code;
+
+  if (!stralloc_copys(&smtptext,"")) die_nomem();
+
+  get(&ch); code = ch - '0';
+  get(&ch); code = code * 10 + (ch - '0');
+  get(&ch); code = code * 10 + (ch - '0');
+  for (;;) {
+    get(&ch);
+    if (ch != '-') break;
+    while (ch != '\n') get(&ch);
+    get(&ch); get(&ch); get(&ch);
+  }
+  while (ch != '\n') { get(&ch); }
+
+  return code;
 }
-void smtp_mail(arg) char *arg;
+
+/**
+ * ip_is_in_mx_blacklist() - test, if the ip isn't allowed as mx
+ *
+ * 0 = okay
+ * 1 = not okay (is listed)
+ */
+int ip_is_in_mx_blacklist(struct ip_address *mx)
 {
-  if (!addrparse(arg)) { err_syntax(); return; }
-  flagbarf = bmfcheck();
-  seenmail = 1;
-  if (!stralloc_copys(&rcptto,"")) die_nomem();
-  if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
-  if (!stralloc_0(&mailfrom)) die_nomem();
-  out("250 ok\r\n");
-}
-void smtp_rcpt(arg) char *arg; {
-  if (!seenmail) { err_wantmail(); return; }
-  if (!addrparse(arg)) { err_syntax(); return; }
-  if (flagbarf) { err_bmf(); return; }
-  if (relayclient) {
-    --addr.len;
-    if (!stralloc_cats(&addr,relayclient)) die_nomem();
-    if (!stralloc_0(&addr)) die_nomem();
+  int i,k=0;
+  char *x;
+  struct ip_address ip;
+
+  for (i=0; i < mxbl.len; i+=strlen(mxbl.s+i)+1) {
+    x=mxbl.s+i;
+    k=ip_scan(mxbl.s, &ip);
+    if (k) {
+      if (byte_equal(mx, sizeof(struct ip_address), &ip)) {
+	return 1;
+      }
+    }
+    k=0;
   }
-  else
-    if (!addrallowed()) { err_nogateway(); return; }
-  if (!stralloc_cats(&rcptto,"T")) die_nomem();
-  if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
-  if (!stralloc_0(&rcptto)) die_nomem();
-  out("250 ok\r\n");
+
+  return 0;
 }
 
+void mfcheck_close(void)
+{
+  timeoutwrite(timeout, smtpfrom.fd,"RSET\r\n", 6);
+  timeoutwrite(timeout, smtpfrom.fd,"QUIT\r\n", 6);
+  close(smtpfrom.fd);
+  return;
+}
 
-int saferead(fd,buf,len) int fd; char *buf; int len;
+/* mail from: check
+ *
+ *  0 = okay
+ * -1 = dns soft
+ * -2 = dns hard
+ * -3 = dns mem
+ * -4 = callback temp. failed (DNS_VRFY)
+ */
+int mfcheck(void)
 {
-  int r;
-  flush();
-  r = timeoutread(timeout,fd,buf,len);
-  if (r == -1) if (errno == error_timeout) die_alarm();
-  if (r <= 0) die_read();
-  return r;
+  stralloc sa = {0};
+  ipalloc ia = {0};
+  unsigned int random;
+  int i,code;
+
+  if (authdone) return 0; /* valid auth. was done, no need for checking */
+  if (ctl_mfcheck <= 0) return 0; /* mfcheck is disabled */
+
+  i = byte_rchr(addr.s, addr.len, '@') + 1;
+  if (i >= addr.len) return 0;
+  random = now() + (getpid() << 16);
+  dns_init(0);
+  if (!stralloc_copys(&sa, addr.s + i)) die_nomem();
+  i = dns_mxip(&ia,&sa,random);
+  if (i < 0) return i; /* -1 -2 -3 */
+  if (ia.len < 1) { stralloc_0(&sa); return DNS_SOFT; }
+  if (ctl_mfcheck <= 1) return 0; /* mfcheck is only 1 */
+
+  /* SMTP callback/sender verification */
+  for (i=0; i<ia.len; ++i) { /* TODO */
+
+    if (ip_is_in_mx_blacklist(&ia.ix[i].ip)) {
+      tarpit("451", "4.1.8", "bad sender's system address, your mx is blacklisted!");
+    }
+
+    smtpfrom.p=smtpfrom.n=0;
+    smtpfrom.fd=socket(AF_INET,SOCK_STREAM,0);
+    smtpfrom.p=smtpfrom.n=0;
+    if (smtpfrom.fd == -1) { die_nosocket(); }
+    if (ipme_is(&ia.ix[i].ip)) return 0;
+
+    if (timeoutconn(smtpfrom.fd, &ia.ix[i].ip, &outip, 25, timeoutconnect) != 0) {
+      tarpit("451", "4.1.8", "bad sender's system address, can't contact your mx!");
+    }
+
+    code = smtpcode();
+    if (code >= 400) {
+      mfcheck_close();
+      continue; /* try next one */
+    }
+
+    if (!stralloc_ready(&sa,20+me.len)) die_nomem();
+    if (!stralloc_copys(&sa,"HELO ")) die_nomem();
+    if (!stralloc_cat(&sa,&me)) die_nomem();
+    if (!stralloc_cats(&sa,"\r\n")) die_nomem();
+    if (timeoutwrite(timeout,smtpfrom.fd,sa.s,sa.len) == -1) {
+      tarpit("451", "4.1.8", "bad sender's system address, sending data failed!");
+    }
+
+    code = smtpcode();
+    if (code >= 400) {
+      mfcheck_close();
+      continue; /* try next one */
+    }
+
+    if (timeoutwrite(timeout,smtpfrom.fd,"MAIL FROM:<>\r\n",14) == -1) {
+      tarpit("451", "4.1.8", "bad sender's system address, sending data failed!");
+    }
+
+    code = smtpcode();
+    if (code >= 400) {
+      mfcheck_close();
+      continue; /* try next one */
+    }
+
+    if (!stralloc_ready(&sa,20+addr.len)) die_nomem();
+    if (!stralloc_copys(&sa,"RCPT TO:<")) die_nomem();
+    if (!stralloc_cats(&sa, addr.s)) die_nomem();
+    if (!stralloc_cats(&sa,">\r\n")) die_nomem();
+    if (timeoutwrite(timeout,smtpfrom.fd,sa.s,sa.len) == -1) {
+      tarpit("451", "4.1.8", "bad sender's mailbox address, sending data failed!");
+    }
+
+    code = smtpcode();
+    if (code >= 500) { /* temp. errors are okay / greylisting! */
+      if (!stralloc_copys(&sa, "bad sender's mailbox address, RCPT TO:<")) die_nomem();
+      if (!stralloc_cats(&sa, addr.s)) die_nomem();
+      if (!stralloc_cats(&sa, "> failed")) die_nomem();
+      if (!stralloc_0(&sa)) die_nomem();
+      mfcheck_close();
+      tarpit2("550", "5.1.8", sa.s, "BounceTest: ", &smtptext);
+    }
+
+    mfcheck_close(); /* testbounce was okay */
+    if (!stralloc_copys(&sa, "bad sender's mailbox address, RCPT TO:<")) die_nomem();
+    if (!stralloc_cats(&sa, addr.s)) die_nomem();
+    if (!stralloc_cats(&sa, "> failed")) die_nomem();
+    if (!stralloc_0(&sa)) die_nomem();
+    return 0; /* return OK */
+  } /* for(all mx) */
+
+  return DNS_VRFY;
 }
 
-char ssinbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+int rcptcheck(void)
+{
+  int pid;
+  int wstat;
+  char *av[2] = { rcptchk.s, 0 };
+
+  if (!ctl_rcptchecks) return 0;
+
+  switch (pid=fork()) {
+    case -1:
+      die_fork();
+      break;
+    case 0:
+      if (!env_put2("SENDER", mailfrom.s)) die_nomem();
+      if (!env_put2("RECIPIENT", addr.s)) die_nomem();
+      execv(av[0], av);
+      _exit(120);
+      break;
+  }
+
+  if (wait_pid(&wstat,pid) == -1) die_with3();
+  if (wait_crashed(wstat)) die_with3();
+
+  switch (wait_exitcode(wstat)) {
+    case   0: return 0;
+    case   2: die_with2();
+    case  11: die_with11();
+    case  12: die_with12();
+    case  13: die_with13();
+    case  14: die_with14();
+    case  15: return 0;
+    case  16: die_with16();
+    case  17: die_with17();
+    case  18: die_with18();
+    case  21: die_with21();
+    case  22: die_with22();
+    case 111: die_with111();
+    case 112: die_with112();
+  }
+
+  /* invalid addresses */
+  return 1;
+}
 
 struct qmail qqt;
 unsigned int bytestooverflow = 0;
+stralloc clamtext = {0};
 
-void put(ch)
-char *ch;
+void clamget(char *ch)
 {
+  substdio_get(&clamdsock,ch,1);
+  if (*ch != '\r')
+    if (clamtext.len < HUGESMTPTEXT)
+      if (!stralloc_append(&clamtext,ch)) die_nomem();
+}
+
+void put(char *ch)
+{
+  if (clamd_streamok) {
+    if (timeoutwrite(timeout,clamssock.fd,ch,1) == -1) {
+      doname();
+      Log("problem sending data to clamd stream, skipping the scan!\n");
+      flush();
+      /* we have reached the maximum stream length? */
+      close(clamdsock.fd); close(clamssock.fd); clamd_streamok=0;
+    }
+  }
+
   if (bytestooverflow)
     if (!--bytestooverflow)
       qmail_fail(&qqt);
+
   qmail_put(&qqt,ch,1);
 }
 
-void blast(hops)
-int *hops;
+unsigned int clamport(void)
+{
+  char ch;
+  unsigned int port;
+
+  for (;;) { clamget(&ch); if (ch == ' ') break; }
+  if (!stralloc_copys(&clamtext,"")) die_nomem();
+  for (;;) { clamget(&ch); if (ch == '\n') break; }
+  clamtext.s[clamtext.len]=0;
+  if (scan_ulong(clamtext.s, &port) == 0) return 0;
+
+  return port;
+}
+
+void blast(int *hops)
 {
   char ch;
   int state;
   int flaginheader;
-  int pos; /* number of bytes since most recent \n, if fih */
+  unsigned int pos; /* number of bytes since most recent \n, if fih */
   int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
   int flagmaybey; /* 1 if this line might match \r\n, if fih */
   int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
- 
+
   state = 1;
   *hops = 0;
   flaginheader = 1;
   pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
+
+  if (ctl_clamd) {
+    clamd_streamok = 0; /* reset to unknown state */
+    if (clamd.s) {
+      /* use unix domain socket for control connection */
+      struct sockaddr_un un;
+      clamdsock.fd = socket(AF_UNIX,SOCK_STREAM,0);
+      if (clamdsock.fd == -1) goto blast;
+      un.sun_family = AF_UNIX;
+      un.sun_path[fmt_strn(un.sun_path, clamd.s, sizeof(un.sun_path))]=0;
+      if (connect(clamdsock.fd, (struct sockaddr*)&un, sizeof(un)) == -1) {
+        doname(); Log("problem while connecting to clamd unix socket!\n"); flush();
+        goto blast;
+      }
+    } else {
+      /* use tcp stream for control connection */
+      clamdsock.fd = socket(AF_INET,SOCK_STREAM,0);
+      if (clamdsock.fd == -1) {
+        doname(); Log("problem creating socket for clamd control connection!\n"); flush();
+        goto blast;
+      }
+      if (timeoutconn(clamdsock.fd, &clamd_ip, &outip, clamd_port, timeoutconnect) != 0) {
+        doname(); Log("problem while connecting to clamd!\n"); flush();
+        goto blast;
+      }
+    }
+    /* scanning stream */
+    clamssock.fd = socket(AF_INET,SOCK_STREAM,0);
+    if (clamssock.fd == -1) {
+      doname(); Log("problem creating socket for clamd scan stream!\n"); flush();
+      goto blast;
+    }
+    if (timeoutwrite(timeout,clamdsock.fd,"STREAM\n",7) == -1) {
+      doname(); Log("problem sending STREAM command to clamd!\n"); flush();
+      goto blast;
+    }
+    clamd_sport = clamport();
+    if (clamd_sport == 0) goto blast;
+    if (timeoutconn(clamssock.fd, &clamd_ip, &outip, clamd_sport, timeoutconnect) != 0) {
+      doname(); Log("problem with connecting to clamd stream!\n"); flush();
+      goto blast;
+    }
+    clamd_streamok=1;
+  }
+
+  blast:
   for (;;) {
     substdio_get(&ssin,&ch,1);
     if (flaginheader) {
@@ -322,17 +1140,17 @@
     }
     switch(state) {
       case 0:
-        if (ch == '\n') straynewline();
+        if (ch == '\n') die_newline();
         if (ch == '\r') { state = 4; continue; }
         break;
       case 1: /* \r\n */
-        if (ch == '\n') straynewline();
+        if (ch == '\n') die_newline();
         if (ch == '.') { state = 2; continue; }
         if (ch == '\r') { state = 4; continue; }
         state = 0;
         break;
       case 2: /* \r\n + . */
-        if (ch == '\n') straynewline();
+        if (ch == '\n') die_newline();
         if (ch == '\r') { state = 3; continue; }
         state = 0;
         break;
@@ -351,71 +1169,426 @@
   }
 }
 
-char accept_buf[FMT_ULONG];
-void acceptmessage(qp) unsigned long qp;
+
+void acceptmessage(unsigned long qp)
 {
+  char accept_buf[FMT_ULONG];
   datetime_sec when;
   when = now();
-  out("250 ok ");
+  doserv(); out("250 2.6.0 ok ");
   accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
   out(accept_buf);
   out(" qp ");
   accept_buf[fmt_ulong(accept_buf,qp)] = 0;
   out(accept_buf);
-  out("\r\n");
+  doeol();
 }
 
-void smtp_data() {
+void smtp_data(void) {
   int hops;
   unsigned long qp;
   char *qqx;
- 
+  char at[FMT_ULONG];
+
   if (!seenmail) { err_wantmail(); return; }
-  if (!rcptto.len) { err_wantrcpt(); return; }
+  if (!seenrcpt) { die_wantrcpt(); }
   seenmail = 0;
-  if (databytes) bytestooverflow = databytes + 1;
-  if (qmail_open(&qqt) == -1) { err_qqt(); return; }
+
+  /* rfc 1870 says:
+   * A server is permitted, but not required, to accept a message which
+   * is, in fact, larger than declared in the extended MAIL command, such
+   * as might occur if the client employed a size-estimation heuristic
+   * which was inaccurate.
+   * -> we take 5kb +/- for the given size
+   * -> the size stands for message+headers!
+   */
+  if (ctl_databytes) {
+    bytestooverflow = ctl_databytes + ctl_databytesP;
+  }
+  if (qmail_open(&qqt) == -1) { die_qqt(); }
   qp = qmail_qp(&qqt);
-  out("354 go ahead\r\n");
- 
-  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+  out_err("354 go ahead");
+
+  doname(); Log("C: [...] ");
+  at[fmt_ulong(at,bytestooverflow)]=0; Log(" bytestooverflow=");Log(at);
+  Log("\n");
+
+  /* rfc3848 support: ESMTPA => auth | ESMTPS => tls | ESMTPSA => tls+auth */
+  if (tls_started && authdone) {
+    if (!stralloc_cats(&proto, "ESMTPSA")) die_nomem();
+  } else if (authdone) {
+    if (!stralloc_copys(&proto, "SMTPA")) die_nomem();
+  } else if (tls_started) {
+    if (!stralloc_cats(&proto, "ESMTPS")) die_nomem();
+  } else {
+    if (!stralloc_copys(&proto, "SMTP")) die_nomem();
+  }
+  if (!stralloc_0(&proto)) die_nomem();
+
+  received(&qqt,proto.s,local,remoteip,remotehost,remoteinfo,fakehelo);
+  if (ctl_p0fsock) p0f_received(&qqt, remoteip);
   blast(&hops);
-  hops = (hops >= MAXHOPS);
+  hops = (hops >= ctl_maxhops);
   if (hops) qmail_fail(&qqt);
   qmail_from(&qqt,mailfrom.s);
   qmail_put(&qqt,rcptto.s,rcptto.len);
- 
+
+  if (clamd_streamok) {
+    fd_set rfds;
+    struct timeval tv;
+    char ch;
+    stralloc sa = {0};
+
+    close(clamssock.fd);
+    FD_ZERO(&rfds);
+    FD_SET(clamdsock.fd, &rfds);
+    tv.tv_sec = 1; tv.tv_usec = 0;
+    if (select(clamdsock.fd+1, &rfds, NULL, NULL, &tv)) {
+      if (FD_ISSET(clamdsock.fd, &rfds)) {
+	if (!stralloc_copys(&clamtext,"")) die_nomem();
+	for (;;) { clamget(&ch); if (ch == '\n') break; }
+	/* "stream: Worm.Sober.I FOUND\n" -> "Worm.Sober.I" */
+	clamtext.s[clamtext.len-1]=0;
+	if (strstr(clamtext.s, "FOUND")) {
+	  clamtext.s[clamtext.len-7]=0;
+	  doname(); Log("CLAMD: virus '"); Log(clamtext.s+8); Log("' was found!\n"); flush();
+	  if (!stralloc_copys(&sa, "your email contains the virus '")) die_nomem();
+	  if (!stralloc_cats(&sa, clamtext.s+8)) die_nomem();
+	  if (!stralloc_cats(&sa, "'!")) die_nomem();
+	  if (!stralloc_0(&sa)) die_nomem();
+	  tarpit("554", "5.7.7", sa.s);
+	}
+      }
+    }
+    close(clamdsock.fd);
+  }
+
   qqx = qmail_close(&qqt);
   if (!*qqx) { acceptmessage(qp); return; }
-  if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
-  if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
-  if (*qqx == 'D') out("554 "); else out("451 ");
-  out(qqx + 1);
-  out("\r\n");
+  if (hops)  { err_tmh(); return; }
+
+  doname(); Log("debug: got a message, which was to big: ");
+  at[fmt_ulong(at,bytestooverflow)]=0; Log(" bytestooverflow=");Log(at);
+  at[fmt_ulong(at,ctl_databytes)]=0; Log(" ctl_databytes=");Log(at);
+  at[fmt_ulong(at,databytes)]=0; Log(" databytes=");Log(at);
+  Log("\n");
+
+  if (ctl_databytes) if (!bytestooverflow) { err_size(); return; }
+  doserv(); if (*qqx == 'D') out("554 "); else out("451 "); out(qqx + 1); doeol();
+}
+
+void setup()
+{
+  char *x=0;
+
+  /* change to QMAILHOME/control */
+  if (chdir(auto_qmail) == -1) die_control();
+
+  die_alarm=&die_alarm1; /* set the  default */
+
+  /* reading control/me */
+  if (control_init() == -1) die_control(); hostname=me.s;
+  if (rcpthosts_init() == -1) die_control();
+
+  /* fill greeting.s */
+  if (control_readfile(&greeting,"control/smtpgreeting",1) != 1) die_control();
+  greeting.s[greeting.len]=0;
+
+  /* overides controlfile */
+  if ((x=getenv("SMTPGREETING"))) {
+    greeting.s=x; greeting.len=strlen(x);
+  }
+
+  /* now the logging stuff */
+  if (control_readint(&ctl_log_in, "control/log/smtp_in") == -1) die_control();
+  if (control_readint(&ctl_log_fd, "control/log/smtp_fd") == -1) die_control();
+  if (control_readint(&ctl_log_out,"control/log/smtp_out") == -1) die_control();
+  if (ctl_log_in  < 0) ctl_log_in=0;
+  if (ctl_log_out < 0) ctl_log_out=0;
+  if (ctl_log_fd  < 0) ctl_log_fd=2;
+  sserr.fd = ctl_log_fd;
+
+  /* is there a p0f socket for remote OS information */
+  ctl_p0fsock=env_get("P0FSOCK");
+  if (!ctl_p0fsock) ctl_p0fsock="control/p0fsock";
+  if ((access(ctl_p0fsock, R_OK|W_OK) != 0)) ctl_p0fsock=0;
+
+  /* checking for viruses with clamav */
+  ctl_clamd = control_readline(&clamd, "control/clamd");
+  if (ctl_clamd == -1) die_control();
+  if (ctl_clamd) {
+    clamd.s[clamd.len]=0;
+    if (clamd.s[0] == '/') {
+      /* hopefully a full path to the socket */
+      clamd.s[clamd.len]=0;
+    } else {
+      /* ip:port */
+      int i=ip_scan(clamd.s, &clamd_ip);
+      if (!i) die_control();
+      i=scan_ulong(clamd.s+i+1, &clamd_port);
+      if (!i) die_control();
+      clamd.s=0;
+    }
+  }
+
+  if (env_get("NO_CLAMD")) {
+    ctl_clamd=0; /* disable checking, regardless of good control files */
+  }
+
+  switch (control_readline(&ctl_outgoingip,"control/outgoingip")) {
+    case -1:
+      if (errno == error_nomem) die_nomem();
+      die_control();
+      break;
+    case 0:
+      if (!stralloc_copys(&ctl_outgoingip, "0.0.0.0")) die_nomem();
+      break;
+  }
+  if (str_equal(ctl_outgoingip.s, "0.0.0.0")) {
+    outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long)0;
+  } else if (!ip_scan(ctl_outgoingip.s, &outip)) die_control();
+
+
+
+  ctl_localiphost = control_rldef(&liphost,"control/localiphost",1,(char *) 0);
+  if (ctl_localiphost == -1) die_control();
+
+  if (control_readint(&ctl_timeout,"control/timeoutsmtpd") == -1) die_control();
+  if (ctl_timeout <= 0) ctl_timeout = DEFAULT_TIMEOUT;
+
+  /* log checks of misc stuff ? (all default to off) */
+  if (control_readint(&ctl_log_bmchecks,"control/log/bmchecks") == -1) die_control();
+  if (ctl_log_bmchecks < 0) ctl_log_bmchecks = 0;
+  if (control_readint(&ctl_log_orchecks,"control/log/orchecks") == -1) die_control();
+  if (ctl_log_orchecks < 0) ctl_log_orchecks = 0;
+  if (control_readint(&ctl_log_tarpitting,"control/log/tarpitting") == -1) die_control();
+  if (ctl_log_tarpitting < 0) ctl_log_tarpitting = 0;
+  if (control_readint(&ctl_log_datechecks,"control/log/datechecks") == -1) die_control();
+  if (ctl_log_datechecks < 0) ctl_log_datechecks = 0;
+
+  /* mfcheck patch (dns check) */
+  if (env_get("NO_MFCHECK")) {
+    ctl_mfcheck=0;
+  } else {
+    x = env_get("MFCHECK");
+    if (x) {
+      if (scan_ulong(x,&ctl_mfcheck) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_mfcheck,"control/mfcheck") == -1) die_control();
+    }
+  }
+
+  /* orcheck patch (open relay checks) */
+  if (env_get("NO_ORCHECK")) {
+    ctl_orcheck=0;
+  } else {
+    x = env_get("ORCHECK");
+    if (x) {
+      if (scan_ulong(x,&ctl_orcheck) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_orcheck,"control/orcheck") == -1) die_control();
+    }
+  }
+
+  /* tarpitting */
+  if (env_get("NO_TARPITTING")) {
+    ctl_tarpitcount=0;
+    ctl_tarpitdelay=0;
+  } else {
+    x = env_get("TARPITCOUNT");
+    if (x) {
+      if (scan_ulong(x,&ctl_tarpitcount) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_tarpitcount,"control/tarpitcount") == -1)
+        die_control();
+    }
+    x = env_get("TARPITDELAY");
+    if (x) {
+      if (scan_ulong(x,&ctl_tarpitdelay) == 0) die_control();
+    } else {
+      if (control_readint(&ctl_tarpitdelay,"control/tarpitdelay") == -1)
+        die_control();
+    }
+  }
+
+  if ((x=env_get("BLACKLISTED"))) {
+    /* each "RCPT TO" will be ignored and send to <$BLACKLISTED> */
+    spamfeed=1;
+    if (!stralloc_copys(&rcptto, "T")) die_nomem();
+    if (!stralloc_cats(&rcptto, x)) die_nomem();
+    if (!stralloc_0(&rcptto)) die_nomem();
+  } else if ((x=env_get("RCPTTOFIXED"))) {
+    /* each mail goes to <$RCPTTOFIXED> */
+    ctl_rcpttofixed=1;
+    if (!stralloc_copys(&rcptto, "T")) die_nomem();
+    if (!stralloc_cats(&rcptto, x)) die_nomem();
+    if (!stralloc_0(&rcptto)) die_nomem();
+  }
+
+  /* esmtp auth options */
+  if (control_readint(&ctl_auth_delay,    "control/auth/delay") == -1) die_control();
+  if (control_readint(&ctl_auth_secure,   "control/auth/smtps") == -1) die_control();
+  if (control_readint(&ctl_auth_insecure, "control/auth/smtp")  == -1) die_control();
+  if (control_readint(&ctl_auth_oldauth,  "control/auth/oldauth") == -1) die_control();
+
+  /* checking of sender/recipient via external program */
+  ctl_rcptchecks = control_readline(&rcptchk, "control/rcptcheck");
+  if (ctl_rcptchecks == -1) die_control();
+  x=env_get("RCPTCHECK"); /* overrides controlfile */
+  if (x) { ctl_rcptchecks=1; stralloc_copys(&rcptchk, x); }
+  if (ctl_rcptchecks) rcptchk.s[rcptchk.len]=0;
+
+  /* badhelo - checking against HELO/EHLO <xxx> */
+  if (env_get("NO_BADHELO")) {
+    ctl_bmh=0;
+  } else {
+    x = env_get("BADHELO"); if (!x) x = "control/badhelo";
+    ctl_bmh = control_readfile(&bmh,x,0);
+    if (ctl_bmh == -1) die_control();
+  }
+
+  /* badmailfrom - checking against MAIL FROM:<xxx> */
+  if (env_get("NO_BADMAILFROM")) {
+    ctl_bmf=0;
+  } else {
+    x = env_get("BADMAILFROM"); if (!x) x = "control/badmailfrom";
+    ctl_bmf = control_readfile(&bmf,x,0);
+    if (ctl_bmf == -1) die_control();
+  }
+
+  /* badmailto - checking against RCPT TO:<xxx> */
+  if (env_get("NO_BADMAILTO")) {
+    ctl_bmt=0;
+  } else {
+    x = env_get("BADMAILTO"); if (!x) x = "control/badmailto";
+    ctl_bmt = control_readfile(&bmt,x,0);
+    if (ctl_bmt == -1) die_control();
+  }
+
+  /* goodmailfrom - checking against MAIL FROM:<xxx> */
+  if (env_get("NO_GOODMAILFROM")) {
+    ctl_gmf=0;
+  } else {
+    x = env_get("GOODMAILFROM"); if (!x) x = "control/goodmailfrom";
+    ctl_gmf = control_readfile(&gmf,x,0);
+    if (ctl_gmf == -1) die_control();
+  }
+
+  /* maxrcpt */
+  if (env_get("NO_MAXRCPT")) {
+    ctl_bmf=0;
+  } else { /* XXX: should MAXRCPT contain the int? */
+    x = env_get("MAXRCPT"); if (!x) x = "control/maxrcpt";
+    if (control_readint(&ctl_maxrcpt,x,0) == -1) die_control();
+    if (ctl_maxrcpt < 0) ctl_maxrcpt=0;
+  }
+
+  /* maxhops limit is now changeable on the fly */
+  if (control_readint(&ctl_maxhops, "control/maxhops") == -1) die_control();
+  if (ctl_maxhops <= 0) ctl_maxhops=DEFAULT_MAXHOPS;
+
+  /* max length of an email address */
+  if (control_readint(&ctl_maxaddrlen, "control/maxaddrlen") == -1) die_control();
+  if (ctl_maxaddrlen <= 0) ctl_maxaddrlen=900; /* default from djb */
+
+  /* buffer limit for commands */
+  if (control_readint(&ctl_maxcmdlen, "control/maxcmdlen") == -1) die_control();
+  if (ctl_maxcmdlen < 0) ctl_maxcmdlen=0;
+
+  /* enforce <> in the mail from & rcpt to */
+  if (control_readint(&ctl_reqbrackets, "control/reqbrackets") == -1) die_control();
+  if (ctl_reqbrackets < 0) ctl_reqbrackets=1;
+
+  /* read file into dcf (date control file) */
+  ctl_datechecks = control_readfile(&dcf, "control/datechecks", 0);
+  if (ctl_datechecks == -1) die_control();
+
+  /* load ip blacklist of not useable ip's as dnsmx */
+  ctl_mxblacklist = control_readfile(&mxbl,"control/mxblacklist", 0);
+  if (ctl_mxblacklist == -1) die_control();
+  if (ctl_mxblacklist) {
+    int ip=0,i=0;
+    if (!stralloc_0(&mxbl)) die_nomem();
+    for (; i<mxbl.len; ++i)
+    if (mxbl.s[i]=='\n') {
+      ip++; mxbl.s[i]=0; if (ip>10000) die_control();
+    }
+  }
+
+  /* size limits */
+  if (control_readint(&ctl_databytesP,"control/databytes+") == -1) die_control();
+  if (ctl_databytesP <= 0) ctl_databytesP=5000;
+
+  if (control_readint(&ctl_databytes,"control/databytes") == -1) die_control();
+  x = env_get("DATABYTES");
+  if (x) { scan_ulong(x,&ctl_databytes); }
+  if (ctl_databytes < 0) ctl_databytes=0;
+
+  if (ctl_databytes) {
+    x=smtpsize;
+    x+=fmt_str(x,"250-SIZE ");
+    x+=fmt_uint(x,ctl_databytes);
+    *x=0;
+  }
+
+  x="unknown";
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) remoteip = x;
+
+  local = env_get("TCPLOCALHOST");
+  if (!local) local = env_get("TCPLOCALIP");
+  if (!local) local = x;
+
+  remotehost = env_get("TCPREMOTEHOST");
+  if (!remotehost) remotehost = x;
+
+  remoteinfo  = env_get("TCPREMOTEINFO");
+  relayclient = env_get("RELAYCLIENT");
+  requireauth = env_get("REQUIREAUTH");
+
+  dohelo(remotehost);
 }
 
 struct commands smtpcommands[] = {
   { "rcpt", smtp_rcpt, 0 }
 , { "mail", smtp_mail, 0 }
+, { "rset", smtp_rset, 0 }
 , { "data", smtp_data, flush }
 , { "quit", smtp_quit, flush }
 , { "helo", smtp_helo, flush }
 , { "ehlo", smtp_ehlo, flush }
-, { "rset", smtp_rset, 0 }
 , { "help", smtp_help, flush }
-, { "noop", err_noop, flush }
-, { "vrfy", err_vrfy, flush }
-, { 0, err_unimpl, flush }
-} ;
+, { "auth", smtp_auth, flush }
+, { "noop", smtp_noop, flush }
+, { "vrfy", smtp_vrfy, flush }
+, { "starttls", smtp_starttls, flush }
+, { 0, err_unrecog, flush }
+};
 
-void main()
+int main(int argc, char **argv)
 {
+  int i=0;
+  childargs = argv + 1;
+
   sig_pipeignore();
-  if (chdir(auto_qmail) == -1) die_control();
   setup();
+  p0f_query();
+
+  tls_available = !!env_get("UCSPITLS");
+
   if (ipme_init() != 1) die_ipme();
-  smtp_greet("220 ");
-  out(" ESMTP\r\n");
-  if (commands(&ssin,&smtpcommands) == 0) die_read();
-  die_nomem();
+  while (1) {
+    i+=strlen(greeting.s+i)+1;
+    if (i >= greeting.len) {
+      doserv(); out("220 "); out(greeting.s); doeol(); break;
+    } else {
+      doserv(); out("220-"); out(greeting.s+i); doeol();
+    }
+  }
+
+  if (!*childargs) { auth_available=0; } else { auth_available=1; }
+  if (commands(&ssin, &sserr, &smtpcommands) == 0) die_read();
+  die();
+
+  return 0; /* gcc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-start.c qmail-1.03-md24/qmail-start.c
--- qmail-1.03-vanilla/qmail-start.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-start.c	2007-07-19 20:56:22.000000000 +0200
@@ -27,7 +27,7 @@
   close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]);
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -117,4 +117,5 @@
   closepipes();
   execvp(*qsargs,qsargs);
   die();
+  return 0; /* cc happyness */
 }
diff -urN qmail-1.03-vanilla/qmail-tcpok.c qmail-1.03-md24/qmail-tcpok.c
--- qmail-1.03-vanilla/qmail-tcpok.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-tcpok.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "strerr.h"
 #include "substdio.h"
 #include "lock.h"
@@ -11,7 +13,7 @@
 char buf[1024]; /* XXX: must match size in tcpto_clean.c, tcpto.c */
 substdio ss;
 
-void main()
+int main()
 {
   int fd;
   int i;
diff -urN qmail-1.03-vanilla/qmail-tcpto.c qmail-1.03-md24/qmail-tcpto.c
--- qmail-1.03-vanilla/qmail-tcpto.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qmail-tcpto.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,7 @@
 /* XXX: this program knows quite a bit about tcpto's internals */
 
+#include <sys/types.h>
+#include <unistd.h>
 #include "substdio.h"
 #include "subfd.h"
 #include "auto_qmail.h"
@@ -10,6 +12,8 @@
 #include "exit.h"
 #include "datetime.h"
 #include "now.h"
+#include "open.h"
+#include "byte.h"
 
 void die(n) int n; { substdio_flush(subfdout); _exit(n); }
 
@@ -32,7 +36,7 @@
 
 char tmp[FMT_ULONG + IPFMT];
 
-void main()
+int main()
 {
  int fdlock;
  int fd;
@@ -81,5 +85,6 @@
    record += 16;
   }
 
- die(0);
+ _exit(0);
+ return 0;
 }
diff -urN qmail-1.03-vanilla/qreceipt.c qmail-1.03-md24/qreceipt.c
--- qmail-1.03-vanilla/qreceipt.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qreceipt.c	2007-07-19 20:56:22.000000000 +0200
@@ -92,9 +92,10 @@
  qmail_to(&qqt,returnpath);
  qqx = qmail_close(&qqt);
 
- if (*qqx)
+ if (*qqx) {
    if (*qqx == 'D') die_qqperm();
    else die_qqtemp();
+ }
 }
 
 stralloc hfbuf = {0};
@@ -119,7 +120,7 @@
 
 void dobody(h) stralloc *h; { ; }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -128,4 +129,5 @@
  if (!(returnpath = env_get("SENDER"))) die_usage();
  if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) die_read();
  die_noreceipt();
+ return 0;
 }
diff -urN qmail-1.03-vanilla/qsmhook.c qmail-1.03-md24/qsmhook.c
--- qmail-1.03-vanilla/qsmhook.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qsmhook.c	2007-07-19 20:56:22.000000000 +0200
@@ -35,7 +35,7 @@
 substdio ssin;
 char inbuf[SUBSTDIO_INSIZE];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -78,7 +78,7 @@
 
  if (!*argv) die_usage();
 
- for (arg = argv;x = *arg;++arg)
+ for (arg = argv;(x = *arg);++arg)
   {
    if (!stralloc_copys(&newarg,"")) die_temp();
    flagesc = 0;
diff -urN qmail-1.03-vanilla/qsutil.c qmail-1.03-md24/qsutil.c
--- qmail-1.03-vanilla/qsutil.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/qsutil.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "stralloc.h"
 #include "readwrite.h"
 #include "substdio.h"
diff -urN qmail-1.03-vanilla/rcpthosts.c qmail-1.03-md24/rcpthosts.c
--- qmail-1.03-vanilla/rcpthosts.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/rcpthosts.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,5 +1,6 @@
 #include "cdb.h"
 #include "byte.h"
+#include "case.h"
 #include "open.h"
 #include "error.h"
 #include "control.h"
diff -urN qmail-1.03-vanilla/readwrite.h qmail-1.03-md24/readwrite.h
--- qmail-1.03-vanilla/readwrite.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/readwrite.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,6 @@
 #ifndef READWRITE_H
 #define READWRITE_H
 
-extern int read();
-extern int write();
+#include <unistd.h>
 
 #endif
diff -urN qmail-1.03-vanilla/realrcptto.c qmail-1.03-md24/realrcptto.c
--- qmail-1.03-vanilla/realrcptto.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/realrcptto.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,282 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <pwd.h>
+#include "auto_break.h"
+#include "auto_usera.h"
+#include "byte.h"
+#include "case.h"
+#include "cdb.h"
+#include "constmap.h"
+#include "error.h"
+#include "control.h"
+#include "fmt.h"
+#include "open.h"
+#include "str.h"
+#include "stralloc.h"
+#include "uint32.h"
+#include "substdio.h"
+#include "env.h"
+
+extern void die_nomem();
+extern void die_control();
+extern void die_cdb();
+extern void die_sys();
+
+static stralloc envnoathost = {0};
+static stralloc percenthack = {0};
+static stralloc locals = {0};
+static stralloc vdoms = {0};
+static struct constmap mappercenthack;
+static struct constmap maplocals;
+static struct constmap mapvdoms;
+
+static char *dash;
+static char *extension;
+static char *local;
+static struct passwd *pw;
+
+static char pidbuf[64];
+static char remoteipbuf[64]=" ";
+
+void realrcptto_init()
+{
+  char *x;
+
+  if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1)
+    die_control();
+
+  if (control_readfile(&locals,"control/locals",1) != 1) die_control();
+  if (!constmap_init(&maplocals,locals.s,locals.len,0)) die_nomem();
+  switch(control_readfile(&percenthack,"control/percenthack",0)) {
+    case -1: die_control();
+    case 0: if (!constmap_init(&mappercenthack,"",0,0)) die_nomem();
+    case 1:
+      if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0))
+        die_nomem();
+  }
+  switch(control_readfile(&vdoms,"control/virtualdomains",0)) {
+    case -1: die_control();
+    case 0: if (!constmap_init(&mapvdoms,"",0,1)) die_nomem();
+    case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) die_nomem();
+  }
+
+  str_copy(pidbuf + fmt_ulong(pidbuf,getpid())," ");
+  x=env_get("PROTO");
+  if (x) {
+    static char const remoteip[]="REMOTEIP";
+    unsigned int len = str_len(x);
+    if (len <= sizeof remoteipbuf - sizeof remoteip) {
+      byte_copy(remoteipbuf,len,x);
+      byte_copy(remoteipbuf + len,sizeof remoteip,remoteip);
+      x = env_get(remoteipbuf);
+      len = str_len(x);
+      if (len + 1 < sizeof remoteipbuf) {
+        byte_copy(remoteipbuf,len,x);
+        remoteipbuf[len]=' ';
+        remoteipbuf[len + 1]='\0';
+      }
+    }
+  }
+}
+
+#define GETPW_USERLEN 32
+
+static int userext()
+{
+  char username[GETPW_USERLEN];
+  struct stat st;
+
+  extension = local + str_len(local);
+  for (;;) {
+    if (extension - local < sizeof(username))
+      if (!*extension || (*extension == *auto_break)) {
+	byte_copy(username,extension - local,local);
+	username[extension - local] = 0;
+	case_lowers(username);
+	errno = 0;
+	pw = getpwnam(username);
+	if (errno == error_txtbsy) die_sys();
+	if (pw)
+	  if (pw->pw_uid)
+	    if (stat(pw->pw_dir,&st) == 0) {
+	      if (st.st_uid == pw->pw_uid) {
+		dash = "";
+		if (*extension) { ++extension; dash = "-"; }
+		return 1;
+	      }
+	    }
+	    else
+	      if (error_temp(errno)) die_sys();
+      }
+    if (extension == local) return 0;
+    --extension;
+  }
+}
+
+int realrcptto(addr)
+char *addr;
+{
+  char *homedir;
+  static stralloc localpart = {0};
+  static stralloc lower = {0};
+  static stralloc nughde = {0};
+  static stralloc wildchars = {0};
+  static stralloc safeext = {0};
+  static stralloc qme = {0};
+
+  /* qmail-send:rewrite */
+  unsigned int i,at;
+  if (!stralloc_copys(&localpart,addr)) die_nomem();
+  i = byte_rchr(localpart.s,localpart.len,'@');
+  if (i == localpart.len) {
+    if (!stralloc_cats(&localpart,"@")) die_nomem();
+    if (!stralloc_cat(&localpart,&envnoathost)) die_nomem();
+  }
+  while (constmap(&mappercenthack,localpart.s + i + 1,localpart.len - i - 1)) {
+    unsigned int j = byte_rchr(localpart.s,i,'%');
+    if (j == i) break;
+    localpart.len = i;
+    i = j;
+    localpart.s[i] = '@';
+  }
+  at = byte_rchr(localpart.s,localpart.len,'@');
+  if (constmap(&maplocals,localpart.s + at + 1,localpart.len - at - 1)) {
+    localpart.len = at;
+    localpart.s[at] = '\0';
+  } else {
+    unsigned int xlen,newlen;
+    char *x;
+    for (i = 0;;++i) {
+      if (i > localpart.len) return 1;
+      if (!i || (i == at + 1) || (i == localpart.len) ||
+          ((i > at) && (localpart.s[i] == '.'))) {
+        x = constmap(&mapvdoms,localpart.s + i,localpart.len - i);
+        if (x) break;
+      }
+    }
+    if (!*x) return 1;
+    xlen = str_len(x) + 1;  /* +1 for '-' */
+    newlen = xlen + at + 1; /* +1 for \0 */
+    if (xlen < 1 || newlen - 1 < xlen || newlen < 1 ||
+        !stralloc_ready(&localpart,newlen))
+      die_nomem();
+    localpart.s[newlen - 1] = '\0';
+    byte_copyr(localpart.s + xlen,at,localpart.s);
+    localpart.s[xlen - 1] = '-';
+    byte_copy(localpart.s,xlen - 1,x);
+    localpart.len = newlen;
+  }
+
+  /* qmail-lspawn:nughde_get */
+  {
+    int r,fd,flagwild;
+    if (!stralloc_copys(&lower,"!")) die_nomem();
+    if (!stralloc_cats(&lower,localpart.s)) die_nomem();
+    if (!stralloc_0(&lower)) die_nomem();
+    case_lowerb(lower.s,lower.len);
+    if (!stralloc_copys(&nughde,"")) die_nomem();
+    fd = open_read("users/cdb");
+    if (fd == -1) {
+      if (errno != error_noent) die_cdb();
+    } else {
+      uint32 dlen;
+      r = cdb_seek(fd,"",0,&dlen);
+      if (r != 1) die_cdb();
+      if (!stralloc_ready(&wildchars,(unsigned int) dlen)) die_nomem();
+      wildchars.len = dlen;
+      if (cdb_bread(fd,wildchars.s,wildchars.len) == -1) die_cdb();
+      i = lower.len;
+      flagwild = 0;
+      do { /* i > 0 */
+        if (!flagwild || (i == 1) ||
+            (byte_chr(wildchars.s,wildchars.len,lower.s[i - 1])
+             < wildchars.len)) {
+          r = cdb_seek(fd,lower.s,i,&dlen);
+          if (r == -1) die_cdb();
+          if (r == 1) {
+            char *x;
+            if (!stralloc_ready(&nughde,(unsigned int) dlen)) die_nomem();
+            nughde.len = dlen;
+            if (cdb_bread(fd,nughde.s,nughde.len) == -1) die_cdb();
+            if (flagwild)
+              if (!stralloc_cats(&nughde,localpart.s + i - 1)) die_nomem();
+            if (!stralloc_0(&nughde)) die_nomem();
+            close(fd);
+            x=nughde.s;
+            /* skip username */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip uid */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip gid */
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip homedir */
+            homedir=x;
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            /* skip dash */
+            dash=x;
+            x += byte_chr(x,nughde.s + nughde.len - x,'\0');
+            if (x == nughde.s + nughde.len) return 1;
+            ++x;
+            extension=x;
+            goto got_nughde;
+          }
+        }
+        --i;
+        flagwild = 1;
+      } while (i);
+      close(fd);
+    }
+  }
+
+  /* qmail-getpw */
+  local = localpart.s;
+  if (!userext()) {
+    extension = local;
+    dash = "-";
+    pw = getpwnam(auto_usera);
+  }
+  if (!pw) { return 0; }
+  if (!stralloc_copys(&nughde,pw->pw_dir)) die_nomem();
+  if (!stralloc_0(&nughde)) die_nomem();
+  homedir=nughde.s;
+
+  got_nughde:
+
+  /* qmail-local:qmesearch */
+  if (!*dash) return 1;
+  if (!stralloc_copys(&safeext,extension)) die_nomem();
+  case_lowerb(safeext.s,safeext.len);
+  for (i = 0;i < safeext.len;++i)
+    if (safeext.s[i] == '.')
+      safeext.s[i] = ':';
+  {
+    struct stat st;
+    int i;
+    if (!stralloc_copys(&qme,homedir)) die_nomem();
+    if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+    if (!stralloc_cats(&qme,dash)) die_nomem();
+    if (!stralloc_cat(&qme,&safeext)) die_nomem();
+    if (!stralloc_0(&qme)) die_nomem();
+    if (stat(qme.s, &st) == 0 || errno != error_noent) return 1;
+    for (i = safeext.len;i >= 0;--i)
+      if (!i || (safeext.s[i - 1] == '-')) {
+        if (!stralloc_copys(&qme,homedir)) die_nomem();
+        if (!stralloc_cats(&qme,"/.qmail")) die_nomem();
+        if (!stralloc_cats(&qme,dash)) die_nomem();
+        if (!stralloc_catb(&qme,safeext.s,i)) die_nomem();
+        if (!stralloc_cats(&qme,"default")) die_nomem();
+        if (!stralloc_0(&qme)) die_nomem();
+        if (stat(qme.s, &st) == 0 || errno != error_noent) return 1;
+      }
+    return 0;
+  }
+}
diff -urN qmail-1.03-vanilla/received.c qmail-1.03-md24/received.c
--- qmail-1.03-vanilla/received.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/received.c	2007-07-19 20:56:22.000000000 +0200
@@ -26,7 +26,7 @@
 char *s;
 {
   char ch;
-  while (ch = *s++) {
+  while ((ch = *s++)) {
     if (!issafe(ch)) ch = '?';
     qmail_put(qqt,&ch,1);
   }
diff -urN qmail-1.03-vanilla/received.h qmail-1.03-md24/received.h
--- qmail-1.03-vanilla/received.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/received.h	2007-07-19 20:56:22.000000000 +0200
@@ -2,5 +2,6 @@
 #define RECEIVED_H
 
 extern void received();
+extern void safeput();
 
 #endif
diff -urN qmail-1.03-vanilla/remoteinfo.c qmail-1.03-md24/remoteinfo.c
--- qmail-1.03-vanilla/remoteinfo.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/remoteinfo.c	2007-07-19 20:56:22.000000000 +0200
@@ -32,7 +32,6 @@
 {
   char *x;
   int s;
-  struct sockaddr_in sin;
   substdio ss;
   char buf[32];
   unsigned int len;
@@ -44,12 +43,7 @@
   s = socket(AF_INET,SOCK_STREAM,0);
   if (s == -1) return 0;
  
-  byte_zero(&sin,sizeof(sin));
-  sin.sin_family = AF_INET;
-  byte_copy(&sin.sin_addr,4,ipl);
-  sin.sin_port = 0;
-  if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
-  if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; }
+  if (timeoutconn(s,ipr,ipl,113,timeout) == -1) { close(s); return 0; }
   fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
  
   len = 0;
diff -urN qmail-1.03-vanilla/ripemd.c qmail-1.03-md24/ripemd.c
--- qmail-1.03-vanilla/ripemd.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/ripemd.c	2007-07-19 22:29:46.000000000 +0200
@@ -0,0 +1,353 @@
+#include "ripemd.h"
+
+static void compress(RIPEMD160_CTX *ctx);
+
+/* ROL(x, n) cyclically rotates x over n bits to the left */
+/* x must be of an unsigned 32 bits type and 0 <= n < 32. */
+#define ROL(x, n)   (((x) << (n)) | ((x) >> (32-(n))))
+
+/* the five basic functions F(), G() and H() */
+#define F(x, y, z)  ((x) ^ (y) ^ (z))
+#define G(x, y, z)  (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z)  (((x) | ~(y)) ^ (z))
+#define I(x, y, z)  (((x) & (z)) | ((y) & ~(z)))
+#define J(x, y, z)  ((x) ^ ((y) | ~(z)))
+
+/* the ten basic operations FF() through III() */
+#define FF(a, b, c, d, e, x, s) {\
+ (a) += F((b), (c), (d)) + (x);\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define GG(a, b, c, d, e, x, s)  {\
+ (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define HH(a, b, c, d, e, x, s)  {\
+ (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define II(a, b, c, d, e, x, s)  {\
+ (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define JJ(a, b, c, d, e, x, s)  {\
+ (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define FFF(a, b, c, d, e, x, s) {\
+ (a) += F((b), (c), (d)) + (x);\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define GGG(a, b, c, d, e, x, s) {\
+ (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define HHH(a, b, c, d, e, x, s) {\
+ (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define III(a, b, c, d, e, x, s) {\
+ (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+#define JJJ(a, b, c, d, e, x, s) {\
+ (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10); }
+
+/* collect four u8s into one word: */
+#define bytes_TO_u32(strptr)    \
+ (((u32) *((strptr)+3) << 24) | \
+  ((u32) *((strptr)+2) << 16) | \
+  ((u32) *((strptr)+1) <<  8) | \
+  ((u32) *(strptr)))
+
+static void compress(RIPEMD160_CTX *ctx)
+{
+	u32 aa = ctx->MD[0], aaa = ctx->MD[0];
+	u32 bb = ctx->MD[1], bbb = ctx->MD[1];
+	u32 cc = ctx->MD[2], ccc = ctx->MD[2];
+	u32 dd = ctx->MD[3], ddd = ctx->MD[3];
+	u32 ee = ctx->MD[4], eee = ctx->MD[4];
+
+	/* round 1 */
+	FF(aa, bb, cc, dd, ee, ctx->X[ 0], 11);
+	FF(ee, aa, bb, cc, dd, ctx->X[ 1], 14);
+	FF(dd, ee, aa, bb, cc, ctx->X[ 2], 15);
+	FF(cc, dd, ee, aa, bb, ctx->X[ 3], 12);
+	FF(bb, cc, dd, ee, aa, ctx->X[ 4],  5);
+	FF(aa, bb, cc, dd, ee, ctx->X[ 5],  8);
+	FF(ee, aa, bb, cc, dd, ctx->X[ 6],  7);
+	FF(dd, ee, aa, bb, cc, ctx->X[ 7],  9);
+	FF(cc, dd, ee, aa, bb, ctx->X[ 8], 11);
+	FF(bb, cc, dd, ee, aa, ctx->X[ 9], 13);
+	FF(aa, bb, cc, dd, ee, ctx->X[10], 14);
+	FF(ee, aa, bb, cc, dd, ctx->X[11], 15);
+	FF(dd, ee, aa, bb, cc, ctx->X[12],  6);
+	FF(cc, dd, ee, aa, bb, ctx->X[13],  7);
+	FF(bb, cc, dd, ee, aa, ctx->X[14],  9);
+	FF(aa, bb, cc, dd, ee, ctx->X[15],  8);
+
+	/* round 2 */
+	GG(ee, aa, bb, cc, dd, ctx->X[ 7],  7);
+	GG(dd, ee, aa, bb, cc, ctx->X[ 4],  6);
+	GG(cc, dd, ee, aa, bb, ctx->X[13],  8);
+	GG(bb, cc, dd, ee, aa, ctx->X[ 1], 13);
+	GG(aa, bb, cc, dd, ee, ctx->X[10], 11);
+	GG(ee, aa, bb, cc, dd, ctx->X[ 6],  9);
+	GG(dd, ee, aa, bb, cc, ctx->X[15],  7);
+	GG(cc, dd, ee, aa, bb, ctx->X[ 3], 15);
+	GG(bb, cc, dd, ee, aa, ctx->X[12],  7);
+	GG(aa, bb, cc, dd, ee, ctx->X[ 0], 12);
+	GG(ee, aa, bb, cc, dd, ctx->X[ 9], 15);
+	GG(dd, ee, aa, bb, cc, ctx->X[ 5],  9);
+	GG(cc, dd, ee, aa, bb, ctx->X[ 2], 11);
+	GG(bb, cc, dd, ee, aa, ctx->X[14],  7);
+	GG(aa, bb, cc, dd, ee, ctx->X[11], 13);
+	GG(ee, aa, bb, cc, dd, ctx->X[ 8], 12);
+
+	/* round 3 */
+	HH(dd, ee, aa, bb, cc, ctx->X[ 3], 11);
+	HH(cc, dd, ee, aa, bb, ctx->X[10], 13);
+	HH(bb, cc, dd, ee, aa, ctx->X[14],  6);
+	HH(aa, bb, cc, dd, ee, ctx->X[ 4],  7);
+	HH(ee, aa, bb, cc, dd, ctx->X[ 9], 14);
+	HH(dd, ee, aa, bb, cc, ctx->X[15],  9);
+	HH(cc, dd, ee, aa, bb, ctx->X[ 8], 13);
+	HH(bb, cc, dd, ee, aa, ctx->X[ 1], 15);
+	HH(aa, bb, cc, dd, ee, ctx->X[ 2], 14);
+	HH(ee, aa, bb, cc, dd, ctx->X[ 7],  8);
+	HH(dd, ee, aa, bb, cc, ctx->X[ 0], 13);
+	HH(cc, dd, ee, aa, bb, ctx->X[ 6],  6);
+	HH(bb, cc, dd, ee, aa, ctx->X[13],  5);
+	HH(aa, bb, cc, dd, ee, ctx->X[11], 12);
+	HH(ee, aa, bb, cc, dd, ctx->X[ 5],  7);
+	HH(dd, ee, aa, bb, cc, ctx->X[12],  5);
+
+	/* round 4 */
+	II(cc, dd, ee, aa, bb, ctx->X[ 1], 11);
+	II(bb, cc, dd, ee, aa, ctx->X[ 9], 12);
+	II(aa, bb, cc, dd, ee, ctx->X[11], 14);
+	II(ee, aa, bb, cc, dd, ctx->X[10], 15);
+	II(dd, ee, aa, bb, cc, ctx->X[ 0], 14);
+	II(cc, dd, ee, aa, bb, ctx->X[ 8], 15);
+	II(bb, cc, dd, ee, aa, ctx->X[12],  9);
+	II(aa, bb, cc, dd, ee, ctx->X[ 4],  8);
+	II(ee, aa, bb, cc, dd, ctx->X[13],  9);
+	II(dd, ee, aa, bb, cc, ctx->X[ 3], 14);
+	II(cc, dd, ee, aa, bb, ctx->X[ 7],  5);
+	II(bb, cc, dd, ee, aa, ctx->X[15],  6);
+	II(aa, bb, cc, dd, ee, ctx->X[14],  8);
+	II(ee, aa, bb, cc, dd, ctx->X[ 5],  6);
+	II(dd, ee, aa, bb, cc, ctx->X[ 6],  5);
+	II(cc, dd, ee, aa, bb, ctx->X[ 2], 12);
+
+	/* round 5 */
+	JJ(bb, cc, dd, ee, aa, ctx->X[ 4],  9);
+	JJ(aa, bb, cc, dd, ee, ctx->X[ 0], 15);
+	JJ(ee, aa, bb, cc, dd, ctx->X[ 5],  5);
+	JJ(dd, ee, aa, bb, cc, ctx->X[ 9], 11);
+	JJ(cc, dd, ee, aa, bb, ctx->X[ 7],  6);
+	JJ(bb, cc, dd, ee, aa, ctx->X[12],  8);
+	JJ(aa, bb, cc, dd, ee, ctx->X[ 2], 13);
+	JJ(ee, aa, bb, cc, dd, ctx->X[10], 12);
+	JJ(dd, ee, aa, bb, cc, ctx->X[14],  5);
+	JJ(cc, dd, ee, aa, bb, ctx->X[ 1], 12);
+	JJ(bb, cc, dd, ee, aa, ctx->X[ 3], 13);
+	JJ(aa, bb, cc, dd, ee, ctx->X[ 8], 14);
+	JJ(ee, aa, bb, cc, dd, ctx->X[11], 11);
+	JJ(dd, ee, aa, bb, cc, ctx->X[ 6],  8);
+	JJ(cc, dd, ee, aa, bb, ctx->X[15],  5);
+	JJ(bb, cc, dd, ee, aa, ctx->X[13],  6);
+
+	/* parallel round 1 */
+	JJJ(aaa, bbb, ccc, ddd, eee, ctx->X[ 5],  8);
+	JJJ(eee, aaa, bbb, ccc, ddd, ctx->X[14],  9);
+	JJJ(ddd, eee, aaa, bbb, ccc, ctx->X[ 7],  9);
+	JJJ(ccc, ddd, eee, aaa, bbb, ctx->X[ 0], 11);
+	JJJ(bbb, ccc, ddd, eee, aaa, ctx->X[ 9], 13);
+	JJJ(aaa, bbb, ccc, ddd, eee, ctx->X[ 2], 15);
+	JJJ(eee, aaa, bbb, ccc, ddd, ctx->X[11], 15);
+	JJJ(ddd, eee, aaa, bbb, ccc, ctx->X[ 4],  5);
+	JJJ(ccc, ddd, eee, aaa, bbb, ctx->X[13],  7);
+	JJJ(bbb, ccc, ddd, eee, aaa, ctx->X[ 6],  7);
+	JJJ(aaa, bbb, ccc, ddd, eee, ctx->X[15],  8);
+	JJJ(eee, aaa, bbb, ccc, ddd, ctx->X[ 8], 11);
+	JJJ(ddd, eee, aaa, bbb, ccc, ctx->X[ 1], 14);
+	JJJ(ccc, ddd, eee, aaa, bbb, ctx->X[10], 14);
+	JJJ(bbb, ccc, ddd, eee, aaa, ctx->X[ 3], 12);
+	JJJ(aaa, bbb, ccc, ddd, eee, ctx->X[12],  6);
+
+	/* parallel round 2 */
+	III(eee, aaa, bbb, ccc, ddd, ctx->X[ 6],  9); 
+	III(ddd, eee, aaa, bbb, ccc, ctx->X[11], 13);
+	III(ccc, ddd, eee, aaa, bbb, ctx->X[ 3], 15);
+	III(bbb, ccc, ddd, eee, aaa, ctx->X[ 7],  7);
+	III(aaa, bbb, ccc, ddd, eee, ctx->X[ 0], 12);
+	III(eee, aaa, bbb, ccc, ddd, ctx->X[13],  8);
+	III(ddd, eee, aaa, bbb, ccc, ctx->X[ 5],  9);
+	III(ccc, ddd, eee, aaa, bbb, ctx->X[10], 11);
+	III(bbb, ccc, ddd, eee, aaa, ctx->X[14],  7);
+	III(aaa, bbb, ccc, ddd, eee, ctx->X[15],  7);
+	III(eee, aaa, bbb, ccc, ddd, ctx->X[ 8], 12);
+	III(ddd, eee, aaa, bbb, ccc, ctx->X[12],  7);
+	III(ccc, ddd, eee, aaa, bbb, ctx->X[ 4],  6);
+	III(bbb, ccc, ddd, eee, aaa, ctx->X[ 9], 15);
+	III(aaa, bbb, ccc, ddd, eee, ctx->X[ 1], 13);
+	III(eee, aaa, bbb, ccc, ddd, ctx->X[ 2], 11);
+
+	/* parallel round 3 */
+	HHH(ddd, eee, aaa, bbb, ccc, ctx->X[15],  9);
+	HHH(ccc, ddd, eee, aaa, bbb, ctx->X[ 5],  7);
+	HHH(bbb, ccc, ddd, eee, aaa, ctx->X[ 1], 15);
+	HHH(aaa, bbb, ccc, ddd, eee, ctx->X[ 3], 11);
+	HHH(eee, aaa, bbb, ccc, ddd, ctx->X[ 7],  8);
+	HHH(ddd, eee, aaa, bbb, ccc, ctx->X[14],  6);
+	HHH(ccc, ddd, eee, aaa, bbb, ctx->X[ 6],  6);
+	HHH(bbb, ccc, ddd, eee, aaa, ctx->X[ 9], 14);
+	HHH(aaa, bbb, ccc, ddd, eee, ctx->X[11], 12);
+	HHH(eee, aaa, bbb, ccc, ddd, ctx->X[ 8], 13);
+	HHH(ddd, eee, aaa, bbb, ccc, ctx->X[12],  5);
+	HHH(ccc, ddd, eee, aaa, bbb, ctx->X[ 2], 14);
+	HHH(bbb, ccc, ddd, eee, aaa, ctx->X[10], 13);
+	HHH(aaa, bbb, ccc, ddd, eee, ctx->X[ 0], 13);
+	HHH(eee, aaa, bbb, ccc, ddd, ctx->X[ 4],  7);
+	HHH(ddd, eee, aaa, bbb, ccc, ctx->X[13],  5);
+
+	/* parallel round 4 */   
+	GGG(ccc, ddd, eee, aaa, bbb, ctx->X[ 8], 15);
+	GGG(bbb, ccc, ddd, eee, aaa, ctx->X[ 6],  5);
+	GGG(aaa, bbb, ccc, ddd, eee, ctx->X[ 4],  8);
+	GGG(eee, aaa, bbb, ccc, ddd, ctx->X[ 1], 11);
+	GGG(ddd, eee, aaa, bbb, ccc, ctx->X[ 3], 14);
+	GGG(ccc, ddd, eee, aaa, bbb, ctx->X[11], 14);
+	GGG(bbb, ccc, ddd, eee, aaa, ctx->X[15],  6);
+	GGG(aaa, bbb, ccc, ddd, eee, ctx->X[ 0], 14);
+	GGG(eee, aaa, bbb, ccc, ddd, ctx->X[ 5],  6);
+	GGG(ddd, eee, aaa, bbb, ccc, ctx->X[12],  9);
+	GGG(ccc, ddd, eee, aaa, bbb, ctx->X[ 2], 12);
+	GGG(bbb, ccc, ddd, eee, aaa, ctx->X[13],  9);
+	GGG(aaa, bbb, ccc, ddd, eee, ctx->X[ 9], 12);
+	GGG(eee, aaa, bbb, ccc, ddd, ctx->X[ 7],  5);
+	GGG(ddd, eee, aaa, bbb, ccc, ctx->X[10], 15);
+	GGG(ccc, ddd, eee, aaa, bbb, ctx->X[14],  8);
+
+	/* parallel round 5 */
+	FFF(bbb, ccc, ddd, eee, aaa, ctx->X[12] ,  8);
+	FFF(aaa, bbb, ccc, ddd, eee, ctx->X[15] ,  5);
+	FFF(eee, aaa, bbb, ccc, ddd, ctx->X[10] , 12);
+	FFF(ddd, eee, aaa, bbb, ccc, ctx->X[ 4] ,  9);
+	FFF(ccc, ddd, eee, aaa, bbb, ctx->X[ 1] , 12);
+	FFF(bbb, ccc, ddd, eee, aaa, ctx->X[ 5] ,  5);
+	FFF(aaa, bbb, ccc, ddd, eee, ctx->X[ 8] , 14);
+	FFF(eee, aaa, bbb, ccc, ddd, ctx->X[ 7] ,  6);
+	FFF(ddd, eee, aaa, bbb, ccc, ctx->X[ 6] ,  8);
+	FFF(ccc, ddd, eee, aaa, bbb, ctx->X[ 2] , 13);
+	FFF(bbb, ccc, ddd, eee, aaa, ctx->X[13] ,  6);
+	FFF(aaa, bbb, ccc, ddd, eee, ctx->X[14] ,  5);
+	FFF(eee, aaa, bbb, ccc, ddd, ctx->X[ 0] , 15);
+	FFF(ddd, eee, aaa, bbb, ccc, ctx->X[ 3] , 13);
+	FFF(ccc, ddd, eee, aaa, bbb, ctx->X[ 9] , 11);
+	FFF(bbb, ccc, ddd, eee, aaa, ctx->X[11] , 11);
+
+	/* combine results */
+	ddd += cc + ctx->MD[1];
+	ctx->MD[1] = ctx->MD[2] + dd + eee;
+	ctx->MD[2] = ctx->MD[3] + ee + aaa;
+	ctx->MD[3] = ctx->MD[4] + aa + bbb;
+	ctx->MD[4] = ctx->MD[0] + bb + ccc;
+	ctx->MD[0] = ddd;
+	ctx->len+=64;
+
+	memset(ctx->X, 0, 16*sizeof(u32));
+	return;
+}
+
+void RIPEMD160_Init(RIPEMD160_CTX *ctx)
+{
+	ctx->MD[0] = 0x67452301UL;
+	ctx->MD[1] = 0xefcdab89UL;
+	ctx->MD[2] = 0x98badcfeUL;
+	ctx->MD[3] = 0x10325476UL;
+	ctx->MD[4] = 0xc3d2e1f0UL;
+	ctx->len=ctx->l=0;
+	return;
+}
+
+void RIPEMD160_Update(RIPEMD160_CTX *ctx, const void *data, u32 size)
+{
+	u8 *message=(u8 *)data;
+	u32 i,bytes;
+
+	/* process message in 16-word chunks */
+	for (bytes=size; bytes > 63; bytes-=64) {
+		for (i=0; i<16; i++) {
+			ctx->X[i] = bytes_TO_u32(message); message += 4;
+		}
+		compress(ctx);
+	}
+
+	/* XXX, is this correct:
+	 * - I process firstly the chunks
+	 * - then I add the rest to the data... ist this really okay?
+	 * - Tino Reichardt <crypto@mcmilk.de>
+	 */
+	if (bytes+ctx->l >= 64) {
+		u8 *m=ctx->D;
+		memcpy(m+ctx->l, message, 64-ctx->l);
+		for (i=0; i<16; i++) {
+			ctx->X[i] = bytes_TO_u32(m); m += 4;
+		}
+		compress(ctx);
+		bytes-=64-ctx->l; message+=64-ctx->l; ctx->l=0;
+	}
+
+	if (bytes > 0) {
+		memcpy(ctx->D+ctx->l, message, bytes);
+		ctx->l+=bytes;
+	}
+
+	return;
+}
+
+void RIPEMD160_Final(u8 *result, RIPEMD160_CTX *ctx)
+{
+	int i,bytes=ctx->len+ctx->l;
+	u8 *message=ctx->D;
+
+	memset(ctx->X, 0, 16 * sizeof(u32));
+
+	for (i=0; i<(bytes&63); i++) {
+		ctx->X[i>>2] ^= (u32) *message++ << (8*(i&3));
+	}
+	ctx->X[(bytes>>2)&15] ^= (u32)1 << (8*(bytes&3) + 7);
+	if ((bytes & 63) > 55) { compress(ctx); }
+	ctx->X[14] = bytes << 3;
+	ctx->X[15] = bytes >> 29;
+	compress(ctx);
+	for (i=0; i<20; i+=4) {
+		result[i]   =  ctx->MD[i>>2];
+		result[i+1] = (ctx->MD[i>>2] >>  8);
+		result[i+2] = (ctx->MD[i>>2] >> 16);
+		result[i+3] = (ctx->MD[i>>2] >> 24);
+	}
+
+	return;
+}
+#undef F
+#undef FF
+#undef FFF
+#undef G
+#undef GG
+#undef GGG
+#undef H
+#undef HH
+#undef HHH
+#undef I
+#undef II
+#undef III
+#undef J
+#undef JJ
+#undef JJJ
+#undef ROL
+#undef bytes_TO_u32
diff -urN qmail-1.03-vanilla/ripemd.h qmail-1.03-md24/ripemd.h
--- qmail-1.03-vanilla/ripemd.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/ripemd.h	2007-07-19 22:22:33.000000000 +0200
@@ -0,0 +1,19 @@
+#ifndef QP_RMD_H
+#define QP_RMD_H
+
+#include "typesx.h"
+#include <string.h>
+
+typedef struct {
+	u32 MD[5]; /* used for the digest */
+	u32 X[16]; /* current 16 bit chunk */
+	u32 len;   /* full length */
+	u8  D[64]; /* 512 bit data block */
+	u32 l;     /* current length of data block -> D[l] */
+} RIPEMD160_CTX;
+
+void RIPEMD160_Init(RIPEMD160_CTX *ctx);
+void RIPEMD160_Update(RIPEMD160_CTX *ctx, const void *data, u32 size);
+void RIPEMD160_Final(u8 *result, RIPEMD160_CTX *ctx);
+
+#endif
diff -urN qmail-1.03-vanilla/scan.h qmail-1.03-md24/scan.h
--- qmail-1.03-vanilla/scan.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/scan.h	2007-07-19 20:56:22.000000000 +0200
@@ -23,5 +23,6 @@
 extern unsigned int scan_memcmp();
 
 extern unsigned int scan_long();
+extern unsigned int scan_8long();
 
 #endif
diff -urN qmail-1.03-vanilla/seek_cur.c qmail-1.03-md24/seek_cur.c
--- qmail-1.03-vanilla/seek_cur.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/seek_cur.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <sys/types.h>
 #include "seek.h"
 
 #define CUR 1 /* sigh */
diff -urN qmail-1.03-vanilla/seek_end.c qmail-1.03-md24/seek_end.c
--- qmail-1.03-vanilla/seek_end.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/seek_end.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <sys/types.h>
 #include "seek.h"
 
 #define END 2 /* sigh */
diff -urN qmail-1.03-vanilla/seek.h qmail-1.03-md24/seek.h
--- qmail-1.03-vanilla/seek.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/seek.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,9 @@
 #ifndef SEEK_H
 #define SEEK_H
 
+#include <sys/types.h>
+#include <unistd.h>
+
 typedef unsigned long seek_pos;
 
 extern seek_pos seek_cur();
diff -urN qmail-1.03-vanilla/seek_set.c qmail-1.03-md24/seek_set.c
--- qmail-1.03-vanilla/seek_set.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/seek_set.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <sys/types.h>
 #include "seek.h"
 
 #define SET 0 /* sigh */
diff -urN qmail-1.03-vanilla/seek_trunc.c qmail-1.03-md24/seek_trunc.c
--- qmail-1.03-vanilla/seek_trunc.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/seek_trunc.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,3 @@
-#include <sys/types.h>
 #include "seek.h"
 
 int seek_trunc(fd,pos) int fd; seek_pos pos;
diff -urN qmail-1.03-vanilla/sendmail.c qmail-1.03-md24/sendmail.c
--- qmail-1.03-vanilla/sendmail.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/sendmail.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "sgetopt.h"
 #include "substdio.h"
 #include "subfd.h"
@@ -37,6 +39,37 @@
   _exit(111);
 }
 
+void do_sender(const char *s)
+{
+  char *x;
+  int n;
+  int a;
+  int i;
+  
+  env_unset("QMAILNAME");
+  env_unset("MAILNAME");
+  env_unset("NAME");
+  env_unset("QMAILHOST");
+  env_unset("MAILHOST");
+
+  n = str_len(s);
+  a = str_rchr(s, '@');
+  if (a == n)
+  {
+    env_put2("QMAILUSER", s);
+    return;
+  }
+  env_put2("QMAILHOST", s + a + 1);
+
+  x = (char *) alloc((a + 1) * sizeof(char));
+  if (!x) nomem();
+  for (i = 0; i < a; i++)
+    x[i] = s[i];
+  x[i] = 0;
+  env_put2("QMAILUSER", x);
+  alloc_free(x);
+}
+
 char *qreadarg[] = { "bin/qmail-qread", 0 };
 void mailq()
 {
@@ -48,7 +81,7 @@
 int flagh;
 char *sender;
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -64,8 +97,9 @@
 
   flagh = 0;
   sender = 0;
-  while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJxb:")) != opteof)
+  while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJxb:N:")) != opteof)
     switch(opt) {
+      case 'N': break; /* ignore DSN option */
       case 'B': break;
       case 't': flagh = 1; break;
       case 'f': sender = optarg; break;
@@ -118,6 +152,7 @@
   if (sender) {
     *arg++ = "-f";
     *arg++ = sender;
+    do_sender(sender);
   }
   *arg++ = "--";
   for (i = 0;i < argc;++i) *arg++ = argv[i];
diff -urN qmail-1.03-vanilla/sha1.c qmail-1.03-md24/sha1.c
--- qmail-1.03-vanilla/sha1.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/sha1.c	2007-07-19 22:31:12.000000000 +0200
@@ -0,0 +1,187 @@
+
+/**
+ * Copyright (C) 2005-2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "sha1.h"
+
+/*  define the SHA1 circular left shift macro */
+#define SHA1CircularShift(bits,word) \
+	(((word) << (bits)) | ((word) >> (32-(bits))))
+
+static void SHA1PadMessage(SHA1_CTX *);
+static void SHA1ProcessMessageBlock(SHA1_CTX *);
+
+void SHA1_Init(SHA1_CTX *ctx)
+{
+	ctx->Length_Low             = 0;
+	ctx->Length_High            = 0;
+	ctx->Message_Block_Index    = 0;
+	ctx->Intermediate_Hash[0]   = 0x67452301;
+	ctx->Intermediate_Hash[1]   = 0xEFCDAB89;
+	ctx->Intermediate_Hash[2]   = 0x98BADCFE;
+	ctx->Intermediate_Hash[3]   = 0x10325476;
+	ctx->Intermediate_Hash[4]   = 0xC3D2E1F0;
+}
+
+void SHA1_Update(SHA1_CTX *ctx, const void *data, u32 size)
+{
+	const u8 *ptr=data;
+
+	while (size--) {
+		ctx->Message_Block[ctx->Message_Block_Index++] = (*ptr & 0xFF);
+		ctx->Length_Low += 8;
+
+		if (ctx->Length_Low == 0) {
+			ctx->Length_High++;
+			if (ctx->Length_High == 0) return; /* ERR */
+		}
+
+		if (ctx->Message_Block_Index == 64) {
+			SHA1ProcessMessageBlock(ctx);
+		}
+		ptr++;
+	}
+}
+
+void SHA1_Final(u8 *Message_Digest, SHA1_CTX *ctx)
+{
+	int i;
+
+	SHA1PadMessage(ctx);
+	for(i=0; i<64; ++i) {
+		/* message may be sensitive, clear it out */
+		ctx->Message_Block[i] = 0;
+	}
+	ctx->Length_Low = 0;    /* and clear length */
+	ctx->Length_High = 0;
+	
+	for(i = 0; i < SHA1HashSize; ++i) {
+		Message_Digest[i] = ctx->Intermediate_Hash[i>>2] >> 8*(3-(i&0x03));
+	}
+}
+
+static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
+{
+	/* Constants defined in SHA-1 */
+	const u32 K[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
+	int t;         /* Loop counter          */
+	u32 temp;      /* Temporary word value  */
+	u32 W[80];     /* Word sequence         */
+	u32 A,B,C,D,E; /* Word buffers          */
+
+	for (t = 0; t < 16; t++) {
+		W[t] =  ctx->Message_Block[t * 4]     << 24;
+		W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
+		W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
+		W[t] |= ctx->Message_Block[t * 4 + 3];
+	}
+
+	for (t = 16; t < 80; t++) {
+		W[t] = SHA1CircularShift(1,W[t-3] ^
+			W[t-8] ^ W[t-14] ^ W[t-16]);
+	}
+
+	A = ctx->Intermediate_Hash[0];
+	B = ctx->Intermediate_Hash[1];
+	C = ctx->Intermediate_Hash[2];
+	D = ctx->Intermediate_Hash[3];
+	E = ctx->Intermediate_Hash[4];
+
+	for (t = 0; t < 20; t++) {
+		temp =  SHA1CircularShift(5,A) +
+			((B & C) | ((~B) & D)) + E + W[t] + K[0];
+		E = D;
+		D = C;
+		C = SHA1CircularShift(30,B);
+		B = A;
+		A = temp;
+	}
+
+	for (t = 20; t < 40; t++) {
+		temp = SHA1CircularShift(5,A) +
+			(B ^ C ^ D) + E + W[t] + K[1];
+		E = D;
+		D = C;
+		C = SHA1CircularShift(30,B);
+		B = A;
+		A = temp;
+	}
+
+	for (t = 40; t < 60; t++) {
+		temp = SHA1CircularShift(5,A) +
+		       ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+		E = D;
+		D = C;
+		C = SHA1CircularShift(30,B);
+		B = A;
+		A = temp;
+	}
+
+	for (t = 60; t < 80; t++) {
+		temp = SHA1CircularShift(5,A) +
+			(B ^ C ^ D) + E + W[t] + K[3];
+		E = D;
+		D = C;
+		C = SHA1CircularShift(30,B);
+		B = A;
+		A = temp;
+	}
+
+	ctx->Intermediate_Hash[0] += A;
+	ctx->Intermediate_Hash[1] += B;
+	ctx->Intermediate_Hash[2] += C;
+	ctx->Intermediate_Hash[3] += D;
+	ctx->Intermediate_Hash[4] += E;
+	ctx->Message_Block_Index = 0;
+}
+
+static void SHA1PadMessage(SHA1_CTX *ctx)
+{
+	if (ctx->Message_Block_Index > 55) {
+		ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+
+		while (ctx->Message_Block_Index < 64) {
+			ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+		}
+
+		SHA1ProcessMessageBlock(ctx);
+
+		while (ctx->Message_Block_Index < 56) {
+			ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+		}
+
+	} else {
+
+		ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
+		while (ctx->Message_Block_Index < 56) {
+			ctx->Message_Block[ctx->Message_Block_Index++] = 0;
+		}
+	}
+
+	/*  Store the message length as the last 8 octets */
+	ctx->Message_Block[56] = ctx->Length_High >> 24;
+	ctx->Message_Block[57] = ctx->Length_High >> 16;
+	ctx->Message_Block[58] = ctx->Length_High >> 8;
+	ctx->Message_Block[59] = ctx->Length_High;
+	ctx->Message_Block[60] = ctx->Length_Low >> 24;
+	ctx->Message_Block[61] = ctx->Length_Low >> 16;
+	ctx->Message_Block[62] = ctx->Length_Low >> 8;
+	ctx->Message_Block[63] = ctx->Length_Low;
+
+	SHA1ProcessMessageBlock(ctx);
+}
+#undef SHA1CircularShift
diff -urN qmail-1.03-vanilla/sha1.h qmail-1.03-md24/sha1.h
--- qmail-1.03-vanilla/sha1.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/sha1.h	2007-07-19 22:31:03.000000000 +0200
@@ -0,0 +1,39 @@
+#ifndef SW_SHA1_H
+#define SW_SHA1_H
+
+/**
+ * Copyright (C) 2005-2006 Tino Reichardt
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "typesx.h"
+#include <string.h>
+
+#define SHA1HashSize 20
+
+typedef struct SHA1_CTX
+{
+    u32 Intermediate_Hash[SHA1HashSize/4]; /* Message Digest  */
+    u32 Length_Low;            /* Message length in bits      */
+    u32 Length_High;           /* Message length in bits      */
+    u32 Message_Block_Index;   /* Index into message block array   */
+    u8 Message_Block[64];      /* 512-bit message blocks      */
+} SHA1_CTX;
+
+extern void SHA1_Init(SHA1_CTX *ctx);
+extern void SHA1_Update(SHA1_CTX *ctx, const void *data, u32 size);
+extern void SHA1_Final(u8 *result, SHA1_CTX *ctx);
+
+#endif
diff -urN qmail-1.03-vanilla/sig_catch.c qmail-1.03-md24/sig_catch.c
--- qmail-1.03-vanilla/sig_catch.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/sig_catch.c	2007-07-19 20:56:22.000000000 +0200
@@ -3,13 +3,18 @@
 #include "hassgact.h"
 
 void sig_catch(sig,f)
-int sig;
-void (*f)();
+  int sig;
+  void (*f)();
 {
 #ifdef HASSIGACTION
   struct sigaction sa;
   sa.sa_handler = f;
+#ifdef SA_RESTART
+  /* if available */
+  sa.sa_flags = SA_RESTART;
+#else
   sa.sa_flags = 0;
+#endif
   sigemptyset(&sa.sa_mask);
   sigaction(sig,&sa,(struct sigaction *) 0);
 #else
diff -urN qmail-1.03-vanilla/slurpclose.c qmail-1.03-md24/slurpclose.c
--- qmail-1.03-vanilla/slurpclose.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/slurpclose.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,6 @@
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "stralloc.h"
 #include "readwrite.h"
 #include "slurpclose.h"
diff -urN qmail-1.03-vanilla/spawn.c qmail-1.03-md24/spawn.c
--- qmail-1.03-vanilla/spawn.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/spawn.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,10 +1,13 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unistd.h>
+
 #include "sig.h"
 #include "wait.h"
 #include "substdio.h"
 #include "byte.h"
 #include "str.h"
+#include "alloc.h"
 #include "stralloc.h"
 #include "select.h"
 #include "exit.h"
@@ -63,7 +66,7 @@
 int flagreading = 1;
 char outbuf[1024]; substdio ssout;
 
-int stage = 0; /* reading 0:delnum 1:messid 2:sender 3:recip */
+int stage = 0; /* reading 0:delnum 1:delnum2 2:messid 3:sender 4:recip */
 int flagabort = 0; /* if 1, everything except delnum is garbage */
 int delnum;
 stralloc messid = {0};
@@ -73,6 +76,7 @@
 void err(s) char *s;
 {
  char ch; ch = delnum; substdio_put(&ssout,&ch,1);
+ ch = delnum >> 8; substdio_put(&ssout,&ch,1);
  substdio_puts(&ssout,s); substdio_putflush(&ssout,"",1);
 }
 
@@ -85,44 +89,44 @@
  int pi[2];
  struct stat st;
 
- if (flagabort) { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
- if (delnum < 0) { err("ZInternal error: delnum negative. (#4.3.5)\n"); return; }
- if (delnum >= auto_spawn) { err("ZInternal error: delnum too big. (#4.3.5)\n"); return; }
- if (d[delnum].used) { err("ZInternal error: delnum in use. (#4.3.5)\n"); return; }
+ if (flagabort) { err("Z4.3.0 qmail-spawn out of memory\n"); return; }
+ if (delnum < 0) { err("Z4.3.5 Internal error: delnum negative\n"); return; }
+ if (delnum >= auto_spawn) { err("Z4.3.5 Internal error: delnum too big\n"); return; }
+ if (d[delnum].used) { err("Z4.3.5 Internal error: delnum in use\n"); return; }
  for (i = 0;i < messid.len;++i)
    if (messid.s[i])
      if (!i || (messid.s[i] != '/'))
        if ((unsigned char) (messid.s[i] - '0') > 9)
-        { err("DInternal error: messid has nonnumerics. (#5.3.5)\n"); return; }
- if (messid.len > 100) { err("DInternal error: messid too long. (#5.3.5)\n"); return; }
- if (!messid.s[0]) { err("DInternal error: messid too short. (#5.3.5)\n"); return; }
+        { err("D5.3.5 Internal error: messid has nonnumerics\n"); return; }
+ if (messid.len > 100) { err("D5.3.5 Internal error: messid too long\n"); return; }
+ if (!messid.s[0]) { err("D5.3.5 Internal error: messid too short\n"); return; }
 
  if (!stralloc_copys(&d[delnum].output,""))
-  { err("Zqmail-spawn out of memory. (#4.3.0)\n"); return; }
+  { err("Z4.3.0 qmail-spawn out of memory\n"); return; }
 
  j = byte_rchr(recip.s,recip.len,'@');
- if (j >= recip.len) { err("DSorry, address must include host name. (#5.1.3)\n"); return; }
+ if (j >= recip.len) { err("D5.1.3 Sorry, address must include host name\n"); return; }
 
  fdmess = open_read(messid.s);
- if (fdmess == -1) { err("Zqmail-spawn unable to open message. (#4.3.0)\n"); return; }
+ if (fdmess == -1) { err("Z4.3.0 qmail-spawn unable to open message\n"); return; }
 
  if (fstat(fdmess,&st) == -1)
-  { close(fdmess); err("Zqmail-spawn unable to fstat message. (#4.3.0)\n"); return; }
+  { close(fdmess); err("Z4.3.0 qmail-spawn unable to fstat message\n"); return; }
  if ((st.st_mode & S_IFMT) != S_IFREG)
-  { close(fdmess); err("ZSorry, message has wrong type. (#4.3.5)\n"); return; }
+  { close(fdmess); err("Z4.3.5 Sorry, message has wrong type\n"); return; }
  if (st.st_uid != auto_uidq) /* aaack! qmailq has to be trusted! */
   /* your security is already toast at this point. damage control... */
-  { close(fdmess); err("ZSorry, message has wrong owner. (#4.3.5)\n"); return; }
+  { close(fdmess); err("Z4.3.5 Sorry, message has wrong owner\n"); return; }
 
  if (pipe(pi) == -1)
-  { close(fdmess); err("Zqmail-spawn unable to create pipe. (#4.3.0)\n"); return; }
+  { close(fdmess); err("Z4.3.0 qmail-spawn unable to create pipe\n"); return; }
 
  coe(pi[0]);
 
- f = spawn(fdmess,pi[1],sender.s,recip.s,j);
+ f = spawn(fdmess,pi[1],st.st_size,sender.s,recip.s,j);
  close(fdmess);
  if (f == -1)
-  { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; }
+  { close(pi[0]); close(pi[1]); err("Z4.3.0 qmail-spawn unable to fork\n"); return; }
 
  d[delnum].fdin = pi[0];
  d[delnum].fdout = pi[1]; coe(pi[1]);
@@ -155,16 +159,19 @@
     {
      case 0:
        delnum = (unsigned int) (unsigned char) ch;
-       messid.len = 0; stage = 1; break;
+       stage = 1; break;
      case 1:
+       delnum += (unsigned int) ((unsigned int) ch) << 8;
+       messid.len = 0; stage = 2; break;
+     case 2:
        if (!stralloc_append(&messid,&ch)) flagabort = 1;
        if (ch) break;
-       sender.len = 0; stage = 2; break;
-     case 2:
+       sender.len = 0; stage = 3; break;
+     case 3:
        if (!stralloc_append(&sender,&ch)) flagabort = 1;
        if (ch) break;
-       recip.len = 0; stage = 3; break;
-     case 3:
+       recip.len = 0; stage = 4; break;
+     case 4:
        if (!stralloc_append(&recip,&ch)) flagabort = 1;
        if (ch) break;
        docmd();
@@ -175,7 +182,7 @@
 
 char inbuf[128];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
@@ -201,7 +208,8 @@
 
  initialize(argc,argv);
 
- ch = auto_spawn; substdio_putflush(&ssout,&ch,1);
+ ch = auto_spawn; substdio_put(&ssout,&ch,1);
+ ch = auto_spawn >> 8; substdio_putflush(&ssout,&ch,1);
 
  for (i = 0;i < auto_spawn;++i) { d[i].used = 0; d[i].output.s = 0; }
 
@@ -236,7 +244,8 @@
 	   continue; /* read error on a readable pipe? be serious */
 	 if (r == 0)
 	  {
-           ch = i; substdio_put(&ssout,&ch,1);
+           char ch; ch = i; substdio_put(&ssout,&ch,1);
+           ch = i >> 8; substdio_put(&ssout,&ch,1);
 	   report(&ssout,d[i].wstat,d[i].output.s,d[i].output.len);
 	   substdio_put(&ssout,"",1);
 	   substdio_flush(&ssout);
diff -urN qmail-1.03-vanilla/splogger.c qmail-1.03-md24/splogger.c
--- qmail-1.03-vanilla/splogger.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/splogger.c	2007-07-19 20:56:22.000000000 +0200
@@ -45,7 +45,7 @@
   bufpos = 0;
 }
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char **argv;
 {
diff -urN qmail-1.03-vanilla/str_cpyb.c qmail-1.03-md24/str_cpyb.c
--- qmail-1.03-vanilla/str_cpyb.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/str_cpyb.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,18 @@
+#include "str.h"
+
+unsigned int str_copyb(s,t,max)
+register char *s;
+register char *t;
+unsigned int max;
+{
+  register int len;
+
+  len = 0;
+  while (max-- > 0) {
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+    if (!(*s = *t)) return len; ++s; ++t; ++len;
+  }
+  return len;
+}
diff -urN qmail-1.03-vanilla/str.h qmail-1.03-md24/str.h
--- qmail-1.03-vanilla/str.h	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/str.h	2007-07-19 20:56:22.000000000 +0200
@@ -1,13 +1,15 @@
 #ifndef STR_H
 #define STR_H
 
-extern unsigned int str_copy();
 extern int str_diff();
 extern int str_diffn();
+extern int str_start();
+
 extern unsigned int str_len();
 extern unsigned int str_chr();
 extern unsigned int str_rchr();
-extern int str_start();
+extern unsigned int str_copy();
+extern unsigned int str_copyb();
 
 #define str_equal(s,t) (!str_diff((s),(t)))
 
diff -urN qmail-1.03-vanilla/strsalloc.c qmail-1.03-md24/strsalloc.c
--- qmail-1.03-vanilla/strsalloc.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/strsalloc.c	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,7 @@
+#include "alloc.h"
+#include "gen_allocdefs.h"
+#include "stralloc.h"
+#include "strsalloc.h"
+
+GEN_ALLOC_readyplus(strsalloc,stralloc,sa,len,a,i,n,x,10,strsalloc_readyplus)
+GEN_ALLOC_append(strsalloc,stralloc,sa,len,a,i,n,x,10,strsalloc_readyplus,strsalloc_append)
diff -urN qmail-1.03-vanilla/strsalloc.h qmail-1.03-md24/strsalloc.h
--- qmail-1.03-vanilla/strsalloc.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/strsalloc.h	2007-07-19 20:56:22.000000000 +0200
@@ -0,0 +1,12 @@
+#ifndef STRSALLOC_H
+#define STRSALLOC_H
+
+#include "stralloc.h"
+
+#include "gen_alloc.h"
+
+GEN_ALLOC_typedef(strsalloc,stralloc,sa,len,a)
+extern int strsalloc_readyplus();
+extern int strsalloc_append();
+
+#endif
diff -urN qmail-1.03-vanilla/subfderr.c qmail-1.03-md24/subfderr.c
--- qmail-1.03-vanilla/subfderr.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/subfderr.c	2007-07-19 20:56:22.000000000 +0200
@@ -2,6 +2,6 @@
 #include "substdio.h"
 #include "subfd.h"
 
-char subfd_errbuf[256];
-static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256);
+char subfd_errbuf[1024];
+static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,1024);
 substdio *subfderr = &it;
diff -urN qmail-1.03-vanilla/TARGETS qmail-1.03-md24/TARGETS
--- qmail-1.03-vanilla/TARGETS	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/TARGETS	2007-07-28 15:56:12.000000000 +0200
@@ -1,387 +1,354 @@
+alloc.a
+alloc.o
+alloc_re.o
+auto_break.c
+auto_break.o
 auto-ccld.sh
-make-load
-find-systype
-systype
-load
-make-compile
-compile
-fork.h
-qmail-local.o
-qmail.o
-quote.o
-now.o
-gfrom.o
-myctime.o
-slurpclose.o
-make-makelib
-makelib
+auto-gid
+auto-gid.o
+auto-int
+auto-int8
+auto-int8.o
+auto-int.o
+auto_patrn.c
+auto_patrn.o
+auto_qmail.c
+auto_qmail.o
+auto_spawn.c
+auto_spawn.o
+auto_split.c
+auto_split.o
+auto-str
+auto-str.o
+auto-uid
+auto-uid.o
+auto_uids.c
+auto_uids.o
+auto_usera.c
+auto_usera.o
+base64.o
+binm1
+binm1+df
+binm2
+binm2+df
+binm3
+binm3+df
+bouncesaying
+bouncesaying.o
+byte_chr.o
+byte_copy.o
+byte_cr.o
+byte_cspn.o
+byte_diff.o
+byte_rchr.o
+byte_rcspn.o
+byte_zero.o
+case.a
 case_diffb.o
 case_diffs.o
 case_lowerb.o
 case_lowers.o
 case_starts.o
-case.a
-getln.o
-getln2.o
-getln.a
-subgetopt.o
-sgetopt.o
-getopt.a
-sig_alarm.o
-hassgprm.h
-sig_block.o
-hassgact.h
-sig_catch.o
-sig_pause.o
-sig_pipe.o
-sig_child.o
-sig_hup.o
-sig_term.o
-sig_bug.o
-sig_misc.o
-sig.a
-open_append.o
-open_excl.o
-open_read.o
-open_trunc.o
-open_write.o
-open.a
-seek_cur.o
-seek_end.o
-seek_set.o
-seek_trunc.o
-seek.a
-hasflock.h
-lock_ex.o
-lock_exnb.o
-lock_un.o
-lock.a
-fd_copy.o
-fd_move.o
-fd.a
-haswaitp.h
-wait_pid.o
-wait_nohang.o
-wait.a
+cdb.a
+cdb_hash.o
+cdbmake.a
+cdbmake_add.o
+cdbmake_hash.o
+cdbmake_pack.o
+cdbmss.o
+cdb_seek.o
+cdb_unpack.o
+check
+chkshsgr
+chkshsgr.o
+chkspawn
+chkspawn.o
+coe.o
+commands.o
+compile
+condredirect
+condredirect.o
+config
+config-fast
+constmap.o
+control.o
+date822fmt.o
+datemail
+datetime.a
+datetime.o
+datetime_un.o
+direntry.h
+dnscname
+dnscname.o
+dnsdoe.o
+dnsfq
+dnsfq.o
+dnsip
+dnsip.o
+dns.lib
+dnsmxip
+dnsmxip.o
+dns.o
+dnsptr
+dnsptr.o
+dnstxt
+dnstxt.o
+dot-qmail.5
+elq
+env.a
 env.o
 envread.o
-env.a
-stralloc_eady.o
-stralloc_pend.o
-stralloc_copy.o
-stralloc_opys.o
-stralloc_opyb.o
-stralloc_cat.o
-stralloc_cats.o
-stralloc_catb.o
-stralloc_arts.o
-stralloc.a
-alloc.o
-alloc_re.o
-alloc.a
-strerr_sys.o
-strerr_die.o
-strerr.a
-substdio.o
-substdi.o
-substdo.o
-subfderr.o
-subfdout.o
-subfdouts.o
-subfdin.o
-subfdins.o
-substdio_copy.o
-substdio.a
+error.a
 error.o
 error_str.o
 error_temp.o
-error.a
-str_len.o
-str_diff.o
-str_diffn.o
-str_cpy.o
-str_chr.o
-str_rchr.o
-str_start.o
-byte_chr.o
-byte_rchr.o
-byte_diff.o
-byte_copy.o
-byte_cr.o
-byte_zero.o
-str.a
-fmt_str.o
+except
+except.o
+fd.a
+fd_copy.o
+fd_move.o
+fifo.o
+find-systype
+fmtqfn.o
 fmt_strn.o
-fmt_uint.o
+fmt_str.o
 fmt_uint0.o
+fmt_uint.o
 fmt_ulong.o
-scan_ulong.o
-scan_8long.o
+fork.h
+forward
+forward.o
 fs.a
-datetime.o
-datetime_un.o
-datetime.a
-auto-str.o
-auto-str
-auto_qmail.c
-auto_qmail.o
-auto-int8.o
-auto-int8
-auto_patrn.c
-auto_patrn.o
-socket.lib
-qmail-local
-uint32.h
-qmail-lspawn.o
-select.h
-chkspawn.o
-auto-int.o
-auto-int
-auto_spawn.c
-auto_spawn.o
-chkspawn
-spawn.o
-chkshsgr.o
-chkshsgr
+getln2.o
+getln.a
+getln.o
+getopt.a
+gfrom.o
+hasflock.h
+hasmkffo.h
+hasnpbg1.h
+hassalen.h
+hassgact.h
+hassgprm.h
 hasshsgr.h
-prot.o
-coe.o
-cdb_hash.o
-cdb_unpack.o
-cdb_seek.o
-cdb.a
-auto-uid.o
-auto-uid
-auto-gid.o
-auto-gid
-auto_uids.c
-auto_uids.o
-qmail-lspawn
-qmail-getpw.o
-auto_break.c
-auto_break.o
-auto_usera.c
-auto_usera.o
-qmail-getpw
-qmail-remote.o
-control.o
-constmap.o
-timeoutread.o
-timeoutwrite.o
-timeoutconn.o
-tcpto.o
-dns.o
-ip.o
+haswaitp.h
+headerbody.o
+hfield.o
+hier.o
+hmac_md5.o
+hmac_ripemd.o
+hmac_sha1.o
+home
+home+df
+hostname
+hostname.o
+idedit
+idedit.o
+install
+install-big
+install-big.o
+install.o
+instcheck
+instcheck.o
 ipalloc.o
-hassalen.h
 ipme.o
+ipmeprint
+ipmeprint.o
+ip.o
+it
+load
+lock.a
+lock_exnb.o
+lock_ex.o
+lock_un.o
+maildir2mbox
+maildir2mbox.o
+maildirmake
+maildirmake.o
+maildir.o
+maildirwatch
+maildirwatch.o
+mailsubj
+make-compile
+makelib
+make-load
+make-makelib
+man
+md5.o
+myctime.o
+ndelay.a
 ndelay.o
 ndelay_off.o
-ndelay.a
-dns.lib
-qmail-remote
-qmail-rspawn.o
-tcpto_clean.o
-qmail-rspawn
-direntry.h
-qmail-clean.o
-fmtqfn.o
-auto_split.c
-auto_split.o
-qmail-clean
-qmail-send.o
-qsutil.o
 newfield.o
+now.o
+open.a
+open_append.o
+open_excl.o
+open_read.o
+open_trunc.o
+open_write.o
+out_log.o
+pinq
+predate
+predate.o
+preline
+preline.o
 prioq.o
-hasmkffo.h
-fifo.o
-hasnpbg1.h
-trigger.o
-readsubdir.o
-date822fmt.o
-qmail-send
-qmail-start.o
-qmail-start
-splogger.o
-syslog.lib
-splogger
-qmail-queue.o
-triggerpull.o
-qmail-queue
-qmail-inject.o
-headerbody.o
-hfield.o
-token822.o
+proc
+proc+df
+prot.o
+qail
+qbiff
+qbiff.o
+qmail-clean
+qmail-clean.o
+qmail-control.5
+qmail-getpw
+qmail-getpw.8
+qmail-getpw.o
 qmail-inject
-predate.o
-predate
-datemail
-mailsubj
-qmail-upq
-qmail-showctl.o
-qmail-showctl
-qmail-newu.o
-cdbmss.o
-cdbmake_pack.o
-cdbmake_hash.o
-cdbmake_add.o
-cdbmake.a
+qmail-inject.o
+qmail-limits.7
+qmail-local
+qmail-local.o
+qmail-lspawn
+qmail-lspawn.o
+qmail-newmrh
+qmail-newmrh.8
+qmail-newmrh.o
 qmail-newu
-qmail-pw2u.o
-qmail-pw2u
-qmail-qread.o
-qmail-qread
-qmail-qstat
-qmail-tcpto.o
-qmail-tcpto
-qmail-tcpok.o
-qmail-tcpok
-qmail-pop3d.o
-commands.o
-maildir.o
+qmail-newu.8
+qmail-newu.o
+qmail.o
+qmail-p0f.o
 qmail-pop3d
-qmail-popup.o
+qmail-pop3d.o
 qmail-popup
-qmail-qmqpc.o
+qmail-popup.o
+qmail-pw2u
+qmail-pw2u.8
+qmail-pw2u.o
 qmail-qmqpc
-qmail-qmqpd.o
-received.o
+qmail-qmqpc.o
 qmail-qmqpd
-qmail-qmtpd.o
-rcpthosts.o
+qmail-qmqpd.o
 qmail-qmtpd
-qmail-smtpd.o
-qmail-smtpd
-sendmail.o
-sendmail
-tcp-env.o
-remoteinfo.o
-tcp-env
-qmail-newmrh.o
-qmail-newmrh
-config
-config-fast
-dnscname.o
-dnsdoe.o
-dnscname
-dnsptr.o
-dnsptr
-dnsip.o
-dnsip
-dnsmxip.o
-dnsmxip
-dnsfq.o
-dnsfq
-hostname.o
-hostname
-ipmeprint.o
-ipmeprint
-qreceipt.o
-qreceipt
-qsmhook.o
-qsmhook
-qbiff.o
-qbiff
-forward.o
-forward
-preline.o
-preline
-condredirect.o
-condredirect
-bouncesaying.o
-bouncesaying
-except.o
-except
-maildirmake.o
-maildirmake
-maildir2mbox.o
-maildir2mbox
-maildirwatch.o
-maildirwatch
-qail
-elq
-pinq
-idedit.o
-idedit
-install-big.o
-install.o
-install-big
-hier.o
-install
-instcheck.o
-instcheck
-home
-home+df
-proc
-proc+df
-binm1
-binm1+df
-binm2
-binm2+df
-binm3
-binm3+df
-it
-qmail-local.0
-qmail-lspawn.0
-qmail-getpw.8
-qmail-getpw.0
-qmail-remote.0
-qmail-rspawn.0
-qmail-clean.0
+qmail-qmtpd.o
+qmail-qread
+qmail-qread.o
+qmail-qstat
+qmail-queue
+qmail-queue.o
+qmail-remote
+qmail-remote.o
+qmail-rspawn
+qmail-rspawn.o
+qmail-sasl.o
+qmail-send
 qmail-send.8
-qmail-send.0
+qmail-send.o
+qmail-showctl
+qmail-showctl.o
+qmail-smtpd
+qmail-smtpd.o
+qmail-start
 qmail-start.8
-qmail-start.0
-splogger.0
-qmail-queue.0
-qmail-inject.0
-mailsubj.0
-qmail-showctl.0
-qmail-newu.8
-qmail-newu.0
-qmail-pw2u.8
-qmail-pw2u.0
-qmail-qread.0
-qmail-qstat.0
-qmail-tcpto.0
-qmail-tcpok.0
-qmail-pop3d.0
-qmail-popup.0
-qmail-qmqpc.0
-qmail-qmqpd.0
-qmail-qmtpd.0
-qmail-smtpd.0
-tcp-env.0
-qmail-newmrh.8
-qmail-newmrh.0
-qreceipt.0
-qbiff.0
-forward.0
-preline.0
-condredirect.0
-bouncesaying.0
-except.0
-maildirmake.0
-maildir2mbox.0
-maildirwatch.0
-qmail.0
-qmail-limits.7
-qmail-limits.0
-qmail-log.0
-qmail-control.5
-qmail-control.0
-qmail-header.0
+qmail-start.o
+qmail-tcpok
+qmail-tcpok.o
+qmail-tcpto
+qmail-tcpto.o
+qmail-upq
 qmail-users.5
-qmail-users.0
-dot-qmail.5
-dot-qmail.0
-qmail-command.0
-tcp-environ.0
-maildir.0
-mbox.0
-addresses.0
-envelopes.0
-forgeries.0
-man
+qreceipt
+qreceipt.o
+qsmhook
+qsmhook.o
+qsutil.o
+quote.o
+rcpthosts.o
+readsubdir.o
+realrcptto.o
+received.o
+remoteinfo.o
+ripemd.o
+scan_8long.o
+scan_ulong.o
+seek.a
+seek_cur.o
+seek_end.o
+seek_set.o
+seek_trunc.o
+select.h
+sendmail
+sendmail.o
 setup
-check
+sgetopt.o
+sha1.o
+sig.a
+sig_alarm.o
+sig_block.o
+sig_bug.o
+sig_catch.o
+sig_child.o
+sig_hup.o
+sig_misc.o
+sig_pause.o
+sig_pipe.o
+sig_term.o
+slurpclose.o
+socket.lib
+spawn.o
+splogger
+splogger.o
+str.a
+stralloc.a
+stralloc_arts.o
+stralloc_catb.o
+stralloc_cat.o
+stralloc_cats.o
+stralloc_copy.o
+stralloc_eady.o
+stralloc_opyb.o
+stralloc_opys.o
+stralloc_pend.o
+str_chr.o
+str_cpyb.o
+str_cpy.o
+str_diffn.o
+str_diff.o
+strerr.a
+strerr_die.o
+strerr_sys.o
+str_len.o
+str_rchr.o
+strsalloc.o
+str_start.o
+subfderr.o
+subfdin.o
+subfdins.o
+subfdout.o
+subfdouts.o
+subgetopt.o
+substdi.o
+substdio.a
+substdio_copy.o
+substdio.o
+substdo.o
+syslog.lib
+systype
+tcp-env
+tcp-env.o
+tcpto_clean.o
+tcpto.o
+timeoutconn.o
+timeoutread.o
+timeoutwrite.o
+token822.o
+trigger.o
+triggerpull.o
+ucspitls.o
+uint32.h
+wait.a
+wait_nohang.o
+wait_pid.o
diff -urN qmail-1.03-vanilla/tcp-env.c qmail-1.03-md24/tcp-env.c
--- qmail-1.03-vanilla/tcp-env.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tcp-env.c	2007-07-19 20:56:22.000000000 +0200
@@ -2,6 +2,8 @@
 #include <sys/socket.h>
 #include <sys/param.h>
 #include <netinet/in.h>
+#include <unistd.h>
+
 #include "sig.h"
 #include "stralloc.h"
 #include "str.h"
@@ -10,6 +12,7 @@
 #include "scan.h"
 #include "subgetopt.h"
 #include "ip.h"
+#include "strsalloc.h"
 #include "dns.h"
 #include "byte.h"
 #include "remoteinfo.h"
@@ -30,10 +33,11 @@
 
 char temp[IPFMT + FMT_ULONG];
 
-void main(argc,argv)
+int main(argc,argv)
 int argc;
 char *argv[];
 {
+ strsalloc ssa = {0};
  int dummy;
  char *proto;
  int opt;
@@ -74,12 +78,13 @@
    temp[ip_fmt(temp,&iplocal)] = 0;
    if (!env_put2("TCPLOCALIP",temp)) die();
 
-   switch(dns_ptr(&localname,&iplocal))
+   switch(dns_ptr(&ssa,&iplocal))
     {
      case DNS_MEM: die();
      case DNS_SOFT:
        if (!stralloc_copys(&localname,"softdnserror")) die();
      case 0:
+       if (!stralloc_copy(&localname,&ssa.sa[0])) die();
        if (!stralloc_0(&localname)) die();
        case_lowers(localname.s);
        if (!env_put2("TCPLOCALHOST",localname.s)) die();
@@ -99,12 +104,13 @@
    temp[ip_fmt(temp,&ipremote)] = 0;
    if (!env_put2("TCPREMOTEIP",temp)) die();
 
-   switch(dns_ptr(&remotename,&ipremote))
+   switch(dns_ptr(&ssa,&ipremote))
     {
      case DNS_MEM: die();
      case DNS_SOFT:
        if (!stralloc_copys(&remotename,"softdnserror")) die();
      case 0:
+       if (!stralloc_copy(&remotename,&ssa.sa[0])) die();
        if (!stralloc_0(&remotename)) die();
        case_lowers(remotename.s);
        if (!env_put2("TCPREMOTEHOST",remotename.s)) die();
@@ -125,5 +131,5 @@
 
  sig_pipedefault();
  execvp(*argv,argv);
- die();
+ return 111;
 }
diff -urN qmail-1.03-vanilla/tcpto.c qmail-1.03-md24/tcpto.c
--- qmail-1.03-vanilla/tcpto.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tcpto.c	2007-07-19 20:56:22.000000000 +0200
@@ -73,7 +73,7 @@
  int i;
  char *record;
  datetime_sec when;
- datetime_sec firstwhen;
+ datetime_sec firstwhen=0;
  int firstpos;
  datetime_sec lastwhen;
 
diff -urN qmail-1.03-vanilla/tcpto_clean.c qmail-1.03-md24/tcpto_clean.c
--- qmail-1.03-vanilla/tcpto_clean.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tcpto_clean.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "tcpto.h"
 #include "open.h"
 #include "substdio.h"
diff -urN qmail-1.03-vanilla/timeoutconn.c qmail-1.03-md24/timeoutconn.c
--- qmail-1.03-vanilla/timeoutconn.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/timeoutconn.c	2007-07-19 20:56:22.000000000 +0200
@@ -10,38 +10,46 @@
 #include "byte.h"
 #include "timeoutconn.h"
 
-int timeoutconn(s,ip,port,timeout)
-int s;
-struct ip_address *ip;
-unsigned int port;
-int timeout;
+int timeoutconn(s,ip,outip,port,timeout)
+  int s;
+  struct ip_address *ip;
+  struct ip_address *outip;
+  unsigned int port;
+  int timeout;
 {
   char ch;
   struct sockaddr_in sin;
   char *x;
   fd_set wfds;
   struct timeval tv;
- 
+
+  /* bind() an outgoing ipaddr */
+  byte_zero(&sin,sizeof(sin));
+  byte_copy(&sin.sin_addr.s_addr,4,outip);
+  sin.sin_family = AF_INET;
+
+  if (-1 == bind(s,(struct sockaddr *) &sin,sizeof(sin))) return -1;
+
   byte_zero(&sin,sizeof(sin));
   byte_copy(&sin.sin_addr,4,ip);
   x = (char *) &sin.sin_port;
   x[1] = port; port >>= 8; x[0] = port;
   sin.sin_family = AF_INET;
- 
+
   if (ndelay_on(s) == -1) return -1;
- 
+
   /* XXX: could bind s */
- 
+
   if (connect(s,(struct sockaddr *) &sin,sizeof(sin)) == 0) {
     ndelay_off(s);
     return 0;
   }
   if ((errno != error_inprogress) && (errno != error_wouldblock)) return -1;
- 
+
   FD_ZERO(&wfds);
   FD_SET(s,&wfds);
   tv.tv_sec = timeout; tv.tv_usec = 0;
- 
+
   if (select(s + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1;
   if (FD_ISSET(s,&wfds)) {
     int dummy;
@@ -53,7 +61,7 @@
     ndelay_off(s);
     return 0;
   }
- 
+
   errno = error_timeout; /* note that connect attempt is continuing */
   return -1;
 }
diff -urN qmail-1.03-vanilla/trigger.c qmail-1.03-md24/trigger.c
--- qmail-1.03-vanilla/trigger.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trigger.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "select.h"
 #include "open.h"
 #include "trigger.h"
diff -urN qmail-1.03-vanilla/triggerpull.c qmail-1.03-md24/triggerpull.c
--- qmail-1.03-vanilla/triggerpull.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/triggerpull.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <unistd.h>
 #include "ndelay.h"
 #include "open.h"
 #include "triggerpull.h"
diff -urN qmail-1.03-vanilla/trycpp.c qmail-1.03-md24/trycpp.c
--- qmail-1.03-vanilla/trycpp.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trycpp.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,4 @@
-void main()
+int main()
 {
 #ifdef NeXT
   printf("nextstep\n"); exit(0);
diff -urN qmail-1.03-vanilla/tryflock.c qmail-1.03-md24/tryflock.c
--- qmail-1.03-vanilla/tryflock.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tryflock.c	2007-07-19 20:56:22.000000000 +0200
@@ -2,7 +2,7 @@
 #include <sys/file.h>
 #include <fcntl.h>
 
-void main()
+int main()
 {
   flock(0,LOCK_EX | LOCK_UN | LOCK_NB);
 }
diff -urN qmail-1.03-vanilla/trymkffo.c qmail-1.03-md24/trymkffo.c
--- qmail-1.03-vanilla/trymkffo.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trymkffo.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-void main()
+int main()
 {
   mkfifo("temp-trymkffo",0);
 }
diff -urN qmail-1.03-vanilla/trynpbg1.c qmail-1.03-md24/trynpbg1.c
--- qmail-1.03-vanilla/trynpbg1.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trynpbg1.c	2007-07-19 20:56:22.000000000 +0200
@@ -4,7 +4,7 @@
 
 #define FN "temp-trynpbg1.fifo"
 
-void main()
+int main()
 {
   int flagbug;
   struct timeval instant;
diff -urN qmail-1.03-vanilla/trysgact.c qmail-1.03-md24/trysgact.c
--- qmail-1.03-vanilla/trysgact.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trysgact.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,6 @@
 #include <signal.h>
 
-void main()
+int main()
 {
   struct sigaction sa;
   sa.sa_handler = 0;
diff -urN qmail-1.03-vanilla/trysgprm.c qmail-1.03-md24/trysgprm.c
--- qmail-1.03-vanilla/trysgprm.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trysgprm.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,6 +1,6 @@
 #include <signal.h>
 
-void main()
+int main()
 {
   sigset_t ss;
  
diff -urN qmail-1.03-vanilla/tryshsgr.c qmail-1.03-md24/tryshsgr.c
--- qmail-1.03-vanilla/tryshsgr.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tryshsgr.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,4 @@
-void main()
+int main()
 {
   short x[4];
  
diff -urN qmail-1.03-vanilla/tryulong32.c qmail-1.03-md24/tryulong32.c
--- qmail-1.03-vanilla/tryulong32.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tryulong32.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,4 @@
-void main()
+int main()
 {
   unsigned long u;
   u = 1;
diff -urN qmail-1.03-vanilla/tryvfork.c qmail-1.03-md24/tryvfork.c
--- qmail-1.03-vanilla/tryvfork.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/tryvfork.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,4 +1,4 @@
-void main()
+int main()
 {
   vfork();
 }
diff -urN qmail-1.03-vanilla/trywaitp.c qmail-1.03-md24/trywaitp.c
--- qmail-1.03-vanilla/trywaitp.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-md24/trywaitp.c	2007-07-19 20:56:22.000000000 +0200
@@ -1,7 +1,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
-void main()
+int main()
 {
   waitpid(0,0,0);
 }
diff -urN qmail-1.03-vanilla/typesx.h qmail-1.03-md24/typesx.h
--- qmail-1.03-vanilla/typesx.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/typesx.h	2007-07-19 22:19:14.000000000 +0200
@@ -0,0 +1,26 @@
+#ifndef MISC_TYPES_H
+#define MISC_TYPES_H
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+/* used for crypto routines */
+#ifdef uint32_t
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t   u8;
+
+typedef int32_t i32;
+typedef int16_t i16;
+typedef int8_t   i8;
+#else
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+
+typedef signed int i32;
+typedef signed short i16;
+typedef signed char i8;
+#endif
+
+#endif
diff -urN qmail-1.03-vanilla/ucspitls.c qmail-1.03-md24/ucspitls.c
--- qmail-1.03-vanilla/ucspitls.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/ucspitls.c	2007-07-28 15:55:38.000000000 +0200
@@ -0,0 +1,31 @@
+#include "scan.h"
+#include "env.h"
+
+int ucspitls(void)
+{
+  unsigned long fd;
+  char *fdstr;
+   
+  if (!(fdstr=env_get("SSLCTLFD")))
+    return 0;
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (write((int)fd, "y", 1) < 1)
+    return 0;
+ 
+  if (!(fdstr=env_get("SSLREADFD")))
+    return 0;
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (dup2((int)fd,0) == -1)
+    return 0;
+ 
+  if (!(fdstr=env_get("SSLWRITEFD")))
+    return 0; 
+  if (!scan_ulong(fdstr,&fd))
+    return 0;
+  if (dup2((int)fd,1) == -1)
+    return 0;
+ 
+  return 1;
+}
diff -urN qmail-1.03-vanilla/ucspitls.h qmail-1.03-md24/ucspitls.h
--- qmail-1.03-vanilla/ucspitls.h	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-md24/ucspitls.h	2007-07-28 15:55:42.000000000 +0200
@@ -0,0 +1 @@
+int ucspitls(void);
