20060105                                                        12/15/2004

This is a collection of several popular qmail patches rolled into one.  This
composite patch applies to netqmail 1.05.  The patches included are:

smtp-auth patch v. 0.5.7 by Erwin Hoffmann 
http://www.fehcom.de/qmail/smtpauth.html

TLS patch by Frederik Vermeulen <jos-tls@Kotnet.org>.  Here's the original
patch with documentation at the top:
http://inoa.net/qmail-tls/netqmail-1.05-tls--20060104.patch

oversize dns patch by Christopher K. Davis.
http://www.ckdhr.com/ckd/qmail-103.patch

qregex 20040725 originally by by Andrew St. Jean.  
http://www.arda.homeunix.net/store/qmail/
adds pattern matching in the badhelo, badmailfrom, badmailfromnorelay, 
badmailto, and badmailtonorelay control files. Pattern matching is case 
insensitive and logs are generated when a match is found.

Big Concurrency patch by Johannes Erdfelt
http://qmail.org/big-concurrency.patch

netqmail-maildir++.patch by me.  Here's the link to the original patch:
http://shupp.org/patches/netqmail-maildir++.patch
This adds maildirquota support to qmail-pop3d and qmail-local.

chkuser 2.0.8 by Antonio Nati
http://www.interazioni.it/opensource/chkuser/
NOTE: This requires vpopmail to already be compiled.
You may need to edit the Makefile for paths, etc.

Dale Woolridge, James Law, and Moto Kawasaki's Spam Throttle 2.02
http://spamthrottle.qmail.ca/

SPF rc5 by christophe@saout.de
http://www.saout.de/misc/spf/



INSTALL:

Download netqmail-1.05 and this patch in the same directory.
then:

tar -xzf netqmail-1.05.tar.gz
cd netqmail-1.05
./collate.sh
cd netqmail-1.05
bunzip2 -cd  ../../qmail-toaster-0.8.1.patch.bz2 | patch -p0
make
make setup check


CREDITS:

This composite patch was put together by Bill Shupp, and sponsored by
"Nerds On Site Inc." - http://www.nerdsonsite.com



Cheers,

Bill Shupp
hostmaster@shupp.org








diff -urN ../../netqmail-1.05-orig/netqmail-1.05/CHANGES.spamthrottle ./CHANGES.spamthrottle
--- ../../netqmail-1.05-orig/netqmail-1.05/CHANGES.spamthrottle	1969-12-31 16:00:00.000000000 -0800
+++ ./CHANGES.spamthrottle	2006-01-05 15:03:43.280251776 -0800
@@ -0,0 +1,79 @@
+20021231 do spam dir existence checks first (more likely case) {dw}
+         update/fix man page(s) {dw}
+         public release 2.01
+
+20021230 minor fixes/tweaking {dw}
+
+20021228 finish testing {dw}
+
+20021226 further testing, code clean up {dw}
+         update documentation and qmail-showctl {dw}
+         write timeout code (so we don't keep sleeping if
+           other end closes) using getpeername() {dw}
+
+20021129 finish initial testing of new control structure {dw}
+
+22021016 rewrite parameter input via cdb-style control file rather
+           than via multiple control files + environment variables {dw}
+         the cdb file allows IP/network keys with network masks (/bits format) {dw}
+         no intention of legacy support at the moment as moving environment
+           variables from tcprule-style files to the spam cdb file is simple
+           and the default values in the control files are intended to be
+           placed as a single entry in the spam cdb file {dw}
+         had to add -Hhl options (stolen from existing djb code) to tcp-env.c
+           to make it actually useful (spamt relies on TCPREMOTEIP being set) {dw}
+
+20020226 documentation says spamthrottlercpt defaults to 0, but it wasn't
+           (fixed code to match documentation)
+         obviously the non-libtai time code hasn't been tested since
+         it was rewritten:
+           time_sub() calculated t2-t1 (should be t1-t2)
+           time_pack() didn't preserve usec's leading zeroes (added fmt_ulong0())
+           reading times from an empty file resulted in a crash
+         added spam.h dependencies in Makefile
+         public release 1.03
+
+20020219 forgot to flush continuation lines in teergrube code
+         public release 1.02
+
+20020219 fix time(tai)-related bugs in reading/writing taia values
+           (thanks to Roland Chan)
+         add entry to qmail-spamthrottle(9) man page with a simple perl
+           expression to convert packed taia values to tai64n timestamps
+         public release 1.01
+
+20020218 add teergrube support (now 1.01 release) {dw}
+         remove all strerr_warn... calls as they cause problems
+           with qmail's sendmail and the -bs switch (as used by pine
+           for instance)
+         remove dead/redundant code {dw}
+
+20020213 public release 1.00 {dw,jl,mk}
+
+20011224 fix fpe error
+
+20011213 release 1.00 candidate complete
+
+20010923 new formulation, code restructure, man pages updated
+
+20010319 spam wrap open/lock calls
+
+20010313 wrap tai handlers so tai isn't required
+
+20010311 remove an extra CRLF in EHLO response
+         short circuit when sleep time would be zero
+
+20010309 RFC 2920 compliance (don't advertise PIPELINING with stflush on)
+         add fcntl() style lock module for compatibility
+         make new control functions return values
+         lock file is separate from time/wait files
+
+20010227 update man pages with spamthrottle info
+         add spamthrottleflush/spamthrottlemax support
+         add warning in readme about libtai dependency
+
+20010221 remove testing code
+         add spamthrottledir support (so IPs can be grouped)
+           (the '.' means new subdir semantic still enforced though)
+
+20010220 alpha implementation
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/FILES ./FILES
--- ../../netqmail-1.05-orig/netqmail-1.05/FILES	2006-01-05 15:06:38.644592344 -0800
+++ ./FILES	2006-01-05 15:03:43.281251624 -0800
@@ -136,6 +136,8 @@
 dnsip.c
 dnsmxip.c
 dnsptr.c
+dnstxt.c
+spfquery.c
 hostname.c
 ipmeprint.c
 tcp-env.c
@@ -336,13 +338,16 @@
 byte.h
 byte_chr.c
 byte_copy.c
+byte_cspn.c
 byte_cr.c
 byte_diff.c
 byte_rchr.c
+byte_rcspn.c
 byte_zero.c
 str.h
 str_chr.c
 str_cpy.c
+str_cpyb.c
 str_diff.c
 str_diffn.c
 str_len.c
@@ -402,6 +407,8 @@
 date822fmt.c
 dns.h
 dns.c
+spf.h
+spf.c
 trylsock.c
 tryrsolv.c
 ip.h
@@ -432,3 +439,25 @@
 tcp-environ.5
 constmap.h
 constmap.c
+README.spamthrottle
+CHANGES.spamthrottle
+OTHERS.spamthrottle
+fmt_2long.c
+fmt_2long0.c
+fmt_ulong0.c
+time.c
+time.h
+control_time.c
+lock_exfcntl.c
+lock_unfcntl.c
+spam.c
+spam.h
+spam_get.c
+tryltai.c
+trytai.c
+open_rw.c
+qmail-newst.c
+qmail-newst.9
+qmail-spamt.9
+qmail-spamthrottle.9
+scan_2long.c
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/FILES.auth ./FILES.auth
--- ../../netqmail-1.05-orig/netqmail-1.05/FILES.auth	1969-12-31 16:00:00.000000000 -0800
+++ ./FILES.auth	2006-01-05 15:03:43.282251472 -0800
@@ -0,0 +1,18 @@
+The qmail-smtpd Auth patch modifies the following QMAIL 1.03 files:
+
+= TARGETS
+= Makefile
+= qmail-smtpd.c
+= qmail-smtpd.8
+
+Added files:
+
++ base64.c
++ base64.h
++ case_startb.c
+
+Informational files:
+
+% install_auth.sh  (Installation shell script)
+% README.auth
+% README.auth.old (old description of SMTP Auth)
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/Makefile ./Makefile
--- ../../netqmail-1.05-orig/netqmail-1.05/Makefile	2006-01-05 15:06:38.648591736 -0800
+++ ./Makefile	2006-01-05 15:08:14.800974352 -0800
@@ -2,6 +2,10 @@
 
 SHELL=/bin/sh
 
+VPOPMAIL_HOME=/home/vpopmail
+SMTPD_CHKUSER_OBJ=chkuser.o
+VPOPMAIL_LIBS=`head -1 $(VPOPMAIL_HOME)/etc/lib_deps`
+
 default: it
 
 addresses.0: \
@@ -136,6 +140,10 @@
 compile auto_usera.c
 	./compile auto_usera.c
 
+base64.o: \
+compile base64.c base64.h stralloc.h substdio.h str.h
+	./compile base64.c
+
 binm1: \
 binm1.sh conf-qmail
 	cat binm1.sh \
@@ -203,6 +211,10 @@
 compile byte_cr.c byte.h
 	./compile byte_cr.c
 
+byte_cspn.o: \
+compile byte_cspn.c byte.h
+	./compile byte_cspn.c
+
 byte_diff.o: \
 compile byte_diff.c byte.h
 	./compile byte_diff.c
@@ -211,6 +223,10 @@
 compile byte_rchr.c byte.h
 	./compile byte_rchr.c
 
+byte_rcspn.o: \
+compile byte_rcspn.c byte.h
+	./compile byte_rcspn.c
+
 byte_zero.o: \
 compile byte_zero.c byte.h
 	./compile byte_zero.c
@@ -300,6 +316,10 @@
 exit.h auto_spawn.h
 	./compile chkspawn.c
 
+chkuser.o: \
+compile chkuser.c chkuser.h chkuser_settings.h
+	./compile chkuser.c
+
 clean: \
 TARGETS
 	rm -f `cat TARGETS`
@@ -358,9 +378,14 @@
 
 control.o: \
 compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \
-substdio.h error.h control.h alloc.h scan.h
+substdio.h error.h control.h alloc.h scan.h fmt.h
 	./compile control.c
 
+control_time.o: \
+compile control_time.c readwrite.h open.h stralloc.h gen_alloc.h \
+substdio.h error.h control.h alloc.h time.h hastai.h
+	./compile control_time.c
+
 date822fmt.o: \
 compile date822fmt.c datetime.h fmt.h date822fmt.h
 	./compile date822fmt.c
@@ -393,84 +418,96 @@
 	rm -f trydrent.o
 
 dns.lib: \
-tryrsolv.c compile load socket.lib dns.o ipalloc.o ip.o stralloc.a \
-alloc.a error.a fs.a str.a
+tryrsolv.c compile load socket.lib dns.o ipalloc.o strsalloc.o ip.o \
+stralloc.a alloc.a error.a fs.a str.a
 	( ( ./compile tryrsolv.c && ./load tryrsolv dns.o \
-	ipalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
+	ipalloc.o strsalloc.o ip.o stralloc.a alloc.a error.a fs.a str.a \
 	-lresolv `cat socket.lib` ) >/dev/null 2>&1 \
 	&& echo -lresolv || exit 0 ) > dns.lib
 	rm -f tryrsolv.o tryrsolv
 
 dns.o: \
-compile dns.c ip.h ipalloc.h ip.h gen_alloc.h fmt.h alloc.h str.h \
-stralloc.h gen_alloc.h dns.h case.h
+compile dns.c ip.h ipalloc.h strsalloc.h gen_alloc.h fmt.h alloc.h \
+str.h stralloc.h dns.h case.h
 	./compile dns.c
 
 dnscname: \
-load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
+load dnscname.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
 substdio.a error.a str.a fs.a dns.lib socket.lib
-	./load dnscname dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
+	./load dnscname dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
 	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
 	socket.lib`
 
 dnscname.o: \
-compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \
+compile dnscname.c substdio.h subfd.h stralloc.h \
 gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h
 	./compile dnscname.c
 
 dnsdoe.o: \
-compile dnsdoe.c substdio.h subfd.h substdio.h exit.h dns.h dnsdoe.h
+compile dnsdoe.c substdio.h subfd.h exit.h dns.h dnsdoe.h
 	./compile dnsdoe.c
 
 dnsfq: \
-load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
+load dnsfq.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
 substdio.a error.a str.a fs.a dns.lib socket.lib
-	./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
+	./load dnsfq dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
 	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
 	socket.lib`
 
 dnsfq.o: \
-compile dnsfq.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
-dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
+compile dnsfq.c substdio.h subfd.h stralloc.h gen_alloc.h \
+dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
 	./compile dnsfq.c
 
 dnsip: \
-load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
+load dnsip.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
 substdio.a error.a str.a fs.a dns.lib socket.lib
-	./load dnsip dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
+	./load dnsip dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
 	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
 	socket.lib`
 
 dnsip.o: \
-compile dnsip.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
-dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h exit.h
+compile dnsip.c substdio.h subfd.h stralloc.h gen_alloc.h \
+dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h exit.h
 	./compile dnsip.c
 
 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
-	./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o now.o \
+load dnsmxip.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o now.o stralloc.a \
+alloc.a substdio.a error.a str.a fs.a dns.lib socket.lib
+	./load dnsmxip dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o now.o \
 	stralloc.a alloc.a substdio.a error.a str.a fs.a  `cat \
 	dns.lib` `cat socket.lib`
 
 dnsmxip.o: \
-compile dnsmxip.c substdio.h subfd.h substdio.h stralloc.h \
-gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h ip.h gen_alloc.h \
+compile dnsmxip.c substdio.h subfd.h stralloc.h \
+gen_alloc.h fmt.h dns.h dnsdoe.h ip.h ipalloc.h strsalloc.h \
 now.h datetime.h exit.h
 	./compile dnsmxip.c
 
 dnsptr: \
-load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o stralloc.a alloc.a \
+load dnsptr.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
 substdio.a error.a str.a fs.a dns.lib socket.lib
-	./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o stralloc.a \
+	./load dnsptr dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
 	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
 	socket.lib`
 
 dnsptr.o: \
-compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
+compile dnsptr.c substdio.h subfd.h stralloc.h gen_alloc.h \
 str.h scan.h dns.h dnsdoe.h ip.h exit.h
 	./compile dnsptr.c
 
+dnstxt: \
+load dnstxt.o dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
+substdio.a error.a str.a fs.a dns.lib socket.lib
+	./load dnstxt dns.o dnsdoe.o ip.o ipalloc.o strsalloc.o stralloc.a \
+	alloc.a substdio.a error.a str.a fs.a  `cat dns.lib` `cat \
+	socket.lib`
+
+dnstxt.o: \
+compile dnstxt.c substdio.h subfd.h stralloc.h gen_alloc.h \
+str.h scan.h dns.h dnsdoe.h ip.h exit.h
+	./compile dnstxt.c
+
 dot-qmail.0: \
 dot-qmail.5
 	nroff -man dot-qmail.5 > dot-qmail.0
@@ -557,6 +594,14 @@
 	cat auto-ccld.sh find-systype.sh > find-systype
 	chmod 755 find-systype
 
+fmt_2long.o: \
+compile fmt_2long.c fmt.h
+	./compile fmt_2long.c
+
+fmt_2long0.o: \
+compile fmt_2long0.c fmt.h
+	./compile fmt_2long0.c
+
 fmt_str.o: \
 compile fmt_str.c fmt.h
 	./compile fmt_str.c
@@ -577,6 +622,10 @@
 compile fmt_ulong.c fmt.h
 	./compile fmt_ulong.c
 
+fmt_ulong0.o: \
+compile fmt_ulong0.c fmt.h
+	./compile fmt_ulong0.c
+
 fmtqfn.o: \
 compile fmtqfn.c fmtqfn.h fmt.h auto_split.h
 	./compile fmtqfn.c
@@ -608,10 +657,11 @@
 	./compile forward.c
 
 fs.a: \
-makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \
-scan_ulong.o scan_8long.o
-	./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \
-	fmt_ulong.o scan_ulong.o scan_8long.o
+makelib fmt_2long.o fmt_2long0.o fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \
+fmt_ulong.o fmt_ulong0.o scan_ulong.o scan_2long.o scan_8long.o
+	./makelib fs.a fmt_2long.o fmt_2long0.o fmt_str.o fmt_strn.o \
+	fmt_uint.o fmt_uint0.o fmt_ulong.o fmt_ulong0.o scan_ulong.o \
+	scan_2long.o scan_8long.o
 
 getln.a: \
 makelib getln.o getln2.o
@@ -685,6 +735,13 @@
 	hasshsgr.h
 	rm -f tryshsgr.o tryshsgr
 
+hastai.h: \
+trytai.c compile load
+	( ( ./compile trytai.c && ./load trytai -ltai ) >/dev/null \
+	2>&1 \
+	&& echo \#define HASTAI 1 || exit 0 ) > hastai.h
+	rm -f trytai.o trytai
+
 haswaitp.h: \
 trywaitp.c compile load
 	( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \
@@ -777,38 +834,38 @@
 	./compile ip.c
 
 ipalloc.o: \
-compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \
+compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h \
 gen_alloc.h
 	./compile ipalloc.c
 
 ipme.o: \
-compile ipme.c hassalen.h byte.h ip.h ipalloc.h ip.h gen_alloc.h \
-stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h
+compile ipme.c hassalen.h byte.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h \
+stralloc.h gen_alloc.h ipme.h ip.h ipalloc.h strsalloc.h
 	./compile ipme.c
 
 ipmeprint: \
-load ipmeprint.o ipme.o ip.o ipalloc.o stralloc.a alloc.a substdio.a \
-error.a str.a fs.a socket.lib
-	./load ipmeprint ipme.o ip.o ipalloc.o stralloc.a alloc.a \
-	substdio.a error.a str.a fs.a  `cat socket.lib`
+load ipmeprint.o ipme.o ip.o ipalloc.o strsalloc.o stralloc.a alloc.a \
+substdio.a error.a str.a fs.a socket.lib
+	./load ipmeprint ipme.o ip.o ipalloc.o strsalloc.o stralloc.a \
+	alloc.a substdio.a error.a str.a fs.a `cat socket.lib`
 
 ipmeprint.o: \
 compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \
-ipalloc.h ip.h gen_alloc.h exit.h
+ipalloc.h strsalloc.h ip.h gen_alloc.h exit.h
 	./compile ipmeprint.c
 
 it: \
 qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \
 qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \
-predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
+predate datemail mailsubj qmail-upq qmail-showctl qmail-newst qmail-newu \
 qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
 qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
 qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
-dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
+dnsptr dnsip dnsmxip dnsfq dnstxt hostname ipmeprint qreceipt qsmhook qbiff \
 forward preline condredirect bouncesaying except maildirmake \
 maildir2mbox maildirwatch qail elq pinq idedit install-big install \
 instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
-binm3 binm3+df
+binm3 binm3+df spfquery update_tmprsadh
 
 load: \
 make-load warn-auto.sh systype
@@ -816,8 +873,8 @@
 	chmod 755 load
 
 lock.a: \
-makelib lock_ex.o lock_exnb.o lock_un.o
-	./makelib lock.a lock_ex.o lock_exnb.o lock_un.o
+makelib lock_ex.o lock_exnb.o lock_un.o lock_exfcntl.o lock_unfcntl.o
+	./makelib lock.a lock_ex.o lock_exnb.o lock_un.o lock_exfcntl.o lock_unfcntl.o
 
 lock_ex.o: \
 compile lock_ex.c hasflock.h lock.h
@@ -831,6 +888,14 @@
 compile lock_un.c hasflock.h lock.h
 	./compile lock_un.c
 
+lock_exfcntl.o: \
+compile lock_exfcntl.c lock.h
+	./compile lock_exfcntl.c
+
+lock_unfcntl.o: \
+compile lock_unfcntl.c lock.h
+	./compile lock_unfcntl.c
+
 maildir.0: \
 maildir.5
 	nroff -man maildir.5 > maildir.0
@@ -890,6 +955,38 @@
 readwrite.h open.h headerbody.h maildir.h strerr.h
 	./compile maildirwatch.c
 
+maildirgetquota.o: \
+compile maildirgetquota.c maildirgetquota.h maildirmisc.h
+	./compile maildirgetquota.c
+
+maildirflags.o: \
+compile maildirflags.c
+	./compile maildirflags.c
+
+maildiropen.o: \
+compile maildiropen.c maildirmisc.h
+	./compile maildiropen.c
+
+maildirparsequota.o: \
+compile maildirparsequota.c
+	./compile maildirparsequota.c
+
+maildirquota.o: \
+compile maildirquota.c maildirquota.h maildirmisc.h numlib.h
+	./compile maildirquota.c
+
+overmaildirquota.o: \
+compile overmaildirquota.c 
+	./compile overmaildirquota.c
+
+strtimet.o: \
+compile strtimet.c 
+	./compile strtimet.c
+
+strpidt.o: \
+compile strpidt.c 
+	./compile strpidt.c
+
 mailsubj: \
 warn-auto.sh mailsubj.sh conf-qmail conf-break conf-split
 	cat warn-auto.sh mailsubj.sh \
@@ -927,7 +1024,7 @@
 man: \
 qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \
 qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \
-qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \
+qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newst.0 qmail-newu.0 \
 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.0 qreceipt.0 qbiff.0 forward.0 \
@@ -935,7 +1032,7 @@
 maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.0 qmail-log.0 \
 qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.0 \
 qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \
-envelopes.0 forgeries.0
+envelopes.0 forgeries.0 qmail-spamt.0 qmail-spamthrottle.0
 
 mbox.0: \
 mbox.5
@@ -968,9 +1065,9 @@
 
 open.a: \
 makelib open_append.o open_excl.o open_read.o open_trunc.o \
-open_write.o
+open_write.o open_rw.o
 	./makelib open.a open_append.o open_excl.o open_read.o \
-	open_trunc.o open_write.o
+	open_trunc.o open_write.o open_rw.o
 
 open_append.o: \
 compile open_append.c open.h
@@ -984,6 +1081,10 @@
 compile open_read.c open.h
 	./compile open_read.c
 
+open_rw.o: \
+compile open_rw.c open.h
+	./compile open_rw.c
+
 open_trunc.o: \
 compile open_trunc.c open.h
 	./compile open_trunc.c
@@ -1174,12 +1275,15 @@
 load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \
 slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \
 wait.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \
-fs.a datetime.a auto_qmail.o auto_patrn.o socket.lib
+fs.a datetime.a auto_qmail.o auto_patrn.o socket.lib maildirquota.o \
+maildirgetquota.o maildiropen.o maildirparsequota.o overmaildirquota.o \
+strtimet.o strpidt.o
 	./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \
 	slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a \
 	lock.a fd.a wait.a env.a stralloc.a alloc.a strerr.a \
 	substdio.a error.a str.a fs.a datetime.a auto_qmail.o \
-	auto_patrn.o  `cat socket.lib`
+	auto_patrn.o  `cat socket.lib` maildirquota.o maildirgetquota.o \
+    maildiropen.o maildirparsequota.o overmaildirquota.o strtimet.o strpidt.o
 
 qmail-local.0: \
 qmail-local.8
@@ -1241,6 +1345,31 @@
 uint32.h substdio.h
 	./compile qmail-newmrh.c
 
+qmail-newst: \
+load qmail-newst.o cdbmss.o ip.o getln.a open.a seek.a cdbmake.a case.a \
+stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o
+	./load qmail-newst cdbmss.o ip.o getln.a open.a seek.a cdbmake.a \
+	case.a stralloc.a alloc.a substdio.a error.a str.a fs.a \
+	auto_qmail.o
+
+qmail-newst.0: \
+qmail-newst.8
+	nroff -man qmail-newst.8 > qmail-newst.0
+
+qmail-newst.8: \
+qmail-newst.9 conf-break conf-spawn
+	cat qmail-newst.9 \
+	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
+	| sed s}BREAK}"`head -1 conf-break`"}g \
+	| sed s}SPAWN}"`head -1 conf-spawn`"}g \
+	> qmail-newst.8
+
+qmail-newst.o: \
+compile qmail-newst.c stralloc.h gen_alloc.h subfd.h substdio.h \
+getln.h substdio.h cdbmss.h cdbmake.h uint32.h substdio.h exit.h \
+readwrite.h open.h error.h case.h ip.h fmt.h auto_qmail.h
+	./compile qmail-newst.c
+
 qmail-newu: \
 load qmail-newu.o cdbmss.o getln.a open.a seek.a cdbmake.a case.a \
 stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o
@@ -1269,11 +1398,13 @@
 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 \
-stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib
+stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib maildirquota.o \
+maildirparsequota.o maildirflags.o maildiropen.o strtimet.o strpidt.o
 	./load qmail-pop3d commands.o case.a timeoutread.o \
 	timeoutwrite.o maildir.o prioq.o now.o env.a strerr.a sig.a \
 	open.a getln.a stralloc.a alloc.a substdio.a error.a str.a \
-	fs.a  `cat socket.lib`
+	fs.a  `cat socket.lib` maildirquota.o maildirgetquota.o \
+    maildirparsequota.o maildirflags.o maildiropen.o strtimet.o strpidt.o
 
 qmail-pop3d.0: \
 qmail-pop3d.8
@@ -1439,12 +1570,13 @@
 
 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 ipalloc.o strsalloc.o ipme.o quote.o \
 ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \
 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 \
+	tls.o ssl_timeoutio.o -L/usr/local/ssl/lib -lssl -lcrypto \
+	ipalloc.o strsalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \
 	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`
 
@@ -1455,7 +1587,7 @@
 qmail-remote.o: \
 compile qmail-remote.c sig.h stralloc.h gen_alloc.h substdio.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 \
+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
@@ -1513,10 +1645,10 @@
 
 qmail-showctl: \
 load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \
-alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
+alloc.a substdio.a error.a str.a fs.a spam_get.o cdb.a auto_qmail.o auto_break.o \
 auto_patrn.o auto_spawn.o auto_split.o
 	./load qmail-showctl auto_uids.o control.o open.a getln.a \
-	stralloc.a alloc.a substdio.a error.a str.a fs.a \
+	stralloc.a alloc.a substdio.a error.a str.a fs.a spam_get.o cdb.a \
 	auto_qmail.o auto_break.o auto_patrn.o auto_spawn.o \
 	auto_split.o 
 
@@ -1528,34 +1660,60 @@
 compile qmail-showctl.c substdio.h subfd.h substdio.h exit.h fmt.h \
 str.h control.h constmap.h stralloc.h gen_alloc.h direntry.h \
 auto_uids.h auto_qmail.h auto_break.h auto_patrn.h auto_spawn.h \
-auto_split.h
+auto_split.h spf.h
 	./compile qmail-showctl.c
 
 qmail-smtpd: \
-load qmail-smtpd.o rcpthosts.o commands.o timeoutread.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 \
-	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 \
+load qmail-smtpd.o rcpthosts.o qregex.o commands.o timeoutread.o \
+timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o control_time.o time.o constmap.o \
+received.o date822fmt.o now.o qmail.o spf.o dns.o spam.o spam_get.o cdb.a fd.a wait.a \
+datetime.a getln.a open.a sig.a case.a env.a stralloc.a alloc.a strerr.a substdio.a \
+error.a str.a fs.a auto_uids.o tai.lib lock.a auto_qmail.o base64.o socket.lib \
+$(SMTPD_CHKUSER_OBJ) dns.lib
+	./load qmail-smtpd $(SMTPD_CHKUSER_OBJ) qregex.o rcpthosts.o commands.o timeoutread.o \
+	timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o control_time.o time.o \
+    constmap.o tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
+	received.o date822fmt.o now.o qmail.o spf.o spam.o spam_get.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 \
-	socket.lib`
+	alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o base64.o  `cat \
+	socket.lib tai.lib dns.lib` dns.o lock.a $(VPOPMAIL_LIBS)
 
 qmail-smtpd.0: \
 qmail-smtpd.8
 	nroff -man qmail-smtpd.8 > qmail-smtpd.0
 
 qmail-smtpd.o: \
-compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \
+compile qmail-smtpd.c chkuser.h sig.h readwrite.h stralloc.h gen_alloc.h \
 substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \
-error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h \
+error.h ipme.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h ip.h qmail.h \
 substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \
-exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h
+exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h spam.h base64.h spf.h
 	./compile qmail-smtpd.c
 
+qmail-spamt.0: \
+qmail-spamt.5
+	nroff -man qmail-spamt.5 > qmail-spamt.0
+
+qmail-spamt.5: \
+qmail-spamt.9 conf-break conf-spawn
+	cat qmail-spamt.9 \
+      | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
+      | sed s}BREAK}"`head -1 conf-break`"}g \
+      | sed s}SPAWN}"`head -1 conf-spawn`"}g \
+      > qmail-spamt.5
+
+qmail-spamthrottle.0: \
+qmail-spamthrottle.5
+	nroff -man qmail-spamthrottle.5 > qmail-spamthrottle.0
+
+qmail-spamthrottle.5: \
+qmail-spamthrottle.9 conf-break conf-spawn
+	cat qmail-spamthrottle.9 \
+      | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
+      | sed s}BREAK}"`head -1 conf-break`"}g \
+      | sed s}SPAWN}"`head -1 conf-spawn`"}g \
+      > qmail-spamthrottle.5
+
 qmail-start: \
 load qmail-start.o prot.o fd.a auto_uids.o
 	./load qmail-start prot.o fd.a auto_uids.o 
@@ -1681,6 +1839,10 @@
 constmap.h stralloc.h gen_alloc.h rcpthosts.h
 	./compile rcpthosts.c
 
+qregex.o: \
+compile qregex.c qregex.h
+	./compile qregex.c
+
 readsubdir.o: \
 compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \
 auto_split.h
@@ -1696,6 +1858,10 @@
 timeoutread.h timeoutwrite.h remoteinfo.h
 	./compile remoteinfo.c
 
+scan_2long.o: \
+compile scan_2long.c scan.h
+	./compile scan_2long.c
+
 scan_8long.o: \
 compile scan_8long.c scan.h
 	./compile scan_8long.c
@@ -1779,7 +1945,7 @@
 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 \
+dnsip.c dnsmxip.c dnsptr.c dnstxt.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 \
@@ -1813,21 +1979,25 @@
 trywaitp.c sig.h sig_alarm.c sig_block.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 str.h \
-str_chr.c str_cpy.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 \
+byte_copy.c byte_cr.c byte_cspn.c byte_diff.c byte_rchr.c byte_rcspn.c \
+byte_zero.c str.h spf.c spf.h spfquery.c \
+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 lock_exfcntl.c lock_unfcntl.c getln.3 \
 getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.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 \
+fmt_uint.c fmt_uint0.c fmt_ulong.c fmt_ulong0.c scan.h scan_ulong.c scan_2long.c scan_8long.c \
 slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \
 headerbody.h headerbody.c token822.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 trylsock.c tryrsolv.c ip.h ip.c \
-ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
+ipalloc.h strsalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
 ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \
 prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \
-maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c
+maildir.5 maildir.h maildir.c tcp-environ.5 constmap.h constmap.c \
+README.spamthrottle time.c time.h control_time.c lock_exfcntl.c \
+lock_unfcntl.c spam.c spam_get.c tryltai.c trytai.c open_rw.c qmail-spamt.9 \
+qmail-spamthrottle.9 update_tmprsadh
 	shar -m `cat FILES` > shar
 	chmod 400 shar
 
@@ -1890,6 +2060,16 @@
 	&& echo -lsocket -lnsl || exit 0 ) > socket.lib
 	rm -f trylsock.o trylsock
 
+spam.o: \
+compile spam.c auto_uids.h lock.h stralloc.h gen_alloc.h control.h \
+open.h fmt.h timeoutread.h error.h time.h hastai.h ip.h env.h cdb.h \
+uint32.h spam.h substdio.h
+	./compile spam.c
+
+spam_get.o: \
+compile spam_get.c stralloc.h gen_alloc.h spam.h substdio.h
+	./compile spam_get.c
+
 spawn.o: \
 compile chkspawn spawn.c sig.h wait.h substdio.h byte.h str.h \
 stralloc.h gen_alloc.h select.h exit.h alloc.h coe.h open.h error.h \
@@ -1897,6 +2077,23 @@
 	./chkspawn
 	./compile spawn.c
 
+spf.o: \
+compile spf.c stralloc.h gen_alloc.h alloc.h ipme.h ip.h ipalloc.h \
+strsalloc.h str.h fmt.h scan.h byte.h now.h case.h
+	./compile spf.c
+
+spfquery: \
+load spfquery.o spf.o ip.o ipme.o ipalloc.o strsalloc.o now.o dns.o \
+datetime.a stralloc.a alloc.a str.a substdio.a error.a fs.a case.a dns.lib
+	./load spfquery spf.o ip.o ipme.o ipalloc.o strsalloc.o \
+	now.o dns.o datetime.a stralloc.a alloc.a str.a substdio.a \
+	case.a error.a fs.a `cat dns.lib` `cat socket.lib`
+
+spfquery.o: \
+compile spfquery.c substdio.h subfd.h stralloc.h gen_alloc.h alloc.h \
+spf.h exit.h
+	./compile spfquery.c
+
 splogger: \
 load splogger.o substdio.a error.a str.a fs.a syslog.lib socket.lib
 	./load splogger substdio.a error.a str.a fs.a  `cat \
@@ -1912,12 +2109,12 @@
 	./compile splogger.c
 
 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
-	./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
+makelib str_len.o str_diff.o str_diffn.o str_cpy.o str_cpyb.o str_chr.o \
+str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_cspn.o byte_rcspn.o \
+byte_diff.o byte_copy.o byte_cr.o byte_zero.o
+	./makelib str.a str_len.o str_diff.o str_diffn.o str_cpy.o str_cpyb.o \
+	str_chr.o str_rchr.o str_start.o byte_chr.o byte_rchr.o byte_cspn.o \
+	byte_rcspn.o byte_diff.o byte_copy.o byte_cr.o byte_zero.o
 
 str_chr.o: \
 compile str_chr.c str.h
@@ -1927,6 +2124,10 @@
 compile str_cpy.c str.h
 	./compile str_cpy.c
 
+str_cpyb.o: \
+compile str_cpyb.c str.h
+	./compile str_cpyb.c
+
 str_diff.o: \
 compile str_diff.c str.h
 	./compile str_diff.c
@@ -2006,6 +2207,11 @@
 compile strerr_sys.c error.h strerr.h
 	./compile strerr_sys.c
 
+strsalloc.o: \
+compile strsalloc.c alloc.h gen_allocdefs.h stralloc.h strsalloc.h \
+gen_alloc.h
+	./compile strsalloc.c
+
 subfderr.o: \
 compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
 	./compile subfderr.c
@@ -2064,13 +2270,20 @@
 find-systype trycpp.c
 	./find-systype > systype
 
+tai.lib: \
+tryltai.c compile load
+	( ( ./compile tryltai.c && \
+	./load tryltai -ltai ) >/dev/null 2>&1 \
+	&& echo -ltai || exit 0 ) > tai.lib
+	rm -f tryltai.o tryltai
+
 tcp-env: \
 load tcp-env.o dns.o remoteinfo.o timeoutread.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 dns.lib socket.lib
+timeoutconn.o ip.o ipalloc.o strsalloc.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 \
-	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 \
+	timeoutwrite.o timeoutconn.o ip.o ipalloc.o strsalloc.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`
 
 tcp-env.0: \
@@ -2095,6 +2308,10 @@
 compile tcpto_clean.c tcpto.h open.h substdio.h readwrite.h
 	./compile tcpto_clean.c
 
+time.o: \
+compile time.c time.h stralloc.h gen_alloc.h fmt.h scan.h hastai.h
+	./compile time.c
+
 timeoutconn.o: \
 compile timeoutconn.c ndelay.h select.h error.h readwrite.h ip.h \
 byte.h timeoutconn.h
@@ -2108,6 +2325,19 @@
 compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
 	./compile timeoutwrite.c
 
+qmail-smtpd: tls.o ssl_timeoutio.o ndelay.a
+qmail-remote: tls.o ssl_timeoutio.o
+qmail-smtpd.o: tls.h ssl_timeoutio.h
+qmail-remote.o: tls.h ssl_timeoutio.h
+
+tls.o: \
+compile tls.c exit.h error.h
+	./compile tls.c
+
+ssl_timeoutio.o: \
+compile ssl_timeoutio.c ssl_timeoutio.h select.h error.h ndelay.h
+	./compile ssl_timeoutio.c
+
 token822.o: \
 compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
 gen_alloc.h gen_allocdefs.h
@@ -2139,3 +2369,26 @@
 wait_pid.o: \
 compile wait_pid.c error.h haswaitp.h
 	./compile wait_pid.c
+
+cert cert-req: \
+Makefile-cert
+	@$(MAKE) -sf $< $@
+
+Makefile-cert: \
+conf-qmail conf-users conf-groups Makefile-cert.mk
+	@cat Makefile-cert.mk \
+	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
+	> $@
+
+update_tmprsadh: \
+conf-qmail conf-users conf-groups update_tmprsadh.sh
+	@cat update_tmprsadh.sh\
+	| sed s}UGQMAILD}"`head -2 conf-users|tail -1`:`head -1 conf-groups`"}g \
+	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
+	> $@
+	chmod 755 update_tmprsadh 
+
+tmprsadh: \
+update_tmprsadh
+	echo "Creating new temporary RSA and DH parameters"
+	./update_tmprsadh
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/Makefile-cert.mk ./Makefile-cert.mk
--- ../../netqmail-1.05-orig/netqmail-1.05/Makefile-cert.mk	1969-12-31 16:00:00.000000000 -0800
+++ ./Makefile-cert.mk	2006-01-05 15:03:43.295249496 -0800
@@ -0,0 +1,21 @@
+cert-req: req.pem
+cert cert-req: QMAIL/control/clientcert.pem
+	@:
+
+QMAIL/control/clientcert.pem: QMAIL/control/servercert.pem
+	ln -s $< $@
+
+QMAIL/control/servercert.pem:
+	PATH=$$PATH:/usr/local/ssl/bin \
+		openssl req -new -x509 -nodes -days 366 -out $@ -keyout $@
+	chmod 640 $@
+	chown vpopmail:qmail $@
+
+req.pem:
+	PATH=$$PATH:/usr/local/ssl/bin openssl req \
+		-new -nodes -out $@ -keyout QMAIL/control/servercert.pem
+	chmod 640 QMAIL/control/servercert.pem
+	chown vpopmail:qmail QMAIL/control/servercert.pem
+	@echo
+	@echo "Send req.pem to your CA to obtain signed_req.pem, and do:"
+	@echo "cat signed_req.pem >> QMAIL/control/servercert.pem"
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/OTHERS.spamthrottle ./OTHERS.spamthrottle
--- ../../netqmail-1.05-orig/netqmail-1.05/OTHERS.spamthrottle	1969-12-31 16:00:00.000000000 -0800
+++ ./OTHERS.spamthrottle	2006-01-05 15:03:43.296249344 -0800
@@ -0,0 +1,20 @@
+There are other (slightly) similar ideas:
+
+1: tarpitting with qmail-smtpd (using qmail MTA):
+    http://www.palomine.net/qmail/tarpit.html
+
+2: teergrubing:
+    http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html
+
+3: "spam throttling content filter" for Stalker CommuniGate Pro mail server:
+    http://www.cse.fau.edu/~valankar/CG_spam_filter/README
+
+4: rate limiting by host (using exim MTA):
+    http://www.exim.org/exim-html-4.10/doc/html/spec_13.html#IX981
+
+5: "recipient limits"/"slowing down bad clients" (using postfix MTA):
+    http://www.postfix.org/rate.html#recipients
+    http://www.postfix.org/rate.html#slowdown
+
+
+If you have additions/notes for this list, please let us know.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/README.auth ./README.auth
--- ../../netqmail-1.05-orig/netqmail-1.05/README.auth	1969-12-31 16:00:00.000000000 -0800
+++ ./README.auth	2006-01-05 15:03:43.297249192 -0800
@@ -0,0 +1,66 @@
+README qmail-smtpd SMTP Authentication
+======================================
+
+
+History:
+--------
+
+This patch is based on Krzysztof Dabrowski's qmail-smtpd-auth-0.31 patch 
+which itself uses "Mrs. Brisby's" initial code. 
+Version 0.41 of this patch fixes the "CAPS-LOCK" typo announcing
+'CRAM_MD5' instead of 'CRAM-MD5' (german keyboard) - tx to Mike Garrison.
+Version 0.42 fixes the '421 unable to read controls (#4.3.0)' problem
+(can't read control/morercpthosts.cdb) because FD 3 was already closed - tx Richard Lyons.
+Version 0.43 fixes the ba64decode() failure in case CRAM_MD5 is not enabled - tx Vladimir Zidar.
+Version 0.51 includes the evaluation of the 'Auth' and the 'Size' parameter in the 'Mail From:' command.
+Version 0.52 uses DJB functions to copy FDs.
+Version 0.56 corrects some minor mistakes displaying the 'Auth' userid.
+Version 0.57 uses keyword "ESMTPA" in Received header in case of authentication to comply with RFC 3848.
+
+
+Scope:
+------
+
+This patch supports RFC 2554 "SMTP Service Extension for Authentication" for qmail-smtpd.
+Additionally, RFC 1870 is honoured ("SMTP Service Extension for Message Size Declaration").
+For more technical details see: http://www.fehcom.de/qmail/docu/smtpauth.html.
+
+
+Installation:
+-------------
+
+* Untar the source in the qmail-1.03 home direcotry.
+* Run ./install_auth.
+* Modify the compile time option "#define CRAM_MD5" to your needs.
+* Re-make qmail.
+
+
+Setup:
+------
+
+In order to use SMTP Authentication you have to use a 'Pluggable Authentication Module'
+PAM to be called by qmail-smtpd; typically
+
+	/var/qmail/bin/qmail-smtpd /bin/checkpassword true 2>&1
+
+Since qmail-smtpd does not run as root, checkpassword has to be made sticky.
+There is no need to include additionally the hostname in the call.
+In order to compute the CRAM-MD5 challenge, qmail-smtpd uses the 'tcplocalhost' information.
+
+
+Changes wrt. Krysztof Dabrowski's patch:
+----------------------------------------
+
+* Avoid the 'hostname' in the call of the PAM.
+* Confirm to Dan Bernstein's checkpassword interface even for CRAM-MD5.
+* Doesn't close FD 2; thus not inhibiting logging to STDERR.
+* Fixed bugs in base64.c.
+* Modified unconditional close of FD 3 in order to sustain reading of 'control/morecpthosts.cdb'.
+* Evaluation of the (informational) Mail From: < > Auth=username.
+* Additional support for the advertised "Size" via 'Mail From: <return-path> SIZE=123456780' (RFC 1870).
+* RFC 3848 conformance for Received header in case of SMTP Auth.
+
+
+Erwin Hoffmann - Cologne 2005-01-23 (www.fehcom.de)
+
+
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/README.qregex ./README.qregex
--- ../../netqmail-1.05-orig/netqmail-1.05/README.qregex	1969-12-31 16:00:00.000000000 -0800
+++ ./README.qregex	2006-01-05 15:03:43.299248888 -0800
@@ -0,0 +1,196 @@
+QREGEX (v2) 20040725 - README July 25, 2004
+A Regular Expression matching patch for qmail 1.03 and netqmail
+
+
+OVERVIEW:
+
+qregex adds the ability to match address evelopes via Regular Expressions (REs)
+in the qmail-smtpd process. It has the abiltiy to match `helo/ehlo` (host name),
+`mail from` (envelope sender), and `rcpt to` (envelope recipient) commands.
+It follows all the base rules that are set out with qmail (ie using control
+files) so it makes for easy integretion into an existing setup (see the
+install instructions for more info). The v2 is specified because qregex was
+re-written to better conform to the security guarantee set forth by the author
+of qmail. The original version used stdio.h and stdlib.h for reading the
+control files whereas v2 now uses all stralloc functions which are much more
+regulated against buffer overruns and the like.
+See: http://cr.yp.to/qmail/guarantee.html
+
+
+FEATURES:
+
+Features of qregex include:
+
+1. Performs pattern matching on envelope senders and envelope
+   recipients against REs in the badmailfrom and badmailto control
+   files. Two additional control files, badmailfromnorelay and
+   badmailtonorelay, are used for pattern matching when the 
+   RELAYCLIENT environment variable is not set.
+
+2. Performs pattern matching on the helo/ehlo host name. Setting the
+   NOBADHELO environment variable prevents the host name from being
+   compared to the patterns in the badhelo control file.
+
+3. Matches to patterns are logged
+
+4. Matching is case insensitive.
+
+5. qregex ignores empty envelope senders. An empty envelope sender is not
+   compared to the patterns in the badmailfrom and badmailfromnorelay
+   control files and is always accepted.
+
+
+PLATFORMS:
+
+qregex has been built and tested on the following platforms. I'm sure it won't
+have any problems on any platform that qmail will run on (providing they have
+a regex interface) but if you run into problems let me know.
+
+	- OpenBSD 3.x
+	- FreeBSD 4.x
+	- Mandrake Linux 9.x
+	- SuSE Linux 8.x
+
+
+
+INSTALLATION INSTRUCTIONS:
+
+Installation is very simple, there is only one requirement. You need to use the
+GNU version of the patch utility (http://www.gnu.org/software/patch/patch.html).
+(For Solaris 8 users it is installed as 'gpatch')
+
+- If this is a new setup.
+Unpack the qmail archive, cd into the qmail-1.03 directory and run
+"patch < /path/to/qregex-<version>.patch". Follow the instructions as per the
+included qmail INSTALL file. Once you are done come back to this file and read
+the section on the control files.
+
+If you are using netqmail, then unpack the netqmail archive. Run the collate.sh
+script and cd into the resulting netqmail-<version> directory. From there, run
+"patch < /path/to/qregex-<version>.patch". Complete the netqmail installation
+normally. Once you are done, come back to this file and read the section on the
+control files.
+
+- If this is an existing setup.
+FIRST: create your control files (see below).
+cd into your existing qmail or netqmail source directory. Run
+"patch < /path/to/qregex-<version>.patch" then "make qmail-smtpd". Now run
+./qmail-smtpd and test your new rules to make sure they work as expected.
+
+Install the new binary by cd'ing to /var/qmail/bin and as root (in one command)
+copy the existing binary to 'qmail-smtpd.old' and copy the new binary from the
+source directory to 'qmail-smtpd'.
+(ex. cp qmail-smtpd qmail-smtpd.old && cp ~/qmail-1.03/qmail-smtpd qmail-smtpd)
+
+You can also optionally just run "make setup check" as it will install the
+updated documentation and man pages provided with this patch. Stopping qmail
+before doing the "make setup check" is always a good idea.
+
+
+LOGGING:
+
+qregex will log matches to the patterns in the various control files. Log
+messages will take these three forms depending on which control file was
+matched:
+
+badhelo
+qmail-smtpd: badhelo: <host> at <remote IP>
+
+badmailfrom and badmailfromnorelay
+qmail-smtpd: badmailfrom: <sender address> at <remote IP>
+
+badmailto and badmailtonorelay
+qmail-smtpd: badmailto: <rcpt address> at <remote IP>
+
+
+CONTROL FILES:
+
+qregex provides you with five control files. None of these control files
+is mandatory and you can use them in any combination you choose in your setup.
+
+The "control/badmailfrom" and "control/badmailto" files contain your REs for
+matching against the 'mail from' (envelope sender) and 'rcpt to' (envelope
+recipient) smtp commands respectively.
+The "control/badmailfromnorelay" and "control/badmailtonorelay" match against
+the same commands but are read only when the RELAYCLIENT environment variable
+is not set.
+The "control/badhelo" file matches against the 'helo/ehlo' smtp command.
+
+If you prefer you can symlink the badmailfrom and badmailto control files
+(ln -s badmailfrom badmailto) and maintain fewer sets of rules. Beware
+this might cause problems in certain setups.
+        
+	Here's an example "badhelo" file.
+	-----------------------------------
+	# block host strings with no dot (not a FQDN)
+	!\.
+	-----------------------------------
+	
+	An example "badmailfrom" file.
+	-----------------------------------
+	# this will drop everything containing the string
+	# bad.domain.com or Bad.Domain.Com or BAD.domain.COM
+	bad\.domain\.com
+	# force users to fully qualify themselves
+	# (i.e. deny "user", accept "user@domain")
+	!@
+	-----------------------------------
+
+	And "badmailto" (a little more interesting)
+	-----------------------------------
+	# must not contain invalid characters, brakets or multiple @'s
+	[!%#:*^(){}]
+	@.*@
+	-----------------------------------
+
+You can use the non-RE character '!' to start an RE as a signal to qregex to
+negate the action. As used above in the badmailfrom file, by negating the '@'
+symbol qregex will signal qmail-smtpd to deny the 'mail from' command whenever
+the address doesn't contain an @ symbol. When used inside a bracket expression,
+the '!' character looses this special meaning. This is shown in the badmailto
+example.
+
+The norelay control files follow the same rules as the other control files but
+are intended to address two specific scenarios.
+The badmailfromnorelay file can be used to block mail trying to spoof a domain
+hosted on your mail server. It prevents a mail client that is not allowed to
+relay email through your server from using one of your hosted domains as its
+envelope sender.
+The badmailtonorelay file can be used to create email addresses that cannot
+receive mail from any source not allowed to relay email through your server.
+This is handy for creating email addresses for use only within your own 
+domain(s) that can't receive spam from the world at large.
+
+
+INTERNALS:
+
+qregex (or regexmatch as the function is called) will be called during the
+`helo/ehlo`, `rcpt to` and `mail from` handling routines in "qmail-smtpd.c".
+When called, it will read the proper control file then one by one compile and
+execute the regex on the string passed into qmail-smtpd. If the regex matches
+it returns TRUE (1) and the qmail-smtpd process will deny the user the ability
+to continue. If you change anything and think it betters this patch please
+send me a new diff file so I can take a peek.
+
+
+CONTACT:
+qregex is maintained by:
+	Andrew St. Jean
+	andrew@arda.homeunix.net
+	www.arda.homeunix.net/store/qmail/
+
+Contributers to qregex:
+	Jeremy Kitchen	
+	kitchen at scriptkitchen dot com
+	http://www.scriptkitchen.com/qmail
+
+	Alex Pleiner
+	alex@zeitform.de
+	zeitform Internet Dienste
+	http://www.zeitform.de/
+
+	Thanos Massias
+
+Original qregex patch written by:
+	Evan Borgstrom
+	evan at unixpimps dot org
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/README.spamthrottle ./README.spamthrottle
--- ../../netqmail-1.05-orig/netqmail-1.05/README.spamthrottle	1969-12-31 16:00:00.000000000 -0800
+++ ./README.spamthrottle	2006-01-05 15:03:43.300248736 -0800
@@ -0,0 +1,21 @@
+qmail-spamthrottle 2.01
+20021225
+Copyright 2001,2002
+D. Woolridge
+J. Law
+M. Kawasaki
+
+Contact the authors via email: <spamthrottle@qmail.ca>
+
+Man pages have been updated with spamthrottle documentation:
+  qmail-smtpd(8)		(file qmail-smtpd.8)
+  qmail-control(5)		(file qmail-control.9)
+  qmail-spamt(5)		(file qmail-spamt.9) ** new **
+  qmail-spamthrottle(5)		(file qmail-spamthrottle.9) ** new **
+  qmail-newst(8)		(file qmail-newst.9) ** new **
+
+This patch uses subsecond precision calculations.  Use of libtai
+(http://cr.yp.to/libtai.html) is recommended, but not required.
+If you choose to use libtai, we suggest version 0.60 since this patch
+has been tested with it.  Use of libtai is automatic when it is
+available (for inclusion and linking).
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/TARGETS ./TARGETS
--- ../../netqmail-1.05-orig/netqmail-1.05/TARGETS	1998-06-15 03:53:16.000000000 -0700
+++ ./TARGETS	2006-01-05 15:03:43.301248584 -0800
@@ -10,11 +10,20 @@
 qmail.o
 quote.o
 now.o
+base64.o
 gfrom.o
 myctime.o
 slurpclose.o
 make-makelib
 makelib
+maildirflags.o
+maildirparsequota.o
+maildiropen.o
+maildirgetquota.o
+maildirquota.o
+overmaildirquota.o
+strtimet.o
+strpidt.o
 case_diffb.o
 case_diffs.o
 case_lowerb.o
@@ -100,11 +109,14 @@
 str_diff.o
 str_diffn.o
 str_cpy.o
+str_cpyb.o
 str_chr.o
 str_rchr.o
 str_start.o
 byte_chr.o
 byte_rchr.o
+byte_cspn.o
+byte_rcspn.o
 byte_diff.o
 byte_copy.o
 byte_cr.o
@@ -168,11 +180,15 @@
 constmap.o
 timeoutread.o
 timeoutwrite.o
+tls.o
+ssl_timeoutio.o
 timeoutconn.o
 tcpto.o
 dns.o
+spf.o
 ip.o
 ipalloc.o
+strsalloc.o
 hassalen.h
 ipme.o
 ndelay.o
@@ -212,6 +228,9 @@
 headerbody.o
 hfield.o
 token822.o
+spf.o
+spfquery.o
+spfquery
 qmail-inject
 predate.o
 predate
@@ -252,6 +271,7 @@
 qmail-qmtpd
 qmail-smtpd.o
 qmail-smtpd
+qregex.o
 sendmail.o
 sendmail
 tcp-env.o
@@ -270,6 +290,8 @@
 dnsip
 dnsmxip.o
 dnsmxip
+dnstxt.o
+dnstxt
 dnsfq.o
 dnsfq
 hostname.o
@@ -320,6 +342,7 @@
 binm2+df
 binm3
 binm3+df
+Makefile-cert
 it
 qmail-local.0
 qmail-lspawn.0
@@ -385,3 +408,24 @@
 man
 setup
 check
+update_tmprsadh
+spam.o
+spam_get.o
+open_rw.o
+lock_exfcntl.o
+lock_unfcntl.o
+fmt_2long.o
+fmt_2long0.o
+fmt_ulong0.o
+scan_2long.o
+control_time.o
+hastai.h
+time.o
+tai.lib
+qmail-newst.o
+qmail-newst
+qmail-spamt.5
+qmail-spamt.0
+qmail-spamthrottle.5
+qmail-spamthrottle.0
+chkuser.o
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/auth.log ./auth.log
--- ../../netqmail-1.05-orig/netqmail-1.05/auth.log	1969-12-31 16:00:00.000000000 -0800
+++ ./auth.log	2006-01-05 15:03:43.302248432 -0800
@@ -0,0 +1,22 @@
+Installing qmail-smtpd AUTH 056 (Build 2004272152823) at Thu Nov 11 14:31:44 PST 2004 <<<
+Targeting file TARGETS ...
+--> TARGETS copied to TARGETS.056
+--> Patching qmail source file TARGETS  ....
+patching file TARGETS
+Targeting file Makefile ...
+--> Makefile copied to Makefile.056
+--> Patching qmail source file Makefile  ....
+patching file Makefile
+Targeting file qmail-smtpd.c ...
+--> qmail-smtpd.c copied to qmail-smtpd.c.056
+--> Patching qmail source file qmail-smtpd.c  ....
+patching file qmail-smtpd.c
+Hunk #2 succeeded at 53 with fuzz 1.
+Hunk #3 succeeded at 64 with fuzz 1.
+Hunk #6 succeeded at 305 with fuzz 1.
+Targeting file qmail-smtpd.8 ...
+--> qmail-smtpd.8 copied to qmail-smtpd.8.056
+--> Patching qmail source file qmail-smtpd.8  ....
+patching file qmail-smtpd.8
+Copying documentation and samples to /var/qmail/doc/ ...
+Installation of qmail-smtpd AUTH 056 (Build 2004272152823) finished at Thu Nov 11 14:31:44 PST 2004 <<<
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/base64.c ./base64.c
--- ../../netqmail-1.05-orig/netqmail-1.05/base64.c	1969-12-31 16:00:00.000000000 -0800
+++ ./base64.c	2006-01-05 15:03:43.303248280 -0800
@@ -0,0 +1,122 @@
+#include "base64.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "str.h"
+
+static char *b64alpha =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#define B64PAD '='
+
+/* returns 0 ok, 1 illegal, -1 problem */
+
+int b64decode(in,l,out)
+const unsigned char *in;
+int l;
+stralloc *out; /* not null terminated */
+{
+  int p = 0;
+  int n;
+  unsigned int x;
+  int i, j;
+  char *s;
+  unsigned char b[3];
+
+  if (l == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  while(in[l-1] == B64PAD) {
+    p ++;
+    l--;
+  }
+
+  n = (l + p) / 4;
+  out->len = (n * 3) - p;
+  if (!stralloc_ready(out,out->len)) return -1;
+  s = out->s;
+
+  for(i = 0; i < n - 1 ; i++) {
+    x = 0;
+    for(j = 0; j < 4; j++) {
+      if(in[j] >= 'A' && in[j] <= 'Z')
+        x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+      else if(in[j] >= 'a' && in[j] <= 'z')
+        x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+      else if(in[j] >= '0' && in[j] <= '9')
+        x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+      else if(in[j] == '+')
+        x = (x << 6) + 62;
+      else if(in[j] == '/')
+        x = (x << 6) + 63;
+      else if(in[j] == '=')
+        x = (x << 6);
+    }
+
+    s[2] = (unsigned char)(x & 255); x >>= 8;
+    s[1] = (unsigned char)(x & 255); x >>= 8;
+    s[0] = (unsigned char)(x & 255); x >>= 8;
+    s += 3; in += 4;
+  }
+
+  x = 0;
+  for(j = 0; j < 4; j++) {
+    if(in[j] >= 'A' && in[j] <= 'Z')
+      x = (x << 6) + (unsigned int)(in[j] - 'A' + 0);
+    else if(in[j] >= 'a' && in[j] <= 'z')
+      x = (x << 6) + (unsigned int)(in[j] - 'a' + 26);
+    else if(in[j] >= '0' && in[j] <= '9')
+      x = (x << 6) + (unsigned int)(in[j] - '0' + 52);
+    else if(in[j] == '+')
+      x = (x << 6) + 62;
+    else if(in[j] == '/')
+      x = (x << 6) + 63;
+    else if(in[j] == '=')
+      x = (x << 6);
+  }
+
+  b[2] = (unsigned char)(x & 255); x >>= 8;
+  b[1] = (unsigned char)(x & 255); x >>= 8;
+  b[0] = (unsigned char)(x & 255); x >>= 8;
+
+  for(i = 0; i < 3 - p; i++)
+    s[i] = b[i];
+
+  return 0;
+}
+
+int b64encode(in,out)
+stralloc *in;
+stralloc *out; /* not null terminated */
+{
+  unsigned char a, b, c;
+  int i;
+  char *s;
+
+  if (in->len == 0)
+  {
+    if (!stralloc_copys(out,"")) return -1;
+    return 0;
+  }
+
+  if (!stralloc_ready(out,in->len / 3 * 4 + 4)) return -1;
+  s = out->s;
+
+  for (i = 0;i < in->len;i += 3) {
+    a = in->s[i];
+    b = i + 1 < in->len ? in->s[i + 1] : 0;
+    c = i + 2 < in->len ? in->s[i + 2] : 0;
+
+    *s++ = b64alpha[a >> 2];
+    *s++ = b64alpha[((a & 3 ) << 4) | (b >> 4)];
+
+    if (i + 1 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[((b & 15) << 2) | (c >> 6)];
+
+    if (i + 2 >= in->len) *s++ = B64PAD;
+    else *s++ = b64alpha[c & 63];
+  }
+  out->len = s - out->s;
+  return 0;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/base64.h ./base64.h
--- ../../netqmail-1.05-orig/netqmail-1.05/base64.h	1969-12-31 16:00:00.000000000 -0800
+++ ./base64.h	2006-01-05 15:03:43.304248128 -0800
@@ -0,0 +1,7 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern int b64decode();
+extern int b64encode();
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/byte.h ./byte.h
--- ../../netqmail-1.05-orig/netqmail-1.05/byte.h	1998-06-15 03:53:16.000000000 -0700
+++ ./byte.h	2006-01-05 15:03:43.305247976 -0800
@@ -3,6 +3,8 @@
 
 extern unsigned int byte_chr();
 extern unsigned int byte_rchr();
+extern unsigned int byte_cspn();
+extern unsigned int byte_rcspn();
 extern void byte_copy();
 extern void byte_copyr();
 extern int byte_diff();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/byte_cspn.c ./byte_cspn.c
--- ../../netqmail-1.05-orig/netqmail-1.05/byte_cspn.c	1969-12-31 16:00:00.000000000 -0800
+++ ./byte_cspn.c	2006-01-05 15:03:43.306247824 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/byte_rcspn.c ./byte_rcspn.c
--- ../../netqmail-1.05-orig/netqmail-1.05/byte_rcspn.c	1969-12-31 16:00:00.000000000 -0800
+++ ./byte_rcspn.c	2006-01-05 15:03:43.307247672 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/case_startb.c ./case_startb.c
--- ../../netqmail-1.05-orig/netqmail-1.05/case_startb.c	1969-12-31 16:00:00.000000000 -0800
+++ ./case_startb.c	2006-01-05 15:03:43.308247520 -0800
@@ -0,0 +1,21 @@
+#include "case.h"
+
+int case_startb(s,len,t)
+register char *s;
+unsigned int len;
+register char *t;
+{
+  register unsigned char x;
+  register unsigned char y;
+
+  for (;;) {
+    y = *t++ - 'A';
+    if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+    if (!y) return 1;
+    if (!len) return 0;
+    --len;
+    x = *s++ - 'A';
+    if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
+    if (x != y) return 0;
+  }
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/chkspawn.c ./chkspawn.c
--- ../../netqmail-1.05-orig/netqmail-1.05/chkspawn.c	1998-06-15 03:53:16.000000000 -0700
+++ ./chkspawn.c	2006-01-05 15:03:43.309247368 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/chkuser.c ./chkuser.c
--- ../../netqmail-1.05-orig/netqmail-1.05/chkuser.c	1969-12-31 16:00:00.000000000 -0800
+++ ./chkuser.c	2006-01-05 15:03:43.314246608 -0800
@@ -0,0 +1,1156 @@
+
+/*
+ *
+ * 'chkuser.c' v.2.0.8
+ * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x
+ *
+ * Author: Antonio Nati tonix@interazioni.it
+ * All rights on this software and
+ * the identifying words chkusr and chkuser kept by the author
+ *
+ * This software may be freely used, modified and distributed,
+ * but this lines must be kept in every original or derived version.
+ * Original author "Antonio Nati" and the web URL
+ * "http://www.interazioni.it/opensource"
+ * must be indicated in every related work or web page
+ *
+ */
+
+#include <pwd.h>
+
+/* required by vpopmail */
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dns.h"
+#include "env.h"
+#include "ipme.h"
+#include "now.h"
+#include "open.h"
+#include "subfd.h"
+#include "substdio.h"
+#include "stralloc.h"
+
+#include "vpopmail.h"
+#include "vauth.h"
+#include "vpopmail_config.h"
+
+#include "chkuser.h"
+#include "chkuser_settings.h"
+
+#if defined _exit
+#undef _exit
+#endif
+
+extern void flush();
+extern void out (char *s);
+
+extern char *remotehost;
+extern char *remoteip;
+extern char *remoteinfo;
+extern char *relayclient;
+extern char *fakehelo;
+
+extern void die_nomem();
+
+#define DIE_NOMEM() die_nomem()
+
+#if defined CHKUSER_DEBUG
+
+#if defined CHKUSER_DEBUG_STDERR
+
+#define CHKUSER_DBG(a) write (STDERR_FILENO, a, strlen (a))
+#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDERR_FILENO, str, strlen (str));}
+
+#else
+
+#define CHKUSER_DBG(a) write (STDOUT_FILENO, a, strlen (a))
+#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDOUT_FILENO, str, strlen (str));}
+
+#endif
+#else
+
+#define CHKUSER_DBG(a) /* DBG dummy */
+#define CHKUSER_DBG_INT(a) /* DBG dummy */
+
+#endif
+
+static int INTRUSION_threshold_reached = 0;
+static int first_time_init_flag = 1;
+
+static int recipients = 0;
+static int wrong_recipients = 0;
+
+static stralloc user = {0};
+static stralloc domain = {0};
+static stralloc domain_path = {0};
+static stralloc tmp_path = {0};
+static stralloc alias_path = {0};
+
+#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE
+ static char *identify_remote;
+#endif
+
+#if defined CHKUSER_ENABLE_EXTENSIONS
+#define CHKUSER_ENABLE_USERS_EXTENSIONS
+#endif
+
+#if defined CHKUSER_ENABLE_LISTS
+#define CHKUSER_ENABLE_EZMLM_LISTS
+#endif
+
+#if defined CHKUSER_EXTENSION_DASH
+#define CHKUSER_USERS_DASH CHKUSER_EXTENSION_DASH
+#endif
+
+
+#if defined CHKUSER_ENABLE_VAUTH_OPEN
+ static int db_already_open = 0;
+#endif
+
+#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE
+  static char *starting_string = 0;
+  static int starting_value = -1;
+#endif
+
+#if defined CHKUSER_RCPT_LIMIT_VARIABLE
+  static char *maxrcpt_string = 0;
+  static int maxrcpt_limit = 0;
+  static int maxrcpt_limit_reached = 0;
+#endif
+
+#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE
+  static char *maxwrongrcpt_string = 0;
+  static int maxwrongrcpt_limit = 0;
+  static int maxwrongrcpt_limit_reached = 0;
+#endif
+
+#if defined CHKUSER_MBXQUOTA_VARIABLE
+  static char *maxmbxquota_string = 0;
+  static int maxmbxquota_limit = 0;
+#endif
+
+#if defined CHKUSER_SENDER_NOCHECK_VARIABLE
+
+  static unsigned int sender_nocheck = 0;
+
+#endif
+
+#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX
+static stralloc sender_user = {0};
+static stralloc sender_domain = {0};
+#endif
+
+
+#if defined CHKUSER_ERROR_DELAY
+
+  static int chkuser_delay_interval = CHKUSER_ERROR_DELAY * 1000;
+
+#define CHKUSER_DELAY()	chkuser_delay()
+
+void chkuser_delay (void) {
+
+        usleep (chkuser_delay_interval);
+
+#if defined CHKUSER_ERROR_DELAY_INCREASE
+        chkuser_delay_interval += CHKUSER_ERROR_DELAY_INCREASE * 1000;
+#endif
+}
+
+#if defined CHKUSER_RCPT_DELAY_ANYERROR
+#define CHKUSER_RCPT_DELAY_ANY() chkuser_delay()
+#else
+#define CHKUSER_RCPT_DELAY_ANY() /* no delay for any error */
+#endif
+
+#if defined CHKUSER_SENDER_DELAY_ANYERROR
+#define CHKUSER_SENDER_DELAY_ANY() chkuser_delay()
+#else
+#define CHKUSER_SENDER_DELAY_ANY() /* no delay for any error */
+#endif
+
+
+#else
+#define CHKUSER_DELAY() /* no delay */
+#define CHKUSER_RCPT_DELAY_ANY() /* no delay */
+#define CHKUSER_SENDER_DELAY_ANY() /* no delay */
+#endif
+
+#if defined CHKUSER_ENABLE_LOGGING
+
+static stralloc logstr = { 0 };
+
+static void chkuser_commonlog (char *sender, char *rcpt, char *title, char *description) {
+
+  substdio_puts (subfderr, "CHKUSER ");
+  substdio_puts (subfderr, title);
+  substdio_puts (subfderr, ": from <");
+  substdio_puts (subfderr, sender);
+  substdio_puts (subfderr, ":" );
+  if (remoteinfo) {
+	substdio_puts (subfderr, remoteinfo);
+  }
+  substdio_puts (subfderr, ":" );
+#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE
+  if (identify_remote) substdio_puts (subfderr, identify_remote);
+#endif
+  substdio_puts (subfderr, "> remote <");
+  if (fakehelo) substdio_puts (subfderr, fakehelo);
+  substdio_puts (subfderr, ":" );
+  if (remotehost) substdio_puts (subfderr, remotehost);
+  substdio_puts (subfderr, ":" );
+  if (remoteip) substdio_puts (subfderr, remoteip);
+  substdio_puts (subfderr, "> rcpt <");
+  substdio_puts (subfderr, rcpt);
+  substdio_puts (subfderr, "> : ");
+  substdio_puts (subfderr, description);
+  substdio_puts (subfderr, "\n");
+  substdio_flush (subfderr);
+}
+
+#else
+#define chkuser_commonlog(a,b,c,d) /* no log */
+#endif
+
+#if defined CHKUSER_SENDER_FORMAT
+
+static int check_sender_address_format (stralloc *user, stralloc *domain) {
+
+        int x;
+
+        for (x = 0; x < (user->len -1); ++x) {
+                if ((!isalnum (user->s[x])) 
+
+#if defined CHKUSER_ALLOW_SENDER_SRS
+		&& (user->s[x] != '#')
+		&& (user->s[x] != '+')
+#endif
+#if defined CHKUSER_ALLOW_SENDER_CHAR_1
+		&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_1)
+#endif
+#if defined CHKUSER_ALLOW_SENDER_CHAR_2
+		&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_2)
+#endif
+#if defined CHKUSER_ALLOW_SENDER_CHAR_3
+		&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_3)
+#endif
+#if defined CHKUSER_ALLOW_SENDER_CHAR_4
+		&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_4)
+#endif
+#if defined CHKUSER_ALLOW_SENDER_CHAR_5
+		&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_5)
+#endif
+		&& (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) {
+                        return 0;
+                }
+        }
+
+/*
+ * Be careful, this is a base check
+ *      Minimum is x.xx + ending \0
+ *      Minimum characters needed are 5
+ */
+#if defined CHKUSER_MIN_DOMAIN_LEN
+        if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) {
+                return 0;
+        }
+#endif
+
+/*
+ *      This is a safety check
+ */
+#if defined CHKUSER_MIN_DOMAIN_LEN
+        if (domain->len < 2) {
+                return 0;
+        }
+#endif
+
+        for (x = 0; x < (domain->len -1); ++x) {
+                if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) {
+                        return 0;
+                }
+        }
+
+        if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) {
+                return 0;
+        }
+        if (strstr (domain->s, "..") != NULL) {
+                return 0;
+        }
+	if (strncmp (domain->s, "xn--", 4) == 0) {
+		if (strstr (&domain->s[4], "--") != NULL)
+			return 0;
+	} else {
+		if (strstr (domain->s, "--") != NULL)
+			return 0;
+	}
+        if (strstr (domain->s, ".-") != NULL) {
+                return 0;
+        }
+        if (strstr (domain->s, "-.") != NULL) {
+                return 0;
+        }
+        if (strchr (domain->s, '.') == NULL) {
+                return 0;
+        }
+
+        return 1;
+}
+
+#endif
+
+#if defined CHKUSER_RCPT_FORMAT
+
+static int check_rcpt_address_format (stralloc *user, stralloc *domain) {
+
+        int x;
+
+        for (x = 0; x < (user->len -1); ++x) {
+                if ((!isalnum (user->s[x])) 
+#if defined CHKUSER_ALLOW_RCPT_SRS
+                && (user->s[x] != '#')
+                && (user->s[x] != '+')
+#endif
+#if defined CHKUSER_ALLOW_RCPT_CHAR_1
+                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_1)
+#endif
+#if defined CHKUSER_ALLOW_RCPT_CHAR_2
+                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_2)
+#endif
+#if defined CHKUSER_ALLOW_RCPT_CHAR_3
+                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_3)
+#endif
+#if defined CHKUSER_ALLOW_RCPT_CHAR_4
+                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_4)
+#endif
+#if defined CHKUSER_ALLOW_RCPT_CHAR_5
+                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_5)
+#endif
+
+		&& (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) {
+                        return 0;
+                }
+        }
+
+/*
+ * Be careful, this is a base check
+ *      Minimum is x.xx + ending \0
+ *      Minimum characters needed are 5
+ */
+#if defined CHKUSER_MIN_DOMAIN_LEN
+        if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) {
+                return 0;
+        }
+#endif
+
+/*
+ *      This is a safety check
+ */
+#if defined CHKUSER_MIN_DOMAIN_LEN
+        if (domain->len < 2) {
+                return 0;
+        }
+#endif
+        for (x = 0; x < (domain->len -1); ++x) {
+                if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) {
+                        return 0;
+                }
+        }
+
+        if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) {
+                return 0;
+        }
+        if (strstr (domain->s, "..") != NULL) {
+                return 0;
+        }
+	if (strncmp (domain->s, "xn--", 4) == 0) {
+		if (strstr (&domain->s[4], "--") != NULL)
+			return 0;
+	} else {
+		if (strstr (domain->s, "--") != NULL)
+			return 0;
+	}
+        if (strstr (domain->s, ".-") != NULL) {
+                return 0;
+        }
+        if (strstr (domain->s, "-.") != NULL) {
+                return 0;
+        }
+        if (strchr (domain->s, '.') == NULL) {
+                return 0;
+        }
+
+        return 1;
+}
+
+#endif
+
+#if defined CHKUSER_SENDER_MX || defined CHKUSER_RCPT_MX
+
+static   unsigned long mx_random;
+static  ipalloc mx_ip = {0};
+
+static int chkuser_mx_lookup (stralloc *domain) {
+
+  int status;
+
+	mx_random = now() + getpid();
+	dns_init(0);
+	status = dns_mxip (&mx_ip, domain, mx_random);
+
+	if (status == DNS_MEM) DIE_NOMEM();
+
+	return status;
+}
+
+#endif
+
+
+void chkuser_cleanup (int exit_value) {
+
+#if defined CHKUSER_DB_CLEANUP
+	vclose ();
+#endif
+	_exit (exit_value);
+}
+
+static void first_time_init (void) {
+
+  char * temp_string;
+
+#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE
+        starting_string = env_get (CHKUSER_STARTING_VARIABLE);
+        if (starting_string) {
+                if (strcasecmp(starting_string, "ALWAYS") == 0) {
+                        starting_value = 1;
+                } else if (strcasecmp(starting_string, "DOMAIN") == 0) {
+                        starting_value = 0;
+                }
+        } else {
+                starting_string = "";
+        }
+#endif
+
+#if defined CHKUSER_RCPT_LIMIT_VARIABLE
+        maxrcpt_string = env_get (CHKUSER_RCPT_LIMIT_VARIABLE);
+        if (maxrcpt_string) {
+                maxrcpt_limit = atoi (maxrcpt_string);
+                if (maxrcpt_limit < 1) {
+                        maxrcpt_limit = 0;
+                }
+        } else {
+                maxrcpt_string = "";;
+        }
+#endif
+
+#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE
+        maxwrongrcpt_string = env_get (CHKUSER_WRONGRCPT_LIMIT_VARIABLE);
+        if (maxwrongrcpt_string) {
+                maxwrongrcpt_limit = atoi (maxwrongrcpt_string);
+                if (maxwrongrcpt_limit < 1) {
+                        maxwrongrcpt_limit = 0;
+                }
+        } else {
+                maxwrongrcpt_string = "";
+        }
+#endif
+
+#if defined CHKUSER_MBXQUOTA_VARIABLE
+        maxmbxquota_string = env_get (CHKUSER_MBXQUOTA_VARIABLE);
+        if (maxmbxquota_string) {
+                maxmbxquota_limit = atoi (maxmbxquota_string);
+                if (maxmbxquota_limit < 1) {
+                	maxmbxquota_limit = 0;
+                }
+	} else {
+               	maxmbxquota_string = "";
+	}
+#endif
+
+#if defined CHKUSER_SENDER_NOCHECK_VARIABLE
+
+        temp_string = env_get (CHKUSER_SENDER_NOCHECK_VARIABLE);
+        if (temp_string) {
+		sender_nocheck = 1;
+        } else {
+		sender_nocheck = 0;
+        }
+
+#endif
+
+#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE
+
+        identify_remote = env_get (CHKUSER_IDENTIFY_REMOTE_VARIABLE);
+        if (identify_remote) {
+        }
+
+#endif
+
+        if (!stralloc_ready (&user, 300)) DIE_NOMEM();
+        if (!stralloc_ready (&domain, 500)) DIE_NOMEM();
+        if (!stralloc_ready (&domain_path, 1000)) DIE_NOMEM();
+        if (!stralloc_ready (&tmp_path, 1000)) DIE_NOMEM();
+        if (!stralloc_ready (&alias_path, 1000)) DIE_NOMEM();
+
+	first_time_init_flag = 0;
+
+}
+
+/*
+ * realrcpt ()
+ *
+ * Returns:
+ *
+ *	CHKUSER_OK = 1 = Ok, recipients does exists
+ *
+ *	0 = Not in rcpthosts
+ *
+ *	< 0 various errors
+ *
+ *
+ * Parameters:
+ *	stralloc *sender = sender address
+ *	stralloc *rcpt = rcpt address to check
+ *
+ *
+*/
+
+static int realrcpt (stralloc *sender, stralloc *rcpt)
+{
+  int count;
+  int retstat = CHKUSER_KO;
+  struct vqpasswd *user_passwd = NULL;
+  int fd_file = -1;
+  int read_char;
+  int offset;
+  char read_buf[1024];
+
+#if defined CHKUSER_ENABLE_UIDGID
+  uid_t eff_uid;
+  gid_t eff_gid;
+#endif
+
+#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE
+  if (starting_value == -1) {
+                if (addrallowed()) {
+                        return CHKUSER_OK;
+                } else {
+                        if (relayclient) {
+                                return CHKUSER_RELAYING;
+                        }
+
+			return CHKUSER_NORCPTHOSTS;
+		}
+  }
+#endif
+
+  if (INTRUSION_threshold_reached == 1) {
+	return CHKUSER_ERR_INTRUSION_THRESHOLD;
+  }
+
+#if defined CHKUSER_RCPT_LIMIT_VARIABLE
+
+  ++recipients;
+  if ((maxrcpt_limit > 0) && (recipients >= maxrcpt_limit)) {
+	chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed rcpt");
+	INTRUSION_threshold_reached = 1;
+        return CHKUSER_ERR_MAXRCPT;
+  }
+#endif
+
+/* Search the '@' character */
+  count = byte_rchr(rcpt->s,rcpt->len,'@');
+
+  if (count < rcpt->len) {
+    if (!stralloc_copyb (&user, rcpt->s, count)) DIE_NOMEM();
+    if (!stralloc_copys (&domain, rcpt->s + count + 1)) DIE_NOMEM();
+  }
+  else {
+    if (!stralloc_copys (&user, rcpt->s)) DIE_NOMEM();
+    domain.len = 0;
+  }
+  if (!stralloc_0 (&user)) DIE_NOMEM();
+  if (!stralloc_0 (&domain)) DIE_NOMEM();
+
+#if defined CHKUSER_ENABLE_UIDGID
+
+/* qmail-smtpd is running now as (effective) qmaild:nofiles */
+/* Save the effective UID & GID (qmaild:nofiles) */
+  eff_uid = geteuid ();
+  eff_gid = getegid ();
+
+/* Now set new effective UID & GID, getting it from real UID & GID (vpopmail:vchkpw) */
+  setegid (getgid());
+  seteuid (getuid());
+
+/* qmail-smtpd is running now as effective vpopmail:vchkpw */
+#endif
+
+
+/*
+ * 
+ * Now let's start the test/setting suite
+ *
+ **/
+
+	switch (0) {
+
+	case 0:
+/* These are some preliminary settings */
+  		case_lowers (user.s);
+  		case_lowers (domain.s);
+
+	case 1:
+
+                if (domain.len == 1) {
+#if defined CHKUSER_DOMAIN_WANTED
+                        retstat = CHKUSER_ERR_DOMAIN_MISSING;
+			break;
+#else
+                        if (!stralloc_copys (&domain, DEFAULT_DOMAIN)) DIE_NOMEM();
+  			if (!stralloc_0 (&domain)) DIE_NOMEM();
+#endif
+                }
+
+	case 2:
+
+#if defined CHKUSER_RCPT_FORMAT
+
+                if (check_rcpt_address_format (&user, &domain) == 0) {
+                        retstat = CHKUSER_ERR_RCPT_FORMAT;
+                        break;
+                }
+#endif
+
+	case 3:
+
+                if (!addrallowed()) {
+
+#if defined CHKUSER_RCPT_MX
+			switch (chkuser_mx_lookup(&domain)) {
+
+				case DNS_HARD:
+					retstat = CHKUSER_ERR_RCPT_MX;
+					break;
+
+				case DNS_SOFT:
+					retstat = CHKUSER_ERR_RCPT_MX_TMP;
+					break;
+			}
+
+			if (retstat != CHKUSER_KO) {
+				break;
+			}
+#endif
+
+  			if (relayclient) {
+				retstat = CHKUSER_RELAYING;
+				break;
+  			}
+
+                        retstat = CHKUSER_NORCPTHOSTS;
+                        break;
+                }
+
+	case 4:
+
+#if defined CHKUSER_ENABLE_VAUTH_OPEN
+                if (db_already_open != 1) {
+                        if (vauth_open () == 0) {
+                                db_already_open == 1;
+                        } else {
+                                retstat = CHKUSER_ERR_AUTH_RESOURCE;
+                        }
+                };
+#endif
+
+	case 5:
+
+#if defined CHKUSER_ENABLE_VGET_REAL_DOMAIN
+/* Check if domain is a real domain */
+
+                vget_real_domain(domain.s, domain.a);
+
+                domain.len = strlen (domain.s) +1;
+                if (domain.len > (domain.a - 1)) DIE_NOMEM();
+#endif
+
+/* Let's get domain's real path */
+                if (vget_assign(domain.s, domain_path.s, domain_path.a -1, NULL, NULL) == NULL) {
+			retstat = CHKUSER_OK;
+			break;
+		}
+	
+		domain_path.len = strlen (domain_path.s);
+
+	case 6:
+
+/* Check if domain has bouncing enabled */
+
+#if !defined CHKUSER_ALWAYS_ON
+
+#if defined CHKUSER_STARTING_VARIABLE
+		if (starting_value == 0) {
+#endif
+
+	                if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM();
+
+#if defined CHKUSER_SPECIFIC_BOUNCING
+	  		if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM();
+	  		if (!stralloc_cats (&tmp_path, CHKUSER_SPECIFIC_BOUNCING)) DIE_NOMEM();
+			if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+	  		fd_file = open_read (tmp_path.s);	
+	  		if (fd_file != -1) {
+	      			close (fd_file);
+			} else {
+				retstat = CHKUSER_OK;
+				break;
+			}
+#else
+	  		if (!stralloc_cats (&tmp_path, "/.qmail-default")) DIE_NOMEM();
+			if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+
+	  		read_char = 0;
+	  		fd_file = open_read (tmp_path.s);	
+	  		if (fd_file != -1) {
+	      			read_char = read (fd_file, read_buf, sizeof(read_buf) - 1);
+	      			close (fd_file);
+	      			if (read_char < 0) read_char = 0;
+	  			}
+	  		read_buf[read_char] = 0;
+
+	  		if ( strstr(read_buf, CHKUSER_BOUNCE_STRING) == NULL ) {
+				retstat = CHKUSER_OK;
+				break;
+	  		}
+#endif
+#if defined CHKUSER_STARTING_VARIABLE
+		}
+#endif
+#endif
+
+	case 7:
+#if defined VALIAS
+/* Check for aliases/forwards - valias*/
+
+		if (valias_select (user.s, domain.s) != NULL) {
+			retstat = CHKUSER_OK;
+			break;
+		}
+#endif
+
+	case 8:
+#if defined CHKUSER_ENABLE_ALIAS
+/* Check for aliases/forwards - .qmail.x files */
+
+		if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM();
+                /* Change all '.' in ':' before continuing on aliases */
+                for (count = 0; count < tmp_path.len; ++count)
+        	        if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':';
+
+                if (!stralloc_copy (&alias_path, &domain_path)) DIE_NOMEM();
+                if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM();
+                if (!stralloc_cats (&alias_path, tmp_path.s)) DIE_NOMEM();
+                if (!stralloc_0 (&alias_path)) DIE_NOMEM();
+
+		fd_file = open_read (alias_path.s);
+		if (fd_file != -1) {
+			close (fd_file);
+			retstat = CHKUSER_OK;
+			break;
+		}
+#endif
+
+	case 9:
+
+#if defined CHKUSER_ENABLE_ALIAS_DEFAULT
+
+		if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM();
+                /* Change all '.' in ':' before continuing on aliases */
+                for (count = 0; count < tmp_path.len; ++count)
+        	        if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':';
+
+                /* Search for the outer '-' character */
+                for (offset = user.len - 1; offset > 0; --offset)
+                        if (*(user.s + offset) == CHKUSER_USERS_DASH)  {
+                                if (!stralloc_copy (&alias_path, &domain_path)) die_nomem();
+                                if (!stralloc_cats (&alias_path, "/.qmail-")) die_nomem();
+                                if (!stralloc_catb (&alias_path, user.s, offset)) die_nomem();
+                                if (!stralloc_cats (&alias_path, "-default")) die_nomem();
+                                if (!stralloc_0 (&alias_path)) die_nomem();
+
+                                fd_file = open_read (alias_path.s);
+                                if (fd_file != -1) {
+                                        close (fd_file);
+                                        retstat = CHKUSER_OK;
+                                        break;
+                                }
+                        }
+
+                if (retstat != CHKUSER_KO) {
+                        break;
+                }
+
+#endif
+
+        case 10:
+#if defined CHKUSER_ENABLE_USERS
+/* User control: check the existance of a real user */
+
+                user_passwd = vauth_getpw (user.s, domain.s);
+
+#if defined CHKUSER_ENABLE_USERS_EXTENSIONS
+                if (user_passwd == NULL) {
+                       count = 0;
+                       while ((count < (user.len -1)) && (user_passwd == NULL)) {
+                               count += byte_chr(&user.s[count], user.len - count, CHKUSER_USERS_DASH);
+                               if (count < user.len) {
+                                       if (!stralloc_copyb (&tmp_path, user.s, count)) DIE_NOMEM();
+                                       if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+                                       user_passwd = vauth_getpw (tmp_path.s, domain.s);
+                                         ++count;
+                               }
+                        }
+                }
+
+#endif
+                if (user_passwd != NULL) {
+
+                /* If user exists check if he has BOUNCE_MAIL flag set */
+
+                        if (user_passwd->pw_gid & BOUNCE_MAIL)
+                                retstat = CHKUSER_KO;
+                        else {
+                                retstat = CHKUSER_OK;
+#if defined CHKUSER_MBXQUOTA_VARIABLE
+                                if ((maxmbxquota_limit > 0) && (strcasecmp(user_passwd->pw_shell, "NOQUOTA") != 0)) {
+                                        if (!stralloc_copys (&tmp_path, user_passwd->pw_dir)) DIE_NOMEM();
+                                        if (!stralloc_cats (&tmp_path, "/Maildir")) DIE_NOMEM();
+                                        if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+
+                                        if (vmaildir_readquota(tmp_path.s,format_maildirquota(user_passwd->pw_shell))
+                                                >= maxmbxquota_limit) {
+                                                retstat = CHKUSER_ERR_MBXFULL;
+                                        }
+                                }
+#endif
+                        }
+                        break;
+                }
+#endif
+
+	case 11:
+#if defined CHKUSER_ENABLE_EZMLM_LISTS
+/* Let's check for mailing lists */
+
+		/* Search for the outer CHKUSER_EZMLM_DASH character */
+	      	for (offset = user.len - 2; offset > 0; --offset) {
+			if (*(user.s + offset) == CHKUSER_EZMLM_DASH)  {
+				if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM();
+	      			if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM();
+	      			if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM();
+	      			if (!stralloc_cats (&tmp_path, "/mailinglist")) DIE_NOMEM();
+	      			if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+				fd_file = open_read (tmp_path.s);
+				if (fd_file != -1) {
+					close (fd_file);
+					retstat = CHKUSER_OK;
+					break;
+				}
+	        	}
+		}
+		if (retstat != CHKUSER_KO) {
+			break;
+		}
+#endif
+
+        case 12:
+#if defined CHKUSER_ENABLE_MAILMAN_LISTS
+/* Let's check for mailing lists */
+
+                /* Search for the outer CHKUSER_MAILMAN_DASH character */
+                for (offset = user.len - 2; offset > 0; --offset) {
+                        if (*(user.s + offset) == CHKUSER_MAILMAN_DASH)  {
+                                if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM();
+                                if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM();
+				if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM();
+                                if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM();
+                                if (!stralloc_0 (&tmp_path)) DIE_NOMEM();
+                                fd_file = open_read (tmp_path.s);
+	                        read_char = 0;
+        	                if (fd_file != -1) {
+                	                read_char = read (fd_file, read_buf, sizeof(read_buf) - 1);
+                        	        close (fd_file);
+                                	if (read_char < 0) read_char = 0;
+                                }
+	                        read_buf[read_char] = 0;
+
+        	                if ( strstr(read_buf, CHKUSER_MAILMAN_STRING) == NULL ) {
+	                                retstat = CHKUSER_OK;
+	                                break;
+	                        }
+
+                        }
+                }
+                if (retstat != CHKUSER_KO) {
+                        break;
+                }
+#endif
+
+/*
+ * Add this code if another case is following
+	case xx:
+		code ....
+		code ....
+		code ....
+		code ....
+
+		if (xxxxxxxx) {
+			retstat != CHKUSER_KO)
+			break;
+		}
+*/
+	    
+        default:
+                retstat = CHKUSER_KO;
+
+	} /* end switch */
+
+#if defined CHKUSER_ENABLE_UIDGID
+/* Now switch back effective to saved UID & GID (qmaild:nofiles) */
+
+  setegid (eff_gid);
+  seteuid (eff_uid);
+
+/* qmail-smtpd is running again as (effective) qmaild:nofiles */
+#endif
+
+  return retstat;
+
+}
+
+
+
+/*
+ * chkuser_realrcpt ()
+ *
+ * Returns a simple status:
+ *
+ *      CHKUSER_OK = 1 = Ok, recipients does exists
+ *
+ *      CHKUSER_NORCPTHOSTS = Not in rcpthosts
+ *
+ *      CHKUSER_KO = ERROR
+ *
+ *
+ * Parameters:
+ *      stralloc *sender = sender address
+ *      stralloc *rcpt = rcpt address to check
+ *
+ *
+*/
+
+int chkuser_realrcpt (stralloc *sender, stralloc *rcpt) {
+
+int retstat;
+
+  if (first_time_init_flag) {
+        first_time_init ();
+  }
+
+  retstat = realrcpt (sender, rcpt);
+
+	switch (retstat) {
+
+		case CHKUSER_OK:
+#if defined CHKUSER_LOG_VALID_RCPT
+			chkuser_commonlog (sender->s, rcpt->s, "accepted rcpt", "found existing recipient");
+#endif
+			return CHKUSER_OK;
+			break;
+
+                case CHKUSER_RELAYING:
+#if defined CHKUSER_LOG_VALID_RCPT
+                        chkuser_commonlog (sender->s, rcpt->s, "relaying rcpt", "client allowed to relay");
+#endif
+                        return CHKUSER_RELAYING;
+                        break;
+
+		case CHKUSER_NORCPTHOSTS:
+                        chkuser_commonlog (sender->s, rcpt->s, "rejected relaying", "client not allowed to relay");
+		        CHKUSER_RCPT_DELAY_ANY();
+			out(CHKUSER_NORELAY_STRING);
+			break;
+
+		case CHKUSER_KO:
+			chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "not existing recipient");
+		        CHKUSER_DELAY();
+ 			out(CHKUSER_NORCPT_STRING);
+			break;
+
+		case CHKUSER_ERR_AUTH_RESOURCE:
+			chkuser_commonlog (sender->s, rcpt->s, "no auth resource", "no auth resource available");
+		        CHKUSER_RCPT_DELAY_ANY();
+			out(CHKUSER_RESOURCE_STRING);
+			break;
+
+		case CHKUSER_ERR_MBXFULL:
+			chkuser_commonlog (sender->s, rcpt->s, "mbx overquota", "rcpt mailbox is overquota");
+		        CHKUSER_RCPT_DELAY_ANY();
+			out(CHKUSER_MBXFULL_STRING);
+			break;
+
+		case CHKUSER_ERR_MAXRCPT:
+			chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of recipients");
+		        CHKUSER_DELAY ();
+			out(CHKUSER_MAXRCPT_STRING);
+			break;
+
+		case CHKUSER_ERR_MAXWRONGRCPT:
+			chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of invalid recipients");
+		        CHKUSER_DELAY ();
+			out(CHKUSER_MAXWRONGRCPT_STRING);
+			break;
+
+		case CHKUSER_ERR_INTRUSION_THRESHOLD:
+			chkuser_commonlog (sender->s, rcpt->s, "rejected intrusion", "rcpt ignored, session over INTRUSION threshold");
+			CHKUSER_DELAY ();
+			out(CHKUSER_INTRUSIONTHRESHOLD_STRING);
+			break;
+
+		case CHKUSER_ERR_DOMAIN_MISSING:
+		        CHKUSER_DELAY ();
+			out(CHKUSER_DOMAINMISSING_STRING);
+			break;
+
+                case CHKUSER_ERR_RCPT_FORMAT:
+                        chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt address format");
+		        CHKUSER_RCPT_DELAY_ANY();
+			out(CHKUSER_RCPTFORMAT_STRING);
+                        break;
+
+                case CHKUSER_ERR_RCPT_MX:
+			chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt MX domain");
+		        CHKUSER_RCPT_DELAY_ANY();
+			out(CHKUSER_RCPTMX_STRING);
+                        break;
+
+                case CHKUSER_ERR_RCPT_MX_TMP:
+                        chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "temporary DNS problem");
+                        CHKUSER_RCPT_DELAY_ANY();
+                        out(CHKUSER_RCPTMX_TMP_STRING);
+                        break;
+	}
+
+
+
+#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE
+	if ((retstat == CHKUSER_KO) || (retstat == CHKUSER_ERR_DOMAIN_MISSING)) {
+        	++wrong_recipients;
+        	if ((INTRUSION_threshold_reached == 0) && (maxwrongrcpt_limit > 0) && (wrong_recipients >= maxwrongrcpt_limit)) {
+        	        chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed invalid rcpt");
+        	        INTRUSION_threshold_reached = 1;
+        	}
+	}
+#endif
+
+	return CHKUSER_KO;
+}
+
+
+/*
+ *
+ * This routine checks for sender format and MX
+ *
+ */
+
+
+int chkuser_sender (stralloc *sender) {
+
+int count;
+
+	if (first_time_init_flag) {
+		first_time_init ();
+	}
+
+#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE
+	if (starting_value == -1) {
+		return CHKUSER_OK;
+	}
+#endif
+
+#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX
+
+#if defined CHKUSER_SENDER_NOCHECK_VARIABLE
+
+	if (sender_nocheck == 1) {
+		return CHKUSER_OK;
+	}
+#endif
+
+        if (sender->len <= 1) {
+#if defined CHKUSER_LOG_VALID_SENDER
+		chkuser_commonlog (sender->s, "", "accepted null sender", "accepted null sender always");
+#endif
+                return CHKUSER_OK;
+	}
+
+        count = byte_rchr(sender->s,sender->len,'@');
+        if (count < sender->len) {
+                if (!stralloc_copyb (&sender_user, sender->s, count)) DIE_NOMEM();
+                if (!stralloc_copys (&sender_domain, sender->s + count + 1)) DIE_NOMEM();
+        } else {
+                if (!stralloc_copys (&sender_user, sender->s)) DIE_NOMEM();
+                sender_domain.len = 0;
+        }
+        if (!stralloc_0 (&sender_user)) DIE_NOMEM();
+        if (!stralloc_0 (&sender_domain)) DIE_NOMEM();
+
+#if defined CHKUSER_SENDER_FORMAT
+        if (check_sender_address_format (&sender_user, &sender_domain) == 0) {
+                chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender address format");
+		CHKUSER_SENDER_DELAY_ANY();
+		out(CHKUSER_SENDERFORMAT_STRING);
+	        return CHKUSER_ERR_SENDER_FORMAT;
+        }
+
+#endif
+
+#if defined CHKUSER_SENDER_MX
+
+	switch (chkuser_mx_lookup(&sender_domain)) {
+
+		case DNS_HARD:
+			CHKUSER_SENDER_DELAY_ANY();
+			out(CHKUSER_SENDERMX_STRING);
+			chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender MX domain");
+			return CHKUSER_ERR_SENDER_MX;
+			break;
+
+		case DNS_SOFT:
+			CHKUSER_SENDER_DELAY_ANY();
+			out(CHKUSER_SENDERMX_TMP_STRING);
+			chkuser_commonlog (sender->s, "", "rejected sender", "temporary DNS problem");
+			return CHKUSER_ERR_SENDER_MX_TMP;
+			break;
+	}
+
+#if defined CHKUSER_LOG_VALID_SENDER
+                        chkuser_commonlog (sender->s, "", "accepted sender", "sender accepted");
+#endif
+
+	return CHKUSER_OK;
+#endif
+
+#else
+
+	return CHKUSER_OK;
+
+#endif
+
+}
+
+
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/chkuser.h ./chkuser.h
--- ../../netqmail-1.05-orig/netqmail-1.05/chkuser.h	1969-12-31 16:00:00.000000000 -0800
+++ ./chkuser.h	2006-01-05 15:03:43.315246456 -0800
@@ -0,0 +1,51 @@
+
+/*
+ *
+ * 'chkuser.h' v.2.0.8
+ * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x
+ *
+ * Author: Antonio Nati tonix@interazioni.it
+ * All rights on this software and
+ * the identifying words chkusr and chkuser kept by the author
+ *
+ * This software may be freely used, modified and distributed,
+ * but this lines must be kept in every original or derived version.
+ * Original author "Antonio Nati" and the web URL
+ * "http://www.interazioni.it/opensource"
+ * must be indicated in every related work or web page
+ *
+ */
+
+#define CHKUSER
+#define CHKUSER_VERSION		"2.0.8"
+#define CHKUSER_VERSION_RL	2
+#define CHKUSER_VERSION_MJ	0
+#define CHKUSER_VERSION_MN	8
+
+#define CHKUSER_OK			1
+#define CHKUSER_RELAYING		0
+#define CHKUSER_KO			-1
+#define CHKUSER_NORCPTHOSTS		-10
+#define CHKUSER_ERR_AUTH_RESOURCE	-20
+#define CHKUSER_ERR_MBXFULL		-30
+#define CHKUSER_ERR_MAXRCPT		-40
+#define CHKUSER_ERR_MAXWRONGRCPT	-50
+#define CHKUSER_ERR_DOMAIN_MISSING	-60
+#define CHKUSER_ERR_RCPT_FORMAT		-70
+#define CHKUSER_ERR_RCPT_MX		-75
+#define CHKUSER_ERR_RCPT_MX_TMP		-76
+#define CHKUSER_ERR_SENDER_FORMAT	-80
+#define CHKUSER_ERR_SENDER_MX		-85
+#define CHKUSER_ERR_SENDER_MX_TMP	-86
+#define CHKUSER_ERR_INTRUSION_THRESHOLD	-90
+
+void chkuser_cleanup (int exit_value);
+int chkuser_realrcpt (stralloc *sender, stralloc *rcpt);
+int chkuser_sender (stralloc *sender);
+
+#ifdef TLS_H
+#undef _exit
+#define _exit(value) { if (ssl) ssl_free(ssl); chkuser_cleanup(value); }
+#else
+#define _exit(value) chkuser_cleanup(value);
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/chkuser_settings.h ./chkuser_settings.h
--- ../../netqmail-1.05-orig/netqmail-1.05/chkuser_settings.h	1969-12-31 16:00:00.000000000 -0800
+++ ./chkuser_settings.h	2006-01-05 15:03:43.317246152 -0800
@@ -0,0 +1,373 @@
+
+/*
+ *
+ * 'chkuser_settings.h' v.2.0.8
+ * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x
+ *
+ * Author: Antonio Nati tonix@interazioni.it
+ * All rights on this software and
+ * the identifying words chkusr and chkuser kept by the author
+ *
+ * This software may be freely used, modified and distributed,
+ * but this lines must be kept in every original or derived version.
+ * Original author "Antonio Nati" and the web URL
+ * "http://www.interazioni.it/opensource"
+ * must be indicated in every related work or web page
+ *
+ */
+
+/*
+ * the following line enables debugging of chkuser
+ */
+/* #define CHKUSER_DEBUG */
+
+/*
+ * The following line moves DEBUG output from STDOUT (default) to STDERR
+ * Example of usage within sh: ./qmail-smtpd 2> /var/log/smtpd-debug.log
+ */
+/* #define CHKUSER_DEBUG_STDERR */
+
+/*
+ * Uncomment the following define if you want chkuser ALWAYS enabled.
+ * If uncommented, it will check for rcpt existance despite any .qmail-default
+ * setting.
+ * So, unsomments this if you are aware that ALL rcpt in all domains will be
+ * ALWAYS checked.
+ */
+/* #define CHKUSER_ALWAYS_ON */
+
+/*
+ * The following defines which virtual manager is used.
+ * Up to know, only vpopmail, but versions with pure qmail are in the mind.
+ */
+#define CHKUSER_VPOPMAIL
+
+/*
+ * Uncomment the following line if you want chkuser to work depending on a VARIABLE setting
+ * VALUE HERE DEFINED is the name of the variable
+ * Values admitted inside the variable: NONE | ALWAYS | DOMAIN
+ * 		NONE 	= chkuser will not work
+ *		ALWAYS	= chkuser will work always
+ *		DOMAIN	= chkuser will work depending by single domain settings
+ * if CHKUSER_ALWAYS_ON is defined, this define is useless
+ * if CHKUSER_STARTING_VARIABLE is defined, and no variable or no value is set, then chkuser is disabled
+ */
+/* #define CHKUSER_STARTING_VARIABLE "CHKUSER_START" */
+
+/*
+ * Uncomment this to enable uid/gid changing
+ * (switching UID/GID is NOT compatible with TLS; you may keep this commented if you have TLS)
+ */
+/* #define CHKUSER_ENABLE_UIDGID */
+
+/*
+ * Uncomment this to check if a domain is ALWAYS specified in rcpt addresses
+ */
+#define CHKUSER_DOMAIN_WANTED
+
+/*
+ * Uncomment this to check for vpopmail users
+ */
+#define CHKUSER_ENABLE_USERS
+
+/*
+ * Uncomment this to check for alias
+ */
+#define CHKUSER_ENABLE_ALIAS
+
+/*
+ * The following #define set the character used for lists extensions
+ * be careful: this is a  single char '-' definition, not a "string"
+ */
+#define CHKUSER_EZMLM_DASH '-'
+
+/*
+ * Uncomment this to set an alternative way to check for bouncing enabling;
+ * with this option enabled, the file here defined 
+ * will be searched, inside the domain dir, in order to check if bouncing is enabled
+ * The content of this file is not important, just it's existence is enough
+ */
+/* #define CHKUSER_SPECIFIC_BOUNCING ".qmailchkuser-bouncing" */
+
+/*
+ * This is the string to look for inside .qmail-default
+ * Be careful, chkuser looks within the first 1023 characters of .qmail-default for
+ * this string (despite the line containing the string is working or commented).
+ */
+#define CHKUSER_BOUNCE_STRING "bounce-no-mailbox"
+
+/*
+ * This is to enable auth open checking
+ * it is useful to avoid bouncing if MySQL/LDAP/PostGRES/etc are down or not reachable
+ */
+/* #define CHKUSER_ENABLE_VAUTH_OPEN */
+
+/*
+ * Uncomment to enable logging of rejected recipients and variuos limits reached
+ */
+#define CHKUSER_ENABLE_LOGGING
+
+/*
+ * Uncomment to enable logging of "good" rcpts
+ * valid only if CHKUSER_ENABLE_LOGGING is defined
+ */
+#define CHKUSER_LOG_VALID_RCPT
+
+/*
+ * Uncomment to enable usage of a variable escluding any check on the sender.
+ * The variable should be set in tcp.smtp for clients, with static IP, whose mailer
+ * is composing bad sender addresses
+ */
+/* #define CHKUSER_SENDER_NOCHECK_VARIABLE "SENDER_NOCHECK" */
+
+/*
+ * Uncomment to enable usage of "#" and "+" characters within sender address
+ * This is used by SRS (Sender Rewriting Scheme) products
+ */
+/* #define CHKUSER_ALLOW_SENDER_SRS */
+
+/*
+ * If you need more additional characters to be accepted within sender address
+ * uncomment one of the following #define and edit the character value.
+ * Be careful to use '*' (single hiphen) and NOT "*" (double hiphen) around the
+ * wanted char.
+ */
+/* #define CHKUSER_ALLOW_SENDER_CHAR_1 '$' */
+/* #define CHKUSER_ALLOW_SENDER_CHAR_2 '%' */
+/* #define CHKUSER_ALLOW_SENDER_CHAR_3 '£' */
+/* #define CHKUSER_ALLOW_SENDER_CHAR_4 '?' */
+/* #define CHKUSER_ALLOW_SENDER_CHAR_5 '*' */
+
+/*
+ * The following #define sets the minimum length of a domain:
+ * as far as I know, "k.st" is the shortest domain, so 4 characters is the
+ * minimum length.
+ * This value is used to check formally a domain name validity.
+ * if CHKUSER_SENDER_FORMAT is undefined, no check on length is done.
+ * If you comment this define, no check on length is done.
+ */
+#define CHKUSER_MIN_DOMAIN_LEN 4
+
+/*
+ * Uncomment to enable logging of "good" senders
+ * valid only if CHKUSER_ENABLE_LOGGING is defined
+ */
+#define CHKUSER_LOG_VALID_SENDER
+
+/*
+ * Uncomment to define a variable which contains the max recipients number
+ * this will return always error if total recipients exceed this limit.
+ * The first reached, between CHKUSER_RCPT_LIMIT_VARIABLE and CHKUSER_WRONGRCPT_LIMIT_VARIABLE,
+ * makes chkuser rejecting everything else
+ */
+#define CHKUSER_RCPT_LIMIT_VARIABLE "CHKUSER_RCPTLIMIT"
+
+/*
+ * Uncomment to define a variable which contains the max unknown recipients number
+ * this will return always error if not existing recipients exceed this limit.
+ * The first reached, between CHKUSER_RCPT_LIMIT_VARIABLE and CHKUSER_WRONGRCPT_LIMIT_VARIABLE,
+ * makes chkuser rejecting everything else
+ */
+#define CHKUSER_WRONGRCPT_LIMIT_VARIABLE "CHKUSER_WRONGRCPTLIMIT"
+
+/*
+ * Uncomment to define the variable containing the percent to check for.
+ * Remember to define externally (i.e. in tcp.smtp) the environment variable containing
+ * the limit percent.
+ * If the variable is not defined, or it is <= 0, quota checking is not performed.
+ */
+#define CHKUSER_MBXQUOTA_VARIABLE "CHKUSER_MBXQUOTA"
+
+/*
+ * Delay to wait for each not existing recipient
+ * value is expressed in milliseconds
+ */
+#define CHKUSER_ERROR_DELAY 1000
+
+/*
+ * Uncomment to consider rcpt errors on address format and MX as intrusive
+ *
+ */
+#define CHKUSER_RCPT_DELAY_ANYERROR
+
+/*
+ * Uncomment to consider sender errors on address format and MX as intrusive
+ *
+ */
+#define CHKUSER_SENDER_DELAY_ANYERROR
+
+#define CHKUSER_NORCPT_STRING "511 sorry, no mailbox here by that name (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_RESOURCE_STRING "430 system temporary unavailable, try again later (#4.3.0 - chkuser)\r\n"
+#define CHKUSER_MBXFULL_STRING "522 sorry, recipient mailbox is full (#5.2.2 - chkuser)\r\n"
+#define CHKUSER_MAXRCPT_STRING "571 sorry, reached maximum number of recipients for one session (#5.7.1 - chkuser)\r\n"
+#define CHKUSER_MAXWRONGRCPT_STRING "571 sorry, you are violating our security policies (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_DOMAINMISSING_STRING "511 sorry, you must specify a domain (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_RCPTFORMAT_STRING "511 sorry, recipient address has invalid format (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_RCPTMX_STRING "511 sorry, can't find a valid MX for rcpt domain (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_SENDERFORMAT_STRING "571 sorry, sender address has invalid format (#5.7.1 - chkuser)\r\n"
+#define CHKUSER_SENDERMX_STRING "511 sorry, can't find a valid MX for sender domain (#5.1.1 - chkuser)\r\n"
+#define CHKUSER_INTRUSIONTHRESHOLD_STRING "571 sorry, you are violating our security policies (#5.7.1 - chkuser)\r\n"
+#define CHKUSER_NORELAY_STRING "553 sorry, that domain isn't in my list of allowed rcpthosts (#5.5.3 - chkuser)\r\n"
+
+/***************************************************
+ *
+ *      new/modified defines in/from 2.0.6
+ *
+ **************************************************/
+
+/*
+ * Before version 5.3.25, vpopmail used the function vget_real_domain()
+ * to get the real name of a domain (useful if rcpt domain is aliasing
+ * another domain).
+ * From version 5.3.25, this call is not available and has been
+ * substituted by other calls.
+ *
+ *        must be enabled if vpopmail version< 5.3.5
+ *        must be disabled  if vpopmail version => 5.3.5 *
+ */
+/* #define CHKUSER_ENABLE_VGET_REAL_DOMAIN */
+
+/***************************************************
+ *
+ *      new/modified defines in/from 2.0.7
+ *
+ **************************************************/
+
+/*
+ * Uncomment next define to accept recipients for
+ * aliases that have a -default extension
+ */
+/* #define CHKUSER_ENABLE_ALIAS_DEFAULT */
+
+
+/*
+ * Uncomment to enable usage of "#" and "+" characters within rcpt address
+ * This is used by SRS (Sender Rewriting Scheme) products
+ */
+/* #define CHKUSER_ALLOW_RCPT_SRS */
+
+/*
+ * If you need more additional characters to be accepted within rcpt address
+ * uncomment one of the following #define and edit the character value.
+ * Be careful to use '*' (single hiphen) and NOT "*" (double hiphen) around the
+ * wanted char.
+ */
+/* #define CHKUSER_ALLOW_RCPT_CHAR_1 '$' */
+/* #define CHKUSER_ALLOW_RCPT_CHAR_2 '%' */
+/* #define CHKUSER_ALLOW_RCPT_CHAR_3 '£' */
+/* #define CHKUSER_ALLOW_RCPT_CHAR_4 '?' */
+/* #define CHKUSER_ALLOW_RCPT_CHAR_5 '*' */
+
+/*
+ * This define has been eliminated.
+ * Turning it ON or OFF has no effect, as we consider the existence
+ * of #define VALIAS inside ~vpopmail/include/vpopmail_config.h
+ */
+/* #define CHKUSER_ENABLE_VALIAS */
+
+/*
+ * Uncomment this to enable user extension on names (i.e. TMDA)
+ * (for mailing lists this is done without checking this define)
+ * This define substitutes #define CHKUSER_ENABLE_EXTENSIONS
+ */
+/* #define CHKUSER_ENABLE_USERS_EXTENSIONS */
+
+/*
+ * Enables checking for EZMLM lists
+ * this define substitutes #define CHKUSER_ENABLE_LISTS
+ *
+ */
+#define CHKUSER_ENABLE_EZMLM_LISTS
+
+/*
+ * Help identifying remote authorized IPs giving them a descriptive name
+ * Can be put in tcp.smtp, and will be displayed inside chkuser log
+ * Substitutes RELAYCLIENT in chkuser logging
+ */
+#define CHKUSER_IDENTIFY_REMOTE_VARIABLE "CHKUSER_IDENTIFY"
+
+/*
+ * The following #define set the character used for users extensions
+ * be careful: this is a  single char '-' definition, not a "string"
+ * this define substitutes #define CHKUSER_EXTENSION_DASH
+ * MUST be defined if CHKUSER_ENABLE_USERS_EXTENSIONS is defined
+ */
+#define CHKUSER_USERS_DASH '-'
+
+/*
+ * New error strings for SOFT DNS problems
+ */
+#define CHKUSER_RCPTMX_TMP_STRING "451 DNS temporary failure (#4.5.1 - chkuser)\r\n"
+#define CHKUSER_SENDERMX_TMP_STRING "451 DNS temporary failure (#4.5.1 - chkuser)\r\n"
+
+/*
+ * Enables checking for mailman lists
+ *
+ */
+/* #define CHKUSER_ENABLE_MAILMAN_LISTS */
+
+/*
+ * Identifies the pattern string to be searched within mailman aliases
+ *
+ */
+#define CHKUSER_MAILMAN_STRING "mailman"
+
+/*
+ * The following #define set the character used for mailman lists extensions
+ * be careful: this is a  single char '-' definition, not a "string"
+ */
+#define CHKUSER_MAILMAN_DASH '-'
+
+
+/*
+ * Enables final clean-up routine of chkuser
+ * This routine cleans open DB connections used for checking users and valiases
+ */
+#define CHKUSER_DB_CLEANUP
+
+/***************************************************
+ *
+ *      new/modified defines in/from 2.0.8
+ *
+ **************************************************/
+
+/*
+ * The following defines are NO MORE used. NULL SENDER rejecting breaks RFC
+ * compatibility, and makes harder to handle e-mail receipts.
+ * Please comment or delete them from your chkuser_settings.h.
+ */
+/* #define CHKUSER_ACCEPT_NULL_SENDER */
+/* #define CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST */
+
+/*
+ * Uncomment to enable checking of user and domain format for rcpt addresses
+ *      user    =       [a-z0-9_-]
+ *      domain  =       [a-z0-9-.] with not consecutive "-.", not leading or ending "-."
+ */
+/* #define CHKUSER_RCPT_FORMAT */
+
+/*
+ * Uncomment to enable checking of domain MX for rcpt addresses
+ * It works on any rcpt address domain that is not inside rcpthosts
+ */
+/* #define CHKUSER_RCPT_MX */
+
+/*
+ * Uncomment to enable checking of user and domain format for sender address
+ *      user    =       [a-z0-9_-]
+ *      domain  =       [a-z0-9-.] with not consecutive "-.", not leading or ending "-."
+ */
+/* #define CHKUSER_SENDER_FORMAT */
+
+/*
+ * Uncomment to enable checking of domain MX for sender address
+ * it works on the first rcpt address, despite of any domain setting on chkuser
+ */
+/* #define CHKUSER_SENDER_MX */
+
+/*
+ * Delay to add, for each not existing recipient, to the initial CHKUSER_ERROR_DELAY value
+ * value is expressed in milliseconds
+ */
+#define CHKUSER_ERROR_DELAY_INCREASE 300
+
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/conf-cc ./conf-cc
--- ../../netqmail-1.05-orig/netqmail-1.05/conf-cc	1998-06-15 03:53:16.000000000 -0700
+++ ./conf-cc	2006-01-05 15:08:14.801974200 -0800
@@ -1,3 +1,3 @@
-cc -O2
+cc -O2 -DTLS=20060104 -I/usr/local/ssl/include -I/home/vpopmail/include
 
 This will be used to compile .c files.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/conf-spawn ./conf-spawn
--- ../../netqmail-1.05-orig/netqmail-1.05/conf-spawn	1998-06-15 03:53:16.000000000 -0700
+++ ./conf-spawn	2006-01-05 15:03:43.319245848 -0800
@@ -1,4 +1,4 @@
-120
+509
 
 This is a silent concurrency limit. You can't set it above 255. On some
 systems you can't set it above 125. qmail will refuse to compile if the
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/control.c ./control.c
--- ../../netqmail-1.05-orig/netqmail-1.05/control.c	1998-06-15 03:53:16.000000000 -0700
+++ ./control.c	2006-01-05 15:03:43.321245544 -0800
@@ -7,8 +7,10 @@
 #include "control.h"
 #include "alloc.h"
 #include "scan.h"
+#include "fmt.h"
 
 static char inbuf[64];
+static char outbuf[64];
 static stralloc line = {0};
 static stralloc me = {0};
 static int meok = 0;
@@ -128,3 +130,25 @@
  close(fd);
  return -1;
 }
+
+
+int control_writeint(i,fn)
+int *i;
+char *fn;
+{
+ substdio ss;
+ int fd;
+ char num[FMT_ULONG];
+
+ fd = open_write(fn);
+ if (fd == -1) { if (errno == error_noent) return 0; return -1; }
+ 
+ substdio_fdbuf(&ss,write,fd,outbuf,sizeof(outbuf));
+
+ substdio_putflush(&ss,num,fmt_ulong(num,*i));
+ substdio_putsflush(&ss,"\n");
+
+ close(fd);
+
+ return 1;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/control.h ./control.h
--- ../../netqmail-1.05-orig/netqmail-1.05/control.h	1998-06-15 03:53:16.000000000 -0700
+++ ./control.h	2006-01-05 15:03:43.322245392 -0800
@@ -6,5 +6,9 @@
 extern int control_rldef();
 extern int control_readint();
 extern int control_readfile();
+extern int control_writeint();
+
+extern int control_readtime();
+extern int control_writetime();
 
 #endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/control_time.c ./control_time.c
--- ../../netqmail-1.05-orig/netqmail-1.05/control_time.c	1969-12-31 16:00:00.000000000 -0800
+++ ./control_time.c	2006-01-05 15:03:43.323245240 -0800
@@ -0,0 +1,62 @@
+#include "readwrite.h"
+#include "open.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "error.h"
+#include "control.h"
+#include "alloc.h"
+#include "time.h"
+
+static char inbuf[64];
+static char outbuf[64];
+
+
+int control_readtime(t,fn)
+struct q_time_t *t;
+char *fn;
+{
+ stralloc sa = { 0 };
+ substdio ss;
+ int fd;
+ char tb;
+
+ fd = open_read(fn);
+ if (fd == -1) { if (errno == error_noent) return 0; return -1; }
+
+ substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf));
+
+ for (;;)
+  {
+   if (substdio_get(&ss,&tb,1) <= 0) break;
+   if (!stralloc_append(&sa,&tb)) return -1; 
+  }
+
+ if ((!Q_TIME_PACK && sa.len) || (Q_TIME_PACK && sa.len == Q_TIME_PACK))
+  {
+   time_unpack(sa.s,t);
+  }
+
+ close(fd);
+ return 1;
+}
+
+
+int control_writetime(t,fn)
+struct q_time_t *t;
+char *fn;
+{
+ stralloc sa = { 0 };
+ substdio ss;
+ int fd;
+
+ fd = open_write(fn);
+ if (fd == -1) { if (errno == error_noent) return 0; return -1; }
+ 
+ substdio_fdbuf(&ss,write,fd,outbuf,sizeof(outbuf));
+
+ time_pack(&sa,t);
+ substdio_putflush(&ss,sa.s,sa.len);
+
+ close(fd);
+ return 1;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/dns.c ./dns.c
--- ../../netqmail-1.05-orig/netqmail-1.05/dns.c	2006-01-05 15:06:38.653590976 -0800
+++ ./dns.c	2006-01-05 15:03:43.325244936 -0800
@@ -9,6 +9,7 @@
 extern int res_search();
 #include "ip.h"
 #include "ipalloc.h"
+#include "strsalloc.h"
 #include "fmt.h"
 #include "alloc.h"
 #include "str.h"
@@ -19,14 +20,17 @@
 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 u_long saveresoptions;
 
 static int numanswers;
 static char name[MAXDNAME];
 static struct ip_address ip;
+static stralloc txt = {0};
 unsigned short pref;
 
 static stralloc glue = {0};
@@ -43,18 +47,33 @@
  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)
+  if (response.buf = (unsigned char *)alloc(PACKETSZ+1))
+   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);
@@ -64,7 +83,7 @@
    if (i < QFIXEDSZ) return DNS_SOFT;
    responsepos += QFIXEDSZ;
   }
- numanswers = ntohs(response.hdr.ancount);
+ numanswers = ntohs(((HEADER *)response.buf)->ancount);
  return 0;
 }
 
@@ -177,6 +196,49 @@
  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)
+  {
+   unsigned short txtpos;
+   unsigned char txtlen;
+
+   txt.len = 0;
+   for (txtpos = 0;txtpos < rrdlen;txtpos += txtlen)
+    {
+     txtlen = responsepos[txtpos++];
+     if (txtlen > rrdlen-txtpos) txtlen = rrdlen-txtpos;
+     if (!stralloc_catb(&txt,&responsepos[txtpos],txtlen)) return DNS_MEM;
+    }
+
+   responsepos += rrdlen;
+   return 1;
+ }
+
+ responsepos += rrdlen;
+ return 0;
+}
+
 void dns_init(flagsearch)
 int flagsearch;
 {
@@ -235,15 +297,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;
@@ -254,25 +319,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;
@@ -291,9 +377,16 @@
    ix.ip = ip;
    ix.pref = pref;
    if (r == DNS_SOFT) return DNS_SOFT;
-   if (r == 1)
+   if (r == 1) {
+#ifdef IX_FQDN
+     ix.fqdn = glue.s;
+#endif
      if (!ipalloc_append(ia,&ix)) return DNS_MEM;
   }
+  }
+#ifdef IX_FQDN
+ glue.s = 0;
+#endif
  return 0;
 }
 
@@ -313,7 +406,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;
@@ -325,7 +418,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;
@@ -396,3 +488,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_copy(&sa,&txt)) 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 ../../netqmail-1.05-orig/netqmail-1.05/dns.h ./dns.h
--- ../../netqmail-1.05-orig/netqmail-1.05/dns.h	1998-06-15 03:53:16.000000000 -0700
+++ ./dns.h	2006-01-05 15:03:43.326244784 -0800
@@ -10,5 +10,6 @@
 int dns_mxip();
 int dns_ip();
 int dns_ptr();
+int dns_txt();
 
 #endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/dnsfq.c ./dnsfq.c
--- ../../netqmail-1.05-orig/netqmail-1.05/dnsfq.c	1998-06-15 03:53:16.000000000 -0700
+++ ./dnsfq.c	2006-01-05 15:03:43.327244632 -0800
@@ -5,15 +5,19 @@
 #include "dnsdoe.h"
 #include "ip.h"
 #include "ipalloc.h"
+#include "strsalloc.h"
 #include "exit.h"
 
 stralloc sa = {0};
+strsalloc ssa = {0};
 ipalloc ia = {0};
 
 void 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 ../../netqmail-1.05-orig/netqmail-1.05/dnsptr.c ./dnsptr.c
--- ../../netqmail-1.05-orig/netqmail-1.05/dnsptr.c	1998-06-15 03:53:16.000000000 -0700
+++ ./dnsptr.c	2006-01-05 15:03:43.328244480 -0800
@@ -6,22 +6,28 @@
 #include "dns.h"
 #include "dnsdoe.h"
 #include "ip.h"
+#include "strsalloc.h"
 #include "exit.h"
 
-stralloc sa = {0};
+strsalloc ssa = {0};
 struct ip_address ip;
 
 void 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 ../../netqmail-1.05-orig/netqmail-1.05/dnstxt.c ./dnstxt.c
--- ../../netqmail-1.05-orig/netqmail-1.05/dnstxt.c	1969-12-31 16:00:00.000000000 -0800
+++ ./dnstxt.c	2006-01-05 15:03:43.329244328 -0800
@@ -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};
+
+void 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 ../../netqmail-1.05-orig/netqmail-1.05/fmt.h ./fmt.h
--- ../../netqmail-1.05-orig/netqmail-1.05/fmt.h	1998-06-15 03:53:16.000000000 -0700
+++ ./fmt.h	2006-01-05 15:03:43.330244176 -0800
@@ -2,6 +2,7 @@
 #define FMT_H
 
 #define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_2LONG 129 /* same, but in binary */
 #define FMT_LEN ((char *) 0) /* convenient abbreviation */
 
 extern unsigned int fmt_uint();
@@ -12,8 +13,11 @@
 extern unsigned int fmt_xshort();
 extern unsigned int fmt_nbbshort();
 extern unsigned int fmt_ulong();
+extern unsigned int fmt_ulong0();
 extern unsigned int fmt_xlong();
 extern unsigned int fmt_nbblong();
+extern unsigned int fmt_2long();
+extern unsigned int fmt_2long0();
 
 extern unsigned int fmt_plusminus();
 extern unsigned int fmt_minus();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/fmt_2long.c ./fmt_2long.c
--- ../../netqmail-1.05-orig/netqmail-1.05/fmt_2long.c	1969-12-31 16:00:00.000000000 -0800
+++ ./fmt_2long.c	2006-01-05 15:03:43.331244024 -0800
@@ -0,0 +1,13 @@
+#include "fmt.h"
+
+unsigned int fmt_2long(s,u) register char *s; register unsigned long u;
+{
+  register unsigned int len; register unsigned long q;
+  len = 1; q = u;
+  while (q > 1) { ++len; q /= 2; }
+  if (s) {
+    s += len;
+    do { *--s = '0' + (u % 2); u >>= 1; } while(u); /* handles u == 0 */
+  }
+  return len;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/fmt_2long0.c ./fmt_2long0.c
--- ../../netqmail-1.05-orig/netqmail-1.05/fmt_2long0.c	1969-12-31 16:00:00.000000000 -0800
+++ ./fmt_2long0.c	2006-01-05 15:03:43.332243872 -0800
@@ -0,0 +1,10 @@
+#include "fmt.h"
+
+unsigned int fmt_2long0(s,u,n) char *s; unsigned long u; unsigned int n;
+{
+  unsigned int len;
+  len = fmt_2long(FMT_LEN,u);
+  while (len < n) { if (s) *s++ = '0'; ++len; }
+  if (s) fmt_2long(s,u);
+  return len;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/fmt_ulong0.c ./fmt_ulong0.c
--- ../../netqmail-1.05-orig/netqmail-1.05/fmt_ulong0.c	1969-12-31 16:00:00.000000000 -0800
+++ ./fmt_ulong0.c	2006-01-05 15:03:43.333243720 -0800
@@ -0,0 +1,10 @@
+#include "fmt.h"
+
+unsigned int fmt_ulong0(s,u,n) char *s; unsigned long u; unsigned int n;
+{
+  unsigned int len;
+  len = fmt_ulong(FMT_LEN,u);
+  while (len < n) { if (s) *s++ = '0'; ++len; }
+  if (s) fmt_ulong(s,u);
+  return len;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/hier.c ./hier.c
--- ../../netqmail-1.05-orig/netqmail-1.05/hier.c	1998-06-15 03:53:16.000000000 -0700
+++ ./hier.c	2006-01-05 15:03:43.335243416 -0800
@@ -47,6 +47,7 @@
   d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755);
 
   d(auto_qmail,"alias",auto_uida,auto_gidq,02755);
+  d(auto_qmail,"spam",auto_uidd,auto_gidn,02700);
 
   d(auto_qmail,"queue",auto_uidq,auto_gidq,0750);
   d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700);
@@ -76,6 +77,7 @@
   c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
@@ -109,6 +111,7 @@
   c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
   c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
   c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
+  c(auto_qmail,"bin","qmail-newst",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-newu",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-newmrh",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711);
@@ -143,6 +146,9 @@
   c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755);
   c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755);
+#ifdef TLS
+  c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755);
+#endif
 
   c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
@@ -164,6 +170,10 @@
   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/man5","qmail-spamt.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-spamt.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-spamthrottle.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-spamthrottle.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);
@@ -223,6 +233,8 @@
   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-newst.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-newst.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);
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/install-big.c ./install-big.c
--- ../../netqmail-1.05-orig/netqmail-1.05/install-big.c	1998-06-15 03:53:16.000000000 -0700
+++ ./install-big.c	2006-01-05 15:03:43.336243264 -0800
@@ -76,6 +76,7 @@
   c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
 
   c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
   c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/install_auth.sh ./install_auth.sh
--- ../../netqmail-1.05-orig/netqmail-1.05/install_auth.sh	1969-12-31 16:00:00.000000000 -0800
+++ ./install_auth.sh	2006-01-05 15:03:43.337243112 -0800
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+# qmail-smtpd AUTH (UN)INSTALL Script (install_auth.sh)
+# -----------------------------------------------------
+#
+# Purpose:      To install and uninstall the qmail-smtpd Authentication Patch
+#
+# Parameters:   -u (uninstall)
+#	        VRF (Version to be uninstalled)
+#
+# Usage:        ./install_auth.sh [-u] [Version]
+#
+#		Installation: 	./install_auth.sh
+# 		Uninstallation: ./install_auth.sh -u 105
+#
+# Return Codes: 0 - Patches applied successfully
+#		1 - Original QMAIL files not found (Patch not extracted in QMAIL source directory)
+#		2 - Patch files not found 
+#
+# Output:	install_auth.log
+#
+# History:      1.0.0 - Erwin Hoffmann - Initial release
+#		1.0.1 - 	       - grep fix; Gentoo fix
+#		1.0.2 -			 removed '-v' optio for cp
+#
+#---------------------------------------------------------------------------------------
+#
+DATE=$(date)
+LOCDIR=${PWD}
+QMAILHOME=$(head -n 1 conf-qmail)
+SOLARIS=$(sh ./find-systype.sh | grep -ci "SunOS")
+LOGFILE=auth.log
+TARGETS=FILES.auth
+IFSKEEP=${IFS}
+REL=057 # Should be identical to qmail-smtpd AUTH level
+BUILD=2005024212941
+
+
+if [ $# -eq 0 ] ; then
+
+	echo "Installing qmail-smtpd AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+	for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
+		echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
+		if [ -s ${FILE} ] ; then
+			cp ${FILE} ${FILE}.$REL | tee -a $LOGFILE 2>&1
+			echo "--> ${FILE} copied to ${FILE}.$REL" | tee -a $LOGFILE 2>&1
+		else
+			echo "${FILE} not found !"
+			exit 1
+		fi
+		if [ -s ${FILE}.patch ] ; then
+			if [ ${SOLARIS} -gt 0 ]; then
+				echo "--> Patching qmail source file ${FILE} for Solaris ...." | tee -a $LOGFILE 2>&1
+				patch -i ${FILE}.patch ${FILE} 2>&1 | tee -a $LOGFILE
+			else
+				echo "--> Patching qmail source file ${FILE}  ...." | tee -a $LOGFILE 2>&1
+				patch ${FILE} ${FILE}.patch 2>&1 | tee -a $LOGFILE
+			fi
+		else
+			echo "!! ${FILE}.patch not found !"
+			exit 2
+		fi
+	done 
+
+
+	echo "Copying documentation and samples to ${QMAILHOME}/doc/ ..." | tee -a $LOGFILE 2>&1 
+
+	cp README.auth* ${QMAILHOME}/doc/ | tee -a $LOGFILE 2>&1
+	echo ""
+	echo "If you dont wont CRAM-MD5 suport disable '#define CRAM_MD5' in qmail-smtpd !"
+	echo "Installation of qmail-smtpd AUTH $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+# Now go for the uninstallation....
+
+elif [ "$1" = "-u" ] ; then
+
+# Get the Version Number from INPUT 
+
+	if [ $# -eq 2 ] ; then
+		REL=$2
+	fi
+
+	echo "De-installing qmail-smtpd AUTH $REL (Build $BUILD) at $DATE <<<" | tee -a $LOGFILE 2>&1 
+
+	for FILE in $(grep "^= " ${TARGETS} | awk '{print $2}'); do
+		echo "Targeting file $FILE ..." | tee -a $LOGFILE 2>&1
+		if [ -s ${FILE}.$REL ] ; then
+			mv ${FILE}.$REL ${FILE} | tee -a $LOGFILE 2>&1
+			touch ${FILE}
+			echo "--> ${FILE}.$REL moved to ${FILE}" | tee -a $LOGFILE 2>&1
+		else
+			echo "!! ${FILE}.$REL not found !"
+		fi
+	done
+	echo "De-installation of qmail-smtpd AUTH $REL (Build $BUILD) finished at $DATE <<<" | tee -a $LOGFILE 2>&1 
+fi
+
+exit 0
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ip.c ./ip.c
--- ../../netqmail-1.05-orig/netqmail-1.05/ip.c	1998-06-15 03:53:16.000000000 -0700
+++ ./ip.c	2006-01-05 15:03:43.338242960 -0800
@@ -1,6 +1,7 @@
 #include "fmt.h"
 #include "scan.h"
 #include "ip.h"
+#include "byte.h"
 
 unsigned int ip_fmt(s,ip)
 char *s;
@@ -20,6 +21,44 @@
   return len;
 }
 
+unsigned int fmt_ipn(s,ip,n)
+char *s;
+struct ip_address *ip;
+unsigned int n;
+{
+  struct ip_address ipn;
+  unsigned long uip = 0;
+
+  uip += ip->d[0]; uip <<= 8;
+  uip += ip->d[1]; uip <<= 8;
+  uip += ip->d[2]; uip <<= 8;
+  uip += ip->d[3];
+
+  uip &= ~((1<<(32-n))-1);
+
+  ipn.d[3] = uip & 0xff; uip >>= 8;
+  ipn.d[2] = uip & 0xff; uip >>= 8;
+  ipn.d[1] = uip & 0xff; uip >>= 8;
+  ipn.d[0] = uip;
+
+  return ip_fmt(s,&ipn);
+}
+
+unsigned int fmt_2ip0(s,ip)
+char *s;
+struct ip_address *ip;
+{
+  unsigned long uip = 0;
+
+  uip += ip->d[0]; uip <<= 8;
+  uip += ip->d[1]; uip <<= 8;
+  uip += ip->d[2]; uip <<= 8;
+  uip += ip->d[3];
+
+  return fmt_2long0(s,uip,32);
+}
+
+
 unsigned int ip_scan(s,ip)
 char *s;
 struct ip_address *ip;
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ip.h ./ip.h
--- ../../netqmail-1.05-orig/netqmail-1.05/ip.h	1998-06-15 03:53:16.000000000 -0700
+++ ./ip.h	2006-01-05 15:03:43.339242808 -0800
@@ -4,7 +4,10 @@
 struct ip_address { unsigned char d[4]; } ;
 
 extern unsigned int ip_fmt();
+extern unsigned int fmt_ipn();		/* to n-bit masked ip address */
+extern unsigned int fmt_2ip0();		/* to a binary string with leading zeroes */
 #define IPFMT 19
+#define FMT_2IP 33
 extern unsigned int ip_scan();
 extern unsigned int ip_scanbracket();
 
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ipalloc.h ./ipalloc.h
--- ../../netqmail-1.05-orig/netqmail-1.05/ipalloc.h	1998-06-15 03:53:16.000000000 -0700
+++ ./ipalloc.h	2006-01-05 15:03:43.340242656 -0800
@@ -3,7 +3,15 @@
 
 #include "ip.h"
 
+#ifdef TLS
+# define IX_FQDN 1
+#endif
+
+#ifdef IX_FQDN
+struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ;
+#else
 struct ip_mx { struct ip_address ip; int pref; } ;
+#endif
 
 #include "gen_alloc.h"
 
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/lock.h ./lock.h
--- ../../netqmail-1.05-orig/netqmail-1.05/lock.h	1998-06-15 03:53:16.000000000 -0700
+++ ./lock.h	2006-01-05 15:03:43.341242504 -0800
@@ -5,4 +5,7 @@
 extern int lock_un();
 extern int lock_exnb();
 
+extern int lock_exfcntl();
+extern int lock_unfcntl();
+
 #endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/lock_exfcntl.c ./lock_exfcntl.c
--- ../../netqmail-1.05-orig/netqmail-1.05/lock_exfcntl.c	1969-12-31 16:00:00.000000000 -0800
+++ ./lock_exfcntl.c	2006-01-05 15:03:43.342242352 -0800
@@ -0,0 +1,16 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include "lock.h"
+
+int lock_exfcntl(fd)
+int fd;
+{
+  struct flock fl;
+
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start = 0;
+  fl.l_len = 0;
+
+  return fcntl(fd,F_SETLKW,&fl);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/lock_unfcntl.c ./lock_unfcntl.c
--- ../../netqmail-1.05-orig/netqmail-1.05/lock_unfcntl.c	1969-12-31 16:00:00.000000000 -0800
+++ ./lock_unfcntl.c	2006-01-05 15:03:43.343242200 -0800
@@ -0,0 +1,16 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include "lock.h"
+
+int lock_unfcntl(fd)
+int fd;
+{
+  struct flock fl;
+
+  fl.l_type = F_UNLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start = 0;
+  fl.l_len = 0;
+
+  return fcntl(fd,F_SETLKW,&fl);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirflags.c ./maildirflags.c
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirflags.c	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirflags.c	2006-01-05 15:03:43.344242048 -0800
@@ -0,0 +1,23 @@
+/*
+** Copyright 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include	<sys/types.h>
+#include	<string.h>
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+int maildir_hasflag(const char *filename, char flag)
+{
+	const char *p=strrchr(filename, '/');
+
+	if (p)
+		filename=p+1;
+
+	p=strrchr(p, ':');
+	if (p && strncmp(p, ":2,", 3) == 0 &&
+	    strchr(p+3, flag))
+		return (1);
+	return (0);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirgetquota.c ./maildirgetquota.c
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirgetquota.c	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirgetquota.c	2006-01-05 15:03:43.345241896 -0800
@@ -0,0 +1,50 @@
+/*
+** Copyright 1998 - 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include	"maildirgetquota.h"
+#include	"maildirmisc.h"
+#if	HAVE_UNISTD_H
+#include	<unistd.h>
+#endif
+#include	<stdlib.h>
+#include	<string.h>
+#include	<fcntl.h>
+#include	<sys/types.h>
+#include	<sys/stat.h>
+
+int	maildir_getquota(const char *dir, char buf[QUOTABUFSIZE])
+{
+char	*p;
+struct	stat	stat_buf;
+int	n;
+int	l;
+
+	p=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
+	if (!p)	return (-1);
+
+	strcat(strcpy(p, dir), "/maildirfolder");
+	if (stat(p, &stat_buf) == 0)
+	{
+		strcat(strcpy(p, dir), "/..");
+		n=maildir_getquota(p, buf);
+		free(p);
+		return (n);
+	}
+
+	strcat(strcpy(p, dir), "/maildirsize");
+	n=maildir_safeopen(p, O_RDONLY, 0);
+	free(p);
+	if (n < 0)	return (n);
+	if ((l=read(n, buf, QUOTABUFSIZE-1)) < 0)
+	{
+		close(n);
+		return (-1);
+	}
+	close(n);
+	for (n=0; n<l; n++)
+		if (buf[n] == '\n')	break;
+	buf[n]=0;
+	return (0);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirgetquota.h ./maildirgetquota.h
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirgetquota.h	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirgetquota.h	2006-01-05 15:03:43.346241744 -0800
@@ -0,0 +1,30 @@
+#ifndef	maildirgetquota_h
+#define	maildirgetquota_h
+
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+
+#include	<sys/types.h>
+#include	<stdio.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+static const char maildirgetquota_h_rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+#define	QUOTABUFSIZE	256
+
+int maildir_getquota(const char *, char [QUOTABUFSIZE]);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirmisc.h ./maildirmisc.h
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirmisc.h	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirmisc.h	2006-01-05 15:03:43.348241440 -0800
@@ -0,0 +1,145 @@
+#ifndef	maildirmisc_h
+#define	maildirmisc_h
+
+/*
+** Copyright 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+static const char maildirmisc_h_rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+/*
+**
+** Miscellaneous maildir-related code
+**
+*/
+
+/* Some special folders */
+
+#define	INBOX	"INBOX"
+#define	DRAFTS	"Drafts"
+#define	SENT	"Sent"
+#define	TRASH	"Trash"
+
+#define	SHAREDSUBDIR	"shared-folders"
+
+char *maildir_folderdir(const char *,		/* maildir */
+	const char *);				/* folder name */
+	/* Returns the directory corresponding to foldername (foldername is
+	** checked to make sure that it's a valid name, else we set errno
+	** to EINVAL, and return (0).
+	*/
+
+char *maildir_filename(const char *,		/* maildir */
+	const char *,				/* folder */
+	const char *);				/* filename */
+	/*
+	** Builds the filename to this message, suitable for opening.
+	** If the file doesn't appear to be there, search the maildir to
+	** see if someone changed the flags, and return the current filename.
+	*/
+
+int maildir_safeopen(const char *,		/* filename */
+	int,				/* mode */
+	int);				/* perm */
+
+/*
+**	Same arguments as open().  When we're accessing a shared maildir,
+**	prevent someone from playing cute and dumping a bunch of symlinks
+**	in there.  This function will open the indicate file only if the
+**	last component is not a symlink.
+**	This is implemented by opening the file with O_NONBLOCK (to prevent
+**	a DOS attack of someone pointing the symlink to a pipe, causing
+**	the open to hang), clearing O_NONBLOCK, then stat-int the file
+**	descriptor, lstating the filename, and making sure that dev/ino
+**	match.
+*/
+
+int maildir_semisafeopen(const char *,	/* filename */
+	int,				/* mode */
+	int);				/* perm */
+
+/*
+** Same thing, except that we allow ONE level of soft link indirection,
+** because we're reading from our own maildir, which points to the
+** message in the sharable maildir.
+*/
+
+int maildir_mkdir(const char *);	/* directory */
+/*
+** Create maildir including all subdirectories in the path (like mkdir -p)
+*/
+
+void maildir_purgetmp(const char *);		/* maildir */
+	/* purges old stuff out of tmp */
+
+void maildir_purge(const char *,		/* directory */
+	unsigned);				/* time_t to purge */
+
+void maildir_getnew(const char *,		/* maildir */
+	const char *);				/* folder */
+	/* move messages from new to cur */
+
+int maildir_deletefolder(const char *,		/* maildir */
+	const char *);				/* folder */
+	/* deletes a folder */
+
+int maildir_mddelete(const char *);	/* delete a maildir folder by path */
+
+void maildir_list_sharable(const char *,	/* maildir */
+	void (*)(const char *, void *),		/* callback function */
+	void *);				/* 2nd arg to callback func */
+	/* list sharable folders */
+
+int maildir_shared_subscribe(const char *,	/* maildir */
+		const char *);			/* folder */
+	/* subscribe to a shared folder */
+
+void maildir_list_shared(const char *,		/* maildir */
+	void (*)(const char *, void *),		/* callback function */
+	void *);			/* 2nd arg to the callback func */
+	/* list subscribed folders */
+
+int maildir_shared_unsubscribe(const char *,	/* maildir */
+		const char *);			/* folder */
+	/* unsubscribe from a shared folder */
+
+char *maildir_shareddir(const char *,		/* maildir */
+	const char *);				/* folder */
+	/*
+	** Validate and return a path to a shared folder.  folderdir must be
+	** a name of a valid shared folder.
+	*/
+
+void maildir_shared_sync(const char *);		/* maildir */
+	/* "sync" the shared folder */
+
+int maildir_sharedisro(const char *);		/* maildir */
+	/* maildir is a shared read-only folder */
+
+int maildir_unlinksharedmsg(const char *);	/* filename */
+	/* Remove a message from a shared folder */
+
+/* Internal function that reads a symlink */
+
+char *maildir_getlink(const char *);
+
+	/* Determine whether the maildir filename has a certain flag */
+
+int maildir_hasflag(const char *filename, char);
+
+#define	MAILDIR_DELETED(f)	maildir_hasflag((f), 'T')
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildiropen.c ./maildiropen.c
--- ../../netqmail-1.05-orig/netqmail-1.05/maildiropen.c	1969-12-31 16:00:00.000000000 -0800
+++ ./maildiropen.c	2006-01-05 15:03:43.349241288 -0800
@@ -0,0 +1,133 @@
+/*
+** Copyright 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<string.h>
+#include	<stdlib.h>
+#include	<time.h>
+#if	HAVE_UNISTD_H
+#include	<unistd.h>
+#endif
+#include	<stdio.h>
+#include	<ctype.h>
+#include	<errno.h>
+#include	<fcntl.h>
+
+#include	"maildirmisc.h"
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+char *maildir_getlink(const char *filename)
+{
+#if     HAVE_READLINK
+size_t	bufsiz;
+char	*buf;
+
+	bufsiz=0;
+	buf=0;
+
+	for (;;)
+	{
+	int	n;
+
+		if (buf)	free(buf);
+		bufsiz += 256;
+		if ((buf=malloc(bufsiz)) == 0)
+		{
+			perror("malloc");
+			return (0);
+		}
+		if ((n=readlink(filename, buf, bufsiz)) < 0)
+		{
+			free(buf);
+			return (0);
+		}
+		if (n < bufsiz)
+		{
+			buf[n]=0;
+			break;
+		}
+	}
+	return (buf);
+#else
+	return (0);
+#endif
+}
+
+int maildir_semisafeopen(const char *path, int mode, int perm)
+{
+
+#if	HAVE_READLINK
+
+char	*l=maildir_getlink(path);
+
+	if (l)
+	{
+	int	f;
+
+		if (*l != '/')
+		{
+		char	*q=malloc(strlen(path)+strlen(l)+2);
+		char	*s;
+
+			if (!q)
+			{
+				free(l);
+				return (-1);
+			}
+
+			strcpy(q, path);
+			if ((s=strchr(q, '/')) != 0)
+				s[1]=0;
+			else	*q=0;
+			strcat(q, l);
+			free(l);
+			l=q;
+		}
+
+		f=maildir_safeopen(l, mode, perm);
+
+		free(l);
+		return (f);
+	}
+#endif
+
+	return (maildir_safeopen(path, mode, perm));
+}
+		
+int maildir_safeopen(const char *path, int mode, int perm)
+{
+struct	stat	stat1, stat2;
+
+int	fd=open(path, mode
+#ifdef	O_NONBLOCK
+			| O_NONBLOCK
+#else
+			| O_NDELAY
+#endif
+				, perm);
+
+	if (fd < 0)	return (fd);
+	if (fcntl(fd, F_SETFL, (mode & O_APPEND)) || fstat(fd, &stat1)
+	    || lstat(path, &stat2))
+	{
+		close(fd);
+		return (-1);
+	}
+
+	if (stat1.st_dev != stat2.st_dev || stat1.st_ino != stat2.st_ino)
+	{
+		close(fd);
+		errno=ENOENT;
+		return (-1);
+	}
+
+	return (fd);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirparsequota.c ./maildirparsequota.c
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirparsequota.c	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirparsequota.c	2006-01-05 15:03:43.350241136 -0800
@@ -0,0 +1,44 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include	"maildirquota.h"
+#include	<stdlib.h>
+#include	<string.h>
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+int maildir_parsequota(const char *n, unsigned long *s)
+{
+const char *o;
+int	yes;
+
+	if ((o=strrchr(n, '/')) == 0)	o=n;
+
+	for (; *o; o++)
+		if (*o == ':')	break;
+	yes=0;
+	for ( ; o >= n; --o)
+	{
+		if (*o == '/')	break;
+
+		if (*o == ',' && o[1] == 'S' && o[2] == '=')
+		{
+			yes=1;
+			o += 3;
+			break;
+		}
+	}
+	if (yes)
+	{
+		*s=0;
+		while (*o >= '0' && *o <= '9')
+			*s= *s*10 + (*o++ - '0');
+		return (0);
+	}
+	return (-1);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirquota.c ./maildirquota.c
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirquota.c	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirquota.c	2006-01-05 15:03:43.352240832 -0800
@@ -0,0 +1,685 @@
+/*
+** Copyright 1998 - 2002 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+/* #if HAVE_DIRENT_H */
+#include <dirent.h>
+#define NAMLEN(dirent) strlen((dirent)->d_name)
+/* #else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#if HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#if HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#if HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif */
+#include	<sys/types.h>
+/* #if	HAVE_SYS_STAT_H */
+#include	<sys/stat.h>
+/* #endif */
+#include	<sys/uio.h>
+
+#include	"maildirquota.h"
+#include	"maildirmisc.h"
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include	<errno.h>
+/* #if	HAVE_FCNTL_H */
+#include	<fcntl.h>
+/* #endif */
+#if	HAVE_UNISTD_H
+#include	<unistd.h>
+#endif
+#include	<time.h>
+#include	"numlib.h"
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+/* Read the maildirsize file */
+
+int maildirsize_read(const char *filename,	/* The filename */
+	int *fdptr,	/* Keep the file descriptor open */
+	off_t *sizeptr,	/* Grand total of maildir size */
+	unsigned *cntptr, /* Grand total of message count */
+	unsigned *nlines, /* # of lines in maildirsize */
+	struct stat *statptr)	/* The stats on maildirsize */
+{
+char buf[5120];
+int f;
+char *p;
+unsigned l;
+int n;
+int first;
+
+	if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0)
+		return (-1);
+	p=buf;
+	l=sizeof(buf);
+
+	while (l)
+	{
+		n=read(f, p, l);
+		if (n < 0)
+		{
+			close(f);
+			return (-1);
+		}
+		if (n == 0)	break;
+		p += n;
+		l -= n;
+	}
+	if (l == 0 || fstat(f, statptr))	/* maildir too big */
+	{
+		close(f);
+		return (-1);
+	}
+
+	*sizeptr=0;
+	*cntptr=0;
+	*nlines=0;
+	*p=0;
+	p=buf;
+	first=1;
+	while (*p)
+	{
+	long n=0;
+	int c=0;
+	char	*q=p;
+
+		while (*p)
+			if (*p++ == '\n')
+			{
+				p[-1]=0;
+				break;
+			}
+
+		if (first)
+		{
+			first=0;
+			continue;
+		}
+		sscanf(q, "%ld %d", &n, &c);
+		*sizeptr += n;
+		*cntptr += c;
+		++ *nlines;
+	}
+	*fdptr=f;
+	return (0);
+}
+
+static char *makenewmaildirsizename(const char *, int *);
+static int countcurnew(const char *, time_t *, off_t *, unsigned *);
+static int countsubdir(const char *, const char *,
+		time_t *, off_t *, unsigned *);
+static int statcurnew(const char *, time_t *);
+static int statsubdir(const char *, const char *, time_t *);
+
+#define	MDQUOTA_SIZE	'S'	/* Total size of all messages in maildir */
+#define	MDQUOTA_BLOCKS	'B'	/* Total # of blocks for all messages in
+				maildir -- NOT IMPLEMENTED */
+#define	MDQUOTA_COUNT	'C'	/* Total number of messages in maildir */
+
+static int qcalc(off_t s, unsigned n, const char *quota, int *percentage)
+{
+off_t i;
+int	spercentage=0;
+int	npercentage=0;
+
+	errno=ENOSPC;
+	while (quota && *quota)
+	{
+		int x=1;
+
+		if (*quota < '0' || *quota > '9')
+		{
+			++quota;
+			continue;
+		}
+		i=0;
+		while (*quota >= '0' && *quota <= '9')
+			i=i*10 + (*quota++ - '0');
+		switch (*quota)	{
+		default:
+			if (i < s)
+			{
+				*percentage=100;
+				return (-1);
+			}
+
+			/*
+			** For huge quotas, over 20mb,
+			** divide numerator & denominator by 1024 to prevent
+			** an overflow when multiplying by 100
+			*/
+
+			x=1;
+			if (i > 20000000) x=1024;
+
+			spercentage = i ? (s/x) * 100 / (i/x):100;
+			break;
+		case 'C':
+
+			if (i < n)
+			{
+				*percentage=100;
+				return (-1);
+			}
+
+			/* Ditto */
+
+			x=1;
+			if (i > 20000000) x=1024;
+
+			npercentage = i ? ((off_t)n/x) * 100 / (i/x):100;
+			break;
+		}
+	}
+	*percentage = spercentage > npercentage ? spercentage:npercentage;
+	return (0);
+}
+
+static int	doaddquota(const char *, int, const char *, long, int, int);
+
+static int docheckquota(const char *dir,
+	int *maildirsize_fdptr,
+	const char *quota_type,
+	long xtra_size,
+	int xtra_cnt, int *percentage);
+
+
+int maildir_checkquota(const char *dir,
+	int *maildirsize_fdptr,
+	const char *quota_type,
+	long xtra_size,
+	int xtra_cnt)
+{
+int	dummy;
+
+	return (docheckquota(dir, maildirsize_fdptr, quota_type,
+		xtra_size, xtra_cnt, &dummy));
+}
+
+int maildir_readquota(const char *dir, const char *quota_type)
+{
+int	percentage=0;
+int	fd=-1;
+
+	(void)docheckquota(dir, &fd, quota_type, 0, 0, &percentage);
+	if (fd >= 0)
+		close(fd);
+	return (percentage);
+}
+
+static int docheckquota(const char *dir,
+	int *maildirsize_fdptr,
+	const char *quota_type,
+	long xtra_size,
+	int xtra_cnt,
+	int *percentage)
+{
+char	*checkfolder=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
+char	*newmaildirsizename;
+struct stat stat_buf;
+int	maildirsize_fd;
+off_t	maildirsize_size;
+unsigned maildirsize_cnt;
+unsigned maildirsize_nlines;
+int	n;
+time_t	tm;
+time_t	maxtime;
+DIR	*dirp;
+struct dirent *de;
+
+	if (checkfolder == 0)	return (-1);
+	*maildirsize_fdptr= -1;
+	strcat(strcpy(checkfolder, dir), "/maildirfolder");
+	if (stat(checkfolder, &stat_buf) == 0)	/* Go to parent */
+	{
+		strcat(strcpy(checkfolder, dir), "/..");
+		n=docheckquota(checkfolder, maildirsize_fdptr,
+			quota_type, xtra_size, xtra_cnt, percentage);
+		free(checkfolder);
+		return (n);
+	}
+	if (!quota_type || !*quota_type)	return (0);
+
+	strcat(strcpy(checkfolder, dir), "/maildirsize");
+	time(&tm);
+	if (maildirsize_read(checkfolder, &maildirsize_fd,
+		&maildirsize_size, &maildirsize_cnt,
+		&maildirsize_nlines, &stat_buf) == 0)
+	{
+		n=qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
+			quota_type, percentage);
+
+		if (n == 0)
+		{
+			free(checkfolder);
+			*maildirsize_fdptr=maildirsize_fd;
+			return (0);
+		}
+		close(maildirsize_fd);
+
+		if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60)
+			return (n);
+	}
+
+	maxtime=0;
+	maildirsize_size=0;
+	maildirsize_cnt=0;
+
+	if (countcurnew(dir, &maxtime, &maildirsize_size, &maildirsize_cnt))
+	{
+		free(checkfolder);
+		return (-1);
+	}
+
+	dirp=opendir(dir);
+	while (dirp && (de=readdir(dirp)) != 0)
+	{
+		if (countsubdir(dir, de->d_name, &maxtime, &maildirsize_size,
+			&maildirsize_cnt))
+		{
+			free(checkfolder);
+			closedir(dirp);
+			return (-1);
+		}
+	}
+	if (dirp)
+	{
+#if	CLOSEDIR_VOID
+		closedir(dirp);
+#else
+		if (closedir(dirp))
+		{
+			free(checkfolder);
+			return (-1);
+		}
+#endif
+	}
+
+	newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
+	if (!newmaildirsizename)
+	{
+		free(checkfolder);
+		return (-1);
+	}
+
+	*maildirsize_fdptr=maildirsize_fd;
+
+	if (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
+		maildirsize_cnt, 1))
+	{
+		unlink(newmaildirsizename);
+		free(newmaildirsizename);
+		close(maildirsize_fd);
+		*maildirsize_fdptr= -1;
+		free(checkfolder);
+		return (-1);
+	}
+
+	strcat(strcpy(checkfolder, dir), "/maildirsize");
+
+	if (rename(newmaildirsizename, checkfolder))
+	{
+		/* free(checkfolder); */
+		unlink(newmaildirsizename);
+		close(maildirsize_fd);
+		*maildirsize_fdptr= -1;
+	}
+	free(checkfolder);
+	free(newmaildirsizename);
+
+	tm=0;
+
+	if (statcurnew(dir, &tm))
+	{
+		close(maildirsize_fd);
+		*maildirsize_fdptr= -1;
+		return (-1);
+	}
+
+	dirp=opendir(dir);
+	while (dirp && (de=readdir(dirp)) != 0)
+	{
+		if (statsubdir(dir, de->d_name, &tm))
+		{
+			close(maildirsize_fd);
+			*maildirsize_fdptr= -1;
+			closedir(dirp);
+			return (-1);
+		}
+	}
+	if (dirp)
+	{
+#if	CLOSEDIR_VOID
+		closedir(dirp);
+#else
+		if (closedir(dirp))
+		{
+			close(maildirsize_fd);
+			*maildirsize_fdptr= -1;
+			return (-1);
+		}
+#endif
+	}
+
+	if (tm != maxtime)	/* Race condition, someone changed something */
+	{
+		errno=EAGAIN;
+		return (-1);
+	}
+
+	return (qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
+		quota_type, percentage));
+}
+
+int	maildir_addquota(const char *dir, int maildirsize_fd,
+	const char *quota_type, long maildirsize_size, int maildirsize_cnt)
+{
+	if (!quota_type || !*quota_type)	return (0);
+	return (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
+			maildirsize_cnt, 0));
+}
+
+static int doaddquota(const char *dir, int maildirsize_fd,
+	const char *quota_type, long maildirsize_size, int maildirsize_cnt,
+	int isnew)
+{
+union	{
+	char	buf[100];
+	struct stat stat_buf;
+	} u;				/* Scrooge */
+char	*newname2=0;
+char	*newmaildirsizename=0;
+struct	iovec	iov[3];
+int	niov;
+struct	iovec	*p;
+int	n;
+
+	niov=0;
+	if ( maildirsize_fd < 0)
+	{
+		newname2=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
+		if (!newname2)	return (-1);
+		strcat(strcpy(newname2, dir), "/maildirfolder");
+		if (stat(newname2, &u.stat_buf) == 0)
+		{
+			strcat(strcpy(newname2, dir), "/..");
+			n=doaddquota(newname2, maildirsize_fd, quota_type,
+					maildirsize_size, maildirsize_cnt,
+					isnew);
+			free(newname2);
+			return (n);
+		}
+
+		strcat(strcpy(newname2, dir), "/maildirsize");
+
+		if ((maildirsize_fd=maildir_safeopen(newname2,
+			O_RDWR|O_APPEND, 0644)) < 0)
+		{
+			newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
+			if (!newmaildirsizename)
+			{
+				free(newname2);
+				return (-1);
+			}
+
+			maildirsize_fd=maildir_safeopen(newmaildirsizename,
+				O_CREAT|O_RDWR|O_APPEND, 0644);
+
+			if (maildirsize_fd < 0)
+			{
+				free(newname2);
+				return (-1);
+			}
+			isnew=1;
+		}
+	}
+
+	if (isnew)
+	{
+		iov[0].iov_base=(caddr_t)quota_type;
+		iov[0].iov_len=strlen(quota_type);
+		iov[1].iov_base=(caddr_t)"\n";
+		iov[1].iov_len=1;
+		niov=2;
+	}
+
+
+	sprintf(u.buf, "%ld %d\n", maildirsize_size, maildirsize_cnt);
+	iov[niov].iov_base=(caddr_t)u.buf;
+	iov[niov].iov_len=strlen(u.buf);
+
+	p=iov;
+	++niov;
+	n=0;
+	while (niov)
+	{
+		if (n)
+		{
+			if (n < p->iov_len)
+			{
+				p->iov_base=
+					(caddr_t)((char *)p->iov_base + n);
+				p->iov_len -= n;
+			}
+			else
+			{
+				n -= p->iov_len;
+				++p;
+				--niov;
+				continue;
+			}
+		}
+
+		n=writev( maildirsize_fd, p, niov);
+
+		if (n <= 0)
+		{
+			if (newname2)
+			{
+				close(maildirsize_fd);
+				free(newname2);
+			}
+			return (-1);
+		}
+	}
+	if (newname2)
+	{
+		close(maildirsize_fd);
+
+		if (newmaildirsizename)
+		{
+			rename(newmaildirsizename, newname2);
+			free(newmaildirsizename);
+		}
+		free(newname2);
+	}
+	return (0);
+}
+
+/* New maildirsize is built in the tmp subdirectory */
+
+static char *makenewmaildirsizename(const char *dir, int *fd)
+{
+char	hostname[256];
+struct	stat stat_buf;
+time_t	t;
+char	*p;
+
+	hostname[0]=0;
+	hostname[sizeof(hostname)-1]=0;
+	gethostname(hostname, sizeof(hostname)-1);
+	p=(char *)malloc(strlen(dir)+strlen(hostname)+130);
+	if (!p)	return (0);
+
+	for (;;)
+	{
+	char	tbuf[NUMBUFSIZE];
+	char	pbuf[NUMBUFSIZE];
+
+		time(&t);
+		strcat(strcpy(p, dir), "/tmp/");
+		sprintf(p+strlen(p), "%s.%s_NeWmAiLdIrSiZe.%s",
+			str_time_t(t, tbuf),
+			str_pid_t(getpid(), pbuf), hostname);
+
+		if (stat( (const char *)p, &stat_buf) < 0 &&
+			(*fd=maildir_safeopen(p,
+				O_CREAT|O_RDWR|O_APPEND, 0644)) >= 0)
+			break;
+		sleep(3);
+	}
+	return (p);
+}
+
+static int statcurnew(const char *dir, time_t *maxtimestamp)
+{
+char	*p=(char *)malloc(strlen(dir)+5);
+struct	stat	stat_buf;
+
+	if (!p)	return (-1);
+	strcat(strcpy(p, dir), "/cur");
+	if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
+		*maxtimestamp=stat_buf.st_mtime;
+	strcat(strcpy(p, dir), "/new");
+	if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
+		*maxtimestamp=stat_buf.st_mtime;
+	free(p);
+	return (0);
+}
+
+static int statsubdir(const char *dir, const char *subdir, time_t *maxtime)
+{
+char	*p;
+int	n;
+
+	if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
+		strcmp(subdir, "..") == 0 || strcmp(subdir, "." TRASH) == 0)
+		return (0);
+
+	p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
+	if (!p)	return (-1);
+	strcat(strcat(strcpy(p, dir), "/"), subdir);
+	n=statcurnew(p, maxtime);
+	free(p);
+	return (n);
+}
+
+static int docount(const char *, time_t *, off_t *, unsigned *);
+
+static int countcurnew(const char *dir, time_t *maxtime,
+	off_t *sizep, unsigned *cntp)
+{
+char	*p=(char *)malloc(strlen(dir)+5);
+int	n;
+
+	if (!p)	return (-1);
+	strcat(strcpy(p, dir), "/new");
+	n=docount(p, maxtime, sizep, cntp);
+	if (n == 0)
+	{
+		strcat(strcpy(p, dir), "/cur");
+		n=docount(p, maxtime, sizep, cntp);
+	}
+	free(p);
+	return (n);
+}
+
+static int countsubdir(const char *dir, const char *subdir, time_t *maxtime,
+	off_t *sizep, unsigned *cntp)
+{
+char	*p;
+int	n;
+
+	if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
+		strcmp(subdir, "..") == 0 || strcmp(subdir, "." TRASH) == 0)
+		return (0);
+
+	p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
+	if (!p)	return (2);
+	strcat(strcat(strcpy(p, dir), "/"), subdir);
+	n=countcurnew(p, maxtime, sizep, cntp);
+	free(p);
+	return (n);
+}
+
+static int docount(const char *dir, time_t *dirstamp,
+	off_t *sizep, unsigned *cntp)
+{
+struct	stat	stat_buf;
+char	*p;
+DIR	*dirp;
+struct dirent *de;
+unsigned long	s;
+
+	if (stat(dir, &stat_buf))	return (0);	/* Ignore */
+	if (stat_buf.st_mtime > *dirstamp)	*dirstamp=stat_buf.st_mtime;
+	if ((dirp=opendir(dir)) == 0)	return (0);
+	while ((de=readdir(dirp)) != 0)
+	{
+	const char *n=de->d_name;
+
+		if (*n == '.')	continue;
+
+		/* PATCH - do not count msgs marked as deleted */
+
+		for ( ; *n; n++)
+		{
+			if (n[0] != ':' || n[1] != '2' ||
+				n[2] != ',')	continue;
+			n += 3;
+			while (*n >= 'A' && *n <= 'Z')
+			{
+				if (*n == 'T')	break;
+				++n;
+			}
+			break;
+		}
+		if (*n == 'T')	continue;
+		n=de->d_name;
+
+
+		if (maildir_parsequota(n, &s) == 0)
+			stat_buf.st_size=s;
+		else
+		{
+			p=(char *)malloc(strlen(dir)+strlen(n)+2);
+			if (!p)
+			{
+				closedir(dirp);
+				return (-1);
+			}
+			strcat(strcat(strcpy(p, dir), "/"), n);
+			if (stat(p, &stat_buf))
+			{
+				free(p);
+				continue;
+			}
+			free(p);
+		}
+		*sizep += stat_buf.st_size;
+		++*cntp;
+	}
+
+#if	CLOSEDIR_VOID
+	closedir(dirp);
+#else
+	if (closedir(dirp))
+		return (-1);
+#endif
+	return (0);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/maildirquota.h ./maildirquota.h
--- ../../netqmail-1.05-orig/netqmail-1.05/maildirquota.h	1969-12-31 16:00:00.000000000 -0800
+++ ./maildirquota.h	2006-01-05 15:03:43.354240528 -0800
@@ -0,0 +1,45 @@
+#ifndef	maildirquota_h
+#define	maildirquota_h
+
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+
+#include	<sys/types.h>
+#include	<stdio.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+static const char maildirquota_h_rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+int maildir_checkquota(const char *,	/* Pointer to directory */
+	int *,	/* Initialized to -1, or opened descriptor for maildirsize */
+	const char *,	/* The quota */
+	long,		/* Extra bytes planning to add/remove from maildir */
+	int);		/* Extra messages planning to add/remove from maildir */
+
+int maildir_addquota(const char *,	/* Pointer to the maildir */
+	int,	/* Must be the int pointed to by 2nd arg to checkquota */
+	const char *,	/* The quota */
+	long,	/* +/- bytes */
+	int);	/* +/- files */
+
+int maildir_readquota(const char *,	/* Directory */
+	const char *);			/* Quota, from getquota */
+
+int maildir_parsequota(const char *, unsigned long *);
+	/* Attempt to parse file size encoded in filename.  Returns 0 if
+	** parsed, non-zero if we didn't parse. */
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/numlib.h ./numlib.h
--- ../../netqmail-1.05-orig/netqmail-1.05/numlib.h	1969-12-31 16:00:00.000000000 -0800
+++ ./numlib.h	2006-01-05 15:03:43.355240376 -0800
@@ -0,0 +1,45 @@
+#ifndef	numlib_h
+#define	numlib_h
+
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+static const char numlib_h_rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+
+#include	<sys/types.h>
+#include	<time.h>
+
+#define	NUMBUFSIZE	60
+
+/* Convert various system types to decimal */
+
+char	*str_time_t(time_t, char *);
+char	*str_off_t(off_t, char *);
+char	*str_pid_t(pid_t, char *);
+char	*str_ino_t(ino_t, char *);
+char	*str_uid_t(uid_t, char *);
+char	*str_gid_t(gid_t, char *);
+char	*str_size_t(size_t, char *);
+
+char	*str_sizekb(unsigned long, char *);	/* X Kb or X Mb */
+
+/* Convert selected system types to hex */
+
+char	*strh_time_t(time_t, char *);
+char	*strh_pid_t(pid_t, char *);
+char	*strh_ino_t(ino_t, char *);
+
+#ifdef	__cplusplus
+}
+#endif
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/open.h ./open.h
--- ../../netqmail-1.05-orig/netqmail-1.05/open.h	1998-06-15 03:53:16.000000000 -0700
+++ ./open.h	2006-01-05 15:03:43.355240376 -0800
@@ -6,5 +6,6 @@
 extern int open_append();
 extern int open_trunc();
 extern int open_write();
+extern int open_rw();
 
 #endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/open_rw.c ./open_rw.c
--- ../../netqmail-1.05-orig/netqmail-1.05/open_rw.c	1969-12-31 16:00:00.000000000 -0800
+++ ./open_rw.c	2006-01-05 15:03:43.356240224 -0800
@@ -0,0 +1,6 @@
+#include <sys/types.h>
+#include <fcntl.h>
+#include "open.h"
+
+int open_rw(fn) char *fn;
+{ return open(fn,O_RDWR | O_CREAT); }
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/overmaildirquota.c ./overmaildirquota.c
--- ../../netqmail-1.05-orig/netqmail-1.05/overmaildirquota.c	1969-12-31 16:00:00.000000000 -0800
+++ ./overmaildirquota.c	2006-01-05 15:03:43.358239920 -0800
@@ -0,0 +1,42 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include        "maildirquota.h"
+#include        <stdlib.h>
+#include        <string.h>
+#include        <errno.h>
+#include        <sys/stat.h>
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+
+int user_over_maildirquota( const char *dir, const char *q)
+{
+struct  stat    stat_buf;
+int     quotafd;
+int     ret_value;
+
+        if (fstat(0, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) &&
+                stat_buf.st_size > 0 && *q)
+        {
+                if (maildir_checkquota(dir, &quotafd, q, stat_buf.st_size, 1)
+                        && errno != EAGAIN)
+                {
+                        if (quotafd >= 0)       close(quotafd);
+                        ret_value = 1;
+                } else {
+                        maildir_addquota(dir, quotafd, q, stat_buf.st_size, 1);
+                        if (quotafd >= 0)       close(quotafd);
+                        ret_value = 0;
+                }
+        } else {
+                ret_value = 0;
+        }
+
+        return(ret_value);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-control.9 ./qmail-control.9
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-control.9	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-control.9	2006-01-05 15:03:43.359239768 -0800
@@ -20,7 +20,11 @@
 
 Comments are allowed
 in
+.IR badhelo ,
 .IR badmailfrom ,
+.IR badmailfromnorelay ,
+.IR badmailto ,
+.IR badmailtonorelay ,
 .IR locals ,
 .IR percenthack ,
 .IR qmqpservers ,
@@ -40,14 +44,22 @@
 .ta 5c 10c
 control	default	used by
 
+.I badhelo	\fR(none)	\fRqmail-smtpd
 .I badmailfrom	\fR(none)	\fRqmail-smtpd
+.I badmailfromnorelay	\fR(none)	\fRqmail-smtpd
+.I badmailto	\fR(none)	\fRqmail-smtpd
+.I badmailtonorelay	\fR(none)	\fRqmail-smtpd
 .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
 .I bouncehost	\fIme	\fRqmail-send
+.I clientca.pem	\fR(none)	\fRqmail-smtpd
+.I clientcert.pem	\fR(none)	\fRqmail-remote
 .I concurrencylocal	\fR10	\fRqmail-send
 .I concurrencyremote	\fR20	\fRqmail-send
 .I defaultdomain	\fIme	\fRqmail-inject
 .I defaulthost	\fIme	\fRqmail-inject
 .I databytes	\fR0	\fRqmail-smtpd
+.I dh1024.pem	\fR(none)	\fRqmail-smtpd
+.I dh512.pem	\fR(none)	\fRqmail-smtpd
 .I doublebouncehost	\fIme	\fRqmail-send
 .I doublebounceto	\fRpostmaster	\fRqmail-send
 .I envnoathost	\fIme	\fRqmail-send
@@ -61,11 +73,22 @@
 .I qmqpservers	\fR(none)	\fRqmail-qmqpc
 .I queuelifetime	\fR604800	\fRqmail-send
 .I rcpthosts	\fR(none)	\fRqmail-smtpd
+.I rsa512.pem	\fR(none)	\fRqmail-smtpd
+.I servercert.pem	\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 spamt	\fR(none)	\fRqmail-smtpd
 .I timeoutconnect	\fR60	\fRqmail-remote
 .I timeoutremote	\fR1200	\fRqmail-remote
 .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
+.I tlsclients	\fR(none)	\fRqmail-smtpd
+.I tlsclientciphers	\fR(none)	\fRqmail-remote
+.I tlshosts/FQDN.pem	\fR(none)	\fRqmail-remote
+.I tlsserverciphers	\fR(none)	\fRqmail-smtpd
 .I virtualdomains	\fR(none)	\fRqmail-send
 .fi
 .RE
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-local.c ./qmail-local.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-local.c	2006-01-05 15:06:38.656590520 -0800
+++ ./qmail-local.c	2006-01-05 15:03:43.361239464 -0800
@@ -66,6 +66,7 @@
 
 char buf[1024];
 char outbuf[1024];
+#define QUOTABUFSIZE    256
 
 /* child process */
 
@@ -86,9 +87,15 @@
  int fd;
  substdio ss;
  substdio ssout;
+ char quotabuf[QUOTABUFSIZE];
 
  sig_alarmcatch(sigalrm);
  if (chdir(dir) == -1) { if (error_temp(errno)) _exit(1); _exit(2); }
+ if (maildir_getquota(dir, quotabuf) == 0) {
+  if (user_over_maildirquota(dir,quotabuf)==1) {
+   _exit(1);
+  }
+ }
  pid = getpid();
  host[0] = 0;
  gethostname(host,sizeof(host));
@@ -99,7 +106,10 @@
    s += fmt_str(s,"tmp/");
    s += fmt_ulong(s,time); *s++ = '.';
    s += fmt_ulong(s,pid); *s++ = '.';
-   s += fmt_strn(s,host,sizeof(host)); *s++ = 0;
+   s += fmt_strn(s,host,sizeof(host));
+   s += fmt_strn(s,",S=",sizeof(",S="));
+   if (fstat(0,&st) == -1) if (errno == error_noent) break;
+   s += fmt_ulong(s,st.st_size); *s++ = 0;
    if (stat(fntmptph,&st) == -1) if (errno == error_noent) break;
    /* really should never get to this point */
    if (loop == 2) _exit(1);
@@ -159,6 +169,7 @@
  switch(wait_exitcode(wstat))
   {
    case 0: break;
+   case 1: strerr_die1x(1, "User over quota. (#5.1.1)");
    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)");
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.0 ./qmail-newst.0
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.0	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-newst.0	2006-01-05 15:03:43.362239312 -0800
@@ -0,0 +1,40 @@
+qmail-newst(8)                                     qmail-newst(8)
+
+
+
+NAME
+       qmail-newst  -  prepare spamthrottle parameters for qmail-
+       smtpd
+
+SYNOPSIS
+       qmail-newst
+
+DESCRIPTION
+       qmail-newst   reads   the   spamthrottle   parameters   in
+       /var/qmail/control/spamt     and    writes    them    into
+       /var/qmail/control/spamt.cdb in a binary format suited for
+       quick access by qmail-smtpd.
+
+       If there is a problem with control/spamt, qmail-newst com-
+       plains and leaves control/spamt.cdb alone.
+
+       qmail-newst  ensures  that  control/spamt.cdb  is  updated
+       atomically,  so  qmail-smtpd  never has to wait for qmail-
+       newst to finish.  However, qmail-newst makes no attempt to
+       protect   against   two   simultaneous   updates  of  con-
+       trol/spamt.cdb.
+
+       The binary control/spamt.cdb  format  is  portable  across
+       machines.
+
+SEE ALSO
+       qmail-spamt(5), qmail-spamthrottle(5), qmail-smtpd(8)
+
+
+AUTHOR
+       Dale Woolridge, James Law, and Moto Kawasaki.  Contact the
+       authors via email: <spamthrottle@qmail.ca>.
+
+
+
+                                                   qmail-newst(8)
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.8 ./qmail-newst.8
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.8	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-newst.8	2006-01-05 15:03:43.363239160 -0800
@@ -0,0 +1,47 @@
+.TH qmail-newst 8
+.SH NAME
+qmail-newst \- prepare spamthrottle parameters for qmail-smtpd
+.SH SYNOPSIS
+.B qmail-newst
+.SH DESCRIPTION
+.B qmail-newst
+reads the spamthrottle parameters in
+.B /var/qmail/control/spamt
+and writes them into
+.B /var/qmail/control/spamt.cdb
+in a binary format suited
+for quick access by
+.BR qmail-smtpd .
+
+If there is a problem with
+.BR control/spamt ,
+.B qmail-newst
+complains and leaves
+.B control/spamt.cdb
+alone.
+
+.B qmail-newst
+ensures that
+.B control/spamt.cdb
+is updated atomically,
+so
+.B qmail-smtpd
+never has to wait for
+.B qmail-newst
+to finish.
+However,
+.B qmail-newst
+makes no attempt to protect against two simultaneous updates of
+.BR control/spamt.cdb .
+
+The binary
+.B control/spamt.cdb
+format is portable across machines.
+.SH "SEE ALSO"
+qmail-spamt(5),
+qmail-spamthrottle(5),
+qmail-smtpd(8)
+
+.SH AUTHOR
+Dale Woolridge, James Law, and Moto Kawasaki.  Contact the authors
+via email: <spamthrottle@qmail.ca>.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.9 ./qmail-newst.9
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.9	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-newst.9	2006-01-05 15:03:43.364239008 -0800
@@ -0,0 +1,47 @@
+.TH qmail-newst 8
+.SH NAME
+qmail-newst \- prepare spamthrottle parameters for qmail-smtpd
+.SH SYNOPSIS
+.B qmail-newst
+.SH DESCRIPTION
+.B qmail-newst
+reads the spamthrottle parameters in
+.B QMAILHOME/control/spamt
+and writes them into
+.B QMAILHOME/control/spamt.cdb
+in a binary format suited
+for quick access by
+.BR qmail-smtpd .
+
+If there is a problem with
+.BR control/spamt ,
+.B qmail-newst
+complains and leaves
+.B control/spamt.cdb
+alone.
+
+.B qmail-newst
+ensures that
+.B control/spamt.cdb
+is updated atomically,
+so
+.B qmail-smtpd
+never has to wait for
+.B qmail-newst
+to finish.
+However,
+.B qmail-newst
+makes no attempt to protect against two simultaneous updates of
+.BR control/spamt.cdb .
+
+The binary
+.B control/spamt.cdb
+format is portable across machines.
+.SH "SEE ALSO"
+qmail-spamt(5),
+qmail-spamthrottle(5),
+qmail-smtpd(8)
+
+.SH AUTHOR
+Dale Woolridge, James Law, and Moto Kawasaki.  Contact the authors
+via email: <spamthrottle@qmail.ca>.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.c ./qmail-newst.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-newst.c	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-newst.c	2006-01-05 15:03:43.365238856 -0800
@@ -0,0 +1,185 @@
+#include "stralloc.h"
+#include "subfd.h"
+#include "getln.h"
+#include "substdio.h"
+#include "cdbmss.h"
+#include "exit.h"
+#include "readwrite.h"
+#include "open.h"
+#include "error.h"
+#include "case.h"
+#include "ip.h"
+#include "fmt.h"
+#include "auto_qmail.h"
+
+
+/*
+ * this is pretty much a complete ripoff of qmail-newu.c
+ */
+
+/*
+ * spamt format is:
+ * <network>:dir:st:stmax:flush:rcpt:tg:tg_resp:
+ * fields left empty are "inherited" from less restrictive matches
+ * and an empty entry is the least restrictive network (default settings)
+ */
+
+void die_temp() { _exit(111); }
+
+void die_chdir()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to chdir\n");
+  die_temp();
+}
+void die_nomem()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: out of memory\n");
+  die_temp();
+}
+void die_opena()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to open control/spamt\n");
+  die_temp();
+}
+void die_reada()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to read control/spamt\n");
+  die_temp();
+}
+void die_format()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: bad format in control/spamt\n");
+  die_temp();
+}
+void die_opent()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to open control/spamt.tmp\n");
+  die_temp();
+}
+void die_writet()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to write control/spamt.tmp\n");
+  die_temp();
+}
+void die_rename()
+{
+  substdio_putsflush(subfderr,"qmail-newst: fatal: unable to move control/spamt.tmp to control/spamt.cdb\n");
+  die_temp();
+}
+
+struct cdbmss cdbmss;
+stralloc key = {0};
+stralloc data = {0};
+
+char inbuf[1024];
+substdio ssin;
+
+int fd;
+int fdtemp;
+
+stralloc line = {0};
+int match;
+
+void makedata(sa)
+stralloc *sa;
+{
+  int i;
+  int numcolons = 0;
+
+  for (i = 0;i < sa->len;++i)
+    if (sa->s[i] == ':') {
+      sa->s[i] = 0;
+      if (++numcolons == 7)
+	break;
+    }
+
+  sa->len = i;
+
+  if (numcolons < 7) die_format();
+}
+ 
+
+void main()
+{
+  int i;
+  int j;
+  unsigned int numbits;
+  unsigned long u;
+  unsigned long ipbits;
+  struct ip_address ip;
+  unsigned long uip;
+  char str2ip[FMT_2IP];
+  stralloc defdata = {0};
+
+  umask(033);
+  if (chdir(auto_qmail) == -1) die_chdir();
+
+  if (!stralloc_copyb(&defdata,"\0\0\0\0\0\0\0",7)) die_nomem();
+
+  fd = open_read("control/spamt");
+  if (fd == -1) die_opena();
+
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+
+  fdtemp = open_trunc("control/spamt.tmp");
+  if (fdtemp == -1) die_opent();
+
+  if (cdbmss_start(&cdbmss,fdtemp) == -1) die_writet();
+
+  ipbits = 0;
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') != 0) die_reada();
+    if (line.len && (line.s[0] == '.')) break;
+    if (!match) die_format();
+    if (line.len && (line.s[0] == '#')) continue;
+
+    if (byte_chr(line.s,line.len,'\0') < line.len) die_format();
+    i = byte_chr(line.s,line.len,':');
+    if (i == line.len) die_format();
+    if (i == 0) {
+      if (!stralloc_copyb(&defdata,line.s + 1,line.len - 1)) die_nomem() ;
+      makedata(&defdata);
+    }
+    else {
+      numbits = 32;
+
+      j = ip_scan(line.s,&ip);
+      if (!j) die_format();
+
+      if (j < i) {
+	if (line.s[j] != '/') die_format();
+	scan_ulong(line.s + j + 1,&u);
+	numbits = u;
+	if (numbits == 0) die_format();
+	numbits = numbits % 32;
+	if (numbits == 0) numbits = 32;
+      }
+
+      str2ip[fmt_2ip0(str2ip,&ip)] = 0;
+
+      if (!stralloc_copyb(&key,str2ip,numbits)) die_nomem();
+      if (!stralloc_0(&key)) die_nomem();
+
+      uip = 1 << (numbits - 1);
+      ipbits |= uip;
+
+      if (!stralloc_copyb(&data,&uip,4)) die_nomem();
+      if (!stralloc_catb(&data,line.s + i + 1,line.len - i - 1)) die_nomem();
+      makedata(&data);
+
+      if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_writet();
+    }
+  }
+
+  if (!stralloc_copyb(&data,&ipbits,4)) die_nomem();
+  if (!stralloc_cat(&data,&defdata)) die_nomem();
+
+  if (cdbmss_add(&cdbmss,"",0,data.s,data.len) == -1) die_writet();
+
+  if (cdbmss_finish(&cdbmss) == -1) die_writet();
+  if (fsync(fdtemp) == -1) die_writet();
+  if (close(fdtemp) == -1) die_writet(); /* NFS stupidity */
+  if (rename("control/spamt.tmp","control/spamt.cdb") == -1) die_rename();
+
+  _exit(0);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-pop3d.c ./qmail-pop3d.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-pop3d.c	2006-01-05 15:06:38.658590216 -0800
+++ ./qmail-pop3d.c	2006-01-05 15:03:43.367238552 -0800
@@ -16,6 +16,11 @@
 #include "readwrite.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
+#include <errno.h>
+#include "maildirquota.h"
+#include "maildirmisc.h"
+
+#define QUOTABUFSIZE 256
 
 void die() { _exit(0); }
 
@@ -45,19 +50,15 @@
 {
   substdio_put(&ssout,buf,len);
 }
-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");
+  substdio_puts(&ssout,"-ERR ");
+  substdio_puts(&ssout,s);
+  substdio_puts(&ssout,"\r\n");
   flush();
 }
 
@@ -73,7 +74,7 @@
 void err_nosuch() { err("unable to open that message"); }
 void err_nounlink() { err("unable to unlink all deleted messages"); }
 
-void okay(arg) char *arg; { puts("+OK \r\n"); flush(); }
+void okay() { substdio_puts(&ssout,"+OK \r\n"); flush(); }
 
 void printfn(fn) char *fn;
 {
@@ -153,11 +154,11 @@
  
   total = 0;
   for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size;
-  puts("+OK ");
+  substdio_puts(&ssout,"+OK ");
   put(strnum,fmt_uint(strnum,numm));
-  puts(" ");
+  substdio_puts(&ssout," ");
   put(strnum,fmt_ulong(strnum,total));
-  puts("\r\n");
+  substdio_puts(&ssout,"\r\n");
   flush();
 }
 
@@ -171,18 +172,41 @@
 
 void pop3_last(arg) char *arg;
 {
-  puts("+OK ");
+  substdio_puts(&ssout,"+OK ");
   put(strnum,fmt_uint(strnum,last));
-  puts("\r\n");
+  substdio_puts(&ssout,"\r\n");
   flush();
 }
 
 void pop3_quit(arg) char *arg;
 {
   int i;
+  char quotabuf[QUOTABUFSIZE];
+  int has_quota=maildir_getquota(".", quotabuf);
+
+  long deleted_bytes=0;
+  long deleted_messages=0;
+
   for (i = 0;i < numm;++i)
     if (m[i].flagdeleted) {
-      if (unlink(m[i].fn) == -1) err_nounlink();
+      unsigned long un=0;
+      const char *filename=m[i].fn;
+      if (has_quota == 0 && !MAILDIR_DELETED(filename)) {
+          if (maildir_parsequota(filename, &un)) {
+              struct stat stat_buf;
+
+              if (stat(filename, &stat_buf) == 0)
+                  un=stat_buf.st_size;
+          }
+      }
+      if (unlink(m[i].fn) == -1) {
+          err_nounlink();
+          un=0;
+      }
+      if (un) {
+          deleted_bytes -= un;
+          deleted_messages -= 1;
+      }
     }
     else
       if (str_start(m[i].fn,"new/")) {
@@ -192,6 +216,21 @@
 	if (!stralloc_0(&line)) die_nomem();
 	rename(m[i].fn,line.s); /* if it fails, bummer */
       }
+
+    if (deleted_messages < 0) {
+        int quotafd;
+
+        if (maildir_checkquota(".", &quotafd, quotabuf, deleted_bytes,
+                               deleted_messages) && errno != EAGAIN &&
+                               deleted_bytes >= 0)
+            {
+                if (quotafd >= 0) close (quotafd);
+            } else {
+                 maildir_addquota(".", quotafd, quotabuf,
+                                 deleted_bytes, deleted_messages);
+                 if (quotafd >= 0) close(quotafd);
+            }
+        }
   okay(0);
   die();
 }
@@ -222,10 +261,10 @@
 int flaguidl;
 {
   put(strnum,fmt_uint(strnum,i + 1));
-  puts(" ");
+  substdio_puts(&ssout," ");
   if (flaguidl) printfn(m[i].fn);
   else put(strnum,fmt_ulong(strnum,m[i].size));
-  puts("\r\n");
+  substdio_puts(&ssout,"\r\n");
 }
 
 void dolisting(arg,flaguidl) char *arg; int flaguidl;
@@ -234,7 +273,7 @@
   if (*arg) {
     i = msgno(arg);
     if (i == -1) return;
-    puts("+OK ");
+    substdio_puts(&ssout,"+OK ");
     list(i,flaguidl);
   }
   else {
@@ -242,7 +281,7 @@
     for (i = 0;i < numm;++i)
       if (!m[i].flagdeleted)
 	list(i,flaguidl);
-    puts(".\r\n");
+    substdio_puts(&ssout,".\r\n");
   }
   flush();
 }
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.8 ./qmail-remote.8
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.8	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-remote.8	2006-01-05 15:03:43.368238400 -0800
@@ -114,6 +114,10 @@
 always exits zero.
 .SH "CONTROL FILES"
 .TP 5
+.I clientcert.pem
+SSL certificate that is used to authenticate with the remote server
+during a TLS session.
+.TP 5
 .I helohost
 Current host name,
 for use solely in saying hello to the remote SMTP server.
@@ -123,6 +127,16 @@
 otherwise
 .B qmail-remote
 refuses to run.
+
+.TP 5
+.I notlshosts/<FQDN>
+.B qmail-remote
+will not try TLS on servers for which this file exists
+.RB ( <FQDN>
+is the fully-qualified domain name of the server). 
+.IR (tlshosts/<FQDN>.pem 
+takes precedence over this file however).
+
 .TP 5
 .I smtproutes
 Artificial SMTP routes.
@@ -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,33 @@
 .B qmail-remote
 will wait for each response from the remote SMTP server.
 Default: 1200.
+
+.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 TLS 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.
+
+.TP 5
+.I tlshosts/exhaustivelist
+if this file exists
+no TLS will be tried on hosts other than those for which a file
+.B tlshosts/<FQDN>.pem
+exists.
+
 .SH "SEE ALSO"
 addresses(5),
 envelopes(5),
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.c ./qmail-remote.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-remote.c	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-remote.c	2006-01-05 15:08:14.803973896 -0800
@@ -48,6 +48,17 @@
 
 struct ip_address partner;
 
+#ifdef TLS
+# include <sys/stat.h>
+# include "tls.h"
+# include "ssl_timeoutio.h"
+# include <openssl/x509v3.h>
+# define EHLO 1
+
+int tls_init();
+const char *ssl_err_str = 0;
+#endif 
+
 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); }
@@ -99,6 +110,9 @@
   outhost();
   out(" but connection died. ");
   if (flagcritical) out("Possible duplicate! ");
+#ifdef TLS
+  if (ssl_err_str) { out(ssl_err_str); out(" "); }
+#endif
   out("(#4.4.2)\n");
   zerodie();
 }
@@ -110,6 +124,12 @@
 int saferead(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
+#ifdef TLS
+  if (ssl) {
+    r = ssl_timeoutread(timeout, smtpfd, smtpfd, ssl, buf, len);
+    if (r < 0) ssl_err_str = ssl_error_str();
+  } else
+#endif
   r = timeoutread(timeout,smtpfd,buf,len);
   if (r <= 0) dropped();
   return r;
@@ -117,6 +137,12 @@
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
+#ifdef TLS
+  if (ssl) {
+    r = ssl_timeoutwrite(timeout, smtpfd, smtpfd, ssl, buf, len);
+    if (r < 0) ssl_err_str = ssl_error_str();
+  } else
+#endif 
   r = timeoutwrite(timeout,smtpfd,buf,len);
   if (r <= 0) dropped();
   return r;
@@ -163,6 +189,65 @@
   return code;
 }
 
+#ifdef EHLO
+saa ehlokw = {0}; /* list of EHLO keywords and parameters */
+int maxehlokwlen = 0;
+
+unsigned long ehlo()
+{
+  stralloc *sa;
+  char *s, *e, *p;
+  unsigned long code;
+
+  if (ehlokw.len > maxehlokwlen) maxehlokwlen = ehlokw.len;
+  ehlokw.len = 0;
+
+# ifdef MXPS
+  if (type == 's') return 0;
+# endif
+
+  substdio_puts(&smtpto, "EHLO ");
+  substdio_put(&smtpto, helohost.s, helohost.len);
+  substdio_puts(&smtpto, "\r\n");
+  substdio_flush(&smtpto);
+
+  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)
+  {
+    int wasspace = 0;
+
+    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 (!wasspace)
+           if (!stralloc_catb(sa, s, p - s) || !stralloc_0(sa)) temp_nomem();
+         if (*p == '\n') break;
+         wasspace = 1;
+       } else if (wasspace == 1) {
+         wasspace = 0;
+         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;
+}
+#endif
+
 void outsmtptext()
 {
   int i; 
@@ -179,6 +264,11 @@
 char *prepend;
 char *append;
 {
+#ifdef TLS
+  /* shouldn't talk to the client unless in an appropriate state */
+  int state = ssl ? ssl->state : SSL_ST_BEFORE;
+  if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE))
+#endif
   substdio_putsflush(&smtpto,"QUIT\r\n");
   /* waiting for remote side is just too ridiculous */
   out(prepend);
@@ -186,6 +276,30 @@
   out(append);
   out(".\n");
   outsmtptext();
+
+#if defined(TLS) && defined(DEBUG)
+  if (ssl) {
+    X509 *peercert;
+
+    out("STARTTLS proto="); out(SSL_get_version(ssl));
+    out("; cipher="); out(SSL_get_cipher(ssl));
+
+    /* we want certificate details */
+    if (peercert = SSL_get_peer_certificate(ssl)) {
+      char *str;
+
+      str = X509_NAME_oneline(X509_get_subject_name(peercert), NULL, 0);
+      out("; subject="); out(str); OPENSSL_free(str);
+
+      str = X509_NAME_oneline(X509_get_issuer_name(peercert), NULL, 0);
+      out("; issuer="); out(str); OPENSSL_free(str);
+
+      X509_free(peercert);
+    }
+    out(";\n");
+  }
+#endif
+
   zerodie();
 }
 
@@ -214,6 +328,194 @@
   substdio_flush(&smtpto);
 }
 
+#ifdef TLS
+char *partner_fqdn = 0;
+
+# define TLS_QUIT quit(ssl ? "; connected to " : "; connecting to ", "")
+void tls_quit(const char *s1, const char *s2)
+{
+  out(s1); if (s2) { out(": "); out(s2); } TLS_QUIT;
+}
+# define tls_quit_error(s) tls_quit(s, ssl_error())
+
+int match_partner(const char *s, int len)
+{
+  if (!case_diffb(partner_fqdn, len, s) && !partner_fqdn[len]) return 1;
+  /* we also match if the name is *.domainname */
+  if (*s == '*') {
+    const char *domain = partner_fqdn + str_chr(partner_fqdn, '.');
+    if (!case_diffb(domain, --len, ++s) && !domain[len]) return 1;
+  }
+  return 0;
+}
+
+/* don't want to fail handshake if certificate can't be verified */
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
+
+int tls_init()
+{
+  int i;
+  SSL *myssl;
+  SSL_CTX *ctx;
+  stralloc saciphers = {0};
+  const char *ciphers, *servercert = 0;
+
+  if (partner_fqdn) {
+    struct stat st;
+    stralloc tmp = {0};
+    if (!stralloc_copys(&tmp, "control/tlshosts/")
+      || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn))
+      || !stralloc_catb(&tmp, ".pem", 5)) temp_nomem();
+    if (stat(tmp.s, &st) == 0) 
+      servercert = tmp.s;
+    else {
+      if (!stralloc_copys(&tmp, "control/notlshosts/")
+        || !stralloc_catb(&tmp, partner_fqdn, str_len(partner_fqdn)+1))
+        temp_nomem();
+      if ((stat("control/tlshosts/exhaustivelist", &st) == 0) ||
+	  (stat(tmp.s, &st) == 0)) {
+         alloc_free(tmp.s);
+         return 0;
+      }
+      alloc_free(tmp.s);
+    }
+  }
+ 
+  if (!smtps) {
+    stralloc *sa = ehlokw.sa;
+    unsigned int len = ehlokw.len;
+    /* look for STARTTLS among EHLO keywords */
+    for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
+    if (!len) {
+      if (!servercert) return 0;
+      out("ZNo TLS achieved while "); out(servercert);
+      out(" exists"); smtptext.len = 0; TLS_QUIT;
+    }
+  }
+
+  SSL_library_init();
+  ctx = SSL_CTX_new(SSLv23_client_method());
+  if (!ctx) {
+    if (!smtps && !servercert) return 0;
+    smtptext.len = 0;
+    tls_quit_error("ZTLS error initializing ctx");
+  }
+
+  if (servercert) {
+    if (!SSL_CTX_load_verify_locations(ctx, servercert, NULL)) {
+      SSL_CTX_free(ctx);
+      smtptext.len = 0;
+      out("ZTLS unable to load "); tls_quit_error(servercert);
+    }
+    /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
+    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);
+  }
+
+  /* let the other side complain if it needs a cert and we don't have one */
+# define CLIENTCERT "control/clientcert.pem"
+  if (SSL_CTX_use_certificate_chain_file(ctx, CLIENTCERT))
+    SSL_CTX_use_RSAPrivateKey_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM);
+# undef CLIENTCERT
+
+  myssl = SSL_new(ctx);
+  SSL_CTX_free(ctx);
+  if (!myssl) {
+    if (!smtps && !servercert) return 0;
+    smtptext.len = 0;
+    tls_quit_error("ZTLS error initializing ssl");
+  }
+
+  if (!smtps) substdio_putsflush(&smtpto, "STARTTLS\r\n");
+
+  /* while the server is preparing a responce, do something else */
+  if (control_readfile(&saciphers, "control/tlsclientciphers", 0) == -1)
+    { SSL_free(myssl); temp_control(); }
+  if (saciphers.len) {
+    for (i = 0; i < saciphers.len - 1; ++i)
+      if (!saciphers.s[i]) saciphers.s[i] = ':';
+    ciphers = saciphers.s;
+  }
+  else ciphers = "DEFAULT";
+  SSL_set_cipher_list(myssl, ciphers);
+  alloc_free(saciphers.s);
+
+  /* SSL_set_options(myssl, SSL_OP_NO_TLSv1); */
+  SSL_set_fd(myssl, smtpfd);
+
+  /* read the responce to STARTTLS */
+  if (!smtps) {
+    if (smtpcode() != 220) {
+      SSL_free(myssl);
+      if (!servercert) return 0;
+      out("ZSTARTTLS rejected while ");
+      out(servercert); out(" exists"); TLS_QUIT;
+    }
+    smtptext.len = 0;
+  }
+
+  ssl = myssl;
+  if (ssl_timeoutconn(timeout, smtpfd, smtpfd, ssl) <= 0)
+    tls_quit("ZTLS connect failed", ssl_error_str());
+
+  if (servercert) {
+    X509 *peercert;
+    STACK_OF(GENERAL_NAME) *gens;
+
+    int r = SSL_get_verify_result(ssl);
+    if (r != X509_V_OK) {
+      out("ZTLS unable to verify server with ");
+      tls_quit(servercert, X509_verify_cert_error_string(r));
+    }
+    alloc_free(servercert);
+
+    peercert = SSL_get_peer_certificate(ssl);
+    if (!peercert) {
+      out("ZTLS unable to verify server ");
+      tls_quit(partner_fqdn, "no certificate provided");
+    }
+
+    /* RFC 2595 section 2.4: find a matching name
+     * first find a match among alternative names */
+    gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0);
+    if (gens) {
+      for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i)
+      {
+        const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
+        if (gn->type == GEN_DNS)
+          if (match_partner(gn->d.ia5->data, gn->d.ia5->length)) break;
+      }
+      sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+    }
+
+    /* no alternative name matched, look up commonName */
+    if (!gens || i >= r) {
+      stralloc peer = {0};
+      X509_NAME *subj = X509_get_subject_name(peercert);
+      i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1);
+      if (i >= 0) {
+        const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value;
+        if (s) { peer.len = s->length; peer.s = s->data; }
+      }
+      if (peer.len <= 0) {
+        out("ZTLS unable to verify server ");
+        tls_quit(partner_fqdn, "certificate contains no valid commonName");
+      }
+      if (!match_partner(peer.s, peer.len)) {
+        out("ZTLS unable to verify server "); out(partner_fqdn);
+        out(": received certificate for "); outsafe(&peer); TLS_QUIT;
+      }
+    }
+
+    X509_free(peercert);
+  }
+
+  if (smtps) if (smtpcode() != 220)
+    quit("ZTLS Connected to "," but greeting failed");
+
+  return 1;
+}
+#endif
+
 stralloc recip = {0};
 
 void smtp()
@@ -222,14 +524,53 @@
   int flagbother;
   int i;
  
+#ifndef PORT_SMTP
+  /* the qmtpc patch uses smtp_port and undefines PORT_SMTP */
+# define port smtp_port
+#endif
+
+#ifdef TLS
+# ifdef MXPS
+  if (type == 'S') smtps = 1;
+  else if (type != 's')
+# endif
+    if (port == 465) smtps = 1;
+  if (!smtps)
+#endif
+ 
   if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
  
+#ifdef EHLO
+# ifdef TLS
+  if (!smtps)
+# endif
+  code = ehlo();
+
+# ifdef TLS
+  if (tls_init())
+    /* RFC2487 says we should issue EHLO (even if we might not need
+     * extensions); at the same time, it does not prohibit a server
+     * to reject the EHLO and make us fallback to HELO */
+    code = ehlo();
+# endif
+
+  if (code == 250) {
+    /* add EHLO response checks here */
+
+    /* and if EHLO failed, use HELO */
+  } else {
+#endif
+ 
   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");
  
+#ifdef EHLO
+  }
+#endif
+ 
   substdio_puts(&smtpto,"MAIL FROM:<");
   substdio_put(&smtpto,sender.s,sender.len);
   substdio_puts(&smtpto,">\r\n");
@@ -417,6 +758,9 @@
     if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
       tcpto_err(&ip.ix[i].ip,0);
       partner = ip.ix[i].ip;
+#ifdef TLS
+      partner_fqdn = ip.ix[i].fqdn;
+#endif
       smtp(); /* does not return */
     }
     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-send.c ./qmail-send.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-send.c	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-send.c	2006-01-05 15:03:43.374237488 -0800
@@ -262,6 +262,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();
@@ -906,41 +908,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;
@@ -1544,7 +1547,7 @@
  numjobs = 0;
  for (c = 0;c < CHANNELS;++c)
   {
-   char ch;
+   char ch, ch1;
    int u;
    int r;
    do
@@ -1552,7 +1555,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];
   }
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-showctl.c ./qmail-showctl.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-showctl.c	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-showctl.c	2006-01-05 15:03:43.376237184 -0800
@@ -9,12 +9,15 @@
 #include "constmap.h"
 #include "stralloc.h"
 #include "direntry.h"
+#include "spam.h"
+#include "uint32.h"
 #include "auto_uids.h"
 #include "auto_qmail.h"
 #include "auto_break.h"
 #include "auto_patrn.h"
 #include "auto_spawn.h"
 #include "auto_split.h"
+#include "spf.h"
 
 stralloc me = {0};
 int meok;
@@ -136,6 +139,130 @@
   }
 }
 
+void do_spam()
+{
+  struct stat st;
+  struct stat stcdb;
+  uint32 dlen;
+  stralloc data = {0};
+  int i;
+  int r;
+  int fd;
+  struct spam_t spamt = spam_t_init(0,0);
+  unsigned int uip;
+
+  substdio_puts(subfdout,"\nspamt/spamt.cdb: ");
+  if (stat("spamt",&st) == -1)
+    if (stat("spamt.cdb",&stcdb) == -1)
+      substdio_puts(subfdout,"(Default.) No effect.\n");
+    else
+      substdio_puts(subfdout,"Oops! spamt.cdb exists but spamt doesn't (Spam throttling active).\n");
+  else
+    if (stat("spamt.cdb",&stcdb) == -1)
+      substdio_puts(subfdout,"Oops! spamt exists but spamt.cdb doesn't (No effect).\n");
+    else
+      if (st.st_mtime > stcdb.st_mtime)
+        substdio_puts(subfdout,"Oops! spamt.cdb is older than spamt.\n");
+      else
+        substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n");
+
+  fd = open_read("spamt.cdb");
+  if (fd == -1) return;
+
+  substdio_puts(subfdout,"\nspamt.cdb (defaults): ");
+
+  r = cdb_seek(fd,"",0,&dlen);
+  if (r != 1)
+  {
+    substdio_puts(subfdout,"No default entry (Spam throttling inactive).\n");
+    return;
+  }
+
+  if (!stralloc_ready(&data,(unsigned int) dlen))
+  {
+    substdio_puts(subfdout,"Unknown (temporary error).\n");
+    return;
+  }
+  data.len = dlen;
+  if (cdb_bread(fd,data.s,data.len) == -1)
+  {
+    substdio_puts(subfdout,"Unknown (unknown error...try running qmail-newst).\n");
+    return;
+  }
+
+  /* get the ipbits block from this key */
+  byte_copy(&uip,4,data.s);
+  /* then populate the spam_t (defaults) */
+  if (spam_get(&spamt,data.s + 4,data.len - 4) == -1)
+  {
+    substdio_puts(subfdout,"Unknown (unknown error...try running qmail-newst).\n");
+    return;
+  }
+
+  substdio_puts(subfdout,"\n\tthrottle constant: ");
+  if (spamt.throttle) {
+    substdio_put(subfdout,num,fmt_uint(num,spamt.throttle));
+    substdio_puts(subfdout,"ms");
+  } else
+    substdio_puts(subfdout,"none (spam throttling not active)");
+
+  substdio_puts(subfdout,"\n\tthrottle max: ");
+  if (spamt.max) {
+    substdio_put(subfdout,num,fmt_uint(num,spamt.max));
+    substdio_puts(subfdout,"ms");
+  } else
+    substdio_puts(subfdout,"no maximum");
+
+  substdio_puts(subfdout,"\n\treasonable recipient count: ");
+  if (spamt.reasonablercpt)
+    substdio_put(subfdout,num,fmt_uint(num,spamt.reasonablercpt));
+  else
+    substdio_puts(subfdout,"unlimited");
+
+  substdio_puts(subfdout,"\n\tpre-DATA flush? ");
+  substdio_puts(subfdout,spamt.flush ? "yes" : "no");
+
+  substdio_puts(subfdout,"\n\tteergrubing periodicity: ");
+  if (spamt.tg) {
+    substdio_put(subfdout,num,fmt_uint(num,spamt.tg));
+    substdio_puts(subfdout,"s");
+  } else
+    substdio_puts(subfdout, "not active");
+
+  if (spamt.tg) {
+    substdio_puts(subfdout,"\n\tteergrube response: ");
+    if (spamt.tg_resp.s)
+      substdio_puts(subfdout,spamt.tg_resp.s);
+    else
+      substdio_puts(subfdout,"(Default.) please wait.");
+  }
+
+  substdio_puts(subfdout,"\n\tspam throttle (state) directory: ");
+  if (spamt.dir.s && spamt.dir.s[0] )
+    if (spamt.dir.s[0] == '/') {
+      substdio_puts(subfdout,"construct ");
+      substdio_puts(subfdout,spamt.dir.s+1);
+      substdio_puts(subfdout,"-bit directory from remote IP");
+    } else
+      substdio_puts(subfdout,spamt.dir.s);
+  else
+    substdio_puts(subfdout,"construct 32-bit directory from remote IP");
+
+  substdio_puts(subfdout,"\n\tother active network blocks (bits): ");
+  r = 0;
+  for (i = 32;i >= 1;--i)
+  {
+    if (!(uip & (1 << (i - 1)))) continue;
+    if (r++)
+      substdio_puts(subfdout,", ");
+    substdio_put(subfdout,num,fmt_uint(num,i));
+  }
+  if (!r)
+    substdio_puts(subfdout,"none");
+
+  substdio_puts(subfdout,"\n");
+}
+
 void main()
 {
   DIR *dir;
@@ -214,7 +341,11 @@
     _exit(111);
   }
 
-  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
+  do_lst("badhelo","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern.");
+  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern.");
+  do_lst("badmailfromnorelay","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern and RELAYCLIENT is not set.");
+  do_lst("badmailto","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern.");
+  do_lst("badmailtonorelay","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern and RELAYCLIENT is not set.");
   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 ","");
@@ -257,6 +388,11 @@
 
   do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
   do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
+  do_int("spfbehavior","0","The SPF behavior is ","");
+  do_str("spfexp",0,SPF_DEFEXP,"The SPF default explanation is: 550 ");
+  do_str("spfguess",0,"","The guess SPF rules are: ");
+  do_str("spfrules",0,"","The local SPF rules are: ");
+  do_spam();
   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");
@@ -267,7 +403,11 @@
     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,"badhelo")) continue;
     if (str_equal(d->d_name,"badmailfrom")) continue;
+    if (str_equal(d->d_name,"badmailfromnorelay")) continue;
+    if (str_equal(d->d_name,"badmailto")) continue;
+    if (str_equal(d->d_name,"badmailtonorelay")) 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;
@@ -292,6 +432,12 @@
     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,"spamt")) continue;
+    if (str_equal(d->d_name,"spamt.cdb")) 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;
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.8 ./qmail-smtpd.8
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.8	1998-06-15 03:53:16.000000000 -0700
+++ ./qmail-smtpd.8	2006-01-05 15:03:43.378236880 -0800
@@ -14,6 +14,15 @@
 see
 .BR tcp-environ(5) .
 
+If the environment variable
+.B SMTPS
+is non-empty,
+.B qmail-smtpd
+starts a TLS session (to support the deprecated SMTPS protocol,
+normally on port 465). Otherwise,
+.B qmail-smtpd
+offers the STARTTLS extension to ESMTP.
+
 .B qmail-smtpd
 is responsible for counting hops.
 It rejects any message with 100 or more 
@@ -23,7 +32,30 @@
 header fields.
 
 .B qmail-smtpd
-supports ESMTP, including the 8BITMIME and PIPELINING options.
+supports ESMTP, including the 8BITMIME, DATA, PIPELINING, SIZE, and AUTH options.
+.B qmail-smtpd
+includes a \'MAIL FROM:\' parameter parser and obeys \'Auth\' and \'Size\' advertisements.
+.B qmail-smtpd
+can accept LOGIN, PLAIN, and CRAM-MD5 AUTH types. It invokes
+.IR checkprogram ,
+which reads on file descriptor 3 the username, a 0 byte, the password
+or CRAM-MD5 digest/response derived from the SMTP client,
+another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type),
+and a final 0 byte.
+.I checkprogram
+invokes
+.I subprogram
+upon successful authentication, which should in turn return 0 to
+.BR qmail-smtpd ,
+effectively setting the environment variables $RELAYCLIENT and $TCPREMOTEINFO
+(any supplied value replaced with the authenticated username).
+.B qmail-smtpd
+will reject the authentication attempt if it receives a nonzero return
+value from
+.I checkprogram
+or
+.IR subprogram .
+
 .SH TRANSPARENCY
 .B qmail-smtpd
 converts the SMTP newline convention into the UNIX newline convention
@@ -37,11 +69,26 @@
 even though such messages violate the SMTP protocol.
 .SH "CONTROL FILES"
 .TP 5
+.I badhelo
+Unacceptable HELO/EHLO host names.
+.B qmail-smtpd
+will reject every recipient address for a message if
+the host name is listed in, 
+or matches a POSIX regular expression pattern listed in,
+.IR badhelo .
+If the 
+.B NOBADHELO 
+environment variable is set, then the contents of 
+.IR badhelo 
+will be ignored.
+For more information, please have a look at doc/README.qregex.
+.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
+if the envelope sender address is listed in, or matches a POSIX regular expression
+pattern listed in,
 .IR badmailfrom .
 A line in
 .I badmailfrom
@@ -49,6 +96,45 @@
 .BR @\fIhost ,
 meaning every address at
 .IR host .
+For more information, please have a look at doc/README.qregex.
+.TP 5
+.I badmailfromnorelay
+Functions the same as the
+.IR badmailfrom
+control file but is read only if the 
+.B RELAYCLIENT 
+environment variable is not set.
+For more information, please have a look at doc/README.qregex.
+.TP 5
+.I badmailto
+Unacceptable envelope recipient addresses.
+.B qmail-smtpd
+will reject every recipient address for a message if the recipient address
+is listed in,
+or matches a POSIX regular expression pattern listed in,
+.IR badmailto .
+For more information, please have a look at doc/README.qregex.
+.TP 5
+.I badmailtonorelay
+Functions the same as the
+.IR badmailto
+control file but is read only if the
+.B RELAYCLIENT
+environment variable is not set.
+For more information, please have a look at doc/README.qregex.
+
+.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 clientcrl.pem
+A list of Certificate Revocation Lists (CRLs). If present it
+should contain the CRLs of the CAs in 
+.I clientca.pem 
+and client certs will be checked for revocation.
+
 .TP 5
 .I databytes
 Maximum number of bytes allowed in a message,
@@ -76,6 +162,18 @@
 .B DATABYTES
 is set, it overrides
 .IR databytes .
+
+.TP 5
+.I dh1024.pem
+If these 1024 bit DH parameters are provided,
+.B qmail-smtpd
+will use them for TLS sessions instead of generating one on-the-fly 
+(which is very timeconsuming).
+.TP 5
+.I dh512.pem
+512 bit counterpart for 
+.B dh1024.pem. 
+
 .TP 5
 .I localiphost
 Replacement host name for local IP addresses.
@@ -151,6 +249,19 @@
 
 Envelope recipient addresses without @ signs are
 always allowed through.
+
+.TP 5
+.I rsa512.pem
+If this 512 bit RSA key is provided,
+.B qmail-smtpd
+will use it for TLS sessions instead of generating one on-the-fly.
+
+.TP 5
+.I servercert.pem
+SSL certificate to be presented to clients in TLS-encrypted sessions. 
+Should contain both the certificate and the private key. Certifying Authority
+(CA) and intermediate certificates can be added at the end of the file.
+
 .TP 5
 .I smtpgreeting
 SMTP greeting message.
@@ -169,11 +280,76 @@
 .B qmail-smtpd
 will wait for each new buffer of data from the remote SMTP client.
 Default: 1200.
+.TP 5
+.I spfbehavior
+Set to a value between 1 and 6 to enable SPF checks; 0 to disable.
+1 selects 'annotate-only' mode, where
+.B qmail-smtpd
+will annotate incoming email with
+.B Received-SPF
+fields, but will not reject any messages.  2 will produce temporary
+failures on DNS lookup problems so you can make sure you always have
+meaningful Received-SPF headers.  3 selects 'reject' mode,
+where incoming mail will be rejected if the SPF record says 'fail'.  4
+selects a more stricter rejection mode, which is like 'reject' mode,
+except that incoming mail will also be rejected when the SPF record
+says 'softfail'.  5 will also reject when the SPF record says 'neutral',
+and 6 if no SPF records are available at all (or a syntax error was
+encountered). The contents of this file are overridden by the value of
+the
+.B SPFBEHAVIOR
+environment variable, if set.
+Default: 0.
+.TP 5
+.I spfexp
+You can add a line with a an SPF explanation that will be shown to the
+sender in case of a reject. It will override the default one. You can
+use SPF macro expansion.
+.TP 5
+.I spfguess
+You can add a line with SPF rules that will be checked if a sender
+domain doesn't have a SPF record. The local rules will also be used
+in this case.
+.TP 5
+.I spfrules
+You can add a line with SPF rules that will be checked before other SPF
+rules would fail.  This can be used to always allow certain machines to
+send certain mails.
+.TP 5
+.I spamt
+The spam throttle parameters file.  See
+.BR qmail-newst (8)
+and
+.BR qmail-spamt (5)
+for details.
+
+
+
+.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 "SEE ALSO"
 tcp-env(1),
 tcp-environ(5),
 qmail-control(5),
+qmail-spamt(5),
+qmail-spamthrottle(5)
 qmail-inject(8),
 qmail-newmrh(8),
+qmail-newst(8),
 qmail-queue(8),
 qmail-remote(8)
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.c ./qmail-smtpd.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-smtpd.c	2006-01-05 15:06:38.661589760 -0800
+++ ./qmail-smtpd.c	2006-01-05 15:08:14.805973592 -0800
@@ -1,3 +1,14 @@
+
+/*
+ *
+ * includes chkuser v.2.0.8
+ * for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x
+ *
+ * Author: Antonio Nati tonix@interazioni.it
+ * www.interazioni.it/opensource
+ *
+ */
+
 #include "sig.h"
 #include "readwrite.h"
 #include "stralloc.h"
@@ -23,14 +34,48 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "spam.h"
+#include "wait.h"
+#include "spf.h"
+
+#define CRAM_MD5
+#define AUTHSLEEP 5
+
+#include "qregex.h"
+#include "strerr.h"
+
+#define BMCHECK_BMF 0
+#define BMCHECK_BMFNR 1
+#define BMCHECK_BMT 2
+#define BMCHECK_BMTNR 3
+#define BMCHECK_BHELO 4
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
 int timeout = 1200;
+unsigned int spfbehavior = 0;
+
+#ifdef TLS
+#include <sys/stat.h>
+#include "tls.h"
+#include "ssl_timeoutio.h"
+
+void tls_init();
+int tls_verify();
+void tls_nogateway();
+int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */
+#endif
+
+#include "chkuser.h"
 
 int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
   int r;
+#ifdef TLS
+  if (ssl && fd == ssl_wfd)
+    r = ssl_timeoutwrite(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
+  else
+#endif
   r = timeoutwrite(timeout,fd,buf,len);
   if (r <= 0) _exit(1);
   return r;
@@ -49,8 +94,20 @@
 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_size() { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
+void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); }
+void err_bmt() { out("553 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); }
+void err_bhelo() { out("553 sorry, your HELO host name has been denied (#5.7.1)\r\n"); }
+#ifndef TLS
 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
+#else
+void err_nogateway()
+{
+  out("553 sorry, that domain isn't in my list of allowed rcpthosts");
+  tls_nogateway();
+  out(" (#5.7.1)\r\n");
+}
+#endif
 void err_unimpl(arg) char *arg; { 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"); }
@@ -59,8 +116,39 @@
 void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); }
 void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
 
+int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+int err_write() { out("454 oops, unable to write pipe and I can't auth (#4.3.0)\r\n"); return -1; }
+void err_authd() { out("503 you're already authenticated (#5.5.0)\r\n"); }
+void err_authmail() { out("503 no auth during mail transaction (#5.5.0)\r\n"); }
+int err_noauth() { out("504 auth type unimplemented (#5.5.1)\r\n"); return -1; }
+int err_authabrt() { out("501 auth exchange canceled (#5.0.0)\r\n"); return -1; }
+int err_input() { out("501 malformed auth input (#5.5.4)\r\n"); return -1; }
+void err_authfail() { out("535 authentication failed (#5.7.1)\r\n"); }
+
+int saferead(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  flush();
+#ifdef TLS
+  if (ssl && fd == ssl_rfd)
+    r = ssl_timeoutread(timeout, ssl_rfd, ssl_wfd, ssl, buf, len);
+  else
+#endif
+  r = timeoutread(timeout,fd,buf,len);
+  if (r == -1) if (errno == error_timeout) die_alarm();
+  if (r <= 0) die_read();
+  return r;
+}
+
+char ssinbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
 
 stralloc greeting = {0};
+stralloc spflocal = {0};
+stralloc spfguess = {0};
+stralloc spfexp = {0};
 
 void smtp_greet(code) char *code;
 {
@@ -76,6 +164,7 @@
   smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
 }
 
+char *protocol;
 char *remoteip;
 char *remotehost;
 char *remoteinfo;
@@ -85,7 +174,9 @@
 stralloc helohost = {0};
 char *fakehelo; /* pointer into helohost, or 0 */
 
-void dohelo(arg) char *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;
@@ -95,7 +186,20 @@
 stralloc liphost = {0};
 int bmfok = 0;
 stralloc bmf = {0};
-struct constmap mapbmf;
+
+int bmfnrok = 0;
+stralloc bmfnr = {0};
+
+int bmtok = 0;
+stralloc bmt = {0};
+
+int bmtnrok = 0;
+stralloc bmtnr = {0};
+
+int bhelook = 0;
+stralloc bhelo = {0};
+
+struct spam_t spamt = spam_t_init(&ssin,&ssout);
 
 void setup()
 {
@@ -109,19 +213,43 @@
   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();
 
   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();
- 
+
+  bmfnrok = control_readfile(&bmfnr,"control/badmailfromnorelay",0);
+  if (bmfnrok == -1) die_control();
+
+  bmtok = control_readfile(&bmt,"control/badmailto",0);
+  if (bmtok == -1) die_control();
+
+  bmtnrok = control_readfile(&bmtnr,"control/badmailtonorelay",0);
+  if (bmtnrok == -1) die_control();
+
+  bhelook = control_readfile(&bhelo, "control/badhelo",0);
+  if (bhelook == -1) die_control();
+  if (env_get("NOBADHELO")) bhelook = 0;
+
   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;
  
+  if (control_readint(&spfbehavior,"control/spfbehavior") == -1)
+    die_control();
+  x = env_get("SPFBEHAVIOR");
+  if (x) { scan_ulong(x,&u); spfbehavior = u; }
+
+  if (control_readline(&spflocal,"control/spfrules") == -1) die_control();
+  if (spflocal.len && !stralloc_0(&spflocal)) die_nomem();
+  if (control_readline(&spfguess,"control/spfguess") == -1) die_control();
+  if (spfguess.len && !stralloc_0(&spfguess)) die_nomem();
+  if (control_rldef(&spfexp,"control/spfexp",0,SPF_DEFEXP) == -1)
+    die_control();
+  if (!stralloc_0(&spfexp)) die_nomem();
+
+  protocol = "SMTP";
   remoteip = env_get("TCPREMOTEIP");
   if (!remoteip) remoteip = "unknown";
   local = env_get("TCPLOCALHOST");
@@ -131,6 +259,14 @@
   if (!remotehost) remotehost = "unknown";
   remoteinfo = env_get("TCPREMOTEINFO");
   relayclient = env_get("RELAYCLIENT");
+
+#ifdef TLS
+  if (env_get("SMTPS")) { smtps = 1; tls_init(); }
+  else
+#endif
+
+  spam_control(&spamt);
+
   dohelo(remotehost);
 }
 
@@ -197,14 +333,48 @@
   return 1;
 }
 
-int bmfcheck()
+int bmcheck(which) int which;
 {
-  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;
+  int i = 0;
+  int j = 0;
+  int x = 0;
+  int negate = 0;
+  static stralloc bmb = {0};
+  static stralloc curregex = {0};
+
+  if (which == BMCHECK_BMF) {
+    if (!stralloc_copy(&bmb,&bmf)) die_nomem();
+  } else if (which == BMCHECK_BMFNR) {
+    if (!stralloc_copy(&bmb,&bmfnr)) die_nomem();
+  } else if (which == BMCHECK_BMT) {
+    if (!stralloc_copy(&bmb,&bmt)) die_nomem();
+  } else if (which == BMCHECK_BMTNR) {
+    if (!stralloc_copy(&bmb,&bmtnr)) die_nomem();
+  } else if (which == BMCHECK_BHELO) {
+    if (!stralloc_copy(&bmb,&bhelo)) die_nomem();
+  } else {
+    die_control();
+  }
+
+  while (j < bmb.len) {
+    i = j;
+    while ((bmb.s[i] != '\0') && (i < bmb.len)) i++;
+    if (bmb.s[j] == '!') {
+      negate = 1;
+      j++;
+    }
+    if (!stralloc_copyb(&curregex,bmb.s + j,(i - j))) die_nomem();
+    if (!stralloc_0(&curregex)) die_nomem();
+    if (which == BMCHECK_BHELO) {
+      x = matchregex(helohost.s, curregex.s);
+    } else {
+      x = matchregex(addr.s, curregex.s);
+    }
+    if ((negate) && (x == 0)) return 1;
+    if (!(negate) && (x > 0)) return 1;
+    j = i + 1;
+    negate = 0;
+  }
   return 0;
 }
 
@@ -213,24 +383,115 @@
   int r;
   r = rcpthosts(addr.s,str_len(addr.s));
   if (r == -1) die_control();
+#ifdef TLS
+  if (r == 0) if (tls_verify()) r = -2;
+#endif
   return r;
 }
 
-
 int seenmail = 0;
-int flagbarf; /* defined if seenmail */
+int rcptcount;
+int flagbarfbmf; /* defined if seenmail */
+int flagbarfspf;
+stralloc spfbarfmsg = {0};
+int flagbarfbmt;
+int flagbarfbhelo;
+int flagsize;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
+stralloc fuser = {0};
+stralloc mfparms = {0};
+
+int mailfrom_size(arg) char *arg;
+{
+  long r;
+  unsigned long sizebytes = 0;
+
+  scan_ulong(arg,&r);
+  sizebytes = r;
+  if (databytes) if (sizebytes > databytes) return 1;
+  return 0;
+}
+
+void mailfrom_auth(arg,len) 
+char *arg; 
+int len;
+{
+  int j;
+
+  if (!stralloc_copys(&fuser,"")) die_nomem();
+  if (case_starts(arg,"<>")) { if (!stralloc_cats(&fuser,"unknown")) die_nomem(); }
+  else 
+    while (len) {
+      if (*arg == '+') {
+        if (case_starts(arg,"+3D")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"=")) die_nomem(); }
+        if (case_starts(arg,"+2B")) { arg=arg+2; len=len-2; if (!stralloc_cats(&fuser,"+")) die_nomem(); }
+      }
+      else
+        if (!stralloc_catb(&fuser,arg,1)) die_nomem();
+      arg++; len--;
+    }
+  if(!stralloc_0(&fuser)) die_nomem();
+  if (!remoteinfo) {
+    remoteinfo = fuser.s;
+    if (!env_unset("TCPREMOTEINFO")) die_read();
+    if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+  }
+}
+
+void mailfrom_parms(arg) char *arg;
+{
+  int i;
+  int len;
+
+    len = str_len(arg);
+    if (!stralloc_copys(&mfparms,"")) die_nomem;
+    i = byte_chr(arg,len,'>');
+    if (i > 4 && i < len) {
+      while (len) {
+        arg++; len--; 
+        if (*arg == ' ' || *arg == '\0' ) {
+           if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; }
+           if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5);  
+           if (!stralloc_copys(&mfparms,"")) die_nomem;
+        }
+        else
+          if (!stralloc_catb(&mfparms,arg,1)) die_nomem; 
+      }
+    }
+}
 
 void smtp_helo(arg) char *arg;
 {
   smtp_greet("250 "); out("\r\n");
   seenmail = 0; dohelo(arg);
+  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
 }
+/* ESMTP extensions are published here */
 void smtp_ehlo(arg) char *arg;
 {
-  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  char size[FMT_ULONG];
+#ifdef TLS
+  struct stat st;
+#endif
+  smtp_greet("250-"); 
+#ifdef TLS
+  if (!ssl && (stat("control/servercert.pem",&st) == 0))
+    out("\r\n250-STARTTLS");
+#endif
+  size[fmt_ulong(size,(unsigned int) databytes)] = 0;
+  if (!spamt.flush || !spamt.throttle) {
+   out("\r\n250-PIPELINING");
+  }
+  out("\r\n250-8BITMIME\r\n");
+  out("250-SIZE "); out(size); out("\r\n");
+#ifdef CRAM_MD5
+  out("250 AUTH LOGIN PLAIN CRAM-MD5\r\n");
+#else
+  out("250 AUTH LOGIN PLAIN\r\n");
+#endif
   seenmail = 0; dohelo(arg);
+  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
 }
 void smtp_rset(arg) char *arg;
 {
@@ -239,45 +500,121 @@
 }
 void smtp_mail(arg) char *arg;
 {
+  int r;
   if (!addrparse(arg)) { err_syntax(); return; }
-  flagbarf = bmfcheck();
+  flagsize = 0;
+  mailfrom_parms(arg);
+  if (flagsize) { err_size(); return; }
+  flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */
+  if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF);
+  if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) {
+    flagbarfbmf = bmcheck(BMCHECK_BMFNR);
+  }
+  if (chkuser_sender (&addr) != CHKUSER_OK) { return; }
+  flagbarfspf = 0;
+  if (spfbehavior && !relayclient)
+   { 
+    switch(r = spfcheck()) {
+    case SPF_OK: env_put2("SPFRESULT","pass"); break;
+    case SPF_NONE: env_put2("SPFRESULT","none"); break;
+    case SPF_UNKNOWN: env_put2("SPFRESULT","unknown"); break;
+    case SPF_NEUTRAL: env_put2("SPFRESULT","neutral"); break;
+    case SPF_SOFTFAIL: env_put2("SPFRESULT","softfail"); break;
+    case SPF_FAIL: env_put2("SPFRESULT","fail"); break;
+    case SPF_ERROR: env_put2("SPFRESULT","error"); break;
+    }
+    switch (r) {
+    case SPF_NOMEM:
+      die_nomem();
+    case SPF_ERROR:
+      if (spfbehavior < 2) break;
+      out("451 SPF lookup failure (#4.3.0)\r\n");
+      return;
+    case SPF_NONE:
+    case SPF_UNKNOWN:
+      if (spfbehavior < 6) break;
+    case SPF_NEUTRAL:
+      if (spfbehavior < 5) break;
+    case SPF_SOFTFAIL:
+      if (spfbehavior < 4) break;
+    case SPF_FAIL:
+      if (spfbehavior < 3) break;
+      if (!spfexplanation(&spfbarfmsg)) die_nomem();
+      if (!stralloc_0(&spfbarfmsg)) die_nomem();
+      flagbarfspf = 1;
+    }
+   } 
+  else
+   env_unset("SPFRESULT");
   seenmail = 1;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
   if (!stralloc_0(&mailfrom)) die_nomem();
+  rcptcount = 0;
   out("250 ok\r\n");
 }
+
+void err_spf() {
+  int i,j;
+ 
+   for(i = 0; i < spfbarfmsg.len; i = j + 1) {
+     j = byte_chr(spfbarfmsg.s + i, spfbarfmsg.len - i, '\n') + i;
+     if (j < spfbarfmsg.len) {
+       out("550-");
+       spfbarfmsg.s[j] = 0;
+       out(spfbarfmsg.s);
+       spfbarfmsg.s[j] = '\n';
+       out("\r\n");
+     } else {
+       out("550 ");
+       out(spfbarfmsg.s);
+       out(" (#5.7.1)\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) {
+  if (flagbarfbhelo) {
+    strerr_warn4("qmail-smtpd: badhelo: <",helohost.s,"> at ",remoteip,0);
+    err_bhelo();
+    return;
+  }
+  if (flagbarfbmf) {
+    strerr_warn4("qmail-smtpd: badmailfrom: <",mailfrom.s,"> at ",remoteip,0);
+    err_bmf();
+    return;
+  }
+  if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT);
+  if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) {
+    flagbarfbmt = bmcheck(BMCHECK_BMTNR);
+  }
+  if (flagbarfbmt) {
+    strerr_warn4("qmail-smtpd: badmailto: <",addr.s,"> at ",remoteip,0);
+    err_bmt();
+    return;
+  }
+  if (flagbarfspf) { err_spf(); return; }
+  switch (chkuser_realrcpt (&mailfrom, &addr)) {
+
+        case CHKUSER_KO:
+                return;
+                break;
+
+        case CHKUSER_RELAYING:
     --addr.len;
     if (!stralloc_cats(&addr,relayclient)) die_nomem();
     if (!stralloc_0(&addr)) die_nomem();
+                break;
   }
-  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();
+  ++rcptcount;
   out("250 ok\r\n");
 }
 
-
-int saferead(fd,buf,len) int fd; char *buf; int len;
-{
-  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;
-}
-
-char ssinbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
-
 struct qmail qqt;
 unsigned int bytestooverflow = 0;
 
@@ -351,6 +688,25 @@
   }
 }
 
+void spfreceived()
+{
+  stralloc sa = {0};
+  stralloc rcvd_spf = {0};
+
+  if (!spfbehavior || relayclient) return;
+
+  if (!stralloc_copys(&rcvd_spf, "Received-SPF: ")) die_nomem();
+  if (!spfinfo(&sa)) die_nomem();
+  if (!stralloc_cat(&rcvd_spf, &sa)) die_nomem();
+  if (!stralloc_append(&rcvd_spf, "\n")) die_nomem();
+  if (bytestooverflow) {
+    bytestooverflow -= rcvd_spf.len;
+    if (bytestooverflow <= 0) qmail_fail(&qqt);
+  }
+  qmail_put(&qqt,rcvd_spf.s,rcvd_spf.len);
+}
+
+
 char accept_buf[FMT_ULONG];
 void acceptmessage(qp) unsigned long qp;
 {
@@ -376,9 +732,14 @@
   if (databytes) bytestooverflow = databytes + 1;
   if (qmail_open(&qqt) == -1) { err_qqt(); return; }
   qp = qmail_qp(&qqt);
+
+  spamt.rcptcount = rcptcount;
+  spam_wait(&spamt);
+
   out("354 go ahead\r\n");
  
-  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+  received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo);
+  spfreceived();
   blast(&hops);
   hops = (hops >= MAXHOPS);
   if (hops) qmail_fail(&qqt);
@@ -388,28 +749,496 @@
   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 (databytes) if (!bytestooverflow) { err_size(); return; }
   if (*qqx == 'D') out("554 "); else out("451 ");
   out(qqx + 1);
   out("\r\n");
 }
 
+/* this file is too long ----------------------------------------- SMTP AUTH */
+
+char unique[FMT_ULONG + FMT_ULONG + 3];
+static stralloc authin = {0};   /* input from SMTP client */
+static stralloc user = {0};     /* authorization user-id */
+static stralloc pass = {0};     /* plain passwd or digest */
+static stralloc resp = {0};     /* b64 response */
+#ifdef CRAM_MD5
+static stralloc chal = {0};     /* plain challenge */
+static stralloc slop = {0};     /* b64 challenge */
+#endif
+
+int flagauth = 0;
+char **childargs;
+char ssauthbuf[512];
+substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
+
+int authgetl(void) {
+  int i;
+
+  if (!stralloc_copys(&authin,"")) die_nomem();
+  for (;;) {
+    if (!stralloc_readyplus(&authin,1)) die_nomem(); /* XXX */
+    i = substdio_get(&ssin,authin.s + authin.len,1);
+    if (i != 1) die_read();
+    if (authin.s[authin.len] == '\n') break;
+    ++authin.len;
+  }
+
+  if (authin.len > 0) if (authin.s[authin.len - 1] == '\r') --authin.len;
+  authin.s[authin.len] = 0;
+  if (*authin.s == '*' && *(authin.s + 1) == 0) { return err_authabrt(); }
+  if (authin.len == 0) { return err_input(); }
+  return authin.len;
+}
+
+int authenticate(void)
+{
+  int child;
+  int wstat;
+  int pi[2];
+
+  if (!stralloc_0(&user)) die_nomem();
+  if (!stralloc_0(&pass)) die_nomem();
+#ifdef CRAM_MD5
+  if (!stralloc_0(&chal)) die_nomem();
+#endif
+
+  if (pipe(pi) == -1) return err_pipe();
+  switch(child = fork()) {
+    case -1:
+      return err_fork();
+    case 0:
+      close(pi[1]);
+      if(fd_copy(3,pi[0]) == -1) return err_pipe();
+      sig_pipedefault();
+        execvp(*childargs, childargs);
+      _exit(1);
+  }
+  close(pi[0]);
+
+  substdio_fdbuf(&ssauth,write,pi[1],ssauthbuf,sizeof ssauthbuf);
+  if (substdio_put(&ssauth,user.s,user.len) == -1) return err_write();
+  if (substdio_put(&ssauth,pass.s,pass.len) == -1) return err_write();
+#ifdef CRAM_MD5
+  if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
+#endif
+  if (substdio_flush(&ssauth) == -1) return err_write();
+
+  close(pi[1]);
+#ifdef CRAM_MD5
+  if (!stralloc_copys(&chal,"")) die_nomem();
+  if (!stralloc_copys(&slop,"")) die_nomem();
+#endif
+  byte_zero(ssauthbuf,sizeof ssauthbuf);
+  if (wait_pid(&wstat,child) == -1) return err_child();
+  if (wait_crashed(wstat)) return err_child();
+  if (wait_exitcode(wstat)) { sleep(AUTHSLEEP); return 1; } /* no */
+  return 0; /* yes */
+}
+
+int auth_login(arg) char *arg;
+{
+  int r;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&user) == 1) return err_input();
+  }
+  else {
+    out("334 VXNlcm5hbWU6\r\n"); flush();       /* Username: */
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&user) == 1) return err_input();
+  }
+  if (r == -1) die_nomem();
+
+  out("334 UGFzc3dvcmQ6\r\n"); flush();         /* Password: */
+
+  if (authgetl() < 0) return -1;
+  if (r = b64decode(authin.s,authin.len,&pass) == 1) return err_input();
+  if (r == -1) die_nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+int auth_plain(arg) char *arg;
+{
+  int r, id = 0;
+
+  if (*arg) {
+    if (r = b64decode(arg,str_len(arg),&resp) == 1) return err_input();
+  }
+  else {
+    out("334 \r\n"); flush();
+    if (authgetl() < 0) return -1;
+    if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+  }
+  if (r == -1 || !stralloc_0(&resp)) die_nomem();
+  while (resp.s[id]) id++;                       /* "authorize-id\0userid\0passwd\0" */
+
+  if (resp.len > id + 1)
+    if (!stralloc_copys(&user,resp.s + id + 1)) die_nomem();
+  if (resp.len > id + user.len + 2)
+    if (!stralloc_copys(&pass,resp.s + id + user.len + 2)) die_nomem();
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+
+#ifdef CRAM_MD5
+int auth_cram()
+{
+  int i, r;
+  char *s;
+
+  s = unique;                                           /* generate challenge */
+  s += fmt_uint(s,getpid());
+  *s++ = '.';
+  s += fmt_ulong(s,(unsigned long) now());
+  *s++ = '@';
+  *s++ = 0;
+  if (!stralloc_copys(&chal,"<")) die_nomem();
+  if (!stralloc_cats(&chal,unique)) die_nomem();
+  if (!stralloc_cats(&chal,local)) die_nomem();
+  if (!stralloc_cats(&chal,">")) die_nomem();
+  if (b64encode(&chal,&slop) < 0) die_nomem();
+  if (!stralloc_0(&slop)) die_nomem();
+
+  out("334 ");                                          /* "334 base64_challenge \r\n" */
+  out(slop.s);
+  out("\r\n");
+  flush();
+
+  if (authgetl() < 0) return -1;                        /* got response */
+  if (r = b64decode(authin.s,authin.len,&resp) == 1) return err_input();
+  if (r == -1 || !stralloc_0(&resp)) die_nomem();
+
+  i = str_chr(resp.s,' ');
+  s = resp.s + i;
+  while (*s == ' ') ++s;
+  resp.s[i] = 0;
+  if (!stralloc_copys(&user,resp.s)) die_nomem();       /* userid */
+  if (!stralloc_copys(&pass,s)) die_nomem();            /* digest */
+
+  if (!user.len || !pass.len) return err_input();
+  return authenticate();
+}
+#endif
+
+struct authcmd {
+  char *text;
+  int (*fun)();
+} authcmds[] = {
+  { "login",auth_login }
+,  { "plain",auth_plain }
+#ifdef CRAM_MD5
+, { "cram-md5",auth_cram }
+#endif
+, { 0,err_noauth }
+};
+
+void smtp_auth(arg)
+char *arg;
+{
+  int i;
+  char *cmd = arg;
+
+  if (!*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
+  if (flagauth) { err_authd(); return; }
+  if (seenmail) { err_authmail(); return; }
+
+  if (!stralloc_copys(&user,"")) die_nomem();
+  if (!stralloc_copys(&pass,"")) die_nomem();
+  if (!stralloc_copys(&resp,"")) die_nomem();
+#ifdef CRAM_MD5
+  if (!stralloc_copys(&chal,"")) die_nomem();
+#endif
+
+  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;
+
+  switch (authcmds[i].fun(arg)) {
+    case 0:
+      if (!env_put2("SMTPAUTHMETHOD", authcmds[i].text)) die_nomem();
+      if (!env_put2("SMTPAUTHUSER",user.s)) die_nomem();
+      flagauth = 1;
+      protocol = "ESMTPA";
+      relayclient = "";
+      remoteinfo = user.s;
+      if (!env_unset("TCPREMOTEINFO")) die_read();
+      if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem();
+      if (!env_put2("RELAYCLIENT",relayclient)) die_nomem();
+      out("235 ok, go ahead (#2.0.0)\r\n");
+      break;
+    case 1:
+      err_authfail(user.s,authcmds[i].text);
+  }
+}
+
+
+/* this file is too long --------------------------------------------- GO ON */
+
+#ifdef TLS
+stralloc proto = {0};
+int ssl_verified = 0;
+const char *ssl_verify_err = 0;
+
+void smtp_tls(char *arg)
+{
+  if (ssl) err_unimpl();
+  else if (*arg) out("501 Syntax error (no parameters allowed) (#5.5.4)\r\n");
+  else tls_init();
+}
+
+RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen)
+{
+  if (!export) keylen = 512;
+  if (keylen == 512) {
+    FILE *in = fopen("control/rsa512.pem", "r");
+    if (in) {
+      RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL);
+      fclose(in);
+      if (rsa) return rsa;
+    }
+  }
+  return RSA_generate_key(keylen, RSA_F4, NULL, NULL);
+}
+
+DH *tmp_dh_cb(SSL *ssl, int export, int keylen)
+{
+  if (!export) keylen = 1024;
+  if (keylen == 512) {
+    FILE *in = fopen("control/dh512.pem", "r");
+    if (in) {
+      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
+      fclose(in);
+      if (dh) return dh;
+    }
+  }
+  if (keylen == 1024) {
+    FILE *in = fopen("control/dh1024.pem", "r");
+    if (in) {
+      DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL);
+      fclose(in);
+      if (dh) return dh;
+    }
+  }
+  return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL);
+} 
+
+/* don't want to fail handshake if cert isn't verifiable */
+int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; }
+
+void tls_nogateway()
+{
+  /* there may be cases when relayclient is set */
+  if (!ssl || relayclient) return;
+  out("; no valid cert for gatewaying");
+  if (ssl_verify_err) { out(": "); out(ssl_verify_err); }
+}
+void tls_out(const char *s1, const char *s2)
+{
+  out("454 TLS "); out(s1);
+  if (s2) { out(": "); out(s2); }
+  out(" (#4.3.0)\r\n"); flush();
+}
+void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); }
+
+# define CLIENTCA "control/clientca.pem"
+# define CLIENTCRL "control/clientcrl.pem"
+# define SERVERCERT "control/servercert.pem"
+
+int tls_verify()
+{
+  stralloc clients = {0};
+  struct constmap mapclients;
+
+  if (!ssl || relayclient || ssl_verified) return 0;
+  ssl_verified = 1; /* don't do this twice */
+
+  /* request client cert to see if it can be verified by one of our CAs
+   * and the associated email address matches an entry in tlsclients */
+  switch (control_readfile(&clients, "control/tlsclients", 0))
+  {
+  case 1:
+    if (constmap_init(&mapclients, clients.s, clients.len, 0)) {
+      /* if CLIENTCA contains all the standard root certificates, a
+       * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE;
+       * it is probably due to 0.9.6b supporting only 8k key exchange
+       * data while the 0.9.6c release increases that limit to 100k */
+      STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA);
+      if (sk) {
+        SSL_set_client_CA_list(ssl, sk);
+        SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
+        break;
+      }
+      constmap_free(&mapclients);
+    }
+  case 0: alloc_free(clients.s); return 0;
+  case -1: die_control();
+  }
+
+  if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) {
+    const char *err = ssl_error_str();
+    tls_out("rehandshake failed", err); die_read();
+  }
+
+  do { /* one iteration */
+    X509 *peercert;
+    X509_NAME *subj;
+    stralloc email = {0};
+
+    int n = SSL_get_verify_result(ssl);
+    if (n != X509_V_OK)
+      { ssl_verify_err = X509_verify_cert_error_string(n); break; }
+    peercert = SSL_get_peer_certificate(ssl);
+    if (!peercert) break;
+
+    subj = X509_get_subject_name(peercert);
+    n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1);
+    if (n >= 0) {
+      const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value;
+      if (s) { email.len = s->length; email.s = s->data; }
+    }
+
+    if (email.len <= 0)
+      ssl_verify_err = "contains no email address";
+    else if (!constmap(&mapclients, email.s, email.len))
+      ssl_verify_err = "email address not in my list of tlsclients";
+    else {
+      /* add the cert email to the proto if it helped allow relaying */
+      --proto.len;
+      if (!stralloc_cats(&proto, "\n  (cert ") /* continuation line */
+        || !stralloc_catb(&proto, email.s, email.len)
+        || !stralloc_cats(&proto, ")")
+        || !stralloc_0(&proto)) die_nomem();
+      relayclient = "";
+      protocol = proto.s;
+    }
+
+    X509_free(peercert);
+  } while (0);
+  constmap_free(&mapclients); alloc_free(clients.s);
+
+  /* we are not going to need this anymore: free the memory */
+  SSL_set_client_CA_list(ssl, NULL);
+  SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
+
+  return relayclient ? 1 : 0;
+}
+
+void tls_init()
+{
+  SSL *myssl;
+  SSL_CTX *ctx;
+  const char *ciphers;
+  stralloc saciphers = {0};
+  X509_STORE *store;
+  X509_LOOKUP *lookup;
+
+  SSL_library_init();
+
+  /* a new SSL context with the bare minimum of options */
+  ctx = SSL_CTX_new(SSLv23_server_method());
+  if (!ctx) { tls_err("unable to initialize ctx"); return; }
+
+  if (!SSL_CTX_use_certificate_chain_file(ctx, SERVERCERT))
+    { SSL_CTX_free(ctx); tls_err("missing certificate"); return; }
+  SSL_CTX_load_verify_locations(ctx, CLIENTCA, NULL);
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+  /* crl checking */
+  store = SSL_CTX_get_cert_store(ctx);
+  if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) &&
+      (X509_load_crl_file(lookup, CLIENTCRL, X509_FILETYPE_PEM) == 1))
+    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
+                                X509_V_FLAG_CRL_CHECK_ALL);
+#endif
+
+  /* set the callback here; SSL_set_verify didn't work before 0.9.6c */
+  SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, verify_cb);
+
+  /* a new SSL object, with the rest added to it directly to avoid copying */
+  myssl = SSL_new(ctx);
+  SSL_CTX_free(ctx);
+  if (!myssl) { tls_err("unable to initialize ssl"); return; }
+
+  /* this will also check whether public and private keys match */
+  if (!SSL_use_RSAPrivateKey_file(myssl, SERVERCERT, SSL_FILETYPE_PEM))
+    { SSL_free(myssl); tls_err("no valid RSA private key"); return; }
+
+  ciphers = env_get("TLSCIPHERS");
+  if (!ciphers) {
+    if (control_readfile(&saciphers, "control/tlsserverciphers") == -1)
+      { SSL_free(myssl); die_control(); }
+    if (saciphers.len) { /* convert all '\0's except the last one to ':' */
+      int i;
+      for (i = 0; i < saciphers.len - 1; ++i)
+        if (!saciphers.s[i]) saciphers.s[i] = ':';
+      ciphers = saciphers.s;
+    }
+  }
+  if (!ciphers || !*ciphers) ciphers = "DEFAULT";
+  SSL_set_cipher_list(myssl, ciphers);
+  alloc_free(saciphers.s);
+
+  SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb);
+  SSL_set_tmp_dh_callback(myssl, tmp_dh_cb);
+  SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin));
+  SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout));
+
+  if (!smtps) { out("220 ready for tls\r\n"); flush(); }
+
+  if (ssl_timeoutaccept(timeout, ssl_rfd, ssl_wfd, myssl) <= 0) {
+    /* neither cleartext nor any other response here is part of a standard */
+    const char *err = ssl_error_str();
+    ssl_free(myssl); tls_out("connection failed", err); die_read();
+  }
+  ssl = myssl;
+
+  /* populate the protocol string, used in Received */
+  if (!stralloc_copys(&proto, "(")
+    || !stralloc_cats(&proto, SSL_get_cipher(ssl))
+    || !stralloc_cats(&proto, " encrypted) SMTP")) die_nomem();
+  if (!stralloc_0(&proto)) die_nomem();
+  protocol = proto.s;
+
+  /* have to discard the pre-STARTTLS HELO/EHLO argument, if any */
+  dohelo(remotehost);
+}
+
+# undef SERVERCERT
+# undef CLIENTCA
+
+#endif
+
 struct commands smtpcommands[] = {
   { "rcpt", smtp_rcpt, 0 }
 , { "mail", smtp_mail, 0 }
 , { "data", smtp_data, flush }
+, { "auth", smtp_auth, flush }
 , { "quit", smtp_quit, flush }
 , { "helo", smtp_helo, flush }
 , { "ehlo", smtp_ehlo, flush }
 , { "rset", smtp_rset, 0 }
 , { "help", smtp_help, flush }
+#ifdef TLS
+, { "starttls", smtp_tls, flush }
+#endif
 , { "noop", err_noop, flush }
 , { "vrfy", err_vrfy, flush }
 , { 0, err_unimpl, flush }
 } ;
 
-void main()
+void main(argc,argv)
+int argc;
+char **argv;
 {
+  childargs = argv + 1;
   sig_pipeignore();
   if (chdir(auto_qmail) == -1) die_control();
   setup();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-spamt.9 ./qmail-spamt.9
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-spamt.9	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-spamt.9	2006-01-05 15:03:43.384235968 -0800
@@ -0,0 +1,142 @@
+.TH qmail-spamt 5
+.SH NAME
+qmail-spamt \- assign spam throttle parameters to IP blocks
+.SH OVERVIEW
+The file
+.B QMAILHOME/control/spamt
+assigns spam throttle parameters to IP blocks. For example,
+
+.EX
+   192.168.0.0/24:private:2000:120000::::::
+.EE
+
+says that mail originating from IP block
+.B 192.168.0.0/24
+will use
+.B QMAILHOME/spam/private
+as the spam throttle directory, with a spam throttle
+delay of 2000 and a spam throttle maximum delay of 120000 
+(both in milliseconds).  All other spam throttle parameters
+are unaffected.  To define the default spam throttle parameters,
+define an entry in
+.B QMAILHOME/control/spamt
+with an empty IP block.
+
+Assignments fed to
+.B qmail-newst
+will be used by
+.B qmail-smtpd
+to control spam throttling.
+See
+.BR qmail-newst (8).
+A change to
+.B QMAILHOME/control/spamt
+will have no effect until
+.B qmail-newst
+is run.
+.SH STRUCTURE
+.B QMAILHOME/control/spamt
+is a series of assignments, one per line.
+It ends with a line containing a single dot.
+Lines must not contain NUL.
+.SH "ASSIGNMENTS"
+A simple assignment is a line of the form
+
+.EX
+   ipblock:dir:st:stmax:flush:rcpt:tg:tg_resp:
+.EE
+
+Here
+.I ipblock
+is an IP block (format
+.I \fR[\fIa\fR.\fIb\fR.\fIc\fR.\fId\fR][/\fIn\fR]]);
+.IR dir ,
+.IR st ,
+.IR stmax ,
+.IR flush ,
+.IR rcpt ,
+.IR tg ,
+and
+.I tg_resp
+are the spam throttle parameters for directory (relative path),
+delay (ms), maximum delay (ms), post-DATA flush, reasonable receipt count,
+teergrube periodicity (s), and teergrube response.  Real-time values
+for
+.I ipblock
+will be stored in
+.BR QMAILHOME/spam/\fIdir .
+See
+.BR qmail-spamthrottle (9).
+ 
+If there are several assignments for the same
+.IR ipblock ,
+.B qmail-smtpd
+will use the first one.
+
+If an entry exists with an empty
+.IR ipblock,
+it is always used to define default (initial) values.
+
+If several, distinct
+.IR ipblock s
+match a given IP address, as specified by environment variable
+.BR TCPREMOTEIP ,
+the most specific (smallest network block) entry is used.
+
+If, after applying all applicable rules,
+.I dir 
+is empty, then it will be set to
+.IR a\fR/\fIb\fR/\fIc\fR/\fId ,
+where
+.IR a ,
+.IR b ,
+.IR c ,
+and
+.I d
+are the first four octets (in decimal) for the remote IP address,
+.IR a\fR.\fIb\fR.\fIc\fR.\fId .
+
+If
+.I dir
+starts with a slash (\fB/\fR), then it will be used to generate an \fIn\fR-bit masked
+IP address (format 
+.I \fR[/\fIn\fR])
+based on the remote IP address.  For example, if
+.I dir
+is set to
+.B /16
+and the remote IP address is
+.BR 192.168.10.3 ,
+then the spam throttle directory will be
+.BR 192/168/0/0 .
+
+
+.SH EXAMPLES
+
+.EX
+   192.168.0.0/24::0::::::
+   192.168.0.2:specific:2000::::::
+   192.168.1.0/16:testing:10000:::1:2:hold your horses!:
+   # empty network ==> default entry
+   ::1501:120000::::::
+.EE
+
+The IP address
+.B 192.168.2.1
+is handled by the fourth line;
+the IP address
+.B 192.168.1.2
+is handled by the third line;
+the IP address
+.B 192.168.0.2
+is handled by the second line;
+the address
+.B 192.168.0.1
+is handled by the first line.
+.SH "SEE ALSO"
+qmail-newst(8),
+qmail-spamthrottle(5)
+
+.SH AUTHOR
+Dale Woolridge, James Law, and Moto Kawasaki.  Contact the authors
+via email: <spamthrottle@qmail.ca>.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qmail-spamthrottle.9 ./qmail-spamthrottle.9
--- ../../netqmail-1.05-orig/netqmail-1.05/qmail-spamthrottle.9	1969-12-31 16:00:00.000000000 -0800
+++ ./qmail-spamthrottle.9	2006-01-05 15:03:43.386235664 -0800
@@ -0,0 +1,309 @@
+.TH qmail-spamthrottle 5
+
+.SH NAME
+qmail-spamthrottle \- the qmail spam throttle mechanism
+
+.SH INTRODUCTION
+The idea of spam throttling came about after would-be spammers were
+easily circumventing (classic) tarpitting.  A reasonable recipient
+limit in tarpitting must not adversely affect acceptable mail usage,
+so spam clients typically create multiple SMTP connections, all of
+which fall under this threshold.  Other sources have similar concepts,
+using rate limiting, stuttering, et cetera to describe them.
+
+It was originally intended for use at ISPs to control their internal
+clients (users) SMTP usage, although it can applied equally in other
+environments.  An ISP may wish to enable this mechanism for its customers
+to prevent them from using the mail servers as a convenient location
+from which to send spam.  However, in some or all other cases (other
+originating IP addresses) this mechanism might be disabled to allow
+for legitimate high-volume mail traffic such as mailing lists.
+
+Spam throttling acts in a similar manner to tarpitting, except that
+it is highly parameterized, more flexible, and (hopefully) more effective.
+A wait is imposed (via
+.BR sleep (3))
+following the
+.B DATA
+command depending on these SMTP parameters: remote IP address;
+previous SMTP connection timestamp; and previous wait time.
+
+With the addition of teergrubing, spammers should keep their
+connections open and deliver less mail.
+
+
+.SH DETAILS
+Two files,
+.I wait
+and
+.IR time ,
+store the previous wait time and SMTP connection timestamp,
+respectively.  Both files are found in
+.BR QMAILHOME/spam/\fIdir\fB .
+Where
+.I dir
+is based on parameters set in
+.BR QMAILHOME/control/spamt .
+If
+.I dir
+is empty as a result, then it will be automatically set to
+.IR a\fR/\fIb /0/0,
+where
+.I a
+and
+.I b
+are the two octets (in decimal) for the remote IP address,
+.IR a\fR.\fIb\fR.\fIc\fR.\fId .
+
+Similarly, if
+.I dir
+starts with a slash (\fB/\fR), then it be automatically set to
+the \fIn\fR-bit masked IP address (format
+.IR \fR[/\fIn ]),
+based on the remote IP address.
+
+See 
+.B qmail-spamt(5)
+for details.
+
+.B Note:
+In case it is not yet evident, when
+.I dir
+is empty (or starts with a slash), as indicated above, then every
+dot (\fB.\fR) is interpreted as a slash (\fB/\fR) in the construction
+of the directory where the spam throttle state files are stored.
+
+
+If you are using libtai for your time calculations,
+then the format for the
+.I time
+file is a packed TAI64NA label.  If you have perl and the tai64nlocal
+program, you can use the following perl expression to convert from
+a packed TAI64NA label to a TAI64N timestamp:
+
+.EX
+	print join("","@",unpack("H24",<>)), "\n";
+.EE
+
+
+Given an entry in
+.BR QMAILHOME/control/spamt ,
+such as
+
+.EX
+   ipblock:dir:st:stmax:flush:rcpt:tg:tg_resp:
+.EE
+
+Message throughput is controlled via the value of
+.IR st .
+The delays imposed (by calling 
+.BR sleep (3))
+depend on:  the value of \fIst\fR); number of recipients
+for the current SMTP session (\fIR\fR); the number of reasonable
+recipients per connection (\fIrcpt\fR); how much time has
+passed (\fIT\fR) since the last SMTP request (as determined by
+.BR QMAILHOME/spam/\fIdir\fB/time );
+and the last imposed delay (\fIW\fR) (as determined by
+.BR QMAILHOME/spam/\fIdir\fB/wait ).
+The new delay is approximately
+.EX
+
+    (\fIR\fR - \fIR\fR / 2^(\fIR\fR/\fIrcpt\fR)) * ((\fIW\fR * \fIst\fR * \fIR\fR) / \fIT\fR)
+
+.EE
+when \fIrcpt\fR is greater than 0, and
+.EX
+
+     (\fIW\fR * \fIst\fR * \fIR\fR) / \fIT\fR
+
+.EE
+otherwise.  The unit of time is milliseconds.
+
+If
+.I stmax
+is defined (and is non-zero), then it is used as a maximum
+(in milliseconds) for the delay calculated above.
+
+In short,
+.I st
+is roughly the minimum time between messages and/or connections.  If you already know
+that you only want a throughput of N messages per second, then you can use 1000/N
+as a good starting point for
+.IR st .
+
+.SH CONFIGURATION
+
+For the following discussion, we assuming the matching
+entry in
+.B QMAILHOME/control/spamt
+is
+
+.EX
+   ipblock:dir:st:stmax:flush:rcpt:tg:tg_resp:
+.EE
+
+Despite efforts to impose a waiting period on would-be
+spammers, it is still possible for the client to circumvent
+the call to
+.BR sleep (3).
+That is, they may not wait for the response from
+the DATA command, continuing to write their message, assuming
+success, then closing the socket, again without waiting for a
+response from the server; the message will be delivered at no
+(time) cost to them.  Adherence to standards (such as ignoring
+the absence of PIPELINING) should not be assumed for clients
+acting as agents for unsolicited bulk email.  As such, the
+.I flush
+variable can be set (non-zero) to indicate that all input will
+be flushed after calling
+.BR sleep (3)
+and prior to sending a response to the DATA command.
+RFC 2920 (STD 60) prohibits flushing of the input buffer if
+PIPELINING is supported.  As such, EHLO responses will not
+advertise PIPELINING while 
+.I flush
+is set.
+
+Another method, teergrubing, involves issuing continuation lines
+periodically to keep the client connected while they wait for the
+go ahead from the DATA command.  By setting (non-zero) the variable
+.IR tg ,
+you can specify the frequency of continuation lines in response to the
+DATA command.  If the argument to
+.BR sleep (3)
+would have been 11 (seconds) and
+.I tg
+is set to 2, then the response to the DATA command would result in
+several calls to sleep(2) (and one sleep(1)) with each accompanied
+by a continuation line.  A continuation line consist of a 3-digit code,
+a dash, and an arbitrary string.  The default string is "please wait",
+but can be changed using the
+.I tg_resp
+variable. For example,
+
+.EX
+     ...
+     DATA
+     354-please wait
+     354-please wait
+     354 go ahead
+     ...
+.EE
+
+
+.SH ENVIRONMENT
+The environment variable,
+.BR TCPREMOTEIP ,
+is strictly required by spam throttle.  If you are not using
+.BR tcpserver ,
+then you will have to use
+.B tcp-env
+to ensure
+.B TCPREMOTEIP 
+is set.
+
+
+.SH CAVEATS
+The implicit translation of an empty directory to one based on the
+remote IP address will most certainly result in an unwieldy spam
+directory structure and should be reserved for small networks, such
+as the internal network side of an office or ISP (including ISP users).
+It is recommended that the
+.I \fR/\fIn
+format be used in the default
+.B QMAILHOME/control/spamt
+entry (empty network block).  Then, for specific networks, a directory
+per IP address is still possible: for example, the entries
+
+.EX
+   192.168.0.0/24:/32:::::::
+   :/16:1500:120000::::::
+.EE
+
+define the default spam throttle directory (assuming the remote IP address is
+.IR a\fR.\fIb\fR.\fIc\fR.\fId )
+as
+.IR a\fR/\fIb /0/0.
+However, when the remote IP address is in the 192.168.0.0/24 network block,
+the spam throttle directory will be
+.IR a\fR/\fIb\fR/\fIc\fR/\fId ,
+since the
+.I dir
+parameter is
+.BR /32 .
+
+.SH EXAMPLES
+These examples assume that
+.B QMAILHOME/control/spamthrottle 
+contains a non-zero value.
+
+Here is a sample
+.B QMAILHOME/control/spamt
+file for a home user:
+.EX
+
+    # network:dir:st:stmax:flush:rcpt:tg:tg_resp:
+    # 
+    # default entry (make it all share the public directory)
+    :public:1500:120000::::::
+    #
+    # private (trusted) network does not enforce spamthrottle
+    192.168.0.0/24::0::::::
+    #
+    # some external network which we would like to throttle collectively
+    10.0.0.0/24:collected:::::::
+    #
+    # an external network (semi-trusted) which is throttled
+    # based on individual IP address
+    # - we don't specify SPAMTHROTTLEDIR and the default
+    #   behaviour of storing state files in directories
+    #   based on IP address is used)
+    # - we also allow relaying from this semi-trusted
+    #   network
+    10.1.0.0/16:/32:::::::
+    .
+
+.EE
+
+Here is a sample file for a high-volume mail server (or servers)
+for some arbitrary ISP (with customer network 10.0.0.0/16 and internal/
+employee network 10.1.0.0/24):
+.EX
+
+    # network:dir:st:stmax:flush:rcpt:tg:tg_resp:
+    #
+    # by default, turn throttling off
+    ::0:::::::
+    #
+    # customer network uses default behaviour
+    # (IP-based throttle files)
+    10.0.0.0/16:/32:::::::
+    #
+    # employee network doesn't adhere to throttling
+    10.1.0.0/24::0::::::
+    #
+    # external trusted network which legitimately
+    # provides high volume mail traffic
+    10.1.1.0/24::0::::::
+    #
+    # a collection of addresses/networks which we
+    # might have gathered from past abuse experience
+    # - we allow the mail, but we're aggressive
+    #   about throttling it
+    10.1.2.1/32:abuse:5000::::::
+    10.1.2.2/32:abuse:5000::::::
+    10.1.2.3/32:abuse:5000::::::
+    10.1.3.0/24:abuse:5000::::::
+    .
+
+.EE
+
+.SH "SEE ALSO"
+tcp-env(1),
+tcp-environ(5),
+qmail-spamt(5),
+qmail-smtpd(8)
+
+.SH AUTHOR
+Dale Woolridge, James Law, and Moto Kawasaki.  Contact the authors
+via email: <spamthrottle@qmail.ca>.
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qregex.c ./qregex.c
--- ../../netqmail-1.05-orig/netqmail-1.05/qregex.c	1969-12-31 16:00:00.000000000 -0800
+++ ./qregex.c	2006-01-05 15:03:43.387235512 -0800
@@ -0,0 +1,57 @@
+/*
+ * qregex (v2)
+ * $Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $
+ *
+ * Author  : Evan Borgstrom (evan at unixpimps dot org)
+ * Created : 2001/12/14 23:08:16
+ * Modified: $Date: 2006/03/18 03:32:53 $
+ * Revision: $Revision: 1.1 $
+ *
+ * Do POSIX regex matching on addresses for anti-relay / spam control.
+ * It logs to the maillog
+ * See the qregex-readme file included with this tarball.
+ * If you didn't get this file in a tarball please see the following URL:
+ *  http://www.unixpimps.org/software/qregex
+ *
+ * qregex.c is released under a BSD style copyright.
+ * See http://www.unixpimps.org/software/qregex/copyright.html
+ *
+ * Note: this revision follows the coding guidelines set forth by the rest of
+ *       the qmail code and that described at the following URL.
+ *       http://cr.yp.to/qmail/guarantee.html
+ * 
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+#include "qregex.h"
+
+#define REGCOMP(X,Y)    regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
+#define REGEXEC(X,Y)    regexec(&X, Y, (size_t)0, (regmatch_t *)0, (int)0)
+
+int matchregex(char *text, char *regex) {
+  regex_t qreg;
+  int retval = 0;
+
+
+  /* build the regex */
+  if ((retval = REGCOMP(qreg, regex)) != 0) {
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* execute the regex */
+  if ((retval = REGEXEC(qreg, text)) != 0) {
+    /* did we just not match anything? */
+    if (retval == REG_NOMATCH) {
+      regfree(&qreg);
+      return(0);
+    }
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* signal the match */
+  regfree(&qreg);
+  return(1);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/qregex.h ./qregex.h
--- ../../netqmail-1.05-orig/netqmail-1.05/qregex.h	1969-12-31 16:00:00.000000000 -0800
+++ ./qregex.h	2006-01-05 15:03:43.388235360 -0800
@@ -0,0 +1,5 @@
+/* simple header file for the matchregex prototype */
+#ifndef _QREGEX_H_
+#define _QREGEX_H_
+int matchregex(char *text, char *regex);
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/scan.h ./scan.h
--- ../../netqmail-1.05-orig/netqmail-1.05/scan.h	1998-06-15 03:53:16.000000000 -0700
+++ ./scan.h	2006-01-05 15:03:43.389235208 -0800
@@ -10,6 +10,7 @@
 extern unsigned int scan_ulong();
 extern unsigned int scan_xlong();
 extern unsigned int scan_nbblong();
+extern unsigned int scan_2long();
 
 extern unsigned int scan_plusminus();
 extern unsigned int scan_0x();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/scan_2long.c ./scan_2long.c
--- ../../netqmail-1.05-orig/netqmail-1.05/scan_2long.c	1969-12-31 16:00:00.000000000 -0800
+++ ./scan_2long.c	2006-01-05 15:03:43.390235056 -0800
@@ -0,0 +1,11 @@
+#include "scan.h"
+
+unsigned int scan_2long(s,u) register char *s; register unsigned long *u;
+{
+  register unsigned int pos; register unsigned long result;
+  register unsigned long c;
+  pos = 0; result = 0;
+  while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 2)
+    { result = (result << 1) + c; ++pos; }
+  *u = result; return pos;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spam.c ./spam.c
--- ../../netqmail-1.05-orig/netqmail-1.05/spam.c	1969-12-31 16:00:00.000000000 -0800
+++ ./spam.c	2006-01-05 15:03:43.392234752 -0800
@@ -0,0 +1,395 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "auto_uids.h"
+#include "lock.h"
+#include "stralloc.h"
+#include "control.h"
+#include "open.h"
+#include "fmt.h"
+#include "timeoutread.h"
+#include "error.h"
+#include "time.h"
+#include "ip.h"
+#include "env.h"
+#include "cdb.h"
+#include "spam.h"
+
+
+
+
+int spam_create_directory(dn)
+char *dn;
+{
+  struct stat sd;
+
+  if (stat(dn,&sd) == 0) return 1;				/* already there */
+  if (errno != error_noent) return 0;				/* can't stat, and not there */
+  if (mkdir(dn,0700) == -1 && errno != error_exist) return 0;	/* can't create dir */
+  if (chown(dn,auto_uidd,auto_gidn) == -1) return 0;		/* can't chown dir */
+
+  return 1;
+}
+
+
+int spam_open_rw(fn)
+char *fn;
+{
+  int fd;
+
+  fd = open_rw(fn);
+
+  if (fd == -1) return -1;				/* can't open file for read/write */
+  if (chmod(fn,0600) == -1) { close(fd); return -1; }	/* can't chmod file */
+
+  return fd;
+}
+
+
+int spam_stralloc_path(to,path,pa1,pa2)
+stralloc *to;
+char *path;
+char *pa1;
+char *pa2;
+{
+  if (!stralloc_copys(to,path)) return -1;
+  if (!stralloc_cats(to,pa1)) return -1;
+  if (pa2 && !stralloc_cats(to,pa2)) return -1;
+  if (!stralloc_0(to)) return -1;
+
+  return 0;
+}
+
+
+static unsigned int normalize_recipients(r,r_m)
+unsigned int r;
+unsigned int r_m;
+{
+  static const unsigned int r_min = 1;
+  unsigned int r_new = r_min;
+
+  if( r_m )
+  {
+    r_new = r - (r >> (r/r_m));
+    if( r_new < r_min ) r_new = r_min;
+  }
+
+  return r_new;
+}
+
+
+static unsigned int normalize_wait(w,dt,s_t,s_m,r,r_m)
+unsigned int w;
+unsigned int dt;
+unsigned int s_t;
+unsigned int s_m;
+unsigned int r;
+unsigned int r_m;
+{
+  static const unsigned int min_wait = 100;
+  unsigned int w_new = 0;
+
+  /*
+   * the maximum throttle times the "reasonable" # recipients
+   * is approximately the longest wait we want/expect so if
+   * we've waited that long, then we'll return the minimum
+   */
+  if( r_m && s_m && dt > (s_m * r_m) ) return min_wait;
+
+  /*
+   * then apply a normalizing factor to the previous wait (w) of
+   * (s_t * r) / dt, where s_t is our throttle constant (time per msg),
+   * r is actual # recipients, and dt is time since last imposed wait
+   */
+  w_new = (w * (s_t * r)) / (dt ? dt : 1);
+  if( w_new < min_wait ) w_new = min_wait;
+
+  return w_new;
+}
+
+
+static void spam_sleep(spamt,wait)
+struct spam_t * spamt;
+unsigned int wait;
+{
+  struct sockaddr sa;
+  int salen;
+  unsigned int tg = 0;
+  /*
+   * output continuation lines (up to) every "tg" seconds (when tg active)
+   */
+  while (wait)
+  {
+    if (spamt->tg && spamt->out)
+    {
+      tg = (wait < spamt->tg) ? wait : spamt->tg;
+      wait -= tg;
+      substdio_puts(spamt->out,spamt->code);
+      substdio_put(spamt->out,spamt->tg_resp.s,spamt->tg_resp.len);
+      substdio_puts(spamt->out,"\r\n");
+      substdio_flush(spamt->out);
+    }
+    else
+    {
+      tg = wait;
+      wait = 0;
+    }
+    if (spamt->in)
+    {
+      while (tg--)
+      {
+	salen = sizeof(sa);
+	if (getpeername(spamt->in->fd,&sa,&salen) == -1 && errno == ENOTCONN) return;
+	sleep(1);
+      }
+    }
+    else
+    {
+      sleep(tg);
+    }
+  }
+}
+
+
+static void spam_flush(spamt)
+struct spam_t * spamt;
+{
+  char ch;
+  /*
+   * see if we should flush all input (we want to force them to
+   * wait for the response from their DATA command before we
+   * accept input from them)
+   */
+  if (!spamt) return;
+  if (!spamt->throttle) return;
+  if (!spamt->flush) return;
+  if (!spamt->in) return;
+
+  while (timeoutread(1,spamt->in->fd,&ch,1) > 0) ;
+  /* timeout/error...doesn't matter */
+}
+
+
+int spam_wait(spamt)
+struct spam_t * spamt;
+{
+  stralloc sd = {0};
+  stralloc sw = {0};
+  stralloc st = {0};
+  stralloc sl = {0};
+  unsigned int pd = 0;
+  int fdw = 0;
+  int fdt = 0;
+  int fdl = 0;
+  struct q_time_t tn;
+  struct q_time_t ts;
+  unsigned int lw = 0;
+  unsigned long it = 0;
+  unsigned long sr = 0;
+  int rc = 1;
+  int fc;
+
+  if (!spamt) return 0;
+  if (!spamt->throttle) return 0;
+
+  if (spam_stralloc_path(&sd,"spam/",spamt->dir.s,0) == -1) return 0;
+
+  if (spamt->use_ip)
+    fc = '.';
+  else
+    fc = '/';
+
+  while (1)
+  {
+    pd += str_chr(&sd.s[pd],fc);
+    if (!sd.s[pd]) fc = 0;
+
+    sd.s[pd] = '\0';
+    if (!spam_create_directory(sd.s)) return 0;
+    if (!fc) break;
+    sd.s[pd] = '/';
+    pd++;
+  }
+
+  if (spam_stralloc_path(&sl,sd.s,"/lock",0) == -1) return 0;
+  if (spam_stralloc_path(&st,sd.s,"/time",0) == -1) return 0;
+  if (spam_stralloc_path(&sw,sd.s,"/wait",0) == -1) return 0;
+
+  if ((fdl = spam_open_rw(sl.s)) == -1) return 0;
+
+  if (lock_exfcntl(fdl) == -1)
+  {
+    close(fdl);
+    return 0;
+  }
+
+  if ((fdt = spam_open_rw(st.s)) == -1)
+  {
+    lock_unfcntl(fdl);
+    close(fdl);
+    return 0;
+  }
+
+  if ((fdw = spam_open_rw(sw.s)) == -1)
+  {
+    lock_unfcntl(fdl);
+    close(fdl);
+    close(fdt);
+    return 0;
+  }
+
+  close(fdw);
+  close(fdt);
+
+  time_now(&tn);
+  ts = tn;
+  control_readtime(&ts,st.s);
+  control_readint(&lw,sw.s);
+
+  time_sub(&ts,&tn,&ts);
+
+  it = time_ms(&ts);
+  lw =   normalize_recipients( spamt->rcptcount, spamt->reasonablercpt )
+       * normalize_wait( lw, it, spamt->throttle, spamt->max, spamt->rcptcount, spamt->reasonablercpt );
+
+  if (control_writetime(&tn,st.s) < 1)
+  {
+    lock_unfcntl(fdl);
+    close(fdl);
+    return 0;
+  }
+
+  rc = (control_writeint(&lw,sw.s) > 0);
+  rc &= (lock_unfcntl(fdl) != -1);
+
+  close(fdl);
+
+  if (!rc) return 0;
+
+  if (lw < 1000) return 0;
+
+  if (spamt->max && lw > spamt->max) lw = spamt->max;
+  lw /= 1000;
+
+  spam_sleep(spamt,lw);
+
+  spam_flush(spamt);
+
+  return 1;
+}
+
+
+/*
+ * take a spam_t and update fields from cdb file
+ */
+void spam_control(st)
+struct spam_t * st;
+{
+  char * remoteip = 0;
+  struct ip_address ip;
+  char str2ip[FMT_2IP];
+  char ipdir[IPFMT];
+  stralloc ipkey = {0};
+  uint32 dlen;
+  int fd;
+  int r;
+  stralloc data = {0};
+  unsigned long u;
+  unsigned int numbits;
+  int i;
+  unsigned int uip;
+  struct spam_t rst;
+  int flagrawip = 0;
+
+  if (!st) return;
+  rst = *st;
+
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) return;
+
+  fd = open_read("control/spamt.cdb");
+  if (fd == -1) return;
+
+  r = cdb_seek(fd,"",0,&dlen);
+  if (r != 1) return;		/* require existence of this key (defaults) */
+
+  if (!stralloc_ready(&data,(unsigned int) dlen)) return;
+  data.len = dlen;
+  if (cdb_bread(fd,data.s,data.len) == -1) return;
+
+  /* get the ipbits block from this key */
+  byte_copy(&uip,4,data.s);
+  /* then populate the spam_t (defaults) */
+  if (spam_get(&rst,data.s + 4,data.len - 4) == -1) return;
+
+  if (ip_scan(remoteip,&ip))
+  {
+    str2ip[fmt_2ip0(str2ip,&ip)] = 0;
+
+    /* find the smallest network block that matches */
+    for (i = 32;i >= 1;--i)
+    {
+      if (!(uip & (1 << (i - 1)))) continue;
+
+      stralloc_copyb(&ipkey,str2ip,i);
+      stralloc_0(&ipkey);
+      r = cdb_seek(fd,ipkey.s,ipkey.len,&dlen);
+      if (r == -1) return;
+      if (r == 0) continue;
+
+      if (!stralloc_ready(&data,(unsigned int) dlen)) return;
+      data.len = dlen;
+
+      if (cdb_bread(fd,data.s,data.len) == -1) return;
+
+      /* skip the ipbits block */
+      r = spam_get(&rst,data.s + 4,data.len - 4);
+      if (r == -1) return;
+      break;
+    }
+  }
+  else
+  {
+    flagrawip = 1;
+  }
+
+  close(fd);
+
+  if (!rst.throttle) return;
+
+  if (!rst.dir.s || rst.dir.s[0] == '/')
+  {
+    if (flagrawip)
+    {
+      stralloc_copys(&rst.dir,remoteip);
+      stralloc_0(&rst.dir);
+    }
+    else
+    {
+      /* generate an n-bit masked ip address */
+      numbits = 16;	/* default to a 16-bit block (large, but reasonable) */
+      if (rst.dir.s && rst.dir.s[0] == '/')
+      {
+	/* get bits if specified */
+	scan_ulong(rst.dir.s+1,&u);
+	numbits = u;
+      }
+
+      ipdir[fmt_ipn(ipdir,&ip,numbits)] = 0;
+
+      stralloc_copys(&rst.dir,ipdir);
+      stralloc_0(&rst.dir);
+    }
+
+    rst.use_ip = 1;
+  }
+
+  if (!rst.tg_resp.s)
+  {
+    if (!stralloc_copys(&rst.tg_resp,"please wait")) return;
+    if (!stralloc_0(&rst.tg_resp)) return;
+  }
+
+  *st = rst;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spam.h ./spam.h
--- ../../netqmail-1.05-orig/netqmail-1.05/spam.h	1969-12-31 16:00:00.000000000 -0800
+++ ./spam.h	2006-01-05 15:03:43.393234600 -0800
@@ -0,0 +1,28 @@
+#ifndef SPAM_H
+#define SPAM_H
+
+#include "stralloc.h"
+#include "substdio.h"
+
+extern int spam_wait();
+extern void spam_control();
+extern int spam_get();
+
+typedef struct spam_t {
+  unsigned int throttle;
+  unsigned int use_ip;	/* are we constructing dir using ip addr */
+  unsigned int max;
+  unsigned int reasonablercpt;
+  unsigned int flush;
+  unsigned int tg;	/* teergrube */
+  stralloc tg_resp;	/* continuation line response: <code>-<tg_resp> */
+  substdio * in;
+  substdio * out;
+  char * code;
+  stralloc dir;		/* was "char * dir" */
+  unsigned int rcptcount;
+} spam_t;
+
+#define spam_t_init(in,out) { 0, 0, 0, 0, 0, 0, { 0, 0, 0 }, (in), (out), "354-", { 0, 0, 0 }, 0 }
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spam_get.c ./spam_get.c
--- ../../netqmail-1.05-orig/netqmail-1.05/spam_get.c	1969-12-31 16:00:00.000000000 -0800
+++ ./spam_get.c	2006-01-05 15:03:43.394234448 -0800
@@ -0,0 +1,75 @@
+#include "stralloc.h"
+#include "spam.h"
+
+
+
+
+int spam_get(st,x,xlen)
+struct spam_t * st;
+char * x;
+unsigned int xlen;
+{
+  int n;
+  unsigned long u;
+
+  /*
+   * data entry format is dir\0st\0stmax\0flush\0rcpt\0tg\0tg_resp\0
+   */
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    if (!stralloc_copyb(&st->dir,x,n)) return -1;
+    if (!stralloc_0(&st->dir)) return -1;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    scan_ulong(x,&u);
+    st->throttle = u;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    scan_ulong(x,&u);
+    st->max = u;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    scan_ulong(x,&u);
+    st->flush = u;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    scan_ulong(x,&u);
+    st->reasonablercpt = u;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    scan_ulong(x,&u);
+    st->tg = u;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  n = byte_chr(x,xlen,0);
+  if (n > 0)
+  {
+    if (!stralloc_copyb(&st->tg_resp,x,n)) return -1;
+    if (!stralloc_0(&st->tg_resp)) return -1;
+  }
+  if (n++ == xlen) return 0; x += n; xlen -= n;
+
+  return 1;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spawn.c ./spawn.c
--- ../../netqmail-1.05-orig/netqmail-1.05/spawn.c	2006-01-05 15:06:38.665589152 -0800
+++ ./spawn.c	2006-01-05 15:03:43.396234144 -0800
@@ -64,7 +64,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};
@@ -74,6 +74,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);
 }
 
@@ -156,16 +157,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();
@@ -202,7 +206,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; }
 
@@ -237,7 +242,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 ../../netqmail-1.05-orig/netqmail-1.05/spf.c ./spf.c
--- ../../netqmail-1.05-orig/netqmail-1.05/spf.c	1969-12-31 16:00:00.000000000 -0800
+++ ./spf.c	2006-01-05 15:03:43.399233688 -0800
@@ -0,0 +1,878 @@
+#include "stralloc.h"
+#include "strsalloc.h"
+#include "alloc.h"
+#include "ip.h"
+#include "ipalloc.h"
+#include "ipme.h"
+#include "str.h"
+#include "fmt.h"
+#include "scan.h"
+#include "byte.h"
+#include "now.h"
+#include "dns.h"
+#include "case.h"
+#include "spf.h"
+
+#define SPF_EXT    -1
+#define SPF_SYNTAX -2
+
+#define WSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n')
+#define NXTOK(b, p, a) do { (b) = (p); \
+          while((p) < (a)->len && !WSPACE((a)->s[(p)])) ++(p); \
+          while((p) < (a)->len && WSPACE((a)->s[(p)])) (a)->s[(p)++] = 0; \
+        } while(0)
+
+/* this table and macro came from wget more or less */
+/* and was in turn stolen by me from libspf as is :) */
+const static unsigned char urlchr_table[256] =
+{
+  1,  1,  1,  1,   1,  1,  1,  1,   /* NUL SOH STX ETX  EOT ENQ ACK BEL */
+  1,  1,  1,  1,   1,  1,  1,  1,   /* BS  HT  LF  VT   FF  CR  SO  SI  */
+  1,  1,  1,  1,   1,  1,  1,  1,   /* DLE DC1 DC2 DC3  DC4 NAK SYN ETB */
+  1,  1,  1,  1,   1,  1,  1,  1,   /* CAN EM  SUB ESC  FS  GS  RS  US  */
+  1,  0,  1,  1,   0,  1,  1,  0,   /* SP  !   "   #    $   %   &   '   */
+  0,  0,  0,  1,   0,  0,  0,  1,   /* (   )   *   +    ,   -   .   /   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* 0   1   2   3    4   5   6   7   */
+  0,  0,  1,  1,   1,  1,  1,  1,   /* 8   9   :   ;    <   =   >   ?   */
+  1,  0,  0,  0,   0,  0,  0,  0,   /* @   A   B   C    D   E   F   G   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* H   I   J   K    L   M   N   O   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* P   Q   R   S    T   U   V   W   */
+  0,  0,  0,  1,   1,  1,  1,  0,   /* X   Y   Z   [    \   ]   ^   _   */
+  1,  0,  0,  0,   0,  0,  0,  0,   /* `   a   b   c    d   e   f   g   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* h   i   j   k    l   m   n   o   */
+  0,  0,  0,  0,   0,  0,  0,  0,   /* p   q   r   s    t   u   v   w   */
+  0,  0,  0,  1,   1,  1,  1,  1,   /* x   y   z   {    |   }   ~   DEL */
+
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+  1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,   1,  1,  1,  1,
+};
+
+
+extern stralloc addr;
+extern stralloc helohost;
+extern char *remoteip;
+extern char *local;
+
+extern stralloc spflocal;
+extern stralloc spfguess;
+extern stralloc spfexp;
+
+static stralloc sender_fqdn = {0};
+static stralloc explanation = {0};
+static stralloc expdomain = {0};
+static stralloc errormsg = {0};
+static char *received;
+
+static int recursion;
+static struct ip_address ip;
+
+static void hdr_pass() { received = "pass (%{xr}: %{xs} designates %{i} as permitted sender)"; };
+static void hdr_softfail() { received = "softfail (%{xr}: transitioning %{xs} does not designate %{i} as permitted sender)"; };
+static void hdr_fail() { received = "fail (%{xr}: %{xs} does not designate %{i} as permitted sender)"; };
+static void hdr_unknown() { received = "unknown (%{xr}: domain at %{d} does not designate permitted sender hosts)"; };
+static void hdr_neutral() { received = "neutral (%{xr}: %{i} is neither permitted nor denied by %{xs})"; };
+static void hdr_none() { received = "none (%{xr}: domain at %{d} does not designate permitted sender hosts)"; };
+static void hdr_unknown_msg(e) char *e; { stralloc_copys(&errormsg, e); received = "unknown (%{xr}: %{xe})"; };
+static void hdr_ext(e) char *e; { stralloc_copys(&errormsg, e); received = "unknown %{xe} (%{xr}: %{xs} uses mechanism not recognized by this client)"; };
+static void hdr_syntax() { received = "unknown (%{xr}: parse error in %{xs})"; };
+static void hdr_error(e) char *e; { stralloc_copys(&errormsg, e); received = "error (%{xr}: error in processing during lookup of %{d}: %{xe})"; };
+static void hdr_dns() { hdr_error("DNS problem"); }
+
+
+static int matchip(struct ip_address *net, int mask, struct ip_address *ip)
+{
+	int j;
+	int bytemask;
+
+	for (j = 0; j < 4 && mask > 0; ++j) {
+		if (mask > 8) bytemask = 8; else bytemask = mask;
+		mask -= bytemask;
+
+		if ((net->d[j] ^ ip->d[j]) & (0x100 - (1 << (8 - bytemask))))
+			return 0;
+	}
+	return 1;
+}
+
+static int getipmask(char *mask, int ipv6) {
+	unsigned long r;
+	int pos;
+
+	if (!mask) return 32;
+
+	pos = scan_ulong(mask, &r);
+	if (!pos || (mask[pos] && !(mask[pos] == '/' && ipv6))) return -1;
+	if (r > 32) return -1;
+
+	return r;
+}
+
+int spfget(stralloc *spf, stralloc *domain)
+{
+	strsalloc ssa = {0};
+	int j;
+	int begin, pos, i;
+	int r = SPF_NONE;
+
+	spf->len = 0;
+
+	switch(dns_txt(&ssa, domain)) {
+		case DNS_MEM: return SPF_NOMEM;
+		case DNS_SOFT: hdr_dns(); return SPF_ERROR;
+		case DNS_HARD: return SPF_NONE;
+	}
+
+	for (j = 0;j < ssa.len;++j) {
+		pos = 0;
+
+		NXTOK(begin, pos, &ssa.sa[j]);
+		if (str_len(ssa.sa[j].s + begin) < 6) continue;
+		if (!byte_equal(ssa.sa[j].s + begin,6,"v=spf1")) continue;
+		if (ssa.sa[j].s[begin + 6]) {
+			/* check for subversion */
+			if (ssa.sa[j].s[begin + 6] != '.') continue;
+			for(i = begin + 7;;++i)
+				if (!(ssa.sa[j].s[i] >= '0' && ssa.sa[j].s[i] <= '9')) break;
+			if (i == (begin + 7)) continue;
+			if (ssa.sa[j].s[i]) continue;
+		}
+
+		if (spf->len > 0) {
+			spf->len = 0;
+			hdr_unknown_msg("Multiple SPF records returned");
+			r = SPF_UNKNOWN;
+			break;
+		}
+		if (!stralloc_0(&ssa.sa[j])) return SPF_NOMEM;
+		if (!stralloc_copys(spf,ssa.sa[j].s + pos)) return SPF_NOMEM;
+		r = SPF_OK;
+	}
+
+	for (j = 0;j < ssa.len;++j)
+		alloc_free(ssa.sa[j].s);
+	alloc_free(ssa.sa);
+	return r;
+}
+
+static int spf_ptr(char *spec, char *mask);
+
+int spfsubst(stralloc *expand, char *spec, char *domain)
+{
+	static char hexdigits[] = "0123456789abcdef";
+	stralloc sa = {0};
+	char ch;
+	int digits = -1;
+	int urlencode = 0;
+	int reverse = 0;
+	int start = expand->len;
+	int i, pos;
+	char *split = ".";
+
+	if (!stralloc_readyplus(&sa,0)) return 0;
+
+	if (*spec == 'x') { i = 1; ++spec; } else i = 0;
+	ch = *spec++;
+	if (!ch) { alloc_free(sa.s); return 1; }
+	if (ch >= 'A' && ch <= 'Z') { ch += 32; urlencode = 1; }
+	if (i) ch -= 32;
+	while(*spec >= '0' && *spec <= '9') {
+		if (digits < 0) digits = 0;
+		if (digits >= 1000000) { digits = 10000000; continue; }
+		digits = (digits * 10) + (*spec - '0');
+		spec++;
+	}
+
+	while((*spec >= 'a' && *spec <= 'z') || (*spec >= 'A' && *spec <= 'Z')) {
+		if (*spec == 'r') reverse = 1;
+		spec++;
+	}
+
+	if (*spec) split = spec;
+
+	switch(ch) {
+		case 'l':
+			pos = byte_rchr(addr.s, addr.len, '@');
+			if (pos < addr.len) {
+				if (!stralloc_copyb(&sa, addr.s, pos)) return 0;
+			} else
+				if (!stralloc_copys(&sa, "postmaster")) return 0;
+			break;
+		case 's':
+			if (!stralloc_copys(&sa, addr.s)) return 0;
+			break;
+		case 'o':
+			pos = byte_rchr(addr.s, addr.len, '@') + 1;
+			if (pos > addr.len) break;
+			if (!stralloc_copys(&sa, addr.s + pos)) return 0;
+			break;
+		case 'd':
+			if (!stralloc_copys(&sa, domain)) return 0;
+			break;
+		case 'i':
+			if (!stralloc_ready(&sa, IPFMT)) return 0;
+			sa.len = ip_fmt(sa.s, &ip);
+			break;
+		case 't':
+			if (!stralloc_ready(&sa, FMT_ULONG)) return 0;
+			sa.len = fmt_ulong(sa.s, (unsigned long)now());
+			break;
+		case 'p':
+			if (!sender_fqdn.len)
+				spf_ptr(domain, 0);
+			if (sender_fqdn.len) {
+				if (!stralloc_copy(&sa, &sender_fqdn)) return 0;
+			} else
+				if (!stralloc_copys(&sa, "unknown")) return 0;
+			break;
+		case 'v': 
+			if (!stralloc_copys(&sa, "in-addr")) return 0;
+			break;
+		case 'h':
+			if (!stralloc_copys(&sa, helohost.s)) return 0; /* FIXME: FQDN? */
+			break;
+		case 'E':
+			if (errormsg.len && !stralloc_copy(&sa, &errormsg)) return 0;
+			break;
+		case 'R':
+			if (!stralloc_copys(&sa, local)) return 0;
+			break;
+		case 'S':
+			if (expdomain.len > 0) {
+				if (!stralloc_copys(&sa, "SPF record at ")) return 0;
+				if (!stralloc_cats(&sa, expdomain.s)) return 0;
+			} else {
+				if (!stralloc_copys(&sa, "local policy")) return 0;
+			}
+			break;
+	}
+
+	if (reverse) {
+		for(pos = 0; digits; ++pos) {
+			pos += byte_cspn(sa.s + pos, sa.len - pos, split);
+			if (pos >= sa.len) break;
+			if (!--digits) break;
+		}
+
+		for(; pos > 0; pos = i - 1) {
+			i = byte_rcspn(sa.s, pos, split) + 1;
+			if (i > pos) i = 0;
+			if (!stralloc_catb(expand, sa.s + i, pos - i)) return 0;
+			if (i > 0 && !stralloc_append(expand, ".")) return 0;
+		}
+	} else {
+		for(pos = sa.len; digits; --pos) {
+			i = byte_rcspn(sa.s, pos, split) + 1;
+			if (i > pos) { pos = 0; break; }
+			pos = i;
+			if (!--digits) break;
+		}
+
+		if (!stralloc_catb(expand, sa.s + pos, sa.len - pos)) return 0;
+		if (split[0] != '.' || split[1])
+			for(pos = 0; pos < expand->len; pos++) {
+				pos += byte_cspn(expand->s + pos, expand->len - pos, split);
+				if (pos < expand->len)
+					expand->s[pos] = '.';
+			}
+	}
+
+	if (urlencode) {
+		stralloc_copyb(&sa, expand->s + start, expand->len - start);
+		expand->len = start;
+
+		for(pos = 0; pos < sa.len; ++pos) {
+			ch = sa.s[pos];
+			if (urlchr_table[(unsigned char)ch]) {
+				if (!stralloc_readyplus(expand, 3)) return 0;
+				expand->s[expand->len++] = '%';
+				expand->s[expand->len++] = hexdigits[(unsigned char)ch >> 4];
+				expand->s[expand->len++] = hexdigits[(unsigned char)ch & 15];
+			} else
+				if (!stralloc_append(expand, &ch)) return 0;
+		}
+	}
+
+	alloc_free(sa.s);
+	return 1;
+}
+
+int spfexpand(stralloc *sa, char *spec, char *domain)
+{
+	char *p;
+	char append;
+	int pos;
+
+	if (!stralloc_readyplus(sa, 0)) return 0;
+	sa->len = 0;
+
+	for(p = spec; *p; p++) {
+		append = *p;
+		if (*p == '%') {
+			p++;
+			switch(*p) {
+				case '%': break;
+				case '_': append = ' '; break;
+				case '-': if (!stralloc_cats(sa, "%20")) return 0; continue;
+				case '{':
+					pos = str_chr(p, '}');
+					if (p[pos] != '}') { p--; break; }
+					p[pos] = 0;
+					if (!spfsubst(sa, p + 1, domain)) return 0;
+					p += pos;
+					continue;
+				default: p--;
+			}
+		}
+		if (!stralloc_append(sa, &append)) return 0;
+	}
+
+	return 1;
+}
+
+static int spflookup(stralloc *domain);
+
+static int spf_include(char *spec, char *mask)
+{
+	stralloc sa = {0};
+	int r;
+
+	if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
+	r = spflookup(&sa);
+	alloc_free(sa.s);
+
+	switch(r) {
+		case SPF_NONE:
+			hdr_unknown();
+			r = SPF_UNKNOWN;
+			break;
+		case SPF_SYNTAX:
+			r = SPF_UNKNOWN;
+			break;
+		case SPF_NEUTRAL:
+		case SPF_SOFTFAIL:
+		case SPF_FAIL:
+			r = SPF_NONE;
+			break;
+	}
+
+	return r;
+}
+
+static int spf_a(char *spec, char *mask)
+{
+	stralloc sa = {0};
+	ipalloc ia = {0};
+	int ipmask = getipmask(mask, 1);
+	int r;
+	int j;
+
+	if (ipmask < 0) return SPF_SYNTAX;
+
+	if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
+
+	switch(dns_ip(&ia, &sa)) {
+		case DNS_MEM: return SPF_NOMEM;
+		case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
+		case DNS_HARD: r = SPF_NONE; break;
+		default:
+			r = SPF_NONE;
+			for(j = 0; j < ia.len; ++j)
+				if (matchip(&ia.ix[j].ip, ipmask, &ip)) {
+					r = SPF_OK;
+					break;
+				}
+	}
+
+	alloc_free(sa.s);
+	alloc_free(ia.ix);
+	return r;
+}
+
+static int spf_mx(char *spec, char *mask)
+{
+	stralloc sa = {0};
+	ipalloc ia = {0};
+	int ipmask = getipmask(mask, 1);
+	int random = now() + (getpid() << 16);
+	int r;
+	int j;
+
+	if (ipmask < 0) return SPF_SYNTAX;
+
+	if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
+
+	switch(dns_mxip(&ia, &sa, random)) {
+		case DNS_MEM: return SPF_NOMEM;
+		case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
+		case DNS_HARD: r = SPF_NONE; break;
+		default:
+			r = SPF_NONE;
+			for(j = 0; j < ia.len; ++j)
+				if (matchip(&ia.ix[j].ip, ipmask, &ip)) {
+					r = SPF_OK;
+					break;
+				}
+	}
+
+	alloc_free(sa.s);
+	alloc_free(ia.ix);
+	return r;
+}
+
+static int spf_ptr(char *spec, char *mask)
+{
+	strsalloc ssa = {0};
+	ipalloc ia = {0};
+	int len = str_len(spec);
+	int r;
+	int j, k;
+	int pos;
+
+	/* we didn't find host with the matching ip before */
+	if (sender_fqdn.len == 7 && str_equal(sender_fqdn.s, "unknown"))
+		return SPF_NONE;
+
+	/* the hostname found will probably be the same as before */
+	while (sender_fqdn.len) {
+		pos = sender_fqdn.len - len;
+		if (pos < 0) break;
+		if (pos > 0 && sender_fqdn.s[pos - 1] != '.') break;
+		if (case_diffb(sender_fqdn.s + pos, len, spec)) break;
+
+		return SPF_OK;
+	}
+
+	/* ok, either it's the first test or it's a very weird setup */
+
+	if (!stralloc_readyplus(&ssa, 0)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
+
+	switch(dns_ptr(&ssa, &ip)) {
+		case DNS_MEM: return SPF_NOMEM;
+		case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
+		case DNS_HARD: r = SPF_NONE; break;
+		default:
+			r = SPF_NONE;
+			for(j = 0; j < ssa.len; ++j) {
+				switch(dns_ip(&ia, &ssa.sa[j])) {
+					case DNS_MEM: return SPF_NOMEM;
+					case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
+					case DNS_HARD: break;
+					default:
+						for(k = 0; k < ia.len; ++k)
+							if (matchip(&ia.ix[k].ip, 32, &ip)) {
+								if (!sender_fqdn.len)
+									if (!stralloc_copy(&sender_fqdn, &ssa.sa[j])) return SPF_NOMEM;
+
+								pos = ssa.sa[j].len - len;
+								if (pos < 0) continue;
+								if (pos > 0 && ssa.sa[j].s[pos - 1] != '.') continue;
+								if (case_diffb(ssa.sa[j].s + pos, len, spec)) continue;
+
+								stralloc_copy(&sender_fqdn, &ssa.sa[j]);
+								r = SPF_OK;
+								break;
+							}
+				}
+
+				if (r == SPF_ERROR) break;
+			}
+	}
+
+	for(j = 0;j < ssa.len;++j)
+		alloc_free(ssa.sa[j].s);
+
+	alloc_free(ssa.sa);
+	alloc_free(ia.ix);
+
+	if (!sender_fqdn.len)
+		if (!stralloc_copys(&sender_fqdn, "unknown")) return SPF_NOMEM;
+
+	return r;
+}
+
+static int spf_ip(char *spec, char *mask)
+{
+	struct ip_address net;
+	int ipmask = getipmask(mask, 0);
+
+	if (ipmask < 0) return SPF_SYNTAX;
+	if (!ip_scan(spec, &net)) return SPF_SYNTAX;
+
+	if (matchip(&net, ipmask, &ip)) return SPF_OK;
+
+	return SPF_NONE;
+}
+
+static int spf_exists(char *spec, char *mask)
+{
+	stralloc sa = {0};
+	ipalloc ia = {0};
+	int r;
+
+	if (!stralloc_copys(&sa, spec)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM;
+
+	switch(dns_ip(&ia, &sa)) {
+		case DNS_MEM: return SPF_NOMEM;
+		case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break;
+		case DNS_HARD: r = SPF_NONE; break;
+		default: r = SPF_OK;
+	}
+
+	alloc_free(sa.s);
+	alloc_free(ia.ix);
+	return r;
+}
+
+static struct mechanisms {
+  char *mechanism;
+  int (*func)(char *spec, char *mask);
+  unsigned int takes_spec  : 1;
+  unsigned int takes_mask  : 1;
+  unsigned int expands     : 1;
+  unsigned int filldomain  : 1;
+  int defresult            : 4;
+} mechanisms[] = {
+  { "all",      0,          0,0,0,0,SPF_OK   }
+, { "include",  spf_include,1,0,1,0,0        }
+, { "a",        spf_a,      1,1,1,1,0        }
+, { "mx",       spf_mx,     1,1,1,1,0        }
+, { "ptr",      spf_ptr,    1,0,1,1,0        }
+, { "ip4",      spf_ip,     1,1,0,0,0        }
+, { "ip6",      0,          1,1,0,0,SPF_NONE }
+, { "exists",   spf_exists, 1,0,1,0,0        }
+, { "extension",0,          1,1,0,0,SPF_EXT  }
+, { 0,          0,          1,1,0,0,SPF_EXT  }
+};
+
+static int spfmech(char *mechanism, char *spec, char *mask, char *domain)
+{
+	struct mechanisms *mech;
+	stralloc sa = {0};
+	int r;
+	int pos;
+
+	for(mech = mechanisms; mech->mechanism; mech++)
+		if (str_equal(mech->mechanism, mechanism)) break;
+
+	if (mech->takes_spec && !spec && mech->filldomain) spec = domain;
+	if (!mech->takes_spec != !spec) return SPF_SYNTAX;
+	if (!mech->takes_mask && mask) return SPF_SYNTAX;
+	if (!mech->func) return mech->defresult;
+
+	if (!stralloc_readyplus(&sa, 0)) return SPF_NOMEM;
+	if (mech->expands && spec != domain) {
+		if (!spfexpand(&sa, spec, domain)) return SPF_NOMEM;
+		for (pos = 0; (sa.len - pos) > 255;) {
+			pos += byte_chr(sa.s + pos, sa.len - pos, '.');
+			if (pos < sa.len) pos++;
+		}
+		sa.len -= pos;
+		if (pos > 0) byte_copy(sa.s, sa.len, sa.s + pos);
+		stralloc_0(&sa);
+		spec = sa.s;
+	}
+
+	r = mech->func(spec, mask);
+
+	alloc_free(sa.s);
+	return r;
+}
+
+static struct default_aliases {
+  char *alias;
+  int defret;
+} default_aliases[] = {
+  { "allow",   SPF_OK }
+, { "pass",    SPF_OK }
+, { "deny",    SPF_FAIL }
+, { "softdeny",SPF_SOFTFAIL }
+, { "fail",    SPF_FAIL }
+, { "softfail",SPF_SOFTFAIL }
+, { "unknown", SPF_NEUTRAL }
+, { 0,         SPF_UNKNOWN }
+};
+
+static int spflookup(stralloc *domain)
+{
+	stralloc spf = {0};
+	stralloc sa = {0};
+	struct default_aliases *da;
+	int main = !recursion;
+	int local_pos = -1;
+	int r, q;
+	int begin, pos;
+	int i;
+	int prefix;
+	int done;
+	int guessing = 0;
+	char *p;
+
+	if (!stralloc_readyplus(&spf, 0)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&sa, 0)) return SPF_NOMEM;
+
+	/* fallthrough result */
+	if (main) hdr_none();
+
+redirect:
+	if (++recursion > 20) {
+		alloc_free(spf.s);
+		alloc_free(sa.s);
+		hdr_unknown_msg("Maximum nesting level exceeded, possible loop");
+		return SPF_SYNTAX;
+	}
+
+	if (!stralloc_0(domain)) return SPF_NOMEM;
+	if (!stralloc_copy(&expdomain, domain)) return SPF_NOMEM;
+
+	r = spfget(&spf, domain);
+	if (r == SPF_NONE) {
+		if (!main) { alloc_free(spf.s); return r; }
+
+		if (spfguess.len) {
+			/* try to guess */
+			guessing = 1;
+			if (!stralloc_copys(&spf, spfguess.s)) return SPF_NOMEM;
+			if (!stralloc_append(&spf, " ")) return SPF_NOMEM;
+		} else
+			spf.len = 0;
+
+		/* append local rulest */
+		if (spflocal.len) {
+			local_pos = spf.len;
+			if (!stralloc_cats(&spf, spflocal.s)) return SPF_NOMEM;
+		}
+		if (!stralloc_0(&spf)) return SPF_NOMEM;
+
+		expdomain.len = 0;
+	} else if (r == SPF_OK) {
+		if (!stralloc_0(&spf)) return SPF_NOMEM;
+		if (main) hdr_neutral();
+		r = SPF_NEUTRAL;
+
+		/* try to add local rules before fail all mechs */
+		if (main && spflocal.len) {
+			pos = 0;
+			p = (char *) 0;
+			while(pos < spf.len) {
+				NXTOK(begin, pos, &spf);
+				if (!spf.s[begin]) continue;
+
+				if (p && spf.s[begin] != *p) p = (char *) 0;
+				if (!p && (spf.s[begin] == '-' || spf.s[begin] == '~' ||
+				           spf.s[begin] == '?')) p = &spf.s[begin];
+
+				if (p && p > spf.s && str_equal(spf.s + begin + 1, "all")) {
+					/* ok, we can insert the local rules at p */
+					local_pos = p - spf.s;
+
+					stralloc_readyplus(&spf, spflocal.len);
+					p = spf.s + local_pos;
+					byte_copyr(p + spflocal.len, spf.len - local_pos, p);
+					byte_copy(p, spflocal.len, spflocal.s);
+					spf.len += spflocal.len;
+
+					pos += spflocal.len;
+					break;
+				}
+			}
+
+			if (pos >= spf.len) pos = spf.len - 1;
+			for(i = 0; i < pos; i++)
+				if (!spf.s[i]) spf.s[i] = ' ';
+		}
+	} else {
+		alloc_free(spf.s);
+		return r;
+	}
+
+	pos = 0;
+	done = 0;
+	while(pos < spf.len) {
+		NXTOK(begin, pos, &spf);
+		if (!spf.s[begin]) continue;
+
+		/* in local ruleset? */
+		if (!done && local_pos >= 0 && begin >= local_pos) {
+			if (begin < (local_pos + spflocal.len))
+				expdomain.len = 0;
+			else
+				if (!stralloc_copy(&expdomain, domain))
+					return SPF_NOMEM;
+		}
+
+		for (p = spf.s + begin;*p;++p)
+			if (*p == ':' || *p == '/' || *p == '=') break;
+
+		if (*p == '=') {
+			*p++ = 0;
+
+			/* modifiers are simply handled here */
+			if (str_equal(spf.s + begin, "redirect")) {
+				if (done) continue;
+
+				if (!spfexpand(&sa, p, domain->s)) return SPF_NOMEM;
+				stralloc_copy(domain, &sa);
+
+				hdr_unknown();
+				r = SPF_UNKNOWN;
+
+				goto redirect;
+			} else if (str_equal(spf.s + begin, "default")) {
+				if (done) continue;
+
+				for(da = default_aliases; da->alias; ++da)
+					if (str_equal(da->alias, p)) break;
+
+				r = da->defret;
+			} else if (str_equal(spf.s + begin, "exp")) {
+				strsalloc ssa = {0};
+
+				if (!main) continue;
+
+				if (!stralloc_copys(&sa, p)) return SPF_NOMEM;
+				switch(dns_txt(&ssa, &sa)) {
+					case DNS_MEM: return SPF_NOMEM;
+					case DNS_SOFT: continue; /* FIXME... */
+					case DNS_HARD: continue;
+				}
+
+				explanation.len = 0;
+				for(i = 0; i < ssa.len; i++) {
+					if (!stralloc_cat(&explanation, &ssa.sa[i])) return SPF_NOMEM;
+					if (i < (ssa.len - 1))
+						if (!stralloc_append(&explanation, "\n")) return SPF_NOMEM;
+
+					alloc_free(ssa.sa[i].s);
+				}
+				if (!stralloc_0(&explanation)) return SPF_NOMEM;
+			} /* and unknown modifiers are ignored */
+		} else if (!done) {
+			if (!stralloc_copys(&sa, spf.s + begin)) return SPF_NOMEM;
+			if (!stralloc_0(&sa)) return SPF_NOMEM;
+
+			switch(spf.s[begin]) {
+				case '-': begin++; prefix = SPF_FAIL; break;
+				case '~': begin++; prefix = SPF_SOFTFAIL; break;
+				case '+': begin++; prefix = SPF_OK; break;
+				case '?': begin++; prefix = SPF_NEUTRAL; break;
+				default: prefix = SPF_OK;
+			}
+
+			if (*p == '/') {
+				*p++ = 0;
+				q = spfmech(spf.s + begin, 0, p, domain->s);
+			} else {
+				if (*p) *p++ = 0;
+				i = str_chr(p, '/');
+				if (p[i] == '/') {
+					p[i++] = 0;
+					q = spfmech(spf.s + begin, p, p + i, domain->s);
+				} else if (i > 0)
+					q = spfmech(spf.s + begin, p, 0, domain->s);
+				else
+					q = spfmech(spf.s + begin, 0, 0, domain->s);
+			}
+
+			if (q == SPF_OK) q = prefix;
+
+			switch(q) {
+				case SPF_OK: hdr_pass(); break;
+				case SPF_NEUTRAL: hdr_neutral(); break;
+				case SPF_SYNTAX: hdr_syntax(); break;
+				case SPF_SOFTFAIL: hdr_softfail(); break;
+				case SPF_FAIL: hdr_fail(); break;
+				case SPF_EXT: hdr_ext(sa.s); break;
+				case SPF_ERROR:
+					if (!guessing)
+						break;
+					if (local_pos >= 0 && begin >= local_pos)
+						break;
+					hdr_none();
+					q = SPF_NONE;
+					break;
+				case SPF_NONE: continue;
+			}
+
+			r = q;
+			done = 1; /* we're done, no more mechanisms */
+		}
+	}
+
+	/* we fell through, no local rule applied */
+	if (!done && !stralloc_copy(&expdomain, domain)) return SPF_NOMEM;
+
+	alloc_free(spf.s);
+	alloc_free(sa.s);
+	return r;
+}
+
+int spfcheck()
+{
+	stralloc domain = {0};
+	int pos;
+	int r;
+
+	pos = byte_rchr(addr.s, addr.len, '@') + 1;
+	if (pos < addr.len) {
+		if (!stralloc_copys(&domain, addr.s + pos)) return SPF_NOMEM;
+	} else {
+		pos = str_rchr(helohost.s, '@');
+		if (helohost.s[pos]) {
+			if (!stralloc_copys(&domain, helohost.s + pos + 1)) return SPF_NOMEM;
+		} else
+			if (!stralloc_copys(&domain, helohost.s)) return SPF_NOMEM;
+	}
+	if (!stralloc_copys(&explanation, spfexp.s)) return SPF_NOMEM;
+	if (!stralloc_0(&explanation)) return SPF_NOMEM;
+	recursion = 0;
+
+	if (!remoteip || !ip_scan(remoteip, &ip)) {
+		hdr_unknown_msg("No IP address in conversation");
+		return SPF_UNKNOWN;
+	}
+
+	if (!stralloc_readyplus(&expdomain, 0)) return SPF_NOMEM;
+	if (!stralloc_readyplus(&errormsg, 0)) return SPF_NOMEM;
+	expdomain.len = 0;
+	errormsg.len = 0;
+	sender_fqdn.len = 0;
+	received = (char *) 0;
+
+	if ((ip.d[0] == 127 && ip.d[1] == 0 && ip.d[2] == 0 && ip.d[3] == 1) || ipme_is(&ip))
+		{ hdr_pass(); r = SPF_OK; }
+	else
+		r = spflookup(&domain);
+
+	if (r < 0) r = SPF_UNKNOWN;
+
+	alloc_free(domain.s);
+	return r;
+}
+
+int spfexplanation(sa)
+stralloc *sa;
+{
+	return spfexpand(sa, explanation.s, expdomain.s);
+}
+
+int spfinfo(sa)
+stralloc *sa;
+{
+	stralloc tmp = {0};
+	if (!stralloc_copys(&tmp, received)) return 0;
+	if (!stralloc_0(&tmp)) return 0;
+	if (!spfexpand(sa, tmp.s, expdomain.s)) return 0;
+	alloc_free(tmp.s);
+	return 1;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spf.h ./spf.h
--- ../../netqmail-1.05-orig/netqmail-1.05/spf.h	1969-12-31 16:00:00.000000000 -0800
+++ ./spf.h	2006-01-05 15:03:43.400233536 -0800
@@ -0,0 +1,20 @@
+#ifndef SPF_H
+#define SPF_H
+
+#define SPF_OK       0
+#define SPF_NONE     1
+#define SPF_UNKNOWN  2
+#define SPF_NEUTRAL  3
+#define SPF_SOFTFAIL 4
+#define SPF_FAIL     5
+#define SPF_ERROR    6
+#define SPF_NOMEM    7
+
+#define SPF_DEFEXP   "See http://spf.pobox.com/" \
+                     "why.html?sender=%{S}&ip=%{I}&receiver=%{xR}"
+
+extern int spfcheck();
+extern int spfexplanation();
+extern int spfinfo();
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/spfquery.c ./spfquery.c
--- ../../netqmail-1.05-orig/netqmail-1.05/spfquery.c	1969-12-31 16:00:00.000000000 -0800
+++ ./spfquery.c	2006-01-05 15:03:43.401233384 -0800
@@ -0,0 +1,84 @@
+#include "substdio.h"
+#include "subfd.h"
+#include "stralloc.h"
+#include "alloc.h"
+#include "spf.h"
+#include "exit.h"
+
+void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); }
+void die_usage() { die(100,"fatal: invalid usage\nusage: spfquery <sender-ip> <sender-helo/ehlo> <envelope-from> [<local rules>] [<best guess rules>]\n"); }
+void die_nomem() { die(111,"fatal: out of memory\n"); }
+
+stralloc addr = {0};
+stralloc helohost = {0};
+char *remoteip;
+char *local;
+
+stralloc spflocal = {0};
+stralloc spfguess = {0};
+stralloc spfexp = {0};
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+	stralloc sa = {0};
+	int r;
+
+	if (argc < 4) die_usage();
+
+	remoteip = (char *)strdup(argv[1]);
+	local = "localhost";
+
+	if (!stralloc_copys(&helohost, argv[2])) die_nomem();
+	if (!stralloc_0(&helohost)) die_nomem();
+
+	if (!stralloc_copys(&addr, argv[3])) die_nomem();
+	if (!stralloc_0(&addr)) die_nomem();
+
+	if (argc > 4) {
+		if (!stralloc_copys(&spflocal, argv[4])) die_nomem();
+		if (spflocal.len && !stralloc_0(&spflocal)) die_nomem();
+	}
+
+	if (argc > 5) {
+		if (!stralloc_copys(&spfguess, argv[5])) die_nomem();
+		if (spfguess.len && !stralloc_0(&spfguess)) die_nomem();
+	}
+
+	if (argc > 6) {
+		if (!stralloc_copys(&spfexp, argv[6])) die_nomem();
+	} else
+		if (!stralloc_copys(&spfexp, SPF_DEFEXP)) die_nomem();
+	if (spfexp.len && !stralloc_0(&spfexp)) die_nomem();
+
+	dns_init(0);
+	r = spfcheck();
+	if (r == SPF_NOMEM) die_nomem();
+
+	substdio_puts(subfdout,"result=");
+	switch(r) {
+		case SPF_OK: substdio_puts(subfdout,"pass"); break;
+		case SPF_NONE: substdio_puts(subfdout,"none"); break;
+		case SPF_UNKNOWN: substdio_puts(subfdout,"unknown"); break;
+		case SPF_NEUTRAL: substdio_puts(subfdout,"neutral"); break;
+		case SPF_SOFTFAIL: substdio_puts(subfdout,"softfail"); break;
+		case SPF_FAIL: substdio_puts(subfdout,"fail"); break;
+		case SPF_ERROR: substdio_puts(subfdout,"error"); break;
+	}
+
+	if (r == SPF_FAIL) {
+		substdio_puts(subfdout,": ");
+		if (!spfexplanation(&sa)) die_nomem();
+		substdio_put(subfdout,sa.s,sa.len);
+	}
+
+	substdio_putsflush(subfdout,"\n");
+
+	substdio_puts(subfdout,"Received-SPF: ");
+	if (!spfinfo(&sa)) die_nomem();
+	substdio_put(subfdout,sa.s,sa.len);
+	substdio_putsflush(subfdout,"\n");
+
+	_exit(0);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.c ./ssl_timeoutio.c
--- ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.c	1969-12-31 16:00:00.000000000 -0800
+++ ./ssl_timeoutio.c	2006-01-05 15:03:43.403233080 -0800
@@ -0,0 +1,94 @@
+#include "select.h"
+#include "error.h"
+#include "ndelay.h"
+#include "ssl_timeoutio.h"
+
+int ssl_timeoutio(int (*fun)(),
+  long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  int n;
+  const long end = t + time(NULL);
+
+  do {
+    fd_set fds;
+    struct timeval tv;
+
+    const int r = buf ? fun(ssl, buf, len) : fun(ssl);
+    if (r > 0) return r;
+
+    t = end - time(NULL);
+    if (t < 0) break;
+    tv.tv_sec = t; tv.tv_usec = 0;
+
+    FD_ZERO(&fds);
+    switch (SSL_get_error(ssl, r))
+    {
+    default: return r; /* some other error */
+    case SSL_ERROR_WANT_READ:
+      FD_SET(rfd, &fds); n = select(rfd + 1, &fds, NULL, NULL, &tv);
+      break;
+    case SSL_ERROR_WANT_WRITE:
+      FD_SET(wfd, &fds); n = select(wfd + 1, NULL, &fds, NULL, &tv);
+      break;
+    }
+
+    /* n is the number of descriptors that changed status */
+  } while (n > 0);
+
+  if (n != -1) errno = error_timeout;
+  return -1;
+}
+
+int ssl_timeoutaccept(long t, int rfd, int wfd, SSL *ssl)
+{
+  int r;
+
+  /* if connection is established, keep NDELAY */
+  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
+  r = ssl_timeoutio(SSL_accept, t, rfd, wfd, ssl, NULL, 0);
+
+  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
+  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+  return r;
+}
+
+int ssl_timeoutconn(long t, int rfd, int wfd, SSL *ssl)
+{
+  int r;
+
+  /* if connection is established, keep NDELAY */
+  if (ndelay_on(rfd) == -1 || ndelay_on(wfd) == -1) return -1;
+  r = ssl_timeoutio(SSL_connect, t, rfd, wfd, ssl, NULL, 0);
+
+  if (r <= 0) { ndelay_off(rfd); ndelay_off(wfd); }
+  else SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+  return r;
+}
+
+int ssl_timeoutrehandshake(long t, int rfd, int wfd, SSL *ssl)
+{
+  int r;
+
+  SSL_renegotiate(ssl);
+  r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
+  if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r;
+
+  /* this is for the server only */
+  ssl->state = SSL_ST_ACCEPT;
+  return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0);
+}
+
+int ssl_timeoutread(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  if (!buf) return 0;
+  if (SSL_pending(ssl)) return SSL_read(ssl, buf, len);
+  return ssl_timeoutio(SSL_read, t, rfd, wfd, ssl, buf, len);
+}
+
+int ssl_timeoutwrite(long t, int rfd, int wfd, SSL *ssl, char *buf, int len)
+{
+  if (!buf) return 0;
+  return ssl_timeoutio(SSL_write, t, rfd, wfd, ssl, buf, len);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.h ./ssl_timeoutio.h
--- ../../netqmail-1.05-orig/netqmail-1.05/ssl_timeoutio.h	1969-12-31 16:00:00.000000000 -0800
+++ ./ssl_timeoutio.h	2006-01-05 15:03:43.404232928 -0800
@@ -0,0 +1,21 @@
+#ifndef SSL_TIMEOUTIO_H
+#define SSL_TIMEOUTIO_H
+
+#include <openssl/ssl.h>
+
+/* the version is like this: 0xMNNFFPPS: major minor fix patch status */
+#if OPENSSL_VERSION_NUMBER < 0x00906000L
+# error "Need OpenSSL version at least 0.9.6"
+#endif
+
+int ssl_timeoutconn(long t, int rfd, int wfd, SSL *ssl);
+int ssl_timeoutaccept(long t, int rfd, int wfd, SSL *ssl);
+int ssl_timeoutrehandshake(long t, int rfd, int wfd, SSL *ssl);
+
+int ssl_timeoutread(long t, int rfd, int wfd, SSL *ssl, char *buf, int len);
+int ssl_timeoutwrite(long t, int rfd, int wfd, SSL *ssl, char *buf, int len);
+
+int ssl_timeoutio(
+  int (*fun)(), long t, int rfd, int wfd, SSL *ssl, char *buf, int len);
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/str.h ./str.h
--- ../../netqmail-1.05-orig/netqmail-1.05/str.h	1998-06-15 03:53:16.000000000 -0700
+++ ./str.h	2006-01-05 15:03:43.405232776 -0800
@@ -2,6 +2,7 @@
 #define STR_H
 
 extern unsigned int str_copy();
+extern unsigned int str_copyb();
 extern int str_diff();
 extern int str_diffn();
 extern unsigned int str_len();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/str_cpyb.c ./str_cpyb.c
--- ../../netqmail-1.05-orig/netqmail-1.05/str_cpyb.c	1969-12-31 16:00:00.000000000 -0800
+++ ./str_cpyb.c	2006-01-05 15:03:43.406232624 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/strpidt.c ./strpidt.c
--- ../../netqmail-1.05-orig/netqmail-1.05/strpidt.c	1969-12-31 16:00:00.000000000 -0800
+++ ./strpidt.c	2006-01-05 15:03:43.407232472 -0800
@@ -0,0 +1,26 @@
+/*
+** Copyright 1998 - 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+#include	"numlib.h"
+#include	<string.h>
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+char *str_pid_t(pid_t t, char *arg)
+{
+char	buf[NUMBUFSIZE];
+char	*p=buf+sizeof(buf)-1;
+
+	*p=0;
+	do
+	{
+		*--p= '0' + (t % 10);
+		t=t / 10;
+	} while(t);
+	return (strcpy(arg, p));
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/strsalloc.c ./strsalloc.c
--- ../../netqmail-1.05-orig/netqmail-1.05/strsalloc.c	1969-12-31 16:00:00.000000000 -0800
+++ ./strsalloc.c	2006-01-05 15:03:43.408232320 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/strsalloc.h ./strsalloc.h
--- ../../netqmail-1.05-orig/netqmail-1.05/strsalloc.h	1969-12-31 16:00:00.000000000 -0800
+++ ./strsalloc.h	2006-01-05 15:03:43.409232168 -0800
@@ -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 ../../netqmail-1.05-orig/netqmail-1.05/strtimet.c ./strtimet.c
--- ../../netqmail-1.05-orig/netqmail-1.05/strtimet.c	1969-12-31 16:00:00.000000000 -0800
+++ ./strtimet.c	2006-01-05 15:03:43.410232016 -0800
@@ -0,0 +1,26 @@
+/*
+** Copyright 1998 - 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#if	HAVE_CONFIG_H
+#include	"config.h"
+#endif
+#include	"numlib.h"
+#include	<string.h>
+
+static const char rcsid[]="$Id: netqmail-1.05-toaster-3.1.patch,v 1.1 2006/03/18 03:32:53 matt Exp $";
+
+char *str_time_t(time_t t, char *arg)
+{
+char	buf[NUMBUFSIZE];
+char	*p=buf+sizeof(buf)-1;
+
+	*p=0;
+	do
+	{
+		*--p= '0' + (t % 10);
+		t=t / 10;
+	} while(t);
+	return (strcpy(arg, p));
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tcp-env.1 ./tcp-env.1
--- ../../netqmail-1.05-orig/netqmail-1.05/tcp-env.1	1998-06-15 03:53:16.000000000 -0700
+++ ./tcp-env.1	2006-01-05 15:03:43.411231864 -0800
@@ -4,7 +4,10 @@
 .SH SYNOPSIS
 .B tcp-env
 [
-.B \-rR
+.B \-rRhH
+]
+[
+.B \-l\fIlocalname
 ]
 [
 .B \-t\fItimeout
@@ -55,6 +58,20 @@
 .B TCPREMOTEINFO
 from the remote host.
 .TP
+.B \-h
+(Default.)
+Look up the remote host name in DNS to set the environment variable
+.BR TCPREMOTEHOST .
+.TP
+.B \-H
+Do not look up the remote host name in DNS; remove the environment variable 
+.BR TCPREMOTEHOST .
+.TP
+.B \-l\fIlocalname
+Do not look up the local host name in DNS; use localname for the environment variable 
+.BR TCPLOCALHOST .
+A common choice for localname is 0.
+.TP
 .B \-t\fItimeout
 Give up on the
 .B TCPREMOTEINFO
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tcp-env.c ./tcp-env.c
--- ../../netqmail-1.05-orig/netqmail-1.05/tcp-env.c	1998-06-15 03:53:16.000000000 -0700
+++ ./tcp-env.c	2006-01-05 15:03:43.413231560 -0800
@@ -10,6 +10,7 @@
 #include "scan.h"
 #include "subgetopt.h"
 #include "ip.h"
+#include "strsalloc.h"
 #include "dns.h"
 #include "byte.h"
 #include "remoteinfo.h"
@@ -18,10 +19,13 @@
 
 void die() { _exit(111); }
 
+int flagremotehost = 1;
+
 struct sockaddr_in salocal;
 unsigned long localport;
 struct ip_address iplocal;
 stralloc localname = {0};
+char *localhost = 0;
 
 struct sockaddr_in saremote;
 unsigned long remoteport;
@@ -34,6 +38,7 @@
 int argc;
 char *argv[];
 {
+ strsalloc ssa = {0};
  int dummy;
  char *proto;
  int opt;
@@ -50,6 +55,9 @@
      case 'r': flagremoteinfo = 1; break;
      case 'R': flagremoteinfo = 0; break;
      case 't': scan_ulong(sgoptarg,&timeout); break;
+     case 'H': flagremotehost = 0; break;
+     case 'h': flagremotehost = 1; break;
+     case 'l': localhost = sgoptarg; break;
     }
 
  argv += sgoptind;
@@ -74,19 +82,27 @@
    temp[ip_fmt(temp,&iplocal)] = 0;
    if (!env_put2("TCPLOCALIP",temp)) die();
 
-   switch(dns_ptr(&localname,&iplocal))
+   if (!localhost)
+    {
+   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();
+	 localhost = localname.s;
        break;
      default:
        if (!env_unset("TCPLOCALHOST")) die();
     }
+    }
+   if (localhost)
+    {
+     if (!env_put2("TCPLOCALHOST",localhost)) die();
+    }
 
    dummy = sizeof(saremote);
    if (getpeername(0,(struct sockaddr *) &saremote,&dummy) == -1) die();
@@ -99,18 +115,22 @@
    temp[ip_fmt(temp,&ipremote)] = 0;
    if (!env_put2("TCPREMOTEIP",temp)) die();
 
-   switch(dns_ptr(&remotename,&ipremote))
+   if (flagremotehost)
+    {
+   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();
        break;
      default:
        if (!env_unset("TCPREMOTEHOST")) die();
+      }
     }
 
    if (!env_unset("TCPREMOTEINFO")) die();
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/time.c ./time.c
--- ../../netqmail-1.05-orig/netqmail-1.05/time.c	1969-12-31 16:00:00.000000000 -0800
+++ ./time.c	2006-01-05 15:03:43.414231408 -0800
@@ -0,0 +1,82 @@
+#include "time.h"
+#include "stralloc.h"
+#include "fmt.h"
+#include "scan.h"
+
+void time_unpack(s,t)
+char *s;
+struct q_time_t *t;
+{
+#ifdef HASTAI
+  taia_unpack(s,t);
+#else
+  int i;
+
+  i = scan_ulong(s,&(t->tv_sec));
+  if (s[i] == ':')
+    scan_ulong(s+i+1,&(t->tv_usec));
+  else
+    t->tv_usec = 0;
+#endif
+}
+
+
+void time_pack(sa,t)
+stralloc *sa;
+struct q_time_t *t;
+{
+#ifdef HASTAI
+  stralloc_ready(sa,TAIA_PACK);
+  taia_pack(sa->s,t);
+  sa->len = TAIA_PACK;
+#else
+  char strnum[FMT_ULONG];
+
+  stralloc_catb(sa,strnum,fmt_ulong(strnum,(unsigned long)t->tv_sec));
+  stralloc_cats(sa,":");
+  stralloc_catb(sa,strnum,fmt_ulong0(strnum,(unsigned long)t->tv_usec,6));
+  stralloc_0(sa);
+#endif
+}
+
+void time_now(t)
+struct q_time_t *t;
+{
+#ifdef HASTAI
+  taia_now(t);
+#else
+  gettimeofday(t,0);
+#endif
+}
+
+
+void time_sub(td,t1,t2)
+struct q_time_t *td;
+struct q_time_t *t1;
+struct q_time_t *t2;
+{
+#ifdef HASTAI
+  taia_sub(td,t1,t2);
+#else
+  unsigned long usec = t1->tv_usec;
+  
+  td->tv_sec = t1->tv_sec - t2->tv_sec;
+  td->tv_usec = usec - t2->tv_usec;
+  if (td->tv_usec > usec)
+   {
+    td->tv_usec += 1000000UL;
+    --td->tv_sec;
+   }
+#endif
+}
+
+
+unsigned long time_ms(t)
+struct q_time_t *t;
+{
+#ifdef HASTAI
+  return (unsigned long)((taia_approx(t) + taia_frac(t)) * (double)1000.0);
+#else
+  return (unsigned long)((double)1000.0 * t->tv_sec + t->tv_usec / (double)1000.0);
+#endif
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/time.h ./time.h
--- ../../netqmail-1.05-orig/netqmail-1.05/time.h	1969-12-31 16:00:00.000000000 -0800
+++ ./time.h	2006-01-05 15:03:43.415231256 -0800
@@ -0,0 +1,22 @@
+#ifndef TIME_H
+#define TIME_H
+
+#include "hastai.h"
+
+#ifdef HASTAI
+# include <taia.h>
+# define q_time_t	taia
+# define Q_TIME_PACK	TAIA_PACK
+#else
+# include <sys/time.h>
+# define q_time_t	timeval
+# define Q_TIME_PACK	0
+#endif
+
+void time_pack();
+void time_unpack();
+void time_now();
+void time_sub();
+unsigned long time_ms();
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tls.c ./tls.c
--- ../../netqmail-1.05-orig/netqmail-1.05/tls.c	1969-12-31 16:00:00.000000000 -0800
+++ ./tls.c	2006-01-05 15:08:14.806973440 -0800
@@ -0,0 +1,25 @@
+#include "exit.h"
+#include "error.h"
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+int smtps = 0;
+SSL *ssl = NULL;
+
+void ssl_free(SSL *myssl) { SSL_shutdown(myssl); SSL_free(myssl); }
+void ssl_exit(int status) { if (ssl) ssl_free(ssl); _exit(status); }
+
+const char *ssl_error()
+{
+  int r = ERR_get_error();
+  if (!r) return NULL;
+  SSL_load_error_strings();
+  return ERR_error_string(r, NULL);
+}
+const char *ssl_error_str()
+{
+  const char *err = ssl_error();
+  if (err) return err;
+  if (!errno) return 0;
+  return (errno == error_timeout) ? "timed out" : error_str(errno);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tls.h ./tls.h
--- ../../netqmail-1.05-orig/netqmail-1.05/tls.h	1969-12-31 16:00:00.000000000 -0800
+++ ./tls.h	2006-01-05 15:08:14.807973288 -0800
@@ -0,0 +1,16 @@
+#ifndef TLS_H
+#define TLS_H
+
+#include <openssl/ssl.h>
+
+extern int smtps;
+extern SSL *ssl;
+
+void ssl_free(SSL *myssl);
+void ssl_exit(int status);
+# define _exit ssl_exit
+
+const char *ssl_error();
+const char *ssl_error_str();
+
+#endif
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/tryltai.c ./tryltai.c
--- ../../netqmail-1.05-orig/netqmail-1.05/tryltai.c	1969-12-31 16:00:00.000000000 -0800
+++ ./tryltai.c	2006-01-05 15:03:43.418230800 -0800
@@ -0,0 +1,4 @@
+main()
+{
+  ;
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/trytai.c ./trytai.c
--- ../../netqmail-1.05-orig/netqmail-1.05/trytai.c	1969-12-31 16:00:00.000000000 -0800
+++ ./trytai.c	2006-01-05 15:03:43.419230648 -0800
@@ -0,0 +1,7 @@
+#include <taia.h>
+
+void main()
+{
+  struct taia t;
+  taia_now(&t);
+}
diff -urN ../../netqmail-1.05-orig/netqmail-1.05/update_tmprsadh.sh ./update_tmprsadh.sh
--- ../../netqmail-1.05-orig/netqmail-1.05/update_tmprsadh.sh	1969-12-31 16:00:00.000000000 -0800
+++ ./update_tmprsadh.sh	2006-01-05 15:03:43.420230496 -0800
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Update temporary RSA and DH keys
+# Frederik Vermeulen 2004-05-31 GPL
+
+umask 0077 || exit 0
+
+export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
+
+openssl genrsa -out QMAIL/control/rsa512.new 512 &&
+chmod 640 QMAIL/control/rsa512.new &&
+chown vpopmail:qmail QMAIL/control/rsa512.new &&
+mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem
+echo
+
+openssl dhparam -2 -out QMAIL/control/dh512.new 512 &&
+chmod 640 QMAIL/control/dh512.new &&
+chown vpopmail:qmail QMAIL/control/dh512.new &&
+mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem
+echo
+
+openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 &&
+chmod 640 QMAIL/control/dh1024.new &&
+chown vpopmail:qmail QMAIL/control/dh1024.new &&
+mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem
