Index: npl/mailserver/libdomainkeys/libdomainkeys-0.69.diff
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys-0.69.diff	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys-0.69.diff	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,11 @@
+--- Makefile.orig	2006-01-17 17:28:58.000000000 -0700
++++ Makefile	2009-01-25 21:24:04.000000000 -0700
+@@ -28,7 +28,7 @@
+ dnstest: dnstest.o dns_txt.o
+ 	$(CC) $(CFLAGS) -o dnstest dnstest.o dns_txt.o
+ dns.lib: dnstest.c
+-	(if $(MAKE) dnstest >/dev/null 2>&1; then echo -lresolv; else echo ""; fi) >dns.lib
++	(if ! $(MAKE) dnstest >/dev/null 2>&1; then echo -lresolv; else echo ""; fi) >dns.lib
+ 	 rm -f dnstest
+ 
+ socktest.o: socktest.c
Index: npl/mailserver/libdomainkeys/libdomainkeys.SlackBuild
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+##NEED:...
+#DEP:openssl
+
+#######Essential package info.
+#Change these if autodetection fails.
+
+#Name of the Syn-3 package that we are going to create
+NAME=`basename $0|sed 's/.SlackBuild//'`
+
+#Archive of the sourcefiles to unpack
+SRC_ARC=`ls *.tar.* *.zip 2>/dev/null`
+
+#Version of the sourcefiles
+VER=`echo $SRC_ARC| sed 's/.*-//g' | sed 's/\.tar\..*$//g' | sed 's/\.zip$//g'`
+
+#Architecture that the created binaries run on.
+#Use noarch for scripts.
+ARCH=`uname -m`
+
+#from this point on, exit on errors:
+set -e
+
+########Build and create the pacakge.
+#Uncomment the stuff that you dont want or need
+
+#Unpack source
+#(uncomment if not needed)
+syn3_unpack $SRC_ARC
+
+#Directory where the sourcefiles are unpacked.
+#(you might have to adjust this if autodetection fails)
+SRC_DIR=`ls -c|head -1`
+
+#apply patches
+patch -p0 -d $SRC_DIR < libdomainkeys-0.69.diff || exit 1
+
+pushd $SRC_DIR
+
+make
+
+mkdir -p /tmp/pkg/usr/include
+mkdir -p /tmp/pkg/usr/lib
+
+cp domainkeys.h  /tmp/pkg/usr/include
+cp libdomainkeys.a /tmp/pkg/usr/lib
+
+popd
+
+#strip bins and other stuff
+syn3_strip /tmp/pkg || exit 1
+
+#move development stuff and create seperate development package
+syn3_move_dev /tmp/pkg /tmp/pkgdev || exit 1
+syn3_makepkg /tmp/pkgdev $NAME""_dev $VER $ARCH || exit 1
+
+#make main package
+syn3_makepkg /tmp/pkg $NAME $VER $ARCH || exit 1
Index: npl/mailserver/libdomainkeys/libdomainkeys.arch
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/libdomainkeys/libdomainkeys.build
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1
Index: npl/mailserver/libdomainkeys/libdomainkeys.depver
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.depver	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.depver	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+openssl	5
Index: npl/mailserver/libdomainkeys/libdomainkeys.md5
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,6 @@
+ffb61aa4000b392d7b78b4b7cb77dc62  ./libdomainkeys-0.69.diff
+15ec065c6f645a0b9fde3f1ff7681127  ./libdomainkeys-0.69.tar.gz
+b711f17412450a58537ca8693f5a0b15  ./libdomainkeys_dev.pkg
+ce2468344bdcd96627b5076fa8aee3c4  ./libdomainkeys.pkg
+713ede25dcebb59a244d5b70c97f191f  ./libdomainkeys.SlackBuild
+3062e3647b48a2b1990232bbf8b22f63  ./libdomainkeys.SlackBuild.log.gz
Index: npl/mailserver/libdomainkeys/libdomainkeys.version
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+0.69
Index: npl/mailserver/libdomainkeys/libdomainkeys_dev.arch
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/libdomainkeys/libdomainkeys_dev.build
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1
Index: npl/mailserver/libdomainkeys/libdomainkeys_dev.version
===================================================================
--- npl/mailserver/libdomainkeys/libdomainkeys_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libdomainkeys/libdomainkeys_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+0.69
Index: npl/mailserver/libsrs2/libsrs2.SlackBuild
===================================================================
--- npl/mailserver/libsrs2/libsrs2.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+##NEED:...
+##DEP:..
+
+#######Essential package info.
+#Change these if autodetection fails.
+
+#Name of the Syn-3 package that we are going to create
+NAME=`basename $0|sed 's/.SlackBuild//'`
+
+#Archive of the sourcefiles to unpack 
+SRC_ARC=`ls *.tar.* *.zip 2>/dev/null`
+
+#Version of the sourcefiles
+VER=`echo $SRC_ARC| sed 's/.*-//g' | sed 's/\.tar\..*$//g' | sed 's/\.zip$//g'`
+
+#Architecture that the created binaries run on.
+#Use noarch for scripts.
+ARCH=`uname -m`
+
+#from this point on, exit on errors:
+set -e
+
+########Build and create the pacakge.
+#Uncomment the stuff that you dont want or need
+
+#Unpack source 
+#(uncomment if not needed)
+syn3_unpack $SRC_ARC 
+
+#Directory where the sourcefiles are unpacked. 
+#(you might have to adjust this if autodetection fails)
+SRC_DIR=`ls -c|head -1`
+
+#apply patches
+#patch -p1 -d $SRC_DIR < fluxkiosk.patch || exit 1
+
+pushd $SRC_DIR 
+
+#AUTOMAKE: Configure
+#Some usefull stuff you sometimes need to set:
+#export LDFLAGS="-L/usr/X11/lib/ -L/usr/lib/mysql/"
+#export LD_LIBRARY_PATH=/usr/lib/mysql
+#export VPATH=$LD_LIBRARY_PATH
+#export CFLAGS="-std=c89"
+#export CFLAGS="-fgnu89-inline" #If "multiple definition of `foo'" Also see http://gcc.gnu.org/gcc-4.3/porting_to.html
+MAKE_OPTS=""
+./configure --prefix=/usr  || exit 1
+
+#AUTOMAKE: Compile
+make $MAKE_OPTS || exit 1
+
+#AUTOMAKE: Test (optional)
+if grep ^test: Makefile; then
+	make pkgconfigdir=/usr/lib/pkgconfig $MAKE_OPTS install || exit 1
+	make $MAKE_OPTS test || exit 1
+elif grep ^check: Makefile; then
+	make pkgconfigdir=/usr/lib/pkgconfig $MAKE_OPTS install || exit 1
+	make $MAKE_OPTS check || exit 1 
+fi
+
+#AUTOMAKE: Install
+mkdir -p /tmp/pkg &>/dev/null
+make pkgconfigdir=/usr/lib/pkgconfig install_prefix=/tmp/pkg DESTDIR=/tmp/pkg INSTALL_ROOT=/tmp/pkg install_root=/tmp/pkg $MAKE_OPTS install || exit 1
+popd
+
+#strip bins and other stuff
+syn3_strip /tmp/pkg || exit 1
+
+#move development stuff and create seperate development package
+syn3_move_dev /tmp/pkg /tmp/pkgdev || exit 1
+syn3_makepkg /tmp/pkgdev $NAME""_dev $VER $ARCH || exit 1
+
+#make main package
+syn3_makepkg /tmp/pkg $NAME $VER $ARCH || exit 1
+
+
+
Index: npl/mailserver/libsrs2/libsrs2.arch
===================================================================
--- npl/mailserver/libsrs2/libsrs2.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/libsrs2/libsrs2.build
===================================================================
--- npl/mailserver/libsrs2/libsrs2.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1
Index: npl/mailserver/libsrs2/libsrs2.md5
===================================================================
--- npl/mailserver/libsrs2/libsrs2.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,5 @@
+2178b8cf587eb6e65d4b9753c4a6c67d  ./libsrs2-1.0.18.tar.gz
+23355a6e3c5aaa23b41f95c61c32d1fe  ./libsrs2_dev.pkg
+5369bd193cc9f5d938b5b530f1dfb2a4  ./libsrs2.pkg
+9778f95a4592a0da63c9fa763ed9ae94  ./libsrs2.SlackBuild
+3e2a183f73286827e5706cdc62d613ef  ./libsrs2.SlackBuild.log.gz
Index: npl/mailserver/libsrs2/libsrs2.version
===================================================================
--- npl/mailserver/libsrs2/libsrs2.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1.0.18
Index: npl/mailserver/libsrs2/libsrs2_dev.arch
===================================================================
--- npl/mailserver/libsrs2/libsrs2_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/libsrs2/libsrs2_dev.build
===================================================================
--- npl/mailserver/libsrs2/libsrs2_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1
Index: npl/mailserver/libsrs2/libsrs2_dev.version
===================================================================
--- npl/mailserver/libsrs2/libsrs2_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/libsrs2/libsrs2_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1.0.18
Index: l/mailserver/netqmail/helodnscheck2.c
===================================================================
--- npl/mailserver/netqmail/helodnscheck2.c	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,202 +1,0 @@
-/*
-* Copyright (C) 2007 Jason Frisvold <friz@godshell.com>
-* Original Copyright (C) 2003-2004 Perolo Silantico <per.sil@gmx.it>
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either
-* version 2 of the License, or (at your option) any later
-* version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software Foundation,
-* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-***
-* 1/16 Modified original version to check helo/ehlo instead of mail from
-***
-*
-* $Id$
-*
-*/
-
-/* (2008) modifyed by Bing Ren <bingtimren (at) gmail.com> to further check
-   if the TCPREMOTEIP variable (mostly set by tcpserver) match
-   any of the IP addresses the HELO resolves to
-
-   depending on the environment variable HELO_DNS_CHECK, deny, log and/or
-   add a header if HELO don't solve to an address or the addresses don't 
-   contain the TCPREMOTEIP
-
-	[default] - deny if HELO don't solve to a record
-        P - passthrough, don't deny even HELO don't solve to A record
-            (of course, use with L and/or H)
-        D - deny if TCPREMOTEIP not contained in the addresses solved
-        L - log
-        H - add header "X-Helo-Check"
-        R - if "RELAYCLIENT" is set, don't do anything
-
-   the above can be combined, so DL means deny & log
-   if TCPREMOTEIP is not set, log but allow
-*/ 
-        
-
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <netdb.h>
-
-void block_permanent(const char* message) {
-
-/* Bing Ren: the original helodnscheck print command "E",
-   however, if the spam connection ignore the 553 error and 
-   continue send further commands, qmail-spp simply accept
-   message and deliver it! */
-
-  printf("R553 sorry, %s (#5.7.1)\n", message);
-  fprintf(stderr, "helo-dns-check: blocked with: %s\n", message);  
-}
-
-void block_temporary(const char* message) {
-  printf("E451 %s (#4.3.0)\n", message);
-  fprintf(stderr, "helo-dns-check: temporary failure: %s\n", message);  
-}
-
-int main(void) {
- unsigned char dns_answer[1023];
- unsigned char print_address[1023];
- char *helo_domain = getenv("SMTPHELOHOST");
- char *no_helo_check = getenv("NOHELODNSCHECK");
- char *remote_ip = getenv("TCPREMOTEIP");
- char *action = getenv("HELO_DNS_CHECK");
- struct hostent* result;
-
-  if (!action) {
-    action = "";
-  };
-
-  if (!remote_ip) {
-    remote_ip = "";
-  };
-
-  if (strpbrk(action,"R") && getenv("RELAYCLIENT"))
-     return 0;
-
-  if (no_helo_check) {
-     return 0;
-  }
-
-  if (!helo_domain) {
-    block_permanent("no HELO/EHLO hostname has been sent.");
-    return 0;
-  }
-
-
-  /* init DNS library */
-  res_init();
-
-  /* check A record */
-  result = gethostbyname(helo_domain);
-
-  /* check if there is any result */
-  if (!result) {
-    if (h_errno == HOST_NOT_FOUND) {
-
-       if (strpbrk(action,"H")) 
-          printf("HX-Helo-Check: HELO [%s] from [%s] doesn't solve\n", helo_domain, remote_ip);
-
-       if (strpbrk(action,"L")) 
-          fprintf(stderr, "helo-dns-check: HELO [%s] from [%s] doesn't solve\n", helo_domain, remote_ip);
-
-       if (!strpbrk(action,"P"))
-          block_permanent("invalid host name in HELO/EHLO command.");
-    }
-    else {
-       fprintf(stderr, "HELO DNS CHECK temporary failed, but let it go.\n");
-    };
-    return 0;
-  };
-
-  int count=0;
-  char* addr;
-
-  /* print debug information */
-  /*
-  fprintf(stderr, "dbg: result->h_name %s\n", result->h_name);
-  fprintf(stderr, "dbg: result->h_aliases:\n");
-  char* alias;
-  while (result->h_aliases[count]) {
-    alias=result->h_aliases[count];
-    fprintf(stderr, "dbg: [%d] %s\n", count, alias);
-    count++;
-  };
-
-  fprintf(stderr, "dbg: result->h_addrtype %d\n", result->h_addrtype);
-  fprintf(stderr, "dbg: result->h_length %d\n", result->h_length);
-  fprintf(stderr, "dbg: result->h_addr_list:\n");
-
-  count=0;
-  while (result->h_addr_list[count]) {
-     addr=result->h_addr_list[count];
-     inet_ntop(AF_INET, addr, print_address, 1000);
-     fprintf(stderr, "dbg: [%d] %s\n", count, print_address);
-     count++;
-  };
-    
-  if (*remote_ip) { 
-     fprintf(stderr, "dbg: remote host %s\n", remote_ip);
-  } else {
-     fprintf(stderr, "dbg: no remote ip $TCPREMOTEIP\n");
-  };
-
-  */
-
-  /* check A record of host */ 
-
-  if (!strpbrk(action,"DLH"))
-     return 0;
-
-  if (!(*remote_ip)) {
-     fprintf(stderr, "helo-dns-check: TCPREMOTEIP not set, let it go.\n");
-     return 0;
-  };
-
-  int found=0;
-  count=0;
-  while (result->h_addr_list[count] && (found==0)) {
-     addr=result->h_addr_list[count];
-     inet_ntop(AF_INET, addr, print_address, 1000);
-     if (strcmp(print_address, remote_ip) == 0) {
-	found = 1;
-     };
-     count++;
-  };
-
-  /* fprintf(stderr, "dbg: found = %d\n", found);  */
-
-  if (found == 1)
-     return 0;
-
-  if (strpbrk(action,"H")) 
-     printf("HX-Helo-Check: HELO [%s] doesn't match IP [%s]\n", helo_domain, remote_ip);
-
-  if (strpbrk(action,"L")) 
-     fprintf(stderr, "helo-dns-check: HELO [%s] doesn't match IP [%s]\n", helo_domain, remote_ip);
-
-  if (strpbrk(action,"D") && (!strpbrk(action,"P"))) 
-     block_permanent("HELO/EHLO command must provide FQDN that match your IP address.");
-
-  return 0;
-
-}
-
Index: npl/mailserver/netqmail/netqmail.SlackBuild
===================================================================
--- npl/mailserver/netqmail/netqmail.SlackBuild	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/mailserver/netqmail/netqmail.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -4,4 +4,8 @@
 #DEP:libspf2
 #NEED:groff
+#DEP:libdomainkeys
+#DEP:libsrs2
+#DEP:openssl
+#DEP:vpopmail
 
 #Gemodificeerd door edwin voor mailserver productlijn.
@@ -19,19 +23,9 @@
 # Set initial variables:
 NAME=netqmail
-VERSION=1.05
-BUILD=1DatuX
-
-
-## Location to download the sources
-SRC_LOC="http://ds9a.nl/qmail/$NAME-$VERSION.tar.gz"
+VERSION=1.06
+
 
 PKG=$TMP/package_$NAME
 
-## Lets Grab the Source if needed
-if [ -a $CWD/$NAME-$VERSION.tar.gz ]; then
-  echo "Source present not downloading"
-  else
-  $WGET $SRC_LOC || true
-fi
 
 if [ ! -d $TMP ]; then
@@ -44,9 +38,9 @@
 cd $TMP
 rm -rf $NAME-$VERSION
-tar xzvf $CWD/$NAME-$VERSION.tar.gz || exit 1
-
-
-
-# Maak die godverredommese users and groups aan!! :-)
+tar xvf $CWD/$NAME-$VERSION.tar || exit 1
+
+
+
+# Maak  users and group aan
 groupadd -g 55 nofiles
 useradd -g nofiles -u 50 -d /home/system/qmail/alias alias -s /sbin/false
@@ -61,37 +55,38 @@
 # Directory's maken
 make_dirs() {
-mkdir -p /var/qmail/supervise/qmail-send/log
-mkdir -p /var/qmail/supervise/qmail-smtpd/log
-#mkdir -p /var/qmail/supervise/qmail-pop3d/log
-mkdir -p /var/log/qmail/qmail-send
-mkdir -p /var/log/qmail/qmail-smtpd
-#mkdir -p /var/log/qmail/qmail-pop3d
-mkdir -p /var/qmail/alias
-mkdir -p /var/qmail/control
-mkdir -p /var/qmail/users
-mkdir -p /home/system/qmail
+# mkdir -p /var/qmail/supervise/qmail-send/log
+# mkdir -p /var/qmail/supervise/qmail-smtpd/log
+# #mkdir -p /var/qmail/supervise/qmail-pop3d/log
+# mkdir -p /var/log/qmail/qmail-send
+# mkdir -p /var/log/qmail/qmail-smtpd
+# #mkdir -p /var/log/qmail/qmail-pop3d
+# mkdir -p /var/qmail/alias
+# mkdir -p /var/qmail/control
+# mkdir -p /var/qmail/users
+# mkdir -p /home/system/qmail
 
 # Files touchen
-touch /var/qmail/control/rcpthosts
-touch /var/qmail/control/defaultdomain
-touch /var/qmail/control/virtualdomains
-touch /var/qmail/control/locals
+# touch /var/qmail/control/rcpthosts
+# touch /var/qmail/control/defaultdomain
+# touch /var/qmail/control/virtualdomains
+# touch /var/qmail/control/locals
 #touch /var/qmail/alias/.qmail-postmaster
 #touch /var/qmail/alias/.qmail-root
 # qmqpservers bestand maken
-echo "127.0.0.1" > /var/qmail/control/qmqpservers
+# echo "127.0.0.1" > /var/qmail/control/qmqpservers
 # default alias file voor delivery via dspam naar cyrus
-echo '|/usr/bin/syn3-dagent "$LOCAL" "$SENDER"' > /var/qmail/alias/.qmail-default
+# echo '|/usr/bin/syn3-dagent "$LOCAL" "$SENDER"' > /var/qmail/alias/.qmail-default
 # assign bestand aanmaken om delivery naar een maildir te overiden
-echo '+:alias:50:55:/var/qmail/alias:-::
-.' > /var/qmail/users/assign
+# echo '+:alias:50:55:/var/qmail/alias:-::
+# .' > /var/qmail/users/assign
 
 # Rechten goed zetten
-chmod +t /var/qmail/supervise/qmail-send
-chmod +t /var/qmail/supervise/qmail-smtpd
+# chmod +t /var/qmail/supervise/qmail-send
+# chmod +t /var/qmail/supervise/qmail-smtpd
 #chmod +t /var/qmail/supervise/qmail-pop3d
-chmod 644 /var/qmail/alias/.qmail*
-
-chown -R qmaill /var/log/qmail
+# chmod 644 /var/qmail/alias/.qmail*
+
+# chown -R qmaill /var/log/qmail
+true
 }
 
@@ -100,34 +95,47 @@
 
 
+
+
 #algemene patches netqmail
-./collate.sh || exit 1
+# ./collate.sh || exit 1
+
 
 #qmail tap patch
-patch -F 3 -d $NAME-$VERSION -p1 < $CWD/qmail-tap.diff  || exit 1
+#patch -F 3 -d $NAME-$VERSION -p1 < $CWD/qmail-tap.diff  || exit 1
+#TESTEN OF NIEWUER WERKT!
 
 #qmail dns patch
-patch -F 3 -d $NAME-$VERSION -p1 < $CWD/qmail-103.patch  || exit 1
+# patch -F 3 -d $NAME-$VERSION -p1 < $CWD/qmail-103.patch  || exit 1
 
 
 #qmail spp patch
-echo "SPP"
-tar -xzf $CWD/qmail-spp-0.42.tar.gz || exit 1
-patch -d $NAME-$VERSION -F3 -p0 < qmail-spp-0.42/netqmail-spp.diff || exit 1
-
-#### spp plugins
-mkdir -p $PKG/var/qmail/plugins
-
-#helo plugin:
-gcc -o helodnscheck $CWD/helodnscheck2.c -lresolv || exit 1
-mv helodnscheck $PKG/var/qmail/plugins || exit 1
-
-gcc -Wall -o qmail-spp-spf $CWD/qmail-spp-spf-20091020.c -lspf2 -I/usr/include/spf2 || exit 1
-mv qmail-spp-spf $PKG/var/qmail/plugins || exit 1
-
-
-chmod +x $PKG/var/qmail/plugins/*
+# echo "SPP"
+# tar -xzf $CWD/qmail-spp-0.42.tar.gz || exit 1
+# patch -d $NAME-$VERSION -F3 -p0 < qmail-spp-0.42/netqmail-spp.diff || exit 1
+
+### all important qmail patches
+# above is all replaced by the great uberpatch from http://notes.sagredo.eu/en/qmail-notes-185/patching-qmail-82.html THANKS Roberto Puzzanghera!
+ROBVERSION="rob20180403"
+patch < /tmp/build/roberto-netqmail-1.06.patch-latest || exit 1
+ln -s /usr/include/srs2.h /usr/local/include/srs2.h
+
+# #### spp plugins
+# mkdir -p $PKG/var/qmail/plugins
+#
+# #helo plugin:
+# gcc -o helodnscheck $CWD/helodnscheck2.c -lresolv || exit 1
+# mv helodnscheck $PKG/var/qmail/plugins || exit 1
+#
+# gcc -Wall -o qmail-spp-spf $CWD/qmail-spp-spf-20091020.c -lspf2 -I/usr/include/spf2 || exit 1
+# mv qmail-spp-spf $PKG/var/qmail/plugins || exit 1
+#
+#
+# chmod +x $PKG/var/qmail/plugins/*
 
 #compile it
 cd $NAME-$VERSION
+
+# echo '#define CHKUSER_ENABLE_ALIAS_DEFAULT' >>  chkuser_settings.h || exit 1
+
 #large inode support
 sed 's/O2$/O2 -D_FILE_OFFSET_BITS=64/' conf-cc -i || exit 1
@@ -135,92 +143,92 @@
 
 # Default qmail rules
-cat <<END > /home/system/qmail/tcp.smtp
-127.0.0.1:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-queue"
-127.0.0.2:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-127.0.0.3:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.16.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.17.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.18.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.19.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.20.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.21.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.22.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.23.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.24.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.25.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.26.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.27.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.28.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.29.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.30.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-172.31.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-192.168.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-10.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
-:allow,QMAILQUEUE="bin/qmail-qmqpc"
-END
+# cat <<END > /home/system/qmail/tcp.smtp
+# 127.0.0.1:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-queue"
+# 127.0.0.2:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 127.0.0.3:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.16.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.17.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.18.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.19.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.20.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.21.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.22.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.23.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.24.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.25.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.26.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.27.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.28.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.29.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.30.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 172.31.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 192.168.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# 10.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+# :allow,QMAILQUEUE="bin/qmail-qmqpc"
+# END
 #tcprules /home/system/qmail/tcp.smtp.cdb /home/system/qmail/tcp.smtp.tmp < /home/system/qmail/tcp.smtp
 
-echo 5 > /var/qmail/control/concurrencyincoming
-chmod 644 /var/qmail/control/concurrencyincoming
-
-
-#locals is een link naar me
-rm /var/qmail/control/locals
-ln -s me /var/qmail/control/locals
+# echo 5 > /var/qmail/control/concurrencyincoming
+# chmod 644 /var/qmail/control/concurrencyincoming
+
+
+# #locals is een link naar me
+# rm /var/qmail/control/locals
+# ln -s me /var/qmail/control/locals
 }
 
 make_scripts() {
 # Create a qmail run script
-cat > /var/qmail/rc << END
-#!/bin/sh
-exec env - PATH="/var/qmail/bin:\$PATH" \
-qmail-start ''  splogger qmail
-END
-chmod +x /var/qmail/rc
+# cat > /var/qmail/rc << END
+# #!/bin/sh
+# exec env - PATH="/var/qmail/bin:\$PATH" \
+# qmail-start ''  splogger qmail
+# END
+# chmod +x /var/qmail/rc
 
 # Create a qmail-send supervise (including log) run script
-cat > /var/qmail/supervise/qmail-send/run << END
-#!/bin/sh
-#dynamic update of hostname
-hostname -f > /var/qmail/control/me
-#zet de assign file om naar binair formaat.
-/var/qmail/bin/qmail-newu
-exec /var/qmail/rc
-END
-chmod +x /var/qmail/supervise/qmail-send/run
-
-cat > /var/qmail/supervise/qmail-send/log/run << END
-#!/bin/sh
-exec /usr/bin/setuidgid qmaill /usr/bin/multilog t s2500000 /var/log/qmail/qmail-send
-END
-chmod +x /var/qmail/supervise/qmail-send/log/run
-
-# Create a qmail-smtpd supervise (including log) run script
-cat > /var/qmail/supervise/qmail-smtpd/run << END
-#!/bin/sh
-QMAILDUID=\`id -u qmaild\`
-NOFILESGID=\`id -g qmaild\`
-MAXSMTPD=\`cat /var/qmail/control/concurrencyincoming\`
-LOCAL=\`head -1 /var/qmail/control/me\`
-if [ -z "\$QMAILDUID" -o -z "\$NOFILESGID" -o -z "\$MAXSMTPD" -o -z "\$LOCAL" ]; then
-    echo QMAILDUID, NOFILESGID, MAXSMTPD, or LOCAL is unset in
-    echo /var/qmail/supervise/qmail-smtpd/run
-    exit 1
-fi
-if [ ! -f /var/qmail/control/rcpthosts ]; then
-    echo "No /var/qmail/control/rcpthosts!"
-    echo "Refusing to start SMTP listener because it'll create an open relay"
-    exit 1
-fi
-exec /usr/bin/softlimit -m 150000000 /usr/bin/tcpserver -v -R -l "\$LOCAL" -x /etc/qmail/tcp.smtp.cdb \
--c "\$MAXSMTPD" -u "\$QMAILDUID" -g "\$NOFILESGID" 0 smtp /usr/bin/rblsmtpd -r cbl.abuseat.org -r bl.spamcop.net /usr/bin/fixcrio /var/qmail/bin/qmail-smtpd 2>&1
-END
-chmod +x /var/qmail/supervise/qmail-smtpd/run
-
-cat > /var/qmail/supervise/qmail-smtpd/log/run << END
-#!/bin/sh
-exec /usr/bin/setuidgid qmaill /usr/bin/multilog t s2500000 /var/log/qmail/qmail-smtpd
-END
-chmod +x /var/qmail/supervise/qmail-smtpd/log/run
+# cat > /var/qmail/supervise/qmail-send/run << END
+# #!/bin/sh
+# #dynamic update of hostname
+# hostname -f > /var/qmail/control/me
+# #zet de assign file om naar binair formaat.
+# /var/qmail/bin/qmail-newu
+# exec /var/qmail/rc
+# END
+# chmod +x /var/qmail/supervise/qmail-send/run
+#
+# cat > /var/qmail/supervise/qmail-send/log/run << END
+# #!/bin/sh
+# exec /usr/bin/setuidgid qmaill /usr/bin/multilog t s2500000 /var/log/qmail/qmail-send
+# END
+# chmod +x /var/qmail/supervise/qmail-send/log/run
+#
+# # Create a qmail-smtpd supervise (including log) run script
+# cat > /var/qmail/supervise/qmail-smtpd/run << END
+# #!/bin/sh
+# QMAILDUID=\`id -u qmaild\`
+# NOFILESGID=\`id -g qmaild\`
+# MAXSMTPD=\`cat /var/qmail/control/concurrencyincoming\`
+# LOCAL=\`head -1 /var/qmail/control/me\`
+# if [ -z "\$QMAILDUID" -o -z "\$NOFILESGID" -o -z "\$MAXSMTPD" -o -z "\$LOCAL" ]; then
+#     echo QMAILDUID, NOFILESGID, MAXSMTPD, or LOCAL is unset in
+#     echo /var/qmail/supervise/qmail-smtpd/run
+#     exit 1
+# fi
+# if [ ! -f /var/qmail/control/rcpthosts ]; then
+#     echo "No /var/qmail/control/rcpthosts!"
+#     echo "Refusing to start SMTP listener because it'll create an open relay"
+#     exit 1
+# fi
+# exec /usr/bin/softlimit -m 150000000 /usr/bin/tcpserver -v -R -l "\$LOCAL" -x /etc/qmail/tcp.smtp.cdb \
+# -c "\$MAXSMTPD" -u "\$QMAILDUID" -g "\$NOFILESGID" 0 smtp /usr/bin/rblsmtpd -r cbl.abuseat.org -r bl.spamcop.net /usr/bin/fixcrio /var/qmail/bin/qmail-smtpd 2>&1
+# END
+# chmod +x /var/qmail/supervise/qmail-smtpd/run
+#
+# cat > /var/qmail/supervise/qmail-smtpd/log/run << END
+# #!/bin/sh
+# exec /usr/bin/setuidgid qmaill /usr/bin/multilog t s2500000 /var/log/qmail/qmail-smtpd
+# END
+# chmod +x /var/qmail/supervise/qmail-smtpd/log/run
 
 # Create a qmail-pop3d supervise (including log) run script
@@ -241,43 +249,43 @@
 #END
 #chmod +x /var/qmail/supervise/qmail-pop3d/log/run
+true;
 }
 
 prepare() {
 #niet met symlink, ivm package removal
-mkdir -p $PKG/service
-mkdir -p $PKG/var/log
+# mkdir -p $PKG/service
+# mkdir -p $PKG/var/log
 mkdir -p $PKG/var/qmail
-mkdir -p $PKG/etc
-mkdir -p $PKG/home/system/qmail
-mv /var/qmail/control $PKG/home/system/qmail
-mv /var/qmail/alias $PKG/home/system/qmail
-mv /var/qmail/queue $PKG/home/system/qmail
-mv /var/qmail/users $PKG/home/system/qmail
+# mkdir -p $PKG/etc
+# mkdir -p $PKG/home/system/qmail
+# mv /var/qmail/control $PKG/home/system/qmail
+# mv /var/qmail/alias $PKG/home/system/qmail
+# mv /var/qmail/queue $PKG/home/system/qmail
+# mv /var/qmail/users $PKG/home/system/qmail
 cp -a /var/qmail $PKG/var
-cp -a /var/log/qmail $PKG/var/log
-ln -sf /home/system/qmail/queue $PKG/var/qmail/queue
-ln -sf /home/system/qmail/control $PKG/var/qmail/control
-ln -sf /home/system/qmail/alias $PKG/var/qmail/alias
-ln -sf /home/system/qmail/users $PKG/var/qmail/users
-ln -sf /home/system/qmail $PKG/etc/qmail
-ln -sf /var/qmail/supervise/qmail-send $PKG/service/qmail-send
-ln -sf /var/qmail/supervise/qmail-smtpd $PKG/service/qmail-smtpd
+rm -rf $PKG/var/qmail/{queue,alias,control}
+
+# cp -a /var/log/qmail $PKG/var/log
+# ln -sf /home/system/qmail/queue $PKG/var/qmail/queue
+# ln -sf /home/system/qmail/control $PKG/var/qmail/control
+# ln -sf /home/system/qmail/alias $PKG/var/qmail/alias
+# ln -sf /home/system/qmail/users $PKG/var/qmail/users
+# ln -sf /home/system/qmail $PKG/etc/qmail
+# ln -sf /var/qmail/supervise/qmail-send $PKG/service/qmail-send
+# ln -sf /var/qmail/supervise/qmail-smtpd $PKG/service/qmail-smtpd
 #ln -s /var/qmail/supervise/qmail-pop3d $PKG/service/qmail-pop3d
-cp -a $CWD/qmail.permissions $PKG/etc
-cp -a $CWD/qmail.rc.config $PKG/etc
-cp -a $CWD/qmailctl $PKG/var/qmail/bin/
-cp -a /home/system/qmail/tcp.smtp $PKG/home/system/qmail/
-cp -a /home/system/qmail/tcp.smtp.cdb $PKG/home/system/qmail/
+# cp -a $CWD/qmail.permissions $PKG/etc
+# cp -a $CWD/qmail.rc.config $PKG/etc
+# cp -a $CWD/qmailctl $PKG/var/qmail/bin/
+# cp -a /home/system/qmail/tcp.smtp $PKG/home/system/qmail/
+# cp -a /home/system/qmail/tcp.smtp.cdb $PKG/home/system/qmail/
 mkdir -p $PKG/usr/sbin
 ln -s /var/qmail/bin/sendmail $PKG/usr/sbin/sendmail || exit 1
-cat $TMP/$NAME-$VERSION/$NAME-$VERSION/config-fast.sh | sed "s/QMAIL/\/var\/qmail/" > $PKG/var/qmail/bin/config-fast
-chmod 600 $PKG/etc/qmail.permissions
-chmod 600 $PKG/etc/qmail.rc.config
-chmod 755 $PKG/var/qmail/bin/qmailctl
-chmod 755 $PKG/var/qmail/bin/config-fast
-
-mkdir -p $PKG/usr/bin
-cp $CWD/syn3-dagent $PKG/usr/bin || exit 1
-chmod 755 $PKG/usr/bin/syn3-dagent || exit 1
+# cat $TMP/$NAME-$VERSION/$NAME-$VERSION/config-fast.sh | sed "s/QMAIL/\/var\/qmail/" > $PKG/var/qmail/bin/config-fast
+# chmod 600 $PKG/etc/qmail.permissions
+# chmod 600 $PKG/etc/qmail.rc.config
+# chmod 755 $PKG/var/qmail/bin/qmailctl
+# chmod 755 $PKG/var/qmail/bin/config-fast
+
 }
 
@@ -311,18 +319,6 @@
 cat > $PKG/etc/postinst.d/post.qmail << END
 #!/bin/sh
-svc -d /service/qmail-*
-svcstop /service/nscd/
-/var/qmail/bin/qmailctl user
-svcreset /service/nscd/
-touch /var/qmail/control/smtpplugins
-svc -dx /service/qmail-*
-#update old config?
-if ! grep "127.0.0.3" /etc/qmail/tcp.smtp; then
-    mv /etc/qmail/tcp.smtp.new /etc/qmail/tcp.smtp
-fi
-
-
-#regenerate cdb
-tcprules /etc/qmail/tcp.smtp.cdb /etc/qmail/tcp.smtp.tmp < /etc/qmail/tcp.smtp
+svcrestart /service/qmail-smtpd
+svcrestart /service/qmail-send
 
 END
@@ -332,10 +328,10 @@
 build() {
 # configfile moeten op .new eindigen
-find $PKG/etc/qmail.* $PKG/home/system/qmail/control $PKG/home/system/qmail/users $PKG/home/system/qmail/tcp.* -type f -exec mv "{}" "{}.new" \; || exit 1
+# find $PKG/etc/qmail.* $PKG/home/system/qmail/control $PKG/home/system/qmail/users $PKG/home/system/qmail/tcp.* -type f -exec mv "{}" "{}.new" \; || exit 1
 
 
 # Build the package:
 cd $PKG
-echo $VERSION > $CWD/$NAME.version
+echo $VERSION"_"$ROBVERSION > $CWD/$NAME.version
 echo $ARCH > $CWD/$NAME.arch
 makepkg -l y -c n $CWD/$NAME.pkg
Index: npl/mailserver/netqmail/netqmail.build
===================================================================
--- npl/mailserver/netqmail/netqmail.build	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/mailserver/netqmail/netqmail.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-6349
+6363
Index: npl/mailserver/netqmail/netqmail.depver
===================================================================
--- npl/mailserver/netqmail/netqmail.depver	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/mailserver/netqmail/netqmail.depver	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -2,2 +2,6 @@
 slackpackage	0
 libspf2	0
+libdomainkeys	0
+libsrs2	0
+openssl	5
+vpopmail	0
Index: npl/mailserver/netqmail/netqmail.md5
===================================================================
--- npl/mailserver/netqmail/netqmail.md5	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/mailserver/netqmail/netqmail.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,13 +1,5 @@
-604085a48a5bbb909a67a9a0cedbb173  ./helodnscheck2.c
-4c03848af9d37e281f3b82cc59230d9b  ./netqmail-1.05.tar.gz
-b1c93102cc9ba49ec0f278f918cb95d9  ./netqmail.pkg
-db53b86fa47dced8a100386e97755f41  ./netqmail.SlackBuild
-036914b6ab72fc95e4993976fa44ef85  ./netqmail.SlackBuild.log.gz
-9140ad2b03017145cd7963c84bb24f16  ./qmail-103.patch
-49c6b7898cc85df03dfabb190c7ffc4a  ./qmailctl
-38b762a96e8c462c03e4ed5a42437f9e  ./qmail.permissions
-a781066c2d8b2e42e4eae0cd0545391b  ./qmail.rc.config
-384372f60ba2c1071601d0fea1f221ec  ./qmail-spp-0.42.tar.gz
-13356ef41ba7a8508fa570d569b117cf  ./qmail-spp-spf-20091020.c
-bcafe3f1412a9eef6efe09a97234c04c  ./qmail-tap.diff
-a23a39d1e0321a8d4fc6eeea60df829b  ./syn3-dagent
+26c95bd8faca909f3432c1aa55f251b6  ./netqmail-1.06.tar
+fc09f10879e8fd10880d136de5b51a87  ./netqmail.pkg
+24b173c1fdd1a05abfbd48a6ccba56f4  ./netqmail.SlackBuild
+584232cea7d0ecd5691041e5973edac9  ./netqmail.SlackBuild.log.gz
+2fbc85fee68c868ba2a45e7e84a138b7  ./roberto-netqmail-1.06.patch-latest
Index: npl/mailserver/netqmail/netqmail.version
===================================================================
--- npl/mailserver/netqmail/netqmail.version	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/mailserver/netqmail/netqmail.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-1.05
+1.06_rob20180403
Index: l/mailserver/netqmail/qmail-103.patch
===================================================================
--- npl/mailserver/netqmail/qmail-103.patch	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,63 +1,0 @@
---- qmail-1.03/dns.c.103	Mon Aug 17 16:06:58 1998
-+++ qmail-1.03/dns.c	Wed Aug 26 16:28:56 1998
-@@ -21,10 +21,12 @@
- 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];
-@@ -45,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);
-@@ -66,7 +83,7 @@
-    if (i < QFIXEDSZ) return DNS_SOFT;
-    responsepos += QFIXEDSZ;
-   }
-- numanswers = ntohs(response.hdr.ancount);
-+ numanswers = ntohs(((HEADER *)response.buf)->ancount);
-  return 0;
- }
- 
Index: l/mailserver/netqmail/qmail-spp-spf-20091020.c
===================================================================
--- npl/mailserver/netqmail/qmail-spp-spf-20091020.c	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,520 +1,0 @@
-/*
- * Copyright (C) 2003-2005 Pawel Foremski <pjf@asn.pl>
- *   - Original imported from dirqmail.
- *
- * Copyright (C) 2008 Chris Caputo <ccaputo@alt.net>
- *   - Oct 2008: Adapted to work with libspf2-1.2.8.
- *               Added support for IPv6 via TCP6REMOTEIP.
- *               Altered configuration methodology to use envars.
- *   - Nov 2008: Added SPP_SPF_DONT_ALLOW_RANDOM_IP_PASS.
- *
- * This program is free software; you can redistribute it and/or 
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation; either 
- * version 2 of the License, or (at your option) any later 
- * version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-/*
-   This is an implementation of SPF as a qmail-spp module.  It requires
-   libspf2.  For more information, consult:
-
-     http://www.openspf.org/
-     http://qmail-spp.sourceforge.net/
-     http://www.libspf2.org/
-
-   If an SPF record is not found or doesn't process, a fallback SPF record
-   of "v=spf1 mx -all" can be used to test if the client is listed in the MX
-   records of the envelope domain.
-   
-   Compile plugin using something like:
-
-     gcc -Wall -o qmail-spp-spf qmail-spp-spf.c -lspf2 -I/usr/include/spf2
-
-   Put this in the qmail plugins directory (ex. "/var/qmail/plugins") and add
-   to smtpplugins file (ex. "/var/qmail/control/smtpplugins") after [mail]
-   section:
-
-     [mail]
-     plugins/qmail-spp-spf
-
-   If the "RELAYCLIENT" environment variable (envar) is set, this module
-   exits without doing anything, since the client has permission to relay.
-
-   IPv6 is supported if TCPREMOTEIP contains an IPv6 address or if
-   TCP6REMOTEIP envar is set.
-
-   Set these envars as desired to instruct the module how to handle each SPF
-   result.  Only envars defined will be used.
-
-     SPP_SPF_NO_RESULT          - Used if both SPF and MX checks can't be done.
-
-     SPP_SPF_RESULT_NEUTRAL    \
-     SPP_SPF_RESULT_PASS       |
-     SPP_SPF_RESULT_FAIL       |- Refer to http://www.openspf.org/ for
-     SPP_SPF_RESULT_SOFTFAIL   |  definitions.
-     SPP_SPF_RESULT_NONE       |
-     SPP_SPF_RESULT_TEMPERROR  |
-     SPP_SPF_RESULT_PERMERROR  /
-
-     SPP_SPF_MX_RESULT_PASS    \  If any set, MX check of sender is done when
-     SPP_SPF_MX_RESULT_FAIL    |- SPF record doesn't exist or SPF check result
-     SPP_SPF_MX_RESULT_UNKNOWN /  is None, PermError, TempError or invalid.
-
-   Possible settings of the above envars are taken from
-   http://qmail-spp.sourceforge.net/doc/ :
-
-     Command       Description
-     -----------------------------------------------------------------------
-     A             accept mail - turn off qmail-spp in this session
-     N             next - accept current SMTP command (do not execute
-                   remaining plugins for this command)
-     O             ok - like N, but omits qmail checks in MAIL and RCPT
-     Emsg          error - do not accept this SMTP command and immediately
-                   send msg to the client
-     LMmsg         later, mail - like E, but shows error after MAIL command
-     LRmsg         later, rcpt - like E, but shows error after RCPT command
-     LDmsg         later, data - like E, but shows error after DATA command
-     Rmsg          reject mail - send msg to the client and drop connection
-     D             drop connection immediately, without printing anything
-     Svar=value    set environmental variable var to value
-     Uvar          unset var variable
-     Hcontent      header - add header content (eg. X-Spam-Flag: YES)
-     Cfoo@bar.com  change last address provided by the client to foo@bar.com
-                   (MAIL FROM or RCPT TO address)
-     Pmsg          print - send msg to the client
-
-   Separate commands are separated by a comma or a carriage return.  Be
-   careful not to include a comma for any other reason.
-
-   Except for the SPP_SPF_NO_RESULT and SPP_SPF_MX_RESULT_xx envars, if any
-   envars include the special string "spf_smtp_msg" then "spf_smtp_msg" will
-   be replaced by the output of libspf2's SPF_response_get_smtp_comment()
-   function.  For example:
-
-     SPP_SPF_RESULT_FAIL="E550 spf_smtp_msg"
-
-   If the actual SPF query is able to be done, this module also sets the
-   environmental variable SPP_SPF_RESULT to one of the following (via the
-   qmail-spp 'S' command):
-
-     pass
-     fail
-     softfail
-     neutral
-     none
-     permerror
-     temperror
-
-   In addition, a "Received-SPF:" header is added to the message via the
-   qmail-spp 'H' command when the SPF query is able to be done.
-
-   It is okay to not set a particular SPP_SPF_xxx envar.  If that particular
-   case is hit the module will only return the "SSPP_SPF_RESULT=<result>" and
-   "HReceived-SPF:" commands if the SPF query is done.
-
-   If the SPP_SPF_DONT_ALLOW_RANDOM_IP_PASS envar is set, then when an SPF pass
-   result is obtained, two random IP addresses will also be tried to see if the
-   SPF definition is passing everything as if "+all" is declared.  If the two
-   random IP addresses also receive a pass from the SPF library, then the
-   original pass is ignored.
-
-   Example:
-
-      In /etc/tcprules.d/tcp.qmail-smtp change ":allow" line to be as follows:
-
-         :allow,SPP_SPF_RESULT_PASS="HX-Spam-Flag: No,A",SPP_SPF_RESULT_FAIL="E550 spf_smtp_msg",SPP_SPF_NO_RESULT="SSPF_MODULE_FAILED=1"
-
-      or
-
-         :allow,SPP_SPF_RESULT_PASS="A",SPP_SPF_MX_RESULT_PASS="A"
-
-      (Be sure to rebuild tcp.qmail-smtp.cdb after modification, such as with
-      "make" or "tcprules" commands.)
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <time.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include "spf.h"
-
-#define LOG "qmail-spp-spf: "
-#define LOGR "qmail-spp-spf:%s: "
-#define SPF_SMTP_MSG "spf_smtp_msg"
-#define SPF_SMTP_MSG_LEN 12
-
-
-void envcmd(char *envstr,
-	    SPF_response_t *spf_response)
-{
-  char *p;
-
-  /* Always issue these when there is a response, regardless of whether envar
-     was passed in.  Also, these need to issue first since an envar can include
-     a qmail-spp processing termination command. */
-  if (NULL != spf_response)
-    {
-      printf("SSPP_SPF_RESULT=%s\n",
-	     SPF_strresult(SPF_response_result(spf_response)));
-      printf("H%s\n", SPF_response_get_received_spf(spf_response));
-    }
-
-  if (NULL == envstr || 0 == *envstr)
-    {
-      return;
-    }
-
-  p = envstr;
-  while (*p)
-    {
-      if (NULL != spf_response &&
-	  !strncmp(p, SPF_SMTP_MSG, SPF_SMTP_MSG_LEN))
-	{
-	  printf("%s", SPF_response_get_smtp_comment(spf_response));
-	  p += SPF_SMTP_MSG_LEN;
-	}
-      else
-	{
-	  printf("%c", ',' == *p ? '\n' : *p);
-	  p++;
-	}
-    }
-
-  /* don't print extra carriage return if envstr already ends with one */
-  if (p > envstr       &&
-      ','  != *(p - 1) &&
-      '\n' != *(p - 1))
-    printf("\n");
-}
-
-
-/* Returns 1 on success, 0 on failure. */
-int set_spf_ip(SPF_request_t *spf_request,
-	       int fIPv4,
-	       char *remote)
-{
-  if (fIPv4)
-    {
-      if (SPF_request_set_ipv4_str(spf_request, remote))
-	{
-	  fprintf(stderr,
-		  LOGR "SPF_request_set_ipv4_str('%s') failed.\n",
-		  remote,
-		  remote);
-	  return 0;
-	}
-    }
-  else
-    {
-      if (SPF_request_set_ipv6_str(spf_request, remote))
-	{
-	  fprintf(stderr,
-		  LOGR "SPF_request_set_ipv6_str('%s') failed.\n",
-		  remote,
-		  remote);
-	  return 0;
-	}
-    }
-
-  return 1;
-}
-
-
-/* Returns 1 if a random IP address also results in an SPF pass.
-   0 otherwise (or on error).
-*/
-int random_ip_passes(SPF_request_t *spf_request,
-		     int fIPv4,
-		     char *remote)
-{
-  int ret = 0;
-  struct in_addr addr4;
-  struct in6_addr addr6;
-  char szIP[INET6_ADDRSTRLEN];
-  SPF_response_t *spf_response = NULL;
-  SPF_errcode_t spf_err;
-
-  if (fIPv4)
-    {
-      addr4.s_addr = random();
-
-      if (SPF_request_set_ipv4(spf_request, addr4))
-	{
-	  fprintf(stderr,
-		  LOGR "SPF_request_set_ipv4('%s') failed.\n",
-		  remote,
-		  inet_ntop(AF_INET, &addr4, szIP, sizeof(szIP)));
-	  goto done;
-	}
-    }
-  else
-    {
-      addr6.s6_addr32[0] = random();
-      addr6.s6_addr32[1] = random();
-      addr6.s6_addr32[2] = random();
-      addr6.s6_addr32[3] = random();
-
-      if (SPF_request_set_ipv6(spf_request, addr6))
-	{
-	  fprintf(stderr,
-		  LOGR "SPF_request_set_ipv6('%s') failed.\n",
-		  remote,
-		  inet_ntop(AF_INET6, &addr6, szIP, sizeof(szIP)));
-	  goto done;
-	}
-    }
-
-  if (SPF_E_SUCCESS ==
-      (spf_err = SPF_request_query_mailfrom(spf_request, &spf_response)))
-    {
-      if (SPF_RESULT_PASS == SPF_response_result(spf_response))
-	ret = 1;
-    }
-  else
-    {
-      fprintf(stderr,
-	      LOGR "SPF_request_query_mailfrom (random remote='%s'): "
-	      "surprisingly failed since first test succeeded: %s\n",
-	      remote,
-	      inet_ntop(fIPv4 ? AF_INET : AF_INET6,
-			fIPv4 ? (const void *)&addr4 : &addr6,
-			szIP,
-			sizeof(szIP)),
-	      SPF_strerror(spf_err));
-    }
-
- done:
-  /* restore original IP settings.  no need to check result since this worked
-     already */
-  set_spf_ip(spf_request, fIPv4, remote);
-
-  if (NULL != spf_response) SPF_response_free(spf_response);
-  return ret;
-}
-
-
-int main()
-{
-  char *remote   = NULL;
-  char *helo     = NULL;
-  char *sender   = NULL;
-  char *mxpass   = NULL;
-  char *mxfail   = NULL;
-  char *mxunk    = NULL;
-  SPF_server_t   *spf_server     = NULL;
-  SPF_request_t  *spf_request    = NULL;
-  SPF_response_t *spf_response   = NULL;
-  SPF_response_t *spf_responsemx = NULL;
-  SPF_errcode_t spf_err;
-  int fQuerySuccessful = 0;
-  int fConsiderMXCheck = 0;
-  int fIPv4 = 0;
-
-  /**
-   * env variables
-   **/
-  if (getenv("RELAYCLIENT")) /* known user, don't do anything */
-    return 0;
-
-  remote = getenv("TCPREMOTEIP");
-  if (!remote)
-    remote = getenv("TCP6REMOTEIP");
-  if (!remote) /* should never happen */
-    {
-      fprintf(stderr, LOG "ERROR: can't read TCPREMOTEIP or TCP6REMOTEIP\n");
-      goto done;
-    }
-  fIPv4 = (NULL == strchr(remote, ':'));
-
-  sender = getenv("SMTPMAILFROM");
-  helo   = getenv("SMTPHELOHOST");
-  if (!sender && !helo) /* should never happen */
-    {
-      fprintf(stderr,
-	      LOGR "can't read SMTPMAILFROM or SMTPHELOHOST\n",
-	      remote);
-      goto done;
-    }
-
-  /**
-   * SPF
-   **/
-  if (NULL == (spf_server = SPF_server_new(SPF_DNS_RESOLV, 0)))
-    {
-      fprintf(stderr, LOGR "SPF_server_new failed.\n", remote);
-      goto done;
-    }
-  if (NULL == (spf_request = SPF_request_new(spf_server)))
-    {
-      fprintf(stderr, LOGR "SPF_request_new failed.\n", remote);
-      goto done;
-    }
-  if (!set_spf_ip(spf_request, fIPv4, remote))
-    goto done;
-  if (helo && SPF_request_set_helo_dom(spf_request, helo))
-    {
-      fprintf(stderr,
-	      LOGR "SPF_request_set_helo_dom('%s') failed.\n",
-	      remote,
-	      helo);
-      goto done;
-    }
-  if (sender && SPF_request_set_env_from(spf_request, sender))
-    {
-      fprintf(stderr,
-	      LOGR "SPF_request_set_env_from('%s') failed.\n",
-	      remote,
-	      sender);
-      goto done;
-    }
-  if (SPF_E_SUCCESS ==
-      (spf_err = SPF_request_query_mailfrom(spf_request, &spf_response)))
-    {
-      fQuerySuccessful = 1;
-      fprintf(stderr,
-	      LOGR "%s\n",
-	      remote,
-	      SPF_response_get_received_spf(spf_response));
-      switch (SPF_response_result(spf_response))
-	{
-	case SPF_RESULT_NEUTRAL:
-	  envcmd(getenv("SPP_SPF_RESULT_NEUTRAL"), spf_response);
-	  break;
-	case SPF_RESULT_PASS:
-	  if (getenv("SPP_SPF_DONT_ALLOW_RANDOM_IP_PASS"))
-	    {
-	      /* not intended to be cryptographically secure */
-	      srandom(time(NULL) * getpid());
-
-	      /* test twice.  if both pass, something is odd. */
-	      if (random_ip_passes(spf_request, fIPv4, remote) &&
-		  random_ip_passes(spf_request, fIPv4, remote))
-		{
-		  fConsiderMXCheck = 1;
-		  fprintf(stderr,
-			  LOGR "Two random IP addresses also passed SPF "
-			  "check, so ignoring this result.  Seems like SPF "
-			  "record may contain \"+all\"!\n",
-			  remote);
-		  break;
-		}
-	    }
-	  envcmd(getenv("SPP_SPF_RESULT_PASS"), spf_response);
-	  break;
-	case SPF_RESULT_FAIL:
-	  envcmd(getenv("SPP_SPF_RESULT_FAIL"), spf_response);
-	  break;
-	case SPF_RESULT_SOFTFAIL:
-	  envcmd(getenv("SPP_SPF_RESULT_SOFTFAIL"), spf_response);
-	  break;
-	case SPF_RESULT_NONE:
-	  envcmd(getenv("SPP_SPF_RESULT_NONE"), spf_response);
-	  fConsiderMXCheck = 1;
-	  break;
-	case SPF_RESULT_TEMPERROR:
-	  envcmd(getenv("SPP_SPF_RESULT_TEMPERROR"), spf_response);
-	  fConsiderMXCheck = 1;
-	  break;
-	case SPF_RESULT_PERMERROR:
-	  envcmd(getenv("SPP_SPF_RESULT_PERMERROR"), spf_response);
-	  fConsiderMXCheck = 1;
-	  break;
-	case SPF_RESULT_INVALID:
-	default:
-	  fConsiderMXCheck = 1;
-	  fprintf(stderr,
-		  LOGR "SPF_request_query_mailfrom: invalid or unknown "
-		  "result.\n",
-		  remote);
-	  break;
-	}
-    }
-  else
-    {
-      fConsiderMXCheck = 1;
-      fprintf(stderr,
-	      LOGR "SPF_request_query_mailfrom (helo='%s', mailfrom='%s'): "
-	      "failed: %s\n",
-	      remote,
-	      helo ? helo : "",
-	      sender ? sender : "",
-	      SPF_strerror(spf_err));
-    }
-
-  /**
-   * Fallback MX check
-   **/
-  if (fConsiderMXCheck)
-    {
-#define SPF_MX_STR "v=spf1 mx -all"
-      mxpass = getenv("SPP_SPF_MX_RESULT_PASS");
-      mxfail = getenv("SPP_SPF_MX_RESULT_FAIL");
-      mxunk  = getenv("SPP_SPF_MX_RESULT_UNKNOWN");
-      if (mxpass || mxfail || mxunk)
-	{
-	  if (SPF_E_SUCCESS ==
-	      (spf_err = SPF_request_query_fallback(spf_request,
-						    &spf_responsemx,
-						    SPF_MX_STR)))
-	    {
-	      fQuerySuccessful = 1;
-	      fprintf(stderr,
-		      LOGR "Fallback MX check \"" SPF_MX_STR "\" "
-		      "(helo='%s', mailfrom='%s'): %s\n",
-		      remote,
-		      helo ? helo : "",
-		      sender ? sender : "",
-		      SPF_strresult(SPF_response_result(spf_responsemx)));
-	      switch (SPF_response_result(spf_responsemx))
-		{
-		case SPF_RESULT_PASS:
-		  envcmd(mxpass, NULL);
-		  break;
-		case SPF_RESULT_FAIL:
-		  envcmd(mxfail, NULL);
-		  break;
-		default:
-		  envcmd(mxunk, NULL);
-		  break;
-		}
-	    }
-	  else
-	    {
-	      fprintf(stderr,
-		      LOGR "SPF_request_query_fallback \"" SPF_MX_STR "\" "
-		      "(helo='%s', mailfrom='%s') failed: %s\n",
-		      remote,
-		      helo ? helo : "",
-		      sender ? sender : "",
-		      SPF_strerror(spf_err));
-	    }
-	}
-    }
-
- done:
-  if (NULL != spf_responsemx) SPF_response_free(spf_responsemx);
-  if (NULL != spf_response) SPF_response_free(spf_response);
-  if (NULL != spf_request) SPF_request_free(spf_request);
-  if (NULL != spf_server) SPF_server_free(spf_server);
-
-  if (0 == fQuerySuccessful)
-    {
-      envcmd(getenv("SPP_SPF_NO_RESULT"), NULL);
-    }
-      
-  return 0;
-}
Index: l/mailserver/netqmail/qmail-tap.diff
===================================================================
--- npl/mailserver/netqmail/qmail-tap.diff	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,328 +1,0 @@
-diff -Nur qmail-1.03/error.h qmail-1.03.tap/error.h
---- qmail-1.03/error.h	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/error.h	2005-06-06 13:02:38.000000000 -0500
-@@ -1,5 +1,6 @@
- #ifndef ERROR_H
- #define ERROR_H
-+#include <errno.h>
- 
- extern int errno;
- 
-diff -Nur qmail-1.03/Makefile qmail-1.03.tap/Makefile
---- qmail-1.03/Makefile	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/Makefile	2005-02-15 12:50:37.000000000 -0600
-@@ -1419,13 +1419,14 @@
- 	nroff -man qmail-qstat.8 > qmail-qstat.0
- 
- qmail-queue: \
--load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \
--datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
--str.a fs.a auto_qmail.o auto_split.o auto_uids.o
-+load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o qregex.o \
-+datetime.a seek.a case.a ndelay.a open.a sig.a getln.a stralloc.a alloc.a \
-+substdio.a error.a control.o constmap.o str.a fs.a auto_qmail.o \
-+auto_split.o auto_uids.o 
- 	./load qmail-queue triggerpull.o fmtqfn.o now.o \
--	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
--	alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
--	auto_split.o auto_uids.o 
-+	date822fmt.o qregex.o control.o constmap.o datetime.a case.a seek.a \
-+	ndelay.a open.a sig.a getln.a stralloc.a alloc.a substdio.a error.a \
-+	str.a fs.a auto_qmail.o auto_split.o auto_uids.o
- 
- qmail-queue.0: \
- qmail-queue.8
-@@ -1681,6 +1682,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
-diff -Nur qmail-1.03/qmail-control.9 qmail-1.03.tap/qmail-control.9
---- qmail-1.03/qmail-control.9	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/qmail-control.9	2005-06-06 13:10:03.000000000 -0500
-@@ -63,6 +63,7 @@
- .I rcpthosts	\fR(none)	\fRqmail-smtpd
- .I smtpgreeting	\fIme	\fRqmail-smtpd
- .I smtproutes	\fR(none)	\fRqmail-remote
-+.I taps	\fR(none)	\fRqmail-queue
- .I timeoutconnect	\fR60	\fRqmail-remote
- .I timeoutremote	\fR1200	\fRqmail-remote
- .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
-@@ -72,6 +73,7 @@
- .SH "SEE ALSO"
- qmail-inject(8),
- qmail-qmqpc(8),
-+qmail-queue(8),
- qmail-remote(8),
- qmail-send(8),
- qmail-showctl(8),
-diff -Nur qmail-1.03/qmail-queue.8 qmail-1.03.tap/qmail-queue.8
---- qmail-1.03/qmail-queue.8	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/qmail-queue.8	2005-06-06 13:11:01.000000000 -0500
-@@ -40,6 +40,12 @@
- However, the recipients probably expect to see a proper header,
- as described in
- .BR qmail-header(5) .
-+.SH "CONTROL FILES"
-+.TP 5
-+.I taps
-+Should contain regex syntax of email addresses to tap and
-+the associated email address to send the copy to. The two
-+fields should be separated by a colon.
- .SH "FILESYSTEM RESTRICTIONS"
- .B qmail-queue
- imposes two constraints on the queue structure:
-diff -Nur qmail-1.03/qmail-queue.c qmail-1.03.tap/qmail-queue.c
---- qmail-1.03/qmail-queue.c	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/qmail-queue.c	2005-05-17 14:59:00.000000000 -0500
-@@ -16,6 +16,8 @@
- #include "auto_uids.h"
- #include "date822fmt.h"
- #include "fmtqfn.h"
-+#include "stralloc.h"
-+#include "constmap.h"
- 
- #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
- #define ADDR 1003
-@@ -25,6 +27,14 @@
- char outbuf[256];
- struct substdio ssout;
- 
-+int tapok = 0;
-+stralloc tap = {0};
-+struct constmap maptap;
-+stralloc chkaddr = {0};
-+int tapped;
-+stralloc tapaddr = {0};
-+stralloc controlfile = {0};
-+
- datetime_sec starttime;
- struct datetime dt;
- unsigned long mypid;
-@@ -175,6 +185,13 @@
- 
-  alarm(DEATH);
- 
-+ stralloc_copys( &controlfile, auto_qmail);
-+ stralloc_cats( &controlfile, "/control/taps");
-+ stralloc_0( &controlfile);
-+ tapok = control_readfile(&tap,controlfile.s,0);
-+ if (tapok == -1) die(65);
-+ if (!constmap_init(&maptap,tap.s,tap.len,0)) die(65);
-+
-  pidopen();
-  if (fstat(messfd,&pidst) == -1) die(63);
- 
-@@ -219,14 +236,28 @@
-  if (substdio_get(&ssin,&ch,1) < 1) die_read();
-  if (ch != 'F') die(91);
-  if (substdio_bput(&ssout,&ch,1) == -1) die_write();
-+ stralloc_0(&chkaddr);
-  for (len = 0;len < ADDR;++len)
-   {
-+   if ( len == 1 ) stralloc_copyb(&chkaddr, &ch,1);
-+   else if ( len > 1 ) stralloc_catb(&chkaddr, &ch,1);
-    if (substdio_get(&ssin,&ch,1) < 1) die_read();
-    if (substdio_put(&ssout,&ch,1) == -1) die_write();
-    if (!ch) break;
-   }
-  if (len >= ADDR) die(11);
- 
-+ /* check the from address */
-+ stralloc_0(&chkaddr);
-+ if (tapped == 0 && tapcheck()==1 ) {
-+   tapped = 1;
-+   if ( tapaddr.len > 0 ) {
-+     if (substdio_bput(&ssout,"T",1) == -1) die_write();
-+     if (substdio_bput(&ssout,tapaddr.s,tapaddr.len) == -1) die_write();
-+     if (substdio_bput(&ssout,"",1) == -1) die_write();
-+   }
-+ }
-+
-  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
- 
-  for (;;)
-@@ -237,10 +268,24 @@
-    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
-    for (len = 0;len < ADDR;++len)
-     {
-+     if ( len == 1 ) stralloc_copyb(&chkaddr, &ch,1);
-+     else if ( len > 1 ) stralloc_catb(&chkaddr, &ch,1);
-      if (substdio_get(&ssin,&ch,1) < 1) die_read();
-      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
-      if (!ch) break;
-     }
-+
-+    /* check the to address */
-+    stralloc_0(&chkaddr);
-+    if (tapped == 0 && tapcheck()==1 ) {
-+      tapped = 1;
-+      if ( tapaddr.len > 0 ) {
-+        if (substdio_bput(&ssout,"T",1) == -1) die_write();
-+        if (substdio_bput(&ssout,tapaddr.s,tapaddr.len) == -1) die_write();
-+        if (substdio_bput(&ssout,"",1) == -1) die_write();
-+       }
-+     }
-+
-    if (len >= ADDR) die(11);
-   }
- 
-@@ -252,3 +297,42 @@
-  triggerpull();
-  die(0);
- }
-+
-+int tapcheck()
-+{
-+  int i = 0;
-+  int j = 0;
-+  int x = 0;
-+  int negate = 0;
-+  stralloc curregex = {0};
-+  char tmpbuf[200];
-+
-+  while (j < tap.len) {
-+    i = j;
-+    while ((tap.s[i] != ':') && (i < tap.len)) i++;
-+    if (tap.s[j] == '!') {
-+      negate = 1;
-+      j++;
-+    }
-+    stralloc_copys(&tapaddr, &tap.s[i+1]);
-+
-+    stralloc_copyb(&curregex,tap.s + j,(i - j));
-+    stralloc_0(&curregex);
-+    x = matchregex(chkaddr.s, curregex.s, tmpbuf);
-+
-+    while ((tap.s[i] != '\0') && (i < tap.len)) i++;
-+  
-+    if ((negate) && (x == 0)) {
-+      return 1;
-+    }
-+    if (!(negate) && (x > 0)) {
-+      return 1;
-+    }
-+    j = i + 1;
-+    negate = 0;
-+
-+
-+  }
-+  return 0;
-+}
-+
-diff -Nur qmail-1.03/qregex.c qmail-1.03.tap/qregex.c
---- qmail-1.03/qregex.c	1969-12-31 18:00:00.000000000 -0600
-+++ qmail-1.03.tap/qregex.c	2005-02-15 12:48:58.000000000 -0600
-@@ -0,0 +1,57 @@
-+/*
-+ * qregex (v2)
-+ * $Id: qregex.c,v 2.1 2001/12/28 07:05:21 evan Exp $
-+ *
-+ * Author  : Evan Borgstrom (evan at unixpimps dot org)
-+ * Created : 2001/12/14 23:08:16
-+ * Modified: $Date: 2001/12/28 07:05:21 $
-+ * Revision: $Revision: 2.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 -Nur qmail-1.03/qregex.h qmail-1.03.tap/qregex.h
---- qmail-1.03/qregex.h	1969-12-31 18:00:00.000000000 -0600
-+++ qmail-1.03.tap/qregex.h	2005-02-15 12:48:58.000000000 -0600
-@@ -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 -Nur qmail-1.03/README.tap qmail-1.03.tap/README.tap
---- qmail-1.03/README.tap	1969-12-31 18:00:00.000000000 -0600
-+++ qmail-1.03.tap/README.tap	2005-06-07 09:48:41.000000000 -0500
-@@ -0,0 +1,28 @@
-+qmail provides the ability to make a copy of each email that flows through the system.
-+This is done using the QUEUE_EXTRA code. See qmail FAQ #8.2
-+
-+The qmail tap patch adds additional functionality:
-+1) Specify which email addresses to tap using a regex style control file. With the
-+   regex function, you can specify full domains or individual email addresses.
-+
-+2) Specify which email address to send the emails to.
-+
-+3) Qmail does not need to be restated to when the taps control file is changed.
-+
-+The regex match is applied to both the to and from email addresses. So email
-+sent to or from the addresses will be copied. Matching is case insensitive.
-+If there are multiple matches, the first match is used.
-+
-+The queue tap patch adds a new control file:
-+
-+/var/qmail/control/taps
-+Contains a regex style list of addresses to tap and the email
-+address of where you want the copy sent to.
-+
-+Examples:
-+a) To tap a whole domain add a line like:
-+.*@domain.com:joe@example.com
-+
-+
-+b) To tap an individual email address add a line like:
-+user@domain.com:other@example.com
-diff -Nur qmail-1.03/TARGETS qmail-1.03.tap/TARGETS
---- qmail-1.03/TARGETS	1998-06-15 05:53:16.000000000 -0500
-+++ qmail-1.03.tap/TARGETS	2005-02-15 12:48:21.000000000 -0600
-@@ -385,3 +385,4 @@
- man
- setup
- check
-+qregex.o
Index: l/mailserver/netqmail/qmail.permissions
===================================================================
--- npl/mailserver/netqmail/qmail.permissions	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,191 +1,0 @@
-# qmail permissions - generated by Guilherme Balena Versiani
-# used GNU stat 5.0 by Michael Meskes
-
-qmail_permissions() {
-  chown root.qmail /var/qmail; chmod 755 /var/qmail
-  chown root.root /var/qmail/rc; chmod 700 /var/qmail/rc
-  chown root.qmail /var/qmail/bin; chmod 755 /var/qmail/bin
-  chown root.qmail /var/qmail/bin/elq; chmod 755 /var/qmail/bin/elq
-  chown root.qmail /var/qmail/bin/pinq; chmod 755 /var/qmail/bin/pinq
-  chown root.qmail /var/qmail/bin/qail; chmod 755 /var/qmail/bin/qail
-  chown root.root /var/qmail/bin/checkpassword; chmod 700 /var/qmail/bin/checkpassword
-  chown root.qmail /var/qmail/bin/qmail-showctl; chmod 755 /var/qmail/bin/qmail-showctl
-  chown root.root /var/qmail/bin/printforward; chmod 755 /var/qmail/bin/printforward
-  chown root.qmail /var/qmail/bin/datemail; chmod 755 /var/qmail/bin/datemail
-  chown root.qmail /var/qmail/bin/condredirect; chmod 755 /var/qmail/bin/condredirect
-  chown root.qmail /var/qmail/bin/qsmhook; chmod 755 /var/qmail/bin/qsmhook
-  chown root.root /var/qmail/bin/dot-forward; chmod 755 /var/qmail/bin/dot-forward
-  chown root.qmail /var/qmail/bin/qbiff; chmod 755 /var/qmail/bin/qbiff
-  chown root.qmail /var/qmail/bin/qreceipt; chmod 755 /var/qmail/bin/qreceipt
-  chown root.qmail /var/qmail/bin/splogger; chmod 711 /var/qmail/bin/splogger
-  chown root.root /var/qmail/bin/newaliases; chmod 755 /var/qmail/bin/newaliases
-  chown root.root /var/qmail/bin/qmail-smtpd-conf; chmod 755 /var/qmail/bin/qmail-smtpd-conf
-  chown root.qmail /var/qmail/bin/mailsubj; chmod 755 /var/qmail/bin/mailsubj
-  chown root.qmail /var/qmail/bin/tcp-env; chmod 755 /var/qmail/bin/tcp-env
-  chown root.root /var/qmail/bin/qmail-delivery-conf; chmod 755 /var/qmail/bin/qmail-delivery-conf
-  chown root.root /var/qmail/bin/setmaillist; chmod 755 /var/qmail/bin/setmaillist
-  chown root.root /var/qmail/bin/qmail-pop3d-conf; chmod 755 /var/qmail/bin/qmail-pop3d-conf
-  chown root.qmail /var/qmail/bin/qmail-clean; chmod 711 /var/qmail/bin/qmail-clean
-  chown root.qmail /var/qmail/bin/qmail-getpw; chmod 711 /var/qmail/bin/qmail-getpw
-  chown root.qmail /var/qmail/bin/qmail-local; chmod 711 /var/qmail/bin/qmail-local
-  chown root.qmail /var/qmail/bin/qmail-pop3d; chmod 755 /var/qmail/bin/qmail-pop3d
-  chown root.qmail /var/qmail/bin/qmail-popup; chmod 711 /var/qmail/bin/qmail-popup
-  chown root.qmail /var/qmail/bin/qmail-qmqpc; chmod 755 /var/qmail/bin/qmail-qmqpc
-  chown root.qmail /var/qmail/bin/qmail-qmqpd; chmod 755 /var/qmail/bin/qmail-qmqpd
-  chown root.qmail /var/qmail/bin/qmail-qmtpd; chmod 755 /var/qmail/bin/qmail-qmtpd
-  chown root.qmail /var/qmail/bin/qmail-qread; chmod 755 /var/qmail/bin/qmail-qread
-  chown root.qmail /var/qmail/bin/qmail-qstat; chmod 755 /var/qmail/bin/qmail-qstat
-  chown qmailq.qmail /var/qmail/bin/qmail-queue; chmod 4711 /var/qmail/bin/qmail-queue
-  chown root.qmail /var/qmail/bin/qmail-smtpd; chmod 755 /var/qmail/bin/qmail-smtpd
-  chown root.qmail /var/qmail/bin/qmail-tcpok; chmod 755 /var/qmail/bin/qmail-tcpok
-  chown root.qmail /var/qmail/bin/qmail-tcpto; chmod 755 /var/qmail/bin/qmail-tcpto
-  chown root.qmail /var/qmail/bin/qmail-start; chmod 700 /var/qmail/bin/qmail-start
-  chown root.root /var/qmail/bin/newinclude; chmod 755 /var/qmail/bin/newinclude
-  chown root.root /var/qmail/bin/fastforward; chmod 755 /var/qmail/bin/fastforward
-  chown root.root /var/qmail/bin/config; chmod 755 /var/qmail/bin/config
-  chown root.qmail /var/qmail/bin/maildir2mbox; chmod 755 /var/qmail/bin/maildir2mbox
-  chown root.qmail /var/qmail/bin/forward; chmod 755 /var/qmail/bin/forward
-  chown root.root /var/qmail/bin/qmail-lint; chmod 755 /var/qmail/bin/qmail-lint
-  chown root.qmail /var/qmail/bin/qmail-newu; chmod 700 /var/qmail/bin/qmail-newu
-  chown root.qmail /var/qmail/bin/qmail-pw2u; chmod 711 /var/qmail/bin/qmail-pw2u
-  chown root.qmail /var/qmail/bin/qmail-send; chmod 711 /var/qmail/bin/qmail-send
-  chown root.qmail /var/qmail/bin/except; chmod 755 /var/qmail/bin/except
-  chown root.qmail /var/qmail/bin/qmail-inject; chmod 755 /var/qmail/bin/qmail-inject
-  chown root.qmail /var/qmail/bin/maildirwatch; chmod 755 /var/qmail/bin/maildirwatch
-  chown root.qmail /var/qmail/bin/qmail-lspawn; chmod 700 /var/qmail/bin/qmail-lspawn
-  chown root.qmail /var/qmail/bin/qmail-newmrh; chmod 700 /var/qmail/bin/qmail-newmrh
-  chown root.root /var/qmail/bin/config-fast; chmod 755 /var/qmail/bin/config-fast
-  chown root.root /var/qmail/bin/setforward; chmod 755 /var/qmail/bin/setforward
-  chown root.root /var/qmail/bin/printmaillist; chmod 755 /var/qmail/bin/printmaillist
-  chown root.qmail /var/qmail/bin/maildirmake; chmod 755 /var/qmail/bin/maildirmake
-  chown root.qmail /var/qmail/bin/qmail-remote; chmod 711 /var/qmail/bin/qmail-remote
-  chown root.qmail /var/qmail/bin/qmail-rspawn; chmod 711 /var/qmail/bin/qmail-rspawn
-  chown root.qmail /var/qmail/bin/bouncesaying; chmod 755 /var/qmail/bin/bouncesaying
-  chown root.qmail /var/qmail/bin/sendmail; chmod 755 /var/qmail/bin/sendmail
-  chown root.root /var/qmail/bin/qmail-qmtpd-conf; chmod 755 /var/qmail/bin/qmail-qmtpd-conf
-  chown root.qmail /var/qmail/bin/predate; chmod 755 /var/qmail/bin/predate
-  chown root.qmail /var/qmail/bin/preline; chmod 755 /var/qmail/bin/preline
-  chown root.root /var/qmail/bin/qmail-qmqpd-conf; chmod 755 /var/qmail/bin/qmail-qmqpd-conf
-  chown root.qmail /var/qmail/boot; chmod 755 /var/qmail/boot
-  chown root.qmail /var/qmail/boot/binm1+df; chmod 755 /var/qmail/boot/binm1+df
-  chown root.qmail /var/qmail/boot/binm2+df; chmod 755 /var/qmail/boot/binm2+df
-  chown root.qmail /var/qmail/boot/binm3+df; chmod 755 /var/qmail/boot/binm3+df
-  chown root.qmail /var/qmail/boot/home; chmod 755 /var/qmail/boot/home
-  chown root.qmail /var/qmail/boot/proc; chmod 755 /var/qmail/boot/proc
-  chown root.qmail /var/qmail/boot/binm1; chmod 755 /var/qmail/boot/binm1
-  chown root.qmail /var/qmail/boot/binm2; chmod 755 /var/qmail/boot/binm2
-  chown root.qmail /var/qmail/boot/binm3; chmod 755 /var/qmail/boot/binm3
-  chown root.qmail /var/qmail/boot/home+df; chmod 755 /var/qmail/boot/home+df
-  chown root.qmail /var/qmail/boot/proc+df; chmod 755 /var/qmail/boot/proc+df
-  chown root.qmail /var/qmail/control; chmod 755 /var/qmail/control
-  chown alias.qmail /var/qmail/alias; chmod 2755 /var/qmail/alias
-  chown qmailq.qmail /var/qmail/queue; chmod 750 /var/qmail/queue
-  chown qmailq.qmail /var/qmail/queue/pid; chmod 700 /var/qmail/queue/pid
-  chown qmails.qmail /var/qmail/queue/info; chmod 700 /var/qmail/queue/info
-  chown qmails.qmail /var/qmail/queue/info/0; chmod 700 /var/qmail/queue/info/0
-  chown qmails.qmail /var/qmail/queue/info/1; chmod 700 /var/qmail/queue/info/1
-  chown qmails.qmail /var/qmail/queue/info/2; chmod 700 /var/qmail/queue/info/2
-  chown qmails.qmail /var/qmail/queue/info/3; chmod 700 /var/qmail/queue/info/3
-  chown qmails.qmail /var/qmail/queue/info/4; chmod 700 /var/qmail/queue/info/4
-  chown qmails.qmail /var/qmail/queue/info/5; chmod 700 /var/qmail/queue/info/5
-  chown qmails.qmail /var/qmail/queue/info/6; chmod 700 /var/qmail/queue/info/6
-  chown qmails.qmail /var/qmail/queue/info/7; chmod 700 /var/qmail/queue/info/7
-  chown qmails.qmail /var/qmail/queue/info/8; chmod 700 /var/qmail/queue/info/8
-  chown qmails.qmail /var/qmail/queue/info/9; chmod 700 /var/qmail/queue/info/9
-  chown qmails.qmail /var/qmail/queue/info/10; chmod 700 /var/qmail/queue/info/10
-  chown qmails.qmail /var/qmail/queue/info/11; chmod 700 /var/qmail/queue/info/11
-  chown qmails.qmail /var/qmail/queue/info/12; chmod 700 /var/qmail/queue/info/12
-  chown qmails.qmail /var/qmail/queue/info/13; chmod 700 /var/qmail/queue/info/13
-  chown qmails.qmail /var/qmail/queue/info/14; chmod 700 /var/qmail/queue/info/14
-  chown qmails.qmail /var/qmail/queue/info/15; chmod 700 /var/qmail/queue/info/15
-  chown qmails.qmail /var/qmail/queue/info/16; chmod 700 /var/qmail/queue/info/16
-  chown qmails.qmail /var/qmail/queue/info/17; chmod 700 /var/qmail/queue/info/17
-  chown qmails.qmail /var/qmail/queue/info/18; chmod 700 /var/qmail/queue/info/18
-  chown qmails.qmail /var/qmail/queue/info/19; chmod 700 /var/qmail/queue/info/19
-  chown qmails.qmail /var/qmail/queue/info/20; chmod 700 /var/qmail/queue/info/20
-  chown qmails.qmail /var/qmail/queue/info/21; chmod 700 /var/qmail/queue/info/21
-  chown qmails.qmail /var/qmail/queue/info/22; chmod 700 /var/qmail/queue/info/22
-  chown qmailq.qmail /var/qmail/queue/intd; chmod 700 /var/qmail/queue/intd
-  chown qmailq.qmail /var/qmail/queue/lock; chmod 750 /var/qmail/queue/lock
-  chown qmailr.qmail /var/qmail/queue/lock/tcpto; chmod 644 /var/qmail/queue/lock/tcpto
-  chown qmails.qmail /var/qmail/queue/lock/sendmutex; chmod 600 /var/qmail/queue/lock/sendmutex
-  chown qmails.qmail /var/qmail/queue/lock/trigger; chmod 622 /var/qmail/queue/lock/trigger
-  chown qmailq.qmail /var/qmail/queue/mess; chmod 750 /var/qmail/queue/mess
-  chown qmailq.qmail /var/qmail/queue/mess/0; chmod 750 /var/qmail/queue/mess/0
-  chown qmailq.qmail /var/qmail/queue/mess/1; chmod 750 /var/qmail/queue/mess/1
-  chown qmailq.qmail /var/qmail/queue/mess/2; chmod 750 /var/qmail/queue/mess/2
-  chown qmailq.qmail /var/qmail/queue/mess/3; chmod 750 /var/qmail/queue/mess/3
-  chown qmailq.qmail /var/qmail/queue/mess/4; chmod 750 /var/qmail/queue/mess/4
-  chown qmailq.qmail /var/qmail/queue/mess/5; chmod 750 /var/qmail/queue/mess/5
-  chown qmailq.qmail /var/qmail/queue/mess/6; chmod 750 /var/qmail/queue/mess/6
-  chown qmailq.qmail /var/qmail/queue/mess/7; chmod 750 /var/qmail/queue/mess/7
-  chown qmailq.qmail /var/qmail/queue/mess/8; chmod 750 /var/qmail/queue/mess/8
-  chown qmailq.qmail /var/qmail/queue/mess/9; chmod 750 /var/qmail/queue/mess/9
-  chown qmailq.qmail /var/qmail/queue/mess/10; chmod 750 /var/qmail/queue/mess/10
-  chown qmailq.qmail /var/qmail/queue/mess/11; chmod 750 /var/qmail/queue/mess/11
-  chown qmailq.qmail /var/qmail/queue/mess/12; chmod 750 /var/qmail/queue/mess/12
-  chown qmailq.qmail /var/qmail/queue/mess/13; chmod 750 /var/qmail/queue/mess/13
-  chown qmailq.qmail /var/qmail/queue/mess/14; chmod 750 /var/qmail/queue/mess/14
-  chown qmailq.qmail /var/qmail/queue/mess/15; chmod 750 /var/qmail/queue/mess/15
-  chown qmailq.qmail /var/qmail/queue/mess/16; chmod 750 /var/qmail/queue/mess/16
-  chown qmailq.qmail /var/qmail/queue/mess/17; chmod 750 /var/qmail/queue/mess/17
-  chown qmailq.qmail /var/qmail/queue/mess/18; chmod 750 /var/qmail/queue/mess/18
-  chown qmailq.qmail /var/qmail/queue/mess/19; chmod 750 /var/qmail/queue/mess/19
-  chown qmailq.qmail /var/qmail/queue/mess/20; chmod 750 /var/qmail/queue/mess/20
-  chown qmailq.qmail /var/qmail/queue/mess/21; chmod 750 /var/qmail/queue/mess/21
-  chown qmailq.qmail /var/qmail/queue/mess/22; chmod 750 /var/qmail/queue/mess/22
-  chown qmailq.qmail /var/qmail/queue/todo; chmod 750 /var/qmail/queue/todo
-  chown qmails.qmail /var/qmail/queue/local; chmod 700 /var/qmail/queue/local
-  chown qmails.qmail /var/qmail/queue/local/0; chmod 700 /var/qmail/queue/local/0
-  chown qmails.qmail /var/qmail/queue/local/1; chmod 700 /var/qmail/queue/local/1
-  chown qmails.qmail /var/qmail/queue/local/2; chmod 700 /var/qmail/queue/local/2
-  chown qmails.qmail /var/qmail/queue/local/3; chmod 700 /var/qmail/queue/local/3
-  chown qmails.qmail /var/qmail/queue/local/4; chmod 700 /var/qmail/queue/local/4
-  chown qmails.qmail /var/qmail/queue/local/5; chmod 700 /var/qmail/queue/local/5
-  chown qmails.qmail /var/qmail/queue/local/6; chmod 700 /var/qmail/queue/local/6
-  chown qmails.qmail /var/qmail/queue/local/7; chmod 700 /var/qmail/queue/local/7
-  chown qmails.qmail /var/qmail/queue/local/8; chmod 700 /var/qmail/queue/local/8
-  chown qmails.qmail /var/qmail/queue/local/9; chmod 700 /var/qmail/queue/local/9
-  chown qmails.qmail /var/qmail/queue/local/10; chmod 700 /var/qmail/queue/local/10
-  chown qmails.qmail /var/qmail/queue/local/11; chmod 700 /var/qmail/queue/local/11
-  chown qmails.qmail /var/qmail/queue/local/12; chmod 700 /var/qmail/queue/local/12
-  chown qmails.qmail /var/qmail/queue/local/13; chmod 700 /var/qmail/queue/local/13
-  chown qmails.qmail /var/qmail/queue/local/14; chmod 700 /var/qmail/queue/local/14
-  chown qmails.qmail /var/qmail/queue/local/15; chmod 700 /var/qmail/queue/local/15
-  chown qmails.qmail /var/qmail/queue/local/16; chmod 700 /var/qmail/queue/local/16
-  chown qmails.qmail /var/qmail/queue/local/17; chmod 700 /var/qmail/queue/local/17
-  chown qmails.qmail /var/qmail/queue/local/18; chmod 700 /var/qmail/queue/local/18
-  chown qmails.qmail /var/qmail/queue/local/19; chmod 700 /var/qmail/queue/local/19
-  chown qmails.qmail /var/qmail/queue/local/20; chmod 700 /var/qmail/queue/local/20
-  chown qmails.qmail /var/qmail/queue/local/21; chmod 700 /var/qmail/queue/local/21
-  chown qmails.qmail /var/qmail/queue/local/22; chmod 700 /var/qmail/queue/local/22
-  chown qmails.qmail /var/qmail/queue/bounce; chmod 700 /var/qmail/queue/bounce
-  chown qmails.qmail /var/qmail/queue/remote; chmod 700 /var/qmail/queue/remote
-  chown qmails.qmail /var/qmail/queue/remote/0; chmod 700 /var/qmail/queue/remote/0
-  chown qmails.qmail /var/qmail/queue/remote/1; chmod 700 /var/qmail/queue/remote/1
-  chown qmails.qmail /var/qmail/queue/remote/2; chmod 700 /var/qmail/queue/remote/2
-  chown qmails.qmail /var/qmail/queue/remote/3; chmod 700 /var/qmail/queue/remote/3
-  chown qmails.qmail /var/qmail/queue/remote/4; chmod 700 /var/qmail/queue/remote/4
-  chown qmails.qmail /var/qmail/queue/remote/5; chmod 700 /var/qmail/queue/remote/5
-  chown qmails.qmail /var/qmail/queue/remote/6; chmod 700 /var/qmail/queue/remote/6
-  chown qmails.qmail /var/qmail/queue/remote/7; chmod 700 /var/qmail/queue/remote/7
-  chown qmails.qmail /var/qmail/queue/remote/8; chmod 700 /var/qmail/queue/remote/8
-  chown qmails.qmail /var/qmail/queue/remote/9; chmod 700 /var/qmail/queue/remote/9
-  chown qmails.qmail /var/qmail/queue/remote/10; chmod 700 /var/qmail/queue/remote/10
-  chown qmails.qmail /var/qmail/queue/remote/11; chmod 700 /var/qmail/queue/remote/11
-  chown qmails.qmail /var/qmail/queue/remote/12; chmod 700 /var/qmail/queue/remote/12
-  chown qmails.qmail /var/qmail/queue/remote/13; chmod 700 /var/qmail/queue/remote/13
-  chown qmails.qmail /var/qmail/queue/remote/14; chmod 700 /var/qmail/queue/remote/14
-  chown qmails.qmail /var/qmail/queue/remote/15; chmod 700 /var/qmail/queue/remote/15
-  chown qmails.qmail /var/qmail/queue/remote/16; chmod 700 /var/qmail/queue/remote/16
-  chown qmails.qmail /var/qmail/queue/remote/17; chmod 700 /var/qmail/queue/remote/17
-  chown qmails.qmail /var/qmail/queue/remote/18; chmod 700 /var/qmail/queue/remote/18
-  chown qmails.qmail /var/qmail/queue/remote/19; chmod 700 /var/qmail/queue/remote/19
-  chown qmails.qmail /var/qmail/queue/remote/20; chmod 700 /var/qmail/queue/remote/20
-  chown qmails.qmail /var/qmail/queue/remote/21; chmod 700 /var/qmail/queue/remote/21
-  chown qmails.qmail /var/qmail/queue/remote/22; chmod 700 /var/qmail/queue/remote/22
-  chown root.qmail /var/qmail/users; chmod 755 /var/qmail/users
-  chown root.root /var/qmail/service; chmod 755 /var/qmail/service
-  chown qmaill /var/log/qmail; chmod 755 /var/log/qmail
-}
-
Index: l/mailserver/netqmail/qmail.rc.config
===================================================================
--- npl/mailserver/netqmail/qmail.rc.config	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,24 +1,0 @@
-#
-# Qmail configuration file
-# 
-# Author:
-# 	Guilherme Balena Versiani, guibv@yahoo.com
-#
-# Last Update: Mon Sep 03 18:57:44 BRT 2001
-
-#
-# Qmail users (you should not change these!)
-#
-QMAIL_USER_0="alias:50:nofiles:/var/qmail/alias"
-QMAIL_USER_1="qmaild:51:nofiles:/var/qmail"
-QMAIL_USER_2="qmaill:52:nofiles:/var/qmail"
-QMAIL_USER_3="qmailp:53:nofiles:/var/qmail"
-QMAIL_USER_4="qmailq:54:qmail:/var/qmail"
-QMAIL_USER_5="qmailr:55:qmail:/var/qmail"
-QMAIL_USER_6="qmails:56:qmail:/var/qmail"
-
-#
-# Qmail groups (you should not change these!)
-#
-QMAIL_GROUP_0="nofiles:55"
-QMAIL_GROUP_1="qmail:56"
Index: l/mailserver/netqmail/qmailctl
===================================================================
--- npl/mailserver/netqmail/qmailctl	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,166 +1,0 @@
-#! /bin/sh
-#
-# Author:
-# 	Guilherme Balena Versiani, guibv@yahoo.com 
-#
-# /usr/sbin/qmailctl
-
-. /etc/qmail.rc.config
-. /etc/qmail.permissions
-
-SEND=qmail-send
-SMTP=qmail-smtpd
-POP3=qmail-pop3d
-QMQP=qmail-qmqpd
-QMTP=qmail-qmtpd
-
-QMAILBIN=/var/qmail
-
-SERVICES="$SEND $SMTP $POP3 $QMQP $QMTP"
-
-qmail_start() {
-  for service in $SERVICES; do
-    if [ -e /service/$service ]; then
-      if svok /service/$service; then
-	echo -n "$service "
-	svc -u /service/$service
-      else
-	echo -n "$service [error] "
-      fi
-    fi
-  done
-  if [ -d /var/run/subsys ]; then
-    touch /var/lock/subsys/qmail
-  fi
-}
-
-qmail_stop() {
-  for service in $SERVICES; do
-    if [ -e /service/$service ]; then
-      echo -n "$service "
-      svc -d /service/$service
-    fi
-  done
-  if [ -f /var/lock/subsys/qmail ]; then
-    rm -f /var/lock/subsys/qmail
-  fi
-}
-
-qmail_restart() {
-  $0 stop  &&  $0 start
-}
-
-qmail_pause() {
-  for service in $SERVICES; do
-    if [ -e /service/$service ]; then
-      echo -n "$service "
-      svc -p /service/$service
-    fi
-  done
-}
-
-qmail_continue() {
-  for service in $SERVICES; do
-    if [ -e /service/$service ]; then
-      echo -n "$service "
-      svc -c /service/$service
-    fi
-  done
-}
-
-qmail_status() {
-  for service in $SERVICES; do
-    if [ -e /service/$service ]; then
-      svstat /service/$service
-      svstat /service/$service/log
-    fi
-  done
-  $QMAILBIN/qmail-qstat
-}
-
-qmail_flush() {
-  if [ -e /service/$SEND ]; then
-    svc -a /service/$SEND
-    echo "OK"
-  else
-    echo "No qmail-send found!"
-  fi
-}
-
-qmail_reload() {
-  $QMAILBIN/qmail-qstat
-  $QMAILBIN/qmail-qread
-}
-
-qmail_user() {
-  for I in _0 _1 _2 _3 _4 _5 _6; do
-    eval CUR_USER=\$QMAIL_USER$I
-    USER=`echo "$CUR_USER" | cut -d ':' -f 1`
-    grep "$USER" /etc/passwd > /dev/null && userdel $USER
-  done
-  for I in _0 _1; do
-    eval CUR_GROUP=\$QMAIL_GROUP$I
-    GROUP=`echo "$CUR_GROUP" | cut -d ':' -f 1`
-    grep "$GROUP" /etc/group > /dev/null && groupdel $GROUP
-  done
-  for I in _0 _1; do
-    eval CUR_GROUP=\$QMAIL_GROUP$I
-    GROUP=`echo "$CUR_GROUP" | cut -d ':' -f 1`
-    CGID=`echo "$CUR_GROUP" | cut -d ':' -f 2`
-    groupadd -g $CGID $GROUP
-  done
-  for I in _0 _1 _2 _3 _4 _5 _6; do
-    eval CUR_USER=\$QMAIL_USER$I
-    USER=`echo "$CUR_USER" | cut -d ':' -f 1`
-    CUID=`echo "$CUR_USER" | cut -d ':' -f 2`
-    GROUP=`echo "$CUR_USER" | cut -d ':' -f 3`
-    HOME=`echo "$CUR_USER" | cut -d ':' -f 4`
-    useradd -u $CUID -g $GROUP -d $HOME -s /bin/false $USER
-  done
-}
-
-qmail_showctl() {
-  $QMAILBIN/qmail-showctl
-}
-
-usage() {
-  cat << EOF
-Qmailctl by Guilherme Balena Versiani
-* Portions from Life with Qmail (http://www.lifewithqmail.org/)
-
-Usage: $0 [OPTION]
-
-Available options:
-
-  start    Start all qmail services
-  stop     Stop all qmail services
-  restart  Restart all qmail services
-  status   Show qmail status
-  showctl  Show qmail control status
-  flush    Flush qmail queue
-  queue    Show qmail queue
-  pause    Pause all qmail services
-  cont     Continue all qmail services
-  perms    Check all qmail permissions
-  user     (Re)create all qmail users
-
-Mail bug reports and suggestions to <guibv@yahoo.com>.
-EOF
-}
-
-# First reset status of this service
-case "$1" in
-    start)   echo -n "Starting qmail: "; qmail_start; echo;;
-    stop)    echo -n "Shutting down qmail: "; qmail_stop; echo;;
-    restart) qmail_restart;;
-    status)  echo "Checking qmail status: "; qmail_status;;
-    showctl) qmail_showctl;;
-    flush)   echo "Sending ALRM signal to qmail-send: "; qmail_flush;;
-    queue)   echo "Listing qmail queue: "; qmail_queue;;
-    pause)   echo -n "Pausing qmail: "; qmail_pause; echo "";;
-    cont)    echo "Continuing qmail: "; qmail_continue; echo "";;
-    user)    echo -n "Checking qmail users/groups: "; qmail_user; echo "OK";;
-    perms)   echo -n "Checking qmail permissions: "; qmail_permissions; echo "OK";;
-    *)       usage; exit 1;;
-esac
-
Index: npl/mailserver/netqmail/roberto-netqmail-1.06.patch-latest
===================================================================
--- npl/mailserver/netqmail/roberto-netqmail-1.06.patch-latest	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail/roberto-netqmail-1.06.patch-latest	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,31209 @@
+v. 2018.04.03
+Combined patch for netqmail-1.06 by Roberto Puzzanghera [roberto dot puzzanghera at sagredo dot eu]
+More info at http://notes.sagredo.eu/node/82
+==========================================================================================================
+
+= This patch puts together
+* Erwin Hoffmann's qmail-authentication patch v. 0.8.3 (23.08.2015), which updates the patches provided by
+  Krysztof Dabrowski and Bjoern Kalkbrenner.
+  It provides cram-md5, login, plain authentication support for qmail-smtpd and qmail-remote.
+  http://www.fehcom.de/qmail/smtpauth.html##PATCHES
+* Frederik Vermeulen's qmail-tls patch v. 20160908
+  implements SSL or TLS encrypted and authenticated SMTP.
+  http://inoa.net/qmail-tls/
+  The file update_tmprsadh was modified to chown all .pem files to vpopmail.
+* Marcel Telka's force-tls patch v. 2016.05.15
+  optionally gets qmail to require TLS before authentication to improve security.
+  You have to declare FORCETLS=0 if you want to allow the auth without TLS
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/roberto-netqmail-1.06_force-tls.patch-2012.10.28
+* Antonio Nati's chkuser patch v. 2.0.9
+  performs, among the other things, a check for the existence of recipients during the SMTP conversation,
+  bouncing emails of fake senders.
+  http://www.interazioni.it/opensource/chkuser/
+* Flavio Curti's qmail-queue-custom-error patch
+  enables simscan and qmail-dkim to return the appropriate message for each e-mail it refuses to deliver.
+  https://no-way.org/uploads/qmail-error/
+* Christophe Saout's qmail-SPF rc5 patch
+  Modified by Manvendra Bhangui to make it IPv4-mapped IPv6 addresses compliant.
+  checks incoming mails inside the SMTP daemon, add Received-SPF lines and optionally block undesired transfers.
+  http://www.saout.de/misc/spf/
+* Marcelo Coelho's qmail-SRS patch
+  implements Sender Rewriting Scheme fixing SPF break upon email forwarding.
+  http://www.mco2.com.br/opensource/qmail/srs/
+* Christopher K. Davis' oversize dns patch
+  enables qmail to handle large DNS packets.
+  http://www.ckdhr.com/ckd/qmail-103.patch
+* Jul's reread-concurrency v.2 patch
+  rereads control/concurrencylocal and control/concurrencyremote files when qmail-send receives a HUP signal.
+  http://js.hu/package/qmail/index.html
+* Johannes Erdfelt's Big Concurrency patch
+  sets the spawn limit above 255
+  http://qmail.org/big-concurrency.patch
+* Mihai Secasiu's Big Concurrency fix v.1.0 patch
+  fixes a compiler error if you set concurrency higher than 509 in conf-spawn.
+  http://patchlog.com/linux/qmail-big-concurrency/
+* Bill Shupp's netqmail-maildir++.patch
+  adds maildirquota support to qmail-pop3d and qmail-local.
+  Fixed a bug where the filesize part of the S=<filesize> component of the Maildir++ compatible filename is wrong (tx MG).
+  More info here: http://notes.sagredo.eu/en/qmail-notes-185/installing-dovecot-and-sieve-on-a-vpopmail-qmail-server-28.html#comment995
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/netqmail-maildir.patch
+* Kyle B. Wheeler's "Better qmail-smtpd Logging" v.4 (05 Jan 2010) patch
+  facilitates diagnostics of qmail-smtpd logging its actions and decisions (search for a line with qmail-smtp:)
+  http://www.memoryhole.net/qmail/#logging
+* John Simpson's (?) Greeting delay patch
+  adds a user-definable delay after SMTP clients have initiated SMTP sessions, prior to qmail-smtpd responding
+  with "220 ESMTP". It can reject connections from clients which tried to send commands before greeting.
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-greetdelay.patch
+* Manvendra Bhangui's DKIM and SURBL filter v.1.22 patch
+  adds DKIM signing & verification and SURBL filtering support to qmail.
+  qmail-dk is based on Russ Nelson's patch: http//:www.qmail.org/qmail-1.03-dk-0.54.patch
+  qmail-dkim uses hacked libdkim libraries from libdkim project at http://libdkim.sourceforge.net/
+  surbfilter is built on djb functions and some functions have been ruthlessly borrowed from qmail surbl
+  interface by Pieter Droogendijk and the surblhost program at http://surblhost.sourceforge.net/
+  (file hier.c modified to chown /var/qmail/control/cache and subdirs to vpopmail)
+  http://sourceforge.net/projects/indimail/files/netqmail-addons/qmail-dkim-1.0/
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/ANNOUNCE.surblfilter
+* Claudio Jeker and Andre Oppermann's EXTTODO patch (release 5. Jan. 2003)
+  addresses a problem known as the silly qmail (queue)  problem
+  http://www.nrg4u.com/qmail/ext_todo-20030105.patch
+* Russell Nelson's big-todo patch
+  makes qmail use a hashing mechanism in the todo folder similar to that used in the rest of the queue
+  http://www.qmail.org/big-todo.103.patch
+* Stephane Cottin's qmail-inject-null-sender patch (let's call it in this way)
+  prevents qmail-inject from rewriting the null sender, fixing an issue with sieve vacation/reject messages.
+  More info here: http://www.dovecot.org/list/dovecot/2009-June/040811.html
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-inject-null-sender.patch
+* Russell Nelson's (modified by Charles Cazabon) doublebounce-trim patch, which updates the original
+  version by Russel Nelson
+  prevents double bounces from hitting your queue a second time provided that you delete the first line
+  from /var/qmail/control/doublebounceto
+  http://qmail.org/doublebounce-trim.patch
+* Will Harris' esmtp-size patch
+  enables qmail-smtpd to reject messages if they're larger than the maximum number of bytes allowed
+  according to the /var/qmail/control/databytes control file.
+  http://will.harris.ch/qmail-smtpd.c.diff
+* Inter7's qmail-taps-extended patch
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-tap.diff
+  Extended by Michai Secasiu (http://patchlog.com/patches/qmail-taps-extended/)
+  Provides the ability to archive each email that flows through the system.
+  Archiving only messages from or to certain email addresses is possible as well.
+* Rolf Eike Beer's qmail-remote CRLF patch
+  enables qmail-remote to handle CR properly, always sending the line breaks as CRLF and avoiding to
+  double the CR (like qmail-remote normally does)
+  http://opensource.sf-tec.de/qmail/
+* Andy Repton's outgoingip patch (adjusted by Sergio Gelato)
+  by default all outgoing emails are sent through the first IP address on the interface. In case of a multiple
+  IP server this patch makes qmail send outgoing emails with the IP eventually stored in control/outgoingip.
+  The ehlo domain is NOT modified by this patch.
+  http://www.qmail.org/outgoingip.patch
+  Robbie Walker provided a patch to correct qmail-qmqpc.c's call to timeoutconn(), because the function
+  signature was modified by the original outgoingip patch
+  http://notes.sagredo.eu/node/82#comment-373
+* Iain Patterson's qmail-smtpd pid, qp log patch
+  makes qmail-smtpd log a line similar to the following:
+  @4000000039b89c95026a89b4 mail recv: pid 8155 from <name@domain.xy> qp 8157
+  The pid allows you to match the message up with a given tcpserver process and the qp lets you find a
+  particular delivery.
+  http://iain.cx/qmail/patches.html#smtpd_pidqp
+* Jonathan de Boyne Pollard's any-to-cname patch
+  avoids qmail getting large amounts of DNS data we have no interest in and that may overflow our response
+  buffer.
+  http://www.memoryhole.net/qmail/#any-to-cname
+* Matthias Andree's qmail-rfc2821 patch
+  makes qmail rfc2821 compliant
+  http://www-dt.e-technik.uni-dortmund.de/~ma/qmail/patch-qmail-1.03-rfc2821.diff
+* Jonathan de Boyne Pollard's smtpd-502-to-500 patch
+  makes qmail rfc2821 compliant
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/smtpd-502-to-500.patch
+* Fabio Busatto's qmail-dnsbl patch
+  allows you to reject spam and virus looking at the sender's ip address.
+  Modified by Luca Franceschini to add support for whitelists, TXT and A queries, configurable return codes 
+  451 or 553 with custom messages
+  http://qmail-dnsbl.sourceforge.net/
+* Scott Gifford's qmail-moreipme patch v. 0.6
+  prevents a problem caused by an MX or other mail routing directive instructing qmail to connect to
+  itself without realizing it's connecting to itself, saving CPU time.
+  http://www.suspectclass.com/sgifford/qmail/qmail-1.03-moreipme.README
+  http://www.suspectclass.com/sgifford/qmail/qmail-1.03-moreipme-0.6.patch
+* Alex Nee's qmail-hide-ip-headers patch
+  It will hide your Private or Public IP in the email Headers when you are sending Mail as a Relay Client.
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-hide-ip-headers.patch
+* John Saunders' qmail-date-localtime patch
+  causes the various qmail programs to generate date stamps in the local timezone.
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-date-localtime.patch
+* Dean Gaudet's qmail-liberal-lf patch v. 0.95
+  allow qmail-smtpd to accept messages that are terminated with a single \n instead of the required \r\n
+  sequence.
+  http://www.arctic.org/~dean/patches/qmail-0.95-liberal-lf.patch
+* Michael Samuel's maxrcpt patch
+  allows you to set a limit on how many recipients are specified for any one email message by setting
+  control/maxrcpt. RFC 2821 section 4.5.3.1 says that an MTA MUST allow at least 100 recipients for each
+  message, since this is one of the favourite tricks of the spammer.
+  http://copilotco.com/mail-archives/qmail.1997/msg03066.html
+* Inter7's qmail-eMPF patch
+  More info: http://www.qmailwiki.org/EMPF
+  eMPF follows a set of administrator-defined rules describing who can message whom.  With this, companies can segregate
+  various parts of their organizations email activities, as well as provide a variety of security-enhancing services.
+* qregex (by  Andrew St. Jean http://www.arda.homeunix.net/downloads-qmail/, contributors: Jeremy Kitchen, Alex Pleiner,
+  Thanos Massias. Original patch by Evan Borgstrom)
+  adds the ability to match address evelopes via Regular Expressions (REs) in the qmail-smtpd process.
+  Added new control file 'badhelonorelay', control/badmailto renamed control/badrcptto (Tx Luca Franceschini).
+* brtlimit
+  Luca Franceschini derived this patch from http://netdevice.com/qmail/patch/goodrcptto-12.patch
+  added control/brtlimit and BRTLIMIT variable to limit max invalid recipient errors before closing the connection (man qmail-control)
+* validrcptto
+  http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/validrcptto.README
+  Luca Franceschini grabbed the code from several patches with additional features: http://qmail.jms1.net/patches/validrcptto cdb.shtml,
+  http://netdevice.com/qmail/patch/goodrcptto-ms-12.patch, http://patch.be/qmail/badrcptto.html
+  It works in conjunction with chkuser with both cdb and mysql accounts.
+* reject-relay-test by Russell Nelson
+  http://qmail.org/qmail-smtpd-relay-reject
+  It gets qmail to reject relay probes generated by so-called anti-spammers. These relay probes have '!', '%' and '@'
+  in the local (username) part of the address.
+* Luca Franceschini
+  added DISABLETLS environment variable, useful if you want to disable TLS on a desired port
+  added FORCEAUTHMAILFROM environment variable to REQUIRE that authenticated user and 'mail from' are identical
+  added SMTPAUTHMETHOD, SMTPAUTHUSER and SMTP_AUTH_USER env variables for external plugins (see http://qmail-spp.sourceforge.net/doc/)
+* fixed little bug in 'mail from' address handling 
+  patch by Andre Opperman at http://qmail.cr.yp.narkive.com/kBry6GJl/bug-in-qmail-smtpd-c-addrparse-function
+* Luca Franceschini's qlog patch
+  smtpd logging with fixed format. An entry 'qlogenvelope' is generated after accepting or rejecting every recipients in the envelope phase.
+* Luca Franceschini's reject null senders patch
+  useful in special cases if you temporarily need to reject the null sender (although breaks RFC compatibility).
+  You just need to put 1 (actually any number different from 0) in your control/rejectnullsenders to reject the null sender with 421 error message.
+* dnscname patch
+  Removes CNAME check in order to avoid getting large amounts of data of no interest in and that may overflow the response buffer.
+  https://lists.gt.net/qmail/users/138190
+* Luca Franceschini's rcptcheck patch
+  (based on original patch from Jay Soffian (http://www.soffian.org/downloads/qmail/qmail-smtpd-doc.html)
+  Originally designed for the purpose of receipt validation, it can also be used to limit the numbr of email a given IP and/or auth-user and/or domain che send
+  in a given time interval. It has to be used in conjuction with the rcptcheck-overlimit.sh LF's script http://notes.sagredo.eu/files/qmail/rcptcheck-overlimit.sh
+  http://notes.sagredo.eu/files/qmail/patches/rcptcheck.patch
+
+= Disclaimer
+This patch comes with the usual warranty: it works for me, it may not work for you,
+use at your own risk etc. etc. :)
+Comments, suggestions, criticisms are always welcome!
+
+= Usage
+
+* Install libdomainkeys
+wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/tar/libdomainkeys-0.69.tar.gz
+tar xzf libdomainkeys-0.69.tar.gz
+wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/libdomainkeys-0.69.diff
+cd libdomainkeys-0.69
+chown -R root.root .
+patch < ../libdomainkeys-0.69.diff
+make
+cp libdomainkeys.a /usr/lib
+
+* Install libsrs2
+wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/tar/libsrs2-1.0.18.tar.gz
+tar xzf libsrs2-1.0.18.tar.gz
+cd libsrs2-1.0.18
+./configure
+make
+make install
+ldconfig
+cd ../
+
+* Apply the patch and compile
+wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/roberto-netqmail-1.06.patch-latest.gz
+wget http://qmail.org/netqmail-1.06.tar.gz
+tar xzf netqmail-1.06.tar.gz
+cd netqmail-1.06
+chown -R root.root .
+gunzip -c ../roberto-netqmail-1.06.patch-latest.gz | patch
+make
+make setup check
+
+* You have to export SMTPAUTH in your run file if you want to do the auth
+
+* You have to export SURBL=1 in your run file if you want to enable SURBL
+
+* /var/qmail/control/cache must be owned by the user who runs qmail-smtpd, vpopmail.vchkpwd in my case.
+  Change the permissions according to your qmail configuration.
+
+=================================================================================================================
+
+= Changelog
+
+2018.04.03
+-DKIM patch updated to v. 1.22
+ * openssl 1.1.0 port
+ * various improvements, bug fixes
+
+2018.01.10
+-maildir++
+ * fixed a bug where the filesize part of the S=<filesize> component of the Maildir++ compatible filename
+   is wrong (tx MG). More info here: http://notes.sagredo.eu/en/qmail-notes-185/installing-dovecot-and-sieve-on-a-vpopmail-qmail-server-28.html#comment995
+-qmail-queue-extra
+ * removed, because it was causing more problems than advantages, as the domain of the log@yourdomain.tld
+   had to match the system domain inside control/me and shouldn't be a virtual domain as well.
+
+2017.10.11 (tx Luca Franceschini)
+-qlogfix
+ * log strings should terminate with \n to avoid trailing ^M using splogger
+ * bug reporting custom errors from qmail-queue in qlog
+-added dnscname patch
+-added rcptcheck patch
+
+2017.08.18
+-qmail-smtpd now retains authentication upon rset
+ (tx to Andreas http://notes.sagredo.eu/qmail-notes-185/smtp-auth-qmail-tls-forcetls-patch-for-qmail-84.html#comment750)
+
+2017-05-14
+-DKIM patch updated to v. 1.20
+ It now manages long TXT records, avoiding the rejection of some hotmail.com messages.
+
+2016-12-19
+-Several new patches and improvements added (thanks to Luca Franceschini)
+More info here http://notes.sagredo.eu/node/178
+ -qregex patch
+ -brtlimit patch
+ -validrcptto patch
+ -rbl patch (updates qmail-dnsbl patch)
+ -reject-relay-test patch
+ -added DISABLETLS environment variable, useful if you want to disable TLS on a desired port
+ -added FORCEAUTHMAILFROM environment variable to REQUIRE that authenticated user and 'mail from' are identical
+ -fixed little bug in 'mail from' address handling (patch by Andre Opperman at http://qmail.cr.yp.narkive.com/kBry6GJl/bug-in-qmail-smtpd-c-addrparse-function)
+ -added SMTPAUTHMETHOD, SMTPAUTHUSER and SMTP_AUTH_USER env variables for external plugins
+ -qlog patch
+ -reject null senders patch
+ -bouncecontrolmime patch
+ -qmail-taps-extended (updates qmail-tap)
+
+2016-12-02
+-fixed BUG in qmail-remote.c: in case of remote server who doesn't allow EHLO the response for an alternative
+HELO was checked twice, making the connection to die. (Thanks to Luca Franceschini)
+Patch applied: http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/fix_sagredo_remotehelo.patch
+
+2016-09-19
+-qmail-tls patch updated to v. 20160918
+  * bug: qmail-remote accepting any dNSName, without checking that is matches (E. Surovegin)
+  * bug: documentation regarding RSA and DH keys (K. Peter, G. A. Bofill)
+
+2016-05-15
+-force-tls patch improved (a big thanks to Marcel Telka). Now qmail-smtpd avoids to write the auth verb if the
+ the STARTTLS command was not sent by the client
+
+2016-03-09
+-DKIM patch upgraded to v. 1.19
+ * verification will not fail when a dkim signature does not include the subject provided that the
+   UNSIGNED_SUBJECT environment variable is declared.
+
+2015-12-26
+-qmail-tls patch updated to v. 20151215
+ * typo in #if OPENSSL_VERSION_NUMBER for 2015-12-08 patch release (V. Smith)
+ * add ECDH to qmail-smtpd
+ * increase size of RSA and DH pregenerated keys to 2048 bits
+ * qmail-smtpd sets RELAYCLIENT if relaying allowed by cert
+ more info at http://inoa.net/qmail-tls/
+
+2015-12-15
+-DKIM patch by Manvendra Bhangui updated to v. 1.18
+
+2015-10-03
+-qmail-authentication: updated to v. 0.8.3
+
+2015-08-08
+-fixed a bug on qmail-remote.c that was causing the sending of an additionale ehlo greeting (thanks to Cristoph Grover)
+
+2015-04-11
+-qmail-authentication: updated to v. 0.8.2
+-qmail-tls: upgraded to v. 20141216 (POODLE vulnerability fixed)
+
+2015-03-28
+-added qmail-eMPF patch
+
+2014-11-19
+-security fix: the SSLv3 connection is now switched off
+
+2014-11-15
+-modified the QUEUE_EXTRA variable in extra.h to improve the qmail-send's log
+
+2014-04-14
+-added maxrcpt patch
+
+2014-03-10
+-added qmail-0.95-liberal-lf patch
+
+2013-12-30
+-added qmail-srs
+-the character "=" is now considered valid in the sender address by chkuser in order to accept SRS
+
+2013-12-18
+-added qmail-date-localtime patch
+
+2013-12-14
+-added qmail-hide-ip patch
+
+2013-12-10
+-the original greetdelay by e.h. has been replaced with the improved patch by John Simpson. Now
+communications trying to send commands before the greeting will be closed. Premature disconnections will be
+logged as well.
+-CHKUSER_SENDER_FORMAT enabled to reject fake senders without any domain declared (like <foo>)
+-chkuser logging: I slightly modified the log line adding the variables' name just to facilitate its interpretation
+-added qmail-moreipme patch
+
+2013-12-07
+-added qmail-dnsbl patch
+
+2013-12-05
+-added two patches to make qmail rfc2821 compliant
+
+2013-11-23
+-added any-to-cname patch
+
+2013-09-27
+-DKIM patch upgraded to v. 1.17. Defined -DHAVE_SHA_256 while compiling dkimverify.cpp in the Makefile.
+This solved an issue while verifying signatures using sha256.
+
+2013-09-16
+-Minor fixes to the DKIM patch.
+
+2013-09-13
+-DKIM patch upgraded to v. 1.16. The signing at qmail-remote level has been revised by its author.
+
+2013-08-25
+-qmail-qmqpc.c call to timeoutconn() needed a correction because the function signature was modified by the
+ outgoingip patch. Thanks to Robbie Walker (diff here http://notes.sagredo.eu/node/82#comment-373)
+
+2013-08-21
+-fixed a bug in hier.c which caused the installation not to build properly the queue/todo dir structure (thanks to
+ Scott Ramshaw)
+
+2013-08-18
+-DKIM-SURBL patch by Manvendra Bhangui updated to v. 1.14
+
+2013-08-12
+-DKIM patch upgraded to v. 1.12. The new patch adds surblfilter functionality.
+-added qmail-smtpd pid, qp log patch
+
+2013-08-08
+-qmail-SPF modified by Manvendra Bhangui to make it IPv6-mapped IPv4 addresses compliant. In order to have it
+working with such addresses you have to patch tcpserver.c accordingly. You can use a patch fot ucspi-tcp6-0.98
+by Manvendra Bhangui at http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/tcpserver-ipv6mapped_ipv4.patch
+or wait for v. 0.99 relase of ucspi-tcp6
+-added outgoingip patch
+-added qmail-bounce patch
+
+2013-03-31
+qmail-auth updated to latest v. 0.8.1 Added authentication by recipient domain for qmail-remote.
+Look at README.auth for further details
+
+2013-02-11
+some code adjustments in qmail-smtpd.c smtpd_ehlo() to restore total compatibility with esmtp-size patch
+
+2013-02-08
+qmail-auth updated to latest v. 0.7.6. Look at README.auth for further details
+
+2013-01-28
+fixed an issue on qmail-pop3d which was causing a double +OK after the pass command (thanks to Rakesh, Orbit
+and Simplex for helping in testing and troubleshooting)
+
+2013-01-06
+environment variable GREETDELAY renamed to SMTPD_GREETDELAY
+
+2012-10-31
+qmail-auth updated to latest v. 0.7.5. Look at README.auth for further details
+The qmail-forcetls patch was simplyfied accordingly.
+You MUST export SMTPAUTH="" in your run file now.
+
+2012-04-25
+-added qmail-remote CRLF (thanks to Pierre Lauriente for the help on testing and troubleshooting)
+The qmail-remote CRLF patch solved a problem of broken headers after sieve forwarding that was
+caused by a bad handling of the CR (carriage return) by qmail-remote.
+The issue is also reported here http://www.dt.e-technik.uni-dortmund.de/~ma/qmail-bugs.html
+
+2012.04.16
+-added qmail-tap
+
+2012.02.08
+-added smtp-size patch
+
+2012.01.29
+-added doublebounce-trim patch
+
+2011.12.12
+-file update_tmprsadh modified to chown the .pem files to vpopmail to avoid hang-ups during the smtp
+conversation on port 587 caused by permission problems.
+
+2011.10.06
+-qmail-remote.c: fixed. It was not going into tls on authentication (thanks to Krzysztof Gajdemski)
+-force-tls now quits if the starttls command is not provided when required (thanks to Jacekalex)
+
+=================================================================================================================
+
+diff -ruN ../netqmail-1.06-original/CHKUSER.automatic_patching netqmail-1.06/CHKUSER.automatic_patching
+--- ../netqmail-1.06-original/CHKUSER.automatic_patching	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.automatic_patching	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,94 @@
++Chkuser 2.0.9 automatic patching
++
++When to use automatic patching
++==============================
++
++The release.tar package contains some .patch files, ready for installation,
++trying to semplify the most frequent situations.
++
++You may use one of these patches if you have these sources:
++
++	- a clean qmail 1.03 or netqmail 1.05 
++
++You may also consider using one of these patches if you have additional compatible
++patches installed. This means that these additional patches should not have changed
++the same sources and lines which are going to be used by chkuser.
++
++If you have any doubt, backup your sources and try the automatic installation,
++otherwise execute the manual installation (that's very easy).
++
++Backup
++======
++
++Save you qmail working sources before making any change.
++
++Basic installation
++==================
++
++Download the newest release.tar package and untar it. It will create a directory
++containing all release chkuser files and patches.
++
++Chose the most appropriate .patch file to be applied, according to your qmail
++installation: .patch files names are self-describing.
++
++Position in the qmail/netqmail source directory:
++
++	$ cd /usr/.../netqmail-1.05
++
++Apply selected patch:
++
++	$ patch < /path_to_chkuser_release_dir/netqmail-1.05_chkuser-2.x.x.patch
++
++No errors should be displayed. If you see any error, better you restore your
++sources and go to manual editing.
++
++editing vpopmail home path
++
++	If your production home path for vpopmail (or whatever you call him) user
++	is NOT /home/vpopmail, you must perform the following additional actions.
++
++	Edit Makefile, changing the line referring to vpopmail's home path and
++	putting the right home path:
++
++		VPOPMAIL_HOME=/home/vpopmail 
++
++	Edit conf-cc, changing the string referring to vpopmail's home path and
++	putting the right home path:
++
++		cc -O2 -I/home/vpopmail/include 
++
++chkuser settings
++================
++
++Edit chkuser_settings.h, uncommenting the options you prefer, and commenting the
++ones you don't want. Default settings should cover the most of situations.
++
++See the related settings pages for more informations.
++
++Make
++====
++Now, make (or gmake on *BSD) as your usual. No errors (just warnings) should
++come out. If you see any error, better you restore your sources
++and go to manual editing.
++
++Checking
++========
++Select a domain, contained in your rcpthosts, for which bouncing is enabled, and run:
++
++	$ ./qmail-smtpd
++	mail from <wrong_sender>
++	mail from <right_sender>
++	rcpt to: <fake_user@your_domain>
++	rcpt to: <real_user@your_domain>
++
++You should see error and ok messages, depending on the addresses you typed.
++
++Install
++=======
++Copy the new executable in the /var/qmail/bin directory (or make install).
++
++Running
++=======
++This patched qmail-smtpd must be executed in a different way than the normal one.
++See the running pages for detailed instructions.
++
+diff -ruN ../netqmail-1.06-original/CHKUSER.changelog netqmail-1.06/CHKUSER.changelog
+--- ../netqmail-1.06-original/CHKUSER.changelog	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.changelog	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,183 @@
++
++CHKUSER 2.0 change log
++
++2.0.9 - 21 march 2007
++   New features
++        - New variable for accepting only authorized senders:
++                #define CHKUSER_EXTRA_MUSTAUTH_VARIABLE "CHKUSER_MUSTAUTH"
++                if the variable exists, then messages are accepted only if RELAYCLIENT is set
++                If defined, it works always despite CHKUSER being ON/OFF
++                This feature can be used for a "submission port" (see RFC 2476)
++        - Improved checking of MySQL server availability (if MySQL is used as vpopmail user's DB)
++        - Introduction of a new variable for disabling chkuser on the fly: CHKUSER_DISABLE_VARIABLE
++                (can be used for single IP or defined as "RELAYCLIENT" for all authorized e-mail clients)
++        - Improved starting variables checking sequence
++                CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE cannot be defined together
++                        and in such a case a fatal error is displayed; (in previous versions
++                        CHKUSER_ALWAYS_ON would automatically disable CHKUSER_STARTING_VARIABLE definition).
++                CHKUSER_DISABLE_VARIABLE is always evaluated after CHKUSER_ALWAYS_ON is set or
++                        CHKUSER_STARTING_VARIABLE is evaluated, so CHKUSER_ALWAYS_ON or
++                        CHKUSER_STARTING_VARIABLE can set the general behaviour, while
++                        CHKUSER_DISABLE_VARIABLE should be invoked to handle exceptions.
++        - New variable for accepting qmail doublebounces: CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE
++                Sender "#@[]" will be accepted. It is used by qmail for doublebounces, and should be enabled for
++                selected IP senders.
++	- define CHKUSER_ENABLE_VAUTH_OPEN has been substituted by CHKUSER_VAUTH_OPEN_CALL: this new 
++		define must contain the name of the call used to open the auth DB
++
++   Updated features
++        - checking for ezmlm mailing list is now done looking for file "editor"
++                within mailing-list directory
++        - defines for allowed character within sender and rcpt addresses increased
++                up to CHKUSER_ALLOW_SENDER_CHAR_10 and CHKUSER_ALLOW_RCPT_CHAR_10
++        - updated SMTP error strings; more exact and detailed error codes
++                (thanks to Olivier Dony and Dane Thorsen)
++        - logging of valid rcpt. If CHKUSER_LOG_VALID_RCPT is defined then all valid
++                recipients are logged, even if domain does not want bouncing or chkuser
++                is disabled
++
++   Bugs corrected
++        - negative checking of backend DB connection did not report
++                DB unavailability in some situations
++                (thanks to Matt Brookings of Inter7)
++        - in check_rcpt_address_format format checking was done using defines
++                reserved for senders
++
++V 2.0.8 - 7 december 2004
++   Features
++	Freeze of new features of 2.0.7, except null senders behaviour.
++	CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST is no more available
++	CHKUSER_ENABLE_NULL_SENDER is no more available
++	NULL SENDERS are now always accepted. No option is available to disable
++		this behaviour. Previous chkuser versions broke RFC compatibility on
++		null senders, and complicated real life e-mailing.
++	Logging of null senders <> is now available.
++	
++   Bugs corrected
++	Sender controls were not executed if CHKUSER_STARTING_VARIABLE was defined
++		(thanks to Charles Sprickman)
++	Domains not in control/virtualdomains are now explicitely excluded from
++		following cascade checks; in previous versions following cascade
++		checks were done using fake domains paths.
++	vget_assign is now handled correctly (a domain in rcpthosts but not
++		in virtualdomains could have an incorrect path in previous versions
++		(this bug is also in all chkusr versions)
++
++	Defaults changed
++	CHKUSER_RCPT_FORMAT is now undefined as default
++	CHKUSER_RCPT_MX is now undefined as default.
++	CHKUSER_SENDER_FORMAT is now undefined as default
++	CHKUSER_SENDER_MX is now undefined as default.
++	CHKUSER_ERROR_DELAY_INCREASE new default is 300 milliseconds
++	
++V 2.0.7 - 25 october 2004
++   Features
++	added vclose() of DB auth connection, overriding
++		qmail-smtpd _exit call
++	improved MX checking; now SOFT failure is handled as
++		temporary error.
++	added #define CHKUSER_RCPTMX_TMP_STRING
++	added #define CHKUSER_SENDERMX_TMP_STRING 
++	added handling of mailman mailing lists
++		(and related #define CHKUSER_ENABLE_MAILMAN_LISTS)
++	changed order of checking for recipients:
++		1 - valias
++		2 - alias
++		3 - alias extensions
++		4 - users
++		5 - users extensions
++		6 - lists
++	added #define CHKUSER_ACCEPT_NULL_SENDER (default defined)
++	added #define CHKUSER_ENABLE_ALIAS_DEFAULT (default not defined)
++		enables checking of .qmail-alias-default
++	added #define CHKUSER_IDENTIFY_REMOTE_VARIABLE "CHKUSER_IDENTIFY"
++		in order to allow a easy identification of remote IP
++		(substitutes RELAYCLIENT in chkuser logging)
++	added #define CHKUSER_ALLOW_RCPT_SRS
++		enable usage of "#" and "+" characters within rcpt address
++	added #define CHKUSER_ALLOW_RCPT_CHAR_1 '$'
++	added #define CHKUSER_ALLOW_RCPT_CHAR_2 '%'
++	added #define CHKUSER_ALLOW_RCPT_CHAR_3 '£'
++	added #define CHKUSER_ALLOW_RCPT_CHAR_4 '?'
++	added #define CHKUSER_ALLOW_RCPT_CHAR_5 '*'
++	#define CHKUSER_ENABLE_USERS_EXTENSIONS
++		substitutes #define CHKUSER_ENABLE_EXTENSIONS
++	#define CHKUSER_ENABLE_EZMLM_LISTS
++		substitutes #define CHKUSER_ENABLE_LISTS
++	#define CHKUSER_USERS_DASH
++		substitutes #define CHKUSER_EXTENSION_DASH
++
++   Bugs corrected
++	sender address "name@" could cause a crash. Corrected
++		(Thanks to Dmitry Petukhov)
++	Corrected Makefile: now qmail-smtpd.c recompiles if chkuser.h
++		changes
++	Corrected a bug in #endif sequence related to
++		#define CHKUSER_RCPT_FORMAT (thanks to Alex Plainer)
++	Corrected a bug in chkuser_sender; now is not executed when
++		chkuser is disabled
++	Corrected check of format for domains:
++		"xn--" admitted as leading string
++	Deleted correction over usage of RELAYCLIENT variable
++		Previous correction could affect a special
++		feature of RELAYCLIENT (thanks to Alex Pleiner)
++
++   Defaults changed
++	#define CHKUSER_ENABLE_NULL_SENDER_WITH_TCPREMOTEHOST (default undefined)
++
++
++V 2.0.6 - 25 september 2004
++	No bugs, just doc updates and an empty patch file corrected
++
++	#define CHKUSER_ENABLE_VGET_REAL_DOMAIN was existing and working in code,
++		but not reported both in docs and inside chkuser_settings.h
++			(default is commented, but this #define is important)	
++	patch for toaster-0.6-1 was empty. Now the correct one is provided
++
++V 2.0.5 - 23 september 2004
++	This is the first public release.
++
++	added #define CHKUSER_ALLOW_SENDER_CHAR_1 (default not defined) 
++	added #define CHKUSER_ALLOW_SENDER_CHAR_2 (default not defined) 
++	added #define CHKUSER_ALLOW_SENDER_CHAR_3 (default not defined) 
++	added #define CHKUSER_ALLOW_SENDER_CHAR_4 (default not defined) 
++	added #define CHKUSER_ALLOW_SENDER_CHAR_5 (default not defined) 
++	added #define CHKUSER_MIN_DOMAIN_LEN (default defined 4) -
++		Previously it was hard coded as 5. Juergen Kendzorra
++		showed me some existing names long only 4 chars. 
++	added #define CHKUSER_LOG_VALID_SENDER (default defined)
++
++V 2.0.4 - 15 september 2004
++
++	added #define CHKUSER_SENDER_NOCHECK_VARIABLE (default not defined) 
++	added #define CHKUSER_DEBUG_STDERR (default not defined) 
++	added #define CHKUSER_ALLOW_SENDER_SRS (default not defined) 
++	cleaned some typos in code and documentation (thanks to Juergen
++		Kendzorra - http://www.kendzorra.de) 
++
++
++V 2.0.3 - 8 september 2004
++	This is the first version released outside, for wider testing.
++
++	Tested Makefile for netqmail 1.05 
++	Added Makefiles for applying over other patches 
++
++V 2.0.0 - july 2004
++	chkuser 2.0.0 starts here, and is a private internal release.
++	Version 2.0 is much more modular than previous one (named chkusr),
++	and has been designed with the goal of enabling more features and
++	semplifying installations and upgrades of the patch himself. 
++
++	chkusr changes his name, to reflect a deep change of the patch. 
++
++	Chkusr 1.0 received a lot of feedbacks and suggestions.
++	The most of these suggestions are now inside version 2.0.
++
++		- Marcelo Coelho (marcelo at tpn.com.br), segnaled me some
++		unseen minor bugs of chkusr 1.0 (minor but very annoying to
++		my pride) and suggested some very interesting features
++		(some of them are now in chkuser 2.0). 
++		- Iulian Margarintescu (http:://www.erata.net) suggested a
++		workable way of introducing quota check on recipients
++		(now in chkuser 2.0). 
++
+diff -ruN ../netqmail-1.06-original/CHKUSER.copyright netqmail-1.06/CHKUSER.copyright
+--- ../netqmail-1.06-original/CHKUSER.copyright	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.copyright	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,15 @@
++
++chkuser 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
++
+diff -ruN ../netqmail-1.06-original/CHKUSER.log_format netqmail-1.06/CHKUSER.log_format
+--- ../netqmail-1.06-original/CHKUSER.log_format	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.log_format	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,69 @@
++
++chkuser 2.0.9 logging format
++
++When #defines for logging are enabled, chkuser patch emits log informations
++on the same qmail-smtpd log destination
++
++This is the log format:
++
++    CHKUSER "brief message": \
++	    from <sender:remoteinfo:relayclient> \
++	    remote <helo:remotehostname:remotehostip> \
++	    rcpt <recipient> : "extended message"
++
++where
++	brief message 	
++		    * accepted rcpt
++		    * relaying rcpt
++		    * rejected relaying
++		    * rejected rcpt
++		    * no auth resource
++		    * mbx overquota
++		    * rejected intrusion
++		    * intrusion threshold
++		    * accepted sender
++		    * rejected sender
++		    * must auth
++
++	sender 	sender declared within "mail from"
++
++	remoteinfo	the value of "TCPREMOTEINFO" or the autenticated user
++
++	relayclient 	the value of CHKUSER_IDENTIFY env variable (this name
++			 is defined by #define CHKUSER_IDENTIFY_REMOTE_VARIABLE)
++
++	helo 		helo declared from remote system
++
++	hostname 	the value of "TCPREMOTEHOST"
++
++	remotehostip 	the value of "TCPREMOTEIP"
++
++	recipient 	recipient address
++
++	extended message 	this field has more wide description for
++				some generic "brief message":
++			accepted rcpt 	found existing recipient
++			accepted rcpt	accepted any recipient for any rcpt doman (from 2.0.9)
++			accepted rcpt	accepted any recipient for this domain (from 2.0.9)
++			relaying rcpt 	client allowed to relay
++			rejected relaying 	client not allowed to relay
++			rejected rcpt 	not existing recipient
++			rejected rcpt 	max number of recipients
++			rejected rcpt 	max number of invalid recipients
++			rejected rcpt 	invalid rcpt address format
++			rejected rcpt 	invalid rcpt MX domain
++			rejected rcpt	temporary DNS problem (from 2.0.9) 
++			intrusion threshold 	max number of allowed rcpt
++			intrusion threshold 	max number of allowed invalid rcpt
++			rejected intrusion 	rcpt ignored, session over intrusion threshold
++			no auth resource 	no auth resource available
++			must auth	sender not authenticated/authorized (from 2.0.9)
++			mbx overquota 	rcpt mailbox is overquota
++			accepted sender	sender accepted (from 2.0.9)
++			accepted sender accepted any sender always (from 2.0.9)
++			accepted sender accepted null sender always (from 2.0.9)
++			accepted doublebounce	accepted qmail doublebounce #@[] (from 2.0.9)
++			rejected sender 	invalid sender address format
++			rejected sender 	invalid sender MX domain
++			rejected sender		temporary DNS problem (from 2.0.9)
++	
+diff -ruN ../netqmail-1.06-original/CHKUSER.manual_patching netqmail-1.06/CHKUSER.manual_patching
+--- ../netqmail-1.06-original/CHKUSER.manual_patching	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.manual_patching	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,182 @@
++Chkuser 2.0 manual editing
++
++Manual editing is a very simple operation.
++
++Watching the patch design, shown in the patch design page, you may see that
++only some simple changes must be done to qmail-smtpd.c and Makefile.
++
++Backup
++======
++
++Save you qmail working sources before making any change.
++
++Basic installation
++==================
++
++Download the newest release.tar package and untar it. It will create a directory
++containing all chkuser files and patches.
++
++Position in the qmail/netqmail source directory:
++
++	$ cd /usr/.../netqmail-1.05
++
++Copy all the chkuser sources:
++
++	$ cp /path_to_release_tar/chkuser* .
++
++edit qmail-smtpd.c
++	within qmail-smtpd.c, change the following lines:
++
++	At the end of initial #include declarations, add the following (+) lines:
++
++	#include "timeoutwrite.h"
++	#include "commands.h"
++	
+++	/* start chkuser code */ 
+++	#include "chkuser.h"
+++	/* end chkuser code */
++
++	#define MAXHOPS 100 
++
++Within smtp_mail routine, add the following (+) lines
++
++	void smtp_mail(arg) char *arg;
++	{
++	if (!addrparse(arg)) { err_syntax(); return; }
+++	/* start chkuser code */
+++	if (chkuser_sender (&addr) != CHKUSER_OK) { return; }
+++	/* end chkuser code */
++	flagbarf = bmfcheck();
++
++	Within smtp_rcpt routine, delete the following (-) lines and substitute
++	them with the (+) ones:
++
++-	  if (relayclient) {
++-	    --addr.len;
++-	    if (!stralloc_cats(&addr,relayclient)) die_nomem();
++-	  }
++-	  else
++-	    if (!addrallowed()) { err_nogateway(); return; }
++
+++	/* start chkuser code */
+++	  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;
+++	}
+++	/* end chkuser code */
++
++	if (!stralloc_cats(&rcptto,"T")) die_nomem();
++	if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
++	if (!stralloc_0(&rcptto)) die_nomem();
++
++edit Makefile
++	Within Makefile, change or add the following lines.
++
++	At the begininng of the file:
++
++	# Don't edit Makefile! Use conf-* for configuration.
++
+++	VPOPMAIL_HOME=/home/vpopmail
+++	SMTPD_CHKUSER_OBJ=chkuser.o dns.o
+++	VPOPMAIL_LIBS=`head -1 $(VPOPMAIL_HOME)/etc/lib_deps` `cat dns.lib`
++
++	SHELL=/bin/sh
++
++	Be carefule to use the right path, if your vpopmail production home
++	path is NOT "/home/vpopmail".
++
++	dns.lib is added to qmail-smtpd building instructions, so, if you
++	have previously patched qmail-smtpd in order to include dns.lib, take
++	care to delete the duplication from the previous lines.
++
++	Before "clean:" insert the chkuser.o definition:
++
++	exit.h auto_spawn.h
++      		./compile chkspawn.c
+++       chkuser.o: \
+++       compile chkuser.c chkuser.h chkuser_settings.h
+++       	./compile chkuser.c
++
++	clean: \
++
++	Beware: the "./compile chkuser.c" line has an heading TAB.
++
++	Change the qmail-smtpd compiling and linking instructions,
++	deleting the (-) lines and adding the (+) ones.
++
++
++	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
+++	fs.a auto_qmail.o socket.lib $(SMTPD_CHKUSER_OBJ)
++-	      ./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
+++	      ./load qmail-smtpd $(SMTPD_CHKUSER_OBJ) 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 `cat \
++-	      socket.lib`
+++	      alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
+++	      $(VPOPMAIL_LIBS) \
+++	      `cat socket.lib`
++
++	Beware: all the lines starting from and following "./load" have an heading TAB.
++
++edit TARGETS
++	Append the following blue line at the end of TARGETS file:
++
++	man
++	setup
++	check
+++	chkuser.o
++
++edit conf-cc
++	Edit conf-cc, adding the include path of production vpopmail:
++
++	cc -O2 -I/home/vpopmail/include 
++
++	Be carefule to use the right path, if your vpopmail production home path
++	is NOT "/home/vpopmail".
++
++chkuser settings
++================
++Edit chkuser_settings.h, uncommenting the options you prefer, and commenting the
++ones you don't want. Default settings should cover the most of situations.
++
++See the related settings pages for more informations.
++
++Make
++====
++Now, make (or gmake on *BSD) as your usual. No errors (just warnings)
++should come out. If you see any error, check carefully edited lines.
++
++Checking
++========
++Select a domain, contained in your rcpthosts, for which bouncing is enabled, and run:
++
++	$ ./qmail-smtpd
++	mail from <wrong_sender>
++	mail from <right_sender>
++	rcpt to: <fake_user@your_domain>
++	rcpt to: <real_user@your_domain>
++
++You should see error and ok messages, depending on the addresses you typed.
++
++Install
++=======
++Copy the new executable in the /var/qmail/bin directory (or make install).
++
++Running
++=======
++This patched qmail-smtpd must be executed in a different way than the normal one.
++See the running pages for detailed instructions.
++
+diff -ruN ../netqmail-1.06-original/CHKUSER.readme netqmail-1.06/CHKUSER.readme
+--- ../netqmail-1.06-original/CHKUSER.readme	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.readme	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,54 @@
++chkuser 2.0 - README
++
++Description
++===========
++The original qmail-smtpd accepts by default all messages, checking later for
++the existence of the recipient. So, if the message is delivered to not existing
++recipients a lot of additional system work and network traffic are generated,
++with multiple expensive bouncing if the sender is a fake one.
++
++chkuser has been developed with the goal to improve the acceptance SMTP phase
++of qmail-smtpd. qmail-smtpd patched with chkuser may check the existance of
++e-mail recipients immediately in the SMTP acceptance phase of a message and
++rejects istantly all messages not directed to existing users, avoiding
++additional traffic, work and messages bounced more times.
++
++These goals are achieved enquirying the existing vpopmail archives (each
++format is supported: cdb, MySQL, LDAP, etc.) by using standard vpopmail calls,
++or using customized chkuser routines.
++
++Version 2.0 - From chkusr to chkuser
++====================================
++Version 2.0 is a lot different from previous versions, so it deserves a more
++evident change in the name.
++
++Version 2.0 has been designed with the goal to be modular, and to make more easy
++both adding new features to chkuser code and semplifing code update.
++
++Patching over original qmail files is done over a few points, while the most of
++chkuser code remains ouside, in dedicated chkuser's files.
++
++Same for settings, that are inside a dedicated chkuser_settings.h file.
++
++The intention is to semplify upgrading: for future chkuser releases, upgrading
++will require only to update chkuser specific files, leaving all the rest
++untouched, and changing chkuser_settings.h only if new features must be enabled.
++
++Logging and SPAM
++================
++chkuser 2.0 has detailed logging of accepted and refused recipients and senders,
++allowing a deep analysis of "who's sending to who". This can lead to more
++sophisticated future enhancements of anti-SPAM features.
++
++Intrusion rejection
++===================
++chkuser 2.0 can be tuned to reject sessions exceeding some recipients limits
++(limits can be set for max recipients and max not existing recipients). 
++
++URL Location
++============
++For any new release, support, FAQ, mailing lists, or other information, see:
++
++	http://www.interazioni.it/opensource
++
++
+diff -ruN ../netqmail-1.06-original/CHKUSER.running netqmail-1.06/CHKUSER.running
+--- ../netqmail-1.06-original/CHKUSER.running	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/CHKUSER.running	2016-11-22 21:04:38.804137924 +0100
+@@ -0,0 +1,103 @@
++
++CHKUSER 2.0.9 - Running instructions
++
++Chkuser may run using the most of security, following very strictly the sacurity
++model used By Dan Berstein. To achieve this goal, chkuser may switch between
++differents UID/GID, for differente purposes.
++
++However this is incompatible with TLS patches (like toaster-0.6-1), as these patches
++want to run under a unique UID/GID. Luckily, qmail is enought robust to let us
++run this way.
++
++To achieve both these goals, chkuser uses a #define (CHKUSER_ENABLE_UIDGID)
++that indicates if UID/GID switching is wanted, and running instructions must
++adapt to this way.
++
++Instead, when this define is not used, another way of running must be used.
++(Just for precision, even if the CHKUSER_ENABLE_UIDGID define is used, chkuser
++may be run without switching UID/GID).
++
++Running with UID/GID switch
++===========================
++
++If you want the most security when using chkuser, and you have enabled 
++CHKUSER_ENABLE_UIDGID within chkuser_settings.h (it's enabled by default), use
++these instructions.
++
++Description.
++	qmail-smtpd-chkusr must be installed (by default in /var/qmail/bin) with
++	setuid (user qmaild) and setgid (group qnofiles), and executed by tcpserver 
++	with -u vpopmail-user and -g vchkpw-group  parameters.
++
++	qmail-smtpd-chkusr starts running with the original qmail-smtpd uid and gid,
++	switching to needed uid and gid only for vpopmail checks on user existance,
++	turning back to the starting uid and gid.
++
++Instructions.
++	You have to set SUID (set-user-ID-on-execution) and SGID
++	(set-group-ID-on-execution) bits on qmail-smtpd-chkusr:
++		chown qmaild qmail-smtpd
++		chgrp nofiles qmail-smtpd
++		chmod 6555 qmail-smtpd
++
++	and the result you see should be like (different size and date, of course):
++		-r-sr-sr-x 1 qmaild nofiles 57056 Feb 14 18:18 qmail-smtpd-chkusr
++
++	Integrate qmail-smtpd in your start files:
++
++	As example, a real start command for qmail-smtpd-chkusr may be
++
++	#!/bin/sh -e
++	#
++	# Using splogger to send the log through syslog.
++
++	exec env - PATH="/var/qmail/bin:/usr/local/bin" \
++	tcpserver -t 5 -v -p -x <your.tcp.smtp.cdb> \
++	-u <vpopmail-user> -g <vchkpw-group> -l <your-host.domain> 0 smtp \
++	qmail-smtpd-chkusr splogger smtpd &
++
++	where
++		<vpopmail-user> = vpopmail uid
++		<vchkpw-group> = vchkpw gid
++		<your-host.domain> = your host.domain (!)
++		<your.tcp.smtp.cdb> = your tcp.permission.to.relay cdb
++
++	NOTE: if you are using more system users for your domains, the execution
++	uid (which I indicated as vpopmail) should be set to root.
++
++
++Running with fixed UID/GID
++==========================
++You may use these instructions if you've not defined CHKUSER_ENABLE_UIDGID, or if
++you want to run qmail-smtpd as unique user, despite of CHKUSER_ENABLE_UIDGID define.
++qmail-smtpd is well safe and robust, and there is no risk running it directly as
++vpopmail user, unless you use untrusted software layered down.
++
++Description.
++	qmail-smtpd must be installed normally (-r-xr-xr-x) and executed by tcpserver
++	with -u vpopmail-user and -g vchkpw-group parameters.
++
++Instructions.
++	Integrate qmail-smtpd-chkusr in your start files:
++
++	As example, a real start command for qmail-smtpd-chkusr may be
++
++	#!/bin/sh -e
++	#
++	# Using splogger to send the log through syslog.
++
++	exec env - PATH="/var/qmail/bin:/usr/local/bin" \
++	tcpserver -t 5 -v -p -x <your.tcp.smtp.cdb> \
++	-u <vpopmail-user> -g <vchkpw-group> -l <your-host.domain> 0 smtp \
++	qmail-smtpd-chkusr splogger smtpd &
++
++	where
++		<vpopmail-user> = vpopmail uid
++		<vchkpw-group> = vchkpw gid
++		<your-host.domain> = your host.domain (!)
++		<your.tcp.smtp.cdb> = your tcp.permission.to.relay cdb
++
++	NOTE: if you are using more system users for your domains, the execution user
++	(which I indicated as vpopmail) should be set to root.
++
++
+diff -ruN ../netqmail-1.06-original/FILES netqmail-1.06/FILES
+--- ../netqmail-1.06-original/FILES	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/FILES	2016-11-22 21:03:57.061529799 +0100
+@@ -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,4 @@
+ tcp-environ.5
+ constmap.h
+ constmap.c
++qmail-todo.c
+diff -ruN ../netqmail-1.06-original/LICENSE.authentication netqmail-1.06/LICENSE.authentication
+--- ../netqmail-1.06-original/LICENSE.authentication	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/LICENSE.authentication	2016-11-22 21:03:57.102528432 +0100
+@@ -0,0 +1,43 @@
++AUTHOR
++======
++
++Author:
++	Dr. Erwin Hoffmann - FEHCom Germany
++Web-Site: 	
++	http://www.fehcom.de/qmail.html
++E-Mail: 	
++	feh@fehcom.de
++
++
++LICENSE
++=======
++
++qmail AUTHENTICATION is free software.
++This includes:
++	You can download and use qmail AUTHENTICATION (and parts of it) as you like.
++	You can modify the source code without notification to or permission by the author.
++Please check:
++	http://www.cr.yp.to/softwarelaw.html
++
++
++DEPENDENCIES
++============
++
++qmail AUTHENTICATION patches (modifies) parts of the qmail-1.03 source files.
++It should only be applied against the source as supplied by D.J. Bernstein.
++
++
++FITNESS
++=======
++
++The Author does not guarantee a specific fitness of qmail AUTHENTICATION.
++If you use qmail AUTHENTICATION, it's on your own risk.
++
++
++DISTRIBUTION
++============
++
++qmail AUTHENTICATION may be included in ports and packages under the following conditions:
++	The port/package has to show the current version number of qmail AUTHENTICATION.
++	All files (namely this) have to be included.
++
+diff -ruN ../netqmail-1.06-original/MakeArgs.c netqmail-1.06/MakeArgs.c
+--- ../netqmail-1.06-original/MakeArgs.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/MakeArgs.c	2016-11-22 21:03:57.102528432 +0100
+@@ -0,0 +1,144 @@
++/*
++ * $Log: MakeArgs.c,v $
++ * Revision 2.8  2007-12-21 14:35:42+05:30  Cprogrammer
++ * included env.h to prevent compiler warning
++ *
++ * Revision 2.7  2007-12-20 12:45:28+05:30  Cprogrammer
++ * expand environment variables with '$' sign
++ *
++ * Revision 2.6  2005-08-23 17:31:28+05:30  Cprogrammer
++ * removed sccsid variable
++ *
++ * Revision 2.5  2005-04-02 19:06:02+05:30  Cprogrammer
++ * djb version
++ *
++ * Revision 2.4  2005-03-30 22:52:47+05:30  Cprogrammer
++ * BUG - Incorrect free
++ *
++ * Revision 2.3  2004-07-12 22:47:58+05:30  Cprogrammer
++ * bug fix. Free all allocated members
++ *
++ * Revision 2.2  2002-12-21 18:21:09+05:30  Cprogrammer
++ * added functionality of escaping text via quotes
++ *
++ * Revision 2.1  2002-08-13 20:35:44+05:30  Cprogrammer
++ * addition spaces were not getting skipped
++ *
++ * Revision 1.2  2002-03-03 17:23:05+05:30  Cprogrammer
++ * replaced strcpy with scopy
++ *
++ * Revision 1.1  2001-12-13 01:46:09+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include "alloc.h"
++#include "str.h"
++#include "stralloc.h"
++#include "env.h"
++#include <ctype.h>
++
++#define isEscape(ch) ((ch) == '"' || (ch) == '\'')
++
++/*
++ * function to expand a string into command line
++ * arguments. To free memory allocated by this
++ * function the following should be done
++ *
++ * free(argv);
++ *
++ */
++char          **
++MakeArgs(char *cmmd)
++{
++	char           *ptr, *marker;
++	char          **argv;
++	int             argc, idx;
++	static stralloc sptr = { 0 };
++
++	for (ptr = cmmd;*ptr && isspace((int) *ptr);ptr++);
++	idx = str_len(ptr);
++	if (!stralloc_copys(&sptr, ptr))
++		return((char **) 0);
++	if (!stralloc_0(&sptr))
++		return((char **) 0);
++	/*-
++	 * Get the number of arguments by counting
++	 * white spaces. Allow escape via the double
++	 * quotes character at the first word
++	 */
++	for (argc = 0, ptr = sptr.s;*ptr;)
++	{
++		for (;*ptr && isspace((int) *ptr);ptr++);
++		if (!*ptr)
++			break;
++		argc++;
++		marker = ptr;
++		/*- Move till you hit the next white space */
++		for (;*ptr && !isspace((int) *ptr);ptr++)
++		{
++			/*-
++			 * 1. If escape char is encounted skip till you
++			 *    hit the terminating escape char
++			 * 2. If terminating escape char is missing, come
++			 *    back to the start escape char
++			 */
++			if (ptr == marker && isEscape(*ptr))
++			{
++				for (ptr++;*ptr && !isEscape(*ptr);ptr++);
++				if (!*ptr)
++					ptr = marker;
++			}
++		} /*- for(;*ptr && !isspace((int) *ptr);ptr++) */
++	} /*- for (argc = 0, ptr = sptr.s;*ptr;) */
++	/*
++	 * Allocate memory to store the arguments
++	 * Do not bother extra bytes occupied by
++	 * white space characters.
++	 */
++	if (!(argv = (char **) alloc((argc + 1) * sizeof(char *))))
++		return ((char **) 0);
++	for (idx = 0, ptr = sptr.s;*ptr;)
++	{
++		for (;*ptr && isspace((int) *ptr);ptr++)
++			*ptr = 0;
++		if (!*ptr)
++			break;
++		if (*ptr == '$')
++			argv[idx++] = env_get(ptr + 1);
++		else
++			argv[idx++] = ptr;
++		marker = ptr;
++		for (;*ptr && !isspace((int) *ptr);ptr++)
++		{
++			if (ptr == marker && isEscape(*ptr))
++			{
++				for (ptr++;*ptr && !isEscape(*ptr);ptr++);
++				if (!*ptr)
++					ptr = marker;
++				else /*- Remove the quotes */
++				{
++					argv[idx - 1] += 1;
++					*ptr = 0;
++				}
++			}
++		}
++	} /*- for (idx = 0, ptr = sptr.s;*ptr;) */
++	argv[idx++] = (char *) 0;
++	return (argv);
++}
++
++void
++FreeMakeArgs(char **argv)
++{
++	alloc_free(argv);
++	return;
++}
++
++void
++getversion_MakeArgs__c()
++{
++	static char     *x = "$Id: MakeArgs.c,v 2.8 2007-12-21 14:35:42+05:30 Cprogrammer Stab mbhangui $";
++	x++;
++	x--;
++	return;
++}
+diff -ruN ../netqmail-1.06-original/Makefile netqmail-1.06/Makefile
+--- ../netqmail-1.06-original/Makefile	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/Makefile	2018-04-03 15:05:13.390470191 +0200
+@@ -1,5 +1,14 @@
+ # Don't edit Makefile! Use conf-* for configuration.
+ 
++VPOPMAIL_HOME=/home/vpopmail
++VPOPMAIL_LIBS=`head -1 $(VPOPMAIL_HOME)/etc/lib_deps` `cat dns.lib`
++
++SMTPD_CHKUSER_OBJ=chkuser.o dns.o
++
++LIBDOMAINKEYS=/usr/lib
++
++DEFINES=-DEXTERNAL_TODO # use to enable external todo
++
+ SHELL=/bin/sh
+ 
+ default: it
+@@ -136,6 +145,18 @@
+ compile auto_usera.c
+ 	./compile auto_usera.c
+ 
++base64.o: \
++compile base64.c base64.h stralloc.h substdio.h str.h
++	./compile base64.c
++
++md5c.o : \
++compile md5c.c md5.h
++	./compile md5c.c
++
++hmac_md5.o : \
++compile hmac_md5.c hmac_md5.h global.h
++	./compile hmac_md5.c
++
+ binm1: \
+ binm1.sh conf-qmail
+ 	cat binm1.sh \
+@@ -203,6 +224,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 +236,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 +329,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`
+@@ -320,10 +353,13 @@
+ 	chmod 755 compile
+ 
+ condredirect: \
+-load condredirect.o qmail.o strerr.a fd.a sig.a wait.a seek.a env.a \
+-substdio.a error.a str.a fs.a auto_qmail.o
+-	./load condredirect qmail.o strerr.a fd.a sig.a wait.a \
+-	seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o 
++load condredirect.o srs.o rcpthosts.o cdb.a control.o constmap.o case.a \
++	getln.a stralloc.a alloc.a open.a qmail.o strerr.a fd.a sig.a \
++	wait.a seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o
++	./load condredirect srs.o rcpthosts.o cdb.a control.o constmap.o \
++	case.a getln.a stralloc.a alloc.a open.a qmail.o strerr.a fd.a sig.a \
++	wait.a seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
+ 
+ condredirect.0: \
+ condredirect.1
+@@ -331,7 +367,7 @@
+ 
+ condredirect.o: \
+ compile condredirect.c sig.h readwrite.h exit.h env.h error.h fork.h \
+-wait.h seek.h qmail.h substdio.h strerr.h substdio.h fmt.h
++wait.h seek.h qmail.h substdio.h strerr.h substdio.h fmt.h stralloc.h srs.h
+ 	./compile condredirect.c
+ 
+ config: \
+@@ -393,84 +429,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
+@@ -593,10 +641,13 @@
+ 	rm -f tryvfork.o tryvfork
+ 
+ forward: \
+-load forward.o qmail.o strerr.a alloc.a fd.a wait.a sig.a env.a \
+-substdio.a error.a str.a fs.a auto_qmail.o
+-	./load forward qmail.o strerr.a alloc.a fd.a wait.a sig.a \
+-	env.a substdio.a error.a str.a fs.a auto_qmail.o 
++load forward.o srs.o qmail.o strerr.a control.o rcpthosts.o constmap.o \
++	cdb.a case.a open.a stralloc.a alloc.a getln.a \
++	fd.a wait.a sig.a env.a substdio.a error.a str.a fs.a auto_qmail.o
++	./load forward srs.o qmail.o strerr.a control.o rcpthosts.o constmap.o \
++	cdb.a case.a open.a stralloc.a alloc.a getln.a \
++	fd.a wait.a sig.a env.a substdio.a error.a str.a fs.a auto_qmail.o \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
+ 
+ forward.0: \
+ forward.1
+@@ -604,7 +655,7 @@
+ 
+ forward.o: \
+ compile forward.c sig.h readwrite.h exit.h env.h qmail.h substdio.h \
+-strerr.h substdio.h fmt.h
++strerr.h substdio.h fmt.h stralloc.h srs.h
+ 	./compile forward.c
+ 
+ fs.a: \
+@@ -703,7 +754,7 @@
+ 
+ hier.o: \
+ compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h
+-	./compile hier.c
++	./compile $(DEFINES) hier.c
+ 
+ home: \
+ home.sh conf-qmail
+@@ -755,7 +806,7 @@
+ install-big.o: \
+ compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \
+ fifo.h
+-	./compile install-big.c
++	./compile $(DEFINES) install-big.c
+ 
+ install.o: \
+ compile install.c substdio.h strerr.h error.h open.h readwrite.h \
+@@ -777,38 +828,52 @@
+ 	./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 readwrite.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 auto_qmail.o open.a getln.a \
++strsalloc.o stralloc.a alloc.a substdio.a error.a str.a fs.a socket.lib
++	./load ipmeprint ipme.o ip.o ipalloc.o auto_qmail.o open.a getln.a \
++	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 auto_qmail.h
+ 	./compile ipmeprint.c
+ 
++ipmetest: \
++load ipmetest.o ipme.o ip.o ipalloc.o auto_qmail.o open.a getln.a stralloc.a alloc.a substdio.a \
++error.a str.a fs.a env.a socket.lib
++	./load ipmetest ipme.o ip.o ipalloc.o auto_qmail.o open.a getln.a stralloc.a alloc.a \
++	substdio.a error.a env.a str.a fs.a `cat socket.lib`
++
++ipmetest.o: \
++compile ipmetest.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \
++ipalloc.h ip.h gen_alloc.h exit.h auto_qmail.h
++	./compile ipmetest.c
++
+ it: \
+ qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \
++qmail-newmvrt \
+ qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \
+ predate datemail mailsubj qmail-upq qmail-showctl 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 ipmetest qreceipt qreceipt qsmhook qbiff \
+ forward preline condredirect bouncesaying except maildirmake \
+ maildir2mbox maildirwatch qail elq pinq idedit install-big install \
++dktest qmail-dk qmail-dkim dkim spawn-filter dk-filter surblfilter \
+ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
+-binm3 binm3+df
++binm3 binm3+df srsfilter surblqueue dknewkey qmail-todo spfquery update_tmprsadh
+ 
+ load: \
+ make-load warn-auto.sh systype
+@@ -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 \
+@@ -934,8 +1031,9 @@
+ preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \
+ 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
++qmail-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 dkim.8 dktest.8 \
++envelopes.0 forgeries.0 qmail-dk.0 qmail-dkim.0 dk-filter.0 spawn-filter.0 \
++surblfilter.0
+ 
+ mbox.0: \
+ mbox.5
+@@ -1107,11 +1205,80 @@
+ 	| sed s}SPAWN}"`head -1 conf-spawn`"}g \
+ 	> qmail-control.5
+ 
++qmail-dk: \
++load qmail-dk.o triggerpull.o fmtqfn.o now.o date822fmt.o mess822_ok.o \
++subgetopt.o MakeArgs.o datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
++str.a case.a fs.a auto_qmail.o auto_split.o auto_uids.o fd.a wait.a \
++$(LIBDOMAINKEYS)/libdomainkeys.a env.a getln.a control.o stralloc.a dns.lib
++	./load qmail-dk triggerpull.o fmtqfn.o now.o mess822_ok.o \
++	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
++	subgetopt.o MakeArgs.o substdio.a error.a fs.a auto_qmail.o \
++	auto_split.o auto_uids.o \
++	fd.a wait.a $(LIBDOMAINKEYS)/libdomainkeys.a -lcrypto env.a control.o open.a getln.a \
++	stralloc.a alloc.a substdio.a str.a case.a `cat dns.lib`
++
++qmail-dk.0: \
++qmail-dk.8
++	nroff -man qmail-dk.8 > qmail-dk.0
++qmail-dk.8: qmail-dk.9
++	cat qmail-dk.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> qmail-dk.8
++
++qmail-dk.o: \
++compile qmail-dk.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
++qmail.h alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
++env.h wait.h fd.h fork.h str.h uint64.h \
++auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
++	./compile qmail-dk.c
++
++dktest: load dktest.o scan_ulong.o dktrace.o \
++dns.o strsalloc.o ip.o error.o ipalloc.o fmt_ulong.o \
++scan_xlong.o socket_v4mappedprefix.o socket_v6any.o \
++case_diffs.o case_diffb.o fmt_str.o stralloc.a alloc.a str.a \
++$(LIBDOMAINKEYS)/libdomainkeys.a dns.lib
++	./load dktest scan_ulong.o dktrace.o \
++	dns.o strsalloc.o ip.o error.o ipalloc.o fmt_ulong.o \
++	scan_xlong.o socket_v4mappedprefix.o socket_v6any.o \
++	case_diffs.o case_diffb.o fmt_str.o stralloc.a alloc.a str.a \
++	$(LIBDOMAINKEYS)/libdomainkeys.a -lcrypto `cat dns.lib`
++
++dktest.o: compile dktest.c domainkeys.h conf-domainkeys
++	./compile `grep -h -v "^#" conf-domainkeys` dktest.c
++
++dktest.8: dktest.9
++	cat dktest.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> dktest.8
++
++dktrace.o: compile dktrace.c dktrace.h str.h case.h conf-domainkeys
++	./compile `grep -h -v "^#" conf-domainkeys` dktrace.c
++
++qmail-dkim: \
++load qmail-dkim.o triggerpull.o fmtqfn.o now.o date822fmt.o \
++subgetopt.o MakeArgs.o dkimdns.o datetime.a seek.a ndelay.a \
++open.a sig.a alloc.a substdio.a error.a \
++str.a case.a fs.a auto_qmail.o auto_split.o auto_uids.o fd.a wait.a \
++$(LIBDOMAINKEYS)/libdomainkeys.a env.a getln.a control.o stralloc.a dns.lib libdkim.a
++	g++ -o qmail-dkim qmail-dkim.o triggerpull.o dkimdns.o fmtqfn.o now.o \
++	subgetopt.o MakeArgs.o date822fmt.o datetime.a seek.a ndelay.a \
++	open.a sig.a substdio.a error.a fs.a auto_qmail.o \
++	auto_split.o auto_uids.o fd.a wait.a \
++	$(LIBDOMAINKEYS)/libdomainkeys.a -lcrypto env.a control.o open.a getln.a \
++	stralloc.a alloc.a substdio.a str.a case.a libdkim.a `cat dns.lib`
++
++qmail-dkim.o: \
++compile qmail-dkim.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
++qmail.h alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
++sgetopt.h env.h wait.h fd.h fork.h str.h dkim.h \
++auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
++	./compile -DHAVE_CONFIG_H qmail-dkim.c
++
+ qmail-getpw: \
+ load qmail-getpw.o case.a substdio.a error.a str.a fs.a auto_break.o \
+ auto_usera.o
+ 	./load qmail-getpw case.a substdio.a error.a str.a fs.a \
+-	auto_break.o auto_usera.o 
++	auto_break.o auto_usera.o
+ 
+ qmail-getpw.0: \
+ qmail-getpw.8
+@@ -1125,6 +1292,28 @@
+ 	| sed s}SPAWN}"`head -1 conf-spawn`"}g \
+ 	> qmail-getpw.8
+ 
++qmail-dkim.0: qmail-dkim.8
++	nroff -man qmail-dkim.8 > qmail-dkim.0
++qmail-dkim.8: qmail-dkim.9
++	cat qmail-dkim.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> qmail-dkim.8
++
++dkim.8: dkim.9
++	cat dkim.9 | sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> dkim.8
++
++dk-filter.0: dk-filter.8
++	nroff -man dk-filter.8 > dk-filter.0
++dk-filter.8: dk-filter.9
++	cat dk-filter.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> dk-filter.8
++
++dknewkey: dknewkey.sh warn-auto.sh
++	rm -f dknewkey
++	cat warn-auto.sh dknewkey.sh > dknewkey
++
+ qmail-getpw.o: \
+ compile qmail-getpw.c readwrite.h substdio.h subfd.h substdio.h \
+ error.h exit.h byte.h str.h case.h fmt.h auto_usera.h auto_break.h \
+@@ -1136,15 +1325,16 @@
+ 	nroff -man qmail-header.5 > qmail-header.0
+ 
+ qmail-inject: \
+-load qmail-inject.o headerbody.o hfield.o newfield.o quote.o now.o \
++load qmail-inject.o rcpthosts.o cdb.a srs.o headerbody.o hfield.o newfield.o quote.o now.o \
+ control.o date822fmt.o constmap.o qmail.o case.a fd.a wait.a open.a \
+ getln.a sig.a getopt.a datetime.a token822.o env.a stralloc.a alloc.a \
+ substdio.a error.a str.a fs.a auto_qmail.o
+-	./load qmail-inject headerbody.o hfield.o newfield.o \
++	./load qmail-inject rcpthosts.o cdb.a srs.o headerbody.o hfield.o newfield.o \
+ 	quote.o now.o control.o date822fmt.o constmap.o qmail.o \
+ 	case.a fd.a wait.a open.a getln.a sig.a getopt.a datetime.a \
+ 	token822.o env.a stralloc.a alloc.a substdio.a error.a \
+-	str.a fs.a auto_qmail.o 
++	str.a fs.a auto_qmail.o \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
+ 
+ qmail-inject.0: \
+ qmail-inject.8
+@@ -1171,15 +1361,20 @@
+ 	> qmail-limits.7
+ 
+ qmail-local: \
+-load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \
++load qmail-local.o constmap.o control.o rcpthosts.o srs.o cdb.a 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
+-	./load qmail-local qmail.o quote.o now.o gfrom.o myctime.o \
++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 constmap.o control.o rcpthosts.o srs.o cdb.a \
++	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 \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
+ 
+ qmail-local.0: \
+ qmail-local.8
+@@ -1200,11 +1395,11 @@
+ qmail-lspawn: \
+ load qmail-lspawn.o spawn.o prot.o slurpclose.o coe.o sig.a wait.a \
+ case.a cdb.a fd.a open.a stralloc.a alloc.a substdio.a error.a str.a \
+-fs.a auto_qmail.o auto_uids.o auto_spawn.o
++fs.a auto_qmail.o auto_uids.o auto_spawn.o envread.o str_diffn.o
+ 	./load qmail-lspawn spawn.o prot.o slurpclose.o coe.o \
+ 	sig.a wait.a case.a cdb.a fd.a open.a stralloc.a alloc.a \
+ 	substdio.a error.a str.a fs.a auto_qmail.o auto_uids.o \
+-	auto_spawn.o 
++	auto_spawn.o envread.o str_diffn.o
+ 
+ qmail-lspawn.0: \
+ qmail-lspawn.8
+@@ -1213,9 +1408,22 @@
+ qmail-lspawn.o: \
+ compile qmail-lspawn.c fd.h wait.h prot.h substdio.h stralloc.h \
+ gen_alloc.h scan.h exit.h fork.h error.h cdb.h uint32.h case.h \
+-slurpclose.h auto_qmail.h auto_uids.h qlx.h
++slurpclose.h auto_qmail.h auto_uids.h qlx.h env.h
+ 	./compile qmail-lspawn.c
+ 
++qmail-newmvrt: \
++load qmail-newmvrt.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \
++stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o
++	./load qmail-newmvrt cdbmss.o getln.a open.a cdbmake.a \
++	seek.a case.a stralloc.a alloc.a strerr.a substdio.a \
++	error.a str.a auto_qmail.o 
++
++qmail-newmvrt.o: \
++compile qmail-newmvrt.c strerr.h stralloc.h gen_alloc.h substdio.h \
++getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \
++uint32.h substdio.h
++	./compile qmail-newmvrt.c
++
+ qmail-newmrh: \
+ load qmail-newmrh.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \
+ stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o
+@@ -1269,11 +1477,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
+@@ -1419,13 +1629,13 @@
+ 	nroff -man qmail-qstat.8 > qmail-qstat.0
+ 
+ qmail-queue: \
+-load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \
+-datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
+-str.a fs.a auto_qmail.o auto_split.o auto_uids.o
++load qmail-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o wildmat.o qregex.o \
++datetime.a seek.a case.a ndelay.a open.a sig.a getln.a stralloc.a alloc.a substdio.a error.a \
++env.a control.o constmap.o str.a fs.a auto_qmail.o auto_split.o auto_uids.o
+ 	./load qmail-queue triggerpull.o fmtqfn.o now.o \
+-	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
+-	alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
+-	auto_split.o auto_uids.o 
++        date822fmt.o wildmat.o qregex.o env.a control.o constmap.o datetime.a case.a seek.a ndelay.a open.a sig.a \
++        getln.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_split.o auto_uids.o
++
+ 
+ qmail-queue.0: \
+ qmail-queue.8
+@@ -1439,14 +1649,18 @@
+ 
+ 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
++substdio.a error.a str.a fs.a auto_qmail.o \
++base64.o md5c.o hmac_md5.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`
++        base64.o md5c.o hmac_md5.o \
++        str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib`
+ 
+ qmail-remote.0: \
+ qmail-remote.8
+@@ -1455,7 +1669,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
+@@ -1463,11 +1677,11 @@
+ qmail-rspawn: \
+ load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \
+ seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \
+-auto_qmail.o auto_uids.o auto_spawn.o
++auto_qmail.o auto_uids.o auto_spawn.o envread.o str_diffn.o
+ 	./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \
+ 	sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \
+ 	substdio.a error.a str.a auto_qmail.o auto_uids.o \
+-	auto_spawn.o 
++	auto_spawn.o  envread.o str_diffn.o
+ 
+ qmail-rspawn.0: \
+ qmail-rspawn.8
+@@ -1475,20 +1689,21 @@
+ 
+ qmail-rspawn.o: \
+ compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \
+-tcpto.h
++tcpto.h env.h
+ 	./compile qmail-rspawn.c
+ 
+ qmail-send: \
+-load qmail-send.o qsutil.o control.o constmap.o newfield.o prioq.o \
++load qmail-send.o rcpthosts.o cdb.a srs.o qsutil.o control.o constmap.o newfield.o prioq.o \
+ trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \
+ datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \
+ lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
+ auto_split.o env.a
+-	./load qmail-send qsutil.o control.o constmap.o newfield.o \
++	./load qmail-send rcpthosts.o cdb.a srs.o qsutil.o control.o constmap.o newfield.o \
+ 	prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \
+ 	qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \
+ 	wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \
+-	substdio.a error.a str.a fs.a auto_qmail.o auto_split.o env.a
++	substdio.a error.a str.a fs.a auto_qmail.o auto_split.o env.a \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
+ 
+ qmail-send.0: \
+ qmail-send.8
+@@ -1509,7 +1724,7 @@
+ scan.h case.h auto_qmail.h trigger.h newfield.h stralloc.h quote.h \
+ qmail.h substdio.h qsutil.h prioq.h datetime.h gen_alloc.h constmap.h \
+ fmtqfn.h readsubdir.h direntry.h
+-	./compile qmail-send.c
++	./compile $(DEFINES) qmail-send.c
+ 
+ qmail-showctl: \
+ load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \
+@@ -1528,21 +1743,26 @@
+ 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 \
+-	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`
++strerr.a wildmat.o qregex.o \
++timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o constmap.o \
++received.o date822fmt.o now.o qmail.o spf.o dns.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 base64.o socket.lib dns.lib lock.a policy.o \
++$(SMTPD_CHKUSER_OBJ)
++	./load qmail-smtpd $(SMTPD_CHKUSER_OBJ) rcpthosts.o commands.o timeoutread.o \
++	strerr.a wildmat.o qregex.o \
++	timeoutwrite.o ip.o ipme.o ipalloc.o strsalloc.o control.o \
++	tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \
++	constmap.o received.o date822fmt.o now.o qmail.o spf.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 strerr.a str.a fs.a auto_qmail.o base64.o policy.o \
++	$(VPOPMAIL_LIBS) \
++	`cat socket.lib`
+ 
+ qmail-smtpd.0: \
+ qmail-smtpd.8
+@@ -1551,9 +1771,10 @@
+ qmail-smtpd.o: \
+ compile qmail-smtpd.c 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 \
+-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
++error.h ipme.h ip.h ipalloc.h strsalloc.h ip.h gen_alloc.h ip.h qmail.h \
++substdio.h strerr.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 spf.h dns.h base64.h \
++cdb.h chkuser.h
+ 	./compile qmail-smtpd.c
+ 
+ qmail-start: \
+@@ -1574,7 +1795,7 @@
+ 
+ qmail-start.o: \
+ compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h
+-	./compile qmail-start.c
++	./compile $(DEFINES) qmail-start.c
+ 
+ qmail-tcpok: \
+ load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \
+@@ -1606,6 +1827,20 @@
+ fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h
+ 	./compile qmail-tcpto.c
+ 
++qmail-todo: \
++load qmail-todo.o control.o constmap.o trigger.o fmtqfn.o now.o \
++readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a alloc.a \
++substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
++	./load qmail-todo control.o constmap.o trigger.o fmtqfn.o now.o \
++	readsubdir.o case.a ndelay.a getln.a sig.a open.a stralloc.a \
++	alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
++
++qmail-todo.o: \
++compile alloc.h auto_qmail.h byte.h constmap.h control.h direntry.h error.h \
++exit.h fmt.h fmtqfn.h getln.h open.h ndelay.h now.h readsubdir.h readwrite.h \
++scan.h select.h str.h stralloc.h substdio.h trigger.h
++	./compile $(DEFINES) qmail-todo.c
++
+ qmail-upq: \
+ warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split
+ 	cat warn-auto.sh qmail-upq.sh \
+@@ -1639,10 +1874,10 @@
+ qreceipt: \
+ load qreceipt.o headerbody.o hfield.o quote.o token822.o qmail.o \
+ getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a substdio.a error.a \
+-str.a auto_qmail.o
++str.a auto_qmail.o scan_ulong.o
+ 	./load qreceipt headerbody.o hfield.o quote.o token822.o \
+ 	qmail.o getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a \
+-	substdio.a error.a str.a auto_qmail.o 
++	substdio.a error.a str.a auto_qmail.o scan_ulong.o
+ 
+ qreceipt.0: \
+ qreceipt.1
+@@ -1779,7 +2014,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 ipmetest.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,8 +2048,9 @@
+ 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 \
++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 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 \
+@@ -1824,10 +2060,11 @@
+ 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 \
++update_tmprsadh
+ 	shar -m `cat FILES` > shar
+ 	chmod 400 shar
+ 
+@@ -1897,6 +2134,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 getln.o getln2.o open_read.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 getln.o getln2.o open_read.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 \
+@@ -1911,13 +2165,33 @@
+ scan.h fmt.h
+ 	./compile splogger.c
+ 
++srs.o: \
++compile srs.c srs.h auto_qmail.h stralloc.h
++	./compile srs.c
++
++
++srsfilter: \
++load srsfilter.o srs.o qmail.o strerr.a control.o rcpthosts.o constmap.o \
++	cdb.a case.a open.a stralloc.a alloc.a getln.a fd.a wait.a sig.a \
++	env.a substdio.a error.a str.a fs.a auto_qmail.o
++	./load srsfilter srs.o qmail.o strerr.a control.o rcpthosts.o constmap.o \
++	cdb.a case.a open.a stralloc.a alloc.a getln.a fd.a wait.a sig.a \
++	env.a substdio.a error.a str.a fs.a auto_qmail.o \
++	-I/usr/local/include -L/usr/local/lib -lsrs2
++
++srsfilter.o: \
++compile srsfilter.c sig.h readwrite.h exit.h env.h qmail.h substdio.h strerr.h \
++substdio.h fmt.h stralloc.h srs.h
++	./compile srsfilter.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 +2201,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 +2284,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
+@@ -2066,11 +2349,11 @@
+ 
+ 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: \
+@@ -2108,6 +2391,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 +2435,165 @@
+ wait_pid.o: \
+ compile wait_pid.c error.h haswaitp.h
+ 	./compile wait_pid.c
++MakeArgs.o: compile MakeArgs.c alloc.h str.h alloc.h stralloc.h
++	./compile MakeArgs.c
++
++spawn-filter: \
++load spawn-filter.o auto_qmail.o \
++fmt_ulong.o scan_ulong.o control.o open_read.o wildmat.o qregex.o MakeArgs.o \
++case_lowerb.o constmap.o byte_chr.o byte_cr.o case_diffb.o \
++error.a env.a stralloc.a wait.a strerr.a str.a getln.a substdio.a alloc.a
++	./load spawn-filter \
++	fmt_ulong.o scan_ulong.o control.o open_read.o wildmat.o qregex.o MakeArgs.o \
++	case_lowerb.o constmap.o byte_chr.o byte_cr.o case_diffb.o auto_qmail.o \
++	error.a env.a stralloc.a wait.a strerr.a str.a getln.a substdio.a alloc.a
++
++spawn-filter.o: \
++compile spawn-filter.c fmt.h str.h strerr.h env.h substdio.h stralloc.h error.h \
++wait.h qregex.h
++	./compile spawn-filter.c
++
++qregex.o: \
++compile qregex.c qregex.h case.h stralloc.h constmap.h substdio.h byte.h env.h
++	./compile qregex.c
++
++wildmat.o: \
++compile wildmat.c
++	./compile wildmat.c
++
++spawn-filter.0: \
++spawn-filter.8
++	nroff -man spawn-filter.8 > spawn-filter.0
++
++spawn-filter.8: \
++spawn-filter.9
++	cat spawn-filter.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> spawn-filter.8
++
++str_cspn.o: \
++compile str.h str_cspn.c
++	./compile str_cspn.c
++
++mess822_ok.o: \
++compile mess822_ok.c uint64.h
++
++surblfilter.0: surblfilter.8
++	nroff -man surblfilter.8 > surblfilter.0
++
++surblfilter.8: surblfilter.9
++	cat surblfilter.9 \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> surblfilter.8
++
++surblfilter: \
++load surblfilter.o envread.o strerr_die.o strerr_sys.o \
++control.o alloc.o alloc_re.o error.o \
++error_str.o auto_qmail.o \
++case_startb.o byte_diff.o str_cspn.o \
++byte_copy.o byte_chr.o byte_rchr.o byte_cr.o \
++getln.o getln2.o open_read.o str_len.o str_diffn.o \
++str_cpy.o str_chr.o scan_xlong.o \
++now.o scan_ulong.o mess822_ok.o constmap.o \
++ip.o strsalloc.o dns.o ipalloc.o fmt_str.o fmt_ulong.o \
++socket_v6any.o socket_v4mappedprefix.o \
++sgetopt.o subgetopt.o base64sub.o \
++case_diffb.o stralloc.a substdio.a
++	./load surblfilter envread.o strerr_die.o strerr_sys.o \
++	control.o alloc.o alloc_re.o error.o \
++	error_str.o auto_qmail.o \
++	case_startb.o byte_diff.o str_cspn.o \
++	byte_copy.o byte_chr.o byte_rchr.o byte_cr.o \
++	getln.o getln2.o open_read.o str_len.o str_diffn.o \
++	str_cpy.o str_chr.o scan_xlong.o \
++	now.o scan_ulong.o mess822_ok.o constmap.o \
++	ip.o strsalloc.o dns.o ipalloc.o fmt_str.o fmt_ulong.o \
++	socket_v6any.o socket_v4mappedprefix.o \
++	sgetopt.o subgetopt.o base64sub.o \
++	case_diffb.o stralloc.a substdio.a -lresolv
++
++surblfilter.o: \
++compile surblfilter.c alloc.h error.h str.h case.h \
++constmap.h auto_qmail.h stralloc.h env.h control.h \
++strerr.h substdio.h getln.h byte.h dns.h ip.h \
++ipalloc.h mess822.h scan.h subgetopt.h uint64.h \
++base64.h
++	./compile surblfilter.c
++
++surblqueue: \
++surblqueue.sh conf-qmail
++	cat surblqueue.sh \
++	| sed s}QMAIL}"`head -1 conf-qmail`"}g \
++	> surblqueue
++	chmod 755 surblqueue
++
++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
++
++uint64.h: \
++tryulong64.c compile load uint64.h1 uint64.h2
++	( ( ./compile tryulong64.c && ./load tryulong64 && \
++	./tryulong64 ) >/dev/null 2>&1 \
++	&& cat uint64.h1 || cat uint64.h2 ) > uint64.h
++	rm -f tryulong64.o tryulong64
++
++base64sub.o: \
++compile base64sub.c base64.h stralloc.h substdio.h str.h
++	./compile base64sub.c
++
++dk-filter: \
++warn-auto.sh dk-filter.sh conf-qmail
++	cat warn-auto.sh dk-filter.sh \
++	| sed s}QMAILHOME}"`head -1 conf-qmail`"}g \
++	> dk-filter
++
++DKIMHDRS = dkim.h dkimdns.h dkimbase.h dkimsign.h dkimverify.h
++DKIMSRCS = dkimfuncs.cpp dkimbase.cpp
++DKIMOBJS = $(DKIMSRCS:.cpp=.o)
++dkim : libdkim.a dkim.o dkimdns.o
++	g++ -o dkim $(LFLAGS) -L. dkim.o dkimdns.o libdkim.a `cat dns.lib` -lcrypto
++
++dkimverify.o: dkim.h dkimdns.h dkimverify.h dkimverify.cpp
++	g++ -DHAVE_CONFIG_H -c dkimverify.cpp
++
++dkimsign.o: dkim.h dkimsign.h dkimsign.cpp
++	g++ -DHAVE_CONFIG_H -c dkimsign.cpp
++
++dkim.o: dkim.c $(DKIMHDRS)
++	g++ -DHAVE_CONFIG_H -I. -DHAVE_EVP_SHA256 -c dkim.c
++
++libdkim.a: $(DKIMOBJS) dkimverify.o dkimsign.o makelib
++	rm -f libdkim.a
++	./makelib libdkim.a $(DKIMOBJS) dkimsign.o dkimverify.o
++.cpp.o:
++	g++ -I. -DHAVE_CONFIG_H $(CFLAGS) $(INCL) -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
++
++policy.o: policy.c policy.h conf-policy
++	./compile policy.c `head -1 conf-policy`
+diff -ruN ../netqmail-1.06-original/Makefile-cert.mk netqmail-1.06/Makefile-cert.mk
+--- ../netqmail-1.06-original/Makefile-cert.mk	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/Makefile-cert.mk	2016-11-22 21:03:57.103528399 +0100
+@@ -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 `head -2 conf-users | tail -1`:`head -1 conf-groups` $@
++
++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 `head -2 conf-users | tail -1`:`head -1 conf-groups` 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 -ruN ../netqmail-1.06-original/README.auth netqmail-1.06/README.auth
+--- ../netqmail-1.06-original/README.auth	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.auth	2016-11-22 21:03:57.103528399 +0100
+@@ -0,0 +1,154 @@
++README qmail SMTP Authentication
++================================
++
++Scope:
++------
++
++This patch supports RFC 2554 "SMTP Service Extension for Authentication" and 
++RFC 4409 "Message Submission for Mail" for 
++
++* qmail-smtpd and
++* qmail-remote
++
++and supports commonly the AUTH methods
++
++- CRAM-MD5
++- LOGIN (unsecure)
++- PLAIN (unsecure)
++
++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.
++* Re-make qmail.
++
++
++Setup for qmail-smtpd:
++----------------------
++
++1. Prereqs:
++
++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.
++
++2. Invocation:
++
++In order activate SMTP authentication, you need to provide the environment
++variable 'SMTPAUTH' to qmail-smtpd.
++
++Possible choices:
++	
++	a) SMTPAUTH=""; 	qmail-smtpd supports auth of type PLAIN and/or LOGIN.
++	b) SMTPAUTH="+cram";	qmail-smtpd will additionally annonce CRAM-MD5,
++				this requires a CRAM-MD5 supporting PAM.
++	c) SMTPAUTH="cram";	qmail-smtpd will only annonce CRAM-MD5.
++	d) SMTPAUTH="!";	this instructs qmail-smtpd to require (any type) authentication for this connection.
++				This behavior is equivalent to the Submission feaure.
++	e) SMTPAUTH="!cram";	same as d) but now CRAM-MD5 is the only method instead.
++
++
++Setup for qmail-remote:
++-----------------------
++
++SMTP Authentication with qmail-remote is faclitated by two means:
++
++a) SMTP Authentication by sender/sending domain as provided in the 'Mail From:'
++
++The control file 'authsenders' which works similar to 'control/smtproutes'
++but with additional authentication information (username + password):
++
++    @example.com:relay.example.com|user|passwd
++    info@example.com:relay.example.com:26|infouser|infopasswd
++    :mailrelay.example.com:587|e=mc2|testpass
++
++Note: The choice of the AUTH method depends on the capabilities of the server.
++
++b) SMTP Authentication by recipient domain: 
++
++The control file 'smtproutes' is enhanced with the authentication information:
++
++    authdomain.com:mx.authdomain.com:125|myuserid|mypassword
++    :mailrelay.example.com:587|e=mc2|testpass
++
++
++Historical Notes:
++-----------------
++
++SMTP authentication for qmail-smtpd was initially provided by Krysztof Dabrowski (version 0.31):
++
++
++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 (keyword ESMTPA).
++* Added SMTPAUTH environment variable.
++* The particular Submission feature has been removed; obsolete.
++
++
++SMTP authentication for qmail-remote is taken from Bjoern Kalkbrenner.
++
++Changes wrt. Bjoern Kalkbrenner's patch (version 0.0.1 / 20020715):
++
++* Uniform, modular support for LOGIN and PLAIN.
++* Added 'Mail From: < > Auth=username' information in provisionally XTEXT format.
++* Added CRAM-MD5 support.
++* Added authentication by recipient domain.
++
++
++Release Notes:
++--------------
++
++Version:	Notes:					Date:
++-------------------------------------------------------------------
++0.5.9		qmail-smtpd AUTH (only)			25.3.2008
++0.6.9		qmail-authentication			1.2.2010
++0.7.0		Based on qmail-authentication 0.69
++		including now CRAM-MD5 support
++		for qmail-remote			31.7.2010
++0.7.1		cosmetics for qmail-remote		5.8.2010
++0.7.2		authorization-id = authentication-id
++		for qmail-remote;
++		added SMTPAUTH environment variable 
++		for qmail-smtpd; backport from SC 2.7	29.4.2012
++0.7.3		Fixed missing AUTH for qmai-smtpd announcement.
++		Improved SUBMISSION port handling.	2.5.2012
++0.7.4		Fixed missing 250 statements for AUTH.
++		Changed SMTPAUTH settings for cram-md5 	18.5.2012
++0.7.5		Fixed bug in qmail-remote not respecting
++		announced AUTH types. Tx. Callum Gibson.
++		Added '432' server code evaluation for
++	 	AUTH password expired in qmail-remote. 	23.10.2012
++0.7.6		Fixed order of SMTP commands (tx roberto).
++							02.02.2013
++0.8.0		Added authentication by recipient domain
++		for qmail-remote.
++		Removed SUBMISSION port feature for
++		qmail-smtpd.				22.03.2013
++0.8.1		Added SMTPAUTH="!+crom" feature.	24.03.2013
++0.8.2		Bug fix: qmail-smtpd ACCEPTS auth commands
++		even if SMTPAUTH="-". (tx chris).	21.01.2015
++0.8.3		Fixed bug in MD5 calculation for AMD64.
++		Fixed 'die_nomem' bug in qmail-smtpd.	23.08.2015
++
++
++
++Erwin Hoffmann - Hoehn 2015-08-23 (www.fehcom.de)
++
++
+diff -ruN ../netqmail-1.06-original/README.dnsbl netqmail-1.06/README.dnsbl
+--- ../netqmail-1.06-original/README.dnsbl	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.dnsbl	2016-11-30 21:50:01.459033083 +0100
+@@ -0,0 +1,18 @@
++Code and logic from rblsmtpd and qmail-dnsbl patch http://qmail-dnsbl.sourceforge.net/
++
++-added support for whitelists, TXT and A queries, configurable return codes 451 or 553 with custom messages
++
++  # - default file control/dnsbllist can be overridden with env variable DNSBLLIST
++  # - if DNSBLSKIP env variable is set, qmail-smtpd skips the rbl check
++  # - if control/dnsblfailclosed or DNSBLFAILCLOSED are defined, qmail-smtpd considers the source ip as blacklisted even in case of lookup failures (check rblsmtpd man page for more details)
++  # - support for environment variable RBLSMTPD (check rblsmtpd man page for more details)
++  # - dnsbllist can contain empty lines and comments with '#' at start or end of lines; leading and trailing spaces are automatically removed
++
++CONTROL FILES
++
++dnsbllist
++            A list of dnsbl providers that qmail-smtpd checks to identify blacklisted ip addresses.
++
++            Exception:  If  the  environment  variable DNSBLSKIP is set, qmail-smtpd ignores dnsbllist, and the dnsbl check is not performed.  The check is skipped even if
++            some other authentication method succedeed and authorized the client to relay (smtp-auth or tls client certificate), or if RELAYCLIENT enviromnent variable  is
++            set.
+diff -ruN ../netqmail-1.06-original/README.empf netqmail-1.06/README.empf
+--- ../netqmail-1.06-original/README.empf	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.empf	2016-11-22 21:03:57.103528399 +0100
+@@ -0,0 +1,106 @@
++config file is: /var/qmail/control/policy
++more info: http://www.qmailwiki.org/EMPF
++
++eMail Messaging Policy Framework (eMPF)
++
++What it does
++------------
++
++   eMPF follows a set of administrator-defined rules describing
++who can message whom.  With this, companies can segregate various
++parts of their organizations email activities, as well as provide
++a variety of security-enhancing services.
++
++How it does it
++--------------
++
++   During an SMTP session, when a sender identifies themselves, either
++via SMTP_AUTH, or via the message envelope, as well as a recipient,
++eMPF loads applicable message policies to determine if the sender is
++allowed to message the sender, and if the recipient is allowed to
++receive mail from the sender.
++
++What it doesn't do
++------------------
++
++   Because mail from outside your mail server cannot be authenticated,
++the policy framework cannot be entirely sure about the identities of
++senders messaging local users.  However, if SMTP_AUTH is enabled, and
++required by your local users, it can prevent local users from transmitting
++information to parties who should not view it.  It is HIGHLY recommended
++that a mail server implementing eMPF also require SMTP_AUTH by it's local
++users as well as use the POLICY_ENFORCE_AUTHENTICATION configuration so that
++senders from the outside cannot masquerade as local users.
++
++Policy configuration
++--------------------
++
++   A large, complicated policy may be rather intimidating at first, however,
++if the rules are documented well, and a basic knowledge of the format of a
++policy is known, they are rather simple to set up.
++
++   comment:
++	  # text
++	  ; text
++ 
++   policy:
++	  <domain>:<delivery policy>,[<user policy>,][<etc>,]
++
++   user policy:
++	  <username>:<delivery policy>[<delivery policy>]
++
++   delivery policy:
++	  <delivery type>[(<address>[,<address>])]
++
++   delivery types:
++	  L - Local
++	  R - Remote
++	  E - External
++	  I - Internal
++
++Delivery types specify what types of messaging can take place.  An uppercase
++delivery type allows a type of delivery, and a lowercase delivery type,
++disallows a type of delivery.  Delivery types may take a list of addresses.
++When a list of addresses is provided after a delivery type, those addresses
++are the only addresses covered by that delivery type.
++
++Certian delivery types apply only to either the sender of the recipient.
++Here is a more clear definition of each of the delivery types.
++
++   Local    - (Sender only) When sending a message to a user on the same domain
++   Internal - (Recipient only) When recieving a messages from a user of the
++              same domain
++   Remote   - (Sender only) When sending a message to a user on another
++              domain (even if that domain resides on the same mail server).
++   External - (Recipient only) When receiving a message from a user on
++              another domain (even if that domain resides on the same server).
++
++Samples
++-------
++
++In this example, example.com allows all messaging.  In this case,
++simply not defining a policy would be more efficient.
++
++   example.com:LREI,
++
++Now, example.com wishes all mail to stay internal.  As stated above,
++there are particular cases in which eMPF cannot authenticate a sender.
++This only occurs when a remote mail server is transmitting mail to a local
++user on your system.  In this case, a remote user could pretend to be a local
++user, and succesfully deliver mail to another local user.  However, the
++recipient would be unable to message back.
++
++   example.com:LIre,
++
++As in the above example, example.com wants all mail to stay internal, however,
++a few of their users are allowed to communicate with the outside world.  Sales
++can communicate with everybody, and Tasks can send messages only to their
++sister-site, example.org.
++
++   example.com:LIre,sales:RE,tasks:R(*@example.org)E(*@example.org),
++
++Something to keep in mind in this scenario, is that if example.org is hosted
++on the same system, and has similar policies to example.com, a policy must be
++established for example.org which allows messages from example.com.
++
++   example.org:LIre,sales:RE,tasks:E(*@example.com)R(*@example.com),
+diff -ruN ../netqmail-1.06-original/README.exttodo netqmail-1.06/README.exttodo
+--- ../netqmail-1.06-original/README.exttodo	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.exttodo	2016-11-22 21:03:57.103528399 +0100
+@@ -0,0 +1,114 @@
++EXTTODO by Claudio Jeker <jeker@n-r-g.com> and 
++Andre Oppermann <opi@nrg4u.com>
++(c) 1998,1999,2000,2001,2002 Internet Business Solutions Ltd.
++
++The EXTTODO patch is a part of the qmail-ldap patch.
++This patches for qmail come with NO WARRANTY.
++
++These patches are under the BSD license.
++
++RELEASE: 5. Jan. 2003
++
++EXTTODO:
++======================
++
++TOC:
++ WHAT DOES IT DO
++ INSTALL
++ CONFIG FILES
++ SETUP
++ BIG PICTURE
++
++NEWS:
++ 
++ This is the first release of the EXTTODO patch.
++
++================================================================================
++
++WHAT DOES IT DO
++
++ The exttodo patch addresses a problem known as the silly qmail (queue)
++ problem. This problem is found only on system with high injection rates.
++
++ qmail with a big local and remote concurrency could deliver a tremendous 
++ amount of messages but normally this can not be achieved because qmail-send
++ becomes a bottleneck on those high volumes servers.
++ qmail-send preprocesses all new messages before distributing them for local
++ or remote delivering. In one run qmail-send does one todo run but has the 
++ ability to close multiple jobs. Because of this layout qmail-send can not 
++ feed all the new available (local/remote) delivery slots and therefor it is 
++ not possible to achieve the maximum throughput.
++ This would be a minor problem if one qmail-send run could be done in extreme
++ short time but because of many file system calls (fsync and (un)link) a todo
++ run is expensive and throttles the throughput.
++
++ The exttodo patch tries to solve the problem by moving the todo routine into 
++ an external program. This reduces the run time in qmail-send.
++
++ exttodo adds a new program to qmail called qmail-todo. qmail-todo prepares
++ incoming messages for local and remote delivering (by creating info/<messid>
++ local/<messid> and remote/<messid> and removing todo/<messid>). See also
++ INTERNALS. As next qmail-todo transmits the <messid> to qmail-send which will
++ add this message into the priority queue which schedules the message for 
++ delivery. 
++
++INSTALL
++
++ To enable the exttodo patch you need to define EXTERNAL_TODO while compiling
++ qmail(-ldap) this can be done with the -D flag of cc (e.g. cc -DEXTERNAL_TODO).
++
++ NOTE: the exttodo patch can also be used on qmail systems without the 
++ qmail-ldap patch.
++ 
++================================================================================
++
++CONFIG FILES
++
++ No additional control files are used or needed.
++
++================================================================================
++
++SETUP
++
++ qmail-todo will be started by qmail-start and therefor no additional setup
++ is needed.
++
++ To verify that exttodo is running just check if qmail-todo is running.
++
++================================================================================
++
++BIG PICTURE
++
++               +-------+   +-------+
++               | clean |   | clean |
++               +--0-1--+   +--0-1--+       +-----------+
++         trigger  ^ |         ^ |        +->0,1 lspawn |
++            |     | v         | v       /  +-----------+
++ +-------+  v  +--2-3--+   +--5-6--+   /
++ |       |  |  |       0<--7     1,2<-+
++ | queue |--+--| todo  |   | send  |
++ |       |  |  |       1-->8     3,4<-+
++ +-------+     +-------+   +---0---+   \
++                               |        \  +-----------+
++                               v         +->0,1 rspwan |
++                           +---0---+       +-----------+
++                           | logger|
++                           +-------+
++
++Communication between qmail-send and qmail-todo
++
++todo -> send:
++   D[LRB]<mesgid>\0
++          Start delivery for new message with id <messid>.
++          the character L, R or B defines the type
++          of delivery, local, remote or both respectively.
++   L<string>\0
++          Dump string to the logger without adding additional \n or similar.
++send -> todo:
++   H      Got a SIGHUP reread ~/control/locals and ~/control/virtualdomains
++   X      Quit ASAP.
++
++qmail-todo sends "\0" terminated messages whereas qmail-send just send one
++character to qmail-todo.
++
++
+diff -ruN ../netqmail-1.06-original/README.liberal-lf netqmail-1.06/README.liberal-lf
+--- ../netqmail-1.06-original/README.liberal-lf	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.liberal-lf	2016-11-22 21:03:57.103528399 +0100
+@@ -0,0 +1,39 @@
++From dgaudet-list-qmail@arctic.org Fri Jan 17 17:50:19 1997
++Date: Fri, 17 Jan 1997 17:38:33 -0800 (PST)
++From: Dean Gaudet <dgaudet-list-qmail@arctic.org>
++To: Julie Baumler <a4jb@psulib.cc.pdx.edu>
++Cc: qmail list <djb-qmail@koobera.math.uic.edu>
++Subject: [PATCH] qmail and \r\n (was Re: host unable to deliver to host using qmail (summary))
++
++On Thu, 16 Jan 1997, Julie Baumler wrote: 
++> 
++> The admin on the machine in question added "E=\r\n" this morning and low
++> and behold, suddenly they can send us mail. 
++> 
++> >From a quick look at the source code, it appears that the remote machine
++> is notified of the problem, but sendmail in its infinite wisdom apparently
++> doesn't capture the error message.  (SIGH)
++
++I don't know what the sendmail config had wrong with it, but I know that
++systems I've set up bounce the error just fine.  Check also in the mail
++logs. 
++
++qmail by default violates the "be liberal in what you accept" rule when
++receiving mail via smtp.  It enforces strict \r\n behaviour... which is
++exactly what the standard dictates.  But I'm not interested in my mailer
++telling other admins to fix their setup, because I know they won't.  (The
++straynewline() function tells people that if they're under Solaris they
++need E=\r\n in their Mether mailer.) 
++
++There is also bug in sendmail pre 8.8 that in some instances will emit
++\rx\n for some printable x.  The case where it occured to me, the message
++had been generated by a lame PC mail program.  In any event, this causes
++qmail to indefinitely defer the incoming message. 
++
++So instead I looked at the sendmail-8.8.4 code and tried to duplicate its
++behaviour w.r.t. seeing \n when it wasn't expecting it.  That is what this
++patch implements. 
++
++Go ahead, shoot me.
++
++Dean
+diff -ruN ../netqmail-1.06-original/README.maxrcpt netqmail-1.06/README.maxrcpt
+--- ../netqmail-1.06-original/README.maxrcpt	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.maxrcpt	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,60 @@
++maxrcpt patch for qmail-smtpd
++
++    To: djb-qmail@xxxxxxxxxxxxxxxxxxxx
++    Subject: maxrcpt patch for qmail-smtpd
++    From: Michael Samuel <michael@xxxxxxxxxxxxxxxxxx>
++    Date: Wed, 12 Nov 1997 15:18:38 +1100 (EST)
++    Mailing-list: contact djb-qmail-help@xxxxxxxxxxxxxxxxxxxx; run by ezmlm
++
++-----BEGIN PGP SIGNED MESSAGE-----
++
++Here is a patch for qmail-smtpd to read a control file to limit the number
++of rcpt to commands.
++
++In the patch I have a thank-you to Sam, this is referring to
++mrsam@xxxxxxxxxxxxx who gave me the ideas on how to start off.
++
++Anyway, it is a "Do what you like with it, but don't blame me" license,
++but if it doesn't work, tell me what went wrong if you like and I will
++try to figure it out.
++
++
++
++Michael Samuel,
++
++Surf-Net City - Internet Cafe and Internet Service Providers
++
++                                Phone: +61 3 9593-9977
++                                E-Mail: michael@xxxxxxxxxxxxxxxxxx
++
++-----BEGIN PGP SIGNATURE-----
++Version: 2.6.3ia
++Charset: noconv
++
++iQCVAwUBNGkuIUqgdYLWa7qBAQHEiwP+JqNDMZDLwLY7CUdmkuY0OUHwSaFCJJiS
++T853fUkupG2kQz6WU8m0RXWd4Rhr+BT8+hqjDDPQYfWzK6QcEf563D0Mp7nA0ZuQ
++s+XHKflwb8PAZBp+lpzkMsgDg/B8mlw9dnJ4pGeP1keWR/5cgBFM78XsthW2rLXd
++EIXiZJ7AEhc=
++=5RMp
++-----END PGP SIGNATURE-----
++
++Here is a patch I rigged up limit the number of RCPT TO: commands per E-Mail
++messages.
++
++It reads the file control/maxrcpt relative to your qmail directory stucture
++(usually /var/qmail/control/maxrcpt).
++
++In that file you should have a integer, which represents the maximum number
++of recipients per E-Mail Messages.
++
++Apparently one of the SMTP rfcs recommends a minimum of 100 recipients per
++message be allowed.  Just something to keep in mind anyway.
++
++If /var/qmail/control/maxrcpt doesn't exist, it does not impose a limit and
++skips the rcpt part of the code, so unless I missed something in the source, 
++you could even have more than MAXINT.
++
++I would like to thank Sam from the qmail list for giving me a good start to
++this patch, and anyone else who offered me suggestions from the qmail list.
++(When I refer to qmail list, I'm referring to djb-qmail@xxxxxxxxxxxxxxxxxxxx)
++
+diff -ruN ../netqmail-1.06-original/README.moreipme netqmail-1.06/README.moreipme
+--- ../netqmail-1.06-original/README.moreipme	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.moreipme	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,154 @@
++###########
++### WHO ###
++###########
++
++This patch was written by Scott Gifford <sgifford@suspectclass.com>.
++The design and much of the code for supporting "notipme" was
++contributed by Charles Cazabon <charlesc@discworld.dyndns.org>.
++
++
++############
++### WHAT ###
++############
++
++This patch may be necessary in some configurations that involve network
++address translation or port forwarding.  It prevents a problem caused
++by an MX or other mail routing directive instructing qmail to connect to
++itself without realizing it's connecting to itself.  When this happens,
++it accepts the message, finds out where to deliver it to (itself), and
++promptly reconnects to itself to deliver the message.  Eventually, when
++it has done this 20 or 30 times, it will give up and bounce the message,
++but not before sucking up all of your CPU while it's happening.
++
++It may also be useful in some configurations that have multiple qmail
++servers configured on different interfaces of the same system.  qmail
++will normally refuse to deliver mail by SMTP to the machine it's
++running on, but with multiple copies of qmail, you may want to prevent
++this behavior.
++
++Normally, qmail can detect what IP addresses refer to itself by getting
++a list of all network interfaces with IP addresses from the operating
++system.  It uses this list to determine whether connecting to an address
++will cause it to connect to itself, and avoid the situation (it calls
++the perm_ambigmx() function, which prints the message:
++
++   Sorry. Although I'm listed as a best-preference MX or A for that host,
++   it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)
++
++But in situations where the OS is not aware of all IP addresses that
++connect back to itself, this detection fails, causing the CPU-sucking
++phenomenon described above.  This can happen if there is a network
++address translation device in front of the qmail server, such as a
++load-balancer or a router which allows you to share one IP address among
++several machines; if there is a port forwarder forwarding connections
++from some other machine to the SMTP server on the qmail server; or in
++configurations where a "dumb" mailserver is configured to use your qmail
++server as a "smarthost", delivering all mail to it without inspection.
++
++To solve this, other IP addresses which will ultimately connect back to
++your machine can be added to the file "control/moreipme", one per line.
++qmail will treat all addresses in this file exactly as if they were
++local, and if it finds an MX record or other mail routing information
++which would cause it to connect to any of these addresses, it will call
++perm_ambigmx(), and print the above error message.
++
++Additionally, IP addresses which the system detects but which should
++*not* be treated as local can be removed from qmail's ipme list by
++adding them to the file "control/notipme".
++
++IP addresses can be specified as individual addresses in the usual
++dotted-quad format, or as entire networks using a slash followed by
++the full dotted-quad netmask:
++
++    127.0.0.1
++    127.0.0.1/255.255.255.255
++    127.0.0.0/255.0.0.0
++    10.0.0.0/255.255.255.0
++
++An individual address is treated exactly like a network with a mask of
++255.255.255.255.  Addresses of interfaces found on the system are
++added with their individual addresses.  In addition, these addresses
++are implicitly added:
++
++    0.0.0.0
++    127.0.0.0/255.0.0.0
++
++So the list of system addresses (the "ipme" list) is, in order,
++127.0.0.0/255.0.0.0, 0.0.0.0, then all actual interfaces on the system
++in the order they are reported, then the contents of the "moreipme"
++file.  The list of excluded addresses (the "notipme" list) is just the
++contents of the "notipme" file.
++
++If an address appears in both the ipme list and the notipme list, the
++entry with the longest netmask wins.  If the netmask lengths are the
++same, notipme wins.
++
++For example, if the ipme list has 127.0.0.0/255.0.0.0 and notipme has
++127.0.0.2, then 127.0.0.2 will not be considered me because the entry
++in notipme has a 32-bit mask.  If the notipme list has
++127.0.0.0/255.0.0.0, all of 127.* will not be considered me.
++
++You can run the program "ipmeprint" from the source directory to see
++what interfaces qmail is detecting or finds in moreipme.
++
++You can run the program "ipmetest" from the source directory to test
++your configuration.  It takes as its first and only parameter an IP
++address to test, and prints either "me" or "not me".
++
++###########
++### HOW ###
++###########
++
++To apply the patch, download and save it somewhere, then cd into your
++qmail source directory.
++
++For stock qmail, download qmail-1.03-moreipme-0.6.patch then run:
++
++    cd qmail-1.03
++    patch -p1 </path/to/qmail-1.03-moreipme-0.6.patch
++
++For netqmail, first download netqmail-1.05, and run the included
++collate.sh script.  Then download netqmail-1.05-moreipme-0.6.patch and
++apply it to the netqmail base directory, after runn:
++
++    cd netqmail-1.05
++    patch -p1 </path/to/netqmail-1.05-moreipme-0.6.patch
++ 
++
++###################
++### OTHER NOTES ###
++###################
++
++This patch also incorporates the "0.0.0.0" patch, which causes qmail 
++to recognize the IP address 0.0.0.0 as a local address.  See:
++
++    http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.README
++
++for more information, and
++
++    http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch
++
++for a copy of the patch.
++
++
++###############
++### HISTORY ###
++###############
++
++2004 May 22 - Patch version 0.6 released.  Fix from Richard Dawe where
++              masks weren't handled properly, removed some dead code,
++              updated comments and docs.  Produce a copy of the patch
++              for netqmail-1.05.
++
++2003 Apr 29 - Patch version 0.5 released.  Added support for netmasks
++              in moreipme and notipme, ipmetest utility, 127/8 as
++              implicit ipme.
++
++2002 Apr 26 - Patch version 0.4 released.  Includes support for "notipme" file.
++              Many other small fixes and cleanups.  Fixes ipmeprint to
++              chdir(/var/qmail) before running.
++
++2001 Oct  8 - Original release of patch.
++
++2001 Jan 22 - (roughly) Original release of 0.0.0.0 patch.
++
+diff -ruN ../netqmail-1.06-original/README.qregex netqmail-1.06/README.qregex
+--- ../netqmail-1.06-original/README.qregex	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.qregex	2016-11-22 21:04:38.822137319 +0100
+@@ -0,0 +1,203 @@
++QREGEX (v2) 20060423 - README April 23, 2006
++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. Setting the LOGREGEX environment
++   variable causes the matched regex pattern to be included in the log. 
++
++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, 5.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>
++
++When the LOGREGEX environment variable is set, the matched pattern will
++be included in the log. Log messages will have the regex pattern appended
++to them. For example, a badhelo log message will look like this:
++
++qmail-smtpd: badhelo: <host> at <remote IP> matches pattern: <regex>
++
++
++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 -ruN ../netqmail-1.06-original/README.rfc2821 netqmail-1.06/README.rfc2821
+--- ../netqmail-1.06-original/README.rfc2821	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.rfc2821	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,39 @@
++This patch is Copyright (C) 2002 - 2003 by Matthias Andree. License below.
++
++(this is the 2nd edition of this patch and the 4th edition of the
++introductory text)
++
++This patch changes qmail-remote to skip over MX servers that greet with
++codes 400 to 499 and to bounce mail when any MX server that qmail tries
++greets with a code 500 to 599.
++
++If you want qmail-remote to skip over hosts greeting with 5XX-codes and
++try the next MX for real RFC-2821 compliance (Sendmail and Postfix do
++that), change the
++
++  if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed");
++
++to
++
++  if (code >= 500 && code < 600) return;
++
++License:
++
++Permission is hereby granted, free of charge, to any person obtaining a
++copy of this software and associated documentation files (the
++"Software"), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be included
++in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+diff -ruN ../netqmail-1.06-original/README.srs netqmail-1.06/README.srs
+--- ../netqmail-1.06-original/README.srs	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.srs	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,93 @@
++qmail SRS patch
++
++This is a SRS (Sender Rewriting Scheme) implementation for qmail using libsrs2.
++
++Current version: qmail-srs-0.8.patch
++Changes
++
++    2011-03-30 (0.8):
++        Fixed bug reading configuration files. 
++    2007-06-05 (0.7):
++        New QMAILINJECT_FORCE_SRS and QMAILINJECT_SKIP_SRS environment variables can force or skip envelope rewriting in qmail-inject. 
++    2007-05-31 (0.6):
++        qmail-inject only will rewrite envelope if EXT and HOST variables are set.
++        Fixed bug in qmail-send handling chdir() calls (Special Thanks to Werner Fleck).
++    2007-01-11 (0.5):
++        Added parameters srs_separator and srs_alwaysrewrite from libsrs2.
++    2007-01-10 (0.4):
++        If srs_domain is empty or not set, SRS is disabled.
++    2006-12-18 (0.3):
++        forward and condredirect: modified to work with SRS.
++    2006-12-17 (0.2):
++        srsfilter: now rewrites To header with the SRS decoded address.
++        srsfilter: only accepts messages from null-sender, Return-Path: <>.
++        srsfilter: modified to reject messages without body.
++        qmail-inject: error message detailed.
++        If optional parameters are not set, will use libsrs2 defaults.
++        Install instructions revised.
++    2006-12-15 (0.1):
++        First release.
++
++Install instructions
++
++    Download and install libsrs2 from http://www.libsrs2.org/download.html.
++    Download qmail-srs-0.8.patch.
++    Apply this patch:
++
++    tar -xzf /path/to/qmail-1.03.tar.gz
++    cd qmail-1.03
++    patch -p1 < qmail-srs-0.8.patch
++    And follow your qmail instalation (config, make, make setup check, ...)
++    Configure some parameters in /var/qmail/control.
++
++    Required parameters:
++
++    echo srs.YOURDOMAIN > /var/qmail/control/srs_domain
++    echo SECRET > /var/qmail/control/srs_secrets
++
++    YOURDOMAIN: Replace with your domain name, e.g. srs.foo-bar.com
++    SECRET: Replace with a random string
++
++    Important! You MUST create a MX record for srs.YOURDOMAIN pointing to your server.
++
++    Optional parameters:
++
++    echo 7 > /var/qmail/control/srs_maxage
++    echo 4 > /var/qmail/control/srs_hashlength
++    echo 4 > /var/qmail/control/srs_hashmin
++    echo = > /var/qmail/control/srs_separator
++    echo 0 > /var/qmail/control/srs_alwaysrewrite
++    Configure your SRS domain.
++
++    echo srs.YOURDOMAIN >> /var/qmail/control/rcpthosts
++    echo srs.YOURDOMAIN:srs >> /var/qmail/control/virtualdomains
++    echo "| /var/qmail/bin/srsfilter" > /var/qmail/alias/.qmail-srs-default
++
++    YOURDOMAIN: Replace with your domain name, e.g. srs.foo-bar.com.
++
++Configuration Parameters
++
++Parameters in bold are required.
++Parameter 	Description 	Example
++srs_domain 	A domain to use in rewritten addresses. If not set, SRS is disabled. 	srs.foo-bar.com
++srs_secrets 	A random string to generate and check SRS addresses. You can specify a list of secrets (one per line). The first secret in the list is used for generating new SRS addresses. All secrets on the list may be used to verify SRS addresses. 	foobar123
++srs_maxage 	The maximum permitted age of a rewritten address. SRS rewritten addresses expire after a specified number of days. libsrs2 default is 21, but I believe that a week is enougth to get all bounces, so I recommend you to use 7. 	7
++srs_hashlength 	The hash length to generate in a rewritten address. The hash length is a measure of security in the SRS system; longer is more secure. 	4
++srs_hashmin 	The hash length to require when checking an address. If the hash length is increased, there may be SRS addresses from your MTA in the wild which use a shorter hash length. This parameter may be set to permit checking of hashes shorter than srs_hashlength. This parameter must be at most srs_hashlength. 	4
++srs_separator 	The separator to appear immediately after SRS[01] in rewritten addresses. This must be -, + or =. Default value is =. 	=
++srs_alwaysrewrite 	Skip rcpthosts check and perform SRS rewriting for all forwarding, even when not required. This must be 0 (disabled) or 1 (enabled). Default value is 0 (disabled). 	0
++Environment Variables (qmail-inject only)
++
++By default, this patch modifies qmail-inject to rewrite the envelope sender only if EXT and HOST variables are set.
++
++You can change this behavior using the following environment variables:
++
++    QMAILINJECT_FORCE_SRS: qmail-inject will call srsforward() even if EXT and HOST are not set.
++    QMAILINJECT_SKIP_SRS: qmail-inject will not call srsforward() even if EXT and HOST are set.
++
++More about SRS
++
++    http://www.openspf.org/SRS
++    http://www.libsrs2.org/
++    http://wooledge.org/~greg/qmail-srs.html
++
+diff -ruN ../netqmail-1.06-original/README.surbl netqmail-1.06/README.surbl
+--- ../netqmail-1.06-original/README.surbl	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.surbl	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,34 @@
++SURBL filter for netqmail
++=========================
++surblfilter reads an rfc822 email on stdin and prints it back on stdout.
++It extracts URL and checks them against SURBL. surblfilter can be used
++as a filter using qmail-qfilter(1) or as a qmail-queue(8) frontend by
++setting QMAILQUEUE environment variable to a wrapper
++/var/qmail/bin/surblqueue
++
++surbfilter caches the result in /var/qmail/control/cache. qmail-smtpd
++needs to have write permission for this directory.
++
++surbfilter does base64 decoding for base64 encoded text/html, text/plain
++to extract urls.
++
++surblfilter requires two control files level2-tlds and level3-tlds in
++/var/qmail/control. The same can be obtained from surbl.org website
++
++http://www.surbl.org/tld/three-level-tlds 
++http://www.surbl.org/tld/two-level-tlds
++
++surbfilter is a standone program and does not need you to patch qmail-smtpd
++or existing programs. It exits 88 in case it finds a SURBL listed URL. It
++exits 111 for temporary errors. It exits 0 if everyting is fine.
++
++surblfilter has been integrated with my qmail-dkim patch and is avaiable at
++
++https://sourceforge.net/projects/indimail/files/netqmail-addons/qmail-dkim-1.0/
++
++It has been integrated in dkim-netqmail-1.06.patch-1.9.gz. The older patches
++will not have surblfilter
++
++surbfilter is built on djb functions and some functions have been ruthlessly
++borrowed from qmail surbl interface by Pieter Droogendijk and the surblhost
++program at http://surblhost.sourceforge.net/
+diff -ruN ../netqmail-1.06-original/README.tap netqmail-1.06/README.tap
+--- ../netqmail-1.06-original/README.tap	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.tap	2016-11-22 21:04:38.822137319 +0100
+@@ -0,0 +1,34 @@
++qmail provides the ability to make a copy of each email that flows through the system.
++This is done using the QUEUE_EXTRA code. See qmail FAQ #8.2
++
++The qmail tap patch adds additional functionality:
++1) Specify which email addresses to tap using a regex style control file. With the
++   regex function, you can specify full domains or individual email addresses.
++
++2) Specify which email address to send the emails to.
++
++3) Qmail does not need to be restated to when the taps control file is changed.
++
++The regex match is applied to both the to and from email addresses. So email
++sent to or from the addresses will be copied. Matching is case insensitive.
++If there are multiple matches, the first match is used.
++
++The queue tap patch adds a new control file:
++
++/var/qmail/control/taps
++Contains a regex style list of addresses to tap and the email
++address of where you want the copy sent to.
++
++Examples:
++a) To tap a whole domain add a line like:
++A:.*@domain.com:joe@example.com
++
++
++b) To tap an individual email address add a line like:
++A:user@domain.com:other@example.com
++
++c) To tap messages going to a domain add a line like:
++T:.*@domain.com:joe@example.com
++
++d) To tap messages comming from a domain add a line like:
++F:.*@domain.com:joe@example.com
+diff -ruN ../netqmail-1.06-original/README.tls netqmail-1.06/README.tls
+--- ../netqmail-1.06-original/README.tls	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/README.tls	2016-11-22 21:03:57.104528366 +0100
+@@ -0,0 +1,100 @@
++Frederik Vermeulen <qmail-tls akrul inoa.net> 20160918
++http://inoa.net/qmail-tls/
++
++This patch implements RFC 3207 (was RFC 2487) in qmail. 
++This means you can get SSL or TLS encrypted and 
++authenticated SMTP between the MTAs and from MUA to MTA. 
++The code is considered experimental (but has worked for
++many since its first release on 1999-03-21).
++
++Usage: - install OpenSSL-1.0.2 http://www.openssl.org/ or later
++         (any version since 0.9.6 is presumed to work)
++       - apply patch to netqmail-1.06 http://qmail.org/netqmail
++         The patches to qmail-remote.c and qmail-smtpd.c can be applied 
++         separately.
++       - provide a server certificate in /var/qmail/control/servercert.pem.
++         "make cert" makes a self-signed certificate.
++         "make cert-req" makes a certificate request.
++         Note: you can add the CA certificate and intermediate
++         certs to the end of servercert.pem.
++       - replace qmail-smtpd and/or qmail-remote binary
++       - verify operation (header information should show
++         something like
++         "Received [..] with (DHE-RSA-AES256-SHA encrypted) SMTP;")
++
++Optional: - when DEBUG is defined, some extra TLS info will be logged
++          - qmail-remote will authenticate with the certificate in
++            /var/qmail/control/clientcert.pem. By preference this is
++            the same as servercert.pem, where nsCertType should be 
++            == server,client or be a generic certificate (no usage specified). 
++          - when a 2048 bit RSA key is provided in /var/qmail/control/rsa2048.pem,
++            this key will be used instead of (slow) on-the-fly generation by
++            qmail-smtpd. Idem for 2048 DH param in control/dh2048.pem.
++            `make tmprsadh` does this.
++            Periodical replacement can be done by crontab:
++            01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1
++          - server authentication:
++            qmail-remote requires authentication from servers for which
++            /var/qmail/control/tlshosts/host.dom.ain.pem exists.
++            The .pem file contains the validating CA certificates.
++            One of the dNSName or the CommonName attributes have to match.
++            WARNING: this option may cause mail to be delayed, bounced,
++            doublebounced, and lost.
++            If /var/qmail/control/tlshosts/exhaustivelist is present,
++            the lists of hosts in /var/qmail/control/tlshosts is
++            an exhaustive list of hosts TLS is tried on.
++            If /var/qmail/control/notlshosts/host.dom.ain is present,
++            no TLS is tried on this host.
++          - client authentication:
++            when relay rules would reject an incoming mail, 
++            qmail-smtpd can allow the mail based on a presented cert.
++            Certs are verified against a CA list in 
++            /var/qmail/control/clientca.pem (eg. from
++            http://curl.haxx.se/ca/cacert.pem)
++            and the cert email-address has to match a line in
++            /var/qmail/control/tlsclients. This email-address is logged
++            in the headers. CRLs can be provided through 
++            /var/qmail/control/clientcrl.pem.
++          - cipher selection:
++            qmail-remote: 
++              openssl cipher string (`man ciphers`) read from 
++              /var/qmail/control/tlsclientciphers
++            qmail-smtpd: 
++              openssl cipher string read from TLSCIPHERS environment variable
++              (can vary based on client IP address e.g.)
++              or if that is not available /var/qmail/control/tlsserverciphers
++          - smtps (deprecated SMTP over TLS via port 465):
++            qmail-remote: when connecting to port 465 
++            qmail-smtpd: when SMTPS environment variable is not empty
++
++Caveats: - do a `make clean` after patching
++         - binaries dynamically linked with current openssl versions need
++           recompilation when the shared openssl libs are upgraded.
++         - this patch could conflict with other patches (notably those
++           replacing \n with \r\n, which is a bad idea on encrypted links).
++         - some broken servers have a problem with TLSv1 compatibility.
++           Uncomment the line where we set the SSL_OP_NO_TLSv1 option.
++         - needs working /dev/urandom (or EGD for openssl versions >0.9.7)
++           for seeding random number generator.
++         - packagers should make sure that installing without a valid 
++           servercert is impossible
++         - when applied in combination with AUTH patch, AUTH patch
++           should be applied first and first part of this patch
++           will fail. This error can be ignored. Packagers should
++           cut the first 12 lines of this patch to make a happy
++           patch
++         - `make tmprsadh` is recommended (or should I say required), 
++           otherwise DH generation can be unpredictably slow
++         - some need "-I/usr/kerberos/include" to be added in conf-cc
++
++Copyright: GPL
++           Links with OpenSSL
++           Inspiration and code from examples in SSLeay (E. Young
++           <eay@cryptsoft.com> and T. Hudson <tjh@cryptsoft.com>),
++           stunnel (M. Trojnara <mtrojnar@ddc.daewoo.com.pl>),
++           Postfix/TLS (L. Jaenicke <Lutz.Jaenicke@aet.tu-cottbus.de>),
++           modssl (R. Engelschall <rse@engelschall.com>),
++           openssl examples of E. Rescorla <ekr@rtfm.com>.
++
++Bug reports: mailto:<qmail-tls akrul inoa.net>
++
+diff -ruN ../netqmail-1.06-original/TARGETS netqmail-1.06/TARGETS
+--- ../netqmail-1.06-original/TARGETS	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/TARGETS	2016-11-22 21:04:20.043763470 +0100
+@@ -1,3 +1,4 @@
++dktest
+ auto-ccld.sh
+ make-load
+ find-systype
+@@ -10,11 +11,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 +110,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
+@@ -158,6 +171,8 @@
+ auto_uids.o
+ qmail-lspawn
+ qmail-getpw.o
++qmail-newmvrt.o
++qmail-newmvrt
+ auto_break.c
+ auto_break.o
+ auto_usera.c
+@@ -168,11 +183,19 @@
+ constmap.o
+ timeoutread.o
+ timeoutwrite.o
++tls.o
++ssl_timeoutio.o
+ timeoutconn.o
+ tcpto.o
+ dns.o
++srsfilter
++srsfilter.o
++srs
++srs.o
++spf.o
+ ip.o
+ ipalloc.o
++strsalloc.o
+ hassalen.h
+ ipme.o
+ ndelay.o
+@@ -182,6 +205,8 @@
+ qmail-remote
+ qmail-rspawn.o
+ tcpto_clean.o
++md5c.o
++hmac_md5.o
+ qmail-rspawn
+ direntry.h
+ qmail-clean.o
+@@ -212,6 +237,9 @@
+ headerbody.o
+ hfield.o
+ token822.o
++spf.o
++spfquery.o
++spfquery
+ qmail-inject
+ predate.o
+ predate
+@@ -270,12 +298,16 @@
+ dnsip
+ dnsmxip.o
+ dnsmxip
++dnstxt.o
++dnstxt
+ dnsfq.o
+ dnsfq
+ hostname.o
+ hostname
+ ipmeprint.o
+ ipmeprint
++ipmetest.o
++ipmetest
+ qreceipt.o
+ qreceipt
+ qsmhook.o
+@@ -320,6 +352,7 @@
+ binm2+df
+ binm3
+ binm3+df
++Makefile-cert
+ it
+ qmail-local.0
+ qmail-lspawn.0
+@@ -382,6 +415,51 @@
+ addresses.0
+ envelopes.0
+ forgeries.0
++policy.o
+ man
+ setup
+ check
++qmail-todo.o
++qmail-todo
++update_tmprsadh
++chkuser.o
++qmail-dk
++qmail-dkim
++qmail-dkim.o
++qmail-dk.o
++libdkim.a
++dkimbase.o
++dkimdns.o
++dkim.o
++dkimsign.o
++dkimverify.o
++dkim
++dkim.o
++dkim.8
++qmail-dkim.8
++qmail-dkim.0
++str_cpyb.o
++dkimfuncs.o
++MakeArgs.o
++spawn-filter spawn-filter.o qregex.o wildmat.o
++spawn-filter.8
++qmail-dk.0 spawn-filter.0
++dk-filter echo.o echo dk-filter.0 dk-filter.8
++case_startb.o
++mess822_ok.o
++scan_xlong.o
++socket_v4mappedprefix.o
++socket_v6any.o
++str_cspn.o
++surblfilter.o
++surblfilter
++surblfilter.8
++uint64.h
++surblqueue
++surblfilter.0
++base64sub.o
++qmail-dk.8
++dktest.o
++dktrace.o
++dknewkey
++dktest.8
+diff -ruN ../netqmail-1.06-original/alloc.c netqmail-1.06/alloc.c
+--- ../netqmail-1.06-original/alloc.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/alloc.c	2016-11-22 21:03:57.105528332 +0100
+@@ -1,6 +1,6 @@
+ #include "alloc.h"
+ #include "error.h"
+-extern char *malloc();
++extern void *malloc();
+ extern void free();
+ 
+ #define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
+diff -ruN ../netqmail-1.06-original/base64.c netqmail-1.06/base64.c
+--- ../netqmail-1.06-original/base64.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/base64.c	2016-11-22 21:03:57.105528332 +0100
+@@ -0,0 +1,124 @@
++#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;
++  i = (n * 3) - p;
++  if (!stralloc_ready(out,i)) return -1;
++  out->len = i;
++  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;
++  }
++
++  i = in->len / 3 * 4 + 4;   
++  if (!stralloc_ready(out,i)) 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 -ruN ../netqmail-1.06-original/base64.h netqmail-1.06/base64.h
+--- ../netqmail-1.06-original/base64.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/base64.h	2016-11-22 21:03:57.105528332 +0100
+@@ -0,0 +1,13 @@
++#ifndef BASE64_H
++#define BASE64_H
++
++/* DKIM-1.10 */
++#include "stralloc.h"
++extern int b64decode(const unsigned char *, int, stralloc *);
++extern int b64encode(stralloc *, stralloc *);
++/* end DKIM-1.10 */
++
++extern int b64decode();
++extern int b64encode();
++
++#endif
+diff -ruN ../netqmail-1.06-original/base64sub.c netqmail-1.06/base64sub.c
+--- ../netqmail-1.06-original/base64sub.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/base64sub.c	2016-11-22 21:03:57.105528332 +0100
+@@ -0,0 +1,170 @@
++/*
++ * $Log: base64sub.c,v $
++ * Revision 1.6  2010-03-03 09:33:16+05:30  Cprogrammer
++ * renamed base64 to base64sub
++ *
++ * Revision 1.5  2004-10-22 20:18:37+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.4  2004-09-19 14:36:11+05:30  Cprogrammer
++ * corrected number of bytes in stralloc variable 'out'
++ *
++ * Revision 1.3  2004-07-30 17:36:47+05:30  Cprogrammer
++ * fixed bugs in b64decode()
++ *
++ * Revision 1.2  2004-07-17 21:16:27+05:30  Cprogrammer
++ * added RCS log
++ *
++ */
++#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];
++	out->len = (n * 3) - p;
++	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;
++}
++
++void
++getversion_base64sub_c()
++{
++	static char    *x = "$Id: base64sub.c,v 1.6 2010-03-03 09:33:16+05:30 Cprogrammer Stab mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/byte.h netqmail-1.06/byte.h
+--- ../netqmail-1.06-original/byte.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/byte.h	2016-11-22 21:03:57.105528332 +0100
+@@ -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 -ruN ../netqmail-1.06-original/byte_cspn.c netqmail-1.06/byte_cspn.c
+--- ../netqmail-1.06-original/byte_cspn.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/byte_cspn.c	2016-11-22 21:03:57.105528332 +0100
+@@ -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 -ruN ../netqmail-1.06-original/byte_rcspn.c netqmail-1.06/byte_rcspn.c
+--- ../netqmail-1.06-original/byte_rcspn.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/byte_rcspn.c	2016-11-22 21:03:57.105528332 +0100
+@@ -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 -ruN ../netqmail-1.06-original/caldate.h netqmail-1.06/caldate.h
+--- ../netqmail-1.06-original/caldate.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/caldate.h	2016-11-22 21:03:57.105528332 +0100
+@@ -0,0 +1,24 @@
++/*
++ * $Log: caldate.h,v $
++ * Revision 1.3  2004-10-09 23:20:20+05:30  Cprogrammer
++ * added function prototypes
++ *
++ * Revision 1.2  2004-06-18 22:57:44+05:30  Cprogrammer
++ * added RCS log
++ *
++ */
++#ifndef CALDATE_H
++#define CALDATE_H
++
++struct caldate
++{
++	long            year;
++	int             month;
++	int             day;
++};
++
++void            caldate_frommjd(struct caldate *, long, int *, int *);
++long            caldate_mjd(struct caldate *);
++unsigned int    caldate_fmt(char *, struct caldate *);
++
++#endif
+diff -ruN ../netqmail-1.06-original/caltime.h netqmail-1.06/caltime.h
+--- ../netqmail-1.06-original/caltime.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/caltime.h	2016-11-22 21:03:57.105528332 +0100
+@@ -0,0 +1,30 @@
++/*
++ * $Log: caltime.h,v $
++ * Revision 1.3  2004-10-09 23:20:26+05:30  Cprogrammer
++ * added function prototypes
++ *
++ * Revision 1.2  2004-06-18 22:57:47+05:30  Cprogrammer
++ * added RCS log
++ *
++ */
++#ifndef CALTIME_H
++#define CALTIME_H
++
++#include "caldate.h"
++#include "tai.h"
++
++struct caltime
++{
++	struct caldate  date;
++	int             hour;
++	int             minute;
++	int             second;
++	long            offset;
++};
++
++void            caltime_tai(struct caltime *, struct tai *);
++void            caltime_utc(struct caltime *, struct tai *, int *, int *);
++
++unsigned int    caltime_fmt(char *, struct caltime *);
++
++#endif
+diff -ruN ../netqmail-1.06-original/case_startb.c netqmail-1.06/case_startb.c
+--- ../netqmail-1.06-original/case_startb.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/case_startb.c	2016-11-22 21:03:57.106528299 +0100
+@@ -0,0 +1,31 @@
++#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;
++  }
++}
++
++/* DKIM 1.10 */
++void
++getversion_case_startb_c()
++{
++        static char    *x = "$Id: case_startb.c,v 1.3 2004-10-22 20:23:18+05:30 Cprogrammer Stab mbhangui $";
++
++        x++;
++}
++/* end DKIM 1.10 */
+diff -ruN ../netqmail-1.06-original/chkspawn.c netqmail-1.06/chkspawn.c
+--- ../netqmail-1.06-original/chkspawn.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/chkspawn.c	2016-11-22 21:03:57.106528299 +0100
+@@ -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 -ruN ../netqmail-1.06-original/chkuser.c netqmail-1.06/chkuser.c
+--- ../netqmail-1.06-original/chkuser.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/chkuser.c	2016-11-22 21:04:19.987765257 +0100
+@@ -0,0 +1,1258 @@
++
++/*
++ *
++ * 'chkuser.c' v.2.0.9
++ * 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 reserved 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 "str.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_VALIAS
++#error  "chkuser setting error: CHKUSER_ENABLE_VALIAS has been substituted by VALIAS (within vpopmail includes); you don't need anymore this define"
++#endif
++
++#if defined CHKUSER_ENABLE_VAUTH_OPEN
++#error  "chkuser setting error: CHKUSER_ENABLE_VAUTH_OPEN has been substituted by CHKUSER_ENABLE_VAUTH_OPEN_CALL; edit chkuser_settings.h and change your settings"
++#endif
++
++#if defined CHKUSER_ENABLE_VAUTH_OPEN_CALL
++ static int db_already_open = 0;
++#endif
++
++#if defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE
++#error	"chkuser setting error: CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE are mutually esclusive. Edit your chkuser_settings.h and disable one of them"
++#endif
++
++  static int starting_value = 0;
++
++#if defined CHKUSER_STARTING_VARIABLE
++  static char *starting_string = 0;
++#endif
++
++#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE
++  static int mustauth_value = 0;
++#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
++
++  static unsigned int sender_nocheck = 0;
++
++#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX
++static stralloc sender_user = {0};
++static stralloc sender_domain = {0};
++#endif
++
++#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE
++static unsigned int enable_doublebounce = 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, "|remoteinfo/auth:" );
++  if (remoteinfo) {
++	substdio_puts (subfderr, remoteinfo);
++  }
++  substdio_puts (subfderr, "|chkuser-identify:" );
++#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE
++  if (identify_remote) substdio_puts (subfderr, identify_remote);
++#endif
++  substdio_puts (subfderr, "> remote <helo:");
++  if (fakehelo) substdio_puts (subfderr, fakehelo);
++  substdio_puts (subfderr, "|remotehostname:" );
++  if (remotehost) substdio_puts (subfderr, remotehost);
++  substdio_puts (subfderr, "|remotehostip:" );
++  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
++#if defined CHKUSER_ALLOW_SENDER_CHAR_6
++                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_6)
++#endif
++#if defined CHKUSER_ALLOW_SENDER_CHAR_7
++                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_7)
++#endif
++#if defined CHKUSER_ALLOW_SENDER_CHAR_8
++                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_8)
++#endif
++#if defined CHKUSER_ALLOW_SENDER_CHAR_9
++                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_9)
++#endif
++#if defined CHKUSER_ALLOW_SENDER_CHAR_10
++                && (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_10)
++#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_RCPT_CHAR_1)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_2
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_2)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_3
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_3)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_4
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_4)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_5
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_5)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_6
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_6)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_7
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_7)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_8
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_8)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_9
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_9)
++#endif
++#if defined CHKUSER_ALLOW_RCPT_CHAR_10
++                && (user->s[x] != CHKUSER_ALLOW_RCPT_CHAR_10)
++#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) {
++
++  starting_value = 0;
++
++#if defined CHKUSER_ALWAYS_ON
++	starting_value = 1;
++#endif
++
++#if 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 = "";
++		starting_value = -1;
++        }
++#endif
++
++#if defined CHKUSER_DISABLE_VARIABLE 
++	if (env_get (CHKUSER_DISABLE_VARIABLE)) { 
++		starting_value = -1; 
++	} 
++#endif 
++
++#if defined CHKUSER_EXTRA_MUSTAUTH_VARIABLE
++        if (env_get (CHKUSER_EXTRA_MUSTAUTH_VARIABLE)) {
++		if (relayclient) {
++			mustauth_value = 0;
++		} else {
++			mustauth_value = 1;
++		}
++        }
++#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
++
++        if (env_get (CHKUSER_SENDER_NOCHECK_VARIABLE)) {
++		sender_nocheck = 1;
++        } else {
++		sender_nocheck = 0;
++        }
++#endif
++
++#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE
++
++        identify_remote = env_get (CHKUSER_IDENTIFY_REMOTE_VARIABLE);
++#endif
++
++
++#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE
++
++        if (env_get (CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE)) {
++                enable_doublebounce = 1;
++        } else {
++                enable_doublebounce = 0;
++        }
++#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_EXTRA_MUSTAUTH_VARIABLE
++  if (mustauth_value == 1) {
++	return CHKUSER_ERR_MUSTAUTH;
++  }
++#endif
++
++
++  if (starting_value == -1) {
++	if (addrallowed()) {
++		return CHKUSER_OK_NOCHECKALL;
++	} else {
++		if (relayclient) {
++			return CHKUSER_RELAYING;
++		}
++		return CHKUSER_NORCPTHOSTS;
++	}
++  }
++
++  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_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 5:
++
++/* Check if domain has bouncing enabled */
++
++		if (starting_value == 0) {
++
++	                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_NOCHECKDOMAIN;
++				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_NOCHECKDOMAIN;
++				break;
++	  		}
++#endif
++		}
++
++
++        case 6:
++
++#if defined CHKUSER_ENABLE_VAUTH_OPEN_CALL
++                if (db_already_open != 1) {
++                        if (CHKUSER_VAUTH_OPEN_CALL () == 0) {
++                                db_already_open == 1;
++                        } else {
++                                retstat = CHKUSER_ERR_AUTH_RESOURCE;
++				break;
++                        }
++                }
++#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, "/editor")) 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_OK_NOCHECKALL:
++#if defined CHKUSER_LOG_VALID_RCPT
++                        chkuser_commonlog (sender->s, rcpt->s, "accepted any rcpt", "accepted any recipient for any rcpt domain");
++#endif
++                        return CHKUSER_OK;
++                        break;
++
++                case CHKUSER_OK_NOCHECKDOMAIN:
++#if defined CHKUSER_LOG_VALID_RCPT
++                        chkuser_commonlog (sender->s, rcpt->s, "accepted any rcpt", "accepted any recipient for this domain");
++#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_MUSTAUTH:
++                        chkuser_commonlog (sender->s, rcpt->s, "must auth", "sender not authenticated/authorized");
++                        CHKUSER_RCPT_DELAY_ANY();
++                        out(CHKUSER_MUSTAUTH_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 retstat;
++}
++
++
++/*
++ *
++ * 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_EXTRA_MUSTAUTH_VARIABLE
++	if (mustauth_value == 1) {
++		out(CHKUSER_MUSTAUTH_STRING);
++#if defined CHKUSER_LOG_VALID_SENDER
++                        chkuser_commonlog (sender->s, "", "must auth", "sender not authenticated/authorized");
++                        CHKUSER_SENDER_DELAY_ANY();
++#endif
++		return CHKUSER_ERR_MUSTAUTH;
++	}
++#endif
++
++        if (sender->len <= 1) {
++#if defined CHKUSER_LOG_VALID_SENDER
++                chkuser_commonlog (sender->s, "", "accepted sender", "accepted null sender always");
++#endif
++                return CHKUSER_OK;
++        }
++
++	if ((starting_value == -1) || (sender_nocheck == 1)) {
++#if defined CHKUSER_LOG_VALID_SENDER
++                        chkuser_commonlog (sender->s, "", "accepted sender", "accepted any sender always");
++#endif
++		return CHKUSER_OK;
++	}
++
++#if defined CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE
++	if ((enable_doublebounce) && str_equal(sender->s,"#@[]")) {
++#if defined CHKUSER_LOG_VALID_SENDER
++                chkuser_commonlog (sender->s, "", "accepted doublebounce", "accepted qmail doublebounce #@[]");
++#endif
++                return CHKUSER_OK;
++	}
++#endif
++
++#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX
++        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;
++	}
++
++#endif
++#endif
++
++#if defined CHKUSER_LOG_VALID_SENDER
++                        chkuser_commonlog (sender->s, "", "accepted sender", "sender accepted");
++#endif
++
++	return CHKUSER_OK;
++
++}
++
++
+diff -ruN ../netqmail-1.06-original/chkuser.h netqmail-1.06/chkuser.h
+--- ../netqmail-1.06-original/chkuser.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/chkuser.h	2016-11-22 21:03:57.106528299 +0100
+@@ -0,0 +1,55 @@
++
++/*
++ *
++ * 'chkuser.h' v.2.0.9
++ * 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 reserved 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.9"
++#define CHKUSER_VERSION_RL	2
++#define CHKUSER_VERSION_MJ	0
++#define CHKUSER_VERSION_MN	9
++
++#define CHKUSER_OK_NOCHECKALL		11
++#define CHKUSER_OK_NOCHECKDOMAIN	10
++#define CHKUSER_OK			1
++#define CHKUSER_RELAYING		0
++#define CHKUSER_KO			-1
++#define CHKUSER_NORCPTHOSTS		-10
++#define CHKUSER_ERR_MUSTAUTH		-15
++#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 -ruN ../netqmail-1.06-original/chkuser_settings.h netqmail-1.06/chkuser_settings.h
+--- ../netqmail-1.06-original/chkuser_settings.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/chkuser_settings.h	2016-11-28 17:35:36.567382036 +0100
+@@ -0,0 +1,468 @@
++/*
++ *
++ * 'chkuser_settings.h' v.2.0.9
++ * 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 reserved 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
++ * CHKUSER_STARTING_VARIABLE cannot be defined together with CHKUSER_ALWAYS_ON
++ * 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"
++
++
++/*
++ * 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
++ * Defining it as "RELAYCLIENT" will avoid sender checking for authenticated/authorized users.
++ *	Senders will be logged anyway if CHKUSER_LOG_VALID_SENDER is defined.
++ */
++#define CHKUSER_SENDER_NOCHECK_VARIABLE "RELAYCLIENT"
++
++/*
++ * Uncomment to enable usage of "#" and "+" characters within sender address
++ * This is used by SRS (Sender Rewriting Scheme) products
++ */
++#define CHKUSER_ALLOW_SENDER_SRS
++
++/*
++ * 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
++
++
++/***************************************************
++ *
++ *      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
++
++/*
++ * This define has been eliminated and its usage will generate an error.
++ * 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
++ */
++#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 '-'
++
++/*
++ * 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
++
++/***************************************************
++ *
++ *      new/modified defines in/from 2.0.9
++ *
++ **************************************************/
++
++/*
++ * A new class of defines is introduced
++ *	CHKUSER_EXTRA_xxxxx
++ *
++ *	These defines will be used for features/behaviours that may work despite of other CHKUSER enable/disable settings
++ *
++ */
++
++/*
++ * If you want to accept only authenticated/authorized users you MUST enable this define and set the related variable.
++ *
++ * if this define is uncommented and the variable is set (to whatever value) then RELAYCLIENT must be set
++ *      otherwise any message will be rejected giving "not authorized" error.
++ *
++ */
++/* #define CHKUSER_EXTRA_MUSTAUTH_VARIABLE "CHKUSER_MUSTAUTH" */
++
++
++/*
++ * This is to check DB availability
++ * It avoids bouncing messages with wrong codes if MySQL/LDAP/PostGRES/etc are down or not reachable
++ *
++ * If you are using MySQL in normal installation use #define CHKUSER_VAUTH_OPEN_CALL vauth_open_update
++ * If you are using MySQL with separate servers for read and write use #define CHKUSER_VAUTH_OPEN_CALL vauth_open
++ * If you are using other DB, check the most appropriate function for your DB within dedicated vpopmail module
++ *
++ * This define substitutes CHKUSER_ENABLE_VAUTH_OPEN
++ */
++
++/* #define CHKUSER_VAUTH_OPEN_CALL vauth_open   */
++/* #define CHKUSER_VAUTH_OPEN_CALL vauth_open_update */
++
++/*
++ * Variable to be set in order to disable chkuser
++ * You may set it to any value you like. If it exists chkuser will be disabled.
++ * 	Setting it to RELAYCLIENT helps disabling chkuser when sender is a known/authenticated mail client 
++ * 	This is useful because Outlook/Eudora and other clients are not able to handle a KO when multiple recipients
++ *		are present in the message. They should always relay to a SMTP service accepting all.
++ *
++ *	Recipients will be logged anyway if CHKUSER_LOG_VALID_RCPT is defined.
++ *
++ * Important changes from 2.0.9
++ *	CHKUSER_ALWAYS_ON and CHKUSER_STARTING_VARIABLE cannot be defined together and in such a case a fatal error is displayed
++ *	(in the previous versions CHKUSER_ALWAYS_ON would automatically disable CHKUSER_STARTING_VARIABLE definition)
++ *
++ *	CHKUSER_DISABLE_VARIABLE is always evaluated after CHKUSER_ALWAYS_ON is set or CHKUSER_STARTING_VARIABLE is evaluated, so
++ *		CHKUSER_ALWAYS_ON or CHKUSER_STARTING_VARIABLE can set the general behaviour, while CHKUSER_DISABLE_VARIABLE
++ *		should be invoked to handle exceptions.
++ *
++ */
++/* #define CHKUSER_DISABLE_VARIABLE "RELAYCLIENT" */
++
++
++/*
++ * Error strings (SMTP error answers)
++ * If you don't like these definitions you can change them here
++ *
++ */
++#define CHKUSER_NORCPT_STRING "550 5.1.1 sorry, no mailbox here by that name (chkuser)\r\n"
++#define CHKUSER_RESOURCE_STRING "451 4.3.0 system temporary unavailable, try again later (chkuser)\r\n"
++#define CHKUSER_MBXFULL_STRING "552 5.2.2 sorry, recipient mailbox is full (chkuser)\r\n"
++#define CHKUSER_MAXRCPT_STRING "550 5.5.3 sorry, reached maximum number of recipients allowed in one session (chkuser)\r\n"
++#define CHKUSER_MAXWRONGRCPT_STRING "550 5.5.3 sorry, you are violating our security policies (chkuser)\r\n"
++#define CHKUSER_DOMAINMISSING_STRING "550 5.1.2 sorry, you must specify a domain (chkuser)\r\n"
++#define CHKUSER_RCPTFORMAT_STRING "553 5.1.3 sorry, mailbox syntax not allowed (chkuser)\r\n"
++#define CHKUSER_RCPTMX_STRING "550 5.1.2 sorry, can't find a valid MX for rcpt domain (chkuser)\r\n"
++#define CHKUSER_SENDERFORMAT_STRING "553 5.1.7 sorry, mailbox syntax not allowed (chkuser)\r\n"
++#define CHKUSER_SENDERMX_STRING "550 5.1.8 sorry, can't find a valid MX for sender domain (chkuser)\r\n"
++#define CHKUSER_INTRUSIONTHRESHOLD_STRING "550 5.7.1 sorry, you are violating our security policies (chkuser)\r\n"
++#define CHKUSER_NORELAY_STRING "553 5.7.1 sorry, that domain isn't in my list of allowed rcpthosts (chkuser)\r\n"
++
++#define CHKUSER_RCPTMX_TMP_STRING "451 4.4.0 DNS temporary failure (chkuser)\r\n"
++#define CHKUSER_SENDERMX_TMP_STRING "451 4.4.0 DNS temporary failure (chkuser)\r\n"
++
++#define CHKUSER_MUSTAUTH_STRING "530 5.7.0 Authentication required (chkuser)\r\n"
++
++/*
++ * No more used defines
++ *	Following defines are eliminated since 2.0.9
++ *	They will make compilation errors and must be deleted/commented
++ *
++ * 			#define CHKUSER_ENABLE_VAUTH_OPEN -> Substituted by CHKUSER_VAUTH_OPEN_CALL
++ */
++
++
++/*
++ * 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.
++ *
++ * Remember: '#' and '+' are accepted by CHKUSER_ALLOW_SENDER_SRS
++ *
++ */
++#define CHKUSER_ALLOW_SENDER_CHAR_1 "'"
++#define CHKUSER_ALLOW_SENDER_CHAR_2 '='
++/* #define CHKUSER_ALLOW_SENDER_CHAR_2 '%' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_3 '£' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_4 '?' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_5 '*' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_6 '^' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_7 '~' */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_8 '&' */	/* available for other characters */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_9 '#' */ 	/* available for other characters */
++/* #define CHKUSER_ALLOW_SENDER_CHAR_10 '=' */ 	/* available for other characters */
++
++
++/*
++ * 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.
++ *
++ * Remember: '#' and '+' are accepted by CHKUSER_ALLOW_RCPT_SRS
++ *
++ */
++/* #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 '*' */
++/* #define CHKUSER_ALLOW_RCPT_CHAR_6 '^' */
++/* #define CHKUSER_ALLOW_RCPT_CHAR_7 '~' */
++/* #define CHKUSER_ALLOW_RCPT_CHAR_8 '&' */ 	/* available for other characters */
++/* #define CHKUSER_ALLOW_RCPT_CHAR_9 '#' */ 	/* available for other characters */
++/* #define CHKUSER_ALLOW_RCPT_CHAR_10 '=' */ 	/* available for other characters */
++
++
++/*
++ * This define tells chkuser which variable must be set to accept a <#@[]> sender
++ * This kind of sender is usually generated from qmail when there is a doublebounce
++ * and all the job is done within the same system.
++ * You may need to accept double bounces from outside when you are migrating servers and
++ * doublebounces are forwarded between systems
++ */
++#define CHKUSER_ENABLE_DOUBLEBOUNCE_VARIABLE "CHKUSER_DOUBLEBOUNCE"
+diff -ruN ../netqmail-1.06-original/condredirect.c netqmail-1.06/condredirect.c
+--- ../netqmail-1.06-original/condredirect.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/condredirect.c	2016-11-22 21:03:57.107528266 +0100
+@@ -10,6 +10,8 @@
+ #include "strerr.h"
+ #include "substdio.h"
+ #include "fmt.h"
++#include "stralloc.h"
++#include "srs.h"
+ 
+ #define FATAL "condredirect: fatal: "
+ 
+@@ -68,6 +70,16 @@
+   dtline = env_get("DTLINE");
+   if (!dtline) strerr_die2x(100,FATAL,"DTLINE not set");
+  
++  if (str_len(sender)) {
++    switch(srsforward(sender)) {
++      case -3: strerr_die2x(100,FATAL,srs_error.s); break;
++      case -2: strerr_die2x(111,FATAL,"out of memory"); break;
++      case -1: strerr_die2x(111,FATAL,"unable to read controls"); break;
++      case 0: break; // nothing
++      case 1: sender = srs_result.s; break;
++    }
++  }
++ 
+   if (qmail_open(&qqt) == -1)
+     strerr_die2sys(111,FATAL,"unable to fork: ");
+   qmail_puts(&qqt,dtline);
+diff -ruN ../netqmail-1.06-original/conf-cc netqmail-1.06/conf-cc
+--- ../netqmail-1.06-original/conf-cc	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/conf-cc	2016-11-22 21:03:57.107528266 +0100
+@@ -1,3 +1,3 @@
+-cc -O2
++cc -O2 -g -DEXTERNAL_TODO -DTLS=20160918 -I/usr/local/ssl/include -I/home/vpopmail/include
+ 
+ This will be used to compile .c files.
+diff -ruN ../netqmail-1.06-original/conf-domainkeys netqmail-1.06/conf-domainkeys
+--- ../netqmail-1.06-original/conf-domainkeys	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/conf-domainkeys	2016-11-22 21:03:57.107528266 +0100
+@@ -0,0 +1 @@
++-DDOMAIN_KEYS
+diff -ruN ../netqmail-1.06-original/conf-ld netqmail-1.06/conf-ld
+--- ../netqmail-1.06-original/conf-ld	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/conf-ld	2016-11-22 21:03:57.107528266 +0100
+@@ -1,3 +1,3 @@
+-cc -s
++cc -g
+ 
+ This will be used to link .o files into an executable.
+diff -ruN ../netqmail-1.06-original/conf-policy netqmail-1.06/conf-policy
+--- ../netqmail-1.06-original/conf-policy	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/conf-policy	2016-11-22 21:03:57.107528266 +0100
+@@ -0,0 +1,17 @@
++-DPOLICY_FILENAME="/var/qmail/control/policy" -DPOLICY_DEALLOCATE -DPOLICY_ENFORCE_AUTHENTICATION
++
++POLICY_FILENAME
++   Sets where the policy file is located
++
++POLICY_ENFORCE_AUTHENTICATION
++   Require that senders who use a local name for envelope
++   authenticate.  This is the recommended setting.
++
++POLICY_DEALLOCATE
++   For every MAIL FROM, RCPT TO combination, re-read all
++   policy information.  This makes policies more dynamic,
++   and stops remote users from causing lots of memory usage,
++   however, it also increases disk i/o, and slows down
++   policy enforcement.  If this is not defined, domain policies
++   will stay in memory until the SMTP session is ended.
++
+diff -ruN ../netqmail-1.06-original/conf-spawn netqmail-1.06/conf-spawn
+--- ../netqmail-1.06-original/conf-spawn	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/conf-spawn	2016-11-22 21:03:57.108528232 +0100
+@@ -1,4 +1,4 @@
+-120
++1000
+ 
+ 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 -ruN ../netqmail-1.06-original/config.h netqmail-1.06/config.h
+--- ../netqmail-1.06-original/config.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/config.h	2016-11-22 21:03:57.108528232 +0100
+@@ -0,0 +1,10 @@
++/* config.h.  Generated from config.h.in by configure.  */
++/* config.h.in.  Generated from configure.in by autoheader.  */
++
++/* Define to 1 if you have the <arpa/nameser.h> header file. */
++
++/* Define to 1 if you have the <dlfcn.h> header file. */
++
++/* HAVE_EVP_SHA256 */
++#define HAVE_EVP_SHA256 1
++
+diff -ruN ../netqmail-1.06-original/control.c netqmail-1.06/control.c
+--- ../netqmail-1.06-original/control.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/control.c	2016-11-22 21:03:57.108528232 +0100
+@@ -85,6 +85,82 @@
+  return 1;
+ }
+ 
++int
++control_readulong(i, fn)
++	unsigned long  *i;
++	char           *fn;
++{
++	unsigned long   u;
++
++	switch (control_readline(&line, fn))
++	{
++	case 0:
++		return 0;
++	case -1:
++		return -1;
++	}
++	if (!stralloc_0(&line))
++		return -1;
++	if (!scan_ulong(line.s, &u))
++		return 0;
++	*i = u;
++	return 1;
++}
++
++/*
++ * read entire file in variable sa
++ * without any interpretation (e.g. comments)
++ * To be used in case a file contains '#' character
++ * in the first column (which control_readfile() will
++ * skip
++ */
++int
++control_readnativefile(sa, fn, mode)
++      stralloc       *sa;
++      char           *fn;
++      int             mode;
++{
++      substdio        ss;
++      int             fd, match;
++
++      if (!stralloc_copys(sa, ""))
++              return -1;
++      if ((fd = open_read(fn)) == -1)
++      {
++              if (errno == error_noent)
++                      return(0);
++              return -1;
++      }
++      substdio_fdbuf(&ss, read, fd, inbuf, sizeof(inbuf));
++      for (;;)
++      {
++              if (getln(&ss, &line, &match, '\n') == -1)
++                      break;
++              if (!match && !line.len)
++              {
++                      close(fd);
++                      return 1;
++              }
++              if (mode) /* for qmail-dk */
++              {
++                      striptrailingwhitespace(&line);
++                      if (!stralloc_0(&line))
++                              break;
++                      if (line.s[0] && !stralloc_cat(sa, &line))
++                              break;
++              } else
++              if (!stralloc_cat(sa, &line))
++                      break;
++              if (!match)
++              {
++                      close(fd);
++                      return 1;
++              }
++      }
++      close(fd);
++      return -1;
++}
++
+ int control_readfile(sa,fn,flagme)
+ stralloc *sa;
+ char *fn;
+diff -ruN ../netqmail-1.06-original/control.h netqmail-1.06/control.h
+--- ../netqmail-1.06-original/control.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/control.h	2016-11-22 21:03:57.108528232 +0100
+@@ -3,8 +3,10 @@
+ 
+ extern int control_init();
+ extern int control_readline();
++extern int control_readulong();
+ extern int control_rldef();
+ extern int control_readint();
++extern int control_readnativefile();
+ extern int control_readfile();
+ 
+ #endif
+diff -ruN ../netqmail-1.06-original/date822fmt.c netqmail-1.06/date822fmt.c
+--- ../netqmail-1.06-original/date822fmt.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/date822fmt.c	2016-11-22 21:03:57.108528232 +0100
+@@ -1,3 +1,4 @@
++#include <time.h>
+ #include "datetime.h"
+ #include "fmt.h"
+ #include "date822fmt.h"
+@@ -12,18 +13,51 @@
+ {
+   unsigned int i;
+   unsigned int len;
++  time_t now;
++  datetime_sec utc;
++  datetime_sec local;
++  struct tm *tm;
++  struct datetime new_dt;
++  int minutes;
++
++  utc = datetime_untai(dt);
++  now = (time_t)utc;
++  tm = localtime(&now);
++  new_dt.year = tm->tm_year;
++  new_dt.mon = tm->tm_mon;
++  new_dt.mday = tm->tm_mday;
++  new_dt.hour = tm->tm_hour;
++  new_dt.min = tm->tm_min;
++  new_dt.sec = tm->tm_sec;
++  local = datetime_untai(&new_dt);
++
+   len = 0;
+-  i = fmt_uint(s,dt->mday); len += i; if (s) s += i;
++  i = fmt_uint(s,new_dt.mday); len += i; if (s) s += i;
+   i = fmt_str(s," "); len += i; if (s) s += i;
+-  i = fmt_str(s,montab[dt->mon]); len += i; if (s) s += i;
++  i = fmt_str(s,montab[new_dt.mon]); len += i; if (s) s += i;
+   i = fmt_str(s," "); len += i; if (s) s += i;
+-  i = fmt_uint(s,dt->year + 1900); len += i; if (s) s += i;
++  i = fmt_uint(s,new_dt.year + 1900); len += i; if (s) s += i;
+   i = fmt_str(s," "); len += i; if (s) s += i;
+-  i = fmt_uint0(s,dt->hour,2); len += i; if (s) s += i;
++  i = fmt_uint0(s,new_dt.hour,2); len += i; if (s) s += i;
+   i = fmt_str(s,":"); len += i; if (s) s += i;
+-  i = fmt_uint0(s,dt->min,2); len += i; if (s) s += i;
++  i = fmt_uint0(s,new_dt.min,2); len += i; if (s) s += i;
+   i = fmt_str(s,":"); len += i; if (s) s += i;
+-  i = fmt_uint0(s,dt->sec,2); len += i; if (s) s += i;
+-  i = fmt_str(s," -0000\n"); len += i; if (s) s += i;
++  i = fmt_uint0(s,new_dt.sec,2); len += i; if (s) s += i;
++
++  if (local < utc) {
++    minutes = (utc - local + 30) / 60;
++    i = fmt_str(s," -"); len += i; if (s) s += i;
++    i = fmt_uint0(s,minutes / 60,2); len += i; if (s) s += i;
++    i = fmt_uint0(s,minutes % 60,2); len += i; if (s) s += i;
++  }
++  else {
++    minutes = (local - utc + 30) / 60;
++    i = fmt_str(s," +"); len += i; if (s) s += i;
++    i = fmt_uint0(s,minutes / 60,2); len += i; if (s) s += i;
++    i = fmt_uint0(s,minutes % 60,2); len += i; if (s) s += i;
++  }
++
++  i = fmt_str(s,"\n"); len += i; if (s) s += i;
++
+   return len;
+ }
+diff -ruN ../netqmail-1.06-original/dk-filter.9 netqmail-1.06/dk-filter.9
+--- ../netqmail-1.06-original/dk-filter.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dk-filter.9	2016-11-22 21:03:57.108528232 +0100
+@@ -0,0 +1,102 @@
++.TH dk-filter 8
++.SH NAME
++dk-filter \- sign/verify using DK/DKIM (SSP/ADSP optionally) and deliver a mail message for delivery
++.SH SYNOPSIS
++.B FILTERARGS=QMAILHOME/bin/dk-filter
++.SH DESCRIPTION
++.B dk-filter
++is a qfilter which can be set as a filter for
++.BR spawn-filter(8) .
++The filter can be set either as
++.B FILTERARGS
++or in the control file
++.BR filterargs .
++
++.B dk-filter
++supports DK/DKIM signing and verification and can optionally use
++.B Sender Signing Practice (SSP)
++or
++.B Author Domain Signing Practice.
++It uses the libdkim and OpenSSL libraries.  To sign a message, set the
++.B DKIMSIGN
++or
++.B DKSIGIN
++environment variables to the pathname of the private key that will be
++used to sign the message. If there is a % character in the environment
++variable, it is removed and replaced by the domain name in the From: header.
++If, after substituting the %, that file does not exist, QMAILHOME/control/domainkeys/%/default
++will be used as the key. If again, after substituting the % sign, the file does not exist,
++QMAILHOME/control/domainkeys/default will be used as the key.
++After all substitutions, if the key file does not exist, the message will not be signed.
++If there is no % and the file does not exist, the message will be rejected with error 35.
++The selector (s=) will be taken from the basename of the file.
++The private key should be created by 
++.BR dknewkey(8) .
++
++You can set various DK options in getopt style, by setting the environment variable DKSIGNOPTIONS
++ b <advice_length>    Length of Advice
++ c <canonicalization> simple, nofws
++ s <privkeyfile>
++ h                    show headers included
++ r                    Skip Duplicate Headers
++.EX
++ DKSIGNOPTIONS="-h -r -c nofws"
++ sets the h= tag, skips duplicate headers and sets nofws canonicalization
++.EE
++
++You can set various DKIM options in getopt style, by setting the environment variable DKIMSIGNOPTIONS
++
++ b <standard>         1 - allman, 2 - ietf or 3 - both
++ c <canonicalization> r for relaxed [DEFAULT], s - simple,
++                      t relaxed/simple, u - simple/relaxed
++ l                    include body length tag
++ q                    include query method tag;
++ t                    include a timestamp tag
++ h
++ i <identity>         the identity, if not provided it will not be included
++ x <expire_time>      the expire time in seconds since epoch
++                      ( DEFAULT = current time + 604800)
++                      if set to - then it will not be included
++ z <hash>             1 for sha1, 2 for sha256, 3 for both
++ s <privkeyfile>
++ y <selector>
++
++.EX
++ DKIMSIGNOPTIONS="-b 1 -c r -q"
++ sets allman standard, with relaxed canonicalization and include query method tag
++.EE
++
++.B dk-filter
++uses the domain found in the Sender: header to set the domain tag. If not it uses the From: header. You can override this by
++setting 
++.B DKIMDOMAIN
++environment variable.
++.B DKIMDOMAIN
++can be set to an email address or a domain (without the at sign).
++To verify a message, set the
++.B DKIMVERIFY
++or
++.B DKVERIFY
++environment variables
++.B dk-filter
++always inserts the 
++.B DKIM-Status
++or
++.B DomainKey-Status
++header, so that messages can be
++rejected later at delivery time, or in the mail reader. In that case you may set
++.B DKIMVERIFY
++or
++.B DKVERIFY
++to an empty string.
++.B dk-filter
++does not use any signing practice byd default. You can override this by setting the SIGN_PRACTICE to ssp or adsp (lowercase).
++
++.SH "EXIT CODES"
++0 for success, non-zero failure
++
++.SH "SEE ALSO"
++dknewkey(8),
++dktest(8),
++dkim(8),
++spawn-filter(8)
+diff -ruN ../netqmail-1.06-original/dk-filter.sh netqmail-1.06/dk-filter.sh
+--- ../netqmail-1.06-original/dk-filter.sh	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dk-filter.sh	2016-11-22 21:03:57.109528199 +0100
+@@ -0,0 +1,315 @@
++#
++# $Log: dk-filter.sh,v $
++# Revision 1.14  2011-02-10 22:47:01+05:30  Cprogrammer
++# fixed exit code of dk-filter when doing verification
++#
++# Revision 1.13  2011-02-08 22:02:29+05:30  Cprogrammer
++# use sender domain when replacing '%' in private key
++#
++# Revision 1.12  2010-05-04 08:37:42+05:30  Cprogrammer
++# do DK signing before DKIM signing to prevent DK_SYNTAX error
++#
++# Revision 1.11  2009-12-10 19:25:13+05:30  Cprogrammer
++# added RCS id
++#
++# Revision 1.10  2009-12-10 16:41:14+05:30  Cprogrammer
++# continue of message gives DK_SYNTAX_ERR
++#
++# Revision 1.9  2009-05-04 10:30:32+05:30  Cprogrammer
++# fixed argument expected error
++#
++# Revision 1.8  2009-04-21 20:42:44+05:30  Cprogrammer
++# added check for dktest, dkim executables
++#
++# Revision 1.7  2009-04-20 10:06:58+05:30  Cprogrammer
++# added DKSIGNOPTS
++#
++# Revision 1.6  2009-04-19 13:38:24+05:30  Cprogrammer
++# added full set of dkim options
++# replaced indimail/bin/echo with echo 1>&2
++#
++# Revision 1.5  2009-04-06 16:37:50+05:30  Cprogrammer
++# added SIGN_PRACTICE
++# use ietf standard insted of allman so that Yahoo verification does not fail
++#
++# Revision 1.4  2009-04-03 14:39:00+05:30  Cprogrammer
++# added return status
++#
++# Revision 1.3  2009-04-03 08:55:29+05:30  Cprogrammer
++# print error messages to stderr
++#
++# Revision 1.2  2009-04-02 20:36:25+05:30  Cprogrammer
++# added -h option to dktest
++# added -x - option to dkim
++#
++# Revision 1.1  2009-04-02 14:52:27+05:30  Cprogrammer
++# Initial revision
++#
++# $Id: dk-filter.sh,v 1.14 2011-02-10 22:47:01+05:30 Cprogrammer Stab mbhangui $
++#
++if [ -z "$QMAILREMOTE" -a -z "$QMAILLOCAL" ]; then
++	echo "dk-filter should be run by spawn-filter" 1>&2
++	exit 1
++fi
++dksign=0
++dkimsign=0
++dkverify=0
++dkimverify=0
++if [ -z "$DKSIGN" -a -z "$DKVERIFY" ] ; then
++	DKSIGN=QMAILHOME/control/domainkeys/%/default
++	dksign=2
++fi
++if [ -z "$DKIMSIGN" -a -z "$DKIMVERIFY" ] ; then
++	DKIMSIGN=QMAILHOME/control/domainkeys/%/default
++	dkimsign=2
++fi
++if [ ! -z "$DKSIGN" ] ; then
++	if [ ! -f QMAILHOME/bin/dktest ] ; then
++		echo "QMAILHOME/bin/dktest: No such file or directory" 1>&2
++		exit 1
++	fi
++	percent_found=0
++	echo $DKSIGN|grep "%" >/dev/null 2>&1
++	if [ $? -eq 0 ] ; then
++		percent_found=1
++	fi
++	if [ ! " $_SENDER" = " " ] ; then
++		# replace '%' in filename with domain
++		domain=`echo $_SENDER | cut -d@ -f2`
++		dkkeyfn=`echo $DKSIGN | sed s{%{$domain{g`
++	else
++		dkkeyfn=$DKSIGN
++	fi
++	if [ $dksign -eq 2 -a ! -f $dkkeyfn ] ; then
++		dkkeyfn=QMAILHOME/control/domainkeys/default
++	fi
++	if [ -f $dkkeyfn ] ; then
++		dksign=1
++	else
++		dksign=0
++	fi
++	if [ $dksign -eq 0 -a $percent_found -ne 1 ] ; then
++		exit 32
++	fi
++	dkselector=`basename $dkkeyfn`
++fi
++if [ ! -z "$DKIMSIGN" ] ; then
++	if [ ! -f QMAILHOME/bin/dkim ] ; then
++		echo "QMAILHOME/bin/dkim: No such file or directory" 1>&2
++		exit 1
++	fi
++	percent_found=0
++	echo $DKIMSIGN|grep "%" >/dev/null 2>&1
++	if [ $? -eq 0 ] ; then
++		percent_found=1
++	fi
++	if [ ! " $_SENDER" = " " ] ; then
++		# replace '%' in filename with domain
++		domain=`echo $_SENDER | cut -d@ -f2`
++		dkimkeyfn=`echo $DKIMSIGN | sed s{%{$domain{g`
++	else
++		dkimkeyfn=$DKIMSIGN
++	fi
++	if [ $dkimsign -eq 2 -a ! -f $dkimkeyfn ] ; then
++		dkimkeyfn=QMAILHOME/control/domainkeys/default
++	fi
++	if [ -f $dkimkeyfn ] ; then
++		dkimsign=1
++	else
++		dkimsign=0
++	fi
++	if [ $dkimsign -eq 0 -a $percent_found -ne 1 ] ; then
++		exit 32
++	fi
++	dkimselector=`basename $dkimkeyfn`
++fi
++if [ ! -z "$DKVERIFY" ] ; then
++	if [ ! -f QMAILHOME/bin/dktest ] ; then
++		echo "QMAILHOME/bin/dktest: No such file or directory" 1>&2
++		exit 1
++	fi
++	dkverify=1
++fi
++if [ ! -z "$DKIMVERIFY" ] ; then
++	if [ ! -f QMAILHOME/bin/dkim ] ; then
++		echo "QMAILHOME/bin/dkim: No such file or directory" 1>&2
++		exit 1
++	fi
++	dkimverify=1
++fi
++cat > /tmp/dk.$$
++if [ $dkimsign -eq 1 ] ; then
++	# DKIMSIGNOPTIONS="-z 1 -b 2 -x - -y $dkimselector -s $dkimkeyfn"
++	set -- `getopt lqthb:c:d:i:x:z:y:s: $DKIMSIGNOPTIONS`
++	bopt=0
++	xopt=0
++	zopt=0
++	yopt=0
++	sopt=0
++	dkimopts="QMAILHOME/bin/dkim"
++	while [ $1 != -- ]
++	do
++		case $1 in
++		-l)
++		dkimopts="$dkimopts -l"
++		;;
++		-q)
++		dkimopts="$dkimopts -q"
++		;;
++		-t)
++		dkimopts="$dkimopts -t"
++		;;
++		-h)
++		dkimopts="$dkimopts -h"
++		;;
++
++		-b)
++		bopt=1
++		dkimopts="$dkimopts -b $2"
++		shift
++		;;
++
++		-c)
++		dkimopts="$dkimopts -c $2"
++		shift
++		;;
++
++		-i)
++		dkimopts="$dkimopts -i $2"
++		shift
++		;;
++
++		-x)
++		xopt=1
++		dkimopts="$dkimopts -x $2"
++		shift
++		;;
++
++		-z)
++		zopt=1
++		dkimopts="$dkimopts -z $2"
++		shift
++		;;
++
++		-y)
++		yopt=1
++		dkimopts="$dkimopts -y $2"
++		shift
++		;;
++
++		-s)
++		sopt=1
++		dkimopts="$dkimopts -s $2"
++		shift
++		;;
++		esac
++		shift   # next flag
++	done
++	if [ $zopt -eq 0 ] ; then
++		dkimopts="$dkimopts -z 1"
++	fi
++	if [ $bopt -eq 0 ] ; then
++		dkimopts="$dkimopts -b 2"
++	fi
++	if [ $xopt -eq 0 ] ; then
++		dkimopts="$dkimopts -x -"
++	fi
++	if [ $yopt -eq 0 ] ; then
++		dkimopts="$dkimopts -y $dkimselector"
++	fi
++	if [ $sopt -eq 0 ] ; then
++		dkimopts="$dkimopts -s $dkimkeyfn"
++	fi
++	exec 0</tmp/dk.$$
++	eval $dkimopts
++	if [ $? -ne 0 ] ; then
++		/bin/rm -f /tmp/dk.$$
++		exit 1
++	fi
++fi
++if [ $dksign -eq 1 ] ; then
++	#dktest: [-f] [-b advice_length] [-c nofws|simple] [-v|-s selector] [-h] [-t#] [-r] [-T][-d dnsrecord]
++	# DKSIGNOPTIONS="-z 1 -b 2 -x - -y $dkimselector -s $dkimkeyfn"
++	set -- `getopt hrb:c:s: $DKSIGNOPTIONS`
++	dkopts="QMAILHOME/bin/dktest"
++	sopt=0
++	while [ $1 != -- ]
++	do
++		case $1 in
++		-h)
++		dkopts="$dkopts -h"
++		;;
++		-r)
++		dkopts="$dkopts -r"
++		;;
++
++		-b)
++		dkopts="$dkopts -b $2"
++		shift
++		;;
++
++		-c)
++		dkopts="$dkopts -c $2"
++		shift
++		;;
++
++		-s)
++		sopt=1
++		dkopts="$dkopts -s $2"
++		shift
++		;;
++		esac
++		shift   # next flag
++	done
++	if [ $sopt -eq 0 ] ; then
++		dkopts="$dkopts -s $dkkeyfn"
++	fi
++	exec 0</tmp/dk.$$
++	#QMAILHOME/bin/dktest -h -s $dkkeyfn
++	eval $dkopts
++	exit_val=$?
++	# allow error due to duplicate DomainKey-Header
++	if [ $exit_val -ne 0 -a $exit_val -ne 6 ] ; then
++		/bin/rm -f /tmp/dk.$$
++		exit $exit_val
++	fi
++fi
++if [ $dkimverify -eq 1 ] ; then
++	practice=$SIGN_PRACTICE
++	if [ " $practice" = " " ] ; then
++		practice=0
++	elif [ " $practice" = " ssp" ] ; then
++		practice=1
++	elif [ " $practice" = " adsp" ] ; then
++		practice=2
++	fi
++	exec 0</tmp/dk.$$
++	QMAILHOME/bin/dkim -p $practice -v
++	ret=$?
++	case $ret in
++		14)
++		/bin/rm -f /tmp/dk.$$
++		exit 100
++		;;
++		88)
++		/bin/rm -f /tmp/dk.$$
++		exit 111
++		;;
++	esac
++	if [ $ret -lt 0 ] ; then
++		/bin/rm -f /tmp/dk.$$
++		exit 1
++	fi
++fi
++if [ $dkverify -eq 1 ] ; then
++	exec 0</tmp/dk.$$
++	QMAILHOME/bin/dktest -v
++	if [ $? -ne 0 ] ; then
++		/bin/rm -f /tmp/dk.$$
++		exit 1
++	fi
++fi
++exec 0</tmp/dk.$$
++/bin/rm -f /tmp/dk.$$
++cat
++exit $?
+diff -ruN ../netqmail-1.06-original/dkim.9 netqmail-1.06/dkim.9
+--- ../netqmail-1.06-original/dkim.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkim.9	2018-04-03 14:46:51.362411599 +0200
+@@ -0,0 +1,98 @@
++.TH dkim 8
++.SH NAME
++dkim \- exercise the domainkeys library
++.SH SYNOPSIS
++.B dkim
++.I opts
++
++.I opts
++is a series of getopt-style options.
++
++.SH DESCRIPTION
++.B dkim
++exercises the dkim library. Both signing and verification merely print out the DKIM header.
++They do not keep a copy of the input file. You will need to do something like this:
++
++.EX
++ (./dkim -s QMAILHOME/control/domainkeys/dog </tmp/testmsg; cat /tmp/testmsg)\
++ | ./dkim -v
++.EE
++
++.SH OPTIONS
++.TP
++-s \fIkey\fR
++.I key
++is a path to a file containing a PEM-format private key. The base name of
++the file is  used  as  the  selector. Reads the email message on stdin. Prints the
++.B DKIM-Signature
++header.
++
++.TP
++-v
++Verifies the email on stdin. Exits with a non-zero exit code and a message to
++stderr if there was a problem with the signature. Always prints a
++.B DKIM-Status:
++header to stdout. This option requires the \fBs\fR._domainkey.\fBd\fR txt record in
++dns (public key). Here \fBs\fR is the selector and \fBd\fR is the domain
++
++.EX
++DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
++d=gmail.com; s=gamma; h=DomainKey-Status:
++To:Subject:Message-Id:Date:From; bh=IarZI4AMTl/vy1jTbPphDcOl4YNS
++POk7Vn0tDdgkbV4=; b=VpIS6XNOLU2WWWlsYGeLB3wMbyFQwkg7F0hr7blu1W8f
++0RRtuyw9igFwY7q7FNaPVlfZ0cfLPh0mRrlExu4V7uQaTP8nnnHO2cAokYbncGS5
++ADU9NbAcpDh+E2YQwzCX
++.EE
++
++.TP
++-l
++include body length tag
++.TP
++-q
++include query method tag
++.TP
++-t
++include a timestamp tag
++.TP
++-f
++issue error if not all message's From headers are in signature
++.TP
++-h
++include Copied Headers
++.TP
++-p \fIssp\fR | \fIadsp\fR
++0 - disable practice (default), 1- SSP, or 2 - ADSP verification
++.TP
++-b \fIstandard\fR
++1 - allman, 2 - ietf or 3 - both
++.TP
++-c \fIcanonicalization\fR
++r for relaxed [DEFAULT], s - simple, t relaxed/simple, u - simple/relaxed
++-d \fIdomain\fR
++the domain tag, if not provided, determined from the sender/from header
++.TP
++-i \fIidentity\fR
++the identity, if not provided it will not be included
++.TP
++-x \fIexpire_time\fR
++the expire time in seconds since epoch ( DEFAULT = current time + 604800). If set to - then it will not be included
++.TP
++-z \fIhash\fR
++1 for sha1, 2 for sha256, 3 for both
++.TP
++-y \fIselector\fR
++the selector tag DEFAULT=private
++.TP
++-s \fIprivkeyfile\fR
++sign the message using the private key in privkeyfile
++.TP
++-H
++this help
++
++.SH "SEE ALSO"
++dktest(8),
++qmail-dk(8),
++qmail-dkim(8),
++dknewkey(8),
++rfc-4870(5),
++rfc-4871(5)
+diff -ruN ../netqmail-1.06-original/dkim.c netqmail-1.06/dkim.c
+--- ../netqmail-1.06-original/dkim.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkim.c	2018-04-03 14:46:51.363411603 +0200
+@@ -0,0 +1,899 @@
++/*
++ * $Log: dkim.c,v $
++ * Revision 1.19  2016-03-01 16:23:38+05:30  Cprogrammer
++ * added -S option to allow email with unsigned subject
++ *
++ * Revision 1.18  2016-02-01 10:53:32+05:30  Cprogrammer
++ * use basename of private key as the selector in absense of -y option
++ *
++ * Revision 1.17  2015-12-15 15:36:01+05:30  Cprogrammer
++ * added case 3 for 3rd party signature without SSP and ADSP
++ * increased buffer size for Apple mail with X-BrightMail-Tracker header issue
++ *
++ * Revision 1.16  2012-08-16 08:01:19+05:30  Cprogrammer
++ * do not skip X-Mailer headers
++ *
++ * Revision 1.15  2011-06-04 13:55:50+05:30  Cprogrammer
++ * set AllowUnsignedFromHeaders
++ *
++ * Revision 1.14  2011-06-04 09:36:36+05:30  Cprogrammer
++ * added AllowUnsignedFromHeaders option
++ *
++ * Revision 1.13  2011-02-07 22:05:23+05:30  Cprogrammer
++ * added case DKIM_3PS_SIGNATURE
++ *
++ * Revision 1.12  2010-05-04 14:00:13+05:30  Cprogrammer
++ * make option '-z' work on systems without SHA_256
++ *
++ * Revision 1.11  2009-04-20 08:35:45+05:30  Cprogrammer
++ * corrected usage()
++ *
++ * Revision 1.10  2009-04-15 21:30:32+05:30  Cprogrammer
++ * added DKIM-Signature to list of excluded headers
++ *
++ * Revision 1.9  2009-04-15 20:45:04+05:30  Cprogrammer
++ * corrected usage
++ *
++ * Revision 1.8  2009-04-05 19:04:44+05:30  Cprogrammer
++ * improved formating of usage
++ *
++ * Revision 1.7  2009-04-03 12:05:25+05:30  Cprogrammer
++ * minor changes on usage display
++ *
++ * Revision 1.6  2009-03-28 20:15:23+05:30  Cprogrammer
++ * invoke DKIMVerifyGetDetails()
++ *
++ * Revision 1.5  2009-03-27 20:43:48+05:30  Cprogrammer
++ * added HAVE_OPENSSL_EVP_H conditional
++ *
++ * Revision 1.4  2009-03-27 20:19:28+05:30  Cprogrammer
++ * added ADSP
++ *
++ * Revision 1.3  2009-03-26 15:10:53+05:30  Cprogrammer
++ * added ADSP
++ *
++ * Revision 1.2  2009-03-25 08:37:45+05:30  Cprogrammer
++ * added dkim_error
++ *
++ * Revision 1.1  2009-03-21 08:24:47+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ * This code incorporates intellectual property owned by Yahoo! and licensed 
++ * pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ * Unless required by applicable law or agreed to in writing, software 
++ * distributed under the License is distributed on an "AS IS" BASIS, 
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ * See the License for the specific language governing permissions and 
++ * limitations under the License.
++ */
++/*
++ * (cat /tmp/test.msg|./dkimtest -z 2 -b 1 -y private \
++ * -s /var/indimail/control/domainkeys/private ;cat /tmp/test.msg )|./dkimtest -v
++ */
++#ifndef __cplusplus
++#error A C++ compiler is required!
++#endif
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <stdio.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <unistd.h>
++#include <string.h>
++#include <time.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include "dkim.h"
++#include "dkimdns.h"
++
++#ifdef HAVE_OPENSSL_EVP_H
++#include <openssl/evp.h>
++#define DKIM_MALLOC(s)     OPENSSL_malloc(s)
++#define DKIM_MFREE(s)      OPENSSL_free(s); s = NULL;
++#else
++#define DKIM_MALLOC(s)     malloc(s)
++#define DKIM_MFREE(s)      free(s); s = NULL;
++#endif
++
++int DKIM_CALL
++SignThisHeader(const char *szHeader)
++{
++	if ((!strncasecmp(szHeader, "X-", 2) && strncasecmp(szHeader, "X-Mailer", 8))
++		|| !strncasecmp(szHeader, "Received:", 9)
++		|| !strncasecmp(szHeader, "DKIM-Signature:", 15)
++		|| !strncasecmp(szHeader, "Authentication-Results:", 23)
++		|| !strncasecmp(szHeader, "DomainKey-Signature", 19)
++		|| !strncasecmp(szHeader, "Return-Path:", 12)) 
++	{
++		return 0;
++	}
++	return 1;
++}
++
++char           *program;
++
++void
++usage()
++{
++#ifdef HAVE_EVP_SHA256
++	fprintf(stderr, "usage: %s [-lqthvH] [-p <0|1|2>] [-b <1|2|3>] [-c <r|s|t|u>]\n\t[-d domain] [-i you@domain] [-x expire_time] [-z hash] [-y selector] -s privkeyfile\n", program);
++#else
++	fprintf(stderr, "usage: %s [-lqthvH] [-p <0|1|2>] [-b <1|2|3>] [-c <r|s|t|u>]\n\t[-d domain] [-i you@domain] [-x expire_time] [-y selector] -s privkeyfile\n", program);
++#endif
++	fprintf(stderr, "l                    include body length tag\n");
++	fprintf(stderr, "q                    include query method tag\n");
++	fprintf(stderr, "t                    include a timestamp tag\n");
++	fprintf(stderr, "h                    include Copied Headers\n");
++	fprintf(stderr, "v                    verify the message\n");
++	fprintf(stderr, "p <ssp|adsp>         0 - disable practice (default), 1- SSP, or 2 - ADSP verification\n");
++	fprintf(stderr, "b <standard>         1 - allman, 2 - ietf or 3 - both\n");
++	fprintf(stderr, "c <canonicalization> r for relaxed [DEFAULT], s - simple, t relaxed/simple, u - simple/relaxed\n");
++	fprintf(stderr, "d <domain>           the domain tag, if not provided, determined from the sender/from header\n");
++	fprintf(stderr, "i <identity>         the identity, if not provided it will not be included\n");
++	fprintf(stderr, "x <expire_time>      the expire time in seconds since epoch ( DEFAULT = current time + 604800)\n");
++	fprintf(stderr, "                     if set to - then it will not be included\n");
++#ifdef HAVE_EVP_SHA256
++	fprintf(stderr, "z <hash>             1 for sha1, 2 for sha256, 3 for both\n");
++#endif
++	fprintf(stderr, "f                    0 = From headers not included in the signature are not allowed\n");
++	fprintf(stderr, "                     1 = allowed\n");
++	fprintf(stderr, "y <selector>         the selector tag DEFAULT=private\n");
++	fprintf(stderr, "s <privkeyfile>      sign the message using the private key in privkeyfile\n");
++	fprintf(stderr, "H                    this help\n");
++	exit(1);
++}
++
++unsigned int str_chr(char *s, int c)
++{
++	register char   ch;
++	register char  *t;
++
++	ch = c;
++	t = s;
++	for (;;)
++	{
++		if (!*t)
++			break;
++		if (*t == ch)
++			break;
++		++t;
++		if (!*t)
++			break;
++		if (*t == ch)
++			break;
++		++t;
++		if (!*t)
++			break;
++		if (*t == ch)
++			break;
++		++t;
++		if (!*t)
++			break;
++		if (*t == ch)
++			break;
++		++t;
++	}
++	return t - s;
++}
++
++void
++dkim_error(int e)
++{
++	switch (e)
++	{
++	case DKIM_OUT_OF_MEMORY:
++		fprintf(stderr, "memory allocation failed\n");
++		break;
++	case DKIM_INVALID_CONTEXT:
++		fprintf(stderr, "DKIMContext structure invalid for this operation\n");
++		break;
++	case DKIM_NO_SENDER:
++		fprintf(stderr, "Could not find From: or Sender: header in message\n");
++		break;
++	case DKIM_BAD_PRIVATE_KEY:
++		fprintf(stderr, "Could not parse private key\n");
++		break;
++	case DKIM_BUFFER_TOO_SMALL:
++		fprintf(stderr, "Buffer passed in is not large enough");
++		break;
++	}
++}
++
++/*
++ * Allows you to add the headers contain the results and DKIM ADSP
++ */
++int writeHeader(int ret, int resDKIMSSP, int resDKIMADSP, int useSSP, int useADSP )
++{
++	char           *dkimStatus, *sspStatus, *adspStatus;
++
++	dkimStatus = sspStatus = adspStatus = (char *) "";
++	switch (ret)
++	{
++	case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
++		dkimStatus = (char *) "signature result: signature verified but it did not include all of the body";
++		break;
++	case DKIM_NEUTRAL:			/*- 3 verify result: no signatures verified but message is not suspicious */
++		dkimStatus = (char *) "verify result: no signatures verified but message is not suspicious";
++		break;
++	case DKIM_PARTIAL_SUCCESS:	/*- 2 verify result: at least one but not all signatures verified */
++		dkimStatus = (char *) "verify result: at least none but not all signatures verified";
++		break;
++	case DKIM_FINISHED_BODY:	/*- 1 process result: no more message body is needed */
++		dkimStatus = (char *) "process result: no more message body is needed";
++		break;
++	case DKIM_SUCCESS:
++		dkimStatus = (char *) "good        ";
++		break;
++	case DKIM_FAIL:
++		dkimStatus = (char *) "failed      ";
++		break;
++	case DKIM_BAD_SYNTAX:
++		dkimStatus = (char *) "signature error: DKIM-Signature could not parse or has bad tags/values";
++		break;
++	case DKIM_SIGNATURE_BAD:
++		dkimStatus = (char *) "signature error: RSA verify failed";
++		break;
++	case DKIM_SIGNATURE_BAD_BUT_TESTING:
++		dkimStatus = (char *) "signature error: RSA verify failed but testing";
++		break;
++	case DKIM_SIGNATURE_EXPIRED:
++		dkimStatus = (char *) "signature error: x= is old";
++		break;
++	case DKIM_SELECTOR_INVALID:
++		dkimStatus = (char *) "signature error: selector doesn't parse or contains invalid values";
++		break;
++	case DKIM_SELECTOR_GRANULARITY_MISMATCH:
++		dkimStatus = (char *) "signature error: selector g= doesn't match i=";
++		break;
++	case DKIM_SELECTOR_KEY_REVOKED:
++		dkimStatus = (char *) "signature error: selector p= empty";
++		break;
++	case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
++		dkimStatus = (char *) "signature error: selector domain name too long to request";
++		break;
++	case DKIM_SELECTOR_DNS_TEMP_FAILURE:
++		dkimStatus = (char *) "signature error: temporary dns failure requesting selector";
++		break;
++	case DKIM_SELECTOR_DNS_PERM_FAILURE:
++		dkimStatus = (char *) "signature error: permanent dns failure requesting selector";
++		break;
++	case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
++		dkimStatus = (char *) "signature error: selector p= value invalid or wrong format";
++		break;
++	case DKIM_NO_SIGNATURES:
++		dkimStatus = (char *) "process error, no sigs";
++		break;
++	case DKIM_NO_VALID_SIGNATURES:
++		dkimStatus = (char *) "process error, no valid sigs";
++		break;
++	case DKIM_BODY_HASH_MISMATCH:
++		dkimStatus = (char *) "sigature verify error: message body does not hash to bh value";
++		break;
++	case DKIM_SELECTOR_ALGORITHM_MISMATCH:
++		dkimStatus = (char *) "signature error: selector h= doesn't match signature a=";
++		break;
++	case DKIM_STAT_INCOMPAT:
++		dkimStatus = (char *) "signature error: incompatible v=";
++		break;
++	default:
++		dkimStatus = (char *) "error";
++		break;
++	}
++	if (useSSP && resDKIMSSP != -1)
++	{
++		switch(resDKIMSSP)
++		{
++			case DKIM_SSP_ALL:
++				sspStatus = (char *) "all;";
++				break;
++			case DKIM_SSP_STRICT:
++				sspStatus = (char *) "strict;";
++				break;
++			case DKIM_SSP_SCOPE:
++				sspStatus = (char *) "out of scope;";
++				break;
++			case DKIM_SSP_TEMPFAIL:
++				sspStatus = (char *) "temporary failure;";
++				break;
++			case DKIM_SSP_UNKNOWN:
++			default:
++				sspStatus = (char *) "unknown;";
++				break;
++		}
++	}
++	if (useADSP && resDKIMADSP != -1)
++	{
++		switch(resDKIMADSP)
++		{
++			case DKIM_ADSP_ALL:
++				adspStatus = (char *) "all;";
++				break;
++			case DKIM_ADSP_DISCARDABLE:
++				adspStatus = (char *) "discardable;";
++				break;
++			case DKIM_ADSP_SCOPE:
++				adspStatus = (char *) "out of scope;";
++				break;
++			case DKIM_ADSP_TEMPFAIL:
++				adspStatus = (char *) "temporary failure;";
++				break;
++			case DKIM_ADSP_UNKNOWN:
++			default:
++				adspStatus = (char *) "unknown ;";
++				break;
++		}
++	}
++	printf("DKIM-Status: %s\n", dkimStatus);
++	if (useSSP && *sspStatus)
++		printf("X-DKIM-SSP: %s\n", sspStatus);
++	if (useADSP && *adspStatus)
++		printf("X-DKIM-ADSP: %s\n", adspStatus);
++}
++
++int
++ParseTagValues(char *list, char *letters[], char *values[])
++{
++	char           *tmp, *ptr, *key;
++	int             i;
++
++	/*- start with all args unset */
++	for (i = 0; letters[i]; i++)
++		values[i] = 0;
++	key = 0;
++	for(ptr = list;*ptr;)
++	{
++		if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')) /*- FWS */
++			*ptr++ = 0;
++		if (!key)
++			key = ptr;
++		if (*ptr == '=')
++		{
++			*ptr = 0;
++			for (i = 0;letters[i];i++)
++			{
++				if (!strcmp(letters[i], key))
++				{
++					ptr++;
++					for (;*ptr;)
++					{
++						if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n'))
++						{
++							ptr++;
++							continue;
++						}
++						break;
++					}
++					values[i] = ptr;
++					for(;*ptr && *ptr != ';';ptr++);
++					tmp = ptr;
++					if (*ptr)
++						*ptr++ = 0;
++					for(;tmp != values[i];tmp--) /*- RFC 4871 3.2 */
++					{
++						if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\r') || (*tmp == '\n'))
++						{
++							*tmp = 0;
++							continue;
++						}
++						break;
++					}
++					key = 0;
++					break;
++				}
++			}
++		} else
++			ptr++;
++	}
++	return (0);
++}
++
++int
++GetSSP(char *domain, int *bTesting)
++{
++	char           *query, *results;
++	char           *tags[] = { (char *) "dkim", (char *) "t", (char *) 0};
++	char           *values[2];
++	int             bIsParentSSP = 0, iSSP = DKIM_SSP_UNKNOWN;
++
++	*bTesting = 0;
++	if (!(query = (char *) DKIM_MALLOC(strlen("_ssp._domainkey.") + strlen(domain) + 1)))
++	{
++		fprintf(stderr, "malloc: %d: %s\n", strlen("_ssp._domainkey.") + strlen(domain) + 1,
++			strerror(errno));
++		exit(1);
++	}
++	sprintf(query, "_ssp._domainkey.%s", domain);
++	results = dns_text(query);
++	DKIM_MFREE(query);
++	if (!strcmp(results, "e=temp;"))
++	{
++		DKIM_MFREE(results);
++		return DKIM_SSP_TEMPFAIL;
++	} else
++	if (!strcmp(results, "e=perm;"))
++	{
++		DKIM_MFREE(results);
++		results = dns_text(domain);
++		if (!strcmp(results, "e=temp;"))
++		{
++			DKIM_MFREE(results);
++			return DKIM_SSP_TEMPFAIL;
++		} else
++		if (!strcmp(results, "e=perm;"))
++		{
++			DKIM_MFREE(results);
++			return DKIM_SSP_SCOPE;
++		}
++		bIsParentSSP = 1;
++	}
++	if (!ParseTagValues(results, tags, values))
++	{
++		DKIM_MFREE(results);
++		return DKIM_SSP_UNKNOWN;
++	}
++	DKIM_MFREE(results);
++	if (values[0] != NULL) {
++		if (strcasecmp(values[0], "all") == 0)
++			iSSP = DKIM_SSP_ALL;
++		else
++		if (strcasecmp(values[0], "strict") == 0)
++			iSSP = DKIM_SSP_STRICT;
++	}
++	// flags
++	if (values[1] != NULL) {
++		char           *s, *p;
++		for (p = values[1], s = values[1]; *p; p++)
++		{
++			if (*p == '|')
++				*p = 0;
++			else
++				continue;
++			if (!strcmp(s, "y"))
++				*bTesting = 1;
++			else
++			if (!strcmp(s, "s")) {
++				if (bIsParentSSP) {
++					/* 
++					 * this is a parent's SSP record that should not apply to subdomains
++					 * the message is non-suspicious
++					 */
++					*bTesting = 0;
++					return (DKIM_SSP_UNKNOWN);
++				}
++			}
++			s = p + 1;
++		}
++	}
++	return iSSP; /*- No ADSP Record */
++}
++
++int
++GetADSP(char *domain)
++{
++	char           *query, *results;
++	char           *tags[] = {(char *) "dkim", (char *) 0};
++	char           *values[1];
++
++	results = dns_text(domain);
++	if (!strcmp(results, "e=perm;"))
++	{
++		DKIM_MFREE(results);
++		return DKIM_ADSP_SCOPE;
++	} else
++	if (!strcmp(results, "e=temp;"))
++	{
++		DKIM_MFREE(results);
++		return DKIM_ADSP_TEMPFAIL;
++	}
++	if (!(query = (char *) DKIM_MALLOC(strlen((char *) "_adsp._domainkey.") + strlen(domain) + 1)))
++	{
++		fprintf(stderr, "malloc: %d: %s\n", strlen("_adsp._domainkey.") + strlen(domain) + 1,
++			strerror(errno));
++		exit(1);
++	}
++	sprintf(query, "_adsp._domainkey.%s", domain);
++	results = dns_text(query);
++	DKIM_MFREE(query);
++	if (!strcmp(results, "e=perm;"))
++	{
++		DKIM_MFREE(results);
++		return DKIM_ADSP_SCOPE;
++	} else
++	if (!strcmp(results, "e=temp;"))
++	{
++		DKIM_MFREE(results);
++		return DKIM_ADSP_TEMPFAIL;
++	}
++	if (!ParseTagValues(results, tags, values))
++	{
++		DKIM_MFREE(results);
++		return DKIM_ADSP_UNKNOWN;
++	}
++	DKIM_MFREE(results);
++	if (values[0] != NULL) {
++		if (strcasecmp(values[0], "all") == 0)
++			return (DKIM_ADSP_ALL);
++		else
++		if (strcasecmp(values[0], "discardable") == 0)
++			return (DKIM_ADSP_DISCARDABLE);
++	}
++	return DKIM_ADSP_UNKNOWN; /*- No ADSP Record */
++}
++
++int
++main(int argc, char **argv)
++{
++	char           *PrivKey, *PrivKeyFile = NULL, *pSig = NULL, *dkimverify;
++	int             i, ret, ch, nPrivKeyLen, PrivKeyFD, verbose = 0;
++	int             bSign = 1, nSigCount = 0, useSSP = 0, useADSP = 0, accept3ps = 0;
++	int             sCount = 0, sSize = 0, resDKIMSSP = -1, resDKIMADSP = -1;
++	int             nAllowUnsignedFromHeaders = 0;
++	int             nAllowUnsignedSubject = 1;
++	char            Buffer[4096], szPolicy[512];
++	time_t          t;
++	struct stat     statbuf;
++	DKIMContext     ctxt;
++	DKIMSignOptions opts = { 0 };
++	DKIMVerifyDetails *pDetails;
++	DKIMVerifyOptions vopts = { 0 };
++
++	if (!(program = strrchr(argv[0], '/')))
++		program = argv[0];
++	else
++		program++;
++	t = time(0);
++#ifdef HAVE_EVP_SHA256
++	opts.nHash = DKIM_HASH_SHA1_AND_256;
++#else
++	opts.nHash = DKIM_HASH_SHA1;
++#endif
++	opts.nCanon = DKIM_SIGN_RELAXED;
++	opts.nIncludeBodyLengthTag = 0;
++	opts.nIncludeQueryMethod = 0;
++	opts.nIncludeTimeStamp = 0;
++	opts.expireTime = t + 604800;	// expires in 1 week
++	opts.nIncludeCopiedHeaders = 0;
++	opts.nIncludeBodyHash = DKIM_BODYHASH_BOTH;
++	strcpy(opts.szRequiredHeaders, "NonExistent");
++	opts.pfnHeaderCallback = SignThisHeader;
++	while (1)
++	{
++		if ((ch = getopt(argc, argv, "lqtfhHSvVp:b:c:d:i:s:x:y:z:")) == -1)
++			break;
++		switch (ch)
++		{
++		case 'l': /*- body length tag */
++			opts.nIncludeBodyLengthTag = 1;
++			break;
++		case 'q': /*- query method tag */
++			opts.nIncludeQueryMethod = 1;
++			break;
++		case 'S':
++			nAllowUnsignedSubject = 0;
++			break;
++		case 'f':
++			nAllowUnsignedFromHeaders = 1;
++		case 't': /*- timestamp tag */
++			opts.nIncludeTimeStamp = 1;
++			break;
++		case 'h':
++			opts.nIncludeCopiedHeaders = 1;
++			break;
++		case 'H':
++			usage();
++			break;
++		case 'v': /*- verify */
++			bSign = 0;
++			break;
++		case 'V': /*- verbose */
++			verbose = 1;
++			break;
++		case 'p':
++			switch(*optarg)
++			{
++			case '1':
++				accept3ps = 1;
++				useSSP = 1;
++				useADSP = 0;
++				break;
++			case '2':
++				accept3ps = 1;
++				useSSP = 0;
++				useADSP = 1;
++				break;
++			case '3':
++				accept3ps = 1;
++				useSSP = 0;
++				useADSP = 0;
++				break;
++			case '0':
++				accept3ps = 0;
++				useSSP = 0;
++				useADSP = 0;
++				break;
++			default:
++				fprintf(stderr, "%s: unrecognized practice %c.\n", program, *optarg);
++				return (1);
++			}
++			break;
++		case 'b': /*- allman or ietf draft 1 or both */
++			switch (*optarg)
++			{
++			case '1':
++				opts.nIncludeBodyHash = DKIM_BODYHASH_ALLMAN_1;
++				break;
++			case '2':
++				opts.nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
++				break;
++			case '3':
++				opts.nIncludeBodyHash = DKIM_BODYHASH_BOTH;
++				break;
++			default:
++				fprintf(stderr, "%s: unrecognized standard %c.\n", program, *optarg);
++				return (1);
++			}
++			break;
++		case 'c':
++			switch (*optarg)
++			{
++			case 'r':
++				opts.nCanon = DKIM_SIGN_RELAXED;
++				break;
++			case 's':
++				opts.nCanon = DKIM_SIGN_SIMPLE;
++				break;
++			case 't':
++				opts.nCanon = DKIM_SIGN_RELAXED_SIMPLE;
++				break;
++			case 'u':
++				opts.nCanon = DKIM_SIGN_SIMPLE_RELAXED;
++				break;
++			default:
++				fprintf(stderr, "%s: unrecognized canonicalization.\n", program);
++				return (1);
++			}
++			break;
++		case 'd':
++			strncpy(opts.szDomain, optarg, sizeof (opts.szDomain) - 1);
++			break;
++		case 'i':	/*- identity */
++			if (*optarg == '-')
++				opts.szIdentity[0] = '\0';
++			else
++				strncpy(opts.szIdentity, optarg, sizeof (opts.szIdentity) - 1);
++			break;
++		case 's': /*- sign */
++			bSign = 1;
++			PrivKeyFile = optarg;
++			break;
++		case 'x': /*- expire time */
++			if (*optarg == '-')
++				opts.expireTime = 0;
++			else
++				opts.expireTime = t + atoi(optarg);
++			break;
++		case 'y':
++			strncpy(opts.szSelector, optarg, sizeof (opts.szSelector) - 1);
++			break;
++		case 'z': /*- sign w/ sha1, sha256 or both */
++#ifdef HAVE_EVP_SHA256
++			switch (*optarg)
++			{
++			case '1':
++				opts.nHash = DKIM_HASH_SHA1;
++				break;
++			case '2':
++				opts.nHash = DKIM_HASH_SHA256;
++				break;
++			case '3':
++				opts.nHash = DKIM_HASH_SHA1_AND_256;
++				break;
++			default:
++				fprintf(stderr, "%s: unrecognized hash.\n", program);
++				return (1);
++			}
++#else
++			opts.nHash = DKIM_HASH_SHA1;
++#endif
++			break;
++		} /*- switch (ch) */
++	}
++	if (bSign) { /*- sign */
++		if (!PrivKeyFile)
++		{
++			fprintf(stderr, "Private Key not provided\n");
++			usage();
++			return (1);
++		}
++		if (!opts.szSelector[0]) {
++			if ((pSig = strrchr(PrivKeyFile, '/'))) {
++				pSig++;
++				strcpy(opts.szSelector, pSig);
++			} else
++				strcpy(opts.szSelector, "private");
++		}
++		if ((PrivKeyFD = open(PrivKeyFile, O_RDONLY)) == -1) {
++			fprintf(stderr, "%s: %s\n", PrivKeyFile, strerror(errno));
++			return (1);
++		}
++		if (fstat(PrivKeyFD, &statbuf) == -1)
++		{
++			fprintf(stderr, "fstat: %s: %s\n", PrivKeyFile, strerror(errno));
++			return (1);
++		}
++		if (!(PrivKey = (char *) DKIM_MALLOC(sizeof(char) * ((nPrivKeyLen = statbuf.st_size) + 1))))
++		{
++			fprintf(stderr, "malloc: %ld bytes: %s\n", statbuf.st_size + 1, strerror(errno));
++			return (1);
++		}
++		if (read(PrivKeyFD, PrivKey, nPrivKeyLen) != nPrivKeyLen)
++		{
++			fprintf(stderr, "%s: read: %s\n", strerror(errno), program);
++			return (1);
++		}
++		close(PrivKeyFD);
++		PrivKey[nPrivKeyLen] = '\0';
++		if (DKIMSignInit(&ctxt, &opts) != DKIM_SUCCESS)
++		{
++			fprintf(stderr, "DKIMSignInit: failed to initialize signature %s\n", PrivKeyFile);
++			return (1);
++		}
++		for (;;)
++		{
++			if ((ret = read(0, Buffer, sizeof(Buffer) - 1)) == -1)
++			{
++				fprintf(stderr, "read: %s\n", strerror(errno));
++				DKIMSignFree(&ctxt);
++				return (1);
++			} else
++			if (!ret)
++				break;
++			if (DKIMSignProcess(&ctxt, Buffer, ret) == DKIM_INVALID_CONTEXT)
++			{
++				fprintf(stderr, "DKIMSignProcess: DKIMContext structure invalid for this operation\n");
++				DKIMSignFree(&ctxt);
++				return (1);
++			}
++		}
++		if (DKIMSignGetSig2(&ctxt, PrivKey, &pSig) == DKIM_INVALID_CONTEXT)
++		{
++			fprintf(stderr, "DKIMSignProcess: DKIMContext structure invalid for this operation\n");
++			DKIMSignFree(&ctxt);
++			return (1);
++		}
++		if (pSig)
++		{
++			fwrite(pSig, 1, strlen(pSig), stdout);
++			fwrite("\n", 1, 1, stdout);
++		}
++		DKIMSignFree(&ctxt);
++		return 0;
++	} else { /*- verify */
++		if (useADSP)
++			vopts.nCheckPractices = useADSP;
++		else
++		if (useSSP)
++			vopts.nCheckPractices = useSSP;
++		else
++			vopts.nCheckPractices = 0;
++		vopts.nAccept3ps = accept3ps;
++		vopts.pfnSelectorCallback = NULL;	/*- SelectorCallback; */
++		vopts.nAllowUnsignedFromHeaders = nAllowUnsignedFromHeaders;
++		vopts.nSubjectRequired = nAllowUnsignedSubject;
++		DKIMVerifyInit(&ctxt, &vopts);		/*- this is always successful */
++		for (;;)
++		{
++			if ((i = read(0, Buffer, sizeof(Buffer) - 1)) == -1)
++			{
++				fprintf(stderr, "read: %s\n", strerror(errno));
++				DKIMVerifyFree(&ctxt);
++				return (1);
++			} else
++			if (!i)
++				break;
++			ret = DKIMVerifyProcess(&ctxt, Buffer, i);
++			dkim_error(ret);
++			if (ret > 0 && ret < DKIM_FINISHED_BODY)
++				ret = DKIM_FAIL;
++			if (ret)
++				break;
++		}
++		if (!ret)
++		{
++			if ((ret = DKIMVerifyResults(&ctxt, &sCount, &sSize)) != DKIM_SUCCESS)
++				dkim_error(ret);
++			if ((ret = DKIMVerifyGetDetails(&ctxt, &nSigCount, &pDetails, szPolicy)) != DKIM_SUCCESS)
++				dkim_error(ret);
++			else
++			{
++				for (ret = 0,i = 0; i < nSigCount; i++) {
++					if (verbose)
++						printf("Signature # %02d: ", i + 1);
++					if (pDetails[i].nResult >= 0)
++					{
++						if (verbose)
++							printf("Success\n");
++						continue;
++					} else
++					{
++						ret = pDetails[i].nResult;
++						if (verbose)
++							printf("Failure %d\n", ret);
++					}
++				}
++				if (!nSigCount)
++					ret = DKIM_NO_SIGNATURES;
++			}
++		} 
++		if (ret < 0 || ret == DKIM_3PS_SIGNATURE) {
++			if (useADSP)
++			{
++				char           *domain;
++	
++				if ((domain = DKIMVerifyGetDomain(&ctxt)))
++					resDKIMADSP = GetADSP(domain);
++				if (sCount > 0) {
++					if (resDKIMADSP == DKIM_ADSP_UNKNOWN || resDKIMADSP == DKIM_ADSP_ALL)
++						ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
++				} 
++				/* if the message should be signed, return fail */
++				if (resDKIMADSP == DKIM_ADSP_DISCARDABLE)
++					ret = DKIM_FAIL;
++				ret = DKIM_NEUTRAL;
++			} else
++			if (useSSP)
++			{
++				int             bTestingPractices = 0;
++				char           *domain;
++
++				if ((domain = DKIMVerifyGetDomain(&ctxt)))
++					resDKIMSSP = GetSSP(domain, &bTestingPractices);
++				if (sCount > 0) {
++					if ((resDKIMSSP == DKIM_SSP_UNKNOWN || resDKIMSSP == DKIM_SSP_ALL))
++						ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
++				}
++				// if the SSP is testing, return neutral
++				if (bTestingPractices)
++					return(DKIM_NEUTRAL);
++				/* if the message should be signed, return fail */
++				if (resDKIMSSP == DKIM_SSP_ALL || resDKIMSSP == DKIM_SSP_STRICT)
++					return(DKIM_FAIL);
++				ret = DKIM_NEUTRAL;
++			}
++		}
++		DKIMVerifyFree(&ctxt);
++		writeHeader(ret, resDKIMSSP, resDKIMADSP, useSSP, useADSP);
++		if ((dkimverify = getenv("DKIMVERIFY")))
++		{
++			if (ret < 0)
++			{
++				if (dkimverify[str_chr(dkimverify, 'F' - ret)])
++					ret = 14; /*- return permanent error */
++				if (dkimverify[str_chr(dkimverify, 'f' - ret)])
++					ret = 88; /*- return temporary error */
++			} else
++			{
++				if (dkimverify[str_chr(dkimverify, 'A' + ret)])
++					ret = 14; /*- return permanent error */
++				if (dkimverify[str_chr(dkimverify, 'a' + ret)])
++					ret = 88; /*- return temporary error */
++			}
++		}
++		return (ret);
++	}
++	/*- Not Reached */
++	_exit(0);
++}
++
++void
++getversion_dkim_c()
++{
++	static char    *x = (char *) "$Id: dkim.c,v 1.19 2016-03-01 16:23:38+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkim.h netqmail-1.06/dkim.h
+--- ../netqmail-1.06-original/dkim.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkim.h	2018-04-03 14:46:51.364411606 +0200
+@@ -0,0 +1,193 @@
++/*
++ * $Log: dkim.h,v $
++ * Revision 1.8  2015-12-15 16:03:18+05:30  Cprogrammer
++ * use time_t for expireTime
++ *
++ * Revision 1.7  2011-06-04 13:56:06+05:30  Cprogrammer
++ * corrected return codes
++ *
++ * Revision 1.6  2011-06-04 10:04:00+05:30  Cprogrammer
++ * unified error code for signing & verifcation
++ * added signature and identity domain information to
++ *     DKIMVerifyDetails structure
++ *
++ * Revision 1.5  2009-03-27 20:19:05+05:30  Cprogrammer
++ * major changes made for incorporating ADSP
++ *
++ * Revision 1.4  2009-03-26 19:28:15+05:30  Cprogrammer
++ * removed DKIM_3PS_PARTIAL_SUCCESS
++ *
++ * Revision 1.3  2009-03-26 15:11:33+05:30  Cprogrammer
++ * added ADSP
++ *
++ * Revision 1.2  2009-03-25 08:37:58+05:30  Cprogrammer
++ * changed definitions of constants to avoid clash between error and success
++ *
++ * Revision 1.1  2009-03-21 08:50:19+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#define DKIM_CALL
++#define MAKELONG(a,b) ((long)(((unsigned)(a) & 0xffff) | (((unsigned)(b) & 0xffff) << 16)))
++
++#ifdef __cplusplus
++extern          "C" {
++#endif
++
++#include <time.h>
++// DKIM Body hash versions
++#define DKIM_BODYHASH_ALLMAN_1	1
++#define DKIM_BODYHASH_IETF_1	2
++#define DKIM_BODYHASH_BOTH		DKIM_BODYHASH_ALLMAN_1 | DKIM_BODYHASH_IETF_1
++
++// DKIM hash algorithms
++#define DKIM_HASH_SHA1			1
++#define DKIM_HASH_SHA256		2
++#define DKIM_HASH_SHA1_AND_256  DKIM_HASH_SHA1 | DKIM_HASH_SHA256
++
++// DKIM canonicalization methods
++#define DKIM_CANON_SIMPLE		1
++#define DKIM_CANON_NOWSP		2
++#define DKIM_CANON_RELAXED		3
++
++#define DKIM_SIGN_SIMPLE			MAKELONG(DKIM_CANON_SIMPLE,DKIM_CANON_SIMPLE)
++#define DKIM_SIGN_SIMPLE_RELAXED	MAKELONG(DKIM_CANON_RELAXED,DKIM_CANON_SIMPLE)
++#define DKIM_SIGN_RELAXED			MAKELONG(DKIM_CANON_RELAXED,DKIM_CANON_RELAXED)
++#define DKIM_SIGN_RELAXED_SIMPLE	MAKELONG(DKIM_CANON_SIMPLE,DKIM_CANON_RELAXED)
++
++// DKIM_SUCCESS                                 // verify result: all signatures verified
++// signature result: signature verified
++#define DKIM_SUCCESS						 0	// operation successful
++#define DKIM_FINISHED_BODY					 1	// process result: no more message body is needed
++#define DKIM_PARTIAL_SUCCESS				 2	// verify result: at least one but not all signatures verified
++#define DKIM_NEUTRAL						 3	// verify result: no signatures verified but message is not suspicous
++#define DKIM_SUCCESS_BUT_EXTRA				 4	// signature result: signature verified but it did not include all of the body
++#define DKIM_3PS_SIGNATURE					 5	// 3rd-party signature
++
++// DKIM Error codes
++#define DKIM_FAIL							-1	// verify error: message is suspicious
++#define DKIM_BAD_SYNTAX						-2	// signature error: DKIM-Signature could not parse or has bad tags/values
++#define DKIM_SIGNATURE_BAD					-3	// signature error: RSA verify failed
++#define DKIM_SIGNATURE_BAD_BUT_TESTING		-4	// signature error: RSA verify failed but testing
++#define DKIM_SIGNATURE_EXPIRED				-5	// signature error: x= is old
++#define DKIM_SELECTOR_INVALID				-6	// signature error: selector doesn't parse or contains invalid values
++#define DKIM_SELECTOR_GRANULARITY_MISMATCH	-7	// signature error: selector g= doesn't match i=
++#define DKIM_SELECTOR_KEY_REVOKED			-8	// signature error: selector p= empty
++#define DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG	-9	// signature error: selector domain name too long to request
++#define DKIM_SELECTOR_DNS_TEMP_FAILURE		-10	// signature error: temporary dns failure requesting selector
++#define DKIM_SELECTOR_DNS_PERM_FAILURE		-11	// signature error: permanent dns failure requesting selector
++#define DKIM_SELECTOR_PUBLIC_KEY_INVALID	-12	// signature error: selector p= value invalid or wrong format
++#define DKIM_NO_SIGNATURES					-13	// process error, no sigs
++#define DKIM_NO_VALID_SIGNATURES			-14	// process error, no valid sigs
++#define DKIM_BODY_HASH_MISMATCH				-15	// sigature verify error: message body does not hash to bh value
++#define DKIM_SELECTOR_ALGORITHM_MISMATCH	-16	// signature error: selector h= doesn't match signature a=
++#define DKIM_STAT_INCOMPAT					-17	// signature error: incompatible v=
++#define DKIM_UNSIGNED_FROM                  -18 // signature error: not all message's From headers in signature
++#define DKIM_OUT_OF_MEMORY                  -19 // memory allocation failed
++#define DKIM_INVALID_CONTEXT                -20 // DKIMContext structure invalid for this operation
++#define DKIM_NO_SENDER                      -21 // signing error: Could not find From: or Sender: header in message
++#define DKIM_BAD_PRIVATE_KEY                -22 // signing error: Could not parse private key
++#define DKIM_BUFFER_TOO_SMALL               -23 // signing error: Buffer passed in is not large enough
++#define DKIM_MAX_ERROR                      -24 // set this to 1 greater than the highest error code (but negative)
++
++#define DKIM_SSP_UNKNOWN			 1 /*- some messages may be signed */
++#define DKIM_SSP_ALL				 2 /*- all messages are signed, 3rd party allowed */
++#define DKIM_SSP_STRICT				 3 /*- all messages are signed, no 3rd party allowed */
++#define DKIM_SSP_SCOPE				 4 /*- the domain should be considered invalid */
++#define DKIM_SSP_TEMPFAIL			 5 /*- Temporary Error */
++
++#define DKIM_ADSP_UNKNOWN			 1 /*- some messages may be signed */
++#define DKIM_ADSP_ALL				 2 /*- All message are signed with author signature */
++#define DKIM_ADSP_DISCARDABLE		 3 /*- messages which fail verification are Discardable */
++#define DKIM_ADSP_SCOPE				 4 /*- domain is out of scope */
++#define DKIM_ADSP_TEMPFAIL			 5 /*- Temporary Error */
++
++
++// This function is called once for each header in the message
++// return 1 to include this header in the signature and 0 to exclude.
++typedef int     (DKIM_CALL * DKIMHEADERCALLBACK) (const char *szHeader);
++
++// This function is called to retrieve a TXT record from DNS
++typedef int     (DKIM_CALL * DKIMDNSCALLBACK) (const char *szFQDN, char *szBuffer, int nBufLen);
++
++typedef struct DKIMContext_t {
++	unsigned int    reserved1;
++	unsigned int    reserved2;
++	void           *reserved3;
++} DKIMContext;
++
++typedef struct DKIMSignOptions_t {
++	int             nCanon;	// canonization 
++	int             nIncludeBodyLengthTag;	// 0 = don't include l= tag, 1 = include l= tag
++	int             nIncludeTimeStamp;	// 0 = don't include t= tag, 1 = include t= tag
++	int             nIncludeQueryMethod;	// 0 = don't include q= tag, 1 = include q= tag
++	char            szSelector[80];	// selector - required
++	char            szDomain[256];	// domain - optional - if empty, domain is computed from sender
++	char            szIdentity[256];	// for i= tag, if empty tag will not be included in sig
++	time_t          expireTime;	// for x= tag, if 0 tag will not be included in sig
++	DKIMHEADERCALLBACK pfnHeaderCallback;	// header callback
++	char            szRequiredHeaders[256];	// colon-separated list of headers that must be signed
++	int             nHash;	// use one of the DKIM_HASH_xx constants here
++	// even if not present in the message
++	int             nIncludeCopiedHeaders;	// 0 = don't include z= tag, 1 = include z= tag
++	int             nIncludeBodyHash;	// use one of the DKIM_BODYHASH_xx constants here
++} DKIMSignOptions;
++
++typedef struct DKIMVerifyOptions_t {
++	DKIMDNSCALLBACK pfnSelectorCallback;	// selector record callback
++	DKIMDNSCALLBACK pfnPracticesCallback;	// SSP record callback
++	int             nHonorBodyLengthTag;	// 0 = ignore l= tag, 1 = use l= tag to limit the amount of body verified
++	int             nCheckPractices;		// 0 = use default (unknown) practices, 1 = request and use sender's signing practices
++	int             nSubjectRequired;		// 0 = subject is required to be signed, 1 = not required
++	int             nSaveCanonicalizedData;	// 0 = canonicalized data is not saved, 1 = canonicalized data is saved
++	int             nAllowUnsignedFromHeaders;	// 0 = From headers not included in the signature are not allowed, 1 = allowed
++	int             nAccept3ps;				// 0 = don't check 3rd party signature(s), 1 = check 3rd party signature(s)
++} DKIMVerifyOptions;
++
++typedef struct DKIMVerifyDetails_t {
++	char           *szSignature;
++	char           *DNS;
++	char           *szSignatureDomain;
++	char           *szIdentityDomain;
++	char           *szCanonicalizedData;
++	int             nResult;
++} DKIMVerifyDetails;
++
++int DKIM_CALL   DKIMSignInit(DKIMContext *pSignContext, DKIMSignOptions * pOptions);
++int DKIM_CALL   DKIMSignProcess(DKIMContext *pSignContext, char *szBuffer, int nBufLength);
++int DKIM_CALL   DKIMSignGetSig(DKIMContext *pSignContext, char *szPrivKey, char *szSignature, int nSigLength);
++int DKIM_CALL   DKIMSignGetSig2(DKIMContext *pSignContext, char *szPrivKey, char **pszSignature);
++void DKIM_CALL  DKIMSignFree(DKIMContext *pSignContext);
++char           *DKIM_CALL DKIMSignGetDomain(DKIMContext *pSignContext);
++
++int DKIM_CALL   DKIMVerifyInit(DKIMContext *pVerifyContext, DKIMVerifyOptions * pOptions);
++int DKIM_CALL   DKIMVerifyProcess(DKIMContext *pVerifyContext, char *szBuffer, int nBufLength);
++int DKIM_CALL   DKIMVerifyResults(DKIMContext *pVerifyContext , int *sCount, int *sSize);
++int DKIM_CALL   DKIMVerifyGetDetails(DKIMContext *pVerifyContext, int *nSigCount, DKIMVerifyDetails **pDetails, char *szPractices);
++char           *DKIM_CALL DKIMVerifyGetDomain(DKIMContext *pVerifyContext);
++void DKIM_CALL  DKIMVerifyFree(DKIMContext *pVerifyContext);
++char           *DKIM_CALL DKIMVersion();
++char           *DKIM_CALL DKIMGetErrorString(int ErrorCode);
++#include "macros.h"
++#ifdef __cplusplus
++}
++#endif
+diff -ruN ../netqmail-1.06-original/dkimbase.cpp netqmail-1.06/dkimbase.cpp
+--- ../netqmail-1.06-original/dkimbase.cpp	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimbase.cpp	2018-04-03 14:46:51.363411603 +0200
+@@ -0,0 +1,336 @@
++/*
++ * $Log: dkimbase.cpp,v $
++ * Revision 1.4  2017-09-05 10:58:26+05:30  Cprogrammer
++ * removed compiler warnings
++ *
++ * Revision 1.3  2009-03-26 15:10:32+05:30  Cprogrammer
++ * fixed indentation
++ *
++ * Revision 1.2  2009-03-25 08:37:27+05:30  Cprogrammer
++ * fixed indentation
++ *
++ * Revision 1.1  2009-03-21 08:43:08+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#include "dkim.h"
++#include "dkimbase.h"
++#include <string.h>
++#include <algorithm>
++
++CDKIMBase::CDKIMBase()
++{
++	m_From = NULL;
++	m_Sender = NULL;
++	m_hTag = NULL;
++	m_hTagSize = 0;
++	m_hTagPos = 0;
++	m_Line = NULL;
++	m_LineSize = 0;
++	m_LinePos = 0;
++	m_InHeaders = true;
++}
++
++CDKIMBase::~CDKIMBase()
++{
++	Free(m_Line);
++	Free(m_From);
++	Free(m_Sender);
++	Free(m_hTag);
++}
++
++int
++CDKIMBase::Init(void)
++{
++	return DKIM_SUCCESS;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Alloc - allocate buffer
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::Alloc(char *&szBuffer, int nRequiredSize)
++{
++	szBuffer = new char[nRequiredSize];
++
++	return (szBuffer == NULL) ? DKIM_OUT_OF_MEMORY : DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// ReAlloc - extend buffer if necessary, leaving room for future expansion
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::ReAlloc(char *&szBuffer, int &nBufferSize, int nRequiredSize)
++{
++	if (nRequiredSize > nBufferSize) {
++		char           *
++			newp;
++		int
++			nNewSize = nRequiredSize + BUFFER_ALLOC_INCREMENT;
++
++		if (Alloc(newp, nNewSize) == DKIM_SUCCESS) {
++			if (szBuffer != NULL && nBufferSize > 0) {
++				memcpy(newp, szBuffer, nBufferSize);
++				delete[]szBuffer;
++			}
++			szBuffer = newp;
++			nBufferSize = nNewSize;
++		} else {
++			return DKIM_OUT_OF_MEMORY;	// memory alloc error!
++		}
++	}
++	return DKIM_SUCCESS;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Process - split buffers into lines without any CRs or LFs at the end.
++//
++////////////////////////////////////////////////////////////////////////////////
++void CDKIMBase::Free(char *szBuffer)
++{
++	if (szBuffer)
++		delete[]szBuffer;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Process - split buffers into lines without any CRs or LFs at the end.
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::Process(char *szBuffer, int nBufLength, bool bEOF)
++{
++	char           *p = szBuffer;
++	char           *e = szBuffer + nBufLength;
++
++	while (p < e) {
++		if (*p != '\n' && *p != '\r') {
++			if (m_LinePos >= m_LineSize) {
++				int nRet = ReAlloc(m_Line, m_LineSize, m_LinePos + 1);
++				if (nRet != DKIM_SUCCESS)
++							/*
++							 * How to distinguish between
++							 * DKIM_FINISHED_BODY & DKIM_OUT_OF_MEMORY
++							 */
++					return nRet;
++			}
++			m_Line[m_LinePos++] = *p;
++		} else {
++			if (*p == '\r' && p + 1 < e && *(p + 1) == '\n')
++				p++;
++			if (m_InHeaders) {
++			// process header line
++				if (m_LinePos == 0) {
++					m_InHeaders = false;
++					int Result = ProcessHeaders();
++					if (Result != DKIM_SUCCESS)
++						return Result;
++				} else {
++				// append the header to the headers list
++					if (m_Line[0] != ' ' && m_Line[0] != '\t') {
++						HeaderList.push_back(string(m_Line, m_LinePos));
++					} else {
++						if (!HeaderList.empty()) {
++							HeaderList.back().append("\r\n", 2).append(m_Line, m_LinePos);
++						} else {
++						// no header to append to...
++						}
++					}
++				}
++			} else {
++				// process body line
++				int Result = ProcessBody(m_Line, m_LinePos, bEOF);
++				if (Result != DKIM_SUCCESS) {
++					m_LinePos = 0;
++					return Result;
++				}
++			}
++			m_LinePos = 0;
++		}
++		p++;
++	}
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// ProcessFinal - process leftovers if stopping before the body or mid-line
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::ProcessFinal(void)
++{
++	if (m_LinePos > 0) {
++		Process((char *) "\r\n", 2, true);
++	}
++
++	if (m_InHeaders) {
++		m_InHeaders = false;
++		ProcessHeaders();
++		ProcessBody((char *) "", 0, true);
++	}
++
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// ProcessHeaders - process the headers (to be implemented by derived class)
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::ProcessHeaders()
++{
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// ProcessBody - process body line (to be implemented by derived class)
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMBase::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
++{
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// RemoveSWSP - remove streaming white space from buffer/string inline
++//
++////////////////////////////////////////////////////////////////////////////////
++
++struct isswsp {
++	bool
++	operator() (char ch) {
++		return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
++	}
++};
++
++void CDKIMBase::RemoveSWSP(char *szBuffer)
++{
++	*remove_if(szBuffer, szBuffer + strlen(szBuffer), isswsp()) = '\0';
++}
++
++void CDKIMBase::RemoveSWSP(char *pBuffer, int &nBufLength)
++{
++	nBufLength = remove_if(pBuffer, pBuffer + nBufLength, isswsp()) - pBuffer;
++}
++
++void CDKIMBase::RemoveSWSP(string &sBuffer)
++{
++	sBuffer.erase(remove_if(sBuffer.begin(), sBuffer.end(), isswsp()), sBuffer.end());
++}
++
++
++//////////////////////////////////////////////////////////////////////////////////////////
++// 
++// CompressSWSP - compress streaming white space into single spaces from buffer/string inline
++//
++//////////////////////////////////////////////////////////////////////////////////////////
++
++void CDKIMBase::CompressSWSP(char *pBuffer, int &nBufLength)
++{
++	char           *pSrc = pBuffer;
++	char           *pDst = pBuffer;
++	char           *pEnd = pBuffer + nBufLength;
++
++	while (pSrc != pEnd) {
++		if (isswsp()(*pSrc)) {
++			do {
++				++pSrc;
++			} while (pSrc != pEnd && isswsp()(*pSrc));
++			if (pSrc == pEnd)
++				break;
++			*pDst++ = ' ';
++		}
++		*pDst++ = *pSrc++;
++	}
++	nBufLength = pDst - pBuffer;
++}
++
++void CDKIMBase::CompressSWSP(string &sBuffer)
++{
++	string::iterator iSrc = sBuffer.begin();
++	string::iterator iDst = sBuffer.begin();
++	string::iterator iEnd = sBuffer.end();
++
++	while (iSrc != iEnd) {
++		if (isswsp()(*iSrc)) {
++			do {
++				++iSrc;
++			} while (iSrc != iEnd && isswsp()(*iSrc));
++
++			if (iSrc == iEnd)
++				break;
++			*iDst++ = ' ';
++		}
++		*iDst++ = *iSrc++;
++	}
++	sBuffer.erase(iDst, iEnd);
++}
++
++//////////////////////////////////////////////////////////////////////////////////////////
++// 
++// RelaxHeader - relax a header field (lower case the name, remove swsp before and after :)
++//
++// modified 4/21/06 STB to remove white space before colon
++//
++//////////////////////////////////////////////////////////////////////////////////////////
++
++string CDKIMBase::RelaxHeader(const string &sHeader)
++{
++	string sTemp = sHeader;
++
++	CompressSWSP(sTemp);
++
++	int cpos = sTemp.find(':');
++	if (cpos == -1) {
++	// no colon?!
++	} else {
++	// lower case the header field name
++		for (int i = 0; i < cpos; i++) {
++			if (sTemp[i] >= 'A' && sTemp[i] <= 'Z')
++				sTemp[i] += 'a' - 'A';
++		}
++	// remove the space after the :
++		if ((unsigned int) (cpos + 1) < sTemp.length() && sTemp[cpos + 1] == ' ')
++			sTemp.erase(cpos + 1, 1);
++	// remove the space before the :
++		if (cpos > 0 && sTemp[cpos - 1] == ' ')
++			sTemp.erase(cpos - 1, 1);
++	}
++	return sTemp;
++}
++
++void
++getversion_dkimbase_cpp()
++{
++	static char    *x = (char *) "$Id: dkimbase.cpp,v 1.4 2017-09-05 10:58:26+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkimbase.h netqmail-1.06/dkimbase.h
+--- ../netqmail-1.06-original/dkimbase.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimbase.h	2018-04-03 14:46:51.363411603 +0200
+@@ -0,0 +1,72 @@
++/*
++ * $Log: dkimbase.h,v $
++ * Revision 1.1  2009-03-21 08:50:18+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#ifndef DKIMBASE_H
++#define DKIMBASE_H
++
++#include <openssl/evp.h>
++#include <openssl/pem.h>
++#include <openssl/err.h>
++
++#define BUFFER_ALLOC_INCREMENT	256
++
++#include <string>
++#include <list>
++
++using namespace std;
++class           CDKIMBase {
++public:
++
++	CDKIMBase();
++	~CDKIMBase();
++
++	int             Init(void);
++	int             Process(char *szBuffer, int nBufLength, bool bEOF);
++	int             ProcessFinal(void);
++	int             Alloc(char *&szBuffer, int nRequiredSize);
++	int             ReAlloc(char *&szBuffer, int &nBufferLength, int nRequiredSize);
++	void            Free(char *szBuffer);
++	static void     RemoveSWSP(char *szBuffer);
++	static void     RemoveSWSP(char *pBuffer, int &nBufLength);
++	static void     RemoveSWSP(string & sBuffer);
++	static void     CompressSWSP(char *pBuffer, int &nBufLength);
++	static void     CompressSWSP(string & sBuffer);
++	static string   RelaxHeader(const string & sHeader);
++	virtual int     ProcessHeaders(void);
++	virtual int     ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
++
++protected:
++	char           *m_From;
++	char           *m_Sender;
++	char           *m_hTag;
++	int             m_hTagSize;
++	int             m_hTagPos;
++	char           *m_Line;
++	int             m_LineSize;
++	int             m_LinePos;
++	bool            m_InHeaders;
++	                list < string > HeaderList;
++};
++#endif	/*- DKIMBASE_H */
+diff -ruN ../netqmail-1.06-original/dkimdns.cpp netqmail-1.06/dkimdns.cpp
+--- ../netqmail-1.06-original/dkimdns.cpp	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimdns.cpp	2018-04-03 14:46:51.364411606 +0200
+@@ -0,0 +1,322 @@
++/*
++ * $Log: dns.cpp,v $
++ * Revision 1.10  2017-09-05 11:01:06+05:30  Cprogrammer
++ * removed unused variables
++ *
++ * Revision 1.9  2017-09-01 12:46:27+05:30  Cprogrammer
++ * fixed double free() of dnresult
++ *
++ * Revision 1.8  2017-08-09 22:06:33+05:30  Cprogrammer
++ * fixed resolve() function
++ *
++ * Revision 1.7  2017-05-16 12:40:23+05:30  Cprogrammer
++ * refactored dns_text() function
++ *
++ * Revision 1.6  2017-05-10 14:58:06+05:30  Cprogrammer
++ * increase responselen to 1024 for long text records
++ *
++ * Revision 1.5  2017-05-10 12:27:49+05:30  Cprogrammer
++ * use packetsize > 512 to avoid dkim failures for sites having long txt records (hotmail.com)
++ *
++ * Revision 1.4  2009-06-11 13:58:39+05:30  Cprogrammer
++ * port for DARWIN
++ *
++ * Revision 1.3  2009-03-27 19:22:45+05:30  Cprogrammer
++ * dns functions
++ *
++ */
++#include <netdb.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <netinet/in.h>
++#ifdef DARWIN
++#include <nameser8_compat.h>
++#endif
++#include <arpa/nameser.h>
++#include <resolv.h>
++#include <string.h>
++#include "dkimdns.h"
++
++static unsigned short
++getshort(unsigned char *cp)
++{
++	return (cp[0] << 8) | cp[1];
++}
++
++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 int
++resolve(char *domain, int type)
++{
++	int             n, i;
++	unsigned char  *ptr;
++
++	errno = 0;
++	if (!responsebuflen) {
++		if ((response.buf = (unsigned char *) malloc(PACKETSZ + 1)))
++			responsebuflen = PACKETSZ + 1;
++		else
++			return DNS_MEM;
++	}
++	responselen = res_query(domain, C_IN, type, response.buf, responsebuflen);
++	if ((responselen >= responsebuflen) || (responselen > 0 && (((HEADER *) response.buf)->tc))) {
++		if (responsebuflen < 65536) {
++			if ((ptr = (unsigned char *) realloc((void *) response.buf, 65536))) {
++				response.buf = ptr;
++				responsebuflen = 65536;
++			} else {
++				free(response.buf);
++				responsebuflen = 0;
++				return DNS_MEM;
++			}
++		}
++		saveresoptions = _res.options;
++		_res.options |= RES_USEVC;
++		responselen = res_query(domain, 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;
++	}
++	responseend = response.buf + responselen;
++	responsepos = response.buf + sizeof(HEADER);
++	n = ntohs(((HEADER *) response.buf)->qdcount);
++	while (n-- > 0) {
++		if ((i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME)) < 0)
++			return DNS_SOFT;
++		responsepos += i;
++		i = responseend - responsepos;
++		if (i < QFIXEDSZ)
++			return DNS_SOFT;
++		responsepos += QFIXEDSZ;
++	}
++	numanswers = ntohs(((HEADER *) response.buf)->ancount);
++	return 0;
++}
++
++void
++byte_copy(register char *to, register unsigned int n, register char *from)
++{
++	for (;;) {
++		if (!n)
++			return;
++		*to++ = *from++;
++		--n;
++		if (!n)
++			return;
++		*to++ = *from++;
++		--n;
++		if (!n)
++			return;
++		*to++ = *from++;
++		--n;
++		if (!n)
++			return;
++		*to++ = *from++;
++		--n;
++	}
++}
++
++static char     *txt;
++static int      txtlen;
++
++static int
++findtxt(int wanttype, int *txt_strlen)
++{
++	unsigned short  rrtype, rrdlen;
++	char           *ptr;
++	int             i;
++
++	if (numanswers <= 0)
++		return 2;
++	--numanswers;
++	if (responsepos == responseend)
++		return DNS_SOFT;
++
++	if ((i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME)) < 0)
++		return DNS_SOFT;
++	responsepos += i;
++
++	if ((i = responseend - responsepos) < 4 + 3 * 3)
++		return DNS_SOFT;
++
++	rrtype = getshort(responsepos);
++	rrdlen = getshort(responsepos + 8);
++	responsepos += 10;
++
++	*txt_strlen = 0;
++	if (!txtlen) {
++		if (!(txt = (char *) malloc(PACKETSZ * 2 * sizeof(char))))
++			return DNS_MEM;
++		txtlen = PACKETSZ * 2;
++	}
++	if (rrtype == wanttype) {
++		unsigned short  txtpos;
++		unsigned char   n;
++
++		*txt = 0;
++		for (txtpos = 0; txtpos < rrdlen; txtpos += n) {
++			n = responsepos[txtpos++];
++			if (n > rrdlen - txtpos)
++				n = rrdlen - txtpos;
++			if ((*txt_strlen + n + 1) > txtlen) {
++				if (!(ptr = (char *) realloc(txt, (*txt_strlen + n) * 2)))
++					return DNS_MEM;
++				txtlen = (*txt_strlen + n) * 2;
++			}
++			byte_copy(txt + *txt_strlen, n, (char *) &responsepos[txtpos]);
++			*txt_strlen += n;
++		}
++		responsepos += rrdlen;
++		txt[*txt_strlen] = 0;
++		return 1;
++	}
++	responsepos += rrdlen;
++	return 0;
++}
++
++static char    *dnresult;
++static int      dnresultlen;
++
++static int
++dns_txtplus(char *domain)
++{
++	int             r, len, total;
++	char           *ptr;
++
++	switch (resolve(domain, T_TXT))
++	{
++	case DNS_MEM:
++		return DNS_MEM;
++	case DNS_SOFT:
++		return DNS_SOFT;
++	case DNS_HARD:
++		return DNS_HARD;
++	}
++	total = 0;
++	if (!dnresultlen) {
++		if (!(dnresult = (char *) malloc ((2 * PACKETSZ) * sizeof(char))))
++			return DNS_MEM;
++		dnresultlen = 2 * PACKETSZ;
++	}
++	while ((r = findtxt(T_TXT, &len)) != 2) {
++		if (r == DNS_SOFT) {
++			if (txtlen) {
++				txtlen = 0;
++				free(txt);
++			}
++			return DNS_SOFT;
++		}
++		if (r == 1) {
++			if ((total + len + 1) >= dnresultlen) {
++				if (!(ptr = (char *) realloc(dnresult, (total + len) * 2))) {
++					dnresultlen = 0;
++					if (txtlen) {
++						txtlen = 0;
++						free(txt);
++					}
++					return DNS_MEM;
++				}
++				dnresultlen = (total + len) * 2;
++			}
++			byte_copy(dnresult + total, len, txt);
++			total += len;
++		}
++	}
++	if (txtlen) {
++		txtlen = 0;
++		free(txt);
++	}
++	if (total) {
++		dnresult[total] = 0;
++		return (0);
++	}
++	return DNS_HARD;
++}
++
++/*
++ * we always return a null-terminated string which has been malloc'ed.  The string
++ * is always in the tag=value form.  If a temporary or permanent error occurs,
++ * the string will be exactly "e=perm;" or "e=temp;".
++ * Note that it never returns NULL.
++ */
++char           *
++dns_text(char *dn)
++{
++	int             r;
++	
++	switch (r = dns_txtplus(dn))
++	{
++	case DNS_MEM:
++	case DNS_SOFT:
++		if (responsebuflen) {
++			free(response.buf);
++			responsebuflen = 0;
++		}
++		return strdup("e=temp;");
++	case DNS_HARD:
++		if (responsebuflen) {
++			free(response.buf);
++			responsebuflen = 0;
++		}
++		return strdup("e=perm;");
++	}
++	if (responsebuflen) {
++		free(response.buf);
++		responsebuflen = 0;
++	}
++	return dnresult;
++}
++
++
++int
++DNSGetTXT(const char *domain, char *buffer, int maxlen)
++{
++	char           *results;
++	int             len;
++
++	results = dns_text((char *) domain);
++	if (!strcmp(results, "e=perm;")) {
++		free(results);
++		dnresultlen = 0;
++		return DNSRESP_PERM_FAIL;
++	} else
++	if (!strcmp(results, "e=temp;")) {
++		free(results);
++		dnresultlen = 0;
++		return DNSRESP_TEMP_FAIL;
++	}
++	if ((len = strlen(results)) > maxlen - 1) {
++		free(results);
++		dnresultlen = 0;
++		return DNSRESP_DOMAIN_NAME_TOO_LONG;
++	}
++	byte_copy(buffer, len, results);
++	buffer[len] = 0;
++	free(results);
++	dnresultlen = 0;
++	return DNSRESP_SUCCESS;
++}
++
++void
++getversion_dkimdns_cpp()
++{
++	static char    *x = (char *) "$Id: dns.cpp,v 1.10 2017-09-05 11:01:06+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkimdns.h netqmail-1.06/dkimdns.h
+--- ../netqmail-1.06-original/dkimdns.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimdns.h	2018-04-03 14:46:51.364411606 +0200
+@@ -0,0 +1,54 @@
++/*
++ * $Log: dns.h,v $
++ * Revision 1.4  2017-05-16 12:40:39+05:30  Cprogrammer
++ * define DNS_SOFT, DNS_HARD and DNS_MEM
++ *
++ * Revision 1.3  2009-03-27 20:40:16+05:30  Cprogrammer
++ * removed windows definitions
++ *
++ * Revision 1.2  2009-03-27 19:23:01+05:30  Cprogrammer
++ * added dns_text()
++ *
++ * Revision 1.1  2009-03-21 08:50:24+05:30  Cprogrammer
++ * Initial revision
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++// These DNS resolution routines are encapsulated by the API below
++
++// return values for DNS functions:
++
++
++#define MAX_DOMAIN			254
++
++#define DNSRESP_SUCCESS					0	// DNS lookup returned sought after records
++#define DNSRESP_TEMP_FAIL				1	// No response from DNS server
++#define DNSRESP_PERM_FAIL				2	// DNS server returned error or no records
++#define DNSRESP_DOMAIN_NAME_TOO_LONG	3	// Domain name too long
++#define DNSRESP_NXDOMAIN				4	// DNS server returned Name Error
++#define DNSRESP_EMPTY					5	// DNS server returned successful response but no records
++
++#define DNS_SOFT -1
++#define DNS_HARD -2
++#define DNS_MEM  -3
++
++// Pass in the FQDN to get the TXT record
++int             DNSGetTXT(const char *szFQDN, char *Buffer, int nBufLen);
++char           *dns_text(char *szFQDN);
+diff -ruN ../netqmail-1.06-original/dkimfuncs.cpp netqmail-1.06/dkimfuncs.cpp
+--- ../netqmail-1.06-original/dkimfuncs.cpp	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimfuncs.cpp	2018-04-03 14:46:51.364411606 +0200
+@@ -0,0 +1,236 @@
++/*
++ * $Log: dkimfuncs.cpp,v $
++ * Revision 1.4  2011-06-04 10:06:33+05:30  Cprogrammer
++ * unified error strings for signing & verification
++ *
++ * Revision 1.3  2009-04-15 20:45:29+05:30  Cprogrammer
++ * code beautified
++ *
++ * Revision 1.2  2009-03-26 15:11:12+05:30  Cprogrammer
++ * added GetDomain(), ADSP
++ *
++ * Revision 1.1  2009-03-21 08:43:10+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++#include "dkim.h"
++#include "dkimsign.h"
++#include "dkimverify.h"
++#include <string.h>
++
++#define DKIMID ('D' | 'K'<<8 | 'I'<<16 | 'M'<<24)
++
++static void
++InitContext(DKIMContext *pContext, bool bSign, void *pObject)
++{
++	pContext->reserved1 = DKIMID;
++	pContext->reserved2 = bSign ? 1 : 0;
++	pContext->reserved3 = pObject;
++}
++
++static void    *
++ValidateContext(DKIMContext *pContext, bool bSign)
++{
++	if (pContext->reserved1 != DKIMID)
++		return NULL;
++	if (pContext->reserved2 != (unsigned int) (bSign ? 1 : 0))
++		return NULL;
++	return pContext->reserved3;
++}
++
++int             DKIM_CALL
++DKIMSignInit(DKIMContext *pSignContext, DKIMSignOptions *pOptions)
++{
++	int             nRet = DKIM_OUT_OF_MEMORY;
++	CDKIMSign      *pSign = new CDKIMSign;
++
++	if (pSign) {
++		nRet = pSign->Init(pOptions);
++		if (nRet != DKIM_SUCCESS)
++			delete          pSign;
++	}
++	if (nRet == DKIM_SUCCESS)
++		InitContext(pSignContext, true, pSign);
++	return nRet;
++}
++
++int             DKIM_CALL
++DKIMSignProcess(DKIMContext *pSignContext, char *szBuffer, int nBufLength)
++{
++	CDKIMSign      *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
++	if (pSign)
++		return pSign->Process(szBuffer, nBufLength, false);
++	return DKIM_INVALID_CONTEXT;
++}
++
++int             DKIM_CALL
++DKIMSignGetSig(DKIMContext *pSignContext, char *szPrivKey, char *szSignature, unsigned int nSigLength)
++{
++	CDKIMSign      *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
++	if (pSign)
++		return pSign->GetSig(szPrivKey, szSignature, nSigLength);
++	return DKIM_INVALID_CONTEXT;
++}
++
++int             DKIM_CALL
++DKIMSignGetSig2(DKIMContext *pSignContext, char *szPrivKey, char **pszSignature)
++{
++	CDKIMSign      *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
++	if (pSign)
++		return pSign->GetSig2(szPrivKey, pszSignature);
++	return DKIM_INVALID_CONTEXT;
++}
++
++char           *DKIM_CALL
++DKIMSignGetDomain(DKIMContext *pSignContext)
++{
++	CDKIMSign      *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
++	if (pSign)
++		return pSign->GetDomain();
++	return ((char *) 0);
++}
++
++void            DKIM_CALL
++DKIMSignFree(DKIMContext *pSignContext)
++{
++	CDKIMSign      *pSign = (CDKIMSign *) ValidateContext(pSignContext, true);
++	if (pSign) {
++		delete          pSign;
++		pSignContext->reserved3 = NULL;
++	}
++}
++
++int             DKIM_CALL
++DKIMVerifyInit(DKIMContext *pVerifyContext, DKIMVerifyOptions *pOptions)
++{
++	int             nRet = DKIM_OUT_OF_MEMORY;
++	CDKIMVerify    *pVerify = new CDKIMVerify;
++	if (pVerify) {
++		nRet = pVerify->Init(pOptions);
++		if (nRet != DKIM_SUCCESS)
++			delete          pVerify;
++	}
++	if (nRet == DKIM_SUCCESS)
++		InitContext(pVerifyContext, false, pVerify);
++	return nRet;
++}
++
++int             DKIM_CALL
++DKIMVerifyProcess(DKIMContext *pVerifyContext, char *szBuffer, int nBufLength)
++{
++	CDKIMVerify    *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
++	if (pVerify)
++		return pVerify->Process(szBuffer, nBufLength, false);
++	return DKIM_INVALID_CONTEXT;
++}
++
++int             DKIM_CALL
++DKIMVerifyResults( DKIMContext *pVerifyContext , int *sCount, int *sSize)
++{
++	CDKIMVerify    *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
++	if (pVerify)
++		return pVerify->GetResults(sCount, sSize);
++	return DKIM_INVALID_CONTEXT;
++}
++
++int             DKIM_CALL
++DKIMVerifyGetDetails(DKIMContext *pVerifyContext, int *nSigCount, DKIMVerifyDetails **pDetails, char *szPractices)
++{
++	szPractices[0] = '\0';
++	CDKIMVerify    *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
++	if (pVerify) {
++		strcpy(szPractices, pVerify->GetPractices());
++		return pVerify->GetDetails(nSigCount, pDetails);
++	}
++	return DKIM_INVALID_CONTEXT;
++}
++
++void            DKIM_CALL
++DKIMVerifyFree(DKIMContext *pVerifyContext)
++{
++	CDKIMVerify    *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
++	if (pVerify) {
++		delete          pVerify;
++		pVerifyContext->reserved3 = NULL;
++	}
++}
++
++char           *DKIM_CALL
++DKIMVerifyGetDomain(DKIMContext *pVerifyContext)
++{
++	CDKIMVerify    *pVerify = (CDKIMVerify *) ValidateContext(pVerifyContext, false);
++	if (pVerify)
++		return pVerify->GetDomain();
++	return ((char *) 0);
++}
++
++char           *DKIM_CALL
++DKIMVersion()
++{
++	return (char *) "1.4";
++}
++
++static char    *DKIMErrorStrings[-1 - DKIM_MAX_ERROR] = {
++	(char *) "DKIM_FAIL",
++	(char *) "DKIM_BAD_SYNTAX",
++	(char *) "DKIM_SIGNATURE_BAD",
++	(char *) "DKIM_SIGNATURE_BAD_BUT_TESTING",
++	(char *) "DKIM_SIGNATURE_EXPIRED",
++	(char *) "DKIM_SELECTOR_INVALID",
++	(char *) "DKIM_SELECTOR_GRANULARITY_MISMATCH",
++	(char *) "DKIM_SELECTOR_KEY_REVOKED",
++	(char *) "DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG",
++	(char *) "DKIM_SELECTOR_DNS_TEMP_FAILURE",
++	(char *) "DKIM_SELECTOR_DNS_PERM_FAILURE",
++	(char *) "DKIM_SELECTOR_PUBLIC_KEY_INVALID",
++	(char *) "DKIM_NO_SIGNATURES",
++	(char *) "DKIM_NO_VALID_SIGNATURES",
++	(char *) "DKIM_BODY_HASH_MISMATCH",
++	(char *) "DKIM_SELECTOR_ALGORITHM_MISMATCH",
++	(char *) "DKIM_STAT_INCOMPAT",
++	(char *) "DKIM_UNSIGNED_FROM",
++	(char *) "DKIM_OUT_OF_MEMORY",
++	(char *) "DKIM_INVALID_CONTEXT",
++	(char *) "DKIM_NO_SENDER",
++	(char *) "DKIM_BAD_PRIVATE_KEY",
++	(char *) "DKIM_BUFFER_TOO_SMALL"
++};
++
++char           *DKIM_CALL
++DKIMGetErrorString(int ErrorCode)
++{
++	if (ErrorCode >= 0 || ErrorCode <= DKIM_MAX_ERROR)
++		return (char *) "Unknown";
++
++	else
++		return DKIMErrorStrings[-1 - ErrorCode];
++}
++
++void
++getversion_dkimfuncs_cpp()
++{
++	static char    *x = (char *) "$Id: dkimfuncs.cpp,v 1.4 2011-06-04 10:06:33+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkimsign.cpp netqmail-1.06/dkimsign.cpp
+--- ../netqmail-1.06-original/dkimsign.cpp	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimsign.cpp	2018-04-03 14:46:51.365411610 +0200
+@@ -0,0 +1,1016 @@
++/*
++ * $Log: dkimsign.cpp,v $
++ * Revision 1.11  2017-09-05 10:59:03+05:30  Cprogrammer
++ * removed compiler warnings
++ *
++ * Revision 1.10  2017-08-09 22:02:13+05:30  Cprogrammer
++ * replaced EVP_MD_CTX_free() with EVP_MD_CTX_reset()
++ *
++ * Revision 1.9  2017-08-08 23:50:19+05:30  Cprogrammer
++ * openssl 1.1.0 port
++ *
++ * Revision 1.8  2013-07-16 20:18:03+05:30  Cprogrammer
++ * replace '%' with domain name in selector
++ *
++ * Revision 1.7  2013-06-11 00:02:39+05:30  Cprogrammer
++ * removed header iostream
++ *
++ * Revision 1.6  2013-06-09 16:41:28+05:30  Cprogrammer
++ * parse address properly from From and Sender header
++ *
++ * Revision 1.5  2009-04-16 10:32:38+05:30  Cprogrammer
++ * added DKIMDOMAIN env variable
++ *
++ * Revision 1.4  2009-04-15 21:32:12+05:30  Cprogrammer
++ * added DKIM-Signature, Received to list of excluded headers
++ *
++ * Revision 1.3  2009-03-26 15:11:46+05:30  Cprogrammer
++ * added GetDomain
++ *
++ * Revision 1.2  2009-03-21 11:57:19+05:30  Cprogrammer
++ * fixed indentation
++ *
++ * Revision 1.1  2009-03-21 08:43:11+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++#define _strnicmp strncasecmp
++#define _stricmp strcasecmp
++#define LOWORD(l) ((unsigned)(l) & 0xffff)
++#define HIWORD(l) ((unsigned)(l) >> 16)
++
++#include <string.h>
++#include <map>
++#include "dkim.h"
++#include "dkimsign.h"
++
++CDKIMSign::CDKIMSign()
++{
++	m_EmptyLineCount = 0;
++	m_pfnHdrCallback = NULL;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	if (!m_allman_sha1ctx)
++		m_allman_sha1ctx = EVP_MD_CTX_new();
++	EVP_SignInit(m_allman_sha1ctx, EVP_sha1());
++	if (!m_Hdr_ietf_sha1ctx)
++		m_Hdr_ietf_sha1ctx = EVP_MD_CTX_new();
++	EVP_SignInit(m_Hdr_ietf_sha1ctx, EVP_sha1());
++	if (!m_Bdy_ietf_sha1ctx)
++		m_Bdy_ietf_sha1ctx = EVP_MD_CTX_new();
++	EVP_DigestInit(m_Bdy_ietf_sha1ctx, EVP_sha1());
++#ifdef HAVE_EVP_SHA256
++	if (!m_Hdr_ietf_sha256ctx)
++		m_Hdr_ietf_sha256ctx = EVP_MD_CTX_new();
++	EVP_SignInit(m_Hdr_ietf_sha256ctx, EVP_sha256());
++	if (!m_Bdy_ietf_sha256ctx)
++		m_Bdy_ietf_sha256ctx = EVP_MD_CTX_new();
++	EVP_DigestInit(m_Bdy_ietf_sha256ctx, EVP_sha256());
++#endif
++#else
++	EVP_SignInit(&m_allman_sha1ctx, EVP_sha1());
++	EVP_SignInit(&m_Hdr_ietf_sha1ctx, EVP_sha1());
++	EVP_DigestInit(&m_Bdy_ietf_sha1ctx, EVP_sha1());
++#ifdef HAVE_EVP_SHA256
++	EVP_SignInit(&m_Hdr_ietf_sha256ctx, EVP_sha256());
++	EVP_DigestInit(&m_Bdy_ietf_sha256ctx, EVP_sha256());
++#endif
++#endif
++}
++
++CDKIMSign::~CDKIMSign()
++{
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	EVP_MD_CTX_reset(m_allman_sha1ctx);
++	EVP_MD_CTX_reset(m_Hdr_ietf_sha1ctx);
++	EVP_MD_CTX_reset(m_Bdy_ietf_sha1ctx);
++#ifdef HAVE_EVP_SHA256
++	EVP_MD_CTX_reset(m_Hdr_ietf_sha256ctx);
++	EVP_MD_CTX_reset(m_Bdy_ietf_sha256ctx);
++#endif
++#else
++	EVP_MD_CTX_cleanup(&m_allman_sha1ctx);
++	EVP_MD_CTX_cleanup(&m_Hdr_ietf_sha1ctx);
++	EVP_MD_CTX_cleanup(&m_Bdy_ietf_sha1ctx);
++#ifdef HAVE_EVP_SHA256
++	EVP_MD_CTX_cleanup(&m_Hdr_ietf_sha256ctx);
++	EVP_MD_CTX_cleanup(&m_Bdy_ietf_sha256ctx);
++#endif
++#endif
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Init - save the options
++//
++////////////////////////////////////////////////////////////////////////////////
++int
++CDKIMSign::Init(DKIMSignOptions * pOptions)
++{
++	int             nRet = CDKIMBase::Init();
++	m_Canon = pOptions->nCanon;
++
++// as of draft 01, these are the only allowed signing types:
++	if ((m_Canon != DKIM_SIGN_SIMPLE_RELAXED) && (m_Canon != DKIM_SIGN_RELAXED) && (m_Canon != DKIM_SIGN_RELAXED_SIMPLE)) {
++		m_Canon = DKIM_SIGN_SIMPLE;
++	}
++	sSelector.assign(pOptions->szSelector);
++	m_pfnHdrCallback = pOptions->pfnHeaderCallback;
++	sDomain.assign(pOptions->szDomain);
++	m_IncludeBodyLengthTag = (pOptions->nIncludeBodyLengthTag != 0);
++	m_nBodyLength = 0;
++	m_ExpireTime = pOptions->expireTime;
++	sIdentity.assign(pOptions->szIdentity);
++	m_nIncludeTimeStamp = pOptions->nIncludeTimeStamp;
++	m_nIncludeQueryMethod = pOptions->nIncludeQueryMethod;
++	m_nIncludeCopiedHeaders = pOptions->nIncludeCopiedHeaders;
++	m_nIncludeBodyHash = pOptions->nIncludeBodyHash;
++
++// NOTE: the following line is not backwards compatible with MD 8.0.3
++// because the szRequiredHeaders member was added after the release
++//sRequiredHeaders.assign( pOptions->szRequiredHeaders );
++
++//make sure there is a colon after the last header in the list
++	if ((sRequiredHeaders.size() > 0) && sRequiredHeaders.at(sRequiredHeaders.size() - 1) != ':')
++		sRequiredHeaders.append(":");
++	m_nHash = pOptions->nHash;
++	m_bReturnedSigAssembled = false;
++	m_sCopiedHeaders.erase();
++	return nRet;
++}
++
++
++// Hash - update the hash
++void
++CDKIMSign::Hash(const char *szBuffer, int nBufLength, bool bHdr, bool bAllmanOnly)
++{
++	EVP_MD_CTX     *p1, *p2, *p3, *p4, *p5;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	p1 = m_allman_sha1ctx;
++	p2 = m_Hdr_ietf_sha1ctx;
++	p3 = m_Hdr_ietf_sha256ctx;
++	p4 = m_Bdy_ietf_sha1ctx;
++	p5 = m_Bdy_ietf_sha256ctx;
++#else
++	p1 = &m_allman_sha1ctx;
++	p2 = &m_Hdr_ietf_sha1ctx;
++	p3 = &m_Hdr_ietf_sha256ctx;
++	p4 = &m_Bdy_ietf_sha1ctx;
++	p5 = &m_Bdy_ietf_sha256ctx;
++#endif
++	if (bAllmanOnly) {
++		if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1)
++			EVP_SignUpdate(p1, szBuffer, nBufLength);
++	} else {
++		if (m_nIncludeBodyHash < DKIM_BODYHASH_IETF_1)
++			EVP_SignUpdate(p1, szBuffer, nBufLength);
++		else
++		if (m_nIncludeBodyHash & DKIM_BODYHASH_IETF_1) {
++			if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1)
++				EVP_SignUpdate(p1, szBuffer, nBufLength);
++#ifdef HAVE_EVP_SHA256
++			if (m_nHash & DKIM_HASH_SHA256) {
++				if (bHdr)
++					EVP_SignUpdate(p3, szBuffer, nBufLength);
++				else
++					EVP_DigestUpdate(p5, szBuffer, nBufLength);
++			}
++			if (m_nHash != DKIM_HASH_SHA256) {
++				if (bHdr)
++					EVP_SignUpdate(p2, szBuffer, nBufLength);
++				else
++					EVP_DigestUpdate(p4, szBuffer, nBufLength);
++			}
++#else
++			if (bHdr)
++				EVP_SignUpdate(p2, szBuffer, nBufLength);
++			else
++				EVP_DigestUpdate(p4, szBuffer, nBufLength);
++#endif
++		}
++	}
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// SignThisTag - return boolean whether or not to sign this tag
++//
++////////////////////////////////////////////////////////////////////////////////
++bool CDKIMSign::SignThisTag(const string &sTag)
++{
++	bool            bRet = true;
++
++	if (_strnicmp(sTag.c_str(), "X-", 2) == 0
++		|| _stricmp(sTag.c_str(), "Authentication-Results:") == 0
++		|| _stricmp(sTag.c_str(), "DKIM-Signature:") == 0
++		|| _stricmp(sTag.c_str(), "Received:") == 0
++		|| _stricmp(sTag.c_str(), "Return-Path:") == 0)
++	{
++		bRet = false;
++	}
++	return bRet;
++}
++
++bool
++ConvertHeaderToQuotedPrintable(const char *source, char *dest)
++{
++	bool            bConvert = false;
++
++// do quoted printable
++	static unsigned char hexchars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
++	unsigned char  *d = (unsigned char *) dest;
++	for (const unsigned char *s = (const unsigned char *)source; *s != '\0'; s++) {
++		if (*s >= 33 && *s <= 126 && *s != '=' && *s != ':' && *s != ';' && *s != '|') {
++			*d++ = *s;
++		}
++
++		else {
++			bConvert = true;
++			*d++ = '=';
++			*d++ = hexchars[*s >> 4];
++			*d++ = hexchars[*s & 15];
++		}
++	}
++	*d = '\0';
++	return bConvert;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// GetHeaderParams - Extract any needed header parameters
++//
++////////////////////////////////////////////////////////////////////////////////
++void
++CDKIMSign::GetHeaderParams(const string & sHdr)
++{
++	string::size_type pos1, pos2;
++
++	if (_strnicmp(sHdr.c_str(), "X", 1) == 0)
++		return;
++	if (_strnicmp(sHdr.c_str(), "From:", 5) == 0) {
++		sFrom.assign(sHdr.c_str() + 5);
++		pos1 = sFrom.find('(');
++		pos2 = sFrom.find(')');
++		if (pos1 != 0 && pos1 != string::npos && pos2 != 0 && pos2 != string::npos)
++			sFrom.erase(pos1, pos2);
++	}
++	if (_strnicmp(sHdr.c_str(), "Sender:", 7) == 0) {
++		sSender.assign(sHdr.c_str() + 7);
++		pos1 = sSender.find('(');
++		pos2 = sSender.find(')');
++		if (pos1 != 0 && pos1 != string::npos && pos2 != 0 && pos2 != string::npos)
++			sSender.erase(pos1, pos2);
++	}
++	if (_strnicmp(sHdr.c_str(), "Return-Path:", 12) == 0)
++		sReturnPath.assign(sHdr.c_str() + 12);
++	if (m_nIncludeCopiedHeaders) {
++		string::size_type pos = sHdr.find(':');
++		if (pos != string::npos) {
++			string          sTag, sValue;
++			char           *workBuffer = new char[sHdr.size() * 3 + 1];
++			sTag.assign(sHdr.substr(0, pos));
++			sValue.assign(sHdr.substr(pos + 1, string::npos));
++			ConvertHeaderToQuotedPrintable(sTag.c_str(), workBuffer);
++			if (!m_sCopiedHeaders.empty()) {
++				m_sCopiedHeaders.append("|");
++			}
++			m_sCopiedHeaders.append(workBuffer);
++			m_sCopiedHeaders.append(":");
++			ConvertHeaderToQuotedPrintable(sValue.c_str(), workBuffer);
++			m_sCopiedHeaders.append(workBuffer);
++			delete[]workBuffer;
++		}
++	}
++}
++
++// ProcessHeaders - sign headers and save needed parameters
++int
++CDKIMSign::ProcessHeaders(void)
++{
++	map <string, list <string>::reverse_iterator> IterMap;
++	map <string, list <string>::reverse_iterator>::iterator IterMapIter;
++	list <string>::reverse_iterator riter;
++	list <string>::iterator iter;
++	string          sTag;
++	bool            bFromHeaderFound = false;
++
++	// walk the header list
++	for (iter = HeaderList.begin(); iter != HeaderList.end(); iter++) {
++		sTag.assign(*iter);
++		// look for a colon
++		string::size_type pos = sTag.find(':');
++		if (pos != string::npos) {
++			int             nSignThisTag = 1;
++			// hack off anything past the colon
++			sTag.erase(pos + 1, string::npos);
++			// is this the From: header?
++			if (_stricmp(sTag.c_str(), "From:") == 0) {
++				bFromHeaderFound = true;
++				nSignThisTag = 1;
++				IsRequiredHeader(sTag);	// remove from required header list
++			} 
++			// is this in the list of headers that must be signed?
++			else
++			if (IsRequiredHeader(sTag))
++				nSignThisTag = 1;
++			else {
++				if (m_pfnHdrCallback)
++					nSignThisTag = m_pfnHdrCallback(iter->c_str());
++				else
++					nSignThisTag = SignThisTag(sTag) ? 1 : 0;
++			}
++			// save header parameters
++			GetHeaderParams(*iter);
++			if (nSignThisTag > 0) {
++				// add this tag to h=
++				hParam.append(sTag);
++				IterMapIter = IterMap.find(sTag);
++				riter = (IterMapIter == IterMap.end())? HeaderList.rbegin() : IterMapIter->second;
++				// walk the list in reverse looking for the last instance of this header
++				while (riter != HeaderList.rend()) {
++					if (_strnicmp(riter->c_str(), sTag.c_str(), sTag.size()) == 0) {
++						ProcessHeader(*riter);
++						// save the reverse iterator position for this tag
++						riter++;
++						IterMap[sTag] = riter;
++						break;
++					}
++					riter++;
++				}
++			}
++		}
++	}
++	Hash("\r\n", 2, true, true);	// only for Allman sig
++	if (!bFromHeaderFound) {
++		string sFrom("From:");
++		hParam.append(sFrom);
++		IsRequiredHeader(sFrom);	// remove from required header list
++	}
++	hParam.append(sRequiredHeaders);
++	if (hParam.at(hParam.size() - 1) == ':')
++		hParam.erase(hParam.size() - 1, string::npos);
++	return DKIM_SUCCESS;
++}
++
++char           *DKIM_CALL
++CDKIMSign::GetDomain(void)
++{
++	if (ParseFromAddress() == false)
++		return ((char *) 0);
++	return ((char *) sDomain.c_str());
++}
++
++void
++CDKIMSign::ProcessHeader(const string & sHdr)
++{
++	switch (HIWORD(m_Canon)) {
++	case DKIM_CANON_SIMPLE:
++		Hash(sHdr.c_str(), sHdr.size(), true);
++		Hash("\r\n", 2, true);
++		break;
++	case DKIM_CANON_NOWSP:
++		{
++		string sTemp = sHdr;
++		RemoveSWSP(sTemp);
++		// convert characters before ':' to lower case
++		for (char *s = (char *)sTemp.c_str(); *s != '\0' && *s != ':'; s++) {
++			if (*s >= 'A' && *s <= 'Z')
++				*s += 'a' - 'A';
++		}
++		Hash(sTemp.c_str(), sTemp.size(), true);
++		Hash("\r\n", 2, true);
++		}
++		break;
++	case DKIM_CANON_RELAXED:
++		{
++		string sTemp = RelaxHeader(sHdr);
++		Hash(sTemp.c_str(), sTemp.length(), true);
++		Hash("\r\n", 2, true);
++		}
++		break;
++	}
++}
++
++int CDKIMSign::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
++{
++	switch (LOWORD(m_Canon)) {
++	case DKIM_CANON_SIMPLE:
++		if (nBufLength > 0) {
++			while (m_EmptyLineCount > 0) {
++				Hash("\r\n", 2, false);
++				m_nBodyLength += 2;
++				m_EmptyLineCount--;
++			}
++			Hash(szBuffer, nBufLength, false);
++			Hash("\r\n", 2, false);
++			m_nBodyLength += nBufLength + 2;
++		} else {
++			m_EmptyLineCount++;
++			if (bEOF) {
++				Hash("\r\n", 2, false);
++				m_nBodyLength += 2;
++			}
++		}
++		break;
++	case DKIM_CANON_NOWSP:
++		RemoveSWSP(szBuffer, nBufLength);
++		if (nBufLength > 0) {
++			Hash(szBuffer, nBufLength, false);
++			m_nBodyLength += nBufLength;
++		}
++		break;
++	case DKIM_CANON_RELAXED:
++		CompressSWSP(szBuffer, nBufLength);
++		if (nBufLength > 0) {
++			while (m_EmptyLineCount > 0) {
++				Hash("\r\n", 2, false);
++				m_nBodyLength += 2;
++				m_EmptyLineCount--;
++			}
++			Hash(szBuffer, nBufLength, false);
++			m_nBodyLength += nBufLength;
++			if (!bEOF) {
++				Hash("\r\n", 2, false);
++				m_nBodyLength += 2;
++			}
++		} else
++			m_EmptyLineCount++;
++		break;
++	}
++	return DKIM_SUCCESS;
++}
++
++bool CDKIMSign::ParseFromAddress(void)
++{
++	string::size_type pos;
++	string          sAddress;
++	char           *p, *at;
++
++	/* thanks to fred */
++	if (!sReturnPath.empty())
++		sAddress.assign(sReturnPath);
++	else
++	if (!sSender.empty())
++		sAddress.assign(sSender);
++	else
++	if (!sFrom.empty())
++		sAddress.assign(sFrom);
++	else
++		return false;
++	// simple for now, beef it up later
++	// remove '<' and anything before it
++	pos = sAddress.find('<');
++	if (pos != string::npos)
++		sAddress.erase(0, pos);
++	// remove '>' and anything after it
++	pos = sAddress.find('>');
++	if (pos != string::npos)
++		sAddress.erase(pos, string::npos);
++	// look for '@' symbol
++	pos = sAddress.find('@');
++	if (pos == string::npos)
++		return false;
++	if (sDomain.empty()) {
++		p = getenv("DKIMDOMAIN");
++		if (p && *p)
++		{
++			if (!(at = strchr(p, '@')))
++				at = p;
++			else
++				at++;
++			sDomain.assign(at);
++		} else
++			sDomain.assign(sAddress.c_str() + pos + 1);
++		RemoveSWSP(sDomain);
++	}
++	return true;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// InitSig - initialize signature folding algorithm
++//
++////////////////////////////////////////////////////////////////////////////////
++void
++CDKIMSign::InitSig(void)
++{
++	m_sSig.reserve(1024);
++	m_sSig.assign("DKIM-Signature:");
++	m_nSigPos = m_sSig.size();
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// AddTagToSig - add tag and value to signature folding if necessary
++//               if bFold, fold at cbrk char
++//
++////////////////////////////////////////////////////////////////////////////////
++void CDKIMSign::AddTagToSig(char *Tag, const string & sValue, char cbrk, bool bFold)
++{
++	int
++	                nTagLen = strlen(Tag);
++	AddInterTagSpace((!bFold) ? sValue.size() + nTagLen + 2 : nTagLen + 2);
++	m_sSig.append(Tag);
++	m_sSig.append("=");
++	m_nSigPos += 1 + nTagLen;
++	if (!bFold) {
++		m_sSig.append(sValue);
++		m_nSigPos += sValue.size();
++	}
++
++	else {
++		AddFoldedValueToSig(sValue, cbrk);
++	}
++	m_sSig.append(";");
++	m_nSigPos++;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// AddTagToSig - add tag and numeric value to signature folding if necessary
++//
++////////////////////////////////////////////////////////////////////////////////
++void CDKIMSign::AddTagToSig(char *Tag, unsigned long nValue)
++{
++	char            szValue[64];
++	sprintf(szValue, "%lu", nValue);
++	AddTagToSig(Tag, szValue, 0, false);
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// AddInterTagSpace - add space or fold here
++//
++////////////////////////////////////////////////////////////////////////////////
++void CDKIMSign::AddInterTagSpace(int nSizeOfNextTag)
++{
++	if (m_nSigPos + nSizeOfNextTag + 1 > OptimalHeaderLineLength) {
++		m_sSig.append("\n\t");
++		m_nSigPos = 1;
++	}
++
++	else {
++		m_sSig.append(" ");
++		m_nSigPos++;
++	}
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// AddTagToSig - add value to signature folding if necessary
++//               if cbrk == 0 fold anywhere, otherwise fold only at cbrk
++//
++////////////////////////////////////////////////////////////////////////////////
++void CDKIMSign::AddFoldedValueToSig(const string & sValue, char cbrk)
++{
++	string::size_type pos = 0;
++	if (cbrk == 0) {
++
++	// fold anywhere
++		while (pos < sValue.size()) {
++			string::size_type len = OptimalHeaderLineLength - m_nSigPos;
++			if (len > sValue.size() - pos)
++				len = sValue.size() - pos;
++			m_sSig.append(sValue.substr(pos, len));
++			m_nSigPos += len;
++			pos += len;
++			if (pos < sValue.size()) {
++				m_sSig.append("\n\t");
++				m_nSigPos = 1;
++			}
++		}
++	}
++
++	else {
++
++	// fold only at cbrk
++		while (pos < sValue.size()) {
++			string::size_type len = OptimalHeaderLineLength - m_nSigPos;
++			string::size_type brkpos;
++			if (sValue.size() - pos < len) {
++				brkpos = sValue.size() - 1;
++			}
++
++			else {
++				brkpos = sValue.rfind(cbrk, pos + len);
++			}
++			if (brkpos == string::npos || brkpos < pos) {
++				brkpos = sValue.find(cbrk, pos);
++				if (brkpos == string::npos) {
++					brkpos = sValue.size();
++				}
++			}
++			len = brkpos - pos + 1;
++			m_sSig.append(sValue.substr(pos, len));
++			m_nSigPos += len;
++			pos += len;
++			if (pos < sValue.size()) {
++
++			//m_sSig.append( "\r\n\t" );
++				m_sSig.append("\n\t");
++				m_nSigPos = 1;
++			}
++		}
++	}
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// GetSig - compute hash and return signature header in szSignature
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMSign::GetSig(char *szPrivKey, char *szSignature, unsigned int nSigLength)
++{
++	if (szPrivKey == NULL) {
++		return DKIM_BAD_PRIVATE_KEY;
++	}
++	if (szSignature == NULL) {
++		return DKIM_BUFFER_TOO_SMALL;
++	}
++	int             nRet = AssembleReturnedSig(szPrivKey);
++	if (nRet != DKIM_SUCCESS)
++		return nRet;
++	if (m_sReturnedSig.size() + 1 < nSigLength)
++		strcpy(szSignature, m_sReturnedSig.c_str());
++	else 
++		return DKIM_BUFFER_TOO_SMALL;
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// GetSig - compute hash and return signature header in szSignature
++//
++////////////////////////////////////////////////////////////////////////////////
++int CDKIMSign::GetSig2(char *szPrivKey, char **pszSignature)
++{
++	if (szPrivKey == NULL) {
++		return DKIM_BAD_PRIVATE_KEY;
++	}
++	if (pszSignature == NULL) {
++		return DKIM_BUFFER_TOO_SMALL;
++	}
++	int             nRet = AssembleReturnedSig(szPrivKey);
++	if (nRet != DKIM_SUCCESS)
++		return nRet;
++	*pszSignature = (char *) m_sReturnedSig.c_str();
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// IsRequiredHeader - Check if header in required list. If so, delete
++//                    header from list.
++//
++////////////////////////////////////////////////////////////////////////////////
++bool CDKIMSign::IsRequiredHeader(const string & sTag)
++{
++	string::size_type start = 0;
++	string::size_type end = sRequiredHeaders.find(':');
++	while (end != string::npos) {
++
++	// check for a zero-length header
++		if (start == end) {
++			sRequiredHeaders.erase(start, 1);
++		}
++
++		else {
++			if (_stricmp(sTag.c_str(), sRequiredHeaders.substr(start, end - start + 1).c_str()) == 0) {
++				sRequiredHeaders.erase(start, end - start + 1);
++				return true;
++			}
++
++			else {
++				start = end + 1;
++			}
++		}
++		end = sRequiredHeaders.find(':', start);
++	}
++	return false;
++}
++
++int CDKIMSign::ConstructSignature(char *szPrivKey, bool bUseIetfBodyHash, bool bUseSha256)
++{
++	string          sSignedSig;
++	unsigned char  *sig;
++	EVP_PKEY       *pkey;
++	BIO            *bio, *b64;
++	unsigned int    siglen;
++	int             size, len;
++	char           *buf, *cptr; 
++	const char     *ptr, *dptr, *sptr;
++	EVP_MD_CTX     *p1, *p2, *p3, *p4, *p5;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	p1 = m_allman_sha1ctx;
++	p2 = m_Hdr_ietf_sha1ctx;
++	p3 = m_Hdr_ietf_sha256ctx;
++	p4 = m_Bdy_ietf_sha1ctx;
++	p5 = m_Bdy_ietf_sha256ctx;
++#else
++	p1 = &m_allman_sha1ctx;
++	p2 = &m_Hdr_ietf_sha1ctx;
++	p3 = &m_Hdr_ietf_sha256ctx;
++	p4 = &m_Bdy_ietf_sha1ctx;
++	p5 = &m_Bdy_ietf_sha256ctx;
++#endif
++
++// construct the DKIM-Signature: header and add to hash
++	InitSig();
++	if (bUseIetfBodyHash) {
++		AddTagToSig((char *) "v", (char *) "1", 0, false);
++	}
++#ifdef HAVE_EVP_SHA256
++	AddTagToSig((char *) "a", bUseSha256 ? "rsa-sha256" : "rsa-sha1", 0, false);
++#else
++	AddTagToSig((char *) "a", "rsa-sha1", 0, false);
++#endif
++	switch (m_Canon) {
++	case DKIM_SIGN_SIMPLE:
++		AddTagToSig((char *) "c", "simple", 0, false);
++		break;
++	case DKIM_SIGN_SIMPLE_RELAXED:
++		AddTagToSig((char *) "c", "simple/relaxed", 0, false);
++		break;
++	case DKIM_SIGN_RELAXED:
++		AddTagToSig((char *) "c", "relaxed/relaxed", 0, false);
++		break;
++	case DKIM_SIGN_RELAXED_SIMPLE:
++		AddTagToSig((char *) "c", "relaxed", 0, false);
++		break;
++	}
++	AddTagToSig((char *) "d", sDomain, 0, false);
++	/*- replace % with domain name */
++	ptr = sSelector.c_str();
++	if ((sptr = strchr(ptr, '%'))) {
++		dptr = sDomain.c_str();
++		for (sptr = ptr, len = 0;*sptr;sptr++) {
++			if (*sptr == '%')
++				len += (int) strlen(dptr);
++			else
++				len++;
++		}
++		if (!(buf = new char[len])) {
++			return DKIM_OUT_OF_MEMORY;
++		}
++		for (cptr = buf, sptr = ptr; *sptr; sptr++) {
++			if (*sptr == '%') {
++				strncpy(cptr, dptr, (len = strlen(dptr)));
++				cptr += len;
++			} else {
++				*cptr++ = *sptr;
++			}
++		}
++		*cptr = 0;
++		sSelector.assign(buf);
++		delete[]buf;
++	}
++	AddTagToSig((char *) "s", sSelector, 0, false);
++	if (m_IncludeBodyLengthTag) {
++		AddTagToSig((char *) "l", m_nBodyLength);
++	}
++	if (m_nIncludeTimeStamp != 0) {
++		time_t t;
++		time(&t);
++		AddTagToSig((char *) "t", t);
++	}
++	if (m_ExpireTime != 0) {
++		AddTagToSig((char *) "x", m_ExpireTime);
++	}
++	if (!sIdentity.empty()) {
++		AddTagToSig((char *) "i", sIdentity, 0, false);
++	}
++	if (m_nIncludeQueryMethod) {
++		AddTagToSig((char *) "q", bUseIetfBodyHash ? "dns/txt" : "dns", 0, false);
++	}
++	AddTagToSig((char *) "h", hParam, ':', true);
++	if (m_nIncludeCopiedHeaders) {
++		AddTagToSig((char *) "z", m_sCopiedHeaders, 0, true);
++	}
++	if (bUseIetfBodyHash) {
++		unsigned char Hash[EVP_MAX_MD_SIZE];
++		unsigned int nHashLen = 0;
++#ifdef HAVE_EVP_SHA256
++		EVP_DigestFinal(bUseSha256 ? p5 : p4, Hash, &nHashLen);
++#else
++		EVP_DigestFinal(p4, Hash, &nHashLen);
++#endif
++		bio = BIO_new(BIO_s_mem());
++		if (!bio) {
++			return DKIM_OUT_OF_MEMORY;
++		}
++		b64 = BIO_new(BIO_f_base64());
++		if (!b64) {
++			BIO_free(bio);
++			return DKIM_OUT_OF_MEMORY;
++		}
++		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
++		BIO_push(b64, bio);
++		if (BIO_write(b64, Hash, nHashLen) < (int) nHashLen) {
++			BIO_free_all(b64);
++			return DKIM_OUT_OF_MEMORY;
++		}
++		BIO_flush(b64);
++		len = nHashLen * 2;
++		buf = new char[len];
++		if (buf == NULL) {
++			BIO_free_all(b64);
++			return DKIM_OUT_OF_MEMORY;
++		}
++		size = BIO_read(bio, buf, len);
++		BIO_free_all(b64);
++		// this should never happen
++		if (size >= len) {
++			delete[]buf;
++			return DKIM_OUT_OF_MEMORY;
++		}
++		buf[size] = '\0';
++		AddTagToSig((char *) "bh", buf, 0, true);
++		delete[]buf;
++	}
++	AddInterTagSpace(3);
++	m_sSig.append("b=");
++	m_nSigPos += 2;
++	// Force a full copy - no reference copies please
++	sSignedSig.assign(m_sSig.c_str());
++	// note that since we're not calling hash here, need to dump this
++	// to the debug file if you want the full canonical form
++	string          sTemp;
++	if (HIWORD(m_Canon) == DKIM_CANON_RELAXED)
++		sTemp = RelaxHeader(sSignedSig);
++	else
++		sTemp = sSignedSig.c_str();
++	if (bUseIetfBodyHash) {
++#ifdef HAVE_EVP_SHA256
++		EVP_SignUpdate(bUseSha256 ? p3 : p2, sTemp.c_str(), sTemp.size());
++#else
++		EVP_SignUpdate(p2, sTemp.c_str(), sTemp.size());
++#endif
++	} else
++		EVP_SignUpdate(p1, sTemp.c_str(), sTemp.size());
++	if (!(bio = BIO_new_mem_buf(szPrivKey, -1)))
++		return DKIM_OUT_OF_MEMORY;
++	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
++	BIO_free(bio);
++	if (!pkey) {
++		return DKIM_BAD_PRIVATE_KEY;
++	}
++	siglen = EVP_PKEY_size(pkey);
++	int             nSignRet;
++	sig = (unsigned char *) OPENSSL_malloc(siglen);
++	if (sig == NULL) {
++		EVP_PKEY_free(pkey);
++		return DKIM_OUT_OF_MEMORY;
++	}
++	if (bUseIetfBodyHash) {
++#ifdef HAVE_EVP_SHA256
++		nSignRet = EVP_SignFinal(bUseSha256 ? p3 : p2, sig, &siglen, pkey);
++#else
++		nSignRet = EVP_SignFinal(p2, sig, &siglen, pkey);
++#endif
++	} else
++		nSignRet = EVP_SignFinal(p1, sig, &siglen, pkey);
++	EVP_PKEY_free(pkey);
++	if (!nSignRet) {
++		OPENSSL_free(sig);
++		return DKIM_BAD_PRIVATE_KEY;	// key too small
++	}
++	bio = BIO_new(BIO_s_mem());
++	if (!bio) {
++		return DKIM_OUT_OF_MEMORY;
++	}
++	b64 = BIO_new(BIO_f_base64());
++	if (!b64) {
++		BIO_free(bio);
++		return DKIM_OUT_OF_MEMORY;
++	}
++	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
++	BIO_push(b64, bio);
++	if (BIO_write(b64, sig, siglen) < (int) siglen) {
++		OPENSSL_free(sig);
++		BIO_free_all(b64);
++		return DKIM_OUT_OF_MEMORY;
++	}
++	BIO_flush(b64);
++	OPENSSL_free(sig);
++	len = siglen * 2;
++	buf = new char[len];
++	if (buf == NULL) {
++		BIO_free_all(b64);
++		return DKIM_OUT_OF_MEMORY;
++	}
++	size = BIO_read(bio, buf, len);
++	BIO_free_all(b64);
++	// this should never happen
++	if (size >= len) {
++		delete[]buf;
++		return DKIM_OUT_OF_MEMORY;
++	}
++	buf[size] = '\0';
++	AddFoldedValueToSig(buf, 0);
++	delete[]buf;
++	return DKIM_SUCCESS;
++}
++
++int CDKIMSign::AssembleReturnedSig(char *szPrivKey)
++{
++	int             nRet;
++	if (m_bReturnedSigAssembled)
++		return DKIM_SUCCESS;
++	ProcessFinal();
++	if (ParseFromAddress() == false) {
++		//return DKIM_NO_SENDER;
++	}
++	Hash("\r\n", 2, true, true);	// only for Allman sig
++	string allmansha1sig,
++#ifdef HAVE_EVP_SHA256
++		ietfsha256Sig,
++#endif
++		ietfsha1Sig;
++	if (m_nIncludeBodyHash < DKIM_BODYHASH_IETF_1) {
++		nRet = ConstructSignature(szPrivKey, false, false);
++		if (nRet == DKIM_SUCCESS)
++			allmansha1sig.assign(m_sSig);
++		else
++			return nRet;
++	} else
++	if (m_nIncludeBodyHash & DKIM_BODYHASH_IETF_1) {
++		if (m_nIncludeBodyHash & DKIM_BODYHASH_ALLMAN_1) {
++			if ((nRet = ConstructSignature(szPrivKey, false, false)) == DKIM_SUCCESS)
++				allmansha1sig.assign(m_sSig);
++			else
++				return nRet;
++		}
++#ifdef HAVE_EVP_SHA256
++		if (m_nHash & DKIM_HASH_SHA256) {
++			if ((nRet = ConstructSignature(szPrivKey, true, true)) == DKIM_SUCCESS)
++				ietfsha256Sig.assign(m_sSig);
++			else
++				return nRet;
++		}
++		if (m_nHash != DKIM_HASH_SHA256) {
++			if ((nRet = ConstructSignature(szPrivKey, true, false)) == DKIM_SUCCESS)
++				ietfsha1Sig.assign(m_sSig);
++			else
++				return nRet;
++		}
++#else
++		if ((nRet = ConstructSignature(szPrivKey, true, false)) == DKIM_SUCCESS)
++			ietfsha1Sig.assign(m_sSig);
++		else
++			return nRet;
++#endif
++	}
++	m_sReturnedSig.assign(allmansha1sig);
++	if (!ietfsha1Sig.empty()) {
++		if (!m_sReturnedSig.empty())
++			m_sReturnedSig.append("\n");
++		m_sReturnedSig.append(ietfsha1Sig);
++	}
++#ifdef HAVE_EVP_SHA256
++	if (!ietfsha256Sig.empty()) {
++		if (!m_sReturnedSig.empty())
++			m_sReturnedSig.append("\n");
++		m_sReturnedSig.append(ietfsha256Sig);
++	}
++#endif
++	m_bReturnedSigAssembled = true;
++	return DKIM_SUCCESS;
++}
++
++void
++getversion_dkimsign_cpp()
++{
++	static char    *x = (char *) "$Id: dkimsign.cpp,v 1.11 2017-09-05 10:59:03+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkimsign.h netqmail-1.06/dkimsign.h
+--- ../netqmail-1.06-original/dkimsign.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimsign.h	2018-04-03 14:46:51.366411614 +0200
+@@ -0,0 +1,108 @@
++/*
++ * $Log: dkimsign.h,v $
++ * Revision 1.3  2017-08-09 22:03:09+05:30  Cprogrammer
++ * initialized EVP_MD_CTX variables
++ *
++ * Revision 1.2  2017-08-08 23:50:33+05:30  Cprogrammer
++ * openssl 1.1.0 port
++ *
++ * Revision 1.1  2009-04-16 10:34:02+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#ifndef DKIMSIGN_H
++#define DKIMSIGN_H
++
++#include "dkimbase.h"
++
++class           CDKIMSign:public CDKIMBase {
++public:
++
++	CDKIMSign();
++	~CDKIMSign();
++	int             Init(DKIMSignOptions * pOptions);
++	int             GetSig(char *szPrivKey, char *szSignature, unsigned int nSigLength);
++	int             GetSig2(char *szPrivKey, char **pszSignature);
++	virtual int     ProcessHeaders(void);
++	virtual int     ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
++	enum CKDKIMConstants { OptimalHeaderLineLength = 65 };
++	char           *DKIM_CALL GetDomain(void);
++
++protected:
++	void            Hash(const char *szBuffer, int nBufLength, bool bHdr, bool bAllmanOnly = false);
++	bool            SignThisTag(const string & sTag);
++	void            GetHeaderParams(const string & sHdr);
++	void            ProcessHeader(const string & sHdr);
++	bool            ParseFromAddress(void);
++	void            InitSig(void);
++	void            AddTagToSig(char *Tag, const string & sValue, char cbrk, bool bFold);
++	void            AddTagToSig(char *Tag, unsigned long nValue);
++	void            AddInterTagSpace(int nSizeOfNextTag);
++	void            AddFoldedValueToSig(const string & sValue, char cbrk);
++	bool            IsRequiredHeader(const string & sTag);
++	int             ConstructSignature(char *szPrivKey, bool bUseIetfBodyHash, bool bUseSha256);
++	int             AssembleReturnedSig(char *szPrivKey);
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	EVP_MD_CTX     *m_Hdr_ietf_sha1ctx = NULL;	/* the header hash for ietf sha1  */
++	EVP_MD_CTX     *m_Bdy_ietf_sha1ctx = NULL;	/* the body hash for ietf sha1  */
++#ifdef HAVE_EVP_SHA256
++	EVP_MD_CTX     *m_Hdr_ietf_sha256ctx = NULL;	/* the header hash for ietf sha256 */
++	EVP_MD_CTX     *m_Bdy_ietf_sha256ctx = NULL;	/* the body hash for ietf sha256 */
++#endif
++	EVP_MD_CTX     *m_allman_sha1ctx = NULL;	/* the hash for allman sha1  */
++#else
++	EVP_MD_CTX      m_Hdr_ietf_sha1ctx;	/* the header hash for ietf sha1  */
++	EVP_MD_CTX      m_Bdy_ietf_sha1ctx;	/* the body hash for ietf sha1  */
++#ifdef HAVE_EVP_SHA256
++	EVP_MD_CTX      m_Hdr_ietf_sha256ctx;	/* the header hash for ietf sha256 */
++	EVP_MD_CTX      m_Bdy_ietf_sha256ctx;	/* the body hash for ietf sha256 */
++#endif
++	EVP_MD_CTX      m_allman_sha1ctx;	/* the hash for allman sha1  */
++#endif
++	int             m_Canon;	// canonization method
++	int             m_EmptyLineCount;
++	string          hParam;
++	string          sFrom;
++	string          sSender;
++	string          sSelector;
++	string          sReturnPath;
++	string          sDomain;
++	string          sIdentity;	// for i= tag, if empty tag will not be included in sig
++	string          sRequiredHeaders;
++	bool            m_IncludeBodyLengthTag;
++	int             m_nBodyLength;
++	time_t          m_ExpireTime;
++	int             m_nIncludeTimeStamp;	// 0 = don't include t= tag, 1 = include t= tag
++	int             m_nIncludeQueryMethod;	// 0 = don't include q= tag, 1 = include q= tag
++	int             m_nHash;	// use one of the DKIM_HASH_xx constants here
++	int             m_nIncludeCopiedHeaders;	// 0 = don't include z= tag, 1 = include z= tag
++	int             m_nIncludeBodyHash;	// 0 = calculate sig using draft 0, 1 = include bh= tag and 
++	// use new signature computation algorithm
++	DKIMHEADERCALLBACK m_pfnHdrCallback;
++	string          m_sSig;
++	int             m_nSigPos;
++	string          m_sReturnedSig;
++	bool            m_bReturnedSigAssembled;
++	string          m_sCopiedHeaders;
++};
++
++#endif	/*- DKIMSIGN_H */
+diff -ruN ../netqmail-1.06-original/dkimverify.cpp netqmail-1.06/dkimverify.cpp
+--- ../netqmail-1.06-original/dkimverify.cpp	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimverify.cpp	2018-04-03 14:46:51.367411617 +0200
+@@ -0,0 +1,1285 @@
++/*
++ * $Log: dkimverify.cpp,v $
++ * Revision 1.18  2017-09-05 11:00:33+05:30  Cprogrammer
++ * removed extra whitespace
++ *
++ * Revision 1.17  2017-09-03 14:02:04+05:30  Cprogrammer
++ * call EVP_MD_CTX_init() only once
++ *
++ * Revision 1.16  2017-09-01 12:46:05+05:30  Cprogrammer
++ * removed dkimd2i_PUBKEY function
++ *
++ * Revision 1.15  2017-08-31 17:04:34+05:30  Cprogrammer
++ * replaced d2i_PUBKEY() with dkimd2i_PUBKEY() to avoid SIGSEGV on X509_PUBKEY_free()
++ *
++ * Revision 1.14  2017-08-09 21:59:39+05:30  Cprogrammer
++ * fixed segmentation fault. Use EVP_MD_CTX_reset() instead of EVP_MD_CTX_free()
++ *
++ * Revision 1.13  2017-08-08 23:50:41+05:30  Cprogrammer
++ * openssl 1.1.0 port
++ *
++ * Revision 1.12  2017-05-23 09:23:45+05:30  Cprogrammer
++ * use strtok_r instead of strtok() for thread safe operation
++ *
++ * Revision 1.11  2016-03-01 16:24:00+05:30  Cprogrammer
++ * reverse value of m_SubjectIsRequired
++ *
++ * Revision 1.10  2015-12-15 16:05:00+05:30  Cprogrammer
++ * fixed issue with time comparision. Use time_t for time variables
++ *
++ * Revision 1.9  2011-06-04 10:05:01+05:30  Cprogrammer
++ * added signature and identity domain information to
++ *     DKIMVerifyDetails structure
++ *
++ * Revision 1.8  2011-06-04 09:37:13+05:30  Cprogrammer
++ * added AllowUnsignedFromHeaders
++ *
++ * Revision 1.7  2009-06-11 13:58:34+05:30  Cprogrammer
++ * port for DARWIN
++ *
++ * Revision 1.6  2009-05-31 21:09:29+05:30  Cprogrammer
++ * changed cast
++ *
++ * Revision 1.5  2009-03-27 20:19:58+05:30  Cprogrammer
++ * added ADSP code
++ *
++ * Revision 1.4  2009-03-26 15:12:05+05:30  Cprogrammer
++ * added ADSP code
++ *
++ * Revision 1.3  2009-03-25 08:38:20+05:30  Cprogrammer
++ * fixed indentation
++ *
++ * Revision 1.2  2009-03-21 11:57:40+05:30  Cprogrammer
++ * fixed indentation
++ *
++ * Revision 1.1  2009-03-21 08:43:13+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++#define _strnicmp strncasecmp
++#define _stricmp strcasecmp
++#include <string.h>
++#include <ctype.h>
++#include <assert.h>
++#include <vector>
++#include <algorithm>
++#include "dkim.h"
++#include "dkimverify.h"
++#include "dkimdns.h"
++
++#define MAX_SIGNATURES	10		// maximum number of DKIM signatures to process in a message
++
++SignatureInfo::SignatureInfo(bool s)
++{
++	VerifiedBodyCount = 0;
++	UnverifiedBodyCount = 0;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	if (m_Hdr_ctx)
++		EVP_MD_CTX_init(m_Hdr_ctx);
++	else
++		m_Hdr_ctx = EVP_MD_CTX_new();
++	if (m_Bdy_ctx)
++		EVP_MD_CTX_init(m_Bdy_ctx);
++	else
++		m_Bdy_ctx = EVP_MD_CTX_new();
++#else
++	EVP_MD_CTX_init(&m_Hdr_ctx);
++	EVP_MD_CTX_init(&m_Bdy_ctx);
++#endif
++	m_pSelector = NULL;
++	Status = DKIM_SUCCESS;
++	m_nHash = 0;
++	EmptyLineCount = 0;
++	m_SaveCanonicalizedData = s;
++}
++
++SignatureInfo::~SignatureInfo()
++{
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	if (m_Hdr_ctx)
++		EVP_MD_CTX_reset(m_Hdr_ctx);
++	if (m_Bdy_ctx)
++		EVP_MD_CTX_reset(m_Bdy_ctx);
++#else
++	EVP_MD_CTX_cleanup(&m_Hdr_ctx);
++	EVP_MD_CTX_cleanup(&m_Bdy_ctx);
++#endif
++}
++
++inline          bool
++isswsp(char ch)
++{
++	return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Parse a DKIM tag-list.  Returns true for success
++//
++////////////////////////////////////////////////////////////////////////////////
++bool
++ParseTagValueList(char *tagvaluelist, const char *wanted[], char *values[])
++{
++	char           *s = tagvaluelist;
++
++	for (;;) {
++		// skip whitespace
++		while (isswsp(*s))
++			s++;
++		// if at the end of the string, return success.  note: this allows a list with no entries
++		if (*s == '\0')
++			return true;
++		// get tag name
++		if (!isalpha(*s))
++			return false;
++		char           *tag = s;
++		do {
++			s++;
++		} while (isalnum(*s) || *s == '-');
++		char           *endtag = s;
++		// skip whitespace before equals
++		while (isswsp(*s))
++			s++;
++		// next character must be equals
++		if (*s != '=')
++			return false;
++		s++;
++		// null-terminate tag name
++		*endtag = '\0';
++		// skip whitespace after equals
++		while (isswsp(*s))
++			s++;
++		// get tag value
++		char           *value = s;
++		while (*s != ';' && ((*s == '\t' || *s == '\r' || *s == '\n') || (*s >= ' ' && *s <= '~')))
++			s++;
++		char           *e = s;
++		// make sure the next character is the null terminator (which means we're done) or a semicolon (not done)
++		bool            done = false;
++		if (*s == '\0')
++			done = true;
++		else {
++			if (*s != ';')
++				return false;
++			s++;
++		}
++		// skip backwards past any trailing whitespace
++		while (e > value && isswsp(e[-1]))
++			e--;
++		// null-terminate tag value
++		*e = '\0';
++		// check to see if we want this tag
++		for (unsigned i = 0; wanted[i] != NULL; i++) {
++			if (strcmp(wanted[i], tag) == 0) {
++				// return failure if we already have a value for this tag (duplicates not allowed)
++				if (values[i] != NULL)
++					return false;
++				values[i] = value;
++				break;
++			}
++		}
++		if (done)
++			return true;
++	}
++}
++
++// Convert hex char to value (0-15)
++char
++tohex(char ch)
++{
++	if (ch >= '0' && ch <= '9')
++		return (ch - '0');
++	else
++	if (ch >= 'A' && ch <= 'F')
++		return (ch - 'A' + 10);
++	else
++	if (ch >= 'a' && ch <= 'f')
++		return (ch - 'a' + 10);
++	else {
++		assert(0);
++		return 0;
++	}
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Decode quoted printable string in-place
++//
++////////////////////////////////////////////////////////////////////////////////
++void
++DecodeQuotedPrintable(char *ptr)
++{
++	char           *s = ptr;
++	while (*s != '\0' && *s != '=')
++		s++;
++	if (*s == '\0')
++		return;
++	char           *d = s;
++	do {
++		if (*s == '=' && isxdigit(s[1]) && isxdigit(s[2])) {
++			*d++ = (tohex(s[1]) << 4) | tohex(s[2]);
++			s += 3;
++		} else {
++			*d++ = *s++;
++		}
++	} while (*s != '\0');
++	*d = '\0';
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Decode base64 string in-place, returns number of bytes output
++//
++////////////////////////////////////////////////////////////////////////////////
++unsigned
++DecodeBase64(char *ptr)
++{
++	static const char base64_table[256] =
++		{ -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, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
++		-1, -1,
++		-1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
++		-1, -1,
++		26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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, -1, -1, -1, -1, -1
++	};
++	unsigned char  *s = (unsigned char *) ptr;
++	unsigned char  *d = (unsigned char *) ptr;
++	unsigned        b64accum = 0;
++	unsigned char   b64shift = 0;
++	while (*s != '\0') {
++		unsigned char value = base64_table[*s++];
++		if ((signed char) value >= 0) {
++			b64accum = (b64accum << 6) | value;
++			b64shift += 6;
++			if (b64shift >= 8) {
++				b64shift -= 8;
++				*d++ = (b64accum >> b64shift);
++			}
++		}
++	}
++	return (char *) d - ptr;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Match a string with a pattern (used for g= value)
++// Supports a single, optional "*" wildcard character.
++//
++////////////////////////////////////////////////////////////////////////////////
++bool
++WildcardMatch(const char *p, const char *s)
++{
++	// special case: An empty "g=" value never matches any addresses
++	if (*p == '\0')
++		return false;
++	const char     *wildcard = strchr(p, '*');
++	if (wildcard == NULL)
++		return strcmp(s, p) == 0;
++	else {
++		unsigned beforewildcardlen = wildcard - p;
++		unsigned afterwildcardlen = strlen(wildcard + 1);
++		unsigned slen = strlen(s);
++		return (slen >= beforewildcardlen + afterwildcardlen) && (strncmp(s, p, beforewildcardlen) == 0)
++			&& strcmp(s + slen - afterwildcardlen, wildcard + 1) == 0;
++	}
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Parse addresses from a string.  Returns true if at least one address found
++//
++////////////////////////////////////////////////////////////////////////////////
++bool
++ParseAddresses(string str, vector < string > &Addresses)
++{
++	char           *s = (char *) str.c_str();
++	while (*s != '\0') {
++		char           *start = s;
++		char           *from = s;
++		char           *to = s;
++		char           *lt = NULL;	// pointer to less than character (<) which starts the address if found
++		while (*from != '\0') {
++			if (*from == '(') {
++				// skip over comment
++				from++;
++				for (int depth = 1; depth != 0; from++) {
++					if (*from == '\0')
++						break;
++					else
++					if (*from == '(')
++						depth++;
++					else
++					if (*from == ')')
++						depth--;
++					else
++					if (*from == '\\' && from[1] != '\0')
++						from++;
++				}
++			}
++			else
++			if (*from == ')') {
++				// ignore closing parenthesis outside of comment
++				from++;
++			}
++
++			else
++			if (*from == ',' || *from == ';') {
++				// comma/selicolon ends the address
++				from++;
++				break;
++			}
++			else
++			if (*from == ' ' || *from == '\t' || *from == '\r' || *from == '\n') {
++				// ignore whitespace
++				from++;
++			}
++			else
++			if (*from == '"') {
++				// copy the contents of a quoted string
++				from++;
++				while (*from != '\0') {
++					if (*from == '"') {
++						from++;
++						break;
++					}
++					else
++					if (*from == '\\' && from[1] != '\0')
++						*to++ = *from++;
++					*to++ = *from++;
++				}
++			}
++			else
++			if (*from == '\\' && from[1] != '\0') {
++				// copy quoted-pair
++				*to++ = *from++;
++				*to++ = *from++;
++			} else {
++				// copy any other char
++				*to = *from++;
++				// save pointer to '<' for later...
++				if (*to == '<')
++					lt = to;
++				to++;
++			}
++		}
++		*to = '\0';
++		// if there's < > get what's inside
++		if (lt != NULL) {
++			start = lt + 1;
++			char           *gt = strchr(start, '>');
++			if (gt != NULL)
++				*gt = '\0';
++		} else {
++			// look for and strip group name
++			char           *colon = strchr(start, ':');
++			if (colon != NULL) {
++				char           *at = strchr(start, '@');
++				if (at == NULL || colon < at)
++					start = colon + 1;
++			}
++		}
++		if (*start != '\0' && strchr(start, '@') != NULL)
++			Addresses.push_back(start);
++		s = from;
++	}
++	return !Addresses.empty();
++}
++
++CDKIMVerify::CDKIMVerify()
++{
++	m_pfnSelectorCallback = NULL;
++	m_pfnPracticesCallback = NULL;
++	m_HonorBodyLengthTag = false;
++	m_CheckPractices = false;
++	m_Accept3ps = false;
++	m_SubjectIsRequired = true;
++	m_SaveCanonicalizedData = false;
++	m_AllowUnsignedFromHeaders = false;
++}
++
++CDKIMVerify::~CDKIMVerify()
++{
++}
++
++// Init - save the options
++int
++CDKIMVerify::Init(DKIMVerifyOptions *pOptions)
++{
++	int             nRet = CDKIMBase::Init();
++	m_pfnSelectorCallback = pOptions->pfnSelectorCallback;
++	m_pfnPracticesCallback = pOptions->pfnPracticesCallback;
++
++	m_HonorBodyLengthTag = pOptions->nHonorBodyLengthTag != 0;
++	m_CheckPractices = pOptions->nCheckPractices != 0;
++	m_SubjectIsRequired = pOptions->nSubjectRequired != 0;
++	m_Accept3ps = pOptions->nAccept3ps != 0;		//TBS(Luc)
++	m_SaveCanonicalizedData = pOptions->nSaveCanonicalizedData != 0;
++	m_AllowUnsignedFromHeaders = pOptions->nAllowUnsignedFromHeaders != 0;
++	return nRet;
++}
++
++// GetResults - return the pass/fail/neutral verification result
++int
++CDKIMVerify::GetResults(int *sCount, int *sSize)
++{
++	ProcessFinal();
++	unsigned int    SuccessCount = 0;
++	int             TestingFailures = 0;
++	int             RealFailures = 0;
++	list <string>   SuccessfulDomains;	// can contain duplicates
++	/* get the From address's domain if we might need it */
++	string          sFromDomain;
++
++	for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
++		if (i->Status == DKIM_SUCCESS) {
++			if (!i->BodyHashData.empty()) {
++				// check the body hash
++				unsigned char   md[EVP_MAX_MD_SIZE];
++				unsigned        len = 0;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++				int             res = EVP_DigestFinal(i->m_Bdy_ctx, md, &len);
++#else
++				int             res = EVP_DigestFinal(&i->m_Bdy_ctx, md, &len);
++#endif
++				if (!res || len != i->BodyHashData.length() || memcmp(i->BodyHashData.data(), md, len) != 0) {
++					// body hash mismatch
++					// if the selector is in testing mode...
++					if (i->m_pSelector->Testing) {
++						i->Status = DKIM_SIGNATURE_BAD_BUT_TESTING;	// todo: make a new error code for this?
++						TestingFailures++;
++					} else {
++						i->Status = DKIM_BODY_HASH_MISMATCH;
++						RealFailures++;
++					}
++					continue;
++				}
++			} else {
++				// hash CRLF separating the body from the signature
++				i->Hash("\r\n", 2);
++			}
++			// check the header hash
++			string          sSignedSig = i->Header;
++			string          sSigValue = sSignedSig.substr(sSignedSig.find(':') + 1);
++			static const char *tags[] = { "b", NULL };
++			char           *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
++			char           *pSigValue = (char *) sSigValue.c_str();
++			if (ParseTagValueList(pSigValue, tags, values) && values[0] != NULL) {
++				sSignedSig.erase(15 + values[0] - pSigValue, strlen(values[0]));
++			}
++			if (i->HeaderCanonicalization == DKIM_CANON_RELAXED) {
++				sSignedSig = RelaxHeader(sSignedSig);
++			} else
++			if (i->HeaderCanonicalization == DKIM_CANON_NOWSP) {
++				RemoveSWSP(sSignedSig);
++				// convert "DKIM-Signature" to lower case
++				sSignedSig.replace(0, 14, "dkim-signature", 14);
++			}
++			i->Hash(sSignedSig.c_str(), sSignedSig.length());
++			assert(i->m_pSelector != NULL);
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++			int             res = EVP_VerifyFinal(i->m_Hdr_ctx, (unsigned char *) i->SignatureData.data(),
++							i->SignatureData.length(), i->m_pSelector->PublicKey);
++#else
++			int             res = EVP_VerifyFinal(&i->m_Hdr_ctx, (unsigned char *) i->SignatureData.data(),
++							i->SignatureData.length(), i->m_pSelector->PublicKey);
++#endif
++			if (res == 1) {
++				if (i->UnverifiedBodyCount == 0)
++					i->Status = DKIM_SUCCESS;
++				else
++					i->Status = DKIM_SUCCESS_BUT_EXTRA;
++				SuccessCount++;
++				SuccessfulDomains.push_back(i->Domain);
++			} else {
++				// if the selector is in testing mode...
++				if (i->m_pSelector->Testing) {
++					i->Status = DKIM_SIGNATURE_BAD_BUT_TESTING;
++					TestingFailures++;
++				} else {
++					i->Status = DKIM_SIGNATURE_BAD;
++					RealFailures++;
++				}
++			}
++		} else
++		if (i->Status == DKIM_SELECTOR_GRANULARITY_MISMATCH 
++			|| i->Status == DKIM_SELECTOR_ALGORITHM_MISMATCH
++			|| i->Status == DKIM_SELECTOR_KEY_REVOKED) {
++			// treat these as failures
++			// todo: maybe see if the selector is in testing mode?
++			RealFailures++;
++		}
++	}
++	if (SuccessCount > 0 || m_CheckPractices) {
++		for (list < string >::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
++			if (_strnicmp(i->c_str(), "From", 4) == 0) {
++				// skip over whitespace between the header name and :
++				const char     *s = i->c_str() + 4;
++				while (*s == ' ' || *s == '\t')
++					s++;
++				if (*s == ':') {
++					vector <string> Addresses;
++					if (ParseAddresses(s + 1, Addresses)) {
++						unsigned atpos = Addresses[0].find('@');
++						sFromDomain = Addresses[0].substr(atpos + 1);
++						break;
++					}
++				}
++			}
++		}
++	}
++	// if a signature from the From domain verified successfully, return success now
++	// without checking the sender signing practices
++	if (SuccessCount > 0 && !sFromDomain.empty()) {
++		for (list < string >::iterator i = SuccessfulDomains.begin(); i != SuccessfulDomains.end(); ++i) {
++			// see if the successful domain is the same as or a parent of the From domain
++			if (i->length() > sFromDomain.length())
++				continue;
++			if (_stricmp(i->c_str(), sFromDomain.c_str() + sFromDomain.length() - i->length()) != 0)
++				continue;
++			if (i->length() == sFromDomain.length() || sFromDomain.c_str()[sFromDomain.length() - i->length() - 1] == '.')
++				return ((SuccessCount == Signatures.size()) ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
++		}
++	}
++	if (!m_Accept3ps)
++		return DKIM_NEUTRAL;
++	*sCount = SuccessCount;
++	*sSize = Signatures.size();
++	return DKIM_3PS_SIGNATURE;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Hash - update the hash
++//
++////////////////////////////////////////////////////////////////////////////////
++void
++SignatureInfo::Hash(const char *szBuffer, unsigned nBufLength, bool IsBody)
++{
++
++	if (IsBody && BodyLength != -1) {
++		VerifiedBodyCount += nBufLength;
++		if (VerifiedBodyCount > BodyLength) {
++			nBufLength = BodyLength - (VerifiedBodyCount - nBufLength);
++			UnverifiedBodyCount += VerifiedBodyCount - BodyLength;
++			VerifiedBodyCount = BodyLength;
++			if (nBufLength == 0)
++				return;
++		}
++	}
++	if (IsBody && !BodyHashData.empty()) {
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++		EVP_DigestUpdate(m_Bdy_ctx, szBuffer, nBufLength);
++#else
++		EVP_DigestUpdate(&m_Bdy_ctx, szBuffer, nBufLength);
++#endif
++	} else {
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++		EVP_VerifyUpdate(m_Hdr_ctx, szBuffer, nBufLength);
++#else
++		EVP_VerifyUpdate(&m_Hdr_ctx, szBuffer, nBufLength);
++#endif
++	}
++	if (m_SaveCanonicalizedData) {
++		CanonicalizedData.append(szBuffer, nBufLength);
++	}
++}
++
++
++// ProcessHeaders - Look for DKIM-Signatures and start processing them
++int
++CDKIMVerify::ProcessHeaders(void)
++{
++
++	// look for DKIM-Signature header(s)
++	for (list < string >::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
++		if (_strnicmp(i->c_str(), "DKIM-Signature", 14) == 0) {
++			// skip over whitespace between the header name and :
++			const char     *s = i->c_str() + 14;
++			while (*s == ' ' || *s == '\t')
++				s++;
++			if (*s == ':') {
++				// found
++				SignatureInfo   sig(m_SaveCanonicalizedData);
++				sig.Status = ParseDKIMSignature(*i, sig);
++				Signatures.push_back(sig);
++				if (Signatures.size() >= MAX_SIGNATURES)
++					break;
++			}
++		}
++	}
++	if (Signatures.empty())
++		return DKIM_NO_SIGNATURES;
++	bool            ValidSigFound = false;
++	for (list < SignatureInfo >::iterator s = Signatures.begin(); s != Signatures.end(); ++s) {
++		SignatureInfo &sig = *s;
++		if (sig.Status != DKIM_SUCCESS)
++			continue;
++		SelectorInfo &sel = GetSelector(sig.Selector, sig.Domain);
++		sig.m_pSelector = &sel;
++		if (sel.Status != DKIM_SUCCESS) {
++			sig.Status = sel.Status;
++			return (sig.Status);
++		} else {
++			// check the granularity
++			if (!WildcardMatch(sel.Granularity.c_str(), sig.IdentityLocalPart.c_str()))
++				sig.Status = DKIM_SELECTOR_GRANULARITY_MISMATCH;	// this error causes the signature to fail
++			// check the hash algorithm
++#ifdef HAVE_EVP_SHA256
++			if ((sig.m_nHash == DKIM_HASH_SHA1 && !sel.AllowSHA1) || (sig.m_nHash == DKIM_HASH_SHA256 && !sel.AllowSHA256))
++#else
++			if ((sig.m_nHash == DKIM_HASH_SHA1 && !sel.AllowSHA1))
++#endif
++				sig.Status = DKIM_SELECTOR_ALGORITHM_MISMATCH;	// causes signature to fail
++			// check for same domain
++			if (sel.SameDomain && _stricmp(sig.Domain.c_str(), sig.IdentityDomain.c_str()) != 0)
++				sig.Status = DKIM_BAD_SYNTAX;
++		}
++		if (sig.Status != DKIM_SUCCESS)
++			continue;
++		// initialize the hashes
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++#ifdef HAVE_EVP_SHA256
++		if (sig.m_nHash == DKIM_HASH_SHA256) {
++			EVP_VerifyInit(sig.m_Hdr_ctx, EVP_sha256());
++			EVP_DigestInit(sig.m_Bdy_ctx, EVP_sha256());
++		} else {
++			EVP_VerifyInit(sig.m_Hdr_ctx, EVP_sha1());
++			EVP_DigestInit(sig.m_Bdy_ctx, EVP_sha1());
++		}
++#else
++		EVP_VerifyInit(sig.m_Hdr_ctx, EVP_sha1());
++		EVP_DigestInit(sig.m_Bdy_ctx, EVP_sha1());
++#endif
++#else
++#ifdef HAVE_EVP_SHA256
++		if (sig.m_nHash == DKIM_HASH_SHA256) {
++			EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha256());
++			EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha256());
++		} else {
++			EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha1());
++			EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha1());
++		}
++#else
++		EVP_VerifyInit(&sig.m_Hdr_ctx, EVP_sha1());
++		EVP_DigestInit(&sig.m_Bdy_ctx, EVP_sha1());
++#endif
++#endif
++		// compute the hash of the header
++		vector < list < string >::reverse_iterator > used;
++		for (vector < string >::iterator x = sig.SignedHeaders.begin(); x != sig.SignedHeaders.end(); ++x) {
++			list < string >::reverse_iterator i;
++			for (i = HeaderList.rbegin(); i != HeaderList.rend(); ++i) {
++				if (_strnicmp(i->c_str(), x->c_str(), x->length()) == 0) {
++					// skip over whitespace between the header name and :
++					const char     *s = i->c_str() + x->length();
++					while (*s == ' ' || *s == '\t')
++						s++;
++					if (*s == ':' && find(used.begin(), used.end(), i) == used.end())
++						break;
++				}
++			}
++			if (i != HeaderList.rend()) {
++				used.push_back(i);
++				// hash this header
++				if (sig.HeaderCanonicalization == DKIM_CANON_SIMPLE)
++					sig.Hash(i->c_str(), i->length());
++				else
++				if (sig.HeaderCanonicalization == DKIM_CANON_RELAXED) {
++					string          sTemp = RelaxHeader(*i);
++					sig.Hash(sTemp.c_str(), sTemp.length());
++				} else
++				if (sig.HeaderCanonicalization == DKIM_CANON_NOWSP) {
++					string          sTemp = *i;
++					RemoveSWSP(sTemp);
++					// convert characters before ':' to lower case
++					for (char *s = (char *)sTemp.c_str(); *s != '\0' && *s != ':'; s++) {
++						if (*s >= 'A' && *s <= 'Z')
++							*s += 'a' - 'A';
++					}
++					sig.Hash(sTemp.c_str(), sTemp.length());
++				}
++				sig.Hash("\r\n", 2);
++			}
++		}
++		if (sig.BodyHashData.empty()) {
++			// hash CRLF separating headers from body
++			sig.Hash("\r\n", 2);
++		}
++		if (!m_AllowUnsignedFromHeaders) {
++			// make sure the message has no unsigned From headers
++			list<string>::reverse_iterator i;
++			for( i = HeaderList.rbegin(); i != HeaderList.rend(); ++i ) {
++				if( _strnicmp(i->c_str(), "From", 4 ) == 0 ) {
++					// skip over whitespace between the header name and :
++					const char *s = i->c_str()+4;
++					while (*s == ' ' || *s == '\t')
++						s++;
++					if (*s == ':') {
++						if (find(used.begin(), used.end(), i) == used.end()) {
++							// this From header was not signed
++							break;
++						}
++					}
++				}
++			}
++			if (i != HeaderList.rend()) {
++				// treat signature as invalid
++				sig.Status = DKIM_UNSIGNED_FROM;
++				continue;
++			}
++		}
++		ValidSigFound = true;
++	} /*- for (list < SignatureInfo >::iterator s = Signatures.begin(); s != Signatures.end(); ++s) { */
++	if (!ValidSigFound)
++		return DKIM_NO_VALID_SIGNATURES;
++	return DKIM_SUCCESS;
++}
++
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Strictly parse an unsigned integer.  Don't allow spaces, negative sign,
++// 0x prefix, etc.  Values greater than 2^32-1 are capped at 2^32-1
++//
++////////////////////////////////////////////////////////////////////////////////
++bool
++ParseUnsigned(const char *s, unsigned long *result)
++{
++	unsigned        temp = 0, last = 0;
++	bool            overflowed = false;
++
++	do {
++		if (*s < '0' || *s > '9')
++			return false;		// returns false for an initial '\0'
++		temp = temp * 10 + (*s - '0');
++		if (temp < last)
++			overflowed = true;
++		last = temp;
++		s++;
++	} while (*s != '\0');
++	if (overflowed)
++		*result = -1;
++	else
++		*result = temp;
++	return true;
++}
++
++
++// ParseDKIMSignature - Parse a DKIM-Signature header field
++int
++CDKIMVerify::ParseDKIMSignature(const string &sHeader, SignatureInfo &sig)
++{
++
++	// save header for later
++	sig.Header = sHeader;
++	string          sValue = sHeader.substr(sHeader.find(':') + 1);
++	static const char *tags[] = { "v", "a", "b", "d", "h", "s", "c", "i", "l", "q", "t", "x", "bh", NULL };
++	char           *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
++	char           *saveptr;
++
++	if (!ParseTagValueList((char *) sValue.c_str(), tags, values))
++		return DKIM_BAD_SYNTAX;
++	// check signature version
++	if (values[0] != NULL) {
++		if (strcmp(values[0], "1") == 0 || strcmp(values[0], "0.5") == 0 || strcmp(values[0], "0.4") == 0
++			|| strcmp(values[0], "0.3") == 0 || strcmp(values[0], "0.2") == 0) {
++			sig.Version = DKIM_SIG_VERSION_02_PLUS;
++		} else {
++		// unknown version
++			return DKIM_STAT_INCOMPAT;
++		}
++	} else {
++		// Note:  DKIM Interop 1 pointed out that v= is now required, but we do
++		// not enforce that in order to verify signatures made by older drafts.
++
++		// prior to 0.2, there MUST NOT have been a v=
++		// (optionally) support these signatures, for backwards compatibility
++		if (true) {
++			sig.Version = DKIM_SIG_VERSION_PRE_02;
++		} else {
++			return DKIM_BAD_SYNTAX;
++		}
++	}
++	// signature MUST have a=, b=, d=, h=, s=
++	if (values[1] == NULL || values[2] == NULL || values[3] == NULL || values[4] == NULL || values[5] == NULL)
++		return DKIM_BAD_SYNTAX;
++	// algorithm can be "rsa-sha1" or "rsa-sha256"
++	if (strcmp(values[1], "rsa-sha1") == 0) {
++		sig.m_nHash = DKIM_HASH_SHA1;
++	}
++#ifdef HAVE_EVP_SHA256
++	else if (strcmp(values[1], "rsa-sha256") == 0) {
++		sig.m_nHash = DKIM_HASH_SHA256;
++	}
++#endif
++	else {
++		return DKIM_BAD_SYNTAX;	// todo: maybe create a new error code for unknown algorithm
++	}
++	// make sure the signature data is not empty
++	unsigned SigDataLen = DecodeBase64(values[2]);
++	if (SigDataLen == 0)
++		return DKIM_BAD_SYNTAX;
++	sig.SignatureData.assign(values[2], SigDataLen);
++	// check for body hash
++	if (values[12] == NULL) {
++		// use the old single hash way for backwards compatibility
++		if (sig.Version != DKIM_SIG_VERSION_PRE_02)
++			return DKIM_BAD_SYNTAX;
++	} else {
++		unsigned BodyHashLen = DecodeBase64(values[12]);
++		if (BodyHashLen == 0)
++			return DKIM_BAD_SYNTAX;
++		sig.BodyHashData.assign(values[12], BodyHashLen);
++	}
++	// domain must not be empty
++	if (*values[3] == '\0')
++		return DKIM_BAD_SYNTAX;
++	sig.Domain = values[3];
++	// signed headers must not be empty (more verification is done later)
++	if (*values[4] == '\0')
++		return DKIM_BAD_SYNTAX;
++	// selector must not be empty
++	if (*values[5] == '\0')
++		return DKIM_BAD_SYNTAX;
++	sig.Selector = values[5];
++	// canonicalization
++	if (values[6] == NULL) {
++		sig.HeaderCanonicalization = sig.BodyCanonicalization = DKIM_CANON_SIMPLE;
++	}
++	else
++	if (sig.Version == DKIM_SIG_VERSION_PRE_02 && strcmp(values[6], "nowsp") == 0) {
++	// for backwards compatibility
++		sig.HeaderCanonicalization = sig.BodyCanonicalization = DKIM_CANON_NOWSP;
++	} else {
++		char           *slash = strchr(values[6], '/');
++		if (slash != NULL)
++			*slash = '\0';
++		if (strcmp(values[6], "simple") == 0)
++			sig.HeaderCanonicalization = DKIM_CANON_SIMPLE;
++		else
++		if (strcmp(values[6], "relaxed") == 0)
++			sig.HeaderCanonicalization = DKIM_CANON_RELAXED;
++		else
++			return DKIM_BAD_SYNTAX;
++		if (slash == NULL || strcmp(slash + 1, "simple") == 0)
++			sig.BodyCanonicalization = DKIM_CANON_SIMPLE;
++		else
++		if (strcmp(slash + 1, "relaxed") == 0)
++			sig.BodyCanonicalization = DKIM_CANON_RELAXED;
++		else
++			return DKIM_BAD_SYNTAX;
++	}
++	// identity
++	if (values[7] == NULL) {
++		sig.IdentityLocalPart.erase();
++		sig.IdentityDomain = sig.Domain;
++	} else {
++		// quoted-printable decode the value
++		DecodeQuotedPrintable(values[7]);
++		// must have a '@' separating the local part from the domain
++		char           *at = strchr(values[7], '@');
++		if (at == NULL)
++			return DKIM_BAD_SYNTAX;
++		*at = '\0';
++		char           *ilocalpart = values[7];
++		char           *idomain = at + 1;
++		// i= domain must be the same as or a subdomain of the d= domain
++		int idomainlen = strlen(idomain);
++		int ddomainlen = strlen(values[3]);
++
++		// todo: maybe create a new error code for invalid identity domain
++		if (idomainlen < ddomainlen)
++			return DKIM_BAD_SYNTAX;
++		if (_stricmp(idomain + idomainlen - ddomainlen, values[3]) != 0)
++			return DKIM_BAD_SYNTAX;
++		if (idomainlen > ddomainlen && idomain[idomainlen - ddomainlen - 1] != '.')
++			return DKIM_BAD_SYNTAX;
++		sig.IdentityLocalPart = ilocalpart;
++		sig.IdentityDomain = idomain;
++	}
++	// body count
++	if (values[8] == NULL || !m_HonorBodyLengthTag) {
++		sig.BodyLength = -1;
++	} else {
++		if (!ParseUnsigned(values[8], (unsigned long *) &sig.BodyLength))
++			return DKIM_BAD_SYNTAX;
++	}
++	// query methods
++	if (values[9] != NULL) {
++
++		// make sure "dns" is in the list
++		bool            HasDNS = false;
++		char           *s = strtok_r(values[9], ":", &saveptr);
++		while (s != NULL) {
++			if (strncmp(s, "dns", 3) == 0 && (s[3] == '\0' || s[3] == '/')) {
++				HasDNS = true;
++				break;
++			}
++			s = strtok_r(NULL, ": \t", &saveptr);
++		}
++		if (!HasDNS)
++			return DKIM_BAD_SYNTAX;	// todo: maybe create a new error code for unknown query method
++	}
++	// signature time
++	time_t          SignedTime = -1;
++	if (values[10] != NULL) {
++		if (!ParseUnsigned(values[10], (unsigned long *) &SignedTime))
++			return DKIM_BAD_SYNTAX;
++	}
++	// expiration time
++	if (values[11] == NULL) {
++		sig.ExpireTime = -1;
++	} else {
++		if (!ParseUnsigned(values[11], (unsigned long *) &sig.ExpireTime))
++			return DKIM_BAD_SYNTAX;
++		if (sig.ExpireTime != -1) {
++			// the value of x= MUST be greater than the value of t= if both are present
++			if (SignedTime != -1 && sig.ExpireTime <= SignedTime)
++				return DKIM_BAD_SYNTAX;
++			// todo: if possible, use the received date/time instead of the current time
++			time_t curtime = time(NULL);
++			if (curtime > sig.ExpireTime)
++				return DKIM_SIGNATURE_EXPIRED;
++		}
++	}
++	// parse the signed headers list
++	bool            HasFrom = false, HasSubject = false;
++	RemoveSWSP(values[4]);		// header names shouldn't have spaces in them so this should be ok...
++	char           *s = strtok_r(values[4], ":", &saveptr);
++	while (s != NULL) {
++		if (_stricmp(s, "From") == 0)
++			HasFrom = true;
++		else 
++		if (_stricmp(s, "Subject") == 0)
++			HasSubject = true;
++		sig.SignedHeaders.push_back(s);
++		s = strtok_r(NULL, ":", &saveptr);
++	}
++	if (!HasFrom)
++		return DKIM_BAD_SYNTAX;	// todo: maybe create a new error code for h= missing From
++	if (m_SubjectIsRequired && !HasSubject)
++		return DKIM_BAD_SYNTAX;	// todo: maybe create a new error code for h= missing Subject
++	return DKIM_SUCCESS;
++}
++
++
++// ProcessBody - Process message body data
++int
++CDKIMVerify::ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
++{
++	bool            MoreBodyNeeded = false;
++
++	for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
++		if (i->Status == DKIM_SUCCESS) {
++			if (i->BodyCanonicalization == DKIM_CANON_SIMPLE) {
++				if (nBufLength > 0) {
++					while (i->EmptyLineCount > 0) {
++						i->Hash("\r\n", 2, true);
++						i->EmptyLineCount--;
++					}
++					i->Hash(szBuffer, nBufLength, true);
++					i->Hash("\r\n", 2, true);
++				} else {
++					i->EmptyLineCount++;
++					if (bEOF)
++						i->Hash("\r\n", 2, true);
++				}
++			} else
++			if (i->BodyCanonicalization == DKIM_CANON_RELAXED) {
++				CompressSWSP(szBuffer, nBufLength);
++				if (nBufLength > 0) {
++					while (i->EmptyLineCount > 0) {
++						i->Hash("\r\n", 2, true);
++						i->EmptyLineCount--;
++					}
++					i->Hash(szBuffer, nBufLength, true);
++					if (!bEOF)
++						i->Hash("\r\n", 2, true);
++				} else
++					i->EmptyLineCount++;
++			} else
++			if (i->BodyCanonicalization == DKIM_CANON_NOWSP) {
++				RemoveSWSP(szBuffer, nBufLength);
++				i->Hash(szBuffer, nBufLength, true);
++			}
++			if (i->UnverifiedBodyCount == 0)
++				MoreBodyNeeded = true;
++		}
++	}
++	if (!MoreBodyNeeded)
++		return DKIM_FINISHED_BODY;
++	return DKIM_SUCCESS;
++}
++
++SelectorInfo::SelectorInfo(const string &sSelector, const string &sDomain):Selector(sSelector), Domain(sDomain)
++{
++	AllowSHA1 = true;
++#ifdef HAVE_EVP_SHA256
++	AllowSHA256 = true;
++#else
++	AllowSHA256 = false;
++#endif
++	PublicKey = NULL;
++	Testing = false;
++	SameDomain = false;
++	Status = DKIM_SUCCESS;
++} SelectorInfo::~SelectorInfo()
++{
++	if (PublicKey != NULL) {
++		EVP_PKEY_free(PublicKey);
++	}
++}
++
++////////////////////////////////////////////////////////////////////////////////
++// 
++// Parse - Parse a DKIM selector
++//
++////////////////////////////////////////////////////////////////////////////////
++int
++SelectorInfo::Parse(char *Buffer)
++{
++	static const char *tags[] = { "v", "g", "h", "k", "p", "s", "t", "n", NULL };
++	char           *values[sizeof (tags) / sizeof (tags[0])] = { NULL };
++	char           *saveptr;
++
++	if (!ParseTagValueList(Buffer, tags, values))
++		return DKIM_SELECTOR_INVALID;
++	if (values[0] != NULL) {
++
++		// make sure the version is "DKIM1"
++		if (strcmp(values[0], "DKIM1") != 0)
++			return DKIM_SELECTOR_INVALID;	// todo: maybe create a new error code for unsupported selector version
++		// make sure v= is the first tag in the response    // todo: maybe don't enforce this, it seems unnecessary
++		for (unsigned int j = 1; j < sizeof (values) / sizeof (values[0]); j++) {
++			if (values[j] != NULL && values[j] < values[0]) {
++				return DKIM_SELECTOR_INVALID;
++			}
++		}
++	}
++	// selector MUST have p= tag
++	if (values[4] == NULL)
++		return DKIM_SELECTOR_INVALID;
++	// granularity
++	if (values[1] == NULL)
++		Granularity = "*";
++
++	else
++		Granularity = values[1];
++	// hash algorithm
++	if (values[2] == NULL) {
++		AllowSHA1 = true;
++#ifdef HAVE_EVP_SHA256
++		AllowSHA256 = true;
++#else
++		AllowSHA256 = false;
++#endif
++	} else {
++		// MUST include "sha1" or "sha256"
++		char           *s = strtok_r(values[2], ":", &saveptr);
++		while (s != NULL) {
++			if (strcmp(s, "sha1") == 0)
++				AllowSHA1 = true;
++#ifdef HAVE_EVP_SHA256
++			else if (strcmp(s, "sha256") == 0)
++				AllowSHA256 = true;
++#endif
++			s = strtok_r(NULL, ":", &saveptr);
++		}
++#ifdef HAVE_EVP_SHA256
++		if (!(AllowSHA1 || AllowSHA256))
++#else
++		if (!AllowSHA1)
++#endif
++			return DKIM_SELECTOR_INVALID;	// todo: maybe create a new error code for unsupported hash algorithm
++	}
++	// key type
++	if (values[3] != NULL) {
++		// key type MUST be "rsa"
++		if (strcmp(values[3], "rsa") != 0)
++			return DKIM_SELECTOR_INVALID;
++	}
++	// service type
++	if (values[5] != NULL) {
++		// make sure "*" or "email" is in the list
++		bool            ServiceTypeMatch = false;
++		char           *s = strtok_r(values[5], ":", &saveptr);
++		while (s != NULL) {
++			if (strcmp(s, "*") == 0 || strcmp(s, "email") == 0) {
++				ServiceTypeMatch = true;
++				break;
++			}
++			s = strtok_r(NULL, ":", &saveptr);
++		}
++		if (!ServiceTypeMatch)
++			return DKIM_SELECTOR_INVALID;
++	}
++	// flags
++	if (values[6] != NULL) {
++		char           *s = strtok_r(values[6], ":", &saveptr);
++		while (s != NULL) {
++			if (strcmp(s, "y") == 0) {
++				Testing = true;
++			} else
++			if (strcmp(s, "s") == 0) {
++				SameDomain = true;
++			}
++			s = strtok_r(NULL, ":", &saveptr);
++		}
++	}
++#define M_ToConstUCharPtr(p)       reinterpret_cast<const unsigned char*>(p)          // Cast to unsigned char*
++	/*- public key data */
++	unsigned        PublicKeyLen = DecodeBase64(values[4]);
++	if (PublicKeyLen == 0)
++		return DKIM_SELECTOR_KEY_REVOKED;	// this error causes the signature to fail
++	else {
++		EVP_PKEY       *pkey;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++		int             rtype;
++#endif
++		const unsigned char  *qq; /*- public key data */
++
++		qq = M_ToConstUCharPtr(values[4]);
++#ifdef DARWIN
++		pkey = d2i_PUBKEY(NULL, (unsigned char **) &qq, PublicKeyLen);
++#else
++		pkey = d2i_PUBKEY(NULL, &qq, PublicKeyLen);
++#endif
++		if (!pkey)
++			return DKIM_SELECTOR_PUBLIC_KEY_INVALID;
++		/*- make sure public key is the correct type (we only support rsa) */
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++		rtype = EVP_PKEY_base_id(pkey);
++		if (rtype == EVP_PKEY_RSA || rtype == EVP_PKEY_RSA2)
++#else
++		if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2)
++#endif
++			PublicKey = pkey;
++		else {
++			EVP_PKEY_free(pkey);
++			return DKIM_SELECTOR_PUBLIC_KEY_INVALID;
++		}
++	}
++	return DKIM_SUCCESS;
++}
++
++// GetSelector - Get a DKIM selector for a domain
++SelectorInfo &CDKIMVerify::GetSelector(const string &sSelector, const string &sDomain)
++{
++
++	// see if we already have this selector
++	for (list < SelectorInfo >::iterator i = Selectors.begin(); i != Selectors.end(); ++i) {
++		if (_stricmp(i->Selector.c_str(), sSelector.c_str()) == 0 && _stricmp(i->Domain.c_str(), sDomain.c_str()) == 0) {
++			return *i;
++		}
++	}
++	Selectors.push_back(SelectorInfo(sSelector, sDomain));
++	SelectorInfo &sel = Selectors.back();
++	string sFQDN = sSelector;
++	sFQDN += "._domainkey.";
++	sFQDN += sDomain;
++	char            Buffer[1024];
++	int             DNSResult;
++
++	if (m_pfnSelectorCallback)
++		DNSResult = m_pfnSelectorCallback(sFQDN.c_str(), Buffer, sizeof(Buffer));
++	else
++		DNSResult = DNSGetTXT(sFQDN.c_str(), Buffer, sizeof(Buffer));
++	switch (DNSResult) {
++	case DNSRESP_SUCCESS:
++		sel.Status = sel.Parse(Buffer);
++		break;
++	case DNSRESP_TEMP_FAIL:
++		sel.Status = DKIM_SELECTOR_DNS_TEMP_FAILURE;
++		break;
++	case DNSRESP_PERM_FAIL:
++	default:
++		sel.Status = DKIM_SELECTOR_DNS_PERM_FAILURE;
++		break;
++	case DNSRESP_DOMAIN_NAME_TOO_LONG:
++		sel.Status = DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG;
++		break;
++	}
++	return sel;
++}
++
++// GetDetails - Get DKIM verification details (per signature)
++int
++CDKIMVerify::GetDetails(int *nSigCount, DKIMVerifyDetails ** pDetails)
++{
++	Details.clear();
++	for (list < SignatureInfo >::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
++		DKIMVerifyDetails d;
++		d.szSignature = (char *) i->Header.c_str();
++		d.szSignatureDomain = (char*)i->Domain.c_str();
++		d.szIdentityDomain = (char*)i->IdentityDomain.c_str();
++		d.nResult = i->Status;
++		d.szCanonicalizedData = (char *) i->CanonicalizedData.c_str();
++		Details.push_back(d);
++	} *nSigCount = Details.size();
++	*pDetails = (*nSigCount != 0) ? &Details[0] : NULL;
++	return DKIM_SUCCESS;
++}
++
++char           *DKIM_CALL
++CDKIMVerify::GetDomain(void)
++{
++	string          sFromDomain;
++	for (list <string>::iterator i = HeaderList.begin(); i != HeaderList.end(); ++i) {
++		if (_strnicmp(i->c_str(), "From", 4) == 0) {
++			// skip over whitespace between the header name and :
++			const char     *s = i->c_str() + 4;
++			while (*s == ' ' || *s == '\t')
++				s++;
++			if (*s == ':') {
++				vector <string> Addresses;
++				if (ParseAddresses(s + 1, Addresses)) {
++					unsigned atpos = Addresses[0].find('@');
++					sFromDomain = Addresses[0].substr(atpos + 1);
++					break;
++				}
++			}
++		}
++	}
++	return ((char *) sFromDomain.c_str());
++}
++
++void
++getversion_dkimverify_cpp()
++{
++	static char    *x = (char *) "$Id: dkimverify.cpp,v 1.18 2017-09-05 11:00:33+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dkimverify.h netqmail-1.06/dkimverify.h
+--- ../netqmail-1.06-original/dkimverify.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dkimverify.h	2018-04-03 14:46:51.367411617 +0200
+@@ -0,0 +1,139 @@
++/*
++ * $Log: dkimverify.h,v $
++ * Revision 1.7  2017-08-31 17:07:45+05:30  Cprogrammer
++ * fixed g++ compiler warning
++ *
++ * Revision 1.6  2017-08-09 22:03:46+05:30  Cprogrammer
++ * initialized EVP_MD_CTX variables
++ *
++ * Revision 1.5  2017-08-08 23:50:47+05:30  Cprogrammer
++ * openssl 1.1.0 port
++ *
++ * Revision 1.4  2015-12-15 16:03:09+05:30  Cprogrammer
++ * use time_t for ExpireTime
++ *
++ * Revision 1.3  2011-06-04 09:37:25+05:30  Cprogrammer
++ * added AllowUnsignedFromHeaders
++ *
++ * Revision 1.2  2009-03-26 15:12:15+05:30  Cprogrammer
++ * changes for ADSP
++ *
++ * Revision 1.1  2009-03-21 08:50:22+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ *  Copyright 2005 Alt-N Technologies, Ltd. 
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License"); 
++ *  you may not use this file except in compliance with the License. 
++ *  You may obtain a copy of the License at 
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0 
++ *
++ *  This code incorporates intellectual property owned by Yahoo! and licensed 
++ *  pursuant to the Yahoo! DomainKeys Patent License Agreement.
++ *
++ *  Unless required by applicable law or agreed to in writing, software 
++ *  distributed under the License is distributed on an "AS IS" BASIS, 
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
++ *  See the License for the specific language governing permissions and 
++ *  limitations under the License.
++ *
++ */
++
++#ifndef DKIMVERIFY_H
++#define DKIMVERIFY_H
++
++#include "dkimbase.h"
++#include <vector>
++
++#define DKIM_SIG_VERSION_PRE_02			0
++#define DKIM_SIG_VERSION_02_PLUS		1
++
++class           SelectorInfo {
++ public:
++	SelectorInfo(const string & sSelector, const string & sDomain);
++	~SelectorInfo();
++
++	string          Domain;
++	string          Selector;
++	string          Granularity;
++	bool            AllowSHA1;
++	bool            AllowSHA256;
++	EVP_PKEY       *PublicKey;	/* the public key */
++	bool            Testing;
++	bool            SameDomain;
++	int             Status;
++	int             Parse(char *Buffer);
++};
++
++class           SignatureInfo {
++public:
++	SignatureInfo(bool SaveCanonicalizedData);
++	~SignatureInfo();
++
++	void            Hash(const char *szBuffer, unsigned nBufLength, bool IsBody = false);
++	string          Header;
++	unsigned        Version;
++	string          Domain;
++	string          Selector;
++	string          SignatureData;
++	string          BodyHashData;
++	string          IdentityLocalPart;
++	string          IdentityDomain;
++	string          CanonicalizedData;
++	vector <string> SignedHeaders;
++	int             BodyLength;
++	unsigned        HeaderCanonicalization;
++	unsigned        BodyCanonicalization;
++	time_t          ExpireTime;
++	int             VerifiedBodyCount;
++	unsigned        UnverifiedBodyCount;
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++	EVP_MD_CTX     *m_Hdr_ctx = NULL;
++	EVP_MD_CTX     *m_Bdy_ctx = NULL;
++#else
++	EVP_MD_CTX      m_Hdr_ctx;
++	EVP_MD_CTX      m_Bdy_ctx;
++#endif
++	SelectorInfo   *m_pSelector;
++	int             Status;
++	int             m_nHash;	// use one of the DKIM_HASH_xxx constants here
++	unsigned        EmptyLineCount;
++	bool            m_SaveCanonicalizedData;
++};
++
++class           CDKIMVerify:public CDKIMBase {
++public:
++
++	CDKIMVerify();
++	~CDKIMVerify();
++
++	int             Init(DKIMVerifyOptions * pOptions);
++	int             GetResults(int *sCount, int *sSize);
++	int             GetDetails(int *nSigCount, DKIMVerifyDetails ** pDetails);
++	virtual int     ProcessHeaders(void);
++	virtual int     ProcessBody(char *szBuffer, int nBufLength, bool bEOF);
++	const char     *GetPractices() {return Practices.c_str();}
++	char           *DKIM_CALL GetDomain(void);
++
++protected:
++	int             ParseDKIMSignature(const string & sHeader, SignatureInfo & sig);
++	SelectorInfo   &GetSelector(const string & sSelector, const string & sDomain);
++	int             GetADSP(const string &sDomain, int &iADSP);
++	int             GetSSP(const string &sDomain, int &iSSP, bool & bTesting);
++	list <SignatureInfo> Signatures;
++	list <SelectorInfo> Selectors;
++	DKIMDNSCALLBACK m_pfnSelectorCallback;	// selector record callback
++	DKIMDNSCALLBACK m_pfnPracticesCallback;	// SSP record callback
++	bool            m_HonorBodyLengthTag;
++	bool            m_CheckPractices;
++	bool            m_Accept3ps;		//TBS(Luc) : accept 3rd party signature(s)
++	bool            m_SubjectIsRequired;
++	bool            m_SaveCanonicalizedData;
++	bool            m_AllowUnsignedFromHeaders;
++	vector <DKIMVerifyDetails> Details;
++	string          Practices;
++};
++
++#endif	/*- DKIMVERIFY_H */
+diff -ruN ../netqmail-1.06-original/dknewkey.sh netqmail-1.06/dknewkey.sh
+--- ../netqmail-1.06-original/dknewkey.sh	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dknewkey.sh	2016-11-22 21:03:57.112528099 +0100
+@@ -0,0 +1,27 @@
++#
++# $Log: dknewkey.sh,v $
++# Revision 1.4  2010-05-16 19:59:48+05:30  Cprogrammer
++# fix for Mac OS X
++#
++# Revision 1.3  2004-11-02 20:48:31+05:30  Cprogrammer
++# fixed error when dknewkey was called without arguments
++#
++# Revision 1.2  2004-10-21 21:54:25+05:30  Cprogrammer
++# create public key file
++#
++# Revision 1.1  2004-10-20 20:40:56+05:30  Cprogrammer
++# Initial revision
++#
++#
++if [ $# -lt 1 ] ; then
++	echo "USAGE: dknewkey keyfile [bits]"
++	exit 1
++fi
++BITS=384
++if test -n "$2"; then BITS=$2; fi
++
++openssl genrsa -out $1 $BITS 2>/dev/null
++openssl rsa -in $1 -out /tmp/dknewkey.$$ -pubout -outform PEM 2>/dev/null
++printf "%s._domainkey\tIN\tTXT\t\"k=rsa; p=%s\"\n" `basename $1` `grep -v ^-- /tmp/dknewkey.$$ | tr -d '\n'` > $1.pub
++/bin/cat $1.pub
++/bin/rm -f /tmp/dknewkey.$$
+diff -ruN ../netqmail-1.06-original/dktest.9 netqmail-1.06/dktest.9
+--- ../netqmail-1.06-original/dktest.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dktest.9	2016-11-22 21:03:57.112528099 +0100
+@@ -0,0 +1,86 @@
++.TH dktest 8
++.SH NAME
++dktest \- exercise the domainkeys library
++.SH SYNOPSIS
++.B dktest
++.I opts
++
++.I opts
++is a series of getopt-style options.
++
++.SH DESCRIPTION
++.B dktest
++exercises the domainkeys library. Both signing and verification merely print out the DK header.
++They do not keep a copy of the input file. You will need to do something like this:
++
++.EX
++ (./dktest -s QMAILHOME/control/domainkeys/dog </tmp/testmsg; cat /tmp/testmsg)\
++ | ./dktest -v
++.EE
++
++Here are the options:
++.IP \[bu] 2
++-s
++\fIkey\fR: Sign. 
++.I key
++is a path to a file containing a PEM-format private key. The base name of
++the file is  used  as  the  selector. Reads the email message on stdin. Prints the
++.B DomainKey-Signature
++header.
++
++.IP \[bu]
++-v: Verify. Verifies the email on stdin. Exits with a non-zero exit code and a message to
++stderr if there was a problem with the signature. Always prints a
++.B DomainKey-Status:
++header to stdout. This option requires the \fBs\fR._domainkey.\fBd\fR txt record in
++dns (public key). Here \fBs\fR is the selector and \fBd\fR is the domain
++.EX
++
++ Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys
++ DomainKey-Signature: a=rsa-sha1; q=dns; c=simple;
++  s=dog; d=indimail.org; 
++  b=CndyNmOBqXD+d6qLGVjVua/oDJetLzAKAh3JoId93GmWRg1Y40DUdvZZhw8tTIoZ;
++.EE
++
++.IP \[bu]
++-c \fI[simple|nofws]\fR Canonicalization.
++Defaults to simple.
++
++.IP \[bu]
++-t \fIn\fR: Test.
++.I n
++is a number indicating which internal test is being performed. The meanings of the numbers
++are documented in the source code.
++
++.IP \[bu]
++-d \fIdns\fR Test dns record
++
++.IP \[bu]
++-b \fIn\fR: Buffer size.
++.I n
++is a number which forces the buffer size. Only needed for testing.
++
++.IP \[bu]
++-D \fIdkdomain\fR: set d= tag.
++.I dkdomain
++is set as the value for d= tag
++
++.IP \[bu]
++-h:
++include h= tag when signing
++
++.IP \[bu]
++-r:
++only include unique headers in the signature generation, implies -h
++
++.IP \[bu]
++-T:
++Generate DomainKey-Trace: header, shows Diff header if Verifying.
++
++.SH "SEE ALSO"
++dkim(8),
++qmail-dk(8),
++qmail-dkim(8),
++dknewkey(8),
++rfc-4870(5),
++rfc-4871(5)
+diff -ruN ../netqmail-1.06-original/dktest.c netqmail-1.06/dktest.c
+--- ../netqmail-1.06-original/dktest.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dktest.c	2016-11-22 21:03:57.112528099 +0100
+@@ -0,0 +1,431 @@
++/*
++ * $Log: dktest.c,v $
++ * Revision 1.16  2013-08-17 16:01:08+05:30  Cprogrammer
++ * added case for duplicate DomainKey-Signature header
++ *
++ * Revision 1.15  2011-07-29 09:28:09+05:30  Cprogrammer
++ * fixed gcc 4.6 warnings
++ *
++ * Revision 1.14  2011-07-22 14:39:27+05:30  Cprogrammer
++ * added -D option to specify d= tag
++ *
++ * Revision 1.13  2009-12-10 15:04:09+05:30  Cprogrammer
++ * exit with DK_STAT
++ *
++ * Revision 1.12  2009-04-20 22:20:55+05:30  Cprogrammer
++ * fixed compilation warning
++ *
++ * Revision 1.11  2009-04-16 22:39:33+05:30  Cprogrammer
++ * assign from = dk_from()
++ *
++ * Revision 1.10  2009-04-05 12:51:22+05:30  Cprogrammer
++ * added preprocessor warning
++ *
++ * Revision 1.9  2009-03-14 16:28:22+05:30  Cprogrammer
++ * Fixed dktest.c to check for DK_STAT_GRANULARITY
++ *
++ * Revision 1.8  2009-03-14 08:50:41+05:30  Cprogrammer
++ * Added -h option to dktest to add h= tag when signing
++ * Added -r option to dktest to enable ignoring duplicate headers when signing (implies -h)
++ * Added -T option to dktest to enable generation of trace headers
++ * Added -d option to fetch dns text record for domainkey
++ *
++ * Revision 1.7  2005-08-23 17:15:02+05:30  Cprogrammer
++ * gcc 4 compliance
++ *
++ * Revision 1.6  2005-04-25 22:52:45+05:30  Cprogrammer
++ * removed printing of comments
++ *
++ * Revision 1.5  2005-04-01 19:54:27+05:30  Cprogrammer
++ * libdomainkeys-0.64
++ *
++ * Revision 1.4  2004-10-25 14:54:02+05:30  Cprogrammer
++ * libdomainkeys-0.63
++ *
++ * Revision 1.3  2004-10-22 20:24:18+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.2  2004-10-20 20:01:58+05:30  Cprogrammer
++ * upgrade to libdomainkeys-0.62
++ *
++ * Revision 1.1  2004-09-22 23:30:32+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include "domainkeys.h"
++
++#ifdef DOMAIN_KEYS
++int             optf = 0;
++
++void
++errorout(DK *dk, DK_STAT st)
++{
++	if (optf && dk)
++		fprintf(stderr, "%s(%d):", dk_errfile(dk), dk_errline(dk));
++	fprintf(stderr, "dktest: %s\n", DK_STAT_to_string(st));
++	exit(st);
++}
++
++int
++main(int argc, char *argv[])
++{
++	char            inbuf[1024];
++	char            advice[2048];
++	char            trace_count[BUFSIZ];
++	size_t          inlen;
++	size_t          advicelen = sizeof(advice);
++	DK             *dk;
++	DK_LIB         *dklib;
++	DK_STAT         st, dkt_st;
++	signed char     ch;
++	int             opts = 0, optv = 0, optt = 0, opth = 0, optr = 0, optT = 0,
++					optc = DK_CANON_SIMPLE;
++	char           *canon = "simple";
++	char           *keyfn  = 0, *selector  = 0;
++	char           *txtrec, *cp, *from, *dkdomain;
++	char            privkey[2048];
++	FILE           *privkeyf = 0;
++	size_t          privkeylen;
++	DK_FLAGS        dkf = 0;
++	int             i;
++	DK_TRACE_TYPE   dk_trace_tag[4] = {
++		DKT_RAW_HEADER,
++		DKT_CANON_HEADER,
++		DKT_RAW_BODY,
++		DKT_CANON_BODY
++	};
++
++	for (dkdomain = (char *) 0;;)
++	{
++		ch = getopt(argc, argv, "s:vt:fb:c:hrTd:D:");
++		if (ch == -1)
++			break;
++		switch (ch)
++		{
++		case 'D':
++			dkdomain = optarg;
++			break;
++		case 'd': /*- optD */
++			txtrec = dns_text(optarg);
++			cp = txtrec;
++			printf("%ld\n", (long) strlen(cp));
++			while (*cp) {
++				printf("%02x ", *cp++);
++				if ((cp - txtrec) % 16 == 0)
++					printf("\n");
++			}
++			printf("\n");
++			if (!strcmp(txtrec, "e=perm;"))
++				exit(0);
++			if (!strcmp(txtrec, "e=temp;"))
++				exit(0);
++			free(txtrec);
++			return (0);
++			break;
++		case 'T':
++			optT = 1;
++			break;
++		case 'v':
++			optv = 1;
++			break;
++		case 'f':
++			optf = 1;
++			break;
++		case 'r':
++			optr = 1;
++			opth = 1;
++			break;
++		case 's':
++			opts = 1;
++			keyfn = optarg;
++			selector = optarg;
++			while (*optarg)
++			{
++				if (*optarg == '/')
++					selector = optarg + 1;
++				optarg++;
++			}
++			break;
++		case 't':
++			optt = atoi(optarg);
++			break;
++		case 'h':
++			opth = 1;
++			break;
++		case 'b':
++			advicelen = atoi(optarg);
++			if (advicelen > sizeof(advice))
++				advicelen = sizeof(advice);
++			break;
++		case 'c':
++			if (!strcmp(optarg, "simple"))
++				optc = DK_CANON_SIMPLE, canon = "simple";
++			else
++			if (!strcmp(optarg, "nofws"))
++				optc = DK_CANON_NOFWS, canon = "nofws";
++			else
++			{
++				fprintf(stderr, "dktest: unrecognized canonicalization.\n");
++				exit(1);
++			}
++		}
++	}
++	if (opts)
++	{
++		if (!(privkeyf = fopen(keyfn, "r"))) /*- TC10 */
++		{
++			fprintf(stderr, "dktest: can't open private key file %s\n", keyfn);
++			exit(1);
++		}
++		if ((privkeylen = fread(privkey, 1, sizeof(privkey), privkeyf)) == sizeof(privkey))
++					/*- TC9 */
++		{					
++			fprintf(stderr, "dktest: private key buffer isn't big enough, use a smaller private key or recompile.\n");
++			exit(1);
++		}
++		privkey[privkeylen] = '\0';
++		fclose(privkeyf);
++	}
++	if (optt == 1)
++		errorout(NULL, 0);		/*- TC2 */
++	if (optt == 2)
++		errorout(NULL, 32767);	/*- TC3 */
++	dklib = dk_init(&st);
++	if (st != DK_STAT_OK)
++		errorout(NULL, st);
++	if (!dklib)
++		errorout(NULL, 200);
++	if (optv)
++	{
++		dk = dk_verify(dklib, &st);
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++	} else
++	if (opts)
++	{
++		dk = dk_sign(dklib, &st, optc);
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++		if (optr)
++			st = dk_setopts(dk, DKOPT_RDUPE);
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++	} else
++	{
++		fprintf(stderr, "dktest: [-f] [-b#] [-c nofws|simple] [-v|-s selector] [-h] [-t#] [-r] [-T][-d dnsrecord]\n"); /* TC1 */
++		exit(1);
++	}
++	if (optT) /*- trace */
++	{
++		st = dk_setopts(dk, (DKOPT_TRACE_h|DKOPT_TRACE_H|DKOPT_TRACE_b|DKOPT_TRACE_B));
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++	}
++	if (optt == 3)
++		errorout(dk, dk_message(NULL, (const unsigned char *) "", 1));	/*- TC4 */
++	if (optt == 4)
++		errorout(dk, dk_message(dk, (const unsigned char *) NULL, 1));	/*- TC5 */
++	if (optt == 5)
++		errorout(dk, dk_message(dk, (const unsigned char *) "", 0));	/*- TC6 */
++	if (optt >= 100 && optt <= 140)
++		errorout(dk, optt - 100);	/*- TC53 */
++	st = DK_STAT_OK;
++	/* 
++	 * This should work with DOS or UNIX text files -Tim
++	 * Reduced calls to dk_message, in lib dkhash called for EVERY char
++	 * DOS formatted input (CRLF line terminated) will have fewer calls
++	 * to dk_message() than UNIX (LF line terminated) input.
++	 */
++	while (1)
++	{
++		char           *inp;
++
++		inlen = fread(inbuf, 1, sizeof(inbuf), stdin);
++		inp = inbuf;
++		while (inlen--)
++		{
++			if (*inp == '\n')
++				st = dk_message(dk, (const unsigned char *) "\r\n", 2);
++			else
++				st = dk_message(dk, (const unsigned char *) inp, 1);
++			if (st != DK_STAT_OK)
++				break;  //stop looping if there was an error
++			inp++;
++		}
++		if ((inp-inbuf < sizeof(inbuf)) || (st != DK_STAT_OK))
++			break; /*- if we read in the entire message or encountered an error */
++	}
++	if (st == DK_STAT_OK)
++	{
++		if (optt == 10)
++			st = dk_end(dk, &dkf);
++		else
++			st = dk_eom(dk, &dkf);
++	}
++	if (optT)
++	{
++		printf("DomainKey-Trace: U=http://domainkeys.sourceforge.net; V=TESTING;\n");
++		for (i = 0; i < 4; i++)
++		{
++			if (dk_get_trace(dk, dk_trace_tag[i], trace_count, sizeof (trace_count)) != DK_STAT_OK)
++			{
++				fprintf(stderr, "dktest: Not enough resources for trace buffer output\n");
++				break;
++			} else
++				printf("  %s\n", trace_count);
++		}
++		if (optv)
++		{
++			printf("DomainKey-Trace-Diff:\n");
++			for (i = 0; i < 4; i++) {
++				dkt_st = dk_compare_trace(dk,dk_trace_tag[i],trace_count,sizeof(trace_count));
++				if (dkt_st == DK_STAT_NOSIG)
++				{
++					printf("  No DK-Trace: header found\n");
++					break;
++				} else
++				if (dkt_st != DK_STAT_OK)
++				{
++					fprintf(stderr,"dktest: Not enough resources for trace buffer output\n");
++					break;
++				} else
++					printf("  %s\n",trace_count);
++			}
++		}
++	}
++	if ((optt == 6 || optt == 10) && optv)
++	{
++		printf("flags: ");
++		if (dkf & DK_FLAG_SET)
++			printf("+");
++		if (dkf & DK_FLAG_TESTING)
++			printf("t");
++		if (dkf & DK_FLAG_SIGNSALL)
++			printf("s"); /*- wont be set if dk_end() is sucessful */
++		if (dkf & DK_FLAG_G)
++			printf("g");
++		printf("\n");
++	} else
++	if (optt == 6 && opts)
++		errorout(dk, dk_getsig(dk, NULL, NULL, advicelen));	/*- TC14 */
++	else
++	if (optt == 7)
++	{
++		from = dk_from(dk);
++		if (!from)
++			from = "";
++		printf("%s\n", from);	/*- TC14-1, TC14-2 */
++	} else
++	if (optt == 11)
++	{
++		from = dk_address(dk);
++		printf("%s\n", from);	/*- TC14-3, TC14-4 */
++	} else
++	if (optt == 9)
++	{
++		char           *s;
++
++		s = malloc(dk_headers(dk, NULL));
++		dk_headers(dk, s);
++		printf("%s\n", s);
++		free(s);
++	} else
++	if (optt == 8 && opts)
++	{
++		dk_getsig(dk, privkey, (unsigned char *) advice, advicelen);
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++		printf("%d %d\n", (int) dk_siglen(privkey), (int) strlen(advice)); /*- TC39 */
++	} else
++	if (opts)
++	{
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++		st = dk_getsig(dk, privkey, (unsigned char *) advice, advicelen);
++		if (st != DK_STAT_OK)
++			errorout(dk, st);
++#if 0
++		printf("Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys\n");
++#endif
++		from = dk_from(dk);
++		printf("DomainKey-Signature: a=rsa-sha1; q=dns; c=%s;\n"
++			"  s=%s; d=%s;\n" "  b=%s;\n", canon, selector, dkdomain ? dkdomain : from, advice);
++		if (opth == 1)
++		{
++			if (dk_headers(dk, NULL) < sizeof(inbuf))
++			{
++				dk_headers(dk, inbuf);
++				printf("  h=%s;\n", inbuf);
++			}
++		}
++	} else
++	if (optv)
++	{
++		char           *status = 0;
++
++		switch (st)
++		{
++		case DK_STAT_OK:
++			status = "good";
++			break;
++		case DK_STAT_BADSIG:
++			status = "bad";
++			break;
++		case DK_STAT_NOSIG:
++			status = "no signature";
++			break;
++		case DK_STAT_NOKEY:
++		case DK_STAT_CANTVRFY:
++			status = "no key";
++			break;
++		case DK_STAT_BADKEY:
++			status = "bad key";
++			break;
++		case DK_STAT_INTERNAL:
++		case DK_STAT_ARGS:
++		case DK_STAT_SYNTAX:
++			status = "bad format";
++			break;
++		case DK_STAT_NORESOURCE:
++			status = "no resources";
++			break;
++		case DK_STAT_REVOKED:
++			status = "revoked";
++			break;
++		case DK_STAT_GRANULARITY:
++			status = "bad sender (g=)";
++			break;
++		}
++#if 0
++		printf("Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys\n");
++#endif
++		printf("DomainKey-Status: %s\n", status);
++		rewind(stdin);
++	}
++	if (st != DK_STAT_OK)
++		errorout(dk, st);
++	dk_free(dk, 1);//cleanup properly (not really necessary for single run process)
++	dk_shutdown(dklib);
++	return(0);
++}
++#else
++#warning "not compiled with -DDOMAIN_KEYS"
++int
++main(int argc, char *argv[])
++{
++	fprintf(stderr, "not compiled with -DDOMAIN_KEYS\n");
++	return(1);
++}
++#endif
++
++void
++getversion_dktest_c()
++{
++	static char    *x = "$Id: dktest.c,v 1.16 2013-08-17 16:01:08+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dktrace.c netqmail-1.06/dktrace.c
+--- ../netqmail-1.06-original/dktrace.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dktrace.c	2016-11-22 21:03:57.112528099 +0100
+@@ -0,0 +1,277 @@
++/*
++ * $Log: dktrace.c,v $
++ * Revision 1.1  2009-03-14 09:00:52+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++/*
++ * $Id: dktrace.c,v 1.1 2009-03-14 09:00:52+05:30 Cprogrammer Stab mbhangui $ 
++ */
++
++#ifdef DOMAIN_KEYS
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "str.h"
++#include "case.h"
++#include "dktrace.h"
++
++#define strncasecmp(x,y,z) case_diffb((x), (z), (y))
++
++static int     *
++getPointer(DK_TRACE * dkp, DK_TRACE_TYPE type)
++{
++	switch (type) {
++	case DKT_RAW_HEADER:
++		return dkp->ccounts_h;
++	case DKT_CANON_HEADER:
++		return dkp->ccounts_H;
++	case DKT_RAW_BODY:
++		return dkp->ccounts_b;
++	case DKT_CANON_BODY:
++		return dkp->ccounts_B;
++	default:
++		return 0;
++	}
++}
++
++//Modified version of dkparselist()
++static int
++dkt_parselist(char *list, char *letters, char *values[])
++{
++	char            key;
++	int             i;
++	char           *value;
++
++	/*- start with all args unset */
++	for (i = 0; letters[i]; i++) {
++		values[i] = NULL;
++	}
++	key = 0;
++	while (*list) {
++		if ((*list == ' ') || (*list == '\t') || (*list == '\r') || (*list == '\n')) {
++			list++;
++		} else if (*list == '=') {
++			char           *ws;
++
++			++list;
++			value = list;
++			ws = list;
++			while (1) {
++			/*
++			 * copy up to null or semicolon, deleting whitespace as we go 
++			 */
++				*ws = *list;
++				if ((*list == ' ') || (*list == '\t') || (*list == '\r') || (*list == '\n')) {
++				/*
++				 * ignore 
++				 */
++				} else if (!*list) {
++					break;
++				} else if (*list == ';') {
++					*ws = '\0';
++					list++;
++					break;
++				} else {
++					ws++;
++				}
++				list++;
++			}
++			if (!key) {
++				return 0;		//No key
++			}
++		/*
++		 * if we find a matching letter, remember the value 
++		 */
++			for (i = 0; letters[i]; i++) {
++				if (key == letters[i]) {
++					if (values[i]) {
++						return 0;	/* no duplicate keys. TC23 */
++					}
++					values[i] = value;
++				}
++			}
++			key = 0;
++		} else {
++			if (key) {
++				return 0;		/* they already gave us a key. TC24 */
++			}
++			key = *list++;
++		}
++	}
++	return 1;
++}
++
++extern void
++dkt_add(DK_TRACE * dkp, DK_TRACE_TYPE type, const unsigned char *data, int dataLength)
++{
++	int            *ip;
++	ip = getPointer(dkp, type);
++	if (!ip)
++		return;
++
++	while (dataLength-- > 0)
++		ip[*data++]++;
++}
++
++//useful for building table directly
++extern void
++dkt_quickadd(DK_TRACE * dkp, DK_TRACE_TYPE type, int index, int count)
++{
++	int            *ip;
++	ip = getPointer(dkp, type);
++	if (!ip)
++		return;
++	if ((index < 256) && (index >= 0))
++		ip[index] = ip[index] + count;
++}
++
++//reverse of dkt_quickadd, reads data from table and returns the int count
++extern int
++dkt_getcount(DK_TRACE * dkp, DK_TRACE_TYPE type, int index, int count)
++{
++	int            *ip;
++	ip = getPointer(dkp, type);
++	if (!ip)
++		return 0;
++	if ((index < 256) && (index >= 0))
++		return ip[index];
++	return 0;
++}
++
++
++/*
++ * Fills in DK_TRACE *diff_table with the differences between
++ * *dka (before) and *dkb (after), (after - before = diff)
++ */
++extern int
++dkt_diff(DK_TRACE * dka, DK_TRACE * dkb, DK_TRACE_TYPE type, DK_TRACE * diff_table)
++{
++	int            *inputa, *inputb, *output;
++	int             i;
++	inputa = getPointer(dka, type);
++	if (!inputa)
++		return 0;
++	inputb = getPointer(dkb, type);
++	if (!inputb)
++		return 0;
++	output = getPointer(diff_table, type);
++	if (!output)
++		return 0;
++
++	for (i = 0; i < 256; i++) {
++		output[i] = (inputb[i] - inputa[i]);
++	}
++	return 1;
++}
++
++/*
++ * Generate the tag=value; data for a particular trace type
++ * returns length of generated C string including ending '\0'
++ */
++
++extern int
++dkt_generate(DK_TRACE * dkp, DK_TRACE_TYPE type, char *buffer, int maxBufferSize)
++{
++	int            *ip;
++	char           *cp;
++	int             ix;
++	int             len;
++	int             highest;
++
++	if (maxBufferSize < 20)
++		return 0;				/* Getting too close, you lose */
++	cp = buffer;
++	ip = getPointer(dkp, type);
++	if (!ip)
++		return 0;
++	*buffer++ = (char) type;
++	--maxBufferSize;
++	*buffer++ = '=';
++	--maxBufferSize;
++
++/*
++ * Only produce as many entries as needed, rather than the full 256 
++ */
++
++	for (ix = 0, highest = 0; ix < 256; ++ix) {
++		if (ip[ix] != 0)
++			highest = ix;
++	}
++
++	for (ix = 0; ix <= highest; ++ix) {
++		if (ip[ix] != 0) {
++			len = snprintf(buffer, maxBufferSize, "%d", ip[ix]);
++			buffer += len;
++			maxBufferSize -= len;
++		}
++		if (maxBufferSize < 10)
++			return 0;			/* Getting too close, you lose */
++		*buffer++ = ':';
++		--maxBufferSize;
++	}
++	/*
++	 * Finish up the tag with a semi-colon and turn it into a C string 
++	 */
++	--buffer;
++	*buffer++ = ';'; //replace last ':'
++	*buffer++ = '\0';
++	--maxBufferSize;
++	return buffer - cp;
++}
++
++//converts a header to to a DK_TRACE table
++extern int
++dkt_hdrtotrace(char *ptr, DK_TRACE * store)
++{
++	char           *values[4];	// hHbB
++	int             idx;
++	int             delim_count;
++	char           *sptr, *eptr;
++	DK_TRACE_TYPE   dk_trace_tag[4] = {
++		DKT_RAW_HEADER,
++		DKT_CANON_HEADER,
++		DKT_RAW_BODY,
++		DKT_CANON_BODY
++	};
++	int            *ip;
++
++	if ((strncasecmp(ptr, "DomainKey-Trace:", 16)) || !store || (!dkt_parselist(ptr + 16, "hHbB", values))) {
++		return 0;
++	}
++	for (idx = 0; idx < 4; idx++) {
++		if (!values[idx])
++			continue;
++		ip = getPointer(store, dk_trace_tag[idx]);
++		if (!ip)
++			return 0;
++		sptr = values[idx];
++		for (delim_count = 0; ((delim_count < 256) && (*sptr != '\0')); sptr++) {
++			if (*sptr == ':') {
++				delim_count++;
++				continue;
++			}
++		//find the end of the int
++			for (eptr = sptr + 1; ((*eptr != ':') && (*eptr != '\0')); eptr++);
++			if (*eptr == '\0') //if end of values for key finish up
++			{
++				ip[delim_count] = atoi(sptr);
++				break;
++			}
++			*eptr = '\0';
++			ip[delim_count] = atoi(sptr);
++			delim_count++;
++			sptr = eptr;
++		}
++	}
++	return 1;
++}
++#endif
++
++void
++getversion_dktrace_c()
++{
++	static char    *x = "$Id: dktrace.c,v 1.1 2009-03-14 09:00:52+05:30 Cprogrammer Stab mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/dktrace.h netqmail-1.06/dktrace.h
+--- ../netqmail-1.06-original/dktrace.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dktrace.h	2016-11-22 21:03:57.112528099 +0100
+@@ -0,0 +1,26 @@
++/* $Id: dktrace.h,v 1.3 2005/06/27 18:47:57 ted46045 Exp $ */
++
++#ifndef _DK_TRACE_H
++#define _DK_TRACE_H
++
++typedef struct {
++  int ccounts_h[256];
++  int ccounts_H[256];
++  int ccounts_b[256];
++  int ccounts_B[256];
++} DK_TRACE;
++
++typedef enum { DKT_RAW_HEADER='h', DKT_CANON_HEADER='H',
++         DKT_RAW_BODY='b', DKT_CANON_BODY='B' } DK_TRACE_TYPE;
++
++#define dkt_init(s) memset(s,0,sizeof(DK_TRACE))
++
++//extern void   dkt_init(DK_TRACE *dkp);
++extern void   dkt_add(DK_TRACE *dkp, DK_TRACE_TYPE type, const unsigned char *data, int dataLength);
++extern int    dkt_diff(DK_TRACE *dka, DK_TRACE *dkb, DK_TRACE_TYPE type, DK_TRACE *table);
++extern void   dkt_quickadd(DK_TRACE *dkp, DK_TRACE_TYPE type, int index, int count);
++extern int    dkt_getcount(DK_TRACE *dkp, DK_TRACE_TYPE type, int index, int count);
++extern int    dkt_generate(DK_TRACE *dkp, DK_TRACE_TYPE type, char *buffer, int maxBufferSize);
++extern int    dkt_hdrtotrace(char *ptr, DK_TRACE *store);
++
++#endif
+diff -ruN ../netqmail-1.06-original/dns.c netqmail-1.06/dns.c
+--- ../netqmail-1.06-original/dns.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/dns.c	2018-04-02 11:45:03.323768372 +0200
+@@ -1,4 +1,3 @@
+-#include <stdio.h>
+ #include <netdb.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+@@ -9,6 +8,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 +19,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 +46,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 +82,7 @@
+    if (i < QFIXEDSZ) return DNS_SOFT;
+    responsepos += QFIXEDSZ;
+   }
+- numanswers = ntohs(response.hdr.ancount);
++ numanswers = ntohs(((HEADER *)response.buf)->ancount);
+  return 0;
+ }
+ 
+@@ -177,6 +195,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;
+ {
+@@ -194,7 +255,7 @@
+    if (!sa->len) return loop;
+    if (sa->s[sa->len - 1] == ']') return loop;
+    if (sa->s[sa->len - 1] == '.') { --sa->len; continue; }
+-   switch(resolve(sa,T_ANY))
++   switch(resolve(sa,T_CNAME))
+     {
+      case DNS_MEM: return DNS_MEM;
+      case DNS_SOFT: return DNS_SOFT;
+@@ -235,15 +296,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 +318,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 +376,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 +405,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 +417,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 +487,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 -ruN ../netqmail-1.06-original/dns.h netqmail-1.06/dns.h
+--- ../netqmail-1.06-original/dns.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/dns.h	2016-11-22 21:03:57.113528065 +0100
+@@ -10,5 +10,6 @@
+ int dns_mxip();
+ int dns_ip();
+ int dns_ptr();
++int dns_txt();
+ 
+ #endif
+diff -ruN ../netqmail-1.06-original/dnsfq.c netqmail-1.06/dnsfq.c
+--- ../netqmail-1.06-original/dnsfq.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/dnsfq.c	2016-11-22 21:03:57.113528065 +0100
+@@ -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 -ruN ../netqmail-1.06-original/dnsptr.c netqmail-1.06/dnsptr.c
+--- ../netqmail-1.06-original/dnsptr.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/dnsptr.c	2016-11-22 21:03:57.113528065 +0100
+@@ -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 -ruN ../netqmail-1.06-original/dnstxt.c netqmail-1.06/dnstxt.c
+--- ../netqmail-1.06-original/dnstxt.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/dnstxt.c	2016-11-22 21:03:57.113528065 +0100
+@@ -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 -ruN ../netqmail-1.06-original/domainkeys.h netqmail-1.06/domainkeys.h
+--- ../netqmail-1.06-original/domainkeys.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/domainkeys.h	2018-03-31 15:08:54.373109416 +0200
+@@ -0,0 +1,378 @@
++/* This file is automatically created from the corresponding .c file */
++/* Do not change this file; change the .c file instead. */
++/* This is libdomainkeys.  It's Copyright (c) 2004 Yahoo, Inc.
++ * This code incorporates intellectual property owned by
++ * Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License
++ * Agreement: http://domainkeys.sourceforge.net/license/softwarelicense1-0.html
++ */
++#include <openssl/evp.h>
++#include <openssl/pem.h>
++#include <openssl/err.h>
++
++#ifdef SWIG
++%module domainkeys
++%{
++#include "domainkeys.h"
++%}
++#endif
++
++#include "dktrace.h"
++
++/* Performance/Debug options.
++ * Uncomment below or use -D switch in gcc
++ * DK_DEBUG Dumps whatever dkhash() hashes in to stderr and turns on
++ *  some debug warnings that should never happen
++ * DK_HASH_BUFF Enables code that uses a buffer when processing the
++ *  canocalized message, reducing calls to the crypto library (from dkhash()),
++ *  but can use up slightly more memory
++*/
++//#define DK_DEBUG 1
++#define DK_HASH_BUFF 1
++
++
++#define DKMARK ('D' | 'K'<<8 | 'E'<<16 | 'Y'<<24)
++#define DK_SIGNING_SIGN 0
++#define DK_SIGNING_VERIFY 1
++#define DK_SIGNING_NOSIGN 2
++#define DK_SIGNING_NOVERIFY 3
++#define DK_MALLOC(s)  OPENSSL_malloc(s)
++#define DK_MFREE(s)   OPENSSL_free(s); s = NULL;
++#define DKERR(x) ((dk->errline=__LINE__),(dk->errfile=__FILE__),(x))
++#define DK_BLOCK 1024 //default size of malloc'd block
++
++/*
++ * Option Flags for dk_setopts
++ * OR together or run dk_setopts several times
++ * All option flags are OFF by default
++*/
++#define DKOPT_TRACE_h 0x01 //enables tracking character count in pre-canon header
++#define DKOPT_TRACE_H 0x02 //enables tracking character count in post-canon header
++#define DKOPT_TRACE_b 0x04 //enables tracking character count in pre-canon body
++#define DKOPT_TRACE_B 0x08 //enables tracking character count in post-canon header
++#define DKOPT_RDUPE 0x10 //enables skipping duplicate headers when generateing a signature
++
++typedef enum
++{
++  DK_STAT_OK, /* Function completed successfully */
++  DK_STAT_BADSIG, /* Signature was available but failed to verify against domain specified key */
++  DK_STAT_NOSIG, /* No signature available in message */
++  DK_STAT_NOKEY, /* No public key available (permanent failure) */
++  DK_STAT_BADKEY, /* Unusable key, public if verifying, private if signing */
++  DK_STAT_CANTVRFY, /* Cannot get domain key to verify signature (temporary failure) */
++  DK_STAT_SYNTAX, /* Message is not valid syntax. Signature could not be created/checked */
++  DK_STAT_NORESOURCE, /* Could not get critical resource (temporary failure) */
++  DK_STAT_ARGS, /* Arguments are not usable. */
++  DK_STAT_REVOKED,    /* Key has been revoked. */
++  DK_STAT_INTERNAL, /* cannot call this routine in this context.  Internal error. */
++  DK_STAT_GRANULARITY, /* Granularity mismatch: sender doesn't match g= option. */
++} DK_STAT;
++
++typedef enum
++{
++  DK_FLAG_TESTING = 1,    /* set when in testing mode. */
++  DK_FLAG_SIGNSALL = 2,   /* domain signs all outgoing email. */
++  DK_FLAG_SET = 4,    /* flags set from a successful DNS query */
++  DK_FLAG_G = 8,    /* g tag was present in the selector. */
++} DK_FLAGS;
++typedef enum
++{
++  DK_TXT_KEY = 0,
++  DK_TXT_POLICY
++} DK_TXT;
++
++typedef enum
++{
++  DK_CANON_SIMPLE = 0,
++  DK_CANON_NOFWS = 1,
++} DK_CANON;
++/* STARTSTRUCT */
++typedef struct
++{
++
++} DK_LIB;
++/* STOPSTRUCT */
++
++//UnixWare Fix -Tim
++/* STARTSTRUCT */
++typedef struct
++{
++} DK;
++/* STOPSTRUCT */
++
++
++/* returns the source file from which an error was returned. */
++char * dk_errfile(DK *dk)
++;
++
++
++/* returns the source line number from which an error was returned. */
++int dk_errline(DK *dk)
++;
++
++
++/* Per-process, one-time initialization
++ * Returns library structure for subsequent dk_sign or dk_verify calls.
++ * Consult statp before using.
++ *
++ * When terminating the PROCESS its a good idea to call dk_shutdown()
++ * When terminating a THREAD it's a good idea to call ERR_remove_state(0); defined in <openssl/err.h>
++ * NOTE: DK_LIB pointers are safe to use over multiple threads
++ *       DK pointers are NOT safe to use over multiple threads
++ */
++DK_LIB *dk_init(DK_STAT *statp)
++;
++
++
++/* Per-process, one-time cleanup
++ * Should be called just before the application ends.
++ * the dklib pointer is not valid anymore after this call
++ * This function should be called even if dk_init failed.
++ * It's safe to call dk_shutdown with a NULL pointer
++ */
++void dk_shutdown(DK_LIB * dklib)
++;
++
++
++/* Set dk options, use instead of dk_remdupe and dk_enable_trace
++ * Can be called multiple times.
++ * use after dk_sign()/dk_verify()
++ *
++ * the bits field can be an OR of any of the following
++ *DKOPT_TRACE_h Trace pre-canon header
++ *DKOPT_TRACE_H Trace post-canon header
++ *DKOPT_TRACE_b Trace pre-canon body
++ *DKOPT_TRACE_B Trace post-canon body
++ *DKOPT_RDUPE   Exclude duplicate headers from hash (Signing only)
++ */
++DK_STAT dk_setopts(DK *dk, int bits)
++;
++
++
++/* returns the int holding the options set
++ * See dk_setopts for bit flags
++ */
++int dk_getopts(DK *dk)
++;
++
++
++/* DEPRECATED in favor of calling dk_setopts().
++ * Enables character trace tracking
++ *
++ * use after dk_sign()/dk_verify()
++ */
++DK_STAT dk_enable_trace(DK *dk)
++;
++
++
++/* Prints trace table to *store variable (char string)
++ * *dk is the container for the table
++ * *store is a pointer to a character array to output to
++ * store_size is the size of the character array *store
++ *
++ */
++DK_STAT dk_get_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
++;
++
++
++/* Prints difference trace table to *store variable (char string)
++ * *dk is the container for the table
++ * *store is a pointer to a character array to output to
++ * store_size is the size of the character array *store
++ * return DK_STAT_NOSIG if no DK-Trace header was found
++ */
++DK_STAT dk_compare_trace(DK *dk, DK_TRACE_TYPE type, char *store, int store_size)
++;
++
++
++/* Sets the DNS key/policy record manually (no DNS lookup)
++ * txtrecord needs to be set to "e=perm;" to force a permanent DNS failure
++ * txtrecord needs to be set to "e=temp;" to force a temporary DNS failure
++ * Valid DK_TXT types are:
++ * DK_TXT_KEY (normal selector record; for <selctor>._domainkey.<domain>)
++ * DK_TXT_POLICY (domain policy record; for _domainkey.<domain>)
++ */
++DK_STAT dk_settxt(DK *dk, DK_TXT recordtype, const char *txtrecord)
++;
++
++
++/* Per-message, may be threaded.
++ * canon is one of DK_CANON_*.
++ * Returns state structure for operation.  Consult statp before using.
++ */
++DK *dk_sign(DK_LIB *dklib, DK_STAT *statp, int canon)
++;
++
++
++/* Per-message, may be threaded.
++ * Returns state structure for operation.  Consult statp before using.
++ */
++DK *dk_verify(DK_LIB *dklib, DK_STAT *statp)
++;
++
++
++/* DEPRECATED in favor of calling dk_setopts()
++ * set option to remove dupe headers
++ * should be called after dk_sign();
++ * any int NOT 0 turns dupe removal on
++ */
++DK_STAT dk_remdupe(DK *dk,int i)
++;
++
++
++/* Returns the policy flags belonging to the signing domain.
++ * Sender: overrides From:, and the d= entry in the DK-Sig overrides both.
++ * If the policy flags were not successfully fetched, DK_FLAG_SET will not
++ * be set.
++ */
++DK_FLAGS dk_policy(DK *dk)
++;
++
++
++/* Copies the header names that were signed into the pointer.
++ * Returns the number of bytes copied.
++ * ptr may be NULL, in which case the bytes are just counted, not copied.
++ * Feel free to call this twice; once to get the length, and again to
++ * copy the data.
++ * NOTE: If the return value is 0 then an error occured.
++ *	It's a good idea to check for this
++ */
++int dk_headers(DK *dk, char *ptr)
++;
++
++
++/* Must NOT include dots inserted for SMTP encapsulation.
++ * Must NOT include CRLF.CRLF which terminates the message.
++ * Otherwise must be exactly that which is sent or received over the SMTP session.
++ * May be called multiple times (not necessary to read an entire message into memory).
++ */
++DK_STAT dk_message(DK *dk, const unsigned char *ptr, size_t len)
++;
++
++
++/* DEPRECATED in favor of calling dk_address().
++ * Returns a pointer to a null-terminated domain name portion of an RFC 2822 address.
++ * If a Sender: was encountered, it returns that domain.  Otherwise,
++ * if a From: was encountered, it returns that domain.  Otherwise,
++ * return NULL.
++ * return NULL if no domain name found in the address.
++ * return NULL if the dk is unusable for any reason.
++ * return NULL if the address is unusable for any reason.
++ */
++char *dk_from(DK *dk)
++;
++
++
++/* Returns a pointer to the selector name used or NULL if there isn't one
++ * Added by rjp
++ */
++const char *dk_selector(DK *dk)
++;
++
++
++/* Returns a pointer to the domain name used or NULL if there isn't one
++ */
++const char *dk_domain(DK *dk)
++;
++
++
++/*
++ * Returns a pointer to a string which begins with "N", "S", or "F",
++ * corresponding to None, Sender: and From:, respectively.
++ * This single character is followed by a null-terminated RFC 2822 address.
++ * The first character is "N" if no valid address has been seen yet,
++ * "S" if the address came from the Sender: field, and "F" if the
++ * address came from the From: field.
++ */
++char *dk_address(DK *dk)
++;
++
++
++/*
++ * Returns a pointer to a null-terminated string containing the granularity
++ * value found in the selector DNS record, if any, but only after dk_end
++ * has been called. Otherwise returns NULL.
++ */
++char *dk_granularity(DK *dk)
++;
++
++
++/*
++ * Called at end-of-message (before response to DATA-dot, if synchronous with SMTP session).
++ * If verifying, returns signature validity.
++ * This does not calculate the signature.  Call dk_getsig() for that.
++ * Flags are returned indirectly through dkf.
++ * If you pass in NULL for dkf, the flags will not be fetched.
++ * If there is a DK-Sig line, the d= entry will be used to fetch the flags.
++ * Otherwise the Sender: domain will be used to fetch the flags.
++ * Otherwise the From: domain will be used to fetch the flags.
++ *
++ * NOTE: If for some reason dk_end() returns an error (!DK_STAT_OK) dk_policy() should be called
++ * to get the domain signing policy (o=) and handle accordingly.
++ * dkf (selector flags) wont be set if dk_end() returns
++ * DK_STAT_NOSIG
++ * DK_STAT_NOKEY
++ * DK_STAT_SYNTAX
++ * DK_STAT_NORESOURCE
++ * DK_STAT_BADKEY
++ * DK_STAT_CANTVERIFY
++ */
++DK_STAT dk_end(DK *dk, DK_FLAGS *dkf)
++;
++
++
++/*
++ * DEPRECATED in favor of calling dk_end and dk_policy() directly.
++ * If you pass in NULL for dkf, the policy flags will not be fetched.
++ * If the message verified okay, the policy flags will not be fetched.
++ */
++DK_STAT dk_eom(DK *dk, DK_FLAGS *dkf)
++;
++
++
++/*
++ *
++ * privatekey is the private key used to create the signature; It should contain
++ * the entire contents of a PEM-format private key file, thusly it will begin with
++ * -----BEGIN RSA PRIVATE KEY-----.  It should be null-terminated.
++ */
++size_t dk_siglen(void *privatekey)
++;
++
++
++/*
++ * Sets buf to a null-terminated string.
++ * If the message is being signed, signature is stored in the buffer.
++ * If the message is being verified, returns DK_STAT_INTERNAL.
++ * privatekey is the private key used to create the signature; It should contain
++ * the entire contents of a PEM-format private key file, thus it will begin with
++ * -----BEGIN RSA PRIVATE KEY-----.  It should be null-terminated.
++ * If you pass in NULL for buf, you'll get back DK_STAT_NORESOURCE.
++ * If len is not big enough, you'll get back DK_STAT_NORESOURCE.
++ */
++DK_STAT dk_getsig(DK *dk, void *privatekey, unsigned char buf[], size_t len)
++;
++
++
++/*
++ * Free all resources associated with this message.
++ * dk is no longer usable.
++ * if doClearErrState != 0, the OpenSSL ErrorState is freed.
++ * Set clearErrState=0 if you use other openssl functions and
++ * want to call openssl's ERR_remove_state(0) by yourself
++ * ERR_remove_state(0) is declared in <openssl/err.h>
++ */
++DK_STAT dk_free(DK *dk, int doClearErrState)
++;
++
++
++/*
++ * return a pointer to a string which describes st.
++ * The string is structured.  All the characters up to the first colon
++ * contain the name of the DK_STAT constant.  From there to the end of
++ * string is a human-readable description of the error.
++ */
++const char *DK_STAT_to_string(DK_STAT st)
++;
++
++
++char           *dns_text(char *);
+diff -ruN ../netqmail-1.06-original/forward.c netqmail-1.06/forward.c
+--- ../netqmail-1.06-original/forward.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/forward.c	2016-11-22 21:03:57.114528032 +0100
+@@ -6,11 +6,11 @@
+ #include "strerr.h"
+ #include "substdio.h"
+ #include "fmt.h"
++#include "stralloc.h"
++#include "srs.h"
+ 
+ #define FATAL "forward: fatal: "
+ 
+-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+-
+ struct qmail qqt;
+ 
+ int mywrite(fd,buf,len) int fd; char *buf; int len;
+@@ -42,6 +42,16 @@
+   dtline = env_get("DTLINE");
+   if (!dtline)
+     strerr_die2x(100,FATAL,"DTLINE not set");
++
++  if (str_len(sender)) {
++    switch(srsforward(sender)) {
++      case -3: strerr_die2x(100,FATAL,srs_error.s); break;
++      case -2: strerr_die2x(111,FATAL,"out of memory"); break;
++      case -1: strerr_die2x(111,FATAL,"unable to read controls"); break;
++      case 0: break; // nothing
++      case 1: sender = srs_result.s; break;
++    }
++  }
+  
+   if (qmail_open(&qqt) == -1)
+     strerr_die2sys(111,FATAL,"unable to fork: ");
+diff -ruN ../netqmail-1.06-original/global.h netqmail-1.06/global.h
+--- ../netqmail-1.06-original/global.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/global.h	2016-11-22 21:03:57.114528032 +0100
+@@ -0,0 +1,51 @@
++/* GLOBAL.H - RSAREF types and constants */
++
++#include <string.h>
++#include "uint32.h"
++
++/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
++     Inc., created 1991. All rights reserved.
++ */
++
++#ifndef _GLOBAL_H_
++#define _GLOBAL_H_ 1
++
++/* PROTOTYPES should be set to one if and only if the compiler supports
++     function argument prototyping.
++   The following makes PROTOTYPES default to 1 if it has not already been
++     defined as 0 with C compiler flags.
++ */
++#ifndef PROTOTYPES
++#define PROTOTYPES 1
++#endif
++
++/* POINTER defines a generic pointer type */
++typedef unsigned char *POINTER;
++
++/* UINT2 defines a two byte word */
++typedef unsigned short int UINT2;
++
++/* UINT4 defines a four byte word */
++#ifdef UINT32_H
++#define UINT4 uint32
++#endif
++
++#ifndef NULL_PTR
++#define NULL_PTR ((POINTER)0)
++#endif
++
++#ifndef UNUSED_ARG
++#define UNUSED_ARG(x) x = *(&x);
++#endif
++
++/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
++   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
++     returns an empty list.  
++ */
++#if PROTOTYPES
++#define PROTO_LIST(list) list
++#else
++#define PROTO_LIST(list) ()
++#endif
++
++#endif /* end _GLOBAL_H_ */
+diff -ruN ../netqmail-1.06-original/goodrcptto-12.patch netqmail-1.06/goodrcptto-12.patch
+--- ../netqmail-1.06-original/goodrcptto-12.patch	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/goodrcptto-12.patch	2004-11-09 20:12:53.000000000 +0100
+@@ -0,0 +1,834 @@
++This is a goodrcptto patch for qmail-1.03 or netqmail-1.05:
++http://netdevice.com/qmail/patch/goodrcptto-12.patch
++See http://cr.yp.to/qmail.html or http://qmail.org/netqmail/.
++
++A qmail server will normally accept email for any recipient address at a domain.
++This patch causes the server to reject single recipient email to an invalid
++recipient, and filter out the invalid recipients from multiple recipient email,
++while accepting the message for the valid recipients.
++This occurs during the initial SMTP conversation for a reduction in disk I/O.
++The server rejects attempts to queue messages to non existent recipients, and
++joe job bounces to forged recipients, preventing them from becoming double
++bounces.
++To prevent dictionary attacks, the transmission channel is closed after the
++number of bad recipients set in control/brtlimit or BRTLIMIT, two by default.
++Repeated attempts from the same IPs may be handled by a cron that looks at the
++logs and updates tcprules accordingly.
++
++A goodrcptto list and or moregoodrcptto database is maintained.
++Relay and accept clients are not held to the address check, control/brtlimit or
++BRTLIMIT.
++If you need to wildcard domains, list them one per line like @example.net
++in control/goodrcptto only.
++Recipient addresses like name@example.com may be included in control/goodrcptto,
++but the check will run fastest if you put these into control/moregoodrcptto,
++then into control/moregoodrcptto.cdb using qmail-newmgrt.
++A check against a 50,000 address moregoodrcptto.cdb is virtually instantaneous
++on a 300Mhz machine.
++
++A user may want to participate in mailing list discussions, but doesn't want
++spam or off list replies to her now public address.
++Set ACCEPTCLIENT="" for the IPs of the mailing list servers with tcprules, and
++put the recipient address in control/protectedgood instead.
++
++For an example of how to automate this process, see the parent directory for an
++interactive user run script where one can remotely add, remove or list their
++disposable alias addresses, and the mail server cron that keeps the
++moregoodrcptto.cdb up to date.
++The patch assumes a Dave Sill type of installation with regards to extra control
++files concurrencyincoming and defaultdelivery, see http://lifewithqmail.org.
++
++Use http@ to get the patch onto your box, tab characters must be preserved.
++Here are examples of how to patch.
++
++Solaris:
++# gzip -cd qmail-1.03.tar.gz |tar -xf - ;cd qmail-1.03
++# gpatch </path/to/goodrcptto-12.patch
++or
++# gzip -cd netqmail-1.05.tar.gz |tar -xf - ;cd netqmail-1.05
++# sh -c "cat collate.sh |sed -e s/patch/gpatch/ >collate.sh"
++# ./collate.sh ;cd netqmail-1.05
++# gpatch </path/to/goodrcptto-12.patch
++
++Others:
++# gzip -cd qmail-1.03.tar.gz |tar -xf - ;cd qmail-1.03
++# patch </path/to/goodrcptto-12.patch
++or
++# gzip -cd netqmail-1.05.tar.gz |tar -xf - ;cd netqmail-1.05
++# ./collate.sh ;cd netqmail-1.05
++# patch </path/to/goodrcptto-12.patch
++
++Log example:
++2003-06-08 12:56:28.951415500 qmail-smtpd: !ok 29791 Bad recipient user nonexistent@example.com from DealsonWheels@321sm.com by 205.235.78.101 (HELO mx4.321sm.com).
++
++2003-06-08 01: Original version, based on John Levine's badrcptto patch:
++               http://www.iecc.com/bad-rcpt-noisy-patch.txt
++2003-06-15 02: Added support for domain wildcarding.
++2003-06-15 03: Running qmail-showctl also shows good recipient addresses.
++2003-07-01 04: The pid for the connection is included in the log.
++2003-07-11 05: Experimental.
++2003-07-13 06: Experimental.
++2003-07-20 07: Removed the message block on a mix of good and bad recipients.
++               Allowed for only using a goodrcptto list.
++               Corrected an error in the qmail-showctl.c patch.
++2003-09-02 08: Added publicly known recipient address protection using an
++               ACCEPTCLIENT tcprules variable.
++2003-10-04 09: Running qmail-showctl also shows protected recipient addresses.
++2003-11-07 10: Discontinued the non logging version of goodrcptto.
++               Added dictionary attack prevention within qmail-smtpd using
++               control/brtlimit and or BRTLIMIT.
++               Updated the qmail-smtpd.8 man page patch regarding ACCEPTCLIENT,
++               control/brtlimit and BRTLIMIT.
++               Updated the qmail-control.9 man page patch regarding brtlimit,
++               concurrencyincoming, defaultdelivery, goodrcptto, moregoodrcptto
++               and protectedgood.
++2004-02-14 11: Code cleanup and standardization with tcpserver logging at 
++               getpid.
++               This single patch works with both qmail-1.03 and netqmail-1.05.
++               The brtcount is continued across rsets.
++2004-03-05 12: No changes, matched version number with goodrcptto-ms-12.patch.
++
++Eben Pratt, goodrcptto at netdevice dot com
++_____
++
++diff -ur qmail-1.03.orig/Makefile qmail-1.03/Makefile
++--- qmail-1.03.orig/Makefile	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/Makefile	Sat Feb 14 02:41:03 2004
++@@ -803,7 +803,7 @@
++ predate datemail mailsubj qmail-upq qmail-showctl 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 \
+++qmail-smtpd sendmail tcp-env qmail-newmrh qmail-newmgrt config config-fast dnscname \
++ dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
++ forward preline condredirect bouncesaying except maildirmake \
++ maildir2mbox maildirwatch qail elq pinq idedit install-big install \
++@@ -930,8 +930,8 @@
++ qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.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 \
++-preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \
+++qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qmail-newmgrt.0 qreceipt.0 qbiff.0 \
+++forward.0 preline.0 condredirect.0 bouncesaying.0 except.0 maildirmake.0 \
++ maildir2mbox.0 maildirwatch.0 qmail.0 qmail-limits.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 \
++@@ -1241,6 +1241,31 @@
++ uint32.h substdio.h
++ 	./compile qmail-newmrh.c
++ 
+++qmail-newmgrt: \
+++load qmail-newmgrt.o cdbmss.o getln.a open.a cdbmake.a seek.a case.a \
+++stralloc.a alloc.a strerr.a substdio.a error.a str.a auto_qmail.o
+++	./load qmail-newmgrt cdbmss.o getln.a open.a cdbmake.a \
+++	seek.a case.a stralloc.a alloc.a strerr.a substdio.a \
+++	error.a str.a auto_qmail.o 
+++
+++qmail-newmgrt.0: \
+++qmail-newmgrt.8
+++	nroff -man qmail-newmgrt.8 > qmail-newmgrt.0
+++
+++qmail-newmgrt.8: \
+++qmail-newmgrt.9 conf-break conf-spawn
+++	cat qmail-newmgrt.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-newmgrt.8
+++
+++qmail-newmgrt.o: \
+++compile qmail-newmgrt.c strerr.h stralloc.h gen_alloc.h substdio.h \
+++getln.h exit.h readwrite.h open.h auto_qmail.h cdbmss.h cdbmake.h \
+++uint32.h substdio.h
+++	./compile qmail-newmgrt.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
++@@ -1767,7 +1792,7 @@
++ maildirwatch.1 mailsubj.1 mbox.5 preline.1 qbiff.1 qmail-clean.8 \
++ qmail-command.8 qmail-control.9 qmail-getpw.9 qmail-header.5 \
++ qmail-inject.8 qmail-limits.9 qmail-local.8 qmail-log.5 \
++-qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \
+++qmail-lspawn.8 qmail-newmrh.9 qmail-newmgrt.9 qmail-newu.9 qmail-pop3d.8 \
++ qmail-popup.8 qmail-pw2u.9 qmail-qmqpc.8 qmail-qmqpd.8 qmail-qmtpd.8 \
++ qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-remote.8 \
++ qmail-rspawn.8 qmail-send.9 qmail-showctl.8 qmail-smtpd.8 \
++@@ -1774,7 +1799,7 @@
++ qmail-start.9 qmail-tcpok.8 qmail-tcpto.8 qmail-users.9 qmail.7 \
++ qreceipt.1 splogger.8 tcp-env.1 config.sh config-fast.sh \
++ qmail-clean.c qmail-getpw.c qmail-inject.c qmail-local.c \
++-qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \
+++qmail-lspawn.c qmail-newmrh.c qmail-newmgrt.c qmail-newu.c qmail-pop3d.c \
++ qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
++ qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
++ qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
++diff -ur qmail-1.03.orig/TARGETS qmail-1.03/TARGETS
++--- qmail-1.03.orig/TARGETS	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/TARGETS	Sat Feb 14 02:41:03 2004
++@@ -257,6 +257,8 @@
++ tcp-env.o
++ remoteinfo.o
++ tcp-env
+++qmail-newmgrt.o
+++qmail-newmgrt
++ qmail-newmrh.o
++ qmail-newmrh
++ config
++@@ -352,6 +354,8 @@
++ qmail-qmtpd.0
++ qmail-smtpd.0
++ tcp-env.0
+++qmail-newmgrt.8
+++qmail-newmgrt.0
++ qmail-newmrh.8
++ qmail-newmrh.0
++ qreceipt.0
++diff -ur qmail-1.03.orig/conf-spawn qmail-1.03/conf-spawn
++--- qmail-1.03.orig/conf-spawn	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/conf-spawn	Sat Feb 14 02:41:03 2004
++@@ -1,4 +1,4 @@
++-120
+++255
++ 
++ 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 -ur qmail-1.03.orig/hier.c qmail-1.03/hier.c
++--- qmail-1.03.orig/hier.c	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/hier.c	Sat Feb 14 02:41:03 2004
++@@ -109,6 +109,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-newmgrt",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);
++@@ -221,6 +222,8 @@
++   c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
+++  c(auto_qmail,"man/man8","qmail-newmgrt.8",auto_uido,auto_gidq,0644);
+++  c(auto_qmail,"man/cat8","qmail-newmgrt.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
++diff -ur qmail-1.03.orig/install-big.c qmail-1.03/install-big.c
++--- qmail-1.03.orig/install-big.c	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/install-big.c	Sat Feb 14 02:41:03 2004
++@@ -109,6 +109,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-newmgrt",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);
++@@ -221,6 +222,8 @@
++   c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
+++  c(auto_qmail,"man/man8","qmail-newmgrt.8",auto_uido,auto_gidq,0644);
+++  c(auto_qmail,"man/cat8","qmail-newmgrt.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
++   c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
++diff -ur qmail-1.03.orig/qmail-control.9 qmail-1.03/qmail-control.9
++--- qmail-1.03.orig/qmail-control.9	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/qmail-control.9	Sat Feb 14 02:41:03 2004
++@@ -21,6 +21,7 @@
++ Comments are allowed
++ in
++ .IR badmailfrom ,
+++.IR goodrcptto ,
++ .IR locals ,
++ .IR percenthack ,
++ .IR qmqpservers ,
++@@ -43,8 +44,11 @@
++ .I badmailfrom	\fR(none)	\fRqmail-smtpd
++ .I bouncefrom	\fRMAILER-DAEMON	\fRqmail-send
++ .I bouncehost	\fIme	\fRqmail-send
+++.I brtlimit	\fR2	\fRqmail-smtpd
+++.I concurrencyincoming	\fR40	\fRtcpserver
++ .I concurrencylocal	\fR10	\fRqmail-send
++ .I concurrencyremote	\fR20	\fRqmail-send
+++.I defaultdelivery	\fR(none)	\fRqmail-start
++ .I defaultdomain	\fIme	\fRqmail-inject
++ .I defaulthost	\fIme	\fRqmail-inject
++ .I databytes	\fR0	\fRqmail-smtpd
++@@ -51,13 +55,16 @@
++ .I doublebouncehost	\fIme	\fRqmail-send
++ .I doublebounceto	\fRpostmaster	\fRqmail-send
++ .I envnoathost	\fIme	\fRqmail-send
+++.I goodrcptto	\fR(none)	\fRqmail-smtpd
++ .I helohost	\fIme	\fRqmail-remote
++ .I idhost	\fIme	\fRqmail-inject
++ .I localiphost	\fIme	\fRqmail-smtpd
++ .I locals	\fIme	\fRqmail-send
+++.I moregoodrcptto	\fR(none)	\fRqmail-smtpd
++ .I morercpthosts	\fR(none)	\fRqmail-smtpd
++ .I percenthack	\fR(none)	\fRqmail-send
++ .I plusdomain	\fIme	\fRqmail-inject
+++.I protectedgood	\fR(none)	\fRqmail-showctl
++ .I qmqpservers	\fR(none)	\fRqmail-qmqpc
++ .I queuelifetime	\fR604800	\fRqmail-send
++ .I rcpthosts	\fR(none)	\fRqmail-smtpd
++diff -ur qmail-1.03.orig/qmail-newmgrt.9 qmail-1.03/qmail-newmgrt.9
++--- qmail-1.03.orig/qmail-newmgrt.9	Thu Jan  1 00:00:00 1970
+++++ qmail-1.03/qmail-newmgrt.9	Sat Feb 14 02:41:04 2004
++@@ -0,0 +1,41 @@
+++.TH qmail-newmgrt 8
+++.SH NAME
+++qmail-newmgrt \- prepare moregoodrcptto for qmail-smtpd
+++.SH SYNOPSIS
+++.B qmail-newmgrt
+++.SH DESCRIPTION
+++.B qmail-newmgrt
+++reads the instructions in
+++.B QMAILHOME/control/moregoodrcptto
+++and writes them into
+++.B QMAILHOME/control/moregoodrcptto.cdb
+++in a binary format suited
+++for quick access by
+++.BR qmail-smtpd .
+++
+++If there is a problem with
+++.BR control/moregoodrcptto ,
+++.B qmail-newmgrt
+++complains and leaves
+++.B control/moregoodrcptto.cdb
+++alone.
+++
+++.B qmail-newmgrt
+++ensures that
+++.B control/moregoodrcptto.cdb
+++is updated atomically,
+++so
+++.B qmail-smtpd
+++never has to wait for
+++.B qmail-newmgrt
+++to finish.
+++However,
+++.B qmail-newmgrt
+++makes no attempt to protect against two simultaneous updates of
+++.BR control/moregoodrcptto.cdb .
+++
+++The binary
+++.B control/moregoodrcptto.cdb
+++format is portable across machines.
+++.SH "SEE ALSO"
+++qmail-smtpd(8)
++diff -ur qmail-1.03.orig/qmail-newmgrt.c qmail-1.03/qmail-newmgrt.c
++--- qmail-1.03.orig/qmail-newmgrt.c	Thu Jan  1 00:00:00 1970
+++++ qmail-1.03/qmail-newmgrt.c	Sat Feb 14 02:41:04 2004
++@@ -0,0 +1,70 @@
+++#include "strerr.h"
+++#include "stralloc.h"
+++#include "substdio.h"
+++#include "getln.h"
+++#include "exit.h"
+++#include "readwrite.h"
+++#include "open.h"
+++#include "auto_qmail.h"
+++#include "cdbmss.h"
+++
+++#define FATAL "qmail-newmgrt: fatal: "
+++
+++void die_read()
+++{
+++  strerr_die2sys(111,FATAL,"unable to read control/moregoodrcptto: ");
+++}
+++void die_write()
+++{
+++  strerr_die2sys(111,FATAL,"unable to write to control/moregoodrcptto.tmp: ");
+++}
+++
+++char inbuf[1024];
+++substdio ssin;
+++
+++int fd;
+++int fdtemp;
+++
+++struct cdbmss cdbmss;
+++stralloc line = {0};
+++int match;
+++
+++void main()
+++{
+++  umask(033);
+++  if (chdir(auto_qmail) == -1)
+++    strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
+++
+++  fd = open_read("control/moregoodrcptto");
+++  if (fd == -1) die_read();
+++
+++  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf);
+++
+++  fdtemp = open_trunc("control/moregoodrcptto.tmp");
+++  if (fdtemp == -1) die_write();
+++
+++  if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write();
+++
+++  for (;;) {
+++    if (getln(&ssin,&line,&match,'\n') != 0) die_read();
+++    case_lowerb(line.s,line.len);
+++    while (line.len) {
+++      if (line.s[line.len - 1] == ' ') { --line.len; continue; }
+++      if (line.s[line.len - 1] == '\n') { --line.len; continue; }
+++      if (line.s[line.len - 1] == '\t') { --line.len; continue; }
+++      if (line.s[0] != '#')
+++       if (cdbmss_add(&cdbmss,line.s,line.len,"",0) == -1)
+++         die_write();
+++      break;
+++    }
+++    if (!match) break;
+++  }
+++
+++  if (cdbmss_finish(&cdbmss) == -1) die_write();
+++  if (fsync(fdtemp) == -1) die_write();
+++  if (close(fdtemp) == -1) die_write(); /* NFS stupidity */
+++  if (rename("control/moregoodrcptto.tmp","control/moregoodrcptto.cdb") == -1)
+++    strerr_die2sys(111,FATAL,"unable to move control/moregoodrcpto.tmp to control/moregoodrcptto.cdb");
+++
+++  _exit(0);
+++}
++diff -ur qmail-1.03.orig/qmail-showctl.c qmail-1.03/qmail-showctl.c
++--- qmail-1.03.orig/qmail-showctl.c	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/qmail-showctl.c	Sat Feb 14 02:41:04 2004
++@@ -142,6 +142,8 @@
++   direntry *d;
++   struct stat stmrh;
++   struct stat stmrhcdb;
+++  struct stat stmgrt;
+++  struct stat stmgrtcdb;
++ 
++   substdio_puts(subfdout,"qmail home directory: ");
++   substdio_puts(subfdout,auto_qmail);
++@@ -217,9 +219,12 @@
++   do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
++   do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
++   do_str("bouncehost",1,"bouncehost","Bounce host name is ");
+++  do_int("brtlimit","2","Transmission channel close after "," bad recipients");
+++  do_int("concurrencyincoming","1","Incoming concurrency is ","");
++   do_int("concurrencylocal","10","Local concurrency is ","");
++   do_int("concurrencyremote","20","Remote concurrency is ","");
++   do_int("databytes","0","SMTP DATA limit is "," bytes");
+++  do_str("defaultdelivery",1,"defaultdelivery","Default mailbox is "); 
++   do_str("defaultdomain",1,"defaultdomain","Default domain name is ");
++   do_str("defaulthost",1,"defaulthost","Default host name is ");
++   do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: ");
++@@ -235,8 +240,8 @@
++   do_lst("qmqpservers","No QMQP servers.","QMQP server: ",".");
++   do_int("queuelifetime","604800","Message lifetime in the queue is "," seconds");
++ 
++-  if (do_lst("rcpthosts","SMTP clients may send messages to any recipient.","SMTP clients may send messages to recipients at ","."))
++-    do_lst("morercpthosts","No effect.","SMTP clients may send messages to recipients at ",".");
+++  if (do_lst("rcpthosts","SMTP relay clients may send to any recipient.","SMTP relay clients may send to recipients at ","."))
+++    do_lst("morercpthosts","No effect.","SMTP relay clients may send to recipients at ",".");
++   else
++     do_lst("morercpthosts","No rcpthosts; morercpthosts is irrelevant.","No rcpthosts; doesn't matter that morercpthosts has ",".");
++   /* XXX: check morercpthosts.cdb contents */
++@@ -255,6 +260,27 @@
++       else
++         substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n");
++ 
+++  if (do_lst("goodrcptto","Oops? moregoodrcptto must exist if this doesn't.","SMTP clients may send to ","."))
+++    do_lst("moregoodrcptto","No effect.","SMTP clients may send to ",".");
+++  else
+++    do_lst("moregoodrcptto","Oops? goodrcptto must exist if this doesn't.","SMTP clients may send to ",".");
+++  /* XXX: check moregoodrcptto.cdb contents */
+++  substdio_puts(subfdout,"\nmoregoodrcptto.cdb: ");
+++  if (stat("moregoodrcptto",&stmgrt) == -1)
+++    if (stat("moregoodrcptto.cdb",&stmgrtcdb) == -1)
+++      substdio_puts(subfdout,"(Default.) No effect.\n");
+++    else
+++      substdio_puts(subfdout,"Oops! moregoodrcptto.cdb exists but moregoodrcptto doesn't.\n");
+++  else
+++    if (stat("moregoodrcptto.cdb",&stmgrtcdb) == -1)
+++      substdio_puts(subfdout,"Oops! moregoodrcptto exists but moregoodrcptto.cdb doesn't.\n");
+++    else
+++      if (stmgrt.st_mtime > stmgrtcdb.st_mtime)
+++        substdio_puts(subfdout,"Oops! moregoodrcptto.cdb is older than moregoodrcptto.\n");
+++      else
+++        substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n");
+++
+++  do_lst("protectedgood","No accept client addresses.","SMTP accept clients may send to ",".");
++   do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
++   do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
++   do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds");
++@@ -265,19 +291,21 @@
++   while (d = readdir(dir)) {
++     if (str_equal(d->d_name,".")) continue;
++     if (str_equal(d->d_name,"..")) continue;
++-    if (str_equal(d->d_name,"bouncefrom")) continue;
++-    if (str_equal(d->d_name,"bouncehost")) continue;
++     if (str_equal(d->d_name,"badmailfrom")) continue;
++     if (str_equal(d->d_name,"bouncefrom")) continue;
++     if (str_equal(d->d_name,"bouncehost")) continue;
+++    if (str_equal(d->d_name,"brtlimit")) continue;
+++    if (str_equal(d->d_name,"concurrencyincoming")) continue;
++     if (str_equal(d->d_name,"concurrencylocal")) continue;
++     if (str_equal(d->d_name,"concurrencyremote")) continue;
++     if (str_equal(d->d_name,"databytes")) continue;
+++    if (str_equal(d->d_name,"defaultdelivery")) continue;
++     if (str_equal(d->d_name,"defaultdomain")) continue;
++     if (str_equal(d->d_name,"defaulthost")) continue;
++     if (str_equal(d->d_name,"doublebouncehost")) continue;
++     if (str_equal(d->d_name,"doublebounceto")) continue;
++     if (str_equal(d->d_name,"envnoathost")) continue;
+++    if (str_equal(d->d_name,"goodrcptto")) continue;
++     if (str_equal(d->d_name,"helohost")) continue;
++     if (str_equal(d->d_name,"idhost")) continue;
++     if (str_equal(d->d_name,"localiphost")) continue;
++@@ -285,8 +313,11 @@
++     if (str_equal(d->d_name,"me")) continue;
++     if (str_equal(d->d_name,"morercpthosts")) continue;
++     if (str_equal(d->d_name,"morercpthosts.cdb")) continue;
+++    if (str_equal(d->d_name,"moregoodrcptto")) continue;
+++    if (str_equal(d->d_name,"moregoodrcptto.cdb")) continue;
++     if (str_equal(d->d_name,"percenthack")) continue;
++     if (str_equal(d->d_name,"plusdomain")) continue;
+++    if (str_equal(d->d_name,"protectedgood")) continue;
++     if (str_equal(d->d_name,"qmqpservers")) continue;
++     if (str_equal(d->d_name,"queuelifetime")) continue;
++     if (str_equal(d->d_name,"rcpthosts")) continue;
++diff -ur qmail-1.03.orig/qmail-smtpd.8 qmail-1.03/qmail-smtpd.8
++--- qmail-1.03.orig/qmail-smtpd.8	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/qmail-smtpd.8	Sat Feb 14 02:41:04 2004
++@@ -50,6 +50,20 @@
++ meaning every address at
++ .IR host .
++ .TP 5
+++.I brtlimit
+++Number of bad recipients before closing the transmission channel.
+++.B qmail-smtpd
+++will close the transmission channel after 
+++reaching the number of bad recipients in
+++.IR brtlimit .
+++
+++If the environment variable
+++.B BRTLIMIT 
+++is set, it overrides
+++.IR brtlimit .
+++
+++Default and minimum: 2.
+++.TP 5
++ .I databytes
++ Maximum number of bytes allowed in a message,
++ or 0 for no limit.
++@@ -77,6 +91,50 @@
++ is set, it overrides
++ .IR databytes .
++ .TP 5
+++.I goodrcptto 
+++Allowed RCPT addresses.
+++.B qmail-smtpd
+++will reject
+++any envelope recipient address not listed in
+++.I goodrcptto
+++or
+++.IR moregoodrcptto .
+++A line in
+++.I goodrcptto 
+++may be of the form
+++.BR @\fIhost ,
+++meaning every address at
+++.IR host .
+++
+++.I goodrcptto
+++format:
+++
+++.EX
+++   @heaven.af.mil
+++   box@heaven.af.mil
+++.EE 
+++
+++Exceptions:
+++If the environment variable
+++.B RELAYCLIENT
+++is set,
+++.B qmail-smtpd
+++will ignore
+++.I goodrcptto
+++and
+++.IR moregoodrcptto ,
+++and will append the value of
+++.B RELAYCLIENT
+++to each incoming recipient address.
+++If the environment variable
+++.B ACCEPTCLIENT
+++is set,
+++.B qmail-smtpd
+++will ignore
+++.I goodrcptto
+++and
+++.IR moregoodrcptto .
+++.TP 5
++ .I localiphost
++ Replacement host name for local IP addresses.
++ Default:
++@@ -97,6 +155,38 @@
++ This is done before
++ .IR rcpthosts .
++ .TP 5
+++.I moregoodrcptto
+++Extra allowed RCPT addresses.
+++If
+++.I goodrcptto 
+++and
+++.I moregoodrcptto
+++both exist,
+++.I moregoodrcptto
+++is effectively appended to
+++.IR goodrcptto .
+++
+++.I moregoodrcptto
+++format:
+++
+++.EX
+++   box@heaven.af.mil
+++.EE
+++
+++You must run
+++.B qmail-newmgrt
+++whenever
+++.I moregoodrcptto
+++changes.
+++
+++Rule of thumb:
+++Put your
+++.BR @\fIhost
+++wildcarded domains into
+++.IR goodrcptto ,
+++and the rest into
+++.IR moregoodrcptto .
+++.TP 5
++ .I morercpthosts
++ Extra allowed RCPT domains.
++ If
++@@ -150,7 +240,7 @@
++ .EE
++ 
++ Envelope recipient addresses without @ signs are
++-always allowed through.
+++allowed through if added to goodrcptto or moregoodrcptto.
++ .TP 5
++ .I smtpgreeting
++ SMTP greeting message.
++@@ -174,6 +264,7 @@
++ tcp-environ(5),
++ qmail-control(5),
++ qmail-inject(8),
+++qmail-newmgrt(8),
++ qmail-newmrh(8),
++ qmail-queue(8),
++ qmail-remote(8)
++diff -ur qmail-1.03.orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c
++--- qmail-1.03.orig/qmail-smtpd.c	Mon Jun 15 06:53:16 1998
+++++ qmail-1.03/qmail-smtpd.c	Sat Feb 14 03:12:49 2004
++@@ -23,11 +23,19 @@
++ #include "timeoutread.h"
++ #include "timeoutwrite.h"
++ #include "commands.h"
+++#include "cdb.h"
++ 
++ #define MAXHOPS 100
++ unsigned int databytes = 0;
++ int timeout = 1200;
++ 
+++char *remoteip;
+++char *remotehost;
+++char *remoteinfo;
+++char *local;
+++char *relayclient;
+++char *acceptclient;
+++
++ int safewrite(fd,buf,len) int fd; char *buf; int len;
++ {
++   int r;
++@@ -42,12 +50,39 @@
++ void flush() { substdio_flush(&ssout); }
++ void out(s) char *s; { substdio_puts(&ssout,s); }
++ 
+++char sserrbuf[512];
+++substdio sserr = SUBSTDIO_FDBUF(safewrite,2,sserrbuf,sizeof sserrbuf);
+++
+++char strnum[FMT_ULONG];
+++void log(s) char *s; { substdio_putsflush(&sserr,s); }
+++void logs(s1,s2,s3) char *s1; char *s2; char *s3; {
+++  substdio_putsflush(&sserr,s1);
+++  substdio_putsflush(&sserr,s2);
+++  substdio_putsflush(&sserr,s3);
+++}
+++void pid() { log("qmail-smtpd: !ok "); strnum[fmt_ulong(strnum,getpid())] = 0; log(strnum); }
+++
++ void die_read() { _exit(1); }
++-void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
++-void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
++-void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
++-void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
++-void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
+++void die_alarm() {
+++  pid(); logs(" Connection to ",remoteip," timed out.\n");
+++  out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1);
+++}
+++void die_nomem() {
+++  pid(); logs(" Out of memory while connected to ",remoteip,"!\n");
+++  out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1);
+++}
+++void die_control() {
+++  pid(); log(" Unable to read controls!\n");
+++  out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1);
+++}
+++void die_ipme() {
+++  pid(); log(" Unable to figure out my IP addresses!\n");
+++  out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1);
+++}
+++void straynewline() {
+++  pid(); logs(" Stray newline from ",remoteip,".\n");
+++  out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1);
+++}
++ 
++ void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
++ void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
++@@ -76,12 +111,6 @@
++   smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
++ }
++ 
++-char *remoteip;
++-char *remotehost;
++-char *remoteinfo;
++-char *local;
++-char *relayclient;
++-
++ stralloc helohost = {0};
++ char *fakehelo; /* pointer into helohost, or 0 */
++ 
++@@ -96,6 +125,11 @@
++ int bmfok = 0;
++ stralloc bmf = {0};
++ struct constmap mapbmf;
+++int grtok = 0;
+++stralloc grt = {0};
+++struct constmap mapgrt;
+++int fdmgrt;
+++int brtlimit = 0;
++ 
++ void setup()
++ {
++@@ -117,6 +151,19 @@
++   if (bmfok)
++     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
++  
+++  grtok = control_readfile(&grt,"control/goodrcptto",0);
+++  if (grtok == -1) die_control();
+++  if (grtok)
+++    if (!constmap_init(&mapgrt,grt.s,grt.len,0)) die_nomem();
+++
+++  fdmgrt = open_read("control/moregoodrcptto.cdb");
+++  if (fdmgrt == -1) if (errno != error_noent) die_control();
+++
+++  if (control_readint(&brtlimit,"control/brtlimit") == -1) die_control();
+++  x = env_get("BRTLIMIT");
+++  if (x) { scan_ulong(x,&u); brtlimit = u; };
+++  if (brtlimit <= 1) brtlimit = 2;
+++
++   if (control_readint(&databytes,"control/databytes") == -1) die_control();
++   x = env_get("DATABYTES");
++   if (x) { scan_ulong(x,&u); databytes = u; }
++@@ -131,6 +178,7 @@
++   if (!remotehost) remotehost = "unknown";
++   remoteinfo = env_get("TCPREMOTEINFO");
++   relayclient = env_get("RELAYCLIENT");
+++  acceptclient = env_get("ACCEPTCLIENT");
++   dohelo(remotehost);
++ }
++ 
++@@ -197,6 +245,16 @@
++   return 1;
++ }
++ 
+++void err_brt(s1,s2,s3,s4) char *s1; char *s2; char *s3; char *s4; {
+++  pid(); log(s1); log(s2); log(s3); log(s4); log(" by ");
+++  log(remoteip); log(" (HELO "); log(helohost.s); log(").\n");
+++}
+++
+++void die_attack() {
+++  pid(); logs(" Too many bad recipients from ",remoteip,", closing connection.\n");
+++  out("421 service shutting down and closing transmission channel (#4.3.0)\r\n"); flush(); _exit(1);
+++}
+++
++ int bmfcheck()
++ {
++   int j;
++@@ -208,6 +266,24 @@
++   return 0;
++ }
++ 
+++int grtcheck()
+++{
+++  int g;
+++  case_lowerb(addr.s,addr.len);
+++  if (grtok) {
+++    if (constmap(&mapgrt,addr.s,addr.len - 1)) return 1;
+++    g = byte_rchr(addr.s,addr.len,'@');
+++    if (g < addr.len)
+++      if (constmap(&mapgrt,addr.s + g,addr.len - g - 1)) return 1;  
+++  }
+++  if (fdmgrt != -1) {
+++    uint32 dlen;
+++    g = cdb_seek(fdmgrt, addr.s, addr.len - 1, &dlen);
+++    if (g) return g;
+++  }
+++  return 0;
+++}
+++
++ int addrallowed()
++ {
++   int r;
++@@ -221,6 +297,7 @@
++ int flagbarf; /* defined if seenmail */
++ stralloc mailfrom = {0};
++ stralloc rcptto = {0};
+++int brtcount;
++ 
++ void smtp_helo(arg) char *arg;
++ {
++@@ -250,7 +327,10 @@
++ void smtp_rcpt(arg) char *arg; {
++   if (!seenmail) { err_wantmail(); return; }
++   if (!addrparse(arg)) { err_syntax(); return; }
++-  if (flagbarf) { err_bmf(); return; }
+++  if (flagbarf) {
+++    err_brt(" Bad envelope sender ",mailfrom.s," to ",addr.s);
+++    err_bmf(); return;
+++  }
++   if (relayclient) {
++     --addr.len;
++     if (!stralloc_cats(&addr,relayclient)) die_nomem();
++@@ -257,7 +337,23 @@
++     if (!stralloc_0(&addr)) die_nomem();
++   }
++   else
++-    if (!addrallowed()) { err_nogateway(); return; }
+++    if (!addrallowed()) {
+++      err_brt(" Bad recipient host ",addr.s," from ",mailfrom.s);
+++      if (++brtcount == brtlimit) die_attack();
+++      err_nogateway(); return;
+++    }
+++    else
+++      if (!acceptclient) {
+++        if (!grtcheck()) {
+++          if (str_equal(mailfrom.s,"")) {
+++            err_brt(" Forged recipient user ",addr.s," from ","null");
+++          }
+++          else
+++            err_brt(" Bad recipient user ",addr.s," from ",mailfrom.s);
+++          if (++brtcount == brtlimit) die_attack();
+++          out("550 sorry, no mailbox here by that name (#5.1.1)\r\n"); return;
+++        }
+++      }
++   if (!stralloc_cats(&rcptto,"T")) die_nomem();
++   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
++   if (!stralloc_0(&rcptto)) die_nomem();
+diff -ruN ../netqmail-1.06-original/hier.c netqmail-1.06/hier.c
+--- ../netqmail-1.06-original/hier.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/hier.c	2018-01-04 22:33:49.406411066 +0100
+@@ -32,6 +32,7 @@
+   h(auto_qmail,auto_uido,auto_gidq,0755);
+ 
+   d(auto_qmail,"control",auto_uido,auto_gidq,0755);
++  d(auto_qmail,"control/cache",89,89,0755);
+   d(auto_qmail,"users",auto_uido,auto_gidq,0755);
+   d(auto_qmail,"bin",auto_uido,auto_gidq,0755);
+   d(auto_qmail,"boot",auto_uido,auto_gidq,0755);
+@@ -55,6 +56,8 @@
+   d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700);
+ 
+   dsplit("queue/mess",auto_uidq,0750);
++  dsplit("queue/todo",auto_uidq,0750);
++  dsplit("queue/intd",auto_uidq,0700);
+   dsplit("queue/info",auto_uids,0700);
+   dsplit("queue/local",auto_uids,0700);
+   dsplit("queue/remote",auto_uids,0700);
+@@ -89,6 +92,7 @@
+   c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644);
+@@ -104,13 +108,26 @@
+   c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700);
+   c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-local",auto_uido,auto_gidq,0711);
++  c(auto_qmail,"bin","spawn-filter",auto_uido,auto_gidq,0711);
++  c(auto_qmail,"bin","surblfilter",auto_uido,auto_gidq,0711);
++  c(auto_qmail,"bin","dk-filter",auto_uido,auto_gidq,0555);
++  c(auto_qmail,"bin","dknewkey", auto_uido, auto_gidq, 0711);
++  c(auto_qmail,"bin","dktest",auto_uido,auto_gidq,0711);
++  c(auto_qmail,"bin","surblqueue",auto_uido,auto_gidq,0555);
+   c(auto_qmail,"bin","qmail-remote",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
++#ifdef EXTERNAL_TODO
++  c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
++#endif
++  c(auto_qmail,"bin","qmail-dk",auto_uidq,auto_gidq,0711);
++  c(auto_qmail,"bin","qmail-dkim",auto_uidq,auto_gidq,0711);
++  c(auto_qmail,"bin","dkim",auto_uidq,auto_gidq,0711);
+   c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
+   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-newmvrt",auto_uido,auto_gidq,0700);
+   c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755);
+@@ -127,6 +144,7 @@
+   c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755);
++  c(auto_qmail,"bin","srsfilter",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
+@@ -143,6 +161,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);
+@@ -198,6 +219,18 @@
+   c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
+ 
+   c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","qmail-dk.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/cat8","qmail-dk.0",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","dkim.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","qmail-dkim.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/cat8","qmail-dkim.0",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","dk-filter.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/cat8","dk-filter.0",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","dktest.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","surblfilter.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/cat8","surblfilter.0",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/man8","spawn-filter.8",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"man/cat8","spawn-filter.0",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
+diff -ruN ../netqmail-1.06-original/hmac_md5.c netqmail-1.06/hmac_md5.c
+--- ../netqmail-1.06-original/hmac_md5.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/hmac_md5.c	2016-11-22 21:03:57.114528032 +0100
+@@ -0,0 +1,76 @@
++#include "global.h"
++#include "md5.h"
++
++/*
++** Function: hmac_md5
++*/
++
++void hmac_md5(text, text_len, key, key_len, digest)
++unsigned char*  text;                /* pointer to data stream */
++int             text_len;            /* length of data stream */
++unsigned char*  key;                 /* pointer to authentication key */
++int             key_len;             /* length of authentication key */
++unsigned char   *digest;              /* caller digest to be filled in */
++
++{
++        MD5_CTX context;
++        unsigned char k_ipad[65];    /* inner padding -
++                                      * key XORd with ipad
++                                      */
++        unsigned char k_opad[65];    /* outer padding -
++                                      * key XORd with opad
++                                      */
++        unsigned char tk[16];
++        int i;
++        /* if key is longer than 64 bytes reset it to key=MD5(key) */
++        if (key_len > 64) {
++
++                MD5_CTX      tctx;
++
++                MD5Init(&tctx);
++                MD5Update(&tctx, key, key_len);
++                MD5Final(tk, &tctx);
++
++                key = tk;
++                key_len = 16;
++        }
++
++        /*
++         * the HMAC_MD5 transform looks like:
++         *
++         * MD5(K XOR opad, MD5(K XOR ipad, text))
++         *
++         * where K is an n byte key
++         * ipad is the byte 0x36 repeated 64 times
++         * opad is the byte 0x5c repeated 64 times
++         * and text is the data being protected
++         */
++
++        /* start out by storing key in pads */
++        bzero( k_ipad, sizeof k_ipad);
++        bzero( k_opad, sizeof k_opad);
++        bcopy( key, k_ipad, key_len);
++        bcopy( key, k_opad, key_len);
++
++        /* XOR key with ipad and opad values */
++        for (i=0; i<64; i++) {
++                k_ipad[i] ^= 0x36;
++                k_opad[i] ^= 0x5c;
++        }
++        /*
++         * perform inner MD5
++         */
++        MD5Init(&context);                   /* init context for 1st pass */
++        MD5Update(&context, k_ipad, 64);      /* start with inner pad */
++        MD5Update(&context, text, text_len); /* then text of datagram */
++        MD5Final(digest, &context);          /* finish up 1st pass */
++        /*
++         * perform outer MD5
++         */
++        MD5Init(&context);                   /* init context for 2nd
++                                              * pass */
++        MD5Update(&context, k_opad, 64);     /* start with outer pad */
++        MD5Update(&context, digest, 16);     /* then results of 1st
++                                              * hash */
++        MD5Final(digest, &context);          /* finish up 2nd pass */
++}
+diff -ruN ../netqmail-1.06-original/hmac_md5.h netqmail-1.06/hmac_md5.h
+--- ../netqmail-1.06-original/hmac_md5.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/hmac_md5.h	2016-11-22 21:03:57.114528032 +0100
+@@ -0,0 +1,11 @@
++
++/* prototypes */
++
++void hmac_md5( unsigned char* text, int text_len, unsigned char* key, int key_len, unsigned char* digest);
++
++/* pointer to data stream */
++/* length of data stream */
++/* pointer to authentication key */
++/* length of authentication key */
++/* caller digest to be filled in */
++
+diff -ruN ../netqmail-1.06-original/install-big.c netqmail-1.06/install-big.c
+--- ../netqmail-1.06-original/install-big.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/install-big.c	2016-11-22 21:04:38.822137319 +0100
+@@ -89,6 +89,7 @@
+   c(auto_qmail,"doc","TEST.receive",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","REMOVE.sendmail",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","REMOVE.binmail",auto_uido,auto_gidq,0644);
++  c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2alias",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2ext",auto_uido,auto_gidq,0644);
+   c(auto_qmail,"doc","PIC.local2local",auto_uido,auto_gidq,0644);
+@@ -108,9 +109,13 @@
+   c(auto_qmail,"bin","qmail-rspawn",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-clean",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-send",auto_uido,auto_gidq,0711);
++#ifdef EXTERNAL_TODO
++  c(auto_qmail,"bin","qmail-todo",auto_uido,auto_gidq,0711);
++#endif
+   c(auto_qmail,"bin","splogger",auto_uido,auto_gidq,0711);
+   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-newmvrt",auto_uido,auto_gidq,0700);
+   c(auto_qmail,"bin","qmail-pw2u",auto_uido,auto_gidq,0711);
+   c(auto_qmail,"bin","qmail-inject",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","predate",auto_uido,auto_gidq,0755);
+@@ -133,6 +138,7 @@
+   c(auto_qmail,"bin","qsmhook",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","qbiff",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","forward",auto_uido,auto_gidq,0755);
++  c(auto_qmail,"bin","srsfilter",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","preline",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","condredirect",auto_uido,auto_gidq,0755);
+   c(auto_qmail,"bin","bouncesaying",auto_uido,auto_gidq,0755);
+diff -ruN ../netqmail-1.06-original/ip.h netqmail-1.06/ip.h
+--- ../netqmail-1.06-original/ip.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/ip.h	2016-11-22 21:03:57.115527999 +0100
+@@ -2,6 +2,7 @@
+ #define IP_H
+ 
+ struct ip_address { unsigned char d[4]; } ;
++typedef struct  ip_address ip_addr;
+ 
+ extern unsigned int ip_fmt();
+ #define IPFMT 19
+diff -ruN ../netqmail-1.06-original/ipalloc.h netqmail-1.06/ipalloc.h
+--- ../netqmail-1.06-original/ipalloc.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/ipalloc.h	2016-11-22 21:03:57.115527999 +0100
+@@ -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 -ruN ../netqmail-1.06-original/ipme.c netqmail-1.06/ipme.c
+--- ../netqmail-1.06-original/ipme.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/ipme.c	2016-11-22 21:03:57.115527999 +0100
+@@ -14,23 +14,65 @@
+ #include "ipalloc.h"
+ #include "stralloc.h"
+ #include "ipme.h"
++#include "substdio.h"
++#include "readwrite.h"
+ 
+ static int ipmeok = 0;
+ ipalloc ipme = {0};
++ipalloc ipme_mask = {0};
++ipalloc notipme = {0};
++ipalloc notipme_mask = {0};
+ 
+ int ipme_is(ip)
+ struct ip_address *ip;
+ {
+-  int i;
+   if (ipme_init() != 1) return -1;
+-  for (i = 0;i < ipme.len;++i)
+-    if (byte_equal(&ipme.ix[i].ip,4,ip))
+-      return 1;
+-  return 0;
++  return ipme_match(&ipme,&ipme_mask,ip) > ipme_match(&notipme,&notipme_mask,ip);
+ }
+ 
++int ipme_match(ipa, ipa_mask, ip)
++struct ipalloc *ipa, *ipa_mask;
++struct ip_address *ip;
++{
++  int i,j;
++  struct ip_address masked;
++  int masklen, longest_masklen=-1;
++
++  for(i=0;i < ipa->len;++i)
++  {
++    masklen = 0;
++    for(j=0;j<4;++j)
++    {
++      switch(ipa_mask->ix[i].ip.d[j])
++      {
++        case 255:  masklen += 8; break;
++        case 254:  masklen += 7; break;
++        case 252:  masklen += 6; break;
++        case 248:  masklen += 5; break;
++        case 240:  masklen += 4; break;
++        case 224:  masklen += 3; break;
++        case 192:  masklen += 2; break;
++        case 128:  masklen += 1; break;
++        default:   masklen += 0; break;
++      }
++      if (ipa->ix[i].ip.d[j] != (ip->d[j] & ipa_mask->ix[i].ip.d[j]))
++        break;
++    }
++    if ( (j == 4) && (masklen > longest_masklen) )
++    {
++      longest_masklen = masklen;
++    }
++  }
++  return longest_masklen;
++}
+ static stralloc buf = {0};
+ 
++#define ipme_init_retclean(ret) { \
++  if (moreipme.ix) alloc_free(moreipme.ix); \
++  if (moreipme_mask.ix) alloc_free(moreipme_mask.ix); \
++  if (buf.s) alloc_free(buf.s); \
++  return ret; }
++   
+ int ipme_init()
+ {
+   struct ifconf ifc;
+@@ -39,23 +81,45 @@
+   struct sockaddr_in *sin;
+   int len;
+   int s;
+-  struct ip_mx ix;
+- 
++  struct ip_mx ix, ix_mask;
++  ipalloc moreipme = {0};
++  ipalloc moreipme_mask = {0};
++  int i;
++
+   if (ipmeok) return 1;
+-  if (!ipalloc_readyplus(&ipme,0)) return 0;
++  if (!ipalloc_readyplus(&ipme,0)) ipme_init_retclean(0);
++  if (!ipalloc_readyplus(&ipme_mask,0)) ipme_init_retclean(0);
++  if (!ipalloc_readyplus(&notipme,0)) ipme_init_retclean(0);
++  if (!ipalloc_readyplus(&notipme_mask,0)) ipme_init_retclean(0);
++  if (!ipalloc_readyplus(&moreipme,0)) ipme_init_retclean(0);
++  if (!ipalloc_readyplus(&moreipme_mask,0)) ipme_init_retclean(0);
++
+   ipme.len = 0;
+-  ix.pref = 0;
+- 
+-  /* 0.0.0.0 is a special address which always refers to 
+-   * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a.
++  ix.pref = ix_mask.pref = 0;
++
++  if (!ipme_readipfile(&notipme, &notipme_mask, "control/notipme")) ipme_init_retclean(0);
++
++  /* 127.0.0.0/255.0.0.0 is the localhost network.  Linux will treat
++     every address in this range as a local interface, even if it
++     isn't explicitly configured.
+   */
++  byte_copy(&ix.ip,4,"\x7f\0\0\0");
++  byte_copy(&ix_mask.ip,4,"\xff\0\0\0");
++  if (!ipalloc_append(&ipme,&ix)) ipme_init_retclean(0);
++  if (!ipalloc_append(&ipme_mask,&ix_mask)) ipme_init_retclean(0);
++
++  /* 0.0.0.0 is a special address which always refers to
++   * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a.  */
+   byte_copy(&ix.ip,4,"\0\0\0\0");
+-  if (!ipalloc_append(&ipme,&ix)) { return 0; }
+-  if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1;
+- 
++  byte_copy(&ix_mask.ip,4,"\xff\xff\xff\xff");
++  if (!ipalloc_append(&ipme,&ix)) ipme_init_retclean(0);
++  if (!ipalloc_append(&ipme_mask,&ix_mask)) ipme_init_retclean(0);
++
++  if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) ipme_init_retclean(-1);
++
+   len = 256;
+   for (;;) {
+-    if (!stralloc_ready(&buf,len)) { close(s); return 0; }
++    if (!stralloc_ready(&buf,len)) { close(s); ipme_init_retclean(0); }
+     buf.len = 0;
+     ifc.ifc_buf = buf.s;
+     ifc.ifc_len = len;
+@@ -64,7 +128,7 @@
+         buf.len = ifc.ifc_len;
+         break;
+       }
+-    if (len > 200000) { close(s); return -1; }
++    if (len > 200000) { close(s);  ipme_init_retclean(-1); }
+     len += 100 + (len >> 2);
+   }
+   x = buf.s;
+@@ -79,7 +143,10 @@
+       byte_copy(&ix.ip,4,&sin->sin_addr);
+       if (ioctl(s,SIOCGIFFLAGS,x) == 0)
+         if (ifr->ifr_flags & IFF_UP)
+-          if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
++        {
++          if (!ipalloc_append(&ipme,&ix)) { close(s);  ipme_init_retclean(0); }
++          if (!ipalloc_append(&ipme_mask,&ix_mask)) { close(s);  ipme_init_retclean(0); }
++        }
+     }
+ #else
+     len = sizeof(*ifr);
+@@ -89,12 +156,60 @@
+ 	  if (ifr->ifr_addr.sa_family == AF_INET) {
+ 	    sin = (struct sockaddr_in *) &ifr->ifr_addr;
+ 	    byte_copy(&ix.ip,4,&sin->sin_addr);
+-	    if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
++            if (!ipalloc_append(&ipme,&ix)) { close(s);  ipme_init_retclean(0); }
++            if (!ipalloc_append(&ipme_mask,&ix_mask)) { close(s);  ipme_init_retclean(0); }
+ 	  }
+ #endif
+     x += len;
+   }
+   close(s);
++
++  if (!ipme_readipfile(&moreipme, &moreipme_mask, "control/moreipme"))  ipme_init_retclean(0);
++  for(i = 0;i < moreipme.len;++i)
++  {
++    if (!ipalloc_append(&ipme,&moreipme.ix[i])) ipme_init_retclean(0);
++    if (!ipalloc_append(&ipme_mask,&moreipme_mask.ix[i])) ipme_init_retclean(0);
++  }
+   ipmeok = 1;
+-  return 1;
++  ipme_init_retclean(1);
+ }
++
++
++int ipme_readipfile(ipa, ipa_mask, fn)
++  ipalloc *ipa, *ipa_mask;
++  char *fn;
++{
++  int fd = -1;
++  char inbuf[1024];
++  substdio ss;
++  stralloc l = {0};
++  int match;
++  struct ip_mx ix, ix_mask;
++  int ret = 1;
++  int slash = 0;
++
++  if ( (fd = open_read(fn)) != -1) {
++    substdio_fdbuf(&ss, read, fd, inbuf, sizeof(inbuf));
++    while ( (getln(&ss,&l,&match,'\n') != -1) && (match || l.len) ) {
++      l.len--;
++      if (!stralloc_0(&l)) { ret = 0; break; }
++      if (l.s[slash=str_chr(l.s,'/')]!='\0')
++      {
++        l.s[slash]='\0';
++        if (!ip_scan(l.s+slash+1,&ix_mask.ip))
++          continue;
++      }
++      else
++        if (!ip_scan("255.255.255.255",&ix_mask.ip)) { ret = 0; break; }
++
++      if (!ip_scan(l.s, &ix.ip)) continue;
++      if (!ipalloc_append(ipa,&ix)) { ret = 0; break; }
++      if (!ipalloc_append(ipa_mask,&ix_mask.ip)) { ret = 0; break; }
++    }
++    if (l.s) alloc_free(l.s);
++    if ( (fd >= 0) && (close(fd) == -1) )
++      ret = 0;
++  }
++  return ret;
++}
++
+diff -ruN ../netqmail-1.06-original/ipme.h netqmail-1.06/ipme.h
+--- ../netqmail-1.06-original/ipme.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/ipme.h	2016-11-22 21:03:57.115527999 +0100
+@@ -4,7 +4,7 @@
+ #include "ip.h"
+ #include "ipalloc.h"
+ 
+-extern ipalloc ipme;
++extern ipalloc ipme, ipme_mask, notipme, notipme_mask;
+ 
+ extern int ipme_init();
+ extern int ipme_is();
+diff -ruN ../netqmail-1.06-original/ipmeprint.c netqmail-1.06/ipmeprint.c
+--- ../netqmail-1.06-original/ipmeprint.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/ipmeprint.c	2016-11-22 21:03:57.115527999 +0100
+@@ -3,12 +3,15 @@
+ #include "ip.h"
+ #include "ipme.h"
+ #include "exit.h"
++#include "auto_qmail.h"
+ 
+ char temp[IPFMT];
+ 
+ void main()
+ {
+- int j;
++ int j,k;
++
++ chdir(auto_qmail);
+  switch(ipme_init())
+   {
+    case 0: substdio_putsflush(subfderr,"out of memory\n"); _exit(111);
+@@ -17,8 +20,18 @@
+  for (j = 0;j < ipme.len;++j)
+   {
+    substdio_put(subfdout,temp,ip_fmt(temp,&ipme.ix[j].ip));
+-   substdio_puts(subfdout,"\n");
++   substdio_puts(subfdout,"/");
++   substdio_put(subfdout,temp,ip_fmt(temp,&ipme_mask.ix[j].ip));
++   substdio_puts(subfdout," is me\n");
++  }
++ for (j = 0;j < notipme.len;++j)
++  {
++   substdio_put(subfdout,temp,ip_fmt(temp,&notipme.ix[j].ip));
++   substdio_puts(subfdout,"/");
++   substdio_put(subfdout,temp,ip_fmt(temp,&notipme_mask.ix[j].ip));
++   substdio_puts(subfdout," is not me\n");
+   }
++
+  substdio_flush(subfdout);
+  _exit(0);
+ }
+diff -ruN ../netqmail-1.06-original/ipmetest.c netqmail-1.06/ipmetest.c
+--- ../netqmail-1.06-original/ipmetest.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/ipmetest.c	2016-11-22 21:03:57.115527999 +0100
+@@ -0,0 +1,38 @@
++#include "subfd.h"
++#include "substdio.h"
++#include "ip.h"
++#include "ipme.h"
++#include "exit.h"
++#include "auto_qmail.h"
++#include "env.h"
++
++void main(int argc, char *argv[])
++{
++  struct ip_address ip;
++
++  if (!env_get("IPMETEST_HERE"))
++    chdir(auto_qmail);
++
++  if (argc < 2)
++  {
++    substdio_puts(subfdout,"invalid usage\n");
++    substdio_flush(subfdout);
++    exit(1);
++  }
++  if (!ip_scan(argv[1],&ip))
++  {
++    substdio_puts(subfdout,"invalid IP address\n");
++    substdio_flush(subfdout);
++    exit(1);
++  }
++  if (ipme_is(&ip))
++  {
++    substdio_puts(subfdout,"me\n");
++  }
++  else
++  {
++    substdio_puts(subfdout,"not me\n");
++  }
++  substdio_flush(subfdout);
++  exit(0);
++}
+diff -ruN ../netqmail-1.06-original/macros.h netqmail-1.06/macros.h
+--- ../netqmail-1.06-original/macros.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/macros.h	2016-11-22 21:03:57.115527999 +0100
+@@ -0,0 +1,25 @@
++/*
++ * $Log: macros.h,v $
++ * Revision 1.1  2009-03-21 08:50:25+05:30  Cprogrammer
++ * Initial revision
++ *
++ *
++ * macros.h:  Useful macros
++ *
++ * Author:
++ *  Dick Porter (dick@ximian.com)
++ *
++ * (C) 2002 Ximian, Inc.
++ */
++
++#ifndef _WAPI_MACROS_H_
++#define _WAPI_MACROS_H_
++
++#include <sys/types.h>
++
++#define MAKEWORD(low, high) ((__uint16_t)(((__uint8_t)(low)) | \
++				       ((__uint16_t)((__uint8_t)(high))) << 8))
++#define LOBYTE(i16) ((__uint8_t)((i16) & 0xFF))
++#define HIBYTE(i16) ((__uint8_t)(((__uint16_t)(i16) >> 8) & 0xFF))
++
++#endif							/* _WAPI_MACROS_H_ */
+diff -ruN ../netqmail-1.06-original/maildirflags.c netqmail-1.06/maildirflags.c
+--- ../netqmail-1.06-original/maildirflags.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirflags.c	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/maildirgetquota.c netqmail-1.06/maildirgetquota.c
+--- ../netqmail-1.06-original/maildirgetquota.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirgetquota.c	2016-11-22 21:03:57.116527965 +0100
+@@ -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 -ruN ../netqmail-1.06-original/maildirgetquota.h netqmail-1.06/maildirgetquota.h
+--- ../netqmail-1.06-original/maildirgetquota.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirgetquota.h	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins Exp $";
++
++#define	QUOTABUFSIZE	256
++
++int maildir_getquota(const char *, char [QUOTABUFSIZE]);
++
++#ifdef  __cplusplus
++}
++#endif
++
++#endif
+diff -ruN ../netqmail-1.06-original/maildirmisc.h netqmail-1.06/maildirmisc.h
+--- ../netqmail-1.06-original/maildirmisc.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirmisc.h	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/maildiropen.c netqmail-1.06/maildiropen.c
+--- ../netqmail-1.06-original/maildiropen.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildiropen.c	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/maildirparsequota.c netqmail-1.06/maildirparsequota.c
+--- ../netqmail-1.06-original/maildirparsequota.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirparsequota.c	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/maildirquota.c netqmail-1.06/maildirquota.c
+--- ../netqmail-1.06-original/maildirquota.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirquota.c	2016-11-22 21:03:57.116527965 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/maildirquota.h netqmail-1.06/maildirquota.h
+--- ../netqmail-1.06-original/maildirquota.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/maildirquota.h	2016-11-22 21:03:57.117527932 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/md5.h netqmail-1.06/md5.h
+--- ../netqmail-1.06-original/md5.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/md5.h	2016-11-22 21:03:57.117527932 +0100
+@@ -0,0 +1,49 @@
++/* MD5.H - header file for MD5C.C
++ */
++
++/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
++   rights reserved.
++
++   License to copy and use this software is granted provided that it
++   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
++   Algorithm" in all material mentioning or referencing this software
++   or this function.
++
++   License is also granted to make and use derivative works provided
++   that such works are identified as "derived from the RSA Data
++   Security, Inc. MD5 Message-Digest Algorithm" in all material
++   mentioning or referencing the derived work.  
++                                                                    
++   RSA Data Security, Inc. makes no representations concerning either
++   the merchantability of this software or the suitability of this
++   software for any particular purpose. It is provided "as is"
++   without express or implied warranty of any kind.  
++                                                                    
++   These notices must be retained in any copies of any part of this
++   documentation and/or software.  
++ */
++
++#ifndef _MD5_H_
++#define _MD5_H_ 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* MD5 context. */
++typedef struct {
++  UINT4 state[4];                                   /* state (ABCD) */
++  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
++  unsigned char buffer[64];                         /* input buffer */
++} MD5_CTX;
++
++void MD5Init PROTO_LIST ((MD5_CTX *));
++void MD5Update PROTO_LIST
++  ((MD5_CTX *, unsigned char *, unsigned int));
++void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff -ruN ../netqmail-1.06-original/md5c.c netqmail-1.06/md5c.c
+--- ../netqmail-1.06-original/md5c.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/md5c.c	2016-11-22 21:03:57.117527932 +0100
+@@ -0,0 +1,334 @@
++/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
++ */
++
++/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
++   rights reserved.
++
++   License to copy and use this software is granted provided that it
++   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
++   Algorithm" in all material mentioning or referencing this software
++   or this function.
++
++   License is also granted to make and use derivative works provided
++   that such works are identified as "derived from the RSA Data
++   Security, Inc. MD5 Message-Digest Algorithm" in all material
++   mentioning or referencing the derived work.  
++                                                                    
++   RSA Data Security, Inc. makes no representations concerning either
++   the merchantability of this software or the suitability of this
++   software for any particular purpose. It is provided "as is"
++   without express or implied warranty of any kind.  
++                                                                    
++   These notices must be retained in any copies of any part of this
++   documentation and/or software.  
++ */
++
++#include "global.h"
++#include "md5.h"
++
++/* Constants for MD5Transform routine.
++ */
++#define S11 7
++#define S12 12
++#define S13 17
++#define S14 22
++#define S21 5
++#define S22 9
++#define S23 14
++#define S24 20
++#define S31 4
++#define S32 11
++#define S33 16
++#define S34 23
++#define S41 6
++#define S42 10
++#define S43 15
++#define S44 21
++
++static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
++static void Encode PROTO_LIST
++  ((unsigned char *, UINT4 *, unsigned int));
++static void Decode PROTO_LIST
++  ((UINT4 *, unsigned char *, unsigned int));
++static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
++static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
++
++static unsigned char PADDING[64] = {
++  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
++};
++
++/* F, G, H and I are basic MD5 functions.
++ */
++#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
++#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
++#define H(x, y, z) ((x) ^ (y) ^ (z))
++#define I(x, y, z) ((y) ^ ((x) | (~z)))
++
++/* ROTATE_LEFT rotates x left n bits.
++ */
++#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
++
++/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
++   Rotation is separate from addition to prevent recomputation.
++ */
++#define FF(a, b, c, d, x, s, ac) { \
++    (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
++    (a) = ROTATE_LEFT ((a), (s)); \
++    (a) += (b); \
++  }
++#define GG(a, b, c, d, x, s, ac) { \
++    (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
++    (a) = ROTATE_LEFT ((a), (s)); \
++    (a) += (b); \
++  }
++#define HH(a, b, c, d, x, s, ac) { \
++    (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
++    (a) = ROTATE_LEFT ((a), (s)); \
++    (a) += (b); \
++  }
++#define II(a, b, c, d, x, s, ac) { \
++    (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
++    (a) = ROTATE_LEFT ((a), (s)); \
++    (a) += (b); \
++  }
++
++/* MD5 initialization. Begins an MD5 operation, writing a new context.
++ */
++void MD5Init (context)
++MD5_CTX *context;                                        /* context */
++{
++  context->count[0] = context->count[1] = 0;
++
++  /* Load magic initialization constants.
++   */
++  context->state[0] = 0x67452301;
++  context->state[1] = 0xefcdab89;
++  context->state[2] = 0x98badcfe;
++  context->state[3] = 0x10325476;
++}
++
++/* MD5 block update operation. Continues an MD5 message-digest
++     operation, processing another message block, and updating the
++     context.
++ */
++void MD5Update (context, input, inputLen)
++MD5_CTX *context;                                        /* context */
++unsigned char *input;                                /* input block */
++unsigned int inputLen;                     /* length of input block */
++{
++  unsigned int i, index, partLen;
++
++  /* Compute number of bytes mod 64 */
++  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
++
++  /* Update number of bits */
++  if ((context->count[0] += ((UINT4)inputLen << 3))
++      < ((UINT4)inputLen << 3))
++    context->count[1]++;
++  context->count[1] += ((UINT4)inputLen >> 29);
++  
++  partLen = 64 - index;
++  
++  /* Transform as many times as possible.
++   */
++  if (inputLen >= partLen) {
++    MD5_memcpy
++      ((POINTER)&context->buffer[index], (POINTER)input, partLen);
++    MD5Transform (context->state, context->buffer);
++  
++    for (i = partLen; i + 63 < inputLen; i += 64)
++      MD5Transform (context->state, &input[i]);
++    
++    index = 0;
++  }
++  else
++    i = 0;
++  
++  /* Buffer remaining input */
++  MD5_memcpy 
++    ((POINTER)&context->buffer[index], (POINTER)&input[i],
++     inputLen-i);
++}
++
++/* MD5 finalization. Ends an MD5 message-digest operation, writing the
++     the message digest and zeroizing the context.
++ */
++void MD5Final (digest, context)
++unsigned char digest[16];                         /* message digest */
++MD5_CTX *context;                                       /* context */
++{
++  unsigned char bits[8];
++  unsigned int index, padLen;
++
++  /* Save number of bits */
++  Encode (bits, context->count, 8);
++
++  /* Pad out to 56 mod 64.
++   */
++  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
++  padLen = (index < 56) ? (56 - index) : (120 - index);
++  MD5Update (context, PADDING, padLen);
++  
++  /* Append length (before padding) */
++  MD5Update (context, bits, 8);
++
++  /* Store state in digest */
++  Encode (digest, context->state, 16);
++  
++  /* Zeroize sensitive information.
++   */
++  MD5_memset ((POINTER)context, 0, sizeof (*context));
++}
++
++/* MD5 basic transformation. Transforms state based on block.
++ */
++static void MD5Transform (state, block)
++UINT4 state[4];
++unsigned char block[64];
++{
++  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
++  
++  Decode (x, block, 64);
++
++  /* Round 1 */
++  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
++  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
++  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
++  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
++  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
++  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
++  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
++  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
++  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
++  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
++  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
++  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
++  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
++  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
++  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
++  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
++
++  /* Round 2 */
++  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
++  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
++  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
++  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
++  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
++  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
++  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
++  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
++  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
++  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
++  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
++  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
++  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
++  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
++  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
++  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
++
++  /* Round 3 */
++  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
++  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
++  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
++  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
++  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
++  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
++  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
++  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
++  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
++  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
++  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
++  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
++  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
++  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
++  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
++  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
++
++  /* Round 4 */
++  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
++  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
++  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
++  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
++  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
++  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
++  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
++  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
++  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
++  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
++  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
++  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
++  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
++  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
++  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
++  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
++
++  state[0] += a;
++  state[1] += b;
++  state[2] += c;
++  state[3] += d;
++  
++  /* Zeroize sensitive information.
++   */
++  MD5_memset ((POINTER)x, 0, sizeof (x));
++}
++
++/* Encodes input (UINT4) into output (unsigned char). Assumes len is
++     a multiple of 4.
++ */
++static void Encode (output, input, len)
++unsigned char *output;
++UINT4 *input;
++unsigned int len;
++{
++  unsigned int i, j;
++
++  for (i = 0, j = 0; j < len; i++, j += 4) {
++    output[j] = (unsigned char)(input[i] & 0xff);
++    output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
++    output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
++    output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
++  }
++}
++
++/* Decodes input (unsigned char) into output (UINT4). Assumes len is
++     a multiple of 4.
++ */
++static void Decode (output, input, len)
++UINT4 *output;
++unsigned char *input;
++unsigned int len;
++{
++  unsigned int i, j;
++
++  for (i = 0, j = 0; j < len; i++, j += 4)
++    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
++      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
++}
++
++/* Note: Replace "for loop" with standard memcpy if possible.
++ */
++static void MD5_memcpy (output, input, len)
++POINTER output;
++POINTER input;
++unsigned int len;
++{
++  unsigned int i;
++  
++  for (i = 0; i < len; i++)
++    output[i] = input[i];
++}
++
++/* Note: Replace "for loop" with standard memset if possible.
++ */
++static void MD5_memset (output, value, len)
++POINTER output;
++int value;
++unsigned int len;
++{
++  unsigned int i;
++  
++  for (i = 0; i < len; i++)
++    ((char *)output)[i] = (char)value;
++}
+diff -ruN ../netqmail-1.06-original/mess822.h netqmail-1.06/mess822.h
+--- ../netqmail-1.06-original/mess822.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/mess822.h	2016-11-22 21:03:57.117527932 +0100
+@@ -0,0 +1,55 @@
++/*
++ * $Log: mess822.h,v $
++ * Revision 1.3  2004-10-11 13:55:55+05:30  Cprogrammer
++ * added function prototypes
++ *
++ * Revision 1.2  2004-06-18 23:00:58+05:30  Cprogrammer
++ * added RCS log
++ *
++ */
++#ifndef MESS822_H
++#define MESS822_H
++#include "stralloc.h"
++#include "caltime.h"
++
++#define MESS822_HEADER { {0} }
++
++typedef struct
++{
++	struct caltime  ct;
++	int             known; /*- 0 for ct uninitialized; 1 if ok; 2 if ok and right zone */
++}
++mess822_time;
++
++typedef struct
++{
++	char           *name; /*- 0 means all names */
++	int            *flag;
++	stralloc       *copy;
++	stralloc       *value;
++	stralloc       *addr;
++	mess822_time   *when;
++}
++mess822_action;
++
++typedef struct
++{
++	stralloc        inprogress;
++	mess822_action *action;
++}
++mess822_header;
++
++int             mess822_quoteplus(stralloc *, char *, char *);
++int             mess822_quote(stralloc *, char *, char *);
++int             mess822_quotelist(stralloc *, stralloc *);
++int             mess822_fold(stralloc *, stralloc *, char *, int);
++int             mess822_date(stralloc *, mess822_time *);
++int             mess822_token(stralloc *, char *);
++int             mess822_addrlist(stralloc *, char *);
++int             mess822_when(mess822_time *, char *);
++int             mess822_begin(mess822_header *, mess822_action *);
++int             mess822_line(mess822_header *, stralloc *);
++int             mess822_end(mess822_header *);
++int             mess822_ok(stralloc *);
++
++#endif
+diff -ruN ../netqmail-1.06-original/mess822_ok.c netqmail-1.06/mess822_ok.c
+--- ../netqmail-1.06-original/mess822_ok.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/mess822_ok.c	2016-11-22 21:03:57.117527932 +0100
+@@ -0,0 +1,55 @@
++/*
++ * $Log: mess822_ok.c,v $
++ * Revision 1.2  2004-10-22 20:27:30+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.1  2004-01-04 23:17:51+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include "mess822.h"
++#include "byte.h"
++
++int
++mess822_ok(sa)
++	stralloc       *sa;
++{
++	int             i;
++	int             len;
++	int             colon;
++
++	len = sa->len;
++	if (len && (sa->s[len - 1] == '\n'))
++		--len;
++	if (!len)
++		return 0;
++	/*
++	 * if input message is 822-compliant, will return 1 after this 
++	 */
++	if (sa->s[0] == ' ')
++		return 1;
++	if (sa->s[0] == '\t')
++		return 1;
++	colon = byte_chr(sa->s, sa->len, ':');
++	if (colon >= sa->len)
++		return 0;
++	while (colon && ((sa->s[colon - 1] == ' ') || (sa->s[colon - 1] == '\t')))
++		--colon;
++	if (!colon)
++		return 0;
++	for (i = 0; i < colon; ++i)
++		if (sa->s[i] < 33)
++			return 0;
++	for (i = 0; i < colon; ++i)
++		if (sa->s[i] > 126)
++			return 0;
++	return 1;
++}
++
++void
++getversion_mess822_ok_c()
++{
++	static char    *x = "$Id: mess822_ok.c,v 1.2 2004-10-22 20:27:30+05:30 Cprogrammer Stab mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/numlib.h netqmail-1.06/numlib.h
+--- ../netqmail-1.06-original/numlib.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/numlib.h	2016-11-22 21:03:57.117527932 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/overmaildirquota.c netqmail-1.06/overmaildirquota.c
+--- ../netqmail-1.06-original/overmaildirquota.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/overmaildirquota.c	2016-11-22 21:03:57.117527932 +0100
+@@ -0,0 +1,41 @@
++/*
++** 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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/policy.c netqmail-1.06/policy.c
+--- ../netqmail-1.06-original/policy.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/policy.c	2016-11-22 21:03:57.118527899 +0100
+@@ -0,0 +1,1210 @@
++/*
++ * Copyright (C) 2005 Inter7 Internet Technologies, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
++ *
++ * <matt@inter7.com>
++ * eMail Messaging Policy Framework
++ * http://www.inter7.com/?page=empf
++ *
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <errno.h>
++#ifndef _GNU_SOURCE
++   #define _GNU_SOURCE
++#endif
++#ifndef FNM_CASEFOLD
++   #include <ctype.h>
++#endif
++#include <fnmatch.h>
++#include "stralloc.h"
++#include "rcpthosts.h"
++#include "policy.h"
++
++/*
++   Policy delivery flags
++*/
++
++#define POLICY_F_NONE 0
++#define POLICY_F_ALLOW 1		/* Allow this delivery type   */
++#define POLICY_F_DISALLOW 2		/* Do not allow this delivery */
++#define POLICY_F_LOCAL 4		/* Local -> local delivery    */
++#define POLICY_F_REMOTE 8		/* Local -> remote delivery   */
++#define POLICY_F_EXTERNAL 16	/* Remote -> local delivery   */
++#define POLICY_F_INTERNAL 32    /* Local -> local delivery    */
++
++/*
++   Policy
++*/
++
++typedef struct __policy_ {
++   int flags,				/* Allow or disallow */
++	   numargs;				/* Arguments read    */
++   char **args;				/* Argument array    */
++
++   struct __policy_ *next;
++} policy_t;
++
++/*
++   Local delivery name
++*/
++
++typedef struct __local_ {
++   char *local;						/* Local name */
++   policy_t *policy;				/* Policy	  */
++
++   struct __local_ *next;
++} local_t;
++
++/*
++   Domain name
++*/
++
++typedef struct __domain_ {
++   char *domain;					/* Domain name */
++   policy_t *policy;				/* Policy	   */
++   local_t *locals;					/* Locals      */
++
++   struct __domain_ *next;
++} domain_t;
++
++extern char *remoteinfo;
++extern stralloc mailfrom;
++extern stralloc addr;
++extern void out(char *);
++
++static int policy_load(const char *);
++static int policy_parse(const char *, char *);
++static policy_t *policy_construct(char *);
++static int policy_construct_parse_arguments(char **, const int, char *);
++static int policy_match(const char *, const char *);
++static int policy_applies_to(const policy_t *, const char *);
++static int policy_flags(const char);
++static policy_t *policy_find(const policy_t *, const int);
++static int policy_forbids(void);
++static domain_t *domain_find(const char *);
++static local_t *local_find(const domain_t *, const char *);
++static void policy_free(policy_t *);
++static void local_free(local_t *);
++static void domains_free(void);
++
++static domain_t *domains = NULL, *s_domain = NULL, *r_domain = NULL;
++
++/*
++   Check policy for delivery restrictions
++*/
++
++int policy_check(void)
++{
++   int ret = 0;
++   const char *p = NULL;
++   
++   s_domain = r_domain = NULL;
++
++#ifdef POLICY_DEALLOCATE
++   domains_free();
++#endif
++
++   if (remoteinfo)
++	  p = remoteinfo;
++   else
++	  p = mailfrom.s;
++
++   fprintf(stderr, "policy_check: %s %s -> %s %s (%s)\n", 
++		 rcpthosts(p, strlen(p)) ? "local" : "remote", p, 
++		 rcpthosts(addr.s, strlen(addr.s)) ? "local" : "remote", addr.s,
++		 remoteinfo ? "AUTHENTICATED SENDER" : "UNAUTHENTICATED SENDER");
++
++   /*
++	  Load sender-related policy
++   */
++
++   for (; ((p) && (*p)); p++) {
++	  if (*p == '@')
++		 break;
++   }
++
++   if (*p) {
++	  if (rcpthosts(remoteinfo ? remoteinfo : mailfrom.s,
++			   remoteinfo ? strlen(remoteinfo) : strlen(mailfrom.s))) {
++		 ret = policy_load(p + 1);
++		 if (!ret) {
++			fprintf(stderr, "policy_check: policy_load failed\n");
++			return -1;
++		 }
++
++		 s_domain = domain_find(p + 1);
++
++#ifdef POLICY_ENFORCE_AUTHENTICATION
++		 /*
++		    This check is done here in the event that there is
++			no policy for a domain.  In that event, we do not
++			wish to enforce policy rules
++		 */
++
++		 if ((s_domain) && (remoteinfo == NULL)) {
++			fprintf(stderr, "policy_check: sender not authenticated\n");
++			return 0;
++		 }
++#endif
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "policy_check: %s is not local\n", p + 1);
++#endif
++   }
++
++   /*
++	  Load recipient-related policy
++   */
++
++   for (p = addr.s; ((p) && (*p)); p++) {
++	  if (*p == '@')
++		 break;
++   }
++
++   if (*p) {
++	  if (rcpthosts(addr.s, strlen(addr.s))) {
++		 ret = policy_load(p + 1);
++		 if (!ret) {
++			fprintf(stderr, "policy_check: policy_load failed\n");
++			return -1;
++		 }
++
++		 r_domain = domain_find(p + 1);
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "policy_check: %s is not local\n", p + 1);
++#endif
++   }
++
++   /*
++	  Policy enforcement
++   */
++
++   ret = policy_forbids();
++   if (ret == 1) {
++	  fprintf(stderr, "policy_check: policy forbids transmission\n");
++	  return 0;
++   }
++
++   else if (ret == 0) {
++	  fprintf(stderr, "policy_check: policy allows transmission\n");
++	  return 1;
++   }
++
++   fprintf(stderr, "policy_check: policy_forbids failed\n");
++   return -1;
++}
++
++/*
++   Load policy from policy file
++*/
++
++static int policy_load(const char *domain)
++{
++   size_t line = 0;
++   FILE *stream = NULL;
++   char b[4096] = { 0 };
++   int locald = 0, ret = 0;
++
++   if (domain == NULL)
++	  return 1;
++
++   /*
++	  See if we've already loaded this policy
++   */
++
++   if (domain_find(domain)) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_load(%s): already loaded\n", domain);
++#endif
++	  return 1;
++   }
++
++   stream = fopen(POLICY_FILENAME, "r");
++
++   /*
++	  If policy file doesnt exist, allow all messaging
++	  Otherwise trigger error
++   */
++
++   if (stream == NULL) {
++	  if (errno != ENOENT) {
++		 fprintf(stderr, "policy_load(%s): cannot read policy\n", domain);
++		 return 0;
++	  }
++
++#ifdef DEBUG
++	  fprintf(stderr, "policy_load(%s): no policy\n", domain);
++#endif
++	  return 1;
++   }
++
++   /*
++	  Run through policy line-by-line
++   */
++
++   line = 1;
++
++   while(!(feof(stream))) {
++	  memset(b, 0, sizeof(b));
++	  fgets(b, sizeof(b), stream);
++
++	  if ((*b == '#') || (*b == ';') || (*b == '\r') || (*b == '\n') || (*b == '\0'))
++		 continue;
++
++	  ret = policy_parse(domain, b);
++	  if (ret == -1) {
++		 fprintf(stderr, "policy_load(%s): policy_parse failed (line %d)\n", domain, line);
++		 fclose(stream);
++		 return 0;
++	  }
++
++	  else if (ret == 1)
++		 break;
++
++	  line++;
++   }
++
++   fclose(stream);
++
++#ifdef DEBUG
++   fprintf(stderr, "policy_load(%s): loaded\n", domain);
++#endif
++
++   return 1;
++}
++
++/*
++   Parse policy data
++*/
++
++static int policy_parse(const char *domain, char *data)
++{
++   int ia = 0;
++   domain_t *d = NULL;
++   policy_t *p = NULL, *lp = NULL;
++   local_t *l_list = NULL, *l = NULL;
++   char *h = NULL, *t = NULL, *pp = NULL;
++
++   if ((domain == NULL) || (data == NULL))
++	  return -1;
++
++   /*
++	  Seperate out domain part
++   */
++
++   for (h = t = data; *h; h++) {
++	  if (*h == ':')
++		 break;
++   }
++
++   if (*h != ':') {
++	  fprintf(stderr, "policy_parse: syntax error: no domain seperator\n");
++	  return -1;
++   }
++
++   *h = '\0';
++
++   /*
++	  Determine if this is the correct policy
++   */
++
++   if (strcasecmp(domain, t)) 
++	  return 0;
++
++   /*
++	  Seperate domain policy
++   */
++
++   for (ia = 0, t = ++h; *h; h++) {
++	  if ((*h == '(') && (ia == 0))
++		 ia = 1;
++
++	  else if ((*h == ')') && (ia == 1))
++		 ia = 0;
++
++	  else if ((*h == ',') && (ia == 0))
++		 break;
++   }
++
++   if (*h != ',') {
++	  fprintf(stderr, "policy_parse: syntax error: no domain policy seperator\n");
++	  return -1; 
++   }
++
++   *h = '\0';
++
++   p = policy_construct(t);
++   if (p == NULL) {
++	  fprintf(stderr, "policy_parse: policy_construct failed\n");
++	  return -1;
++   }
++
++   /*
++	  Parse locals
++   */
++
++   h++;
++   l_list = l = NULL;
++
++   while(*h) {
++	  if ((*h == '\n') || (*h == '\r'))
++		 break;
++
++	  for (ia = 0, t = h; *h; h++) {
++		 if ((*h == '(') && (ia == 0))
++			ia = 1;
++
++		 else if ((*h == ')') && (ia == 1))
++			ia = 0;
++
++		 else if ((*h == ',') && (ia == 0))
++			break;
++	  }
++
++	  if (*h != ',') {
++		 policy_free(p);
++		 fprintf(stderr, "policy_parse: syntax error: no local policy seperator\n");
++		 return -1; 
++	  }
++
++	  *h = '\0';
++
++	  /*
++	     Seperate local name from local policy 
++	  */
++
++	  for (pp = t; *pp; pp++) {
++		 if (*pp == ':')
++			break;
++	  }
++
++	  if (*pp != ':') {
++		 policy_free(p);
++		 fprintf(stderr, "policy_parse: syntax error: no local name, policy seperator\n");
++		 return -1;
++	  }
++
++	  *pp++ = '\0';
++
++	  if (!(*t)) {
++		 policy_free(p);
++		 fprintf(stderr, "policy_parse: syntax error: empty local name\n");
++		 return -1;
++	  }
++
++	  if ((!(*pp)) || (*pp == ',')) {
++		 policy_free(p);
++		 fprintf(stderr, "policy_parse: syntax error: empty local policy\n");
++		 return -1;
++	  }
++
++	  /*
++	     Load local policy
++	  */
++
++	  lp = policy_construct(pp);
++	  if (lp == NULL) {
++		 policy_free(p);
++		 fprintf(stderr, "policy_parse: policy_construct failed\n");
++		 return -1;
++	  }
++
++	  l = (local_t *)malloc(sizeof(local_t));
++	  if (l == NULL) {
++		 policy_free(p);
++		 policy_free(lp);
++		 fprintf(stderr, "policy_parse: malloc failed\n");
++		 return -1;
++	  }
++
++	  memset(l, 0, sizeof(local_t));
++
++	  ia = strlen(t);
++
++	  l->local = (char *)malloc(ia + 1 + strlen(domain) + 1);
++	  if (l->local == NULL) {
++		 policy_free(p);
++		 policy_free(lp);
++		 free(l);
++		 fprintf(stderr, "policy_parse: malloc failed\n");
++		 return -1;
++	  }
++
++	  memset(l->local, 0, ia + 1 + strlen(domain) + 1);
++	  memcpy(l->local, t, ia);
++	  memcpy(l->local + ia, "@", 1);
++	  memcpy(l->local + ia + 1, domain, strlen(domain));
++
++	  l->policy = lp;
++	  l->next = NULL;
++
++	  l->next = l_list;
++	  l_list = l;
++
++	  t = ++h;
++   }
++
++   /*
++	  Allocate and fill domain structure
++   */
++
++   d = (domain_t *)malloc(sizeof(domain_t));
++   if (d == NULL) {
++	  policy_free(p);
++	  local_free(l_list);
++	  fprintf(stderr, "policy_parse: malloc failed\n");
++	  return -1;
++   }
++
++   memset(d, 0, sizeof(domain_t));
++
++   ia = strlen(domain);
++
++   d->domain = (char *)malloc(ia + 1);
++   if (d->domain == NULL) {
++	  policy_free(p);
++	  local_free(l_list);
++	  free(d);
++	  fprintf(stderr, "policy_parse: malloc failed\n");
++	  return -1;
++   }
++
++   memset(d->domain, 0, ia + 1);
++   memcpy(d->domain, domain, ia);
++
++   d->locals = l_list;
++   d->policy = p;
++
++   d->next = domains;
++   domains = d;
++
++   return 1;
++}
++
++/*
++   Parse policy data into a policy structure
++*/
++
++static policy_t *policy_construct(char *data)
++{
++   char pc = 0, **args = NULL;
++   policy_t *p_list = NULL, *p = NULL;
++   char *h = NULL, *t = NULL, *hp = NULL;
++   int flags = POLICY_F_NONE, numargs = 0, i = 0, ret = 0;
++
++   if (data == NULL)
++	  return 0;
++
++   pc = 0;
++
++   for (h = data; *h; h++) {
++	  pc = *h;
++
++	  flags = policy_flags(*h);
++	  if (flags == POLICY_F_NONE) {
++		 fprintf(stderr, "policy_construct: unknown identifier\n");
++		 return NULL;
++	  }
++
++	  args = NULL;
++
++	  /*
++	     Count, parse and allocate addresses
++	  */
++
++	  if (*(h + 1) == '(') {
++		 t = (h + 2);
++
++		 for (h += 2; *h; h++) {
++			if (*h == ')')
++			   break;
++		 }
++
++		 if (*h != ')') {
++			fprintf(stderr, "policy_construct: no terminating ')'\n");
++			return 0;
++		 }
++
++		 numargs = 1;
++
++		 for (hp = t; hp < h; hp++) {
++			if (*hp == ',') 
++			   numargs++;
++		 }
++
++		 /*
++		    No arguments
++		 */
++
++		 if (hp == t) {
++			fprintf(stderr, "policy_construct: empty argument\n");
++			return NULL;
++		 }
++
++		 args = (char **)malloc(sizeof(char *) * numargs);
++		 if (args == NULL) {
++			fprintf(stderr, "policy_construct: malloc failed\n");
++			return NULL;
++		 }
++
++		 for (i = 0; i < numargs; i++)
++			args[i] = NULL;
++
++		 *h = '\0';
++
++		 ret = policy_construct_parse_arguments(args, numargs, t);
++		 if (!ret) {
++			fprintf(stderr, "policy_construct: policy_construct_parse_arguments failed\n");
++			free(args);
++			return NULL;
++		 }
++	  }
++
++	  /*
++	     Allocate policy structure,
++		 add to linked list
++	  */
++
++	  p = (policy_t *)malloc(sizeof(policy_t));
++	  if (p == NULL) {
++		 for (i = 0; i < numargs; i++)
++			free(args[i]);
++
++		 free(args);
++
++		 fprintf(stderr, "policy_construct: malloc failed\n");
++		 return NULL;
++	  }
++
++	  memset(p, 0, sizeof(policy_t));
++
++	  p->numargs = numargs;
++	  p->args = args;
++	  p->flags = flags;
++	  p->next = NULL;
++
++	  p->next = p_list;
++	  p_list = p;
++   }
++
++   return p_list;
++}
++
++/*
++   Parse policy arguments,
++   fill array
++*/
++
++static int policy_construct_parse_arguments(char **args, const int numargs, char *data)
++{
++   int len = 0, i = 0;
++   char *h = NULL, *t = NULL;
++
++   i = 0;
++
++   for (i = 0, h = t = data;;h++) {
++	 if ((*h == ',') || (*h == '\0')) {
++		len = (h - t);
++
++		 if (*h == '\0')
++			h = NULL;
++		 else
++			*h = '\0';
++
++		 if (!(*t)) {
++			for (; i >= 0; i--)
++			   free(args[i]);
++
++			fprintf(stderr, "policy_construct_parse_arguments: empty argument value\n");
++			return 0;
++		 }
++
++		 if (i >= numargs) {
++			for (; i >= 0; i--)
++			   free(args[i]);
++
++			fprintf(stderr, "policy_construct_parse_arguments: too many arguments\n");
++			return 0;
++		 }
++
++		 args[i] = (char *)malloc(len + 1);
++		 if (args[i] == NULL) {
++			for (; i >= 0; i--)
++			   free(args[i]);
++
++			fprintf(stderr, "policy_construct_parse_arguments: malloc failed\n");
++			return 0;
++		 }
++
++		 memset(args[i], 0, len + 1);
++		 memcpy(args[i], t, len);
++
++		 i++;
++
++		 if (!h) 
++			break;
++
++		 t = (h + 1);
++	  }
++   }
++
++   if (i != numargs) {
++	  fprintf(stderr, "policy_construct_parse_arguments: post argument count failed (%d/%d)\n",
++			i, numargs);
++
++	  for (; i >= 0; i--)
++		 free(args[i]);
++
++	  return 0;
++   }
++
++   return 1;
++}
++
++/*
++   Match a filter against an address string
++*/
++
++static int policy_match(const char *filter, const char *address)
++{
++   int ret = 0;
++
++   if ((filter == NULL) || (address == NULL))
++	  return 0;
++
++#ifndef FNM_CASEFOLD
++   int len = 0, flags = 0;
++   char filt[POLICY_MAX_FILTER] = { 0 }, addr[POLICY_MAX_ADDRESS] = { 0 },
++		*p = NULL;
++
++   memset(filt, 0, sizeof(filt));
++
++   len = strlen(filter);
++   if (len >= POLICY_MAX_FILTER)
++	  len = (POLICY_MAX_FILTER - 1);
++
++   memcpy(filt, filter, len);
++   
++   for (p = filt; *p; p++)
++	  *p = tolower(*p);
++   
++   memset(addr, 0, sizeof(addr));
++
++   len = strlen(address);
++   if (len >= POLICY_MAX_ADDRESS)
++	  len = (POLICY_MAX_ADDRESS - 1);
++
++   memcpy(addr, address, len);
++   
++   for (p = addr; *p; p++)
++	  *p = tolower(*p);
++
++   filter = filt;
++   address = addr;
++#else
++   int flags = FNM_CASEFOLD;
++#endif
++   
++   ret = fnmatch(filter, address, flags);
++   if (ret == 0)
++	  return 1;
++
++   return 0;
++}
++
++/*
++   See if a given policy applies to a particular
++   address
++*/
++
++static int policy_applies_to(const policy_t *p, const char *addr)
++{
++   int i = 0;
++
++   if ((p == NULL) || (addr == NULL))
++	  return 0;
++
++   if (p->numargs == 0) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_applies_to: no arguments (yes)\n");
++#endif
++	  return 1;
++   }
++
++   if (p->args == NULL) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_applies_to: broken arguments (no)\n");
++#endif
++	  return 0;
++   }
++
++   for (i = 0; i < p->numargs; i++) {
++	  if (policy_match(p->args[i], addr)) {
++#ifdef DEBUG
++		 fprintf(stderr, "policy_applies_to: match (yes)\n");
++#endif
++		 return 1;
++	  }
++   }
++
++#ifdef DEBUG
++   fprintf(stderr, "policy_applies_to: no match (no)\n");
++#endif
++   return 0;
++}
++
++/*
++   Return flags for policy identifier
++*/
++
++static int policy_flags(const char c)
++{
++   int flags = POLICY_F_NONE;
++
++   switch(c) {
++	  case 'l':
++		 flags = (POLICY_F_LOCAL|POLICY_F_DISALLOW);
++		 break;
++
++	  case 'r':
++		 flags = (POLICY_F_REMOTE|POLICY_F_DISALLOW);
++		 break;
++
++	  case 'e':
++		 flags = (POLICY_F_EXTERNAL|POLICY_F_DISALLOW);
++		 break;
++
++	  case 'i':
++		 flags = (POLICY_F_INTERNAL|POLICY_F_DISALLOW);
++		 break;
++
++	  case 'L':
++		 flags = (POLICY_F_LOCAL|POLICY_F_ALLOW);
++		 break;
++
++	  case 'R':
++		 flags = (POLICY_F_REMOTE|POLICY_F_ALLOW);
++		 break;
++
++	  case 'E':
++		 flags = (POLICY_F_EXTERNAL|POLICY_F_ALLOW);
++		 break;
++
++	  case 'I':
++		 flags = (POLICY_F_INTERNAL|POLICY_F_ALLOW);
++		 break;
++   
++	  default:
++		 break;
++   };
++
++   return flags;
++}
++
++/*
++   Find a policy definition
++*/
++
++static policy_t *policy_find(const policy_t *sp, const int flag)
++{
++   for (; sp; sp = sp->next) {
++	  if (sp->flags & flag)
++		 return (policy_t *)sp;
++   }
++
++   return NULL;
++}
++
++/*
++   Compare policies and determine
++   if messaging is forbidden
++*/
++
++static int policy_forbids(void)
++{
++   policy_t *pl = NULL, *p = NULL;
++   local_t *s_local = NULL, *r_local = NULL;
++   int dtype = 0, s_forbid = 0, r_forbid = 0;
++
++   /*
++	  Find local policy if any
++   */
++
++   if (s_domain) 
++	  s_local = local_find(s_domain, remoteinfo ? remoteinfo : mailfrom.s);
++
++   if (r_domain)
++	  r_local = local_find(r_domain, addr.s);
++
++   /*
++	  Determine type of delivery
++	  (local, remote, external)
++   */
++
++   if ((s_domain) && (r_domain) && (s_domain == r_domain))
++	  dtype = POLICY_F_LOCAL;
++
++   else if ((s_domain == NULL) && (r_domain))
++	  dtype = POLICY_F_EXTERNAL;
++
++   else if ((s_domain) && (r_domain == NULL))
++	  dtype = POLICY_F_REMOTE;
++
++   else if ((s_domain) && (r_domain) && (s_domain != r_domain))
++	  dtype = POLICY_F_REMOTE;
++
++   else if ((s_domain == NULL) && (r_domain == NULL)) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_forbids: no policies for this delivery\n");
++#endif
++	  return 0;
++   }
++
++   else {
++	  fprintf(stderr, "policy_forbids: unknown delivery type\n");
++	  return -1;
++   }
++
++   p = NULL;
++   s_forbid = r_forbid = 0;
++
++   /*
++	  If there is a local rule for sender, use that to
++	  determine if able to send.  If not, check domain
++   */
++
++   if (s_local) {
++	  p = policy_find(s_local->policy, dtype);
++	  if (p) {
++		 /*
++		    See if policy matches
++		 */
++
++		 if (p->flags & POLICY_F_DISALLOW) {
++			if (policy_applies_to(p, addr.s)) {
++#ifdef DEBUG
++			   fprintf(stderr, "*** sender local policy disallows\n");
++#endif
++			   s_forbid = 1;
++			}
++
++#ifdef DEBUG
++			else
++			   fprintf(stderr, "*** sender local policy allows\n");
++#endif
++		 }
++
++		 else {
++#ifdef DEBUG
++			if (policy_applies_to(p, addr.s))
++			   fprintf(stderr, "*** sender local policy allows\n");
++
++			else {
++			   fprintf(stderr, "*** sender local policy denies\n");
++			   s_forbid = 1;
++			}
++#else
++			if (!(policy_applies_to(p, addr.s)))
++				  s_forbid = 1;
++#endif
++		 }
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "*** no sender local policy\n");
++#endif
++   }
++
++   if ((p == NULL) && (s_domain)) {
++	  p = policy_find(s_domain->policy, dtype);
++	  if (p) {
++		 if (p->flags & POLICY_F_DISALLOW) {
++			s_forbid = 1;
++#ifdef DEBUG
++			fprintf(stderr, "--- sender domain policy disallows\n");
++#endif
++		 }
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "--- no sender domain policy\n");
++#endif
++   }
++
++   /*
++	  Deny messaging
++   */
++
++   if (s_forbid) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_forbids: sender policy denies messaging\n");
++#endif
++	  return 1;
++   }
++
++   /*
++	  Reverse delivery type, and check same above
++	  for recipient unless the recipient is of the
++	  same domain
++   */
++
++   /*
++	  A local user to local user delivery is an 'internal'
++	  delivery for the recipient user.
++   */
++
++   if (dtype == POLICY_F_LOCAL) 
++	  dtype = POLICY_F_INTERNAL;
++
++   /*
++	  Sender on same system, different domain.
++	  This is considered an 'external' delivery
++	  to the recipient
++   */
++
++   else if (dtype == POLICY_F_REMOTE)
++	  dtype = POLICY_F_EXTERNAL;
++
++   /*
++	  Sender from off-system remains
++	  as external
++   */
++
++   else if (dtype != POLICY_F_EXTERNAL) {
++	  fprintf(stderr, "policy_forbids: unknown recipient delivery type\n");
++	  return -1;
++   }
++
++   p = NULL;
++   r_forbid = 0;
++
++   if (r_local) {
++	  p = policy_find(r_local->policy, dtype);
++	  if (p) {
++		 /*
++		    See if policy matches
++		 */
++
++		 if (p->flags & POLICY_F_DISALLOW) {
++			if (policy_applies_to(p, remoteinfo ? remoteinfo : mailfrom.s)) {
++#ifdef DEBUG
++			   fprintf(stderr, "*** recipient local policy disallows\n");
++#endif
++			   r_forbid = 1;
++			}
++
++#ifdef DEBUG
++			else
++			   fprintf(stderr, "*** recipient local policy allows\n");
++#endif
++		 }
++
++		 else {
++#ifdef DEBUG
++			if (policy_applies_to(p, remoteinfo ? remoteinfo : mailfrom.s))
++			   fprintf(stderr, "*** recipient local policy allows\n");
++
++			else {
++			   fprintf(stderr, "*** recipient local policy denies\n");
++			   r_forbid = 1;
++			}
++#else
++			if (!(policy_applies_to(p, remoteinfo ? remoteinfo : mailfrom.s)))
++				  r_forbid = 1;
++#endif
++		 }
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "*** no recipient local policy\n");
++#endif
++   }
++
++   if ((p == NULL) && (r_domain)) {
++	  p = policy_find(r_domain->policy, dtype);
++	  if (p) {
++		 if (p->flags & POLICY_F_DISALLOW) {
++			r_forbid = 1;
++#ifdef DEBUG
++			fprintf(stderr, "--- recipient domain policy disallows\n");
++#endif
++		 }
++	  }
++
++#ifdef DEBUG
++	  else
++		 fprintf(stderr, "--- no recipient domain policy\n");
++#endif
++
++   }
++
++   /*
++	  Deny messaging
++   */
++
++   if (r_forbid) {
++#ifdef DEBUG
++	  fprintf(stderr, "policy_forbids: recipient policy denies messaging\n");
++#endif
++	  return 1;
++   }
++
++   /*
++	  Accept message
++   */
++
++   return 0;
++}
++
++/*
++   Search for a domain in the linked list of domains
++*/
++
++static domain_t *domain_find(const char *domain)
++{
++   domain_t *d = NULL;
++
++   if (domain == NULL)
++	  return NULL;
++
++   for (d = domains; d; d = d->next) {
++	  if (!(strcasecmp(d->domain, domain)))
++		 return d;
++   }
++
++   return NULL;
++}
++
++/*
++   Search for a local under a domain in the locals linked list
++*/
++
++static local_t *local_find(const domain_t *d, const char *local)
++{
++   local_t *l = NULL;
++
++   if ((d == NULL) || (local == NULL)) {
++	  fprintf(stderr, "local_find: null argument\n");
++	  return NULL;
++   }
++
++   for (l = d->locals; l; l = l->next) {
++	  if (policy_match(l->local, local))
++		 return l;
++   }
++
++   return NULL;
++}
++
++/*
++   Deallocate a policy
++*/
++
++static void policy_free(policy_t *policy)
++{
++   int i = 0;
++   policy_t *p = NULL, *op = NULL;
++
++   if (policy == NULL)
++	  return;
++
++   p = policy;
++
++   while(p) {
++	  op = p;
++	  p = p->next;
++
++	  if (op->args) {
++		 if (op->numargs) {
++			for (i = 0; i < op->numargs; i++) 
++			   free(op->args[i]);
++
++			free(op->args);
++		 }
++
++		 else
++			fprintf(stderr, "policy_free: no argument count\n");
++	  }
++
++	  free(op);
++   }
++}
++
++/*
++   Deallocate a local
++*/
++
++static void local_free(local_t *local)
++{
++   local_t *l = NULL, *ol = NULL;
++
++   if (local == NULL)
++	  return;
++
++   l = local;
++
++   while(l) {
++	  ol = l;
++	  l = l->next;
++
++	  if (ol->policy)
++		 policy_free(ol->policy);
++
++	  if (ol->local)
++		 free(ol->local);
++
++	  free(ol);
++   }
++}
++
++/*
++   Deallocate all domains
++*/
++
++static void domains_free(void)
++{
++   domain_t *d = NULL, *od = NULL;
++
++   d = domains;
++
++   while(d) {
++	  od = d;
++	  d = d->next;
++
++	  if (od->policy)
++		 policy_free(od->policy);
++
++	  if (od->locals)
++		 local_free(od->locals);
++
++	  if (od->domain)
++		 free(od->domain);
++
++	  free(od);
++   }
++
++   domains = NULL;
++}
+diff -ruN ../netqmail-1.06-original/policy.h netqmail-1.06/policy.h
+--- ../netqmail-1.06-original/policy.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/policy.h	2016-11-22 21:03:57.118527899 +0100
+@@ -0,0 +1,6 @@
++#ifndef __POLICY_H_
++   #define __POLICY_H_
++
++int policy_check(void);
++
++#endif
+diff -ruN ../netqmail-1.06-original/qmail-clean.c netqmail-1.06/qmail-clean.c
+--- ../netqmail-1.06-original/qmail-clean.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-clean.c	2016-11-22 21:03:57.118527899 +0100
+@@ -73,22 +73,26 @@
+    if (line.len < 7) { respond("x"); continue; }
+    if (line.len > 100) { respond("x"); continue; }
+    if (line.s[line.len - 1]) { respond("x"); continue; } /* impossible */
+-   for (i = 5;i < line.len - 1;++i)
++   for (i = line.len - 2;i > 4;--i)
++    {
++     if (line.s[i] == '/') break;
+      if ((unsigned char) (line.s[i] - '0') > 9)
+       { respond("x"); continue; }
+-   if (!scan_ulong(line.s + 5,&id)) { respond("x"); continue; }
++    }
++   if (line.s[i] == '/')
++     if (!scan_ulong(line.s + i + 1,&id)) { respond("x"); continue; }
+    if (byte_equal(line.s,5,"foop/"))
+     {
+ #define U(prefix,flag) fmtqfn(fnbuf,prefix,id,flag); \
+ if (unlink(fnbuf) == -1) if (errno != error_noent) { respond("!"); continue; }
+-     U("intd/",0)
++     U("intd/",1)
+      U("mess/",1)
+      respond("+");
+     }
+    else if (byte_equal(line.s,4,"todo/"))
+     {
+-     U("intd/",0)
+-     U("todo/",0)
++     U("intd/",1)
++     U("todo/",1)
+      respond("+");
+     }
+    else
+diff -ruN ../netqmail-1.06-original/qmail-control.9 netqmail-1.06/qmail-control.9
+--- ../netqmail-1.06-original/qmail-control.9	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-control.9	2016-11-28 17:36:57.350660496 +0100
+@@ -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,25 @@
+ .ta 5c 10c
+ control	default	used by
+ 
++.I authsender	\fR(none)	\fRqmail-remote
++.I badhelo     \fR(none)       \fRqmail-smtpd
++.I badhelonorelay     \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 brtlimit	\fR0	\fRqmail-smtpd
++.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 dnsbllist	\fR(none)	\fRqmail-smtpd
++.I dh2048.pem	\fR(none)	\fRqmail-smtpd
+ .I doublebouncehost	\fIme	\fRqmail-send
+ .I doublebounceto	\fRpostmaster	\fRqmail-send
+ .I envnoathost	\fIme	\fRqmail-send
+@@ -56,22 +71,35 @@
+ .I localiphost	\fIme	\fRqmail-smtpd
+ .I locals	\fIme	\fRqmail-send
+ .I morercpthosts	\fR(none)	\fRqmail-smtpd
++.I outgoingip	\fR0.0.0.0	\fRqmail-remote
+ .I percenthack	\fR(none)	\fRqmail-send
+ .I plusdomain	\fIme	\fRqmail-inject
+ .I qmqpservers	\fR(none)	\fRqmail-qmqpc
+ .I queuelifetime	\fR604800	\fRqmail-send
+ .I rcpthosts	\fR(none)	\fRqmail-smtpd
++.I rsa2048.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 taps	\fR(none)	\fRqmail-queue
+ .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
+ .SH "SEE ALSO"
+ qmail-inject(8),
+ qmail-qmqpc(8),
++qmail-queue(8),
+ qmail-remote(8),
+ qmail-send(8),
+ qmail-showctl(8),
+diff -ruN ../netqmail-1.06-original/qmail-dk.9 netqmail-1.06/qmail-dk.9
+--- ../netqmail-1.06-original/qmail-dk.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-dk.9	2018-04-03 14:46:51.371411632 +0200
+@@ -0,0 +1,164 @@
++.TH qmail-dk 8
++.SH NAME
++qmail-dk \- sign/verify and queue a mail message for delivery
++.SH SYNOPSIS
++.B qmail-dk
++.SH DESCRIPTION
++.B qmail-dk
++has the same interface as
++.B qmail-queue
++except that it inserts an appropriate DomainKeys header before it
++queues the message.  To invoke
++.BR qmail-dk ,
++set QMAILQUEUE to point to qmail-dk in the environment when
++you send or receive email. qmail-dk will call
++.BR qmail-multi .
++To invoke an executable other than
++.B qmail-multi
++set DKQUEUE=bin/qmail-queue for example.
++
++.B qmail-dk
++supports DomainKey signing and verification.  It uses the libdomainkey
++and OpenSSL libraries.  To sign a message, set the
++.B DKSIGN
++environment variable to the pathname to the private key that will be
++used to sign the message.  If there is a % character in the environment
++variable, it is removed and replaced by the domain name in the From: header.
++If, after substituting the %, that file does not exist, the % will be removed.
++If the private key file does not exist and does not have a % character, the message will
++be rejected with error 32. The selector will be taken from the basename of the file.
++The private key should be created by 
++.BR dknewkey(8) .
++
++In the absense of DKSIGN and DKVERIFY environment variable, qmail-dk will sign the
++message if RELAYCLIENT environment variable is set and verify the message if RELAYCLIENT
++environment variable is not set. If DKVERIFY is set, you can disable dk verification, if
++RELAYCLIENT is set by setting RELAYCLIENT_NODKVERIFY environment variable.
++
++You can set various DK options in getopt style, by setting the environment variable DKSIGNOPTIONS
++ b <advice_length>    Length of Advice
++ c <canonicalization> simple, nofws
++ s <privkeyfile>
++ h                    include h= tag
++ r                    Skip Duplicate Headers
++.EX
++ DKSIGNOPTIONS="-h -r -c nofws"
++ sets the h= tag, skips duplicate headers and sets nofws canonicalization
++.EE
++
++To verify a message, set the
++.B DKVERIFY
++environment variable to a desired set of letters.  Precisely, if you
++want a libdomainkey return status to generate an error, include that
++letter, where A is the first return status (DK_STAT_OK), B is the
++second (DK_STAT_BADSIG), etc.  The letter should be uppercase if you
++want a permanent error to be returned and lowercase if you want a temporary error
++to be returned.
++
++The complete set of letters with the corresponding return status is given below
++
++ A - DK_STAT_OK           - Function completed successfully
++ B - DK_STAT_BADSIG       - Signature was available but failed to verify against
++                            domain specified key
++ C - DK_STAT_NOSIG        - No signature available in message
++ D - DK_STAT_NOKEY        - No public key available (permanent failure)
++ E - DK_STAT_BADKEY       - Unusable key, public if verifying, private if signing
++ F - DK_STAT_CANTVRFY     - Cannot get domain key to verify signature
++                            (temporary failure)
++ G - DK_STAT_SYNTAX       - Message is not valid syntax. Signature could not be
++                            created/checked
++ H - DK_STAT_NORESOURCE   - Could not get critical resource (temporary failure)
++ I - DK_STAT_ARGS         - Arguments are not usable.
++ J - DK_STAT_REVOKED      - Key has been revoked.
++ K - DK_STAT_INTERNAL     - cannot call this routine in this context. Internal error.
++ L - DK_STAT_GRANULARITY  - Granularity mismatch: sender doesn't match g= option.
++ M - DK_STAT_DUPLICATE    - duplicate Domainkey-Signature in message.
++
++For example, if you want to permanently reject messages that have a
++signature that has been revoked, include the letter 'K' in the
++.B DKVERIFY
++environment variable.  A conservative set of letters is
++.BR DEGIJKfh .
++Reject permanently BADSIG, NOKEY, BADKEY, SYNTAX, ARGS, REVOKED, and
++INTERNAL errors, and temporarily CANTVRFY and NORESOURCE. Add in
++.B B
++if you want to reject messages that have a signature that doesn't
++verify (presumably because the message is a forgery or has been
++damaged in transit.  Note that
++.B qmail-dk
++always inserts the 
++.B DomainKey-Status
++header, so that messages can be
++rejected at delivery time, or in the mail reader.
++
++Typically, you would sign messages generated on-host by setting
++.B DKSIGN
++in the environment before running an email program.  DKSIGN will be carried
++through qmail's sendmail emulation through 
++.B qmail-inject
++to
++.BR qmail-dk .
++You would also set it for
++.B qmail-smtpd
++at the same time
++.B RELAYCLIENT
++is set, most often in the tcpserver cdb file.  If a host is authorized
++to relay, you probably want to sign messages sent by that host.
++.B DKVERIFY
++should be set for all other hosts.
++
++If neither
++.B DKSIGN
++nor
++.B DKVERIFY
++are set, then
++.B DKSIGN
++will be set to QMAILHOME/control/domainkeys/%/default. The % will be replaced by the domain in the
++From: header. If such a file does not exist, then it will be set to
++QMAILHOME/control/domainkeys/default. If such a private key exists, it will be used to sign the
++domain. You can also set \fBDKKEY\fR to chose a key different from
++QMAILHOME/control/domainkeys/%/default. \fBDKKEY\fR can also have % character that will be
++replaced by the domain in the From: header.
++
++By default
++.B qmail-dk
++will use all of the headers when signing a message.
++The environment variable
++.B DKEXCLUDEHEADERS
++may be set to a colon-separated list of headers that are to be excluded from signing.
++
++.B qmail-dk
++will ordinarily spawn
++.BR qmail-multi ,
++but if DKQUEUE is set in the environment,
++the program that it points to will be executed instead.
++
++.SH "EXIT CODES"
++.B qmail-dk
++returns the same exit codes as qmail-queue with these additions:
++.TP 5
++.B 35
++The private key file does not exist.
++.TP 5
++.B 57
++Trouble waiting for qmail-queue to exit.
++.TP 5
++.B 58
++Unable to vfork.
++.TP 5
++.B 59
++Unable to create a pipe to qmail-queue.
++.SH "SEE ALSO"
++addresses(5),
++envelopes(5),
++qmail-header(5),
++dknewkey(8),
++dktest(8),
++qmail-inject(8),
++qmail-qmqpc(8),
++qmail-queue(8),
++qmail-send(8),
++qmail-smtpd(8),
++qmail-dkim(8),
++domain-keys(5)
++
+diff -ruN ../netqmail-1.06-original/qmail-dk.c netqmail-1.06/qmail-dk.c
+--- ../netqmail-1.06-original/qmail-dk.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-dk.c	2018-04-03 14:46:51.372411636 +0200
+@@ -0,0 +1,866 @@
++/*
++ * $Log: qmail-dk.c,v $
++ * Revision 1.37  2013-01-24 22:42:07+05:30  Cprogrammer
++ * alternate code for chosing DKSIGN selector filename
++ *
++ * Revision 1.36  2011-11-10 14:31:42+05:30  Cprogrammer
++ * BUG ssout to be assigned only after pidopen()
++ *
++ * Revision 1.35  2011-11-07 09:35:25+05:30  Cprogrammer
++ * set ssout, sserr, ssin before executing other functions
++ *
++ * Revision 1.34  2011-07-29 09:28:48+05:30  Cprogrammer
++ * fixed key file name
++ *
++ * Revision 1.33  2011-07-28 19:34:45+05:30  Cprogrammer
++ * BUG - fixed opening of private key with absolute path
++ *
++ * Revision 1.32  2011-07-22 19:29:06+05:30  Cprogrammer
++ * fixed compilation error
++ *
++ * Revision 1.31  2011-07-22 14:39:53+05:30  Cprogrammer
++ * added DKDOMAIN feature to set d= tag
++ *
++ * Revision 1.30  2011-06-04 17:44:16+05:30  Cprogrammer
++ * remove % sign from private key if file not found
++ *
++ * Revision 1.29  2010-07-21 08:59:14+05:30  Cprogrammer
++ * use CONTROLDIR environment variable instead of a hardcoded control directory
++ *
++ * Revision 1.28  2009-08-13 18:36:39+05:30  Cprogrammer
++ * for verification continue in case of DK_SYNTAX errors
++ *
++ * Revision 1.27  2009-04-22 13:42:47+05:30  Cprogrammer
++ * made fd for custom error configurable through env variable ERROR_FD
++ *
++ * Revision 1.26  2009-04-21 09:05:14+05:30  Cprogrammer
++ * return relevant error message for reading private key
++ *
++ * Revision 1.25  2009-04-21 08:56:03+05:30  Cprogrammer
++ * return temp errors for temporary failures
++ *
++ * Revision 1.24  2009-04-21 08:15:39+05:30  Cprogrammer
++ * moved stralloc variable outside block
++ *
++ * Revision 1.23  2009-04-20 22:20:40+05:30  Cprogrammer
++ * added DKSIGNOPTIONS
++ *
++ * Revision 1.22  2009-04-07 11:38:02+05:30  Cprogrammer
++ * use TMPDIR env variable for tmp directory
++ *
++ * Revision 1.21  2009-04-05 12:52:10+05:30  Cprogrammer
++ * added preprocessor warning
++ *
++ * Revision 1.20  2009-03-31 08:21:12+05:30  Cprogrammer
++ * set dksign when RELAYCLIENT is defined when both dksign, dkverify are undefined
++ *
++ * Revision 1.19  2009-03-28 22:26:35+05:30  Cprogrammer
++ * use DKSIGN,DKVERIFY env variables if RELAYCLIENT is not set
++ *
++ * Revision 1.18  2009-03-28 22:02:32+05:30  Cprogrammer
++ * removed extra white space
++ *
++ * Revision 1.17  2009-03-28 11:34:51+05:30  Cprogrammer
++ * BUG fix. corrected setting of dksign, dkverify variables
++ *
++ * Revision 1.16  2009-03-22 16:58:13+05:30  Cprogrammer
++ * report custom errors to qmail-queue through custom error interface
++ *
++ * Revision 1.15  2009-03-21 15:15:56+05:30  Cprogrammer
++ * improved logic
++ *
++ * Revision 1.14  2009-03-20 22:35:24+05:30  Cprogrammer
++ * fix for multi-line headers
++ *
++ * Revision 1.13  2009-03-19 08:28:12+05:30  Cprogrammer
++ * added EXCLUDEHEADERS
++ *
++ * Revision 1.12  2009-03-14 17:11:32+05:30  Cprogrammer
++ * added DK_STAT_GRANULARITY
++ *
++ * Revision 1.11  2009-03-14 08:52:54+05:30  Cprogrammer
++ * look for domainkey in control/domainkeys
++ *
++ * Revision 1.10  2005-08-23 17:33:37+05:30  Cprogrammer
++ * gcc 4 compliance
++ *
++ * Revision 1.9  2005-04-01 21:42:04+05:30  Cprogrammer
++ * added DK_STAT_SYNTAX
++ * changed error codes
++ *
++ * Revision 1.8  2004-11-02 09:15:53+05:30  Cprogrammer
++ * commented out writing of Comments: header
++ *
++ * Revision 1.7  2004-10-24 21:32:00+05:30  Cprogrammer
++ * removed unecessary header files
++ *
++ * Revision 1.6  2004-10-22 20:28:18+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.5  2004-10-22 15:36:45+05:30  Cprogrammer
++ * removed readwrite.h
++ *
++ * Revision 1.4  2004-10-22 14:44:26+05:30  Cprogrammer
++ * use control_readnativefile to avoid skipping signure with '#' char
++ *
++ * Revision 1.3  2004-10-20 20:08:53+05:30  Cprogrammer
++ * libdomainkeys-0.62
++ *
++ * Revision 1.2  2004-09-23 22:55:32+05:30  Cprogrammer
++ * removed uneccessary header files
++ *
++ * Revision 1.1  2004-08-28 01:02:16+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include <unistd.h>
++#include <stdlib.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include "sgetopt.h"
++#include "substdio.h"
++#include "open.h"
++#include "qmail.h"
++#include "sig.h"
++#include "fmt.h"
++#include "fd.h"
++#include "alloc.h"
++#include "str.h"
++#include "getln.h"
++#include "case.h"
++#include "stralloc.h"
++#include "datetime.h"
++#include "now.h"
++#include "wait.h"
++#include "auto_qmail.h"
++#include "env.h"
++#include "scan.h"
++#include "mess822.h"
++#include "control.h"
++#include "domainkeys.h"
++
++#define DEATH 86400	/*- 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
++#define ADDR 1003
++#define ADVICE_BUF 2048
++
++char            inbuf[2048];
++struct substdio ssin;
++char            outbuf[256];
++struct substdio ssout;
++struct substdio sserr;
++char            errbuf[256];
++
++datetime_sec    starttime;
++struct datetime dt;
++unsigned long   mypid;
++unsigned long   uid;
++char           *pidfn;
++int             messfd;
++int             readfd;
++char           *dksign = 0;
++char           *dkverify = 0;
++
++char          **MakeArgs(char *);
++void            FreeMakeArgs(char **);
++
++void
++die(e)
++	int             e;
++{
++	_exit(e);
++}
++
++void
++die_write()
++{
++	die(53);
++}
++
++void
++die_read()
++{
++	die(54);
++}
++
++void
++sigalrm()
++{
++	/*- thou shalt not clean up here */
++	die(52);
++}
++
++void
++sigbug()
++{
++	die(81);
++}
++
++void
++custom_error(char *flag, char *status, char *code)
++{
++	char           *c;
++
++	if (substdio_put(&sserr, flag, 1) == -1)
++		die_write();
++	if (substdio_put(&sserr, "qmail-dk: ", 10) == -1)
++		die_write();
++	if (substdio_puts(&sserr, status) == -1)
++		die_write();
++	if (code)
++	{
++		if (substdio_put(&sserr, " (#", 3) == -1)
++			die_write();
++		c = (*flag == 'Z') ? "4" : "5";
++		if (substdio_put(&sserr, c, 1) == -1)
++			die_write();
++		if (substdio_put(&sserr, code + 1, 4) == -1)
++			die_write();
++		if (substdio_put(&sserr, ")", 1) == -1)
++			die_write();
++	}
++	if (substdio_flush(&sserr) == -1)
++		die_write();
++	return;
++}
++
++void
++maybe_die_dk(e)
++	DK_STAT         e;
++{
++	switch (e)
++	{
++	case DK_STAT_NORESOURCE:
++		_exit(51);
++	case DK_STAT_INTERNAL:
++		_exit(81);
++	case DK_STAT_ARGS:
++		custom_error("Z", "Arguments are not usable. (#4.3.5)", 0);
++		_exit(88);
++	case DK_STAT_SYNTAX:
++		if (!dksign && dkverify)
++			return;
++		custom_error("Z", "Message is not valid syntax. Signature could not be created/checked (#4.6.0)", 0);
++		_exit(88);
++	case DK_STAT_CANTVRFY:
++		custom_error("Z", "Cannot get domainkeys to verify signature (#5.7.5)", 0);
++		_exit(88);
++	case DK_STAT_BADKEY:
++		if (env_get("DKVERIFY"))
++			custom_error("Z", "Unusable public key for verifying (#5.7.5)", 0);
++		else
++			custom_error("Z", "Unusable private key for signing (#5.7.15", 0);
++		_exit(88);
++	default:
++		return;
++	}
++}
++
++unsigned int
++pidfmt(s, seq)
++	char           *s;
++	unsigned long   seq;
++{
++	unsigned int    i;
++	unsigned int    len;
++	char           *tmpdir;
++
++	if (!(tmpdir = env_get("TMPDIR")))
++		tmpdir = "/tmp";
++	len = 0;
++	i = fmt_str(s, tmpdir);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, "/qmail-dk.");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, mypid);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, ".");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, starttime);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, ".");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, seq);
++	len += i;
++	if (s)
++		s += i;
++	++len;
++	if (s)
++		*s++ = 0;
++
++	return len;
++}
++
++void
++pidopen()
++{
++	unsigned int    len;
++	unsigned long   seq;
++
++	seq = 1;
++	len = pidfmt((char *) 0, seq);
++	if (!(pidfn = alloc(len)))
++		die(51);
++	for (seq = 1; seq < 10; ++seq)
++	{
++		if (pidfmt((char *) 0, seq) > len)
++			die(81); /*- paranoia */
++		pidfmt(pidfn, seq);
++		if ((messfd = open_excl(pidfn)) != -1)
++			return;
++	}
++	die(63);
++}
++
++char            tmp[FMT_ULONG];
++DK_LIB         *dklib;
++DK             *dk;
++DK_STAT         st;
++stralloc        dkoutput = { 0 };    /*- Domainkey-Signature */
++stralloc        dksignature = { 0 }; /*- content of private signature */
++stralloc        dkopts = { 0 };
++char           *dkqueue = 0;
++char           *dkexcludeheaders;
++
++static void
++write_signature(DK *dk, char *dk_selector, char *keyfn,
++	int advicelen, int opth, char *canon)
++{
++	unsigned char   advice[ADVICE_BUF];
++	char           *selector, *from, *tmp;
++	static stralloc keyfnfrom = { 0 };
++	int             i;
++
++	from = dk_from(dk);
++	if (keyfn[0] != '/')
++	{
++		if (!stralloc_copys(&keyfnfrom, "control/"))
++			die(51, 1);
++	}
++	i = str_chr(keyfn, '%');
++	if (keyfn[i])
++	{
++		if (keyfn[0] == '/')
++		{
++			if (!stralloc_copyb(&keyfnfrom, keyfn, i))
++				die(51, 1);
++		} else
++		if (!stralloc_catb(&keyfnfrom, keyfn, i))
++			die(51, 1);
++		if (!stralloc_cats(&keyfnfrom, from))
++			die(51);
++		if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
++			die(51);
++		if (!stralloc_0(&keyfnfrom))
++			die(51);
++		if (access(keyfnfrom.s, F_OK))
++		{
++			/*- since file is not found remove '%' sign */
++			keyfnfrom.len = 8;
++			if (keyfn[0] == '/')
++			{
++				if (!stralloc_copyb(&keyfnfrom, keyfn, i))
++					die(51, 1);
++			} else
++			if (!stralloc_catb(&keyfnfrom, keyfn, i))
++				die(51, 1);
++			if ((i - 1) > 0 && keyfn[i - 1] == '/' && keyfn[i + 1] == '/')
++				i++;
++			if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
++				die(51);
++			if (!stralloc_0(&keyfnfrom))
++				die(51);
++		} 
++	} else
++	{
++		if (keyfn[0] == '/')
++		{
++			if (!stralloc_copys(&keyfnfrom, keyfn))
++				die(51, 1);
++		} else
++		if (!stralloc_cats(&keyfnfrom, keyfn))
++			die(51, 1);
++		if (!stralloc_0(&keyfnfrom))
++			die(51);
++	}
++	switch (control_readnativefile(&dksignature, keyfnfrom.s, 1))
++	{
++	case 0: /*- file not present */
++		/*
++		 * You may have multiple domains, but may chose to sign
++		 * only for few domains which have the key present. Do not
++		 * treat domains with missing key as an error.
++		 */
++		if (keyfn[i])
++			return;
++		die(32);
++	case 1:
++		break;
++	default:
++		custom_error("Z", "Unable to read private key. (#4.3.0)", 0);
++		_exit(88);
++	}
++	for (i = 0; i < dksignature.len; i++)
++	{
++		if (dksignature.s[i] == '\0')
++			dksignature.s[i] = '\n';
++	}
++	if (!stralloc_0(&dksignature))
++		die(51);
++	st = dk_getsig(dk, dksignature.s, advice, advicelen);
++	maybe_die_dk(st);
++	if (!dk_selector)
++	{
++		selector = keyfn;
++		while (*keyfn)
++		{
++			if (*keyfn == '/')
++				selector = keyfn + 1;
++			keyfn++;
++		}
++	} else
++		selector = dk_selector;
++	if (!stralloc_cats(&dkoutput,
++#if 0
++		"Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys\n"
++#endif
++		"DomainKey-Signature: a=rsa-sha1; q=dns; c="))
++		die(51);
++	if (!stralloc_cats(&dkoutput, canon))
++		die(51);
++	if (!stralloc_cats(&dkoutput, ";\n"))
++		die(51);
++	if (!stralloc_cats(&dkoutput, "    s="))
++		die(51);
++	if (!stralloc_cats(&dkoutput, selector))
++		die(51);
++	if (!stralloc_cats(&dkoutput, "; d="))
++		die(51);
++	tmp = env_get("DKDOMAIN");
++	if (from || tmp)
++	{
++		if (!stralloc_cats(&dkoutput, tmp ? tmp : from))
++			die(51);
++	} else
++	if (!stralloc_cats(&dkoutput, "unknown"))
++		die(51);
++	if (!stralloc_cats(&dkoutput, ";\n"))
++		die(51);
++	if (!stralloc_cats(&dkoutput, "    b="))
++		die(51);
++	if (!stralloc_cats(&dkoutput, (char *) advice))
++		die(51);
++	if (dkexcludeheaders || opth)
++	{
++		if ((i = dk_headers(dk, NULL)) > 0)
++		{
++			if (!(tmp = alloc(i)))
++				die(51);
++			if (!dk_headers(dk, tmp))
++				die(51);
++			if (!stralloc_cats(&dkoutput, ";\n    h="))
++				die(51);
++			if (!stralloc_cats(&dkoutput, tmp))
++				die(51);
++			alloc_free(tmp);
++		}
++	}
++	if (!stralloc_cats(&dkoutput, ";\n"))
++		die(51);
++}
++
++int
++find_header(stralloc *line)
++{
++	static stralloc headers = { 0 };
++	int             n, i, j;
++
++	for (n = 0; n < line->len; ++n)
++	{
++		if (line->s[n] == ':')
++			break;
++	}
++	if (n == line->len)
++		return -1;
++	if (!headers.len)
++	{
++		if (!stralloc_copys(&headers, ""))
++			die(51);
++		if (dkexcludeheaders)
++		{
++			if (!stralloc_cats(&headers, dkexcludeheaders))
++				die(51);
++			if (!stralloc_append(&headers, ":"))
++				die(51);
++		}
++	}
++	if (!headers.len)
++		return 0;
++	for (i = j = 0; i < headers.len; ++i)
++	{
++		if (headers.s[i] != ':')
++			continue;
++		if (i - j == n && !case_diffb(headers.s + j, n, line->s))
++			return 1;
++		j = i + 1;
++	}
++	return 0;
++}
++
++int
++dk_setoptions(char **selector, int *advicelen, int *opth, int *optr, int *optc,
++	char **canon, char *signOptions)
++{
++	char          **argv;
++	int             ch, argc;
++
++	*opth = 0;
++	*optr = 0;
++	*optc = DK_CANON_NOFWS;
++	*canon = "nofws";
++	*selector = 0;
++	if (!signOptions)
++		return (0);
++	if (!stralloc_copys(&dkopts, "qmail-dk "))
++		die(51);
++	if (!stralloc_cats(&dkopts, signOptions))
++		die(51);
++	if (!stralloc_0(&dkopts))
++		die(51);
++	if (!(argv = MakeArgs(dkopts.s)))
++		die(51);
++	for (argc = 0;argv[argc];argc++);
++	while ((ch = sgopt(argc, argv, "hrb:c:s:")) != sgoptdone)
++	{
++		switch (ch)
++		{
++		case 'h':
++			*opth = 1;
++			break;
++		case 'r':
++			*optr = 1;
++			*opth = 1;
++			break;
++		case 'b':
++			*advicelen = atoi(optarg);
++			if (*advicelen > ADVICE_BUF);
++				*advicelen = ADVICE_BUF;
++			break;
++		case 'c':
++			if (!str_diffn("simple\0", optarg, 7))
++			{
++				*optc = DK_CANON_SIMPLE;
++				*canon = "simple";
++			}
++			break;
++		case 's':
++			*selector = optarg;
++			break;
++		default:
++			FreeMakeArgs(argv);
++			return (1);
++		}
++	} /*- while ((ch = sgopt(argc, argv, "hrb:c:s:")) != sgoptdone) */
++	FreeMakeArgs(argv);
++	return (0);
++}
++
++static char    *binqqargs[2] = { "bin/qmail-queue", 0 };
++
++int
++main(int argc, char *argv[])
++{
++	int             errfd, pim[2];
++	int             wstat, match, opth = 0, optr = 0, optc = DK_CANON_NOFWS,
++					advicelen = ADVICE_BUF;
++	char           *x, *relayclient, *canon = "nofws", *selector = 0; 
++	stralloc        line = {0}, dkfn = {0};
++	unsigned long   pid;
++
++	sig_blocknone();
++	umask(033);
++	if (!(x = env_get("ERROR_FD")))
++		errfd = CUSTOM_ERR_FD;
++	else
++		scan_int(x, &errfd);
++	substdio_fdbuf(&sserr, write, errfd, errbuf, sizeof(errbuf));
++	if (chdir(auto_qmail) == -1)
++		die(61);
++	dkqueue = env_get("DKQUEUE");
++	if (dkqueue && *dkqueue)
++		binqqargs[0] = dkqueue;
++	dksign = env_get("DKSIGN");
++	dkverify = env_get("DKVERIFY");
++	relayclient = env_get("RELAYCLIENT");
++	if (dkverify && relayclient && env_get("RELAYCLIENT_NODKVERIFY")) {
++		execv(*binqqargs, binqqargs);
++		die(120, 0);
++	}
++	if (!dksign && !dkverify && relayclient)
++	{
++		if (!(dksign = env_get("DKKEY")))
++		{
++			if (!stralloc_copys(&dkfn, "domainkeys/%/default"))
++				die(51);
++			if (!stralloc_0(&dkfn))
++				die(51);
++			dksign = dkfn.s;
++		}
++	}
++	if (dksign || dkverify)
++	{
++		if (!(dklib = dk_init(&st)))
++		{
++			maybe_die_dk(st);
++			custom_error("Z", "dk initialization failed (#4.3.0)", 0);
++			_exit(88);
++		}
++	}
++	/*- Initialization */
++	if (dksign)
++	{
++		if (dk_setoptions(&selector, &advicelen, &opth, &optr, &optc, &canon, env_get("DKSIGNOPTIONS")))
++		{
++			custom_error("Z", "Invalid DKSIGNOPTIONS (#4.3.0)", 0);
++			_exit(88);
++		}
++		if (!(dk = dk_sign(dklib, &st, optc)))
++		{
++			maybe_die_dk(st);
++			custom_error("Z", "dk_sign failed (#4.3.0)", 0);
++			_exit(88);
++		}
++		if (optr && dk_setopts(dk, DKOPT_RDUPE) != DK_STAT_OK)
++		{
++			custom_error("Z", "DKOPT_RDUPE failed (#4.3.0)", 0);
++			_exit(88);
++		}
++	} else
++	if (dkverify)
++	{
++		if (!(dk = dk_verify(dklib, &st)))
++		{
++			maybe_die_dk(st);
++			custom_error("Z", "dk_verify failed (#4.3.0)", 0);
++			_exit(88);
++		}
++	}
++	mypid = getpid();
++	uid = getuid();
++	starttime = now();
++	datetime_tai(&dt, starttime);
++	sig_pipeignore();
++	sig_miscignore();
++	sig_alarmcatch(sigalrm);
++	sig_bugcatch(sigbug);
++	alarm(DEATH);
++	pidopen();
++	if ((readfd = open_read(pidfn)) == -1)
++		die(63);
++	if (unlink(pidfn) == -1)
++		die(63);
++	substdio_fdbuf(&ssin, read, 0, inbuf, sizeof(inbuf));
++	substdio_fdbuf(&ssout, write, messfd, outbuf, sizeof(outbuf));
++	dkexcludeheaders = env_get("DKEXCLUDEHEADERS");
++	if (dkexcludeheaders)
++	{
++		int             hdr_continue, in_header = 1;
++
++		hdr_continue = 0;
++		for (;;)
++		{
++	
++			if (getln(&ssin, &line, &match, '\n') == -1)
++				die_read();
++			if (!match && line.len == 0)
++				break;
++			if (substdio_put(&ssout, line.s, line.len) == -1)
++				die_write();
++			if (!dksign && !dkverify)
++				continue;
++			if (in_header && !mess822_ok(&line))
++				in_header = 0;
++			if (in_header)
++			{
++				if (line.s[0] == ' ' || line.s[0] == '\t')
++				{
++					if (hdr_continue)
++						continue;
++				} else
++				if (find_header(&line) == 1) {
++					hdr_continue = 1;
++					continue;
++				} else
++					hdr_continue = 0;
++			}
++			if (match)
++			{
++				st = dk_message(dk, (unsigned char *) line.s, line.len - 1);
++				maybe_die_dk(st);
++				st = dk_message(dk, (unsigned char *) "\r\n", 2);
++			} else
++				st = dk_message(dk, (unsigned char *) line.s, line.len);
++			maybe_die_dk(st);
++		}
++	} else
++	for (;;)
++	{
++		register int    n;
++		register char  *x;
++		int             i;
++
++		if ((n = substdio_feed(&ssin)) < 0)
++			die_read();
++		if (!n)
++			break;
++		x = substdio_PEEK(&ssin);
++		if (dksign || dkverify)
++		{
++			for (i = 0; i < n; i++)
++			{
++				if (x[i] == '\n')
++					st = dk_message(dk, (unsigned char *) "\r\n", 2);
++				else
++					st = dk_message(dk, (unsigned char *) x + i, 1);
++				maybe_die_dk(st);
++			}
++		}
++		if (substdio_put(&ssout, x, n) == -1)
++			die_write();
++		substdio_SEEK(&ssin, n);
++	}
++	if (substdio_flush(&ssout) == -1)
++		die_write();
++	if (dksign || dkverify)
++	{
++		st = dk_eom(dk, (void *) 0);
++		maybe_die_dk(st);
++		if (dksign)
++			write_signature(dk, selector, dksign, advicelen, opth, canon);
++		else
++		if (dkverify)
++		{
++			char           *status = 0, *code = 0;
++
++			if (!stralloc_copys(&dkoutput, "DomainKey-Status: "))
++				die(51);
++			switch (st)
++			{
++			case DK_STAT_OK:
++				status = "good        ";
++				break;
++			case DK_STAT_BADSIG:
++				status = "bad         ";
++				code = "X.7.5";
++				break;
++			case DK_STAT_NOSIG:
++				status = "no signature";
++				code = "X.7.5";
++				break;
++			case DK_STAT_NOKEY:
++			case DK_STAT_CANTVRFY:
++				status = "no key      ";
++				code = "X.7.0";
++				break;
++			case DK_STAT_BADKEY:
++				status = "bad key     ";
++				code = "X.7.5";
++				break;
++			case DK_STAT_INTERNAL:
++				status = "bad format  ";
++				code = "X.3.0";
++				break;
++			case DK_STAT_ARGS:
++				status = "bad format  ";
++				code = "X.3.5";
++				break;
++			case DK_STAT_SYNTAX:
++				status = "bad format  ";
++				code = "X.6.0";
++				break;
++			case DK_STAT_NORESOURCE:
++				status = "no resources";
++				code = "X.3.0";
++				break;
++			case DK_STAT_REVOKED:
++				status = "revoked     ";
++				code = "X.7.5";
++				break;
++			case DK_STAT_GRANULARITY:
++				status = "bad sender  ";
++				code = "X.7.5";
++				break;
++			}
++			if (!stralloc_cats(&dkoutput, status))
++				die(51);
++			if (!stralloc_cats(&dkoutput, "\n"))
++				die(51);
++			if (dkverify[str_chr(dkverify, 'A' + st)])
++			{
++				custom_error("D", status, code); /*- return permanent error */
++				die(88);
++			}
++			if (dkverify[str_chr(dkverify, 'a' + st)])
++			{
++				custom_error("Z", status, code); /*- return temporary error */
++				die(88);
++			}
++		}
++	}
++	if (pipe(pim) == -1)
++		die(59);
++	switch (pid = vfork())
++	{
++	case -1:
++		close(pim[0]);
++		close(pim[1]);
++		die(58);
++	case 0:
++		close(pim[1]);
++		if (fd_move(0, pim[0]) == -1)
++			die(120);
++		execv(*binqqargs, binqqargs);
++		die(120);
++	}
++	close(pim[0]);
++	substdio_fdbuf(&ssin, read, readfd, inbuf, sizeof(inbuf));
++	substdio_fdbuf(&ssout, write, pim[1], outbuf, sizeof(outbuf));
++	if (substdio_bput(&ssout, dkoutput.s, dkoutput.len) == -1) /*- write DK signature */
++		die_write();
++	switch (substdio_copy(&ssout, &ssin))
++	{
++	case -2:
++		die_read();
++	case -3:
++		die_write();
++	}
++	if (substdio_flush(&ssout) == -1)
++		die_write();
++	close(pim[1]);
++	if (wait_pid(&wstat, pid) != pid)
++		die(57);
++	if (wait_crashed(wstat))
++		die(57);
++	die(wait_exitcode(wstat));
++	/*- Not Reached */
++	exit(0);
++}
++
++void
++getversion_qmail_dk_c()
++{
++	static char    *x = "$Id: qmail-dk.c,v 1.37 2013-01-24 22:42:07+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/qmail-dkim.9 netqmail-1.06/qmail-dkim.9
+--- ../netqmail-1.06-original/qmail-dkim.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-dkim.9	2018-04-03 14:46:51.372411636 +0200
+@@ -0,0 +1,321 @@
++.TH qmail-dkim 8
++.SH NAME
++qmail-dkim \- sign/verify using DKIM (SSP/ADSP optionally) and queue a mail message for delivery
++.SH SYNOPSIS
++.B qmail-dkim
++.SH DESCRIPTION
++.B qmail-dkim
++has the same interface as
++.B qmail-queue
++except that it inserts an appropriate DKIM header (rfc4871) before it
++queues the message.  To invoke
++.BR qmail-dkim ,
++set QMAILQUEUE to point to qmail-dkim in the environment when
++you send or receive email. qmail-dkim will call
++.BR qmail-queue .
++To invoke an executable other than
++.B qmail-queue
++set DKIMQUEUE=bin/qmail-dk for example.
++
++.B qmail-dkim
++supports DKIM signing and verification and can optionally use
++.B Sender Signing Practice (SSP)
++or
++.B Author Domain Signing Practice.
++It uses the libdkim and OpenSSL libraries.  To sign a message, set the
++.B DKIMSIGN
++environment variable to the pathname of the private key that will be
++used to sign the message. If there is a % character in the environment
++variable, it is removed and replaced by the domain name in the From: header.
++If, after substituting the %, that file does not exist, the % character will be
++removed. If the private key file does not exist and does not have a % character,
++the message will be rejected with error 35. The selector (s=) will be taken from
++the basename of the file. The private key should be created by 
++.BR dknewkey(8) .
++
++In the absense of DKSIGN and DKVERIFY environment variable, qmail-dkim will sign the
++message if RELAYCLIENT or AUTHINFO environment variable is set. It will verify the message
++if RELAYCLIENT or AUTHINFO environment variable is not set. Even if DKVERIFY is set, you can disable dkim
++verification, if RELAYCLIENT or AUTHINFO is set, by setting RELAYCLIENT_NODKVERIFY environment variable.
++
++You can set various DKIM options in getopt style, by setting the environment variable
++.B DKIMSIGNOPTIONS
++
++ b <standard>         1 - allman, 2 - ietf or 3 - both
++ c <canonicalization> r for relaxed [DEFAULT], s - simple,
++                      t relaxed/simple, u - simple/relaxed
++ l                    include body length tag
++ q                    include query method tag;
++ t                    include a timestamp tag
++ h                    include copied headers
++ i <identity>         the identity, if not provided it will not be included
++ x <expire_time>      the expire time in seconds since epoch
++                      ( DEFAULT = current time + 604800)
++                      if set to - then it will not be included
++ z <hash>             1 for sha1, 2 for sha256, 3 for both
++
++.EX
++ DKIMSIGNOPTIONS="-b 1 -c r -q"
++ sets allman standard, with relaxed canonicalization and include query method tag
++.EE
++
++Apart from setting
++.BR DKIMSIGNOPTIONS ,
++you can set the identity and the expire time by setting
++.B DKIMIDENTITY
++and
++.B DKIMEXPIRE
++respectively.
++.B DKIMIDENTITY
++takes precedence over -i option specified in
++.BR DKIMSIGNOPTIONS.
++Similarly,
++.B DKIMEXPIRE
++takes precedence over -x option specifed in
++.BR DKIMSIGNOPTIONS.
++.B qmail-dkim
++uses the domain found in the Sender: header to set the domain tag. If not it uses the
++From: header. You can override this by setting 
++.B DKIMDOMAIN
++environment variable.
++.B DKIMDOMAIN
++can be set to an email address or a domain (without the at sign).
++
++To verify a message, set the
++.B DKIMVERIFY
++environment variable to a desired set of letters.  Precisely, if you
++want a libdkim return status to generate an error, include that
++letter, where A is the first return status (DKIM_SUCCESS), B is the
++second (DKIM_FINISHED_BODY), etc.  The letter should be uppercase if you
++want a permanent error to be returned, and lowercase if
++you want a temporary error to be returned (exit code 88). If you omit the letter,
++\fBqmail-dkim\fR will not issue any error inspite of DKIM verification failure. It
++will return success and the email will get delivered. The complete set of letters
++with the corresponding return status is given below
++
++ A - DKIM_SUCCESS                        - Function executed successfully
++ B - DKIM_FINISHED_BODY                  - process result: no more message
++                                           body is needed
++ C - DKIM_PARTIAL_SUCCESS                - verify result: at least one
++                                           but not all signatures verified
++ D - DKIM_NEUTRAL                        - verify result: no signatures
++                                           verified but message is
++                                           not suspicious
++ E - DKIM_SUCCESS_BUT_EXTRA              - signature result: signature
++                                           verified but it did not
++                                           include all of the body
++ F - DKIM_3PS_SIGNATURE                  - 3rd-party signature
++ G - DKIM_FAIL                           - Function failed to execute
++ H - DKIM_BAD_SYNTAX                     - signature error: DKIM-Signature
++                                           could not parse or has bad
++                                           tags/values
++ I - DKIM_SIGNATURE_BAD                  - signature error: RSA verify
++                                           failed
++ J - DKIM_SIGNATURE_BAD_BUT_TESTING      - signature error: RSA verify
++                                           failed but testing
++ K - DKIM_SIGNATURE_EXPIRED              - signature error: x= is old
++ L - DKIM_SELECTOR_INVALID               - signature error: selector doesn't
++                                           parse or contains invalid values
++ M - DKIM_SELECTOR_GRANULARITY_MISMATCH  - signature error: selector
++                                           g= doesn't match i=
++ N - DKIM_SELECTOR_KEY_REVOKED           - signature error: selector
++                                           p= empty
++ O - DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG  - signature error: selector domain
++                                           name too long to request
++ P - DKIM_SELECTOR_DNS_TEMP_FAILURE      - signature error: temporary dns
++                                           failure requesting selector
++ Q - DKIM_SELECTOR_DNS_PERM_FAILURE      - signature error: permanent dns
++                                           failure requesting selector
++ R - DKIM_SELECTOR_PUBLIC_KEY_INVALID    - signature error: selector
++                                           p= value invalid or wrong format
++ S - DKIM_NO_SIGNATURES                  - no signatures
++ T - DKIM_NO_VALID_SIGNATURES            - no valid signatures
++ U - DKIM_BODY_HASH_MISMATCH             - sigature verify error: message
++                                           body does not hash to bh value
++ V - DKIM_SELECTOR_ALGORITHM_MISMATCH    - signature error: selector
++                                           h= doesn't match signature a=
++ W - DKIM_STAT_INCOMPAT                  - signature error: incompatible v=
++ X - DKIM_UNSIGNED_FROM                  - signature error: not all message's
++                                           From headers in signature
++
++For example, if you want to permanently reject messages that have a
++signature that is expired, include the letter 'K' in the
++.B DKIMVERIFY
++environment variable.  A conservative set of letters is
++.BR FGHIKLMNOQRTUVWjp .
++Reject permanently 3PS, FAILURE, SYNTAX, SIGNATURE_BAD, SIGNATURE_EXPIRED, SELECTOR_INVALID,
++GRANULARITY_MISMATCH, SELECTOR_KEY_REVOKED, DOMAIN_NAME_TOO_LONG, SELECTOR_PUBLIC_KEY_INVALID,
++NO_VALID_SIGNATURES and BODY_HASH_MISMATCH errors, and temporarily SIGNATURE_BAD_BUT_TESTING and DNS_TEMP_FAILURE .
++Add in
++.B S
++if you want to reject messages that do not have a DKIM signature. You can use the control files
++signaturedomains and nosignature domains (See Below) to further fine tune the action to be
++taken when a mail arrives with no DKIM signature.  Note that
++.B qmail-dkim
++always inserts the 
++.B DKIM-Status
++header, so that messages can be
++rejected later at delivery time, or in the mail reader. In that case you may set
++.B DKIMVERIFY
++to an empty string. If you want to check all message's From header in signature set the
++\fBUNSIGNED_FROM\fR environment variable to an empty string.
++
++qmail-dkim supports signing practice which can be additonall checked when a signature
++verifcation fails -
++
++.BR "SSP - Sender Signing Practice"
++
++and
++
++.BR "ADSP - Author Domain Signing Practice" .
++
++When a signature fails to verify for a message, you can use SSP/ADSP to determine if the message is suspicious or not.
++To verify a message against SSP/ADSP, set the
++.B DKIMPRACTICE
++environment variable to the desired set of letters allowed for DKIMVERIFY environment variable.
++SSP/ADSP should be used only when signature verification fails. SSP/ADSP should be invoked only when libdkim returns the
++error codes (F,G,H,I,J,K,L,M,N,P,Q,R,S,T,U,V,W,X) for signature verification. In case you want to test
++against SSP/ADSP only for DKIM_NO_SIGNATURE and DKIM_NO_VALID_SIGNATURE
++set the environment variable 
++.BR DKIMPRACTICE="ST" .
++If you want automatic behaviour, set DKIMADSPERROR to an empty string. In this case ADSP/SSP will be used when return code
++matches "FGHIJKLMNPQRSTUVWX".
++.B qmail-dkim
++uses ADSP as the default signing practice. You can override this by setting the SIGN_PRACTICE to ssp, adsp, local (lowercase).
++if you set SIGN_PRACTICE to \fIlocal\fB,
++.B qmail-dkim
++will check the domain against the control file
++.I signaturedomains
++(See Below). If the domain is found listed in
++.I signaturedomains
++.B qmail-dkim
++will bypass ADSP/SSP and return DKIM_FAIL if signature fails to verify. Setting SIGN_PRACTICE
++to anything else will cause
++.B qmail-dkim
++to disable Signing Practice.
++
++If ADSP or SSP is checked,
++.B qmail-dkim
++will insert the
++.B X-DKIM-ADSP
++or
++.B X-DKIM-SSP
++header as given below
++
++ A - DKIM_SUCCESS             - Message passes ADSP test
++ B - DKIM_ADSP_UNKNOWN        - some messages may be signed
++ C - DKIM_ADSP_ALL            - All message are signed with author signature 
++ D - DKIM_ADSP_DISCARDABLE    - messages which fail verification are Discardable
++ E - DKIM_ADSP_SCOPE          - domain is out of scope
++ F - DKIM_ADSP_TEMPFAIL       - Temporary Error 
++
++ or
++
++ A - DKIM_SUCCESS            - Message passes ADSP test
++ B - DKIM_SSP_UNKNOWN        - some messages may be signed
++ C - DKIM_SSP_ALL            - All message are signed with author signature 
++ D - DKIM_SSP_STRICT         - messages which fail verification are Discardable
++ E - DKIM_SSP_SCOPE          - domain is out of scope
++ F - DKIM_SSP_TEMPFAIL       - Temporary Error 
++
++You can have a control file
++.I signaturedomains
++containing a list of domains which you know are sure to sign messages using DKIM. If a message comes
++from a domain listed in
++.IR signaturedomains ,
++and the signature fails verification (any of DKIM failure status), 
++.B qmail-dkim
++will bypass ADSP/SSP checks and return DKIM_FAIL. The name of this control file can be
++overriden by the environment variable
++.BR SIGNATUREDOMAINS .
++
++You can have a control file
++.I nosignaturedomains
++containing a list of domains which you know are sure not to sign messages using DKIM.
++If a message comes from a domain listed in
++.IR signaturedomains ,
++and does not have a DKIM-Signature header, 
++.B qmail-dkim
++will bypass ADSP/SSP checks and return DKIM_NEUTRAL. The wildcard entry '*' in this file, will
++result in all mails which do not have a signature to pass DKIM test (unless the domain is listed
++in the control file
++.BR signaturedomains ).
++The name of this control file can be overriden by the environment variable
++.BR NOSIGNATUREDOMAINS .
++
++Typically, you would sign messages generated on-host by setting
++.B DKIMSIGN
++in the environment before running an email program.  DKIMSIGN will be carried
++through qmail's sendmail emulation through 
++.B qmail-inject
++to
++.BR qmail-dkim .
++You would also set it for
++.B qmail-smtpd
++at the same time
++.B RELAYCLIENT
++is set, most often in the tcpserver cdb file.  If a host is authorized
++to relay, you probably want to sign messages sent by that host.
++.B DKIMVERIFY
++should be set for all other hosts.
++
++If neither
++.B DKIMSIGN
++nor
++.B DKIMVERIFY
++are set, then
++.B DKIMSIGN
++will be set to QMAILHOME/control/domainkeys/%/default. The % will be replaced by the domain in the
++From: header. If such a file does not exist, then it will be set to
++QMAILHOME/control/domainkeys/default. If such a private key exists, it will be used to sign the
++domain. You can also set \fBDKIMKEY\fR to chose a key different from
++QMAILHOME/control/domainkeys/%/default. \fBDKIMKEY\fR can also have % character that will be
++replaced by the domain in the From: header. If the private key does not exist, qmail-dkim
++will exit with return code 32.
++
++By default
++.B qmail-dkim
++will use all of the headers when signing a message.
++
++.B qmail-dkim
++will ordinarily spawn
++.BR qmail-queue ,
++but if DKIMQUEUE is set in the environment,
++the program that it points to will be executed instead.
++
++.SH "EXIT CODES"
++.B qmail-dkim
++returns the same exit codes as qmail-queue with these additions:
++.TP 5
++.B 32
++The private key file does not exist.
++.TP 5
++.B 57
++Trouble waiting for qmail-queue to exit.
++.TP 5
++.B 58
++Unable to vfork.
++.TP 5
++.B 59
++Unable to create a pipe to qmail-queue.
++.SH "SEE ALSO"
++addresses(5),
++envelopes(5),
++qmail-header(5),
++dknewkey(8),
++dktest(8),
++qmail-inject(8),
++qmail-qmqpc(8),
++qmail-queue(8),
++qmail-send(8),
++qmail-smtpd(8),
++qmail-dk(8),
++domain-keys(5)
++
++.SH "AUTHORS"
++
++Manvendra Bhangui.
++.SH PROBLEMS
++Problems with
++.B qmail-dkim
++should be forwarded to "Manvendra Bhangui" <mbhangui@gmail.com>
+diff -ruN ../netqmail-1.06-original/qmail-dkim.c netqmail-1.06/qmail-dkim.c
+--- ../netqmail-1.06-original/qmail-dkim.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-dkim.c	2018-04-03 14:46:51.373411639 +0200
+@@ -0,0 +1,1388 @@
++/*
++ * $Log: qmail-dkim.c,v $
++ * Revision 1.47  2016-06-03 09:57:59+05:30  Cprogrammer
++ * moved qmail-multi to sbin
++ *
++ * Revision 1.46  2016-05-17 19:44:58+05:30  Cprogrammer
++ * use auto_control, set by conf-control to set control directory
++ *
++ * Revision 1.45  2016-03-01 18:48:02+05:30  Cprogrammer
++ * added env variable UNSIGNED_SUBJECT to verify dkim without subject field
++ *
++ * Revision 1.44  2015-12-15 16:05:58+05:30  Cprogrammer
++ * increased buffer size for long header issue
++ *
++ * Revision 1.43  2014-01-22 22:45:01+05:30  Cprogrammer
++ * treat AUTHINFO environment like RELAYCLIENT environment variable
++ *
++ * Revision 1.42  2013-10-01 17:11:24+05:30  Cprogrammer
++ * fixed QMAILQUEUE recursion
++ *
++ * Revision 1.41  2013-09-16 22:16:35+05:30  Cprogrammer
++ * corrected logic for RELAYCLIENT_NODKIMVERIFY
++ *
++ * Revision 1.40  2013-09-13 16:34:35+05:30  Cprogrammer
++ * turn off verification if RELAYCLIENT, DKIMVERIFY and RELAYCLIENT_NODKIMVERIFY is set
++ *
++ * Revision 1.39  2013-08-18 15:53:30+05:30  Cprogrammer
++ * revert back to default verification mode if both dksign, dkverify are not set
++ *
++ * Revision 1.38  2013-08-17 15:00:33+05:30  Cprogrammer
++ * BUG - corrected location of private key when % sign is removed
++ *
++ * Revision 1.37  2013-01-24 22:37:22+05:30  Cprogrammer
++ * BUG (fix by Piotr Gronek) - DKIM_FREE(results) called before call to ParseTagValues()
++ * alternate code for DKIMSIGN selector file name
++ *
++ * Revision 1.36  2012-08-16 08:01:46+05:30  Cprogrammer
++ * do not skip X-Mailer headers
++ *
++ * Revision 1.35  2011-11-10 14:32:08+05:30  Cprogrammer
++ * BUG ssout to be assigned only after pidopen()
++ *
++ * Revision 1.34  2011-11-07 09:35:59+05:30  Cprogrammer
++ * set ssout, sserr, ssin before executing other functions
++ *
++ * Revision 1.33  2011-07-29 09:29:17+05:30  Cprogrammer
++ * fixed key file name
++ *
++ * Revision 1.32  2011-07-28 19:36:36+05:30  Cprogrammer
++ * BUG - fixed opening of private key with absolute path
++ *
++ * Revision 1.31  2011-07-22 14:40:05+05:30  Cprogrammer
++ * fixed checking of private key file
++ *
++ * Revision 1.30  2011-06-04 14:49:48+05:30  Cprogrammer
++ * remove '%' sign from private key if key not found
++ *
++ * Revision 1.29  2011-06-04 14:22:29+05:30  Cprogrammer
++ * added DKIM_UNSIGNED_FROM error code for dkimadspverify
++ *
++ * Revision 1.28  2011-06-04 14:07:41+05:30  Cprogrammer
++ * added DKIM_UNSIGNED_FROM
++ *
++ * Revision 1.27  2011-02-10 23:39:59+05:30  Cprogrammer
++ * use DKIMKEY to override defult control/domainkeys/%/default
++ *
++ * Revision 1.26  2011-02-06 10:13:50+05:30  Cprogrammer
++ * BUG - signature was wrongly freed before being accessed.
++ *
++ * Revision 1.25  2011-02-05 09:47:47+05:30  Cprogrammer
++ * fixed SIGSEGV occuring for messages without body
++ *
++ * Revision 1.24  2010-11-02 18:45:14+05:30  Cprogrammer
++ * Improve DKIM signing/verification speed
++ *
++ * Revision 1.23  2010-07-21 08:59:57+05:30  Cprogrammer
++ * use CONTROLDIR environment variable instead of a hardcoded control directory
++ *
++ * Revision 1.22  2009-04-22 13:42:51+05:30  Cprogrammer
++ * made fd for custom error configurable through env variable ERROR_FD
++ *
++ * Revision 1.21  2009-04-21 09:05:48+05:30  Cprogrammer
++ * return relevant error message for reading private key
++ *
++ * Revision 1.20  2009-04-21 08:55:41+05:30  Cprogrammer
++ * return temporary error for temp failures
++ *
++ * Revision 1.19  2009-04-20 22:19:01+05:30  Cprogrammer
++ * made dkimopts global
++ *
++ * Revision 1.18  2009-04-16 13:48:32+05:30  Cprogrammer
++ * added dkim_setoptions() to set all DKIM options
++ *
++ * Revision 1.17  2009-04-07 11:36:56+05:30  Cprogrammer
++ * use TMPDIR env variable for tmp directory
++ *
++ * Revision 1.16  2009-04-05 12:52:17+05:30  Cprogrammer
++ * added preprocessor warning
++ *
++ * Revision 1.15  2009-04-04 00:33:44+05:30  Cprogrammer
++ * removed dk_strdup()
++ *
++ * Revision 1.14  2009-03-31 08:21:58+05:30  Cprogrammer
++ * set dkimsign when RELAYCLIENT is defined when both dkimsign and dkimverify are undefined
++ *
++ * Revision 1.13  2009-03-30 22:25:54+05:30  Cprogrammer
++ * made DKIM messages friendlier
++ *
++ * Revision 1.12  2009-03-30 14:47:59+05:30  Cprogrammer
++ * added descriptive text for original dkim error
++ *
++ * Revision 1.11  2009-03-29 19:20:43+05:30  Cprogrammer
++ * added nosignaturedomains
++ *
++ * Revision 1.10  2009-03-28 22:27:02+05:30  Cprogrammer
++ * use DKIMSIGN, DKIMVERIFY if RELAYCLIENT is not set
++ *
++ * Revision 1.9  2009-03-28 22:03:05+05:30  Cprogrammer
++ * fixed DKIM return codes
++ *
++ * Revision 1.8  2009-03-28 13:37:37+05:30  Cprogrammer
++ * call DKIMVerifyGetDetails() always
++ *
++ * Revision 1.7  2009-03-28 11:39:23+05:30  Cprogrammer
++ * set automatic setting of dkimsign, dkimverify variables based on RELAYCLIENT
++ *
++ * Revision 1.6  2009-03-28 11:35:58+05:30  Cprogrammer
++ * added ADSP/SSP
++ *
++ * Revision 1.5  2009-03-22 17:39:38+05:30  Cprogrammer
++ * set identity using basename of signature or environment variable DKIMIDENTITY
++ *
++ * Revision 1.4  2009-03-22 16:58:38+05:30  Cprogrammer
++ * fixed bug with verification
++ * report custom errors to qmail-queue through custom error interface
++ *
++ * Revision 1.3  2009-03-21 12:34:38+05:30  Cprogrammer
++ * use hasdkim.h for conditional compilation of dkim
++ *
++ * Revision 1.2  2009-03-20 22:35:57+05:30  Cprogrammer
++ * set error to DKIM_NO_SIGNATURE when DKIM-Signature is not present
++ *
++ * Revision 1.1  2009-03-18 13:54:49+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include <unistd.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include "sgetopt.h"
++#include "substdio.h"
++#include "open.h"
++#include "qmail.h"
++#include "sig.h"
++#include "scan.h"
++#include "case.h"
++#include "fmt.h"
++#include "fd.h"
++#include "alloc.h"
++#include "str.h"
++#include "stralloc.h"
++#include "datetime.h"
++#include "now.h"
++#include "wait.h"
++#include "auto_qmail.h"
++#include "env.h"
++#include "control.h"
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++#include "dkim.h"
++
++#define DEATH 86400	/*- 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
++#define ADDR 1003
++#define HAVE_EVP_SHA256
++#define strncasecmp(x,y,z) case_diffb((x), (z), (y))
++#define strcasecmp(x,y)    case_diffs((x), (y))
++
++char            inbuf[4096];
++char            outbuf[256];
++char            errbuf[256];
++struct substdio ssin;
++struct substdio ssout;
++struct substdio sserr;
++
++datetime_sec    starttime;
++struct datetime dt;
++unsigned long   mypid;
++unsigned long   uid;
++char           *pidfn;
++int             messfd;
++int             readfd;
++DKIMContext     ctxt;
++
++char          **MakeArgs(char *);
++void            FreeMakeArgs(char **);
++
++
++void
++die(int e, int what)
++{
++	if (!what)
++		_exit(e);
++	(what == 1 ? DKIMSignFree : DKIMVerifyFree) (&ctxt);
++	_exit(e);
++}
++
++void
++die_write()
++{
++	die(53, 0);
++}
++
++void
++die_read()
++{
++	die(54, 0);
++}
++
++void
++sigalrm()
++{
++	/*- thou shalt not clean up here */
++	die(52, 0);
++}
++
++void
++sigbug()
++{
++	die(81, 0);
++}
++
++void
++custom_error(char *flag, char *status, char *code)
++{
++	char           *c;
++
++	if (substdio_put(&sserr, flag, 1) == -1)
++		die_write();
++	if (substdio_put(&sserr, "qmail-dkim: ", 12) == -1)
++		die_write();
++	if (substdio_puts(&sserr, status) == -1)
++		die_write();
++	if (code) {
++		if (substdio_put(&sserr, " (#", 3) == -1)
++			die_write();
++		c = (*flag == 'Z') ? "4" : "5";
++		if (substdio_put(&sserr, c, 1) == -1)
++			die_write();
++		if (substdio_put(&sserr, code + 1, 4) == -1)
++			die_write();
++		if (substdio_put(&sserr, ")", 1) == -1)
++			die_write();
++	}
++	if (substdio_flush(&sserr) == -1)
++		die_write();
++	return;
++}
++
++int DKIM_CALL
++SignThisHeader(const char *szHeader)
++{
++	if ((!strncasecmp((char *) szHeader, "X-", 2) 
++			&& strncasecmp((char *) szHeader, "X-Mailer", 8))
++		|| strncasecmp((char *) szHeader, "Received:", 9) == 0
++		|| strncasecmp((char *) szHeader, "Authentication-Results:", 23) == 0
++		|| strncasecmp((char *) szHeader, "Return-Path:", 12) == 0) {
++		return 0;
++	}
++	return 1;
++}
++
++void
++maybe_die_dkim(e)
++	int             e;
++{
++	switch (e)
++	{
++	case DKIM_OUT_OF_MEMORY:
++	case DKIM_BUFFER_TOO_SMALL:
++		_exit (51);
++	case DKIM_INVALID_CONTEXT:
++		custom_error("Z", "DKIMContext structure invalid for this operation (#4.3.0)", 0);
++		_exit(88);
++	case DKIM_NO_SENDER:
++		custom_error("Z", "Could not find From: or Sender: header in message (#5.1.7)", 0);
++		_exit(88);
++	case DKIM_BAD_PRIVATE_KEY:
++		custom_error("D", "Could not parse private key (#5.7.5)", 0);
++		_exit(88);
++	default:
++		return;
++	}
++}
++
++unsigned int
++pidfmt(s, seq)
++	char           *s;
++	unsigned long   seq;
++{
++	unsigned int    i;
++	unsigned int    len;
++	char           *tmpdir;
++
++	if (!(tmpdir = env_get("TMPDIR")))
++		tmpdir = "/tmp";
++	len = 0;
++	i = fmt_str(s, tmpdir);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, "/qmail-dkim.");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, mypid);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, ".");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, starttime);
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_str(s, ".");
++	len += i;
++	if (s)
++		s += i;
++	i = fmt_ulong(s, seq);
++	len += i;
++	if (s)
++		s += i;
++	++len;
++	if (s)
++		*s++ = 0;
++
++	return len;
++}
++
++void
++pidopen()
++{
++	unsigned int    len;
++	unsigned long   seq;
++
++	seq = 1;
++	len = pidfmt((char *) 0, seq);
++	if (!(pidfn = alloc(len)))
++		die(51, 0);
++	for (seq = 1; seq < 10; ++seq) {
++		if (pidfmt((char *) 0, seq) > len)
++			die(81, 0); /*- paranoia */
++		pidfmt(pidfn, seq);
++		if ((messfd = open_excl(pidfn)) != -1)
++			return;
++	}
++	die(63, 0);
++}
++
++char            tmp[FMT_ULONG];
++char           *dkimsign = 0;
++char           *dkimverify = 0;
++char           *dkimadspverify = 0, *dkimpractice =  "FGHIJKLMNPQRSTUVWX";
++stralloc        dkimoutput = { 0 };  /*- DKIM-Signature */
++stralloc        dksignature = { 0 }; /*- content of private signature */
++stralloc        sigdomains = { 0 };  /*- domains which must have signatures */
++stralloc        nsigdomains = { 0 }; /*- domains which do not have signatures */
++stralloc        dkimopts = { 0 };
++char           *dkimqueue = 0;
++
++static void
++write_signature(char *domain, char *keyfn)
++{
++	char           *pSig;
++	int             i;
++	static stralloc keyfnfrom = { 0 };
++
++	if (keyfn[0] != '/') {
++		if (!stralloc_copys(&keyfnfrom, "control/"))
++			die(51, 1);
++	}
++	i = str_chr(keyfn, '%');
++	if (keyfn[i]) {
++		if (keyfn[0] == '/') {
++			if (!stralloc_copyb(&keyfnfrom, keyfn, i))
++				die(51, 1);
++		} else
++		if (!stralloc_catb(&keyfnfrom, keyfn, i))
++			die(51, 1);
++		if (!stralloc_cats(&keyfnfrom, domain))
++			die(51, 1);
++		if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
++			die(51, 1);
++		if (!stralloc_0(&keyfnfrom))
++			die(51, 1);
++		if (access(keyfnfrom.s, F_OK)) {
++			/*- since file does not exists remove '%' sign */
++			keyfnfrom.len = 8;
++			if (keyfn[0] == '/') {
++				if (!stralloc_copyb(&keyfnfrom, keyfn, i))
++					die(51, 1);
++			} else
++			if (!stralloc_catb(&keyfnfrom, keyfn, i))
++				die(51, 1);
++			if ((i - 1) > 0 && keyfn[i - 1] == '/' && keyfn[i + 1] == '/')
++				i++;
++			if (!stralloc_cats(&keyfnfrom, keyfn + i + 1))
++				die(51, 1);
++			if (!stralloc_0(&keyfnfrom))
++				die(51, 1);
++		} 
++	} else {
++		if (keyfn[0] == '/') {
++			if (!stralloc_copys(&keyfnfrom, keyfn))
++				die(51, 1);
++		} else
++		if (!stralloc_cats(&keyfnfrom, keyfn))
++			die(51, 1);
++		if (!stralloc_0(&keyfnfrom))
++			die(51, 1);
++	}
++	switch (control_readnativefile(&dksignature, keyfnfrom.s, 1))
++	{
++	case 0: /*- missing signature file */
++		DKIMSignFree(&ctxt);
++		/*
++		 * You may have multiple domains, but may chose to sign
++		 * only for few domains which have the key present. Do not
++		 * treat domains with missing key as an error.
++		 */
++		if (keyfn[i])
++			return;
++		die(32, 0);
++	case 1:
++		break;
++	default:
++		custom_error("Z", "Unable to read private key. (#4.3.0)", 0);
++		DKIMSignFree(&ctxt);
++		_exit(88);
++	}
++	for (i = 0; i < dksignature.len; i++) {
++		if (dksignature.s[i] == '\0')
++			dksignature.s[i] = '\n';
++	}
++	if (!stralloc_0(&dksignature))
++		die(51, 1);
++	i = DKIMSignGetSig2(&ctxt, dksignature.s, &pSig);
++	maybe_die_dkim(i);
++	if (pSig) {
++		if (!stralloc_catb(&dkimoutput, pSig, str_len(pSig)))
++			die(51, 1);
++		if (!stralloc_cats(&dkimoutput, "\n"))
++			die(51, 1);
++	}
++	DKIMSignFree(&ctxt);
++}
++
++#include <openssl/evp.h>
++#define DKIM_MALLOC(s)     OPENSSL_malloc(s)
++#define DKIM_MFREE(s)      OPENSSL_free(s); s = NULL;
++char           *dns_text(char *);
++
++int
++ParseTagValues(char *list, char *letters[], char *values[])
++{
++	char           *tmp, *ptr, *key;
++	int             i;
++
++	/*- start with all args unset */
++	for (i = 0; letters[i]; i++)
++		values[i] = 0;
++	key = 0;
++	for(ptr = list;*ptr;) {
++		if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')) /*- FWS */
++			*ptr++ = 0;
++		if (!key)
++			key = ptr;
++		if (*ptr == '=') {
++			*ptr = 0;
++			for (i = 0;letters[i];i++) {
++				if (!str_diff(letters[i], key)) {
++					ptr++;
++					for (;*ptr;) {
++						if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')) {
++							ptr++;
++							continue;
++						}
++						break;
++					}
++					values[i] = ptr;
++					for(;*ptr && *ptr != ';';ptr++);
++					tmp = ptr;
++					if (*ptr)
++						*ptr++ = 0;
++					for(;tmp != values[i];tmp--) { /*- RFC 4871 3.2 */
++						if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\r') || (*tmp == '\n')) {
++							*tmp = 0;
++							continue;
++						}
++						break;
++					}
++					key = 0;
++					break;
++				}
++			}
++		} else
++			ptr++;
++	}
++	return (0);
++}
++
++int
++checkSSP(char *domain, int *bTesting)
++{
++	char           *query, *results;
++	char           *tags[] = { "dkim", "t", 0};
++	char           *values[2];
++	int             bIsParentSSP = 0, iSSP = DKIM_SSP_UNKNOWN;
++
++	*bTesting = 0;
++	if (!(query = DKIM_MALLOC(str_len("_ssp._domainkey.") + str_len(domain) + 1)))
++		die(51, 0);
++	sprintf(query, "_ssp._domainkey.%s", domain);
++	results = dns_text(query);
++	DKIM_MFREE(query);
++	if (!str_diff(results, "e=temp;")) {
++		DKIM_MFREE(results);
++		return DKIM_SSP_TEMPFAIL;
++	} else
++	if (!str_diff(results, "e=perm;")) {
++		results = dns_text(domain);
++		if (!str_diff(results, "e=temp;")) {
++			DKIM_MFREE(results);
++			return DKIM_SSP_TEMPFAIL;
++		} else
++		if (!str_diff(results, "e=perm;")) {
++			DKIM_MFREE(results);
++			return DKIM_SSP_SCOPE;
++		}
++		bIsParentSSP = 1;
++	}
++	/* 
++	 * PG.1 2013-01-03
++	 * Bug fix by Piotr Gronek, Faculy of Physics & Applied Computer Science, Poland 2013-01-03
++	 * Deallocating storage for 'results' here is premature - moved beyond last reference to it.
++	 *
++	 */
++	if (!ParseTagValues(results, tags, values)) {
++		DKIM_MFREE(results);
++		return DKIM_SSP_UNKNOWN;
++	}
++	DKIM_MFREE(results);
++	if (values[0] != NULL) {
++		if (strcasecmp(values[0], "all") == 0)
++			iSSP = DKIM_SSP_ALL;
++		else
++		if (strcasecmp(values[0], "strict") == 0)
++			iSSP = DKIM_SSP_STRICT;
++	}
++	// flags
++	if (values[1] != NULL) {
++		char           *s, *p;
++		for (p = values[1], s = values[1]; *p; p++) {
++			if (*p == '|')
++				*p = 0;
++			else
++				continue;
++			if (!str_diff(s, "y"))
++				*bTesting = 1;
++			else
++			if (!str_diff(s, "s")) {
++				if (bIsParentSSP) {
++					/* 
++					 * this is a parent's SSP record that should not apply to subdomains
++					 * the message is non-suspicious
++					 */
++					*bTesting = 0;
++					return (DKIM_SSP_UNKNOWN);
++				}
++			}
++			s = p + 1;
++		}
++	}
++	return iSSP;
++}
++
++int
++checkADSP(char *domain)
++{
++	char           *query, *results;
++	char           *tags[] = { "dkim", 0};
++	char           *values[1];
++
++	results = dns_text(domain);
++	if (!str_diff(results, "e=perm;")) {
++		DKIM_MFREE(results);
++		return DKIM_ADSP_SCOPE;
++	}
++	else
++	if (!str_diff(results, "e=temp;")) {
++		DKIM_MFREE(results);
++		return DKIM_ADSP_TEMPFAIL;
++	}
++	if (!(query = DKIM_MALLOC(str_len("_adsp._domainkey.") + str_len(domain) + 1)))
++		die(51, 0);
++	sprintf(query, "_adsp._domainkey.%s", domain);
++	results = dns_text(query);
++	DKIM_MFREE(query);
++	if (!str_diff(results, "e=perm;")) {
++		DKIM_MFREE(results);
++		return DKIM_ADSP_SCOPE;
++	} else
++	if (!str_diff(results, "e=temp;")) {
++		DKIM_MFREE(results);
++		return DKIM_ADSP_TEMPFAIL;
++	}
++	/* 
++	 * PG.1 2013-01-03
++	 * Bug fix by Piotr Gronek, Faculy of Physics & Applied Computer Science, Poland 2013-01-03
++	 *
++	 * Deallocating storage for 'results' here is premature - moved beyond last reference to it.
++	 *
++	 */
++	if (!ParseTagValues(results, tags, values)) {
++		DKIM_MFREE(results);
++		return DKIM_SSP_UNKNOWN;
++	}
++	DKIM_MFREE(results);
++	if (values[0] != NULL) {
++		if (strcasecmp(values[0], "all") == 0)
++			return (DKIM_ADSP_ALL);
++		else
++		if (strcasecmp(values[0], "discardable") == 0)
++			return (DKIM_ADSP_DISCARDABLE);
++	}
++	return DKIM_ADSP_UNKNOWN; /*- No ADSP Record */
++}
++
++void
++dkimverify_exit(int dkimRet, char *status, char *code)
++{
++	if (dkimRet < 0) {
++		if (dkimverify[str_chr(dkimverify, 'F' - dkimRet)]) {
++			custom_error("D", status, code);
++			die(88, 0);
++		}
++		if (dkimverify[str_chr(dkimverify, 'f' - dkimRet)]) {
++			custom_error("Z", status, code);
++			die(88, 0);
++		}
++	} else {
++		if (dkimverify[str_chr(dkimverify, 'A' + dkimRet)]) {
++			custom_error("D", status, code);
++			die(88, 0);
++		}
++		if (dkimverify[str_chr(dkimverify, 'a' + dkimRet)]) {
++			custom_error("Z", status, code);
++			die(88, 0);
++		}
++	}
++}
++
++void
++writeHeaderNexit(int ret, int origRet, int resDKIMSSP, int resDKIMADSP, int useSSP, int useADSP)
++{
++	char           *dkimStatus = 0, *sspStatus = 0, *adspStatus = 0, *code = 0, *orig = 0;
++	char            strnum[FMT_ULONG];
++
++	switch (ret)
++	{
++	case DKIM_SUCCESS:			/*- 0 */ /*- A */
++		dkimStatus = "good        ";
++		code = "X.7.0";
++		break;
++	case DKIM_FINISHED_BODY:	/*- 1 process result: no more message body is needed */
++		dkimStatus = "process result: no more message body is needed";
++		code = "X.7.0";
++		break;
++	case DKIM_PARTIAL_SUCCESS:	/*- 2 verify result: at least one but not all signatures verified */
++		dkimStatus = "verify result: at least none but not all signatures verified";
++		code = "X.7.0";
++		break;
++	case DKIM_NEUTRAL:			/*- 3 verify result: no signatures verified but message is not suspicious */
++		dkimStatus = "verify result: no signatures verified but message is not suspicious";
++		code = "X.7.0";
++		break;
++	case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
++		dkimStatus = "signature result: signature verified but it did not include all of the body";
++		code = "X.7.0";
++		break;
++	case DKIM_FAIL:				/*- -1 */ /*- F */
++		dkimStatus = "DKIM Signature verification failed";
++		code = "X.7.0";
++		break;
++	case DKIM_BAD_SYNTAX:		/*- -2 */ /*- G */
++		dkimStatus = "signature error: DKIM-Signature could not parse or has bad tags/values";
++		code = "X.7.5";
++		break;
++	case DKIM_SIGNATURE_BAD:	/*- -3 */
++		dkimStatus = "signature error: RSA verify failed";
++		code = "X.7.5";
++		break;
++	case DKIM_SIGNATURE_BAD_BUT_TESTING:
++		dkimStatus = "signature error: RSA verify failed but testing";
++		code = "X.7.5";
++		break;
++	case DKIM_SIGNATURE_EXPIRED:
++		dkimStatus = "signature error: x= is old";
++		code = "X.7.5";
++		break;
++	case DKIM_SELECTOR_INVALID:
++		dkimStatus = "signature error: selector doesn't parse or contains invalid values";
++		code = "X.7.5";
++		break;
++	case DKIM_SELECTOR_GRANULARITY_MISMATCH:
++		dkimStatus = "signature error: selector g= doesn't match i=";
++		code = "X.7.5";
++		break;
++	case DKIM_SELECTOR_KEY_REVOKED:
++		dkimStatus = "signature error: selector p= empty";
++		code = "X.7.5";
++		break;
++	case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
++		dkimStatus = "signature error: selector domain name too long to request";
++		code = "X.7.0";
++		break;
++	case DKIM_SELECTOR_DNS_TEMP_FAILURE:
++		dkimStatus = "signature error: temporary dns failure requesting selector";
++		code = "X.7.0";
++		break;
++	case DKIM_SELECTOR_DNS_PERM_FAILURE:
++		dkimStatus = "signature error: permanent dns failure requesting selector";
++		code = "X.7.0";
++		break;
++	case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
++		dkimStatus = "signature error: selector p= value invalid or wrong format";
++		code = "X.7.5";
++		break;
++	case DKIM_NO_SIGNATURES:
++		dkimStatus = "no signatures";
++		code = "X.7.5";
++		break;
++	case DKIM_NO_VALID_SIGNATURES:
++		dkimStatus = "no valid signatures";
++		code = "X.7.5";
++		break;
++	case DKIM_BODY_HASH_MISMATCH:
++		dkimStatus = "signature verify error: message body does not hash to bh value";
++		code = "X.7.7";
++		break;
++	case DKIM_SELECTOR_ALGORITHM_MISMATCH:
++		dkimStatus = "signature error: selector h= doesn't match signature a=";
++		code = "X.7.7";
++		break;
++	case DKIM_STAT_INCOMPAT:
++		dkimStatus = "signature error: incompatible v=";
++		code = "X.7.6";
++		break;
++	case DKIM_UNSIGNED_FROM:
++		dkimStatus = "signature error: not all message's From headers in signature";
++		code = "X.7.7";
++		break;
++	default:
++		dkimStatus = "error";
++		code = "X.3.0";
++		break;
++	}
++	if (useSSP && resDKIMSSP != -1) {
++		switch(resDKIMSSP)
++		{
++			case DKIM_SSP_ALL:
++				sspStatus = (char *) "all;";
++				break;
++			case DKIM_SSP_STRICT:
++				sspStatus = (char *) "strict;";
++				break;
++			case DKIM_SSP_SCOPE:
++				sspStatus = (char *) "out of scope;";
++				break;
++			case DKIM_SSP_TEMPFAIL:
++				sspStatus = (char *) "temporary failure;";
++				break;
++			case DKIM_SSP_UNKNOWN:
++			default:
++				sspStatus = (char *) "unknown;";
++				break;
++		}
++	}
++	if (useADSP && resDKIMADSP != -1) {
++		switch(resDKIMADSP)
++		{
++			case DKIM_ADSP_ALL:
++				adspStatus = (char *) "all;";
++				break;
++			case DKIM_ADSP_DISCARDABLE:
++				adspStatus = (char *) "discardable;";
++				break;
++			case DKIM_ADSP_SCOPE:
++				adspStatus = (char *) "out of scope;";
++				break;
++			case DKIM_ADSP_TEMPFAIL:
++				adspStatus = (char *) "temporary failure;";
++				break;
++			case DKIM_ADSP_UNKNOWN:
++			default:
++				adspStatus = (char *) "unknown ;";
++				break;
++		}
++	}
++	if (!stralloc_copys(&dkimoutput, "DKIM-Status: "))
++		die(51, 0);
++	if (!stralloc_cats(&dkimoutput, dkimStatus))
++		die(51, 0);
++	if (origRet != DKIM_MAX_ERROR && ret != origRet) {
++		if (!stralloc_cats(&dkimoutput, "\n\t(old="))
++			die(51, 0);
++		switch (origRet)
++		{
++		case DKIM_SUCCESS:			/*- 0 */ /*- A */
++			orig = "SUCCESS";
++			break;
++		case DKIM_FINISHED_BODY:	/*- 1 process result: no more message body is needed */
++			orig = "FINISHED BODY";
++			break;
++		case DKIM_PARTIAL_SUCCESS:	/*- 2 verify result: at least one but not all signatures verified */
++			orig = "PARTIAL SUCCESS";
++			break;
++		case DKIM_NEUTRAL:			/*- 3 verify result: no signatures verified but message is not suspicious */
++			orig = "NEUTRAL";
++			break;
++		case DKIM_SUCCESS_BUT_EXTRA:/*- 4 signature result: signature verified but it did not include all of the body */
++			orig = "SUCCESS(BUT EXTRA)";
++			break;
++		case DKIM_FAIL:				/*- -1 */ /*- F */
++			orig = "FAIL";
++			break;
++		case DKIM_BAD_SYNTAX:		/*- -2 */ /*- G */
++			orig = "BAD SYNTAX";
++			break;
++		case DKIM_SIGNATURE_BAD:	/*- -3 */
++			orig = "SIGNATURE BAD";
++			break;
++		case DKIM_SIGNATURE_BAD_BUT_TESTING:
++			orig = "SIGNATURE BAD (TESTING)";
++			break;
++		case DKIM_SIGNATURE_EXPIRED:
++			orig = "SIGNATURE EXPIRED";
++			break;
++		case DKIM_SELECTOR_INVALID:
++			orig = "SELECTOR INVALID";
++			break;
++		case DKIM_SELECTOR_GRANULARITY_MISMATCH:
++			orig = "SELECTOR GRANULARITY MISMATCH";
++			break;
++		case DKIM_SELECTOR_KEY_REVOKED:
++			orig = "SELECTOR KEY REVOKED";
++			break;
++		case DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG:
++			orig = "DOMAIN NAME TOO LONG";
++			break;
++		case DKIM_SELECTOR_DNS_TEMP_FAILURE:
++			orig = "DNS TEMP FAILURE";
++			break;
++		case DKIM_SELECTOR_DNS_PERM_FAILURE:
++			orig = "DNS PERM FAILURE";
++			break;
++		case DKIM_SELECTOR_PUBLIC_KEY_INVALID:
++			orig = "PUBLIC KEY INVALID";
++			break;
++		case DKIM_NO_SIGNATURES:
++			orig = "NO SIGNATURES";
++			break;
++		case DKIM_NO_VALID_SIGNATURES:
++			orig = "NO VALID SIGNATURES";
++			break;
++		case DKIM_BODY_HASH_MISMATCH:
++			orig = "BODY HASH MISMATCH";
++			break;
++		case DKIM_SELECTOR_ALGORITHM_MISMATCH:
++			orig = "ALGORITHM MISMATCH";
++			break;
++		case DKIM_STAT_INCOMPAT:
++			orig = "STAT INCOMPAT";
++			break;
++		case DKIM_UNSIGNED_FROM:
++			orig = "UNSIGNED FROM";
++			break;
++		default:
++			orig = "Unkown error";
++			break;
++		}
++		if (!stralloc_cats(&dkimoutput, orig))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, ":"))
++			die(51, 0);
++		if (origRet < 0) {
++			if (!stralloc_cats(&dkimoutput, "-"))
++				die(51, 0);
++			strnum[fmt_ulong(strnum, 0 - origRet)] = 0;
++		} else
++			strnum[fmt_ulong(strnum, origRet)] = 0;
++		if (!stralloc_cats(&dkimoutput, strnum))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, ")"))
++			die(51, 0);
++	}
++	if (!stralloc_cats(&dkimoutput, "\n"))
++		die(51, 0);
++	if (useSSP && sspStatus) {
++		if (!stralloc_cats(&dkimoutput, "X-DKIM-SSP: "))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, sspStatus))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, "\n"))
++			die(51, 0);
++	}
++	if (useADSP && adspStatus) {
++		if (!stralloc_cats(&dkimoutput, "X-DKIM-ADSP: "))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, adspStatus))
++			die(51, 0);
++		if (!stralloc_cats(&dkimoutput, "\n"))
++			die(51, 0);
++	}
++	dkimverify_exit(ret, dkimStatus, code);
++	return;
++}
++
++int
++checkPractice(int dkimRet)
++{
++	char           *ptr;
++
++	if (!(ptr = env_get("DKIMPRACTICE")))
++		return (0);
++	else
++		dkimpractice = ptr;
++	if (!*ptr) {
++		if (dkimRet < 0 || dkimRet == DKIM_3PS_SIGNATURE)
++			return (1);
++		return (0);
++	}
++	if (dkimRet < 0) {
++		if (dkimpractice[str_chr(dkimpractice, 'F' - dkimRet)])
++			return (1);
++		if (dkimpractice[str_chr(dkimpractice, 'f' - dkimRet)])
++			return (1);
++	} else {
++		if (dkimpractice[str_chr(dkimpractice, 'A' + dkimRet)])
++			return (1);
++		if (dkimpractice[str_chr(dkimpractice, 'a' + dkimRet)])
++			return (1);
++	}
++	return (0);
++}
++
++static char    *binqqargs[2] = { "bin/qmail-queue", 0 };
++
++int
++dkim_setoptions(DKIMSignOptions *opts, char *signOptions)
++{
++	int             ch, argc;
++	char          **argv;
++
++	opts->nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
++	opts->nCanon = DKIM_SIGN_RELAXED;					/*- c */
++	opts->nIncludeBodyLengthTag = 0;					/*- l */
++	opts->nIncludeQueryMethod = 0;						/*- q */
++	opts->nIncludeTimeStamp = 0;						/*- t */
++	opts->nIncludeCopiedHeaders = 0;					/*- h */
++	opts->szIdentity[0] = '\0';
++	opts->expireTime = starttime + 604800;	// expires in 1 week
++	opts->nHash = DKIM_HASH_SHA1;
++	str_copy(opts->szRequiredHeaders, "NonExistent");
++	if (!signOptions)
++		return (0);
++	if (!stralloc_copys(&dkimopts, "dkim "))
++		die(51, 0);
++	if (!stralloc_cats(&dkimopts, signOptions))
++		die(51, 0);
++	if (!stralloc_0(&dkimopts))
++		die(51, 0);
++	if (!(argv = MakeArgs(dkimopts.s)))
++		die(51, 0);
++	for (argc = 0;argv[argc];argc++);
++#ifdef HAVE_EVP_SHA256
++	while ((ch = sgopt(argc, argv, "b:c:li:qthx:z:")) != sgoptdone) {
++#else
++	while ((ch = sgopt(argc, argv, "b:c:li:qthx:")) != sgoptdone) {
++#endif
++		switch (ch)
++		{
++		case 'b':
++			switch (*optarg)
++			{
++			case '1':
++				opts->nIncludeBodyHash = DKIM_BODYHASH_ALLMAN_1;
++				break;
++			case '2':
++				opts->nIncludeBodyHash = DKIM_BODYHASH_IETF_1;
++				break;
++			case '3':
++				opts->nIncludeBodyHash = DKIM_BODYHASH_BOTH;
++				break;
++			default:
++				FreeMakeArgs(argv);
++				return (1);
++			}
++			break;
++		case 'c':
++			switch (*optarg)
++			{
++			case 'r':
++				opts->nCanon = DKIM_SIGN_RELAXED;
++				break;
++			case 's':
++				opts->nCanon = DKIM_SIGN_SIMPLE;
++				break;
++			case 't':
++				opts->nCanon = DKIM_SIGN_RELAXED_SIMPLE;
++				break;
++			case 'u':
++				opts->nCanon = DKIM_SIGN_SIMPLE_RELAXED;
++				break;
++			default:
++				FreeMakeArgs(argv);
++				return (1);
++			}
++			break;
++		case 'l': /*- body length tag */
++			opts->nIncludeBodyLengthTag = 1;
++			break;
++		case 'q': /*- query method tag */
++			opts->nIncludeQueryMethod = 1;
++			break;
++		case 't': /*- timestamp tag */
++			opts->nIncludeTimeStamp = 1;
++			break;
++		case 'h':
++			opts->nIncludeCopiedHeaders = 1;
++			break;
++		case 'i':	/*- identity */
++			if (*optarg == '-') /* do not use i= tag */
++				opts->szIdentity[0] = '\0';
++			else
++				str_copyb(opts->szIdentity, optarg, sizeof(opts->szIdentity) - 1);
++			break;
++		case 'x': /*- expire time */
++			if (*optarg == '-')
++				opts->expireTime = 0;
++			else
++				opts->expireTime = starttime + atoi(optarg);
++			break;
++#ifdef HAVE_EVP_SHA256
++		case 'z': /*- sign w/ sha1, sha256 or both */
++			switch (*optarg)
++			{
++			case '1':
++				opts->nHash = DKIM_HASH_SHA1;
++				break;
++			case '2':
++				opts->nHash = DKIM_HASH_SHA256;
++				break;
++			case '3':
++				opts->nHash = DKIM_HASH_SHA1_AND_256;
++				break;
++			default:
++				FreeMakeArgs(argv);
++				return (1);
++			}
++			break;
++#endif
++		default:
++			FreeMakeArgs(argv);
++			return (1);
++		} /*- switch (ch) */
++	} /*- while (1) */
++	FreeMakeArgs(argv);
++	return (0);
++}
++
++int
++main(int argc, char *argv[])
++{
++	int             errfd, pim[2];
++	int             wstat;
++	int             resDKIMSSP = -1, resDKIMADSP = -1, useSSP = 0, useADSP = 0, accept3ps = 0;
++	int             sCount = 0, sSize = 0;
++	int             ret = 0, origRet = DKIM_MAX_ERROR, i, nSigCount = 0, len, token_len;
++	unsigned long   pid;
++	char           *selector, *p;
++	stralloc        dkimfn = {0};
++	DKIMSignOptions opts = { 0 };
++	DKIMVerifyDetails *pDetails;
++	DKIMVerifyOptions vopts = { 0 };
++
++	starttime = now();
++	sig_blocknone();
++	umask(033);
++	if (!(p = env_get("ERROR_FD")))
++		errfd = CUSTOM_ERR_FD;
++	else
++		scan_int(p, &errfd);
++	substdio_fdbuf(&sserr, write, errfd, errbuf, sizeof(errbuf));
++	if (chdir(auto_qmail) == -1)
++		die(61, 0);
++	dkimqueue = env_get("DKIMQUEUE");
++	if (dkimqueue && *dkimqueue)
++		binqqargs[0] = dkimqueue;
++	dkimsign = env_get("DKIMSIGN");
++	dkimverify = env_get("DKIMVERIFY");
++	p = (env_get("RELAYCLIENT") || env_get("AUTHINFO")) ? "" : 0;
++	if (dkimverify && p && env_get("RELAYCLIENT_NODKIMVERIFY")) {
++		execv(*binqqargs, binqqargs);
++		die(120, 0);
++	}
++	if (!dkimsign && !dkimverify && p) {
++		if (!(dkimsign = env_get("DKIMKEY"))) {
++			if (!stralloc_copys(&dkimfn, "domainkeys/%/default"))
++				die(51, 0);
++			if (!stralloc_0(&dkimfn))
++				die(51, 0);
++			dkimsign = dkimfn.s;
++		}
++	}
++	if (dkimsign) {
++		/* selector */
++		p = dkimsign;
++		selector = p;
++		while (*p) {
++			if (*p == '/' && *(p + 1))
++				selector = p + 1;
++			p++;
++		}
++		str_copyb(opts.szSelector, selector, sizeof(opts.szSelector) - 1);
++
++		if (dkim_setoptions(&opts, env_get("DKIMSIGNOPTIONS"))) {
++			custom_error("Z", "Invalid DKIMSIGNOPTIONS (#4.3.0)", 0);
++			_exit(88);
++		}
++		p = env_get("DKIMIDENTITY");
++		if (p && *p)
++			str_copyb(opts.szIdentity, p, sizeof(opts.szIdentity) - 1);
++		p = env_get("DKIMEXPIRE");
++		if (p && *p)
++			opts.expireTime = starttime + atol(p);
++		else
++		if (p)
++			opts.expireTime = 0;
++		opts.pfnHeaderCallback = SignThisHeader;
++		if (DKIMSignInit(&ctxt, &opts) != DKIM_SUCCESS) { /*- failed to initialize signature */
++			custom_error("Z", "dkim initialization failed (#4.3.0)", 0);
++			_exit(88);
++		}
++	} else {
++		char           *x;
++
++		if (!dkimverify)
++			dkimverify = "";
++		if (!(x = env_get("SIGN_PRACTICE")))
++			x = "adsp";
++		if (!str_diffn("adsp", x, 4)) {
++			useADSP = 1;
++			accept3ps = 1;
++		}
++		else
++		if (!str_diffn("ssp", x, 3)) {
++			useSSP = 1;
++			accept3ps = 1;
++		} else
++		if (!str_diffn("local", x, 5)) {
++			useSSP = 0;
++			useADSP = 0;
++			accept3ps = 1;
++		}
++		if (useADSP)
++			vopts.nCheckPractices = useADSP;
++		else
++		if (useSSP)
++			vopts.nCheckPractices = useSSP;
++		else
++			vopts.nCheckPractices = 0;
++		vopts.nAccept3ps = accept3ps;
++		vopts.pfnSelectorCallback = NULL;	/*- SelectorCallback; */
++		if (env_get("UNSIGNED_FROM"))
++			vopts.nAllowUnsignedFromHeaders = 1;
++		vopts.nSubjectRequired = env_get("UNSIGNED_SUBJECT") ? 0 : 1;
++		DKIMVerifyInit(&ctxt, &vopts);		/*- this is always successful */
++	}
++	/*- Initialization */
++	mypid = getpid();
++	uid = getuid();
++	datetime_tai(&dt, starttime);
++	sig_pipeignore();
++	sig_miscignore();
++	sig_alarmcatch(sigalrm);
++	sig_bugcatch(sigbug);
++	alarm(DEATH);
++	pidopen(); /*- fd = messfd */
++	if ((readfd = open_read(pidfn)) == -1)
++		die(63, dkimsign ? 1 : 2);
++	if (unlink(pidfn) == -1)
++		die(63, dkimsign ? 1 : 2);
++	substdio_fdbuf(&ssout, write, messfd, outbuf, sizeof(outbuf));
++	substdio_fdbuf(&ssin, read, 0, inbuf, sizeof(inbuf));
++	for (ret = 0;;) {
++		register int    n;
++		register char  *x;
++
++		if ((n = substdio_feed(&ssin)) < 0) {
++			(dkimsign ? DKIMSignFree : DKIMVerifyFree) (&ctxt);
++			die_read();
++		}
++		if (!n)
++			break;
++		x = substdio_PEEK(&ssin);
++		if (!ret) {
++			if ((ret = (dkimsign ? DKIMSignProcess : DKIMVerifyProcess) (&ctxt, x, n)) == DKIM_INVALID_CONTEXT)
++				(dkimsign ? DKIMSignFree : DKIMVerifyFree) (&ctxt);
++			maybe_die_dkim(ret);
++		}
++		if (substdio_put(&ssout, x, n) == -1) {
++			(dkimsign ? DKIMSignFree : DKIMVerifyFree) (&ctxt);
++			die_write();
++		}
++		substdio_SEEK(&ssin, n);
++	}
++	if (substdio_flush(&ssout) == -1) {
++		(dkimsign ? DKIMSignFree : DKIMVerifyFree) (&ctxt);
++		die_write();
++	}
++	if (dkimsign || dkimverify) {
++		if (dkimsign) {
++			char           *p;
++
++			if (!(p = DKIMSignGetDomain(&ctxt))) {
++				DKIMSignFree(&ctxt);
++				maybe_die_dkim(DKIM_INVALID_CONTEXT);
++			}
++			write_signature(p, dkimsign); /*- calls DKIMSignFree(&ctxt) */
++		} else
++		if (dkimverify) {
++			char            szPolicy[512];
++
++			if (!ret) {
++				if ((ret = DKIMVerifyResults(&ctxt, &sCount, &sSize)) != DKIM_SUCCESS)
++					maybe_die_dkim(ret);
++				if ((ret = DKIMVerifyGetDetails(&ctxt, &nSigCount, &pDetails, szPolicy)) != DKIM_SUCCESS)
++					maybe_die_dkim(ret);
++				else
++				for (ret = DKIM_SUCCESS,i = 0; i < nSigCount; i++) {
++					if (pDetails[i].nResult < 0) {
++						ret = pDetails[i].nResult;
++						break; /*- don't know if it is right to break */
++					}
++				}
++				if (!nSigCount)
++					ret = DKIM_NO_SIGNATURES;
++			}
++			/*- what to do if DKIM Verification fails */
++			if (checkPractice(ret)) {
++				char           *domain;
++
++				origRet = ret;
++				if ((domain = DKIMVerifyGetDomain(&ctxt))) {
++					if (!(p = env_get("SIGNATUREDOMAINS"))) {
++						if (control_readfile(&sigdomains, "signaturedomains", 0) == -1)
++							die(55, 2);
++					} else
++					if (!stralloc_copys(&sigdomains, p))
++						die(51, 2);
++					for (len = 0, p = sigdomains.s;len < sigdomains.len;) {
++						len += ((token_len = str_len(p)) + 1); /*- next domain */
++						if (!case_diffb(p, token_len, domain)) {
++							ret = DKIM_FAIL;
++							useADSP = 0;
++							useSSP = 0;
++							break;
++						}
++						p = sigdomains.s + len;
++					}
++					if (!(p = env_get("NOSIGNATUREDOMAINS"))) {
++						if (control_readfile(&nsigdomains, "nosignaturedomains", 0) == -1)
++							die(55, 2);
++					} else
++					if (!stralloc_copys(&nsigdomains, p))
++						die(51, 2);
++					for (len = 0, p = nsigdomains.s;len < nsigdomains.len;) {
++						len += ((token_len = str_len(p)) + 1); /*- next domain */
++						if (*p == '*' || !case_diffb(p, token_len, domain)) {
++							ret = DKIM_NEUTRAL;
++							useADSP = 0;
++							useSSP = 0;
++							break;
++						}
++						p = nsigdomains.s + len;
++					}
++				}
++				if (!domain || !*domain)
++					; /*- do nothing ? */
++				else
++				if (useADSP) {
++					resDKIMADSP = checkADSP(domain);
++					if (sCount > 0) {
++						if (resDKIMADSP == DKIM_ADSP_UNKNOWN || resDKIMADSP == DKIM_ADSP_ALL)
++							ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
++					} 
++					/* if the message should be signed, return fail */
++					if (resDKIMADSP == DKIM_ADSP_DISCARDABLE)
++						ret = DKIM_FAIL;
++					else
++						ret = DKIM_NEUTRAL;
++				} else
++				if (useSSP) {
++					int             bTestingPractices = 0;
++					char           *domain;
++	
++					if ((domain = DKIMVerifyGetDomain(&ctxt)))
++						resDKIMSSP = checkSSP(domain, &bTestingPractices);
++					if (sCount > 0) {
++						if ((resDKIMSSP == DKIM_SSP_UNKNOWN || resDKIMSSP == DKIM_SSP_ALL))
++							ret = (sCount == sSize ? DKIM_SUCCESS : DKIM_PARTIAL_SUCCESS);
++					}
++					// if the SSP is testing, return neutral
++					if (bTestingPractices)
++						ret = DKIM_NEUTRAL;
++					/* if the message should be signed, return fail */
++					if (resDKIMSSP == DKIM_SSP_ALL || resDKIMSSP == DKIM_SSP_STRICT)
++						ret = DKIM_FAIL;
++					else
++						ret = DKIM_NEUTRAL;
++				}
++			}
++			DKIMVerifyFree(&ctxt);
++			writeHeaderNexit(ret, origRet, resDKIMSSP, resDKIMADSP, useSSP, useADSP);
++		} /*- if (dkimverify) */
++	}
++	if (pipe(pim) == -1)
++		die(59, 0);
++	switch (pid = vfork())
++	{
++	case -1:
++		close(pim[0]);
++		close(pim[1]);
++		die(58, 0);
++	case 0:
++		close(pim[1]);
++		if (fd_move(0, pim[0]) == -1)
++			die(120, 0);
++		execv(*binqqargs, binqqargs);
++		die(120, 0);
++	}
++	close(pim[0]);
++	substdio_fdbuf(&ssin, read, readfd, inbuf, sizeof(inbuf));
++	substdio_fdbuf(&ssout, write, pim[1], outbuf, sizeof(outbuf));
++	if (substdio_bput(&ssout, dkimoutput.s, dkimoutput.len) == -1) /*- write DKIM signature */
++		die_write();
++	switch (substdio_copy(&ssout, &ssin))
++	{
++	case -2:
++		die_read();
++	case -3:
++		die_write();
++	}
++	if (substdio_flush(&ssout) == -1)
++		die_write();
++	close(pim[1]);
++	if (wait_pid(&wstat, pid) != pid)
++		die(57, 0);
++	if (wait_crashed(wstat))
++		die(57, 0);
++	die(wait_exitcode(wstat), 0);
++	/*- Not Reached */
++	exit(0);
++}
++
++void
++getversion_qmail_dkim_c()
++{
++	static char    *x = "$Id: qmail-dkim.c,v 1.37 2013-01-24 22:37:22+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/qmail-inject.c netqmail-1.06/qmail-inject.c
+--- ../netqmail-1.06-original/qmail-inject.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-inject.c	2016-11-22 21:03:57.120527832 +0100
+@@ -22,6 +22,7 @@
+ #include "auto_qmail.h"
+ #include "newfield.h"
+ #include "constmap.h"
++#include "srs.h"
+ 
+ #define LINELEN 80
+ 
+@@ -61,6 +62,11 @@
+ void temp() { _exit(111); }
+ void die_nomem() {
+  substdio_putsflush(subfderr,"qmail-inject: fatal: out of memory\n"); temp(); }
++void die_srs() {
++ substdio_puts("qmail-inject: fatal: ");
++ substdio_puts(subfderr,srs_error.s);
++ substdio_putsflush(subfderr,"\n");
++ perm(); }
+ void die_invalid(sa) stralloc *sa; {
+  substdio_putsflush(subfderr,"qmail-inject: fatal: invalid header field: ");
+  substdio_putflush(subfderr,sa->s,sa->len); perm(); }
+@@ -99,6 +105,17 @@
+    int i;
+ 
+    if (!stralloc_0(&sender)) die_nomem();
++   
++   if (!env_get("QMAILINJECT_SKIP_SRS") && (env_get("QMAILINJECT_FORCE_SRS") || (env_get("EXT") && env_get("HOST")))) {
++     switch(srsforward(sender.s)) {
++       case -3: die_srs(); break;
++       case -2: die_nomem(); break;
++       case -1: die_read(); break;
++       case 0: break;
++       case 1: if (!stralloc_copy(&sender,&srs_result)) die_nomem(); break;
++     }
++   }
++   
+    qmail_from(&qqt,sender.s);
+ 
+    for (i = 0;i < reciplist.len;++i)
+@@ -269,6 +286,10 @@
+ token822_alloc *addr;
+ {
+  if (!addr->len) return; /* don't rewrite <> */
++ if (addr->len == 1 && str_equal(addr->t[0].s,"<>")) {
++ addr->len = 0;
++ return;
++ }
+  if (addr->len >= 2)
+    if (addr->t[1].type == TOKEN822_AT)
+      if (addr->t[0].type == TOKEN822_LITERAL)
+diff -ruN ../netqmail-1.06-original/qmail-local.c netqmail-1.06/qmail-local.c
+--- ../netqmail-1.06-original/qmail-local.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/qmail-local.c	2018-01-01 12:10:21.981102868 +0100
+@@ -28,6 +28,7 @@
+ #include "myctime.h"
+ #include "gfrom.h"
+ #include "auto_patrn.h"
++#include "srs.h"
+ 
+ void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
+ 
+@@ -66,6 +67,15 @@
+ 
+ char buf[1024];
+ char outbuf[1024];
++#define QUOTABUFSIZE    256
++
++void die_control() { strerr_die1x(111,"Unable to read controls (#4.3.0)"); }
++void die_srs() {
++  if (!stralloc_copys(&foo,srs_error.s)) temp_nomem();
++  if (!stralloc_cats(&foo," (#4.3.0)")) temp_nomem();
++  if (!stralloc_0(&foo)) temp_nomem();
++  strerr_die1x(111,foo.s);
++}
+ 
+ /* child process */
+ 
+@@ -86,9 +96,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 +115,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+rpline.len+dtline.len); *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 +178,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)");
+@@ -282,6 +302,15 @@
+    qmail_put(&qqt,messline.s,messline.len);
+   }
+  while (match);
++ 
++ switch(srsforward(ueo.s)) {
++   case -3: die_srs(); break;
++   case -2: temp_nomem(); break;
++   case -1: die_control(); break;
++   case 0: break;
++   case 1: if (!stralloc_copy(&ueo,&srs_result)) temp_nomem(); break;
++ } 
++ 
+  qmail_from(&qqt,ueo.s);
+  while (*recips) qmail_to(&qqt,*recips++);
+  qqx = qmail_close(&qqt);
+diff -ruN ../netqmail-1.06-original/qmail-lspawn.c netqmail-1.06/qmail-lspawn.c
+--- ../netqmail-1.06-original/qmail-lspawn.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-lspawn.c	2016-11-22 21:03:57.120527832 +0100
+@@ -1,4 +1,5 @@
+ #include "fd.h"
++#include "env.h"
+ #include "wait.h"
+ #include "prot.h"
+ #include "substdio.h"
+@@ -170,6 +171,7 @@
+ char *s; char *r; int at;
+ {
+  int f;
++ char *ptr;
+ 
+  if (!(f = fork()))
+   {
+@@ -226,7 +228,10 @@
+    if (prot_uid(uid) == -1) _exit(QLX_USAGE);
+    if (!getuid()) _exit(QLX_ROOT);
+ 
+-   execv(*args,args);
++	if(!(ptr = env_get("QMAILLOCAL")))
++		execv(*args, args);
++	else
++		execv(ptr, args);
+    if (error_temp(errno)) _exit(QLX_EXECSOFT);
+    _exit(QLX_EXECHARD);
+   }
+diff -ruN ../netqmail-1.06-original/qmail-newmvrt.c netqmail-1.06/qmail-newmvrt.c
+--- ../netqmail-1.06-original/qmail-newmvrt.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-newmvrt.c	2016-11-22 21:04:20.041763530 +0100
+@@ -0,0 +1,70 @@
++#include "strerr.h"
++#include "stralloc.h"
++#include "substdio.h"
++#include "getln.h"
++#include "exit.h"
++#include "readwrite.h"
++#include "open.h"
++#include "auto_qmail.h"
++#include "cdbmss.h"
++
++#define FATAL "qmail-newmvrt: fatal: "
++
++void die_read()
++{
++  strerr_die2sys(111,FATAL,"unable to read control/morevalidrcptto: ");
++}
++void die_write()
++{
++  strerr_die2sys(111,FATAL,"unable to write to control/morevalidrcptto.tmp: ");
++}
++
++char inbuf[1024];
++substdio ssin;
++
++int fd;
++int fdtemp;
++
++struct cdbmss cdbmss;
++stralloc line = {0};
++int match;
++
++void main()
++{
++  umask(033);
++  if (chdir(auto_qmail) == -1)
++    strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
++
++  fd = open_read("control/morevalidrcptto");
++  if (fd == -1) die_read();
++
++  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf);
++
++  fdtemp = open_trunc("control/morevalidrcptto.tmp");
++  if (fdtemp == -1) die_write();
++
++  if (cdbmss_start(&cdbmss,fdtemp) == -1) die_write();
++
++  for (;;) {
++    if (getln(&ssin,&line,&match,'\n') != 0) die_read();
++    case_lowerb(line.s,line.len);
++    while (line.len) {
++      if (line.s[line.len - 1] == ' ') { --line.len; continue; }
++      if (line.s[line.len - 1] == '\n') { --line.len; continue; }
++      if (line.s[line.len - 1] == '\t') { --line.len; continue; }
++      if (line.s[0] != '#')
++	if (cdbmss_add(&cdbmss,line.s,line.len,"",0) == -1)
++	  die_write();
++      break;
++    }
++    if (!match) break;
++  }
++
++  if (cdbmss_finish(&cdbmss) == -1) die_write();
++  if (fsync(fdtemp) == -1) die_write();
++  if (close(fdtemp) == -1) die_write(); /* NFS stupidity */
++  if (rename("control/morevalidrcptto.tmp","control/morevalidrcptto.cdb") == -1)
++    strerr_die2sys(111,FATAL,"unable to move control/morevalidrcptto.tmp to control/morevalidrcptto.cdb");
++
++  _exit(0);
++}
+diff -ruN ../netqmail-1.06-original/qmail-pop3d.c netqmail-1.06/qmail-pop3d.c
+--- ../netqmail-1.06-original/qmail-pop3d.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/qmail-pop3d.c	2016-11-22 21:03:57.121527799 +0100
+@@ -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 -ruN ../netqmail-1.06-original/qmail-pw2u.c netqmail-1.06/qmail-pw2u.c
+--- ../netqmail-1.06-original/qmail-pw2u.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-pw2u.c	2016-11-22 21:03:57.121527799 +0100
+@@ -1,3 +1,4 @@
++#include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include "substdio.h"
+diff -ruN ../netqmail-1.06-original/qmail-qmqpc.c netqmail-1.06/qmail-qmqpc.c
+--- ../netqmail-1.06-original/qmail-qmqpc.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-qmqpc.c	2016-11-22 21:03:57.121527799 +0100
+@@ -102,6 +102,8 @@
+ char *server;
+ {
+   struct ip_address ip;
++  struct ip_address outip;
++  outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned char) 0;
+   char ch;
+ 
+   if (!ip_scan(server,&ip)) return;
+@@ -109,7 +111,7 @@
+   qmqpfd = socket(AF_INET,SOCK_STREAM,0);
+   if (qmqpfd == -1) die_socket();
+ 
+-  if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) {
++  if (timeoutconn(qmqpfd,&ip,&outip,PORT_QMQP,10) != 0) {
+     lasterror = 73;
+     if (errno == error_timeout) lasterror = 72;
+     close(qmqpfd);
+diff -ruN ../netqmail-1.06-original/qmail-qmtpd.c netqmail-1.06/qmail-qmtpd.c
+--- ../netqmail-1.06-original/qmail-qmtpd.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-qmtpd.c	2016-11-22 21:03:57.121527799 +0100
+@@ -1,3 +1,5 @@
++#include <unistd.h>
++#include <unistd.h>
+ #include "stralloc.h"
+ #include "substdio.h"
+ #include "qmail.h"
+diff -ruN ../netqmail-1.06-original/qmail-qstat.sh netqmail-1.06/qmail-qstat.sh
+--- ../netqmail-1.06-original/qmail-qstat.sh	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-qstat.sh	2016-11-22 21:03:57.121527799 +0100
+@@ -1,7 +1,7 @@
+ cd QMAIL
+ messdirs=`echo queue/mess/* | wc -w`
+ messfiles=`find queue/mess/* -print | wc -w`
+-tododirs=`echo queue/todo | wc -w`
+-todofiles=`find queue/todo -print | wc -w`
++tododirs=`echo queue/todo/* | wc -w`
++todofiles=`find queue/todo/* -print | wc -w`
+ echo messages in queue: `expr $messfiles - $messdirs`
+ echo messages in queue but not yet preprocessed: `expr $todofiles - $tododirs`
+diff -ruN ../netqmail-1.06-original/qmail-queue.8 netqmail-1.06/qmail-queue.8
+--- ../netqmail-1.06-original/qmail-queue.8	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/qmail-queue.8	2016-12-05 19:24:19.597680897 +0100
+@@ -46,6 +46,13 @@
+ will invoke the contents of
+ .B $QMAILQUEUE
+ instead, if that environment variable is set.
++.SH "CONTROL FILES"
++.TP 5
++.I taps
++Should contain source address (T for To,F for From,
++A for Any), regex syntax of email addresses to tap 
++and the associated email address to send the copy to.
++The fields should be separated by colon.
+ .SH "FILESYSTEM RESTRICTIONS"
+ .B qmail-queue
+ imposes two constraints on the queue structure:
+diff -ruN ../netqmail-1.06-original/qmail-queue.c netqmail-1.06/qmail-queue.c
+--- ../netqmail-1.06-original/qmail-queue.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-queue.c	2016-12-05 19:24:19.597680897 +0100
+@@ -16,6 +16,8 @@
+ #include "auto_uids.h"
+ #include "date822fmt.h"
+ #include "fmtqfn.h"
++#include "stralloc.h"
++#include "constmap.h"
+ 
+ #define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
+ #define ADDR 1003
+@@ -25,6 +27,14 @@
+ char outbuf[256];
+ struct substdio ssout;
+ 
++int tapok = 0;
++stralloc tap = {0};
++struct constmap maptap;
++stralloc chkaddr = {0};
++int tapped;
++stralloc tapaddr = {0};
++stralloc controlfile = {0};
++
+ datetime_sec starttime;
+ struct datetime dt;
+ unsigned long mypid;
+@@ -175,13 +185,20 @@
+ 
+  alarm(DEATH);
+ 
++ stralloc_copys( &controlfile, auto_qmail);
++ stralloc_cats( &controlfile, "/control/taps");
++ stralloc_0( &controlfile);
++ tapok = control_readfile(&tap,controlfile.s,0);
++ if (tapok == -1) die(65);
++ if (!constmap_init(&maptap,tap.s,tap.len,0)) die(65);
++
+  pidopen();
+  if (fstat(messfd,&pidst) == -1) die(63);
+ 
+  messnum = pidst.st_ino;
+  messfn = fnnum("mess/",1);
+- todofn = fnnum("todo/",0);
+- intdfn = fnnum("intd/",0);
++ todofn = fnnum("todo/",1);
++ intdfn = fnnum("intd/",1);
+ 
+  if (link(pidfn,messfn) == -1) die(64);
+  if (unlink(pidfn) == -1) die(63);
+@@ -219,14 +236,28 @@
+  if (substdio_get(&ssin,&ch,1) < 1) die_read();
+  if (ch != 'F') die(91);
+  if (substdio_bput(&ssout,&ch,1) == -1) die_write();
++ stralloc_0(&chkaddr);
+  for (len = 0;len < ADDR;++len)
+   {
++   if ( len == 1 ) stralloc_copyb(&chkaddr, &ch,1);
++   else if ( len > 1 ) stralloc_catb(&chkaddr, &ch,1);
+    if (substdio_get(&ssin,&ch,1) < 1) die_read();
+    if (substdio_put(&ssout,&ch,1) == -1) die_write();
+    if (!ch) break;
+   }
+  if (len >= ADDR) die(11);
+ 
++ /* check the from address */
++ stralloc_0(&chkaddr);
++ if (tapped == 0 && tapcheck('F')==1 ) {
++   tapped = 1;
++   if ( tapaddr.len > 0 ) {
++     if (substdio_bput(&ssout,"T",1) == -1) die_write();
++     if (substdio_bput(&ssout,tapaddr.s,tapaddr.len) == -1) die_write();
++     if (substdio_bput(&ssout,"",1) == -1) die_write();
++   }
++ }
++
+  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
+ 
+  for (;;)
+@@ -237,10 +268,24 @@
+    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+    for (len = 0;len < ADDR;++len)
+     {
++     if ( len == 1 ) stralloc_copyb(&chkaddr, &ch,1);
++     else if ( len > 1 ) stralloc_catb(&chkaddr, &ch,1);
+      if (substdio_get(&ssin,&ch,1) < 1) die_read();
+      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+      if (!ch) break;
+     }
++
++    /* check the to address */
++    stralloc_0(&chkaddr);
++    if (tapped == 0 && tapcheck('T')==1 ) {
++      tapped = 1;
++      if ( tapaddr.len > 0 ) {
++        if (substdio_bput(&ssout,"T",1) == -1) die_write();
++        if (substdio_bput(&ssout,tapaddr.s,tapaddr.len) == -1) die_write();
++        if (substdio_bput(&ssout,"",1) == -1) die_write();
++       }
++     }
++
+    if (len >= ADDR) die(11);
+   }
+ 
+@@ -252,3 +297,47 @@
+  triggerpull();
+  die(0);
+ }
++
++int tapcheck(t)
++char t;
++{
++  int i = 0;
++  int j = 0;
++  int x = 0;
++  int negate = 0;
++  stralloc curregex = {0};
++  char tmpbuf[200];
++
++  while (j < tap.len) {
++    i = j;
++    if ( tap.s[i]==t || tap.s[i]=='A'){
++            while ((tap.s[i] != ':') && (i < tap.len)) i++;
++            i++;
++            j=i;
++            while ((tap.s[i] != ':') && (i < tap.len)) i++;
++            if (tap.s[j] == '!') {
++              negate = 1;
++              j++;
++            }
++            stralloc_copys(&tapaddr, &tap.s[i+1]);
++
++            stralloc_copyb(&curregex,tap.s + j,(i - j));
++            stralloc_0(&curregex);
++            x = matchregex(chkaddr.s, curregex.s, tmpbuf);
++
++
++            if ((negate) && (x == 0)) {
++              return 1;
++            }
++            if (!(negate) && (x > 0)) {
++              return 1;
++            }
++    }
++    while ((tap.s[i] != '\0') && (i < tap.len)) i++;
++    j = i + 1;
++    negate = 0;
++
++
++  }
++  return 0;
++}
+diff -ruN ../netqmail-1.06-original/qmail-remote.8 netqmail-1.06/qmail-remote.8
+--- ../netqmail-1.06-original/qmail-remote.8	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-remote.8	2016-11-22 21:03:57.122527765 +0100
+@@ -100,6 +100,73 @@
+ After this letter comes a human-readable description of
+ what happened.
+ 
++.B qmail-remote
++may use SMTP Authenticaton of type CRAM-MD5, PLAIN, or LOGIN
++(in this order) to connect to remote hosts.
++The following reports are provided:
++.TP 5
++K
++no supported AUTH method found, continuing without authentication.
++.TP 5
++Z
++Connected to 
++.I host
++but password expired.
++.TP 5
++Z
++Connected to 
++.I host 
++but authentication was rejected (AUTH PLAIN).
++.TP 5
++Z
++Connected to 
++.I host 
++but unable to base64encode (plain).
++.TP 5
++Z
++Connected to 
++.I host
++but authentication was rejected (plain)."
++.TP 5
++Z
++Connected to
++.I host
++but authentication was rejected (AUTH LOGIN).
++.TP 5
++Z
++Connected to 
++.I host
++but unable to base64encode user.
++.TP 5
++Z
++Connected to 
++.I host 
++but authentication was rejected (username).
++.TP 5
++Z
++Connected to 
++.I host 
++but unable to base64encode pass.
++.TP 5
++Z
++Connected to
++.I host
++but authentication was rejected (AUTH CRAM-MD5).
++Z
++Connected to 
++.I host
++but unable to base64decode challenge.
++.TP 5
++Z
++Connected to 
++.I host
++but unable to base64encode username+digest.
++.TP 5
++Z
++Connected to 
++.I host 
++but authentication was rejected (username+digest).
++.PP
+ The recipient reports will always be printed in the same order as
+ .BR qmail-remote 's
+ .I recip
+@@ -114,6 +181,55 @@
+ always exits zero.
+ .SH "CONTROL FILES"
+ .TP 5
++.I authsenders
++Authenticated sender.
++For each
++.I sender 
++included in 
++.IR authsenders :
++.I sender\fB:\fIrelay\fB:\fIport\fB|\fIuser\fB|\fIpassword 
++.B qmail-remote
++will try SMTP Authentication 
++of type CRAM-MD5, LOGIN, or PLAIN 
++with the provided user name
++.I user 
++and password
++.I password 
++(the authentication information) 
++and eventually relay the 
++mail through
++.I relay
++on port
++.IR port .
++The use of 
++.I relay
++and 
++.I port 
++follows the same rules as for
++.IR smtproutes 
++Note: In case
++.I sender
++is empty, 
++.B qmail-remote
++will try to deliver each outgoing mail 
++SMTP authenticated. If the authentication
++information is missing, the mail is 
++delivered none-authenticated.
++.I authsenders
++can be constructed as follows:
++
++.EX
++   @example.com|generic|passwd
++   .subdomain.example.com|other|otherpw
++   mail@example.com|test|testpass
++   info@example.com:smtp.example.com:26|other|otherpw
++   :mailrelay.example.com:587|e=mc2|testpass
++.EE
++.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,12 +239,31 @@
+ 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 outgoingip
++IP address to be used on outgoing connections.
++Default: system-defined.
++The value 
++.IR 0.0.0.0 
++is equivalent to the system default.
+ .TP 5
+ .I smtproutes
+ Artificial SMTP routes.
+ Each route has the form
+ .IR domain\fB:\fIrelay ,
+-without any extra spaces.
++or
++.IR domain\fB:\fIrelay\fB|\fIuser\fB|\fIpassword
++in case of authenticated routes without any extra spaces.
+ If
+ .I domain
+ matches
+@@ -149,6 +284,7 @@
+ 
+ .EX
+    inside.af.mil:firewall.af.mil:26
++  :submission.myrelay.com:587|myuserid|mypasswd
+ .EE
+ 
+ .I relay
+@@ -156,6 +292,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:
+ 
+@@ -182,6 +320,10 @@
+ you are always safe using
+ .I smtproutes
+ if you do not accept mail from the network.
++Note:
++.I authsender 
++routes have precedence over
++.IR smtproutes .
+ .TP 5
+ .I timeoutconnect
+ Number of seconds
+@@ -195,6 +337,88 @@
+ .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 file 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. The file contains the trusted CA certificates.
++
++.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 "ENVIRONMENT VARIABLES READ"
++Environment variables may be defined globally in the
++.B qmail-smtpd
++startup script and/or individually as part of the
++.B tcpserver's
++cdb database.
++The environment variables may be quoted ("variable", or 'variable') and
++in case of global use, have to be exported.
++.B qmail-smtpd
++supports the following legacy environment variables, typically
++provided by
++.B tcpserver
++or
++.B sslserver
++or
++.BR tcp-env :
++.IR TCPREMOTEIP ,
++.IR TCPREMOTEHOST
++.IR TCPREMOTEINFO
++and
++.IR TCPLOCALPORT
++as well as
++.IR RELAYCLIENT .
++
++.B qmail-smtpd
++may use the following environment variables for SMTP authentication:
++.TP 5
++.IR SMTPAUTH
++is used to enable SMTP Authentication for the AUTH types
++LOGIN and PLAIN.
++In case
++.TP 5
++.IR SMTPAUTH='+cram'
++is defined,
++.B qmail-smtpd
++honors LOGIN, PLAIN, and additionally CRAM-MD5 authentication.
++Simply 
++.TP 5
++.IR SMTPAUTH='cram'
++restricts authentication just to CRAM-MD5.
++If however
++.TP 5
++.IR SMTPAUTH='!'
++starts with an exclamation mark, AUTH is required. In particular,
++.TP 5
++.IR SMTPAUTH='!cram'
++may be useful.
++In opposite, if
++.TP 5
++.IR SMTPAUTH='-'
++starts with a dash, AUTH is disabled for particular
++connections.
++
++Note: The use of 'cram' requires a CRAM-MD5 enabled PAM.
++
+ .SH "SEE ALSO"
+ addresses(5),
+ envelopes(5),
+diff -ruN ../netqmail-1.06-original/qmail-remote.c netqmail-1.06/qmail-remote.c
+--- ../netqmail-1.06-original/qmail-remote.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-remote.c	2017-08-28 17:51:47.068287985 +0200
+@@ -28,6 +28,7 @@
+ #include "timeoutconn.h"
+ #include "timeoutread.h"
+ #include "timeoutwrite.h"
++#include "base64.h"
+ 
+ #define HUGESMTPTEXT 5000
+ 
+@@ -39,14 +40,37 @@
+ static stralloc sauninit = {0};
+ 
+ stralloc helohost = {0};
++stralloc outgoingip = {0};
+ stralloc routes = {0};
+ struct constmap maproutes;
+ stralloc host = {0};
+ stralloc sender = {0};
+ 
++stralloc authsenders = {0};
++struct constmap mapauthsenders;
++stralloc user = {0};
++stralloc pass = {0};
++stralloc auth = {0};
++stralloc plain = {0};
++stralloc chal  = {0};
++stralloc slop  = {0};
++char *authsender;
++
+ saa reciplist = {0};
+ 
+ struct ip_address partner;
++struct ip_address outip;
++
++#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); }
+@@ -56,6 +80,7 @@
+ ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
+ if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
+ 
++void temp_noip() { out("Zinvalid ipaddr in control/outgoingip (#4.3.0)\n"); zerodie(); }
+ void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
+ void temp_oserr() { out("Z\
+ System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); }
+@@ -86,6 +111,12 @@
+ it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
+ zerodie(); }
+ 
++void err_authprot() {
++  out("Kno supported AUTH method found, continuing without authentication.\n");
++  zero();
++  substdio_flush(subfdoutsmall);
++}
++
+ void outhost()
+ {
+   char x[IPFMT];
+@@ -99,6 +130,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 +144,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 +157,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 +209,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 +284,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 +296,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();
+ }
+ 
+@@ -201,6 +335,16 @@
+     if (ch == '.')
+       substdio_put(&smtpto,".",1);
+     while (ch != '\n') {
++      if (ch == '\r') {
++	r = substdio_get(&ssin, &ch, 1);
++	if (r == 0)
++		break;
++	if (r == -1) temp_read();
++	if (ch != '\n') {
++		substdio_put(&smtpto, "\r\n", 2);
++	} else
++		break;
++      }
+       substdio_put(&smtpto,&ch,1);
+       r = substdio_get(&ssin,&ch,1);
+       if (r == 0) perm_partialline();
+@@ -214,30 +358,432 @@
+   substdio_flush(&smtpto);
+ }
+ 
+-stralloc recip = {0};
++#ifdef TLS
++char *partner_fqdn = 0;
+ 
+-void smtp()
++# 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()
+ {
+-  unsigned long code;
+-  int flagbother;
+   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 (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
+- 
+-  substdio_puts(&smtpto,"HELO ");
+-  substdio_put(&smtpto,helohost.s,helohost.len);
+-  substdio_puts(&smtpto,"\r\n");
+-  substdio_flush(&smtpto);
+-  if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+- 
++  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");
++  }
++
++  /* POODLE vulnerability */
++  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
++
++  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_fd(myssl, smtpfd);
++
++  /* read the response 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 found_gen_dns = 0;
++    int matched_gen_dns = 0;
++
++    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){
++          found_gen_dns = 1;
++          if (match_partner(gn->d.ia5->data, gn->d.ia5->length)){
++            matched_gen_dns = 1;
++            break;
++          }
++        }
++      }
++      sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
++    }
++
++    /* no SubjectAltName of type DNS found, look up commonName */
++    if (!found_gen_dns) {
++      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;
++      }
++    } else if (!matched_gen_dns) {
++      out("ZTLS unable to verify server ");
++      tls_quit(partner_fqdn, "certificate contains no matching dNSNnames");
++    }
++
++    X509_free(peercert);
++  }
++
++  if (smtps) if (smtpcode() != 220)
++    quit("ZTLS Connected to "," but greeting failed");
++
++  return 1;
++}
++#endif
++
++stralloc recip = {0};
++
++void mailfrom()
++{
+   substdio_puts(&smtpto,"MAIL FROM:<");
+   substdio_put(&smtpto,sender.s,sender.len);
+   substdio_puts(&smtpto,">\r\n");
+   substdio_flush(&smtpto);
++}
++
++stralloc xuser = {0};
++
++int xtext(sa,s,len)
++stralloc *sa;
++char *s;
++int len;
++{
++  int i;
++
++  if(!stralloc_copys(sa,"")) temp_nomem();
++  
++  for (i = 0; i < len; i++) {
++    if (s[i] == '=') {
++      if (!stralloc_cats(sa,"+3D")) temp_nomem();
++    } else if (s[i] == '+') {  
++        if (!stralloc_cats(sa,"+2B")) temp_nomem(); 
++    } else if ((int) s[i] < 33 || (int) s[i] > 126) {
++        if (!stralloc_cats(sa,"+3F")) temp_nomem(); /* ok. not correct */
++    } else if (!stralloc_catb(sa,s+i,1)) {
++        temp_nomem();
++    }
++  }
++
++  return sa->len;
++}
++
++void mailfrom_xtext()
++{
++  if (!xtext(&xuser,user.s,user.len)) temp_nomem();
++  substdio_puts(&smtpto,"MAIL FROM:<");
++  substdio_put(&smtpto,sender.s,sender.len);
++  substdio_puts(&smtpto,"> AUTH=");
++  substdio_put(&smtpto,xuser.s,xuser.len);
++  substdio_puts(&smtpto,"\r\n");
++  substdio_flush(&smtpto);
++}
++
++int mailfrom_plain()
++{
++  substdio_puts(&smtpto,"AUTH PLAIN\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH PLAIN)."); return -1; }
++  if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authorization-id> */
++  if (!stralloc_0(&plain)) temp_nomem();
++  if (!stralloc_cat(&plain,&user)) temp_nomem(); /* <authentication-id> */
++  if (!stralloc_0(&plain)) temp_nomem();
++  if (!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */
++  if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain).");
++  substdio_put(&smtpto,auth.s,auth.len);
++  substdio_puts(&smtpto,"\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
++  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
++  else { quit("ZConnected to "," but authentication was rejected (plain)."); return 1; }
++
++  return 0;
++}
++
++int mailfrom_login()
++{
++  substdio_puts(&smtpto,"AUTH LOGIN\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)."); return -1; }
++
++  if (!stralloc_copys(&auth,"")) temp_nomem();
++  if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user.");
++  substdio_put(&smtpto,auth.s,auth.len);
++  substdio_puts(&smtpto,"\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username).");
++
++  if (!stralloc_copys(&auth,"")) temp_nomem();
++  if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass.");
++  substdio_put(&smtpto,auth.s,auth.len);
++  substdio_puts(&smtpto,"\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
++  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
++  else { quit("ZConnected to "," but authentication was rejected (password)."); return 1; }
++}
++
++int mailfrom_cram()
++{
++  int j;
++  unsigned char h;
++  unsigned char digest[16];
++  unsigned char digascii[33];
++  static char hextab[]="0123456789abcdef";
++
++  substdio_puts(&smtpto,"AUTH CRAM-MD5\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() != 334) { quit("ZConnected to "," but authentication was rejected (AUTH CRAM-MD5)."); return -1; }
++
++  if (str_chr(smtptext.s+4,' ')) { 			/* Challenge */
++    if(!stralloc_copys(&slop,"")) temp_nomem();
++    if (!stralloc_copyb(&slop,smtptext.s+4,smtptext.len-5)) temp_nomem();
++    if (b64decode(slop.s,slop.len,&chal)) quit("ZConnected to "," but unable to base64decode challenge.");
++  }
++   
++  hmac_md5(chal.s,chal.len,pass.s,pass.len,digest);
++
++  for (j = 0;j < 16;j++)				/* HEX => ASCII */
++  {
++    digascii[2*j] = hextab[digest[j] >> 4];  
++    digascii[2*j+1] = hextab[digest[j] & 0xf]; 
++  }
++  digascii[32]=0;
++
++  slop.len = 0;
++  if (!stralloc_copys(&slop,"")) temp_nomem();
++  if (!stralloc_cat(&slop,&user)) temp_nomem();		 /* user-id */
++  if (!stralloc_cats(&slop," ")) temp_nomem();
++  if (!stralloc_catb(&slop,digascii,32)) temp_nomem();   /* digest */ 
++
++  if (!stralloc_copys(&auth,"")) temp_nomem();
++  if (b64encode(&slop,&auth)) quit("ZConnected to "," but unable to base64encode username+digest.");
++  substdio_put(&smtpto,auth.s,auth.len);
++  substdio_puts(&smtpto,"\r\n");
++  substdio_flush(&smtpto);
++  if (smtpcode() == 235) { mailfrom_xtext(); return 0; }
++  else if (smtpcode() == 432) { quit("ZConnected to "," but password expired."); return 1; }
++  else { quit("ZConnected to "," but authentication was rejected (username+digest)."); return 1; }
++}
++
++void smtp_auth()
++{
++  int i, j; 
++
++  for (i = 0; i + 8 < smtptext.len; i += str_chr(smtptext.s+i,'\n')+1)
++    if (!str_diffn(smtptext.s+i+4,"AUTH",4)) {  
++      if (j = str_chr(smtptext.s+i+8,'C') > 0)
++        if (case_starts(smtptext.s+i+8+j,"CRAM"))
++          if (mailfrom_cram() >= 0) return;
++
++      if (j = str_chr(smtptext.s+i+8,'P') > 0)
++        if (case_starts(smtptext.s+i+8+j,"PLAIN")) 
++          if (mailfrom_plain() >= 0) return;
++
++      if (j = str_chr(smtptext.s+i+8,'L') > 0)
++        if (case_starts(smtptext.s+i+8+j,"LOGIN")) 
++          if (mailfrom_login() >= 0) return;
++
++      err_authprot();
++      mailfrom();
++    }
++}
++
++void smtp()
++{
++  unsigned long code;
++  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
++
++  code = smtpcode();
++  if (code >= 500 && code < 600) quit("DConnected to "," but greeting failed");
++  if (code >= 400 && code < 500) return; /* try next MX, see RFC-2821 */
++  if (code != 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
++
++/*  if (smtpcode() != 250) { */
++    substdio_puts(&smtpto,"HELO ");
++    substdio_put(&smtpto,helohost.s,helohost.len);
++    substdio_puts(&smtpto,"\r\n");
++    substdio_flush(&smtpto);
++    code = smtpcode();
++    if (code >= 500) quit("DConnected to "," but my name was rejected");
++    if (code != 250) quit("ZConnected to "," but my name was rejected");
++/*  } */
++
++#ifdef EHLO
++  }
++#endif
++
++  if (user.len && pass.len)
++    smtp_auth();
++  else
++    mailfrom();
++
+   code = smtpcode();
+   if (code >= 500) quit("DConnected to "," but sender was rejected");
+   if (code >= 400) quit("ZConnected to "," but sender was rejected");
+- 
++
+   flagbother = 0;
+   for (i = 0;i < reciplist.len;++i) {
+     substdio_puts(&smtpto,"RCPT TO:<");
+@@ -297,19 +843,14 @@
+   if (!stralloc_cats(saout,"@")) temp_nomem();
+  
+   if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem();
+-  if (flagcname)
+-    switch(dns_cname(&canonhost)) {
+-      case 0: *flagalias = 0; break;
+-      case DNS_MEM: temp_nomem();
+-      case DNS_SOFT: temp_dnscanon();
+-      case DNS_HARD: ; /* alias loop, not our problem */
+-    }
++  if (flagcname) *flagalias = 0;
+ 
+   if (!stralloc_cat(saout,&canonhost)) temp_nomem();
+ }
+ 
+ void getcontrols()
+ {
++  int r;
+   if (control_init() == -1) temp_control();
+   if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
+   if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
+@@ -324,48 +865,108 @@
+     case 1:
+       if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
+   }
++  
++  switch(control_readfile(&authsenders,"control/authsenders",0)) {
++    case -1:
++       temp_control();
++    case 0:
++      if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break;
++    case 1:
++      if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break;
++  }
++ r = control_readline(&outgoingip,"control/outgoingip");
++ if (-1 == r) { if (errno == error_nomem) temp_nomem(); temp_control(); }
++ if (0 == r && !stralloc_copys(&outgoingip, "0.0.0.0")) temp_nomem();
++ if (str_equal(outgoingip.s, "0.0.0.0"))
++   { outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long) 0; }
++ else if (!ip_scan(outgoingip.s, &outip)) temp_noip();
+ }
+ 
+-void main(argc,argv)
++int main(argc,argv)
+ int argc;
+ char **argv;
+ {
+   static ipalloc ip = {0};
+-  int i;
++  int i, j;
+   unsigned long random;
+   char **recips;
+   unsigned long prefme;
+   int flagallaliases;
+   int flagalias;
+   char *relayhost;
+- 
++   
+   sig_pipeignore();
+   if (argc < 4) perm_usage();
+   if (chdir(auto_qmail) == -1) temp_chdir();
+   getcontrols();
+  
+- 
+   if (!stralloc_copys(&host,argv[1])) temp_nomem();
+- 
++
++  authsender = 0;
+   relayhost = 0;
+-  for (i = 0;i <= host.len;++i)
+-    if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
+-      if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
++
++  addrmangle(&sender,argv[2],&flagalias,0);
++
++  for (i = 0;i <= sender.len;++i)
++    if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@'))
++      if (authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i))
+         break;
+-  if (relayhost && !*relayhost) relayhost = 0;
+- 
+-  if (relayhost) {
+-    i = str_chr(relayhost,':');
+-    if (relayhost[i]) {
+-      scan_ulong(relayhost + i + 1,&port);
+-      relayhost[i] = 0;
++
++  if (authsender && !*authsender) authsender = 0;
++
++  if (authsender) {
++    i = str_chr(authsender,'|');
++    if (authsender[i]) {
++      j = str_chr(authsender + i + 1,'|');
++      if (authsender[j]) {
++        authsender[i] = 0;
++        authsender[i + j + 1] = 0;
++        if (!stralloc_copys(&user,"")) temp_nomem();
++        if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem();
++        if (!stralloc_copys(&pass,"")) temp_nomem();
++        if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem();
++      }
++    }
++    i = str_chr(authsender,':');
++    if (authsender[i]) {
++      scan_ulong(authsender + i + 1,&port);
++      authsender[i] = 0;
+     }
+-    if (!stralloc_copys(&host,relayhost)) temp_nomem();
+-  }
+ 
++    if (!stralloc_copys(&relayhost,authsender)) temp_nomem();
++    if (!stralloc_copys(&host,authsender)) temp_nomem();
++
++  }
++  else {					/* default smtproutes -- authenticated */
++    for (i = 0;i <= host.len;++i)
++      if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
++        if (relayhost = constmap(&maproutes,host.s + i,host.len - i))
++          break;
++
++    if (relayhost && !*relayhost) relayhost = 0;
++
++    if (relayhost) {
++      i = str_chr(relayhost,'|');
++      if (relayhost[i]) {
++        j = str_chr(relayhost + i + 1,'|');
++        if (relayhost[j]) {
++          relayhost[i] = 0;
++          relayhost[i + j + 1] = 0;
++          if (!stralloc_copys(&user,"")) temp_nomem();
++          if (!stralloc_copys(&user,relayhost + i + 1)) temp_nomem();
++          if (!stralloc_copys(&pass,"")) temp_nomem();
++          if (!stralloc_copys(&pass,relayhost + i + j + 2)) temp_nomem();
++        }
++      }
++      i = str_chr(relayhost,':');
++      if (relayhost[i]) {
++        scan_ulong(relayhost + i + 1,&port);
++        relayhost[i] = 0;
++      }
++      if (!stralloc_copys(&host,relayhost)) temp_nomem();
++    }
++  }
+ 
+-  addrmangle(&sender,argv[2],&flagalias,0);
+- 
+   if (!saa_readyplus(&reciplist,0)) temp_nomem();
+   if (ipme_init() != 1) temp_oserr();
+  
+@@ -414,10 +1015,13 @@
+     smtpfd = socket(AF_INET,SOCK_STREAM,0);
+     if (smtpfd == -1) temp_oserr();
+  
+-    if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
++    if (timeoutconn(smtpfd,&ip.ix[i].ip,&outip,(unsigned int) port,timeoutconnect) == 0) {
+       tcpto_err(&ip.ix[i].ip,0);
+       partner = ip.ix[i].ip;
+-      smtp(); /* does not return */
++#ifdef TLS
++      partner_fqdn = ip.ix[i].fqdn;
++#endif
++      smtp(); /* only returns when the next MX is to be tried */
+     }
+     tcpto_err(&ip.ix[i].ip,errno == error_timeout);
+     close(smtpfd);
+diff -ruN ../netqmail-1.06-original/qmail-rspawn.c netqmail-1.06/qmail-rspawn.c
+--- ../netqmail-1.06-original/qmail-rspawn.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-rspawn.c	2016-11-22 21:03:57.123527732 +0100
+@@ -1,3 +1,4 @@
++#include "env.h"
+ #include "fd.h"
+ #include "wait.h"
+ #include "substdio.h"
+@@ -82,7 +83,7 @@
+ char *s; char *r; int at;
+ {
+  int f;
+- char *(args[5]);
++ char *ptr, *(args[5]);
+ 
+  args[0] = "qmail-remote";
+  args[1] = r + at + 1;
+@@ -95,7 +96,10 @@
+    if (fd_move(0,fdmess) == -1) _exit(111);
+    if (fd_move(1,fdout) == -1) _exit(111);
+    if (fd_copy(2,1) == -1) _exit(111);
+-   execvp(*args,args);
++   if(!(ptr = env_get("QMAILREMOTE")))
++      execvp(*args, args);
++   else
++      execvp(ptr, args);
+    if (error_temp(errno)) _exit(111);
+    _exit(100);
+   }
+diff -ruN ../netqmail-1.06-original/qmail-send.9 netqmail-1.06/qmail-send.9
+--- ../netqmail-1.06-original/qmail-send.9	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-send.9	2016-11-22 21:03:57.123527732 +0100
+@@ -51,7 +51,9 @@
+ .B qmail-send
+ receives a HUP signal,
+ it will reread
+-.I locals
++.IR concurrencylocal ,
++.IR concurrencyremote ,
++.IR locals
+ and
+ .IR virtualdomains .
+ .TP 5
+@@ -115,6 +117,10 @@
+ (If that bounces,
+ .B qmail-send
+ gives up.)
++As a special case, if the first line of
++.IR doublebounceto
++is blank (contains a single linefeed), qmail-send will not queue
++the double-bounce at all.
+ .TP 5
+ .I envnoathost
+ Presumed domain name for addresses without @ signs.
+diff -ruN ../netqmail-1.06-original/qmail-send.c netqmail-1.06/qmail-send.c
+--- ../netqmail-1.06-original/qmail-send.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-send.c	2016-11-22 21:03:57.124527699 +0100
+@@ -31,6 +31,7 @@
+ #include "constmap.h"
+ #include "fmtqfn.h"
+ #include "readsubdir.h"
++#include "srs.h"
+ 
+ /* critical timing feature #1: if not triggered, do not busy-loop */
+ /* critical timing feature #2: if triggered, respond within fixed time */
+@@ -44,6 +45,8 @@
+ 
+ int lifetime = 604800;
+ 
++int bouncemaxbytes = 50000;
++
+ stralloc percenthack = {0};
+ struct constmap mappercenthack;
+ stralloc locals = {0};
+@@ -55,6 +58,7 @@
+ stralloc bouncehost = {0};
+ stralloc doublebounceto = {0};
+ stralloc doublebouncehost = {0};
++stralloc srs_domain = {0};
+ 
+ char strnum2[FMT_ULONG];
+ char strnum3[FMT_ULONG];
+@@ -82,9 +86,6 @@
+ 
+ datetime_sec recent;
+ 
+-
+-/* this file is too long ----------------------------------------- FILENAMES */
+-
+ stralloc fn = {0};
+ stralloc fn2 = {0};
+ char fnmake_strnum[FMT_ULONG];
+@@ -96,7 +97,7 @@
+ }
+ 
+ void fnmake_info(id) unsigned long id; { fn.len = fmtqfn(fn.s,"info/",id,1); }
+-void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,0); }
++void fnmake_todo(id) unsigned long id; { fn.len = fmtqfn(fn.s,"todo/",id,1); }
+ void fnmake_mess(id) unsigned long id; { fn.len = fmtqfn(fn.s,"mess/",id,1); }
+ void fnmake_foop(id) unsigned long id; { fn.len = fmtqfn(fn.s,"foop/",id,0); }
+ void fnmake_split(id) unsigned long id; { fn.len = fmtqfn(fn.s,"",id,1); }
+@@ -262,6 +263,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();
+@@ -683,15 +686,39 @@
+   }
+  if (str_equal(sender.s,"#@[]"))
+    log3("triple bounce: discarding ",fn2.s,"\n");
++ else if (!*sender.s && *doublebounceto.s == '@')
++   log3("double bounce: discarding ",fn2.s,"\n");
+  else
+   {
+    if (qmail_open(&qqt) == -1)
+     { log1("warning: unable to start qmail-queue, will try later\n"); return 0; }
+    qp = qmail_qp(&qqt);
+ 
+-   if (*sender.s) { bouncesender = ""; bouncerecip = sender.s; }
+-   else { bouncesender = "#@[]"; bouncerecip = doublebounceto.s; }
+-
++   if (*sender.s) {
++     if (srs_domain.len) {
++       int j = 0;
++       j = byte_rchr(sender.s, sender.len, '@');
++       if (j < sender.len) {
++         if (srs_domain.len == sender.len - j - 1 && stralloc_starts(&srs_domain, sender.s + j + 1)) {
++           switch(srsreverse(sender.s)) {
++             case -3: log1(srs_error.s); log1("\n"); _exit(111); break;
++             case -2: nomem(); break;
++             case -1: log1("alert: unable to read controls\n"); _exit(111); break;
++             case 0: break;
++             case 1: if (!stralloc_copy(&sender,&srs_result)) nomem(); break;
++           }
++           if (chdir(auto_qmail) == -1) { log1("alert: unable to switch to home directory\n"); _exit(111); }
++           if (chdir("queue") == -1) { log1("alert: unable to switch to queue directory\n"); _exit(111); }
++         }
++       }
++     }
++     bouncesender = "";
++     bouncerecip = sender.s;
++   } else {
++     bouncesender = "#@[]";
++     bouncerecip = doublebounceto.s;
++   }
++   
+    while (!newfield_datemake(now())) nomem();
+    qmail_put(&qqt,newfield_date.s,newfield_date.len);
+    qmail_puts(&qqt,"From: ");
+@@ -740,9 +767,17 @@
+      qmail_fail(&qqt);
+    else
+     {
++     int bytestogo = bouncemaxbytes;
++     int bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf;
+      substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf));
+-     while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0)
++     while (bytestoget > 0 && (r = substdio_get(&ssread,buf,bytestoget)) > 0) {
+        qmail_put(&qqt,buf,r);
++       bytestogo -= bytestoget;
++       bytestoget = (bytestogo < sizeof buf) ? bytestogo : sizeof buf;
++     }
++     if (r > 0) {
++       qmail_puts(&qqt,"\n\n--- End of message stripped.\n");
++     }
+      close(fd);
+      if (r == -1)
+        qmail_fail(&qqt);
+@@ -906,41 +941,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;
+@@ -1215,8 +1251,10 @@
+ 
+ /* this file is too long ---------------------------------------------- TODO */
+ 
++#ifndef EXTERNAL_TODO
+ datetime_sec nexttodorun;
+-DIR *tododir; /* if 0, have to opendir again */
++int flagtododir = 0; /* if 0, have to readsubdir_init again */
++readsubdir todosubdir;
+ stralloc todoline = {0};
+ char todobuf[SUBSTDIO_INSIZE];
+ char todobufinfo[512];
+@@ -1224,7 +1262,7 @@
+ 
+ void todo_init()
+ {
+- tododir = 0;
++ flagtododir = 0;
+  nexttodorun = now();
+  trigger_set();
+ }
+@@ -1236,7 +1274,7 @@
+ {
+  if (flagexitasap) return;
+  trigger_selprep(nfds,rfds);
+- if (tododir) *wakeup = 0;
++ if (flagtododir) *wakeup = 0;
+  if (*wakeup > nexttodorun) *wakeup = nexttodorun;
+ }
+ 
+@@ -1253,8 +1291,7 @@
+  char ch;
+  int match;
+  unsigned long id;
+- unsigned int len;
+- direntry *d;
++ int z;
+  int c;
+  unsigned long uid;
+  unsigned long pid;
+@@ -1265,32 +1302,26 @@
+ 
+  if (flagexitasap) return;
+ 
+- if (!tododir)
++ if (!flagtododir)
+   {
+    if (!trigger_pulled(rfds))
+      if (recent < nexttodorun)
+        return;
+    trigger_set();
+-   tododir = opendir("todo");
+-   if (!tododir)
+-    {
+-     pausedir("todo");
+-     return;
+-    }
++   readsubdir_init(&todosubdir, "todo", pausedir);
++   flagtododir = 1;
+    nexttodorun = recent + SLEEP_TODO;
+   }
+ 
+- d = readdir(tododir);
+- if (!d)
++ switch(readsubdir_next(&todosubdir, &id))
+   {
+-   closedir(tododir);
+-   tododir = 0;
++    case 1:
++      break;
++    case 0:
++      flagtododir = 0;
++    default:
+    return;
+   }
+- if (str_equal(d->d_name,".")) return;
+- if (str_equal(d->d_name,"..")) return;
+- len = scan_ulong(d->d_name,&id);
+- if (!len || d->d_name[len]) return;
+ 
+  fnmake_todo(id);
+ 
+@@ -1438,10 +1469,148 @@
+    if (fdchan[c] != -1) close(fdchan[c]);
+ }
+ 
++#endif
++
++/* this file is too long ------------------------------------- EXTERNAL TODO */
++
++#ifdef EXTERNAL_TODO
++stralloc todoline = {0};
++char todobuf[2048];
++int todofdin;
++int todofdout;
++int flagtodoalive;
++
++void tododied() { log1("alert: oh no! lost qmail-todo connection! dying...\n");
++ flagexitasap = 1; flagtodoalive = 0; }
++
++void todo_init()
++{
++  todofdout = 7;
++  todofdin = 8;
++  flagtodoalive = 1;
++  /* sync with external todo */
++  if (write(todofdout, "S", 1) != 1) tododied();
++  
++  return;
++}
++
++void todo_selprep(nfds,rfds,wakeup)
++int *nfds;
++fd_set *rfds;
++datetime_sec *wakeup;
++{
++  if (flagexitasap) {
++    if (flagtodoalive) {
++      write(todofdout, "X", 1);
++    }
++  }
++  if (flagtodoalive) {
++    FD_SET(todofdin,rfds);
++    if (*nfds <= todofdin)
++      *nfds = todofdin + 1;
++  }
++}
++
++void todo_del(char* s)
++{
++ int flagchan[CHANNELS];
++ struct prioq_elt pe;
++ unsigned long id;
++ unsigned int len;
++ int c;
++
++ for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
++ switch(*s++) {
++  case 'L':
++    flagchan[0] = 1;
++    break;
++  case 'R':
++    flagchan[1] = 1;
++    break;
++  case 'B':
++    flagchan[0] = 1;
++    flagchan[1] = 1;
++    break;
++  case 'X':
++    break;
++  default:
++    log1("warning: qmail-send unable to understand qmail-todo\n");
++    return;
++ }
++ 
++ len = scan_ulong(s,&id);
++ if (!len || s[len]) {
++  log1("warning: qmail-send unable to understand qmail-todo\n");
++  return;
++ }
++
++ pe.id = id; pe.dt = now();
++ for (c = 0;c < CHANNELS;++c)
++   if (flagchan[c])
++     while (!prioq_insert(&pqchan[c],&pe)) nomem();
++
++ for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break;
++ if (c == CHANNELS)
++   while (!prioq_insert(&pqdone,&pe)) nomem();
++
++ return;
++}
++
++void todo_do(rfds)
++fd_set *rfds;
++{
++  int r;
++  char ch;
++  int i;
++  
++  if (!flagtodoalive) return;
++  if (!FD_ISSET(todofdin,rfds)) return;
++
++  r = read(todofdin,todobuf,sizeof(todobuf));
++  if (r == -1) return;
++  if (r == 0) {
++    if (flagexitasap)
++      flagtodoalive = 0;
++    else
++      tododied();
++    return;
++  }
++  for (i = 0;i < r;++i) {
++    ch = todobuf[i];
++    while (!stralloc_append(&todoline,&ch)) nomem();
++    if (todoline.len > REPORTMAX)
++      todoline.len = REPORTMAX;
++      /* qmail-todo is responsible for keeping it short */
++    if (!ch && (todoline.len > 1)) {
++      switch (todoline.s[0]) {
++	case 'D':
++	  if (flagexitasap) break;
++	  todo_del(todoline.s + 1);
++	  break;
++	case 'L':
++	  log1(todoline.s + 1);
++	  break;
++	case 'X':
++	  if (flagexitasap)
++	    flagtodoalive = 0;
++	  else
++	    tododied();
++	  break;
++	default:
++	  log1("warning: qmail-send unable to understand qmail-todo: report mangled\n");
++	  break;
++      }
++      todoline.len = 0;
++    }
++  }
++}
++
++#endif
+ 
+ /* this file is too long ---------------------------------------------- MAIN */
+ 
+ int getcontrols() { if (control_init() == -1) return 0;
++ if (control_readint(&bouncemaxbytes,"control/bouncemaxbytes") == -1) return 0;   
+  if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0;
+  if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0;
+  if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0;
+@@ -1449,6 +1618,8 @@
+  if (control_rldef(&bouncefrom,"control/bouncefrom",0,"MAILER-DAEMON") != 1) return 0;
+  if (control_rldef(&bouncehost,"control/bouncehost",1,"bouncehost") != 1) return 0;
+  if (control_rldef(&doublebouncehost,"control/doublebouncehost",1,"doublebouncehost") != 1) return 0;
++ if (control_readline(&srs_domain,"control/srs_domain") == -1) return 0;
++ if (srs_domain.len && !stralloc_0(&srs_domain)) return 0;
+  if (control_rldef(&doublebounceto,"control/doublebounceto",0,"postmaster") != 1) return 0;
+  if (!stralloc_cats(&doublebounceto,"@")) return 0;
+  if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0;
+@@ -1478,6 +1649,10 @@
+ 
+  if (control_readfile(&newlocals,"control/locals",1) != 1)
+   { log1("alert: unable to reread control/locals\n"); return; }
++ if (control_readint(&concurrency[0],"control/concurrencylocal") == -1)
++  { log1("alert: unable to reread control/concurrencylocal\n",0); return; }
++ if (control_readint(&concurrency[1],"control/concurrencyremote") == -1)
++  { log1("alert: unable to reread control/concurrencyremote\n",0); return; }
+  r = control_readfile(&newvdoms,"control/virtualdomains",0);
+  if (r == -1)
+   { log1("alert: unable to reread control/virtualdomains\n"); return; }
+@@ -1504,6 +1679,9 @@
+    log1("alert: unable to reread controls: unable to switch to home directory\n");
+    return;
+   }
++#ifdef EXTERNAL_TODO
++ write(todofdout, "H", 1);
++#endif
+  regetcontrols();
+  while (chdir("queue") == -1)
+   {
+@@ -1544,7 +1722,7 @@
+  numjobs = 0;
+  for (c = 0;c < CHANNELS;++c)
+   {
+-   char ch;
++   char ch, ch1;
+    int u;
+    int r;
+    do
+@@ -1552,7 +1730,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];
+   }
+@@ -1568,7 +1752,11 @@
+  todo_init();
+  cleanup_init();
+ 
++#ifdef EXTERNAL_TODO
++ while (!flagexitasap || !del_canexit() || flagtodoalive)
++#else
+  while (!flagexitasap || !del_canexit())
++#endif
+   {
+    recent = now();
+ 
+diff -ruN ../netqmail-1.06-original/qmail-showctl.c netqmail-1.06/qmail-showctl.c
+--- ../netqmail-1.06-original/qmail-showctl.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-showctl.c	2016-11-28 19:39:45.341600337 +0100
+@@ -15,6 +15,7 @@
+ #include "auto_patrn.h"
+ #include "auto_spawn.h"
+ #include "auto_split.h"
++#include "spf.h"
+ 
+ stralloc me = {0};
+ int meok;
+@@ -112,7 +113,7 @@
+   substdio_puts(subfdout,"\n");
+   substdio_puts(subfdout,fn);
+   substdio_puts(subfdout,": ");
+-  switch(control_readfile(&line,fn)) {
++  switch(control_readfile(&line,fn, 0)) {
+     case 0:
+       substdio_puts(subfdout,"(Default.) ");
+       substdio_puts(subfdout,def);
+@@ -214,14 +215,22 @@
+     _exit(111);
+   }
+ 
+-  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
++  do_lst("authsenders","No authenticated SMTP sender.","Authenicated SMTP sender: ","");
++  do_lst("badhelo","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern.");
++  do_lst("badhelonorelay","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern and RELAYCLIENT is not set.");
++  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("brtlimit","0","The brtlimit is ","");
+   do_int("concurrencylocal","10","Local concurrency is ","");
+   do_int("concurrencyremote","20","Remote concurrency is ","");
+   do_int("databytes","0","SMTP DATA limit is "," bytes");
+   do_str("defaultdomain",1,"defaultdomain","Default domain name is ");
+   do_str("defaulthost",1,"defaulthost","Default host name is ");
++  do_lst("dnsbllist","No dnsbl list configured.","List at "," configured for dnsbl check.");
+   do_str("doublebouncehost",1,"doublebouncehost","2B recipient host: ");
+   do_str("doublebounceto",0,"postmaster","2B recipient user: ");
+   do_str("envnoathost",1,"envnoathost","Presumed domain name is ");
+@@ -230,6 +239,9 @@
+   do_str("localiphost",1,"localiphost","Local IP address becomes ");
+   do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally.");
+   do_str("me",0,"undefined! Uh-oh","My name is ");
++  do_lst("moreipme","No additional IP addresses are me.","IP address "," is me.");
++  do_lst("notipme","All of my IP addresses are me.","IP address "," is not me.");
++  do_str("outgoingip",0,"0.0.0.0","Outgoing IP address is ");
+   do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@",".");
+   do_str("plusdomain",1,"plusdomain","Plus domain name is ");
+   do_lst("qmqpservers","No QMQP servers.","QMQP server: ",".");
+@@ -257,6 +269,15 @@
+ 
+   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_str("srs_domain",0,"","SRS domain name is ");
++  do_lst("srs_secrets","No secrets","","");
++  do_int("srs_maxage","21","SRS maxage is ","");
++  do_int("srs_hashlength","4","SRS hashlength is ","");
++  do_int("srs_hashmin","4","SRS hashmin is ","");
+   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");
+@@ -265,9 +286,12 @@
+   while (d = readdir(dir)) {
+     if (str_equal(d->d_name,".")) continue;
+     if (str_equal(d->d_name,"..")) continue;
+-    if (str_equal(d->d_name,"bouncefrom")) continue;
+-    if (str_equal(d->d_name,"bouncehost")) continue;
++    if (str_equal(d->d_name,"authsenders")) continue;
+     if (str_equal(d->d_name,"badmailfrom")) continue;
++    if (str_equal(d->d_name,"badhelo")) 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;
+@@ -275,6 +299,7 @@
+     if (str_equal(d->d_name,"databytes")) continue;
+     if (str_equal(d->d_name,"defaultdomain")) continue;
+     if (str_equal(d->d_name,"defaulthost")) continue;
++    if (str_equal(d->d_name,"dnsbllist")) continue;
+     if (str_equal(d->d_name,"doublebouncehost")) continue;
+     if (str_equal(d->d_name,"doublebounceto")) continue;
+     if (str_equal(d->d_name,"envnoathost")) continue;
+@@ -283,8 +308,10 @@
+     if (str_equal(d->d_name,"localiphost")) continue;
+     if (str_equal(d->d_name,"locals")) continue;
+     if (str_equal(d->d_name,"me")) continue;
++    if (str_equal(d->d_name,"moreipme")) continue;
+     if (str_equal(d->d_name,"morercpthosts")) continue;
+     if (str_equal(d->d_name,"morercpthosts.cdb")) continue;
++    if (str_equal(d->d_name,"notipme")) continue;
+     if (str_equal(d->d_name,"percenthack")) continue;
+     if (str_equal(d->d_name,"plusdomain")) continue;
+     if (str_equal(d->d_name,"qmqpservers")) continue;
+@@ -292,6 +319,15 @@
+     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,"srs_domain")) continue;
++    if (str_equal(d->d_name,"srs_secrets")) continue;
++    if (str_equal(d->d_name,"srs_maxage")) continue;
++    if (str_equal(d->d_name,"srs_hashlength")) continue;
++    if (str_equal(d->d_name,"srs_hashmin")) 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 -ruN ../netqmail-1.06-original/qmail-smtpd.8 netqmail-1.06/qmail-smtpd.8
+--- ../netqmail-1.06-original/qmail-smtpd.8	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-smtpd.8	2016-12-18 19:08:22.496459855 +0100
+@@ -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,34 @@
+ 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 badhelonorelay
++Functions the same as the
++.IR badhelo
++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 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 +104,61 @@
+ .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 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 badrcptto
++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 badrcptto .
++For more information, please have a look at doc/README.qregex.
++
++.TP 5
++.I brtlimit
++Number of bad recipients before closing the transmission channel.
++.B qmail-smtpd
++will close the transmission channel after 
++reaching the number of bad recipients in
++.IR brtlimit .
++Both badrcptto, chkuser and validrcptto failures are counted.
++
++If the environment variable
++.B BRTLIMIT 
++is set, it overrides
++.IR brtlimit .
++
++Default and minimum: 0.
++
++.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 +186,34 @@
+ .B DATABYTES
+ is set, it overrides
+ .IR databytes .
++
++.TP 5
++.I dh2048.pem
++If these 2048 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 dnsbllist
++A list of dnsbl providers that
++.B qmail-smtpd
++checks to identify blacklisted ip addresses.
++
++Exception:
++If the environment variable
++.B DNSBLSKIP
++is set,
++.B qmail-smtpd
++ignores
++.IR dnsbllist ,
++and the dnsbl check is not performed.
++The check is skipped even if some other authentication method succedeed
++and authorized the client to relay (smtp-auth or tls client certificate),
++or if
++.B RELAYCLIENT
++enviromnent variable is set.
++
+ .TP 5
+ .I localiphost
+ Replacement host name for local IP addresses.
+@@ -151,6 +289,19 @@
+ 
+ Envelope recipient addresses without @ signs are
+ always allowed through.
++
++.TP 5
++.I rsa2048.pem
++If this 2048 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,6 +320,119 @@
+ .B qmail-smtpd
+ will wait for each new buffer of data from the remote SMTP client.
+ Default: 1200.
++
++.SH "ENVIRONMENT VARIABLES READ"
++Environment variables may be defined globally in the
++.B qmail-smtpd
++startup script and/or individually as part of the
++.B tcpserver's
++cdb database.
++The environment variables may be quoted ("variable", or 'variable') and
++in case of global use, have to be exported.
++.B qmail-smtpd
++supports the following legacy environment variables, typically
++provided by
++.B tcpserver
++or
++.B sslserver
++or
++.BR tcp-env :
++.IR TCPREMOTEIP ,
++.IR TCPREMOTEHOST
++.IR TCPREMOTEINFO
++and
++.IR TCPLOCALPORT
++as well as
++.IR RELAYCLIENT .
++
++.B qmail-smtpd
++may use the following environment variables for SMTP authentication:
++.TP 5
++.IR SMTPAUTH
++is used to enable SMTP Authentication for the AUTH types
++LOGIN and PLAIN.
++In case
++.TP 5
++.IR SMTPAUTH='+cram'
++is defined,
++.B qmail-smtpd
++honors LOGIN, PLAIN, and additionally CRAM-MD5 authentication.
++Simply 
++.TP 5
++.IR SMTPAUTH='cram'
++restricts authentication just to CRAM-MD5.
++If however
++.TP 5
++.IR SMTPAUTH='!'
++starts with an exclamation mark, AUTH is required. 
++You can enforce 'Submission' using this option 
++and binding
++.B qmail-smtpd
++to the SUBMISSION port \'587'\.
++In particular,
++.TP 5
++.IR SMTPAUTH='!cram'
++may be useful.
++In opposite, if
++.TP 5
++.IR SMTPAUTH='-'
++starts with a dash, AUTH is disabled for particular
++connections.
++
++Note: The use of 'cram' requires a CRAM-MD5 enabled PAM.
++
++.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.
++
++.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.
+ .SH "SEE ALSO"
+ tcp-env(1),
+ tcp-environ(5),
+diff -ruN ../netqmail-1.06-original/qmail-smtpd.c netqmail-1.06/qmail-smtpd.c
+--- ../netqmail-1.06-original/qmail-smtpd.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/qmail-smtpd.c	2017-11-07 17:45:04.599607652 +0100
+@@ -12,6 +12,9 @@
+ #include "ip.h"
+ #include "qmail.h"
+ #include "str.h"
++#include "strerr.h"
++#include "qregex.h"
++#include "cdb.h"
+ #include "fmt.h"
+ #include "scan.h"
+ #include "byte.h"
+@@ -23,44 +26,178 @@
+ #include "timeoutread.h"
+ #include "timeoutwrite.h"
+ #include "commands.h"
++#include "dns.h"
++#include "wait.h"
++/* start chkuser code */
++#include "chkuser.h"
++/* end chkuser code */
++#include "spf.h"
++/* rbl: start */
++#include "strsalloc.h"
++/* rbl: end */
++
++#define AUTHSLEEP 5
+ 
+ #define MAXHOPS 100
++
++#define BMCHECK_BMF 0
++#define BMCHECK_BMFNR 1
++#define BMCHECK_BMT 2
++#define BMCHECK_BMTNR 3
++#define BMCHECK_BHELO 4
++#define BMCHECK_BHELONR 5
++
++static char strnum[FMT_ULONG];
+ unsigned int databytes = 0;
++unsigned int greetdelay = 0;
++unsigned int drop_pre_greet = 0;
+ int timeout = 1200;
++int maxrcpt = -1;
++unsigned int spfbehavior = 0;
++
++/* rejectrelaytest: start */
++unsigned int rejectrelaytest = 0;
++/* rejecrelayttest: end */
++/* rejectnullsenders: start */
++unsigned int rejnsmf = 0;
++/* rejectnullsenders: end */
++
++const char *protocol = "SMTP";
++
++/* spf ipv6 fix */
++char *remoteip4;
++/* end spf ipv6 fix */
++
++#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 */
++int forcetls = 1;
++#endif
+ 
+ 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;
+ }
+ 
+ char ssoutbuf[512];
++char sslogbuf[512];
+ substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
++substdio sslog = SUBSTDIO_FDBUF(safewrite,2,sslogbuf,sizeof sslogbuf);
++char sserrbuf[512];
++substdio sserr = SUBSTDIO_FDBUF(safewrite,2,sserrbuf,sizeof sserrbuf);
++
++int addrinrcpthosts = 0;
++int envelopepos = 0; // 1: ehlo/helo, 2: mailfrom, 3: rcptto: 4: data
++void qsmtpdlog(const char *head, const char *result, const char *reason, const char *detail, const char *statuscode);
++void qlogenvelope(char *result, char *reason, char *detail, char *statuscode) { qsmtpdlog("qlogenvelope",result,reason,detail,statuscode); }
++void qlogreceived(char *result, char *reason, char *detail, char *statuscode) { qsmtpdlog("qlogreceived",result,reason,detail,statuscode); }
+ 
++void logit(const char* message);
++void logit2(const char* message, const char* reason);
+ void flush() { substdio_flush(&ssout); }
+ void out(s) char *s; { substdio_puts(&ssout,s); }
+ 
+-void die_read() { _exit(1); }
+-void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
+-void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
+-void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
+-void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
+-void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
++void die_read() { logit("read failed"); _exit(1); }
++void die_alarm() { qlogenvelope("rejected","alarmtimeout","","451"); logit("timeout"); out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }
++void die_nomem() { qlogenvelope("rejected","outofmemory","","421"); out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
++void die_control() { qlogenvelope("rejected","cannotreadcontrols","","421"); logit("unable to read controls"); out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }
++void die_ipme() { qlogenvelope("rejected","unknownipme","","553"); logit("unable to figure out my IP addresses"); out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
++/* rbl: start */
++/*
++void die_dnsbl(arg)
++char *arg;
++{
++  out("421 your ip is currently blacklisted, try to auth first ("); out(arg); out(")\r\n");
++  logit2("message rejected (qmail-dnsbl)", arg);
++  flush();
++  _exit(1);
++}
++*/
++/* rbl: end */
++void err_maxrcpt()
++{
++  out("553 max rcpt limit exceeded (#5.7.1)\r\n");
++  logit("max rcpt limit exceeded (qmail-maxrcpt)");
++  qlogenvelope("rejected","maxrcpt","","553");
++  flush();
++}
++void straynewline() { qlogenvelope("rejected","badnewlines","","451"); logit("bad newlines"); out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
++void die_pre_greet() { qlogenvelope("rejected","pregreet","","554"); out("554 SMTP protocol violation\r\n"); flush(); _exit(1); }
+ 
+-void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+-void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
++void err_size() { qlogreceived("rejected","size","","552"); out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); }
++#ifndef TLS
++void err_nogateway() { qlogenvelope("rejected","notinrcpthosts","","553"); out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
++#else
++void err_nogateway()
++{
++  qlogenvelope("rejected","notinrcpthosts","","553"); 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_unrecog() { out("500 unrecognised (#5.5.2)\r\n"); }
+ void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
+ void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
+ void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
+ void err_noop(arg) char *arg; { out("250 ok\r\n"); }
+ 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"); }
++void err_qqt() { qlogenvelope("rejected","qqtfailure","","451"); 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() { qlogenvelope("rejected","authfailed","","535"); out("535 authentication failed (#5.7.1)\r\n"); }
++void err_submission() { qlogenvelope("rejected","authrequired","","530"); out("530 Authorization required (#5.7.1) \r\n"); }
++void err_vrt() { qlogenvelope("rejected","validrcptto","","553"); out("553 sorry, this recipient is not in my validrcptto list (#5.7.1)\r\n"); }
++void die_brtlimit() { qlogenvelope("rejected","brtlimit","","421"); out("421 too many invalid addresses, goodbye (#4.3.0)\r\n"); flush(); _exit(1); }
++void err_rcpt() { qlogenvelope("rejected","nomailbox","","550"); out("550 sorry, no mailbox here by that name (#5.1.1)\r\n"); }
++/* rcptcheck: start */
++void die_fork() { qlogenvelope("rejected","rcptcheck","cannotfork","421"); out("421 unable to fork (#4.3.0)\r\n"); flush(); _exit(1); }
++void die_rcpt() { qlogenvelope("rejected","rcptcheck","cannotverify","421"); out("421 unable to verify recipient (#4.3.0)\r\n"); flush(); _exit(1); }
++void die_rcpt2() { qlogenvelope("rejected","rcptcheck","cannotexecute","421"); out("421 unable to execute recipient check (#4.3.0)\r\n"); flush(); _exit(1); }
++/* rcptcheck: end */
++/* qregex: start */
++/*
++void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\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"); }
++/* qregex: end */
++/* rejectnullsenders: start */
++void die_nullsender() { qlogenvelope("rejected","nullsenderdenied","","421"); out("421 null senders temporarily denied (#4.3.0)\r\n"); flush(); _exit(1); }
++/* rejectnullsenders: end */
++/* rejectrelaytest: start */
++void err_relay() { qlogenvelope("rejected","dontrelay","","553"); out("553 we don't relay (#5.7.1)\r\n"); }
++/* rejectrelaytest: end */
++/* authtlsvariables: start */
++void err_authmismatch() { qlogenvelope("rejected","authnotmailfrom","","503"); out("503 from and auth not the same (#5.5.1)\r\n"); }
++/* authtlsvariables: end */
+ 
+ stralloc greeting = {0};
++stralloc spflocal = {0};
++stralloc spfguess = {0};
++stralloc spfexp = {0};
+ 
+ void smtp_greet(code) char *code;
+ {
+@@ -76,11 +213,33 @@
+   smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
+ }
+ 
++/* char *protocol; */
+ char *remoteip;
+ char *remotehost;
+ char *remoteinfo;
+ char *local;
++char *localport;
++char *submission;
+ char *relayclient;
++char *dnsblskip;
++char *auth;
++/* authtlsvariables: start */
++int flagtls = 0;
++int forceauthmailfrom = 0;
++int disabletls = 0;
++/* authtlsvariables: end */
++
++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 */
++static stralloc chal = {0};     /* plain challenge */
++static stralloc slop = {0};     /* b64 challenge */
++
++char **childargs;
++char ssauthbuf[512];
++substdio ssauth = SUBSTDIO_FDBUF(safewrite,3,ssauthbuf,sizeof(ssauthbuf));
+ 
+ stralloc helohost = {0};
+ char *fakehelo; /* pointer into helohost, or 0 */
+@@ -91,11 +250,101 @@
+   fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+ }
+ 
++int smtpauth = 0;
+ int liphostok = 0;
+ stralloc liphost = {0};
+ int bmfok = 0;
+ stralloc bmf = {0};
+-struct constmap mapbmf;
++
++/* rbl: start */
++int flagrbldns = 0;
++int flagrbldelay = 0;
++int flagrblfailclosed = 0;
++int flagmustnotbounce = 0;
++static stralloc rbldnslist = {0};
++static stralloc rblhost = {0};
++int rblhosterror = 0;
++int rbllistok = 0;
++int rblok = 0;
++char *ip_env;
++static stralloc ip_reverse;
++int rbldecision = 0; /* 0 undecided, 1 accept, 2 reject (451), 3 bounce (553) */
++static stralloc rbltext = {0}; /* defined if rbldecision is 2 or 3 */
++static stralloc rblmessage = {0};
++static stralloc rblserver = {0};
++
++void err_rblreject() {
++  if (env_get("RBLSMTPD")) {
++    qlogenvelope("rejected","rblreject","rblsmtpd","553");
++  }
++  else {
++    if (rblserver.len) qlogenvelope("rejected","rblreject",rblserver.s,"553");
++    else qlogenvelope("rejected","rblreject","","553");
++  }
++  substdio_put(&ssout,rblmessage.s,rblmessage.len);
++  flush();
++}
++
++void die_rbldelay() {
++  if (env_get("RBLSMTPD")) {
++    qlogenvelope("rejected","rbldelay","rblsmtpd","451");
++  }
++  else {
++    if (rblserver.len) qlogenvelope("rejected","rbldelay",rblserver.s,"451");
++    else qlogenvelope("rejected","rbldelay","","451");
++  }
++  substdio_put(&ssout,rblmessage.s,rblmessage.len); flush();
++  _exit(1);
++}
++/* rbl: end */
++
++/* qregex: start */
++/*
++ 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};
++
++int bhelonrok = 0;
++stralloc bhelonr = {0};
++
++int logregex = 0;
++stralloc matchedregex = {0};
++/* qregex: end */
++
++/* validrcptto.cdb: start */
++int vrtok = 0;
++stralloc vrt = {0};
++struct constmap mapvrt;
++
++int vrtfd = -1;
++int vrtcount = 0;
++int vrtlog_do = 0;
++
++stralloc title = {0};
++char pid_buf[FMT_ULONG];
++/* validrcptto.cdb: end */
++
++/* realbadrcpt: start */
++int brtlimit = 0;
++static char strnumpid[FMT_ULONG];
++static char strnumqp[FMT_ULONG];
++/* realbadrcpt: end */
++
++/* rcptcheck: start */
++static char *rcptcheck[2] = { 0, 0 };
++char rcptcheck_err[1024];
++int rcptcheckrelayclient = 0;
++/* rcptcheck: end */
+ 
+ void setup()
+ {
+@@ -109,21 +358,110 @@
+   if (liphostok == -1) die_control();
+   if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
+   if (timeout <= 0) timeout = 1;
++  if (control_readint(&maxrcpt,"control/maxrcpt") == -1) die_control();
+ 
+   if (rcpthosts_init() == -1) die_control();
+ 
+   bmfok = control_readfile(&bmf,"control/badmailfrom",0);
+   if (bmfok == -1) die_control();
++/* qregex: start */
++/*
+   if (bmfok)
+     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
++*/
++  strnumpid[fmt_uint(strnumpid,(unsigned int) getpid())] = 0;
++
++  bmfnrok = control_readfile(&bmfnr,"control/badmailfromnorelay",0);
++  if (bmfnrok == -1) die_control();
++
++  bmtok = control_readfile(&bmt,"control/badrcptto",0);
++  if (bmtok == -1) die_control();
++
++  bmtnrok = control_readfile(&bmtnr,"control/badrcpttonorelay",0);
++  if (bmtnrok == -1) die_control();
++
++  bhelook = control_readfile(&bhelo, "control/badhelo",0);
++  if (bhelook == -1) die_control();
++
++  bhelonrok = control_readfile(&bhelonr, "control/badhelonorelay",0);
++  if (bhelonrok == -1) die_control();
++
++  if (env_get("LOGREGEX")) logregex = 1;
++/* qregex: end */
++
++/* validrcptto.cdb: start */
++  x = env_get("VALIDRCPTTO");
++  if (x) { vrtok = control_readfile(&vrt,x,0); }
++  else vrtok = control_readfile(&vrt,"control/validrcptto",0);
++  if (vrtok == -1) die_control();
++  if (vrtok)
++  if (!constmap_init(&mapvrt,vrt.s,vrt.len,0)) die_nomem();
++
++  x = env_get("MOREVALIDRCPTTO_CDB");
++  if (x) { vrtfd = open_read(x); }
++  else vrtfd = open_read("control/morevalidrcptto.cdb");
++  if (-1 == vrtfd) if (errno != error_noent) die_control();
++
++  x = env_get("VALIDRCPTTO_LOG");
++  if(x) { scan_ulong(x,&u); vrtlog_do = (int) u; }
++/* validrcptto.cdb: end */
++
++/* realbadrcpt: start */
++  if (control_readint(&brtlimit,"control/brtlimit") == -1) die_control();
++  x = env_get("BRTLIMIT");
++  if (x) { scan_ulong(x,&u); brtlimit = u; };
++  /* Disable limits check, defaults to 0 */
++/*  if (brtlimit <= 1) brtlimit = 2; */
++/* realbadrcpt: end */
++
++/* rcptcheck: start */
++  rcptcheck[0] = env_get("RCPTCHECK");
++
++  x = env_get("RCPTCHECKRELAYCLIENT");
++  if (x) { scan_ulong(x,&u); rcptcheckrelayclient = u; };
++/* rcptcheck: end */
++
++/* rejectrelaytest: start */
++  if (control_readint(&rejectrelaytest,"control/rejectrelaytest") == -1) die_control();
++/* rejectrelaytest: end */
++
++/* rejectnullsenders: start */
++  if (control_readint(&rejnsmf,"control/rejectnullsenders") == -1) die_control();
++/* rejectnullsenders: end */
+  
+   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;
+- 
++
++  x = env_get("SMTPD_GREETDELAY");
++  if (x) { scan_ulong(x, &u); greetdelay = u; }
++  x = env_get("DROP_PRE_GREET");
++  if (x) { scan_ulong(x, &u); drop_pre_greet = u; }
++
++  protocol = "SMTP";
++
++  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();
++
++  /* spf ipv6 fix */
++  if (!(remoteip4 = env_get("TCPREMOTEIP")))
++      remoteip4 = "unknown";
++  /* end spf ipv6 fix */
+   remoteip = env_get("TCPREMOTEIP");
+   if (!remoteip) remoteip = "unknown";
++  localport = env_get("TCPLOCALPORT");
++  if (!localport) localport = "0";
+   local = env_get("TCPLOCALHOST");
+   if (!local) local = env_get("TCPLOCALIP");
+   if (!local) local = "unknown";
+@@ -131,10 +469,67 @@
+   if (!remotehost) remotehost = "unknown";
+   remoteinfo = env_get("TCPREMOTEINFO");
+   relayclient = env_get("RELAYCLIENT");
++  dnsblskip = env_get("DNSBLSKIP");
++/* rbl: start */
++  x = env_get("DNSBLLIST");
++  if (x) {
++    rbllistok = control_readfile(&rbldnslist,x,0);
++    if (rbllistok == -1) die_control();
++    if (rbllistok) rblok = 1;
++  }
++  else {
++    rbllistok = control_readfile(&rbldnslist,"control/dnsbllist",0);
++    if (rbllistok == -1) die_control();
++    if (rbllistok) rblok = 1;
++  }
++
++  /* from rblsmtpd.c, if RBLSMTPD is defined and empty then accept mail, if defined and string begins with '-' then
++     block mail using error code 553 + string without hyphen, else (if defined, not null and not beginning with '-')
++     reject mail using error code 451 + string  */
++  x = env_get("RBLSMTPD");
++  if (x) {
++    if (!*x)
++      rbldecision = 1;
++    else if (*x == '-') {
++      if (!stralloc_copys(&rbltext,x + 1)) die_nomem();
++      rbldecision = 3;
++    }
++    else {
++      if (!stralloc_copys(&rbltext,x)) die_nomem();
++      rbldecision = 2;
++    }
++    rblok = 1;
++  }
++  
++  if (control_readint(&flagrblfailclosed,"control/dnsblfailclosed") == -1) die_control();
++  x = env_get("DNSBLFAILCLOSED");
++  if (x) { scan_ulong(x,&u); flagrblfailclosed = u; }
++/* rbl: end */
++  auth = env_get("SMTPAUTH");
++  if (auth) {
++    smtpauth = 1;
++    case_lowers(auth);
++    if (!case_diffs(auth,"-") || !case_diffs(auth,"0")) smtpauth = 0;
++    if (!case_diffs(auth,"!")) smtpauth = 11;
++    if (case_starts(auth,"cram")) smtpauth = 2;
++    if (case_starts(auth,"+cram")) smtpauth = 3;
++    if (case_starts(auth,"!cram")) smtpauth = 12;
++    if (case_starts(auth,"!+cram")) smtpauth = 13;
++  }
++/* authtlsvariables: start */
++  x = env_get("FORCEAUTHMAILFROM"); if (x) if (!str_diff(x,"1")) { forceauthmailfrom = 1; }
++  #ifdef TLS
++  x = env_get("DISABLETLS"); if (x) if (!str_diff(x,"1")) { disabletls = 1; }
++  #endif
++/* authtlsvariables: end */
++  #ifdef TLS
++  x = env_get("FORCETLS"); if (x) if (!str_diff(x, "0")) forcetls = 0;
++  if (env_get("SMTPS")) { smtps = 1; tls_init(); }
++  else
++  #endif
+   dohelo(remotehost);
+ }
+ 
+-
+ stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+ 
+ int addrparse(arg)
+@@ -155,6 +550,7 @@
+     terminator = ' ';
+     arg += str_chr(arg,':');
+     if (*arg == ':') ++arg;
++    if (*arg == '\0') return 0;
+     while (*arg == ' ') ++arg;
+   }
+ 
+@@ -197,6 +593,8 @@
+   return 1;
+ }
+ 
++/* qregex: start */
++/*
+ int bmfcheck()
+ {
+   int j;
+@@ -207,68 +605,1102 @@
+     if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+   return 0;
+ }
++*/
++int bmcheck(which) int which;
++{
++  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 if (which == BMCHECK_BHELONR) {
++    if (!stralloc_copy(&bmb,&bhelonr)) 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)) {
++      if (!stralloc_copyb(&matchedregex,bmb.s + j - 1,(i - j + 1))) die_nomem();
++      if (!stralloc_0(&matchedregex)) die_nomem();
++      return 1;
++    }
++    if (!(negate) && (x > 0)) {
++      if (!stralloc_copyb(&matchedregex,bmb.s + j,(i - j))) die_nomem();
++      if (!stralloc_0(&matchedregex)) die_nomem();
++      return 1;
++    }
++    j = i + 1;
++    negate = 0;
++  }
++  return 0;
++}
++/* qregex: end */
++
++/* validrcptto.cdb: start */
++void vrtlog(l,a,b)
++int l;
++const char *a;
++const char *b;
++{
++/*  if (l <= vrtlog_do)
++    strerr_warn6(title.s,"validrcptto [",remoteip,"] ",a,b,0);*/
++}
++
++int vrtcheck()
++{
++  static char *rcptto = "RCPT TO: ";
++  static char *trying = "trying: ";
++  static char *found  = "found: ";
++  static char *reject = "reject: ";
++  char *f = 0;
++  int j,k,r;
++  uint32 dlen;
++  stralloc laddr = {0};
++
++  stralloc luser = {0};
++  stralloc adom = {0};
++  stralloc utry = {0};
++  stralloc stnoaddr = {0};
++  stralloc stnodom = {0};
++
++  int atfound, okaddr, okdom, noaddr, nodom;
++
++  /* if both validrcptto and morevalidrcptto.cdb are missing, consider valid the recipient */
++  if (!((vrtok) || (vrtfd != -1))) return 1;
++
++  okaddr = 0; okdom = 0; noaddr = 0; nodom = 0; atfound = 0;
++
++  /* lowercase whatever we were sent */
++  if (!stralloc_copy(&laddr,&addr)) die_nomem() ;
++  case_lowerb(laddr.s,laddr.len);
++
++  /* split user/domain parts, create negated stralloc */
++  j = byte_rchr(laddr.s,laddr.len,'@');
++  if (j < laddr.len) {
++    atfound = 1;
++    if (!stralloc_copyb(&luser,laddr.s,j)) die_nomem();
++    if (!stralloc_copyb(&adom,laddr.s+j,laddr.len-j-1)) die_nomem();
++
++    if (!stralloc_copys(&stnodom,"-")) die_nomem();
++    if (!stralloc_cat(&stnodom,&adom)) die_nomem();
++    if (!stralloc_0(&stnodom)) die_nomem();
++
++    if (!stralloc_copys(&stnoaddr,"-")) die_nomem();
++    if (!stralloc_cat(&stnoaddr,&luser)) die_nomem();
++    if (!stralloc_cat(&stnoaddr,&adom)) die_nomem();
++    if (!stralloc_0(&stnoaddr)) die_nomem();
++  }
++  /* validrcptto */
++  if (vrtok) {
++    vrtlog(rcptto,laddr.s,0);
++    if (constmap(&mapvrt,laddr.s,laddr.len - 1)) { okaddr = 1; vrtlog(found,laddr.s,0); }
++    if (atfound) {
++      if (constmap(&mapvrt,stnoaddr.s,stnoaddr.len-1)) { noaddr= 1; vrtlog(reject,stnoaddr.s,0); }
++      if (constmap(&mapvrt,laddr.s+j,laddr.len-j-1)) { okdom = 1; vrtlog(found,laddr.s+j,0); }
++      if (constmap(&mapvrt,stnodom.s,stnodom.len-1)) { nodom = 1; vrtlog(reject,stnodom.s,0); }
++    }
++  }
++  
++  /* morevalidrcptto.cdb */
++  if ((vrtfd != -1)) {
++    vrtlog(rcptto,laddr.s,0);
++
++    if (cdb_seek(vrtfd,laddr.s,laddr.len-1,&dlen) > 0) { okaddr = 1; vrtlog(found,laddr.s,0); }
++    if (atfound) {
++      if (cdb_seek(vrtfd,stnoaddr.s,stnoaddr.len-1,&dlen) > 0) { noaddr = 1; vrtlog(reject,stnoaddr.s,0); }
++      if (cdb_seek(vrtfd,laddr.s+j,laddr.len-j-1,&dlen) > 0) { okdom = 1; vrtlog(found,laddr.s+j,0); }
++      if (cdb_seek(vrtfd,stnodom.s,stnodom.len-1,&dlen) > 0) { nodom = 1; vrtlog(reject,stnodom.s,0); }
++    }
++  }
++
++  if (okaddr) return 1;
++  else if (noaddr) return -1;
++  else if (okdom) return 1;
++  else if (nodom) return -1;
++  else return 0;
++}
++/* validrcptto.cdb: end */
++
++/* rbl: start */
++void rbl(char *base)
++{
++  int i,j;
++  int whitelisted = 0;
++  int altmustbounce = 0;
++  char *altreply = 0;
++  strsalloc ssa = {0};
++
++  if (!str_len(base)) return;
++  if (!stralloc_copys(&rbltext,"")) die_nomem();
++  if (!stralloc_copys(&rblhost,"")) die_nomem();
++  if (!stralloc_copys(&rblserver,"")) die_nomem();
++
++  if (!stralloc_copy(&rblhost,&ip_reverse)) die_nomem();
++  i = str_chr(base, ':');
++  if (base[i]) {
++    if (base[i+1] == '-') { /* if reply begins with '-', message must bounce (check rblsmtpd man page) */
++      altreply = base+i+2;
++      altmustbounce = 1;
++    }
++    else altreply = base+i+1;
++  }
++
++  if (base[0] == '+') { /* entries beginning with '+' are for whitelistedlists */
++    whitelisted = 1;
++    if (!stralloc_catb(&rblhost,base+1,i-1)) die_nomem();
++    if (!stralloc_catb(&rblserver,base+1,i-1)) die_nomem();
++  }
++  else if (base[0] == '-') { /* force bounce (553 error message), instead of default reject (451) */
++    whitelisted = 0;
++    if (!stralloc_catb(&rblhost,base+1,i-1)) die_nomem();
++    if (!stralloc_catb(&rblserver,base+1,i-1)) die_nomem();
++    altmustbounce = 1;
++  }
++  else {
++    if (!stralloc_catb(&rblhost,base,i)) die_nomem();
++    if (!stralloc_catb(&rblserver,base,i)) die_nomem();
++  }
++  if (!stralloc_0(&rblhost)) die_nomem();
++  if (!stralloc_0(&rblserver)) die_nomem();
++
++  rblhosterror = 0; /* set in case of dns errors */
++
++  if (altreply) { /* if text response is defined in control file, query A records */
++    if (dns_ip(&rbltext,&rblhost) == -1) {
++      flagmustnotbounce = 1;
++      rblhosterror = 1;
++      if (flagrblfailclosed) {
++        if (!stralloc_copys(&rbltext,"temporary RBL lookup error")) die_nomem();
++        if (whitelisted) rbldecision = 1; else rbldecision = 2;
++      }
++      return;
++    }
++    if (rbltext.len) {
++      if(!stralloc_copys(&rbltext, "")) die_nomem();
++      while(*altreply) {
++        i = str_chr(altreply, '%');
++        if(!stralloc_catb(&rbltext, altreply, i)) die_nomem();
++        if(altreply[i] &&
++           altreply[i+1]=='I' &&
++           altreply[i+2]=='P' &&
++           altreply[i+3]=='%') {
++          if(!stralloc_catb(&rbltext, ip_env, str_len(ip_env))) die_nomem();
++          altreply+=i+4;
++        } else if(altreply[i]) {
++          if(!stralloc_cats(&rbltext, "%")) die_nomem();
++          altreply+=i+1;
++        } else {
++          altreply+=i;
++        }
++      }
++    }
++  } else { /* normal rbl query looks for TXT record */
++    if (dns_txt(&ssa,&rblhost) == -1) { /* DNS_SOFT = -1, DNS_HARD = -2, DNS_MEM = -3 */
++      flagmustnotbounce = 1;
++      rblhosterror = 1;
++      if (flagrblfailclosed) {
++        if (!stralloc_copys(&rbltext,"temporary RBL lookup error")) die_nomem();
++        if (whitelisted) rbldecision = 1; else rbldecision = 2;
++      }
++      return;
++    }
++    else {
++      /* in case of multiple records, take only the first */
++      if (ssa.len > 0)
++        if (!stralloc_cat(&rbltext,&ssa.sa[0])) die_nomem();
++      /* in case of multiple records, append results to rbltext */
++      /*for (j = 0;j < ssa.len;++j) if (!stralloc_cat(&rbltext,&ssa.sa[j])) die_nomem();*/
++    }
++  }
++  if (rbltext.len) {
++    if (whitelisted) {
++      rbldecision = 1;
++    }
++    else {
++      if (altmustbounce)
++        rbldecision = 3;
++      else
++        rbldecision = 2;
++    }
++  }
++  else rbldecision = 0;
++}
++
++int rblcheck()
++{
++  char *ch;
++  unsigned int i;
++  unsigned int j;
++  stralloc sar = {0};
++
++  if (rbldecision) return rbldecision; /* rbldecision already set in case of RBLSMTPD or if rblcheck was executed previously */
++  if (!rbllistok) return 0;
++
++  ip_env = env_get("TCPREMOTEIP");
++  if (!ip_env) ip_env = "";
++  if (!stralloc_copys(&ip_reverse,"")) die_nomem();
++
++  i = str_len(ip_env);
++  while (i) {
++    for (j = i;j > 0;--j) if (ip_env[j - 1] == '.') break;
++    if (!stralloc_catb(&ip_reverse,ip_env + j,i - j)) die_nomem();
++    if (!stralloc_cats(&ip_reverse,".")) die_nomem();
++    if (!j) break;
++    i = j - 1;
++  }
++  
++  ch = rbldnslist.s;
++  while (ch < (rbldnslist.s + rbldnslist.len)) {
++    rbl(ch);
++    /* debug log */
++    if (!stralloc_copys(&sar,title.s)) die_nomem();
++    if (!stralloc_cats(&sar,"rbl: ip=")) die_nomem();
++    if (!stralloc_cats(&sar,ip_env)) die_nomem();
++    if (!stralloc_cats(&sar," query=")) die_nomem();
++    if (!stralloc_cats(&sar,rblhost.s)) die_nomem();
++    if (rblhosterror) {
++      if (!stralloc_cats(&sar," result=dnserr")) die_nomem();
++    }
++    else {
++      if (!stralloc_cats(&sar," result=")) die_nomem();
++      switch (rbldecision) {
++        case 0: if (!stralloc_cats(&sar,"ignore")) die_nomem(); break;
++        case 1: if (!stralloc_cats(&sar,"accept")) die_nomem(); break;
++        case 2: if (!stralloc_cats(&sar,"delay")) die_nomem(); break;
++        case 3: if (!stralloc_cats(&sar,"reject")) die_nomem(); break;
++      }
++    }
++    if (!stralloc_cats(&sar," message='")) die_nomem();
++    if (!stralloc_catb(&sar,rbltext.s,rbltext.len)) die_nomem();
++    if (!stralloc_cats(&sar,"'")) die_nomem();
++    if (!stralloc_0(&sar)) die_nomem();
++    strerr_warn1(sar.s,0);
++    /* end debug log */
++    if (rbldecision) break;
++    while (*ch++);
++  }
++  return rbldecision;
++}
++/* rbl: end */
++
++int sizelimit(arg)
++char *arg;
++{
++  int i;
++  long r;
++  unsigned long sizebytes = 0;
++
++  i = str_chr(arg,'<');
++  if (arg[i])
++    arg += i + 1;
++  else {
++    arg += str_chr(arg,':');
++    if (*arg == ':') ++arg;
++    while (*arg == ' ') ++arg;
++  }
++
++  arg += str_chr(arg,' ');
++  if (*arg == ' ') while (*arg == ' ') ++arg;
++  else return 1;
++
++  i = str_chr(arg,'=');
++  arg[i] = 0;
++  if (case_equals(arg,"SIZE")) {
++    arg += i;
++    while (*++arg && *arg > 47 && *arg < 58) {
++      sizebytes *= 10;
++      sizebytes += *arg - 48;
++    }
++    r = databytes - sizebytes;
++    if (r < 0) return 0;
++  }
++  return 1;
++}
+ 
+ int addrallowed()
+ {
+   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;
+ }
+ 
++/* rejectrelaytest: start */
++int addrrelay()
++{
++  if (!rejectrelaytest) { return 0; }
++  else
++  {
++    int j;
++    j = addr.len;
++    while(--j >= 0)
++      if (addr.s[j] == '@') break;
++    if (j < 0) j = addr.len;
++    while(--j >= 0) {
++      if (addr.s[j] == '@') return 1;
++      if (addr.s[j] == '%') return 1;
++      if (addr.s[j] == '!') return 1;
++    }
++    return 0;
++  }
++}
++/* rejectrelaytest: end */
+ 
++int seenauth = 0;
+ int seenmail = 0;
+-int flagbarf; /* defined if seenmail */
++int rcptcount = 0;
++
++/* qregex: start */
++/*
++int flagbarf;
++*/
++int flagbarfbmf; /* defined if seenmail */
++int flagbarfbmt;
++int flagbarfbhelo;
++/* qregex: end */
++
++int flagsize;
++int flagbarfspf;
++stralloc spfbarfmsg = {0};
+ stralloc mailfrom = {0};
+ stralloc rcptto = {0};
++stralloc fuser = {0};
++stralloc mfparms = {0};
++stralloc log_buf = {0};
++
++/* realbadrcpt: start */
++int flagvrt; /* defined if valid rcpt */
++int brtcount = 0; /* for brtlimit count */
++/* realbadrcpt: end */
++
++/* rcptcheck: start */
++int addrvalid()
++{
++  int pid;
++  int wstat;
++  int pierr[2] ;
++  substdio ss;
++  char ssbuf[sizeof(rcptcheck_err)];
++  int len = 0 ;
++  char ch;
++
++  if (!rcptcheck[0]) return 1;
++  if (pipe(pierr) == -1) die_rcpt2();
++
++  switch(pid = fork()) {
++    case -1:
++      close(pierr[0]);
++      close(pierr[1]);
++      die_fork();
++    case 0:
++      if (!env_put2("SENDER",mailfrom.s)) die_nomem();
++      if (!env_put2("RECIPIENT",addr.s)) die_nomem();
++      if (!env_put2("HELO",helohost.s)) die_nomem();
++      if (!env_put2("USE_FD4","1")) die_nomem();
++      close(1);
++      dup2(2,1);
++      close(pierr[0]);
++      if (fd_move(4,pierr[1]) == -1) die_rcpt2();
++      execv(*rcptcheck,rcptcheck);
++      _exit(120);
++  }
++
++  close(pierr[1]);
++  if (wait_pid(&wstat,pid) == -1) die_rcpt2();
++  if (wait_crashed(wstat)) die_rcpt2();
++
++  substdio_fdbuf(&ss,read,pierr[0],ssbuf,sizeof(ssbuf));
++  while ( substdio_bget(&ss,&ch,1) && len < (sizeof(ssbuf)-3) )
++    rcptcheck_err[len++] = ch;
++  close(pierr[0]);
++
++  while (len&&((rcptcheck_err[len-1]=='\n')||(rcptcheck_err[len-1]=='\r')))
++    len -- ;
++  if (len) {
++    rcptcheck_err[len] = '\0';
++    strerr_warn3(title.s,"RCPTCHECK error: ",rcptcheck_err,0);
++    rcptcheck_err[len++] = '\r';
++    rcptcheck_err[len++] = '\n';
++  }
++  rcptcheck_err[len] = '\0';
++
++  switch(wait_exitcode(wstat)) {
++    case 100:
++      return 0;
++    case 111:
++      die_rcpt();
++    case 112:
++      return 2; // ignore
++    case 113:
++      return 3; // overlimit
++    case 120:
++      die_rcpt2();
++  }
++  return 1;
++}
++/* rcptcheck: end */
++
++int checkrcptcount() {
++  if (maxrcpt == -1) {return 0;}
++  else if (rcptcount > maxrcpt) {return 1;}
++  else {return 0;}
++}
++
++void logit(message) const char* message;
++{
++  if (!stralloc_copys(&log_buf, "qmail-smtpd: ")) die_nomem();
++  if (!stralloc_cats(&log_buf, message)) die_nomem();
++  if (!stralloc_catb(&log_buf, ": ", 2)) die_nomem();
++  if (mailfrom.s) {
++      if (!stralloc_catb(&log_buf, mailfrom.s, mailfrom.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_catb(&log_buf, " from ", 6)) die_nomem();
++  if (!stralloc_cats(&log_buf, remoteip)) die_nomem();
++  if (!stralloc_catb(&log_buf, " to ", 4)) die_nomem();
++  if (addr.s) {
++      if (!stralloc_catb(&log_buf, addr.s, addr.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_catb(&log_buf, " helo ", 6)) die_nomem();
++  if (helohost.s) {
++      if (!stralloc_catb(&log_buf, helohost.s, helohost.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_catb(&log_buf, "\n", 1)) die_nomem();
++  substdio_putflush(&sserr, log_buf);
++}
++
++void logit2(message, reason)
++const char* message;
++const char* reason;
++{
++  if (!stralloc_copys(&log_buf,"qmail-smtpd: ")) die_nomem();
++  if (!stralloc_cats(&log_buf, message)) die_nomem();
++  if (!stralloc_cats(&log_buf, " (")) die_nomem();
++  if (!stralloc_cats(&log_buf, reason)) die_nomem();
++  if (!stralloc_cats(&log_buf, "): ")) die_nomem();
++  if (mailfrom.s) {
++      if (!stralloc_catb(&log_buf, mailfrom.s, mailfrom.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_cats(&log_buf," from ")) die_nomem();
++  if (!stralloc_cats(&log_buf, remoteip)) die_nomem();
++  if (!stralloc_cats(&log_buf, " to ")) die_nomem();
++  if (addr.s) {
++      if (!stralloc_catb(&log_buf, addr.s, addr.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_cats(&log_buf, " helo ")) die_nomem();
++  if (helohost.s) {
++      if (!stralloc_catb(&log_buf, helohost.s, helohost.len-1)) die_nomem();
++  } else
++      if (!stralloc_catb(&log_buf, "(null)", 6)) die_nomem();
++  if (!stralloc_catb(&log_buf, "\n", 1)) die_nomem();
++  substdio_putflush(&sserr, log_buf);
++}
++
++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;
++{
++  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;
+ {
++  envelopepos = 1;
+   smtp_greet("250 "); out("\r\n");
+   seenmail = 0; dohelo(arg);
++  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
++  if ((!flagbarfbhelo) && (bhelonrok) && (!relayclient)) flagbarfbhelo = bmcheck(BMCHECK_BHELONR);
++}
++char size_buf[FMT_ULONG];
++void smtp_size()
++{
++  size_buf[fmt_ulong(size_buf,(unsigned long) databytes)] = 0;
++  out("250 SIZE "); out(size_buf); out("\r\n");
+ }
++
++/* 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
++  size[fmt_ulong(size,(unsigned int) databytes)] = 0;
++  envelopepos = 1;
++  smtp_greet("250-");
++  #ifdef TLS
++  if (!disabletls && !ssl && (stat("control/servercert.pem",&st) == 0))
++  out("\r\n250-STARTTLS");
++  #endif
++  out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n");
++#ifdef TLS
++  if (!forcetls || ssl) {
++#endif
++  if (smtpauth == 1 || smtpauth == 11) out("250-AUTH LOGIN PLAIN\r\n");
++  if (smtpauth == 3 || smtpauth == 13) out("250-AUTH LOGIN PLAIN CRAM-MD5\r\n");
++  if (smtpauth == 2 || smtpauth == 12) out("250-AUTH CRAM-MD5\r\n");
++#ifdef TLS
++  }
++#endif
++  smtp_size();
+   seenmail = 0; dohelo(arg);
++  if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO);
++  if ((!flagbarfbhelo) && (bhelonrok) && (!relayclient)) flagbarfbhelo = bmcheck(BMCHECK_BHELONR);
+ }
+ void smtp_rset(arg) char *arg;
+ {
+-  seenmail = 0;
++  seenmail = 0; /* seenauth = 0; RFC 5321: retain authentication */
++  mailfrom.len = 0; rcptto.len = 0;
+   out("250 flushed\r\n");
+ }
++
+ void smtp_mail(arg) char *arg;
+ {
++  int r;
++
++  envelopepos = 2;
++  if (smtpauth)
++    if (smtpauth > 10 && !seenauth) { err_submission(); return; }
+   if (!addrparse(arg)) { err_syntax(); return; }
++  if (databytes && !sizelimit(arg)) { err_size(); return; }
++/* start chkuser code */
++  switch (chkuser_sender (&addr)) {
++    case CHKUSER_OK:
++	break;
++    case CHKUSER_ERR_MUSTAUTH:
++	qlogenvelope("rejected","chkusersender","mustauth","530");
++	return;
++	break;
++    case CHKUSER_ERR_SENDER_FORMAT:
++	qlogenvelope("rejected","chkusersender","senderformat","553");
++	return;
++	break;
++    case CHKUSER_ERR_SENDER_MX:
++	qlogenvelope("rejected","chkusersender","sendermxinvalid","550");
++	return;
++	break;
++    case CHKUSER_ERR_SENDER_MX_TMP:
++	qlogenvelope("rejected","chkusersender","sendermxdnstmpfail","451");
++	return;
++	break;
++    default:
++	qlogenvelope("rejected","chkusersender","invalid","550");
++	return;
++	break;
++   }
++/* end chkuser code */
++/* authtlsvariables: start */
++    /* if it is authenticated but MAIL FROM and AUTH USER are different */
++    if (smtpauth && seenauth && forceauthmailfrom) {
++      if (strcmp(addr.s,user.s)) { err_authmismatch(); return; }
++    }
++/* authtlsvariables: end */
++/* rejectnullsenders: start */
++  if ((rejnsmf) && (addr.len <= 1)) { die_nullsender(); return; }
++/* rejectnullsenders: end */
++/* qregex: start */
++  /*
++  flagbarf = bmfcheck();
++  */
++  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);
++  }
++/* qregex: end */
++  flagsize = 0;
++  mailfrom_parms(arg);
++  if (flagsize) { err_size(); return; }
++
++/* qregex: start */
++  /*
+   flagbarf = bmfcheck();
++  */
++  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);
++  }
++/* qregex: end */
++
++  flagbarfspf = 0;
++  if (spfbehavior && !relayclient)
++   { 
++    switch(r = spfcheck(remoteip4)) {
++    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;
++      qlogenvelope("rejected","spf","lookupfailure","451");
++      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();
+   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");
++    }
++  }
++}
++
++int flagdnsbl = 0;
++stralloc dnsblhost = {0};
++
+ void smtp_rcpt(arg) char *arg; {
++  int flagrcptmatch = 0; /* 0 undefined, 1 validrcptto, 2 chkuser, 3 chkuserrelay, 4 rcptcheck */
++/* added by empf patch */
++  int ret = 0;
++/* end of empf pacth  */
++  envelopepos = 3;
+   if (!seenmail) { err_wantmail(); return; }
+   if (!addrparse(arg)) { err_syntax(); return; }
++/* rejectrelaytest: start */
++  if (addrrelay()) { err_relay(); return; }
++/* rejectrelaytest: end */
++  if (addr.len) addrinrcpthosts = addrallowed();
++  else addrinrcpthosts = 0;
++/* qregex: start */
++  /*
+   if (flagbarf) { err_bmf(); return; }
+-  if (relayclient) {
++  */
++  if (flagbarfbhelo) {
++    if (logregex) {
++      strerr_warn5(title.s,"badhelo: <",helohost.s,"> matches pattern: ",matchedregex.s,0);
++    } else {
++      strerr_warn5(title.s,"badhelo: <",helohost.s,"> at ",remoteip,0);
++    }
++    qlogenvelope("rejected","qregexbhelo",matchedregex.s,"553");
++    err_bhelo();
++    return;
++  }
++
++  if (flagbarfbmf) {
++    if (logregex) {
++      strerr_warn5(title.s,"badmailfrom: <",mailfrom.s,"> matches pattern: ",matchedregex.s,0);
++    } else {
++      strerr_warn5(title.s,"badmailfrom: <",mailfrom.s,"> at ",remoteip,0);
++    }
++    qlogenvelope("rejected","qregexbmf",matchedregex.s,"553");
++    err_bmf();
++    return;
++  }
++/* qregex: end */
++
++  if (flagbarfspf) { qlogenvelope("rejected","spf",env_get("SPFRESULT"),"550"); err_spf(); return; }
++
++/* dnsbl: start */
++/*
++  if (!(relayclient || dnsblskip || flagdnsbl))
++    if (dnsblcheck()) die_dnsbl(dnsblhost.s);
++*/
++/* dnsbl: end */
++/* start chkuser code */
++/*  if (relayclient) {
+     --addr.len;
+     if (!stralloc_cats(&addr,relayclient)) die_nomem();
+     if (!stralloc_0(&addr)) die_nomem();
+   }
+   else
+     if (!addrallowed()) { err_nogateway(); return; }
++*/
++
++/* qregex: start */
++    if (brtlimit && (brtcount >= brtlimit)) {
++      strerr_warn3(title.s,"badrcptto: excessive rcptto violations hanging up on ",remoteip,0);
++      die_brtlimit();
++    }
++
++    if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT);
++    if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) {
++      flagbarfbmt = bmcheck(BMCHECK_BMTNR);
++    }
++    if (flagbarfbmt) {
++      if (logregex) {
++        strerr_warn5(title.s,"badrcptto: <",addr.s,"> matches pattern: ",matchedregex.s,0);
++      } else {
++        strerr_warn5(title.s,"badrcptto: <",addr.s,"> at ",remoteip,0);
++      }
++      qlogenvelope("rejected","qregexbmt",matchedregex.s,"553");
++      ++brtcount;
++      err_bmt();
++      return;
++    }
++/* qregex: end */
++
++/* realbadrcpt: start */
++  if (!relayclient) {	/* if relayclient is defined, skip valid recipient checking */
++    /* validrcptto */
++    flagvrt = 0;
++    int vrtres = 0;
++    if ((vrtok) || (vrtfd != -1)) {  /* run check only if validrcptto or morevalidrcptto.cdb exist */
++      vrtres = vrtcheck();
++      if (vrtres > 0) {
++        flagvrt = 1;
++	flagrcptmatch = 1;
++        strerr_warn5(title.s,"validrcptto: accepted address <",addr.s,"> at ",remoteip,0);
++      }
++      else if (vrtres < 0) {
++        strerr_warn5(title.s,"validrcptto: drop address <",addr.s,"> at ",remoteip,0);
++        ++brtcount;
++        err_vrt();
++        /*err_rcpt();*/
++        return;
++      }
++    }
++
++    if (!flagvrt) {
++      switch (chkuser_realrcpt (&mailfrom, &addr)) {
++         case CHKUSER_OK:
++		flagrcptmatch = 2;
++                break;
++         case CHKUSER_RELAYING:
++                --addr.len;
++                if (!stralloc_cats(&addr,relayclient)) die_nomem();
++                if (!stralloc_0(&addr)) die_nomem();
++		flagrcptmatch = 3;
++                break;
++         case CHKUSER_NORCPTHOSTS:
++                qlogenvelope("rejected","chkuser","notinrcpthosts","553");
++                ++brtcount;
++                return;
++                break;
++         case CHKUSER_KO:
++                qlogenvelope("rejected","chkuser","nomailbox","550");
++            	++brtcount;
++                return;
++                break;
++         case CHKUSER_ERR_AUTH_RESOURCE:
++                qlogenvelope("rejected","chkuser","noauthresource","451");
++                return;
++                break;
++         case CHKUSER_ERR_MUSTAUTH:
++                qlogenvelope("rejected","chkuser","mustauth","530");
++                return;
++                break;
++         case CHKUSER_ERR_MBXFULL:
++                qlogenvelope("rejected","chkuser","mailboxfull","552");
++                return;
++                break;
++         case CHKUSER_ERR_MAXRCPT:
++                qlogenvelope("rejected","chkuser","maxrcpt","550");
++                return;
++                break;
++         case CHKUSER_ERR_MAXWRONGRCPT:
++                qlogenvelope("rejected","chkuser","maxwrongrcpt","550");
++                return;
++                break;
++         case CHKUSER_ERR_INTRUSION_THRESHOLD:
++                qlogenvelope("rejected","chkuser","instrusionthreshold","550");
++                ++brtcount;
++                return;
++                break;
++         case CHKUSER_ERR_DOMAIN_MISSING:
++                qlogenvelope("rejected","chkuser","domainmissing","550");
++            	++brtcount;
++                return;
++                break;
++         case CHKUSER_ERR_RCPT_FORMAT:
++                qlogenvelope("rejected","chkuser","rcptformat","553");
++                ++brtcount;
++                return;
++                break;
++         case CHKUSER_ERR_RCPT_MX:
++                qlogenvelope("rejected","chkuser","rcptmxinvalid","550");
++            	++brtcount;
++                return;
++                break;
++         case CHKUSER_ERR_RCPT_MX_TMP:
++                qlogenvelope("rejected","chkuser","rcptmxdnstmpfail","451");
++                return;
++                break;
++         default:
++                qlogenvelope("rejected","chkuser","invalid","550");
++                return;
++                break;
++      }
++    }
++  } // if (!relayclient)
++ 
++
++  /* rcptcheck */
++  if ( (rcptcheck[0]) && (!relayclient || rcptcheckrelayclient) ) { // if RCPTCHECK is not defined, addrvalid returns 1 (rcpt ok),check before calling
++    strerr_warn5(title.s,"rcptcheck: checking <",addr.s,"> at ",remoteip,0);
++    if (flagrcptmatch) {
++      if (!env_put2("RCPTFOUND","1")) die_nomem();
++    }
++    else {
++      if (!env_unset("RCPTFOUND")) die_nomem();
++    }
++    if (addrinrcpthosts) {
++      if (!env_put2("RCPTHOSTS","1")) die_nomem();
++    }
++    else {
++      if (!env_unset("RCPTHOSTS")) die_nomem();
++    }
++
++    int rcres = 0;
++    rcres = addrvalid();
++
++    char smtperrcode[4];
++    char *smtperrstrptr;
++    long smtperrcodenum = 0;
++    int len = 0;
++    int closesession = 0;
++
++    if ((rcptcheck_err[0]) && (sizeof(rcptcheck_err) > 3)) {
++      strncpy(smtperrcode,rcptcheck_err,3);
++      smtperrcode[3] = '\0';
++      smtperrcodenum = strtoul(smtperrcode, &smtperrstrptr, 10);
++      if ((smtperrcodenum >= 400) && (smtperrcodenum <=599)) {
++        if (smtperrcodenum == 421) closesession = 1;
++      }
++      else {
++        len = str_copy(rcptcheck_err,"451 temporary problem (#4.4.2)\r\n");
++        rcptcheck_err[len] = '\0' ;
++      }
++      qlogenvelope("rejected","rcptcheck","custom",smtperrcode);
++    }
++    else {
++      switch (rcres) {
++        case 0:
++          strerr_warn5(title.s,"rcptcheck: drop address <",addr.s,"> at ",remoteip,0);
++          qlogenvelope("rejected","rcptcheck","nomailbox","550");
++          len = str_copy(rcptcheck_err,"550 sorry, no mailbox here by that name. (#5.1.1)\r\n");
++          rcptcheck_err[len] = '\0';
++          break;
++        case 1:
++          strerr_warn5(title.s,"rcptcheck: accepted address <",addr.s,"> at ",remoteip,0);
++          flagrcptmatch = 4;
++          break;
++        case 2:
++          strerr_warn5(title.s,"rcptcheck: ignore address <",addr.s,"> at ",remoteip,0);
++          break;
++        case 3:
++          strerr_warn5(title.s,"rcptcheck: overlimit sender <",addr.s,"> at ",remoteip,0);
++          qlogenvelope("rejected","rcptcheck","overlimit","421");
++          len = str_copy(rcptcheck_err,"421 you have exceeded your messaging limits (#4.3.0)\r\n");
++          rcptcheck_err[len] = '\0';
++          closesession = 1;
++          break;
++      }
++    }
++
++    if ( (rcres == 0) || (rcres == 3) ) {
++      out(rcptcheck_err); flush();
++      if (closesession) {
++        _exit(1);
++      }
++      return;
++    }
++  } // if rcptcheck[0]
++/* realbadrcpt: end */
++
++/* end chkuser code */
++/* rbl: start */
++  if ((rblok) && !(relayclient || seenauth || dnsblskip || flagrbldns)) {
++    flagrbldns = 1;
++    rblcheck();
++  }
++  if (rbldecision >= 2) {
++    if (!stralloc_ready(&rblmessage,0)) die_nomem();
++    if (flagmustnotbounce || (rbldecision == 2)) {
++      if (!stralloc_copys(&rblmessage,"451 ")) die_nomem();
++    }
++    else
++      if (!stralloc_copys(&rblmessage,"553 ")) die_nomem();
++        if (rbltext.len > 500) rbltext.len = 500;
++    if (!stralloc_cat(&rblmessage,&rbltext)) die_nomem();
++    int i;
++    for (i = 0;i < rblmessage.len;++i)
++      if ((rblmessage.s[i] < 32) || (rblmessage.s[i] > 126))
++              rblmessage.s[i] = '?';
++        if (!stralloc_cats(&rblmessage,"\r\n")) die_nomem();
++    if (flagmustnotbounce || (rbldecision == 2)) die_rbldelay();
++    else err_rblreject();
++    return;
++  }
++/* rbl: end */
++
++/* start empf code */
++  ret = policy_check();
++
++  if (ret == 1) {
++    if (!stralloc_cats(&rcptto,"T")) die_nomem();
++    if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
++    if (!stralloc_0(&rcptto)) die_nomem();
++    rcptcount++;
++    if (checkrcptcount() == 1) { err_maxrcpt(); return; }
++    if (flagrcptmatch == 1) { qlogenvelope("accepted","rcptto","validrcptto","250"); }
++    else if (flagrcptmatch == 2) { qlogenvelope("accepted","rcptto","chkuser","250"); }
++    else if (flagrcptmatch == 3) { qlogenvelope("accepted","rcptto","chkuserrelay","250"); }
++    else if (flagrcptmatch == 4) { qlogenvelope("accepted","rcptto","rcptcheck","250"); }
++    else {
++      if (relayclient) { qlogenvelope("accepted","relayclient","","250"); }
++      else { qlogenvelope("accepted","rcpthosts","","250"); }
++    }
++    out("250 ok\r\n");
++  }
++
++  else if (ret == 0) {
++    qlogenvelope("rejected","empf","","550");
++    out("550 cannot message ");
++    out(addr.s);
++    out(" (#5.0.0 denied by policy)\r\n");
++  }
++
++  else {
++    qlogenvelope("rejected","empf","","454");
++    out("454 cannot message ");
++    out(addr.s);
++    out(" (#4.3.0 broken policy)\r\n");
++ }
++/* end of empf code */
++
++/*
++ * code substituted by empf code
+   if (!stralloc_cats(&rcptto,"T")) die_nomem();
+   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
+   if (!stralloc_0(&rcptto)) die_nomem();
++  rcptcount++;
++  if (checkrcptcount() == 1) { err_maxrcpt(); return; }
+   out("250 ok\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();
+@@ -277,6 +1709,9 @@
+ 
+ char ssinbuf[1024];
+ substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
++#ifdef TLS
++void flush_io() { ssin.p = 0; flush(); }
++#endif
+ 
+ struct qmail qqt;
+ unsigned int bytestooverflow = 0;
+@@ -300,7 +1735,7 @@
+   int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
+   int flagmaybey; /* 1 if this line might match \r\n, if fih */
+   int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
+- 
++
+   state = 1;
+   *hops = 0;
+   flaginheader = 1;
+@@ -322,17 +1757,16 @@
+     }
+     switch(state) {
+       case 0:
+-        if (ch == '\n') straynewline();
++        if (ch == '\n') { state = 1; break; }
+         if (ch == '\r') { state = 4; continue; }
+         break;
+       case 1: /* \r\n */
+-        if (ch == '\n') straynewline();
+         if (ch == '.') { state = 2; continue; }
+         if (ch == '\r') { state = 4; continue; }
+-        state = 0;
++        if (ch != '\n') state = 0;
+         break;
+       case 2: /* \r\n + . */
+-        if (ch == '\n') straynewline();
++        if (ch == '\n') return;        /* this is what sendmail-8.8.4 does -djg */
+         if (ch == '\r') { state = 3; continue; }
+         state = 0;
+         break;
+@@ -351,10 +1785,73 @@
+   }
+ }
+ 
++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);
++}
++
++/* rbl: start */
++/*
++int dnsblcheck()
++{
++  char *ch;
++  static stralloc dnsblbyte = {0};
++  static stralloc dnsblrev = {0};
++  static ipalloc dnsblip = {0};
++  static stralloc dnsbllist = {0};
++
++  ch = remoteip;
++  if(control_readfile(&dnsbllist,"control/dnsbllist",0) != 1) return 0;
++
++  if (!stralloc_copys(&dnsblrev,"")) return 0;
++  for (;;) {
++    if (!stralloc_copys(&dnsblbyte,"")) return 0;
++    while (ch[0] && (ch[0] != '.')) {
++      if (!stralloc_append(&dnsblbyte,ch)) return 0;
++      ch++;
++    }
++    if (!stralloc_append(&dnsblbyte,".")) return 0;
++    if (!stralloc_cat(&dnsblbyte,&dnsblrev)) return 0;
++    if (!stralloc_copy(&dnsblrev,&dnsblbyte)) return 0;
++
++    if (!ch[0]) break;
++    ch++;
++  }
++
++  flagdnsbl = 1;
++  ch = dnsbllist.s;
++  while (ch < (dnsbllist.s + dnsbllist.len)) {
++    if (!stralloc_copy(&dnsblhost,&dnsblrev)) return 0;
++    if (!stralloc_cats(&dnsblhost,ch)) return 0;
++    if (!stralloc_0(&dnsblhost)) return 0;
++
++    if (!dns_ip(&dnsblip,&dnsblhost)) return 1;
++    while (*ch++);
++  }
++
++  return 0;
++}
++*/
++/* rbl:end */
++
+ char accept_buf[FMT_ULONG];
+ void acceptmessage(qp) unsigned long qp;
+ {
+   datetime_sec when;
++  strnum[fmt_uint(strnum,(unsigned int) getpid())] = 0;
+   when = now();
+   out("250 ok ");
+   accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
+@@ -363,22 +1860,32 @@
+   accept_buf[fmt_ulong(accept_buf,qp)] = 0;
+   out(accept_buf);
+   out("\r\n");
++  substdio_puts(&sslog, "mail recv: pid ");
++  substdio_puts(&sslog, strnum);
++  substdio_puts(&sslog, " from <");
++  substdio_puts(&sslog, mailfrom.s);
++  substdio_puts(&sslog, "> qp ");
++  substdio_puts(&sslog, accept_buf);
++  substdio_putsflush(&sslog, "\n");
+ }
+ 
+ void smtp_data(arg) char *arg; {
+   int hops;
+   unsigned long qp;
+   char *qqx;
+- 
++
+   if (!seenmail) { err_wantmail(); return; }
+   if (!rcptto.len) { err_wantrcpt(); return; }
++  envelopepos = 4;
+   seenmail = 0;
+   if (databytes) bytestooverflow = databytes + 1;
+   if (qmail_open(&qqt) == -1) { err_qqt(); return; }
+   qp = qmail_qp(&qqt);
++  strnumqp[fmt_ulong(strnumqp,qp)] = 0; /* qp for qlog */
+   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);
+@@ -386,34 +1893,631 @@
+   qmail_put(&qqt,rcptto.s,rcptto.len);
+  
+   qqx = qmail_close(&qqt);
+-  if (!*qqx) { acceptmessage(qp); return; }
+-  if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
+-  if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; }
+-  if (*qqx == 'D') out("554 "); else out("451 ");
++  if (!*qqx) { acceptmessage(qp); logit("message accepted"); qlogreceived("accepted","queueaccept","","250"); return; }
++  if (hops) {
++    out("554 too many hops, this message is looping (#5.4.6)\r\n");
++    logit("message looping");
++    qlogreceived("rejected","mailloop","","554");
++    return;
++  }
++  if (databytes) if (!bytestooverflow) {
++    err_size();
++    logit("message too big");
++    return;
++  }
++  if (*qqx == 'D') {
++    out("554 ");
++    qlogreceived("rejected","queuereject",qqx + 1,"554");
++    logit2("message rejected", qqx + 1);
++  } else {
++    out("451 ");
++    qlogreceived("rejected","queuedelay",qqx + 1,"451");
++    logit2("message delayed", qqx + 1);
++  }
+   out(qqx + 1);
+   out("\r\n");
+ }
+ 
++
++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();
++  if (!stralloc_0(&chal)) die_nomem();
++
++  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();
++  if (smtpauth == 2 || smtpauth == 3 || smtpauth == 12 || smtpauth == 13)
++    if (substdio_put(&ssauth,chal.s,chal.len) == -1) return err_write();
++  if (substdio_flush(&ssauth) == -1) return err_write();
++
++  close(pi[1]);
++  if (!stralloc_copys(&chal,"")) die_nomem();
++  if (!stralloc_copys(&slop,"")) die_nomem();
++  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();
++}
++
++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_rchr(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();
++}
++
++struct authcmd {
++  char *text;
++  int (*fun)();
++} authcmds[] = {
++  { "login",auth_login }
++, { "plain",auth_plain }
++, { "cram-md5",auth_cram }
++, { 0,err_noauth }
++};
++
++void smtp_auth(arg)
++char *arg;
++{
++  int i;
++  char *cmd = arg;
++  if (!smtpauth || !*childargs) { out("503 auth not available (#5.3.3)\r\n"); return; }
++  if (seenauth) { err_authd(); return; }
++  if (seenmail) { err_authmail(); return; }
++#ifdef TLS
++  if (forcetls && !ssl) { out("538 auth not available without TLS (#5.3.3)\r\n"); return; }
++#endif
++
++  if (!stralloc_copys(&user,"")) die_nomem();
++  if (!stralloc_copys(&pass,"")) die_nomem();
++  if (!stralloc_copys(&resp,"")) die_nomem();
++  if (!stralloc_copys(&chal,"")) die_nomem();
++
++  i = str_chr(cmd,' ');
++  arg = cmd + i;
++  while (*arg == ' ') ++arg;
++  cmd[i] = 0;
++
++  for (i = 0;authcmds[i].text;++i)
++    if (case_equals(authcmds[i].text,cmd)) break;
++
++  switch (authcmds[i].fun(arg)) {
++    case 0:
++      seenauth = 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();
++
++      if (!env_unset("SMTPAUTHMETHOD")) die_read();
++      if (!env_put2("SMTPAUTHMETHOD", authcmds[i].text)) die_nomem();
++      if (!env_unset("SMTPAUTHUSER")) die_read();
++      if (!env_put2("SMTPAUTHUSER",user.s)) die_nomem();
++      if (!env_unset("SMTP_AUTH_USER")) die_read();
++      if (!env_put2("SMTP_AUTH_USER",user.s)) die_nomem();
++
++      strerr_warn4(title.s,"auth: auth-success type=login user=<",user.s,">",0);
++      out("235 ok, go ahead (#2.0.0)\r\n");
++      break;
++    case 1:
++      strerr_warn4(title.s,"auth: auth-failed type=login user=<",user.s,">",0);
++      err_authfail(user.s,authcmds[i].text);
++  }
++}
++
++#ifdef TLS
++stralloc proto = {0};
++int ssl_verified = 0;
++const char *ssl_verify_err = 0;
++
++void smtp_tls(char *arg)
++{
++  if (ssl || disabletls) 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 = 2048;
++  if (keylen == 2048) {
++    FILE *in = fopen("control/rsa2048.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 = 2048;
++  if (keylen == 2048) {
++    FILE *in = fopen("control/dh2048.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 = "";
++      /* also inform qmail-queue */
++      if (!env_put("RELAYCLIENT=")) die_nomem();
++      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; }
++
++  /* POODLE vulnerability */
++  SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
++
++  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
++
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L
++  /* support ECDH */
++  SSL_CTX_set_ecdh_auto(ctx,1);
++#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", 0) == -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) { flagtls = 1; 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, "ESMTPS (")
++    || !stralloc_cats(&proto, SSL_get_cipher(ssl))
++    || !stralloc_cats(&proto, " encrypted)")) 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_io }
++#endif
+ , { "noop", err_noop, flush }
+ , { "vrfy", err_vrfy, flush }
+-, { 0, err_unimpl, flush }
++, { 0, err_unrecog, flush }
+ } ;
+ 
+-void main()
++/* qsmtpdlog: start */
++void qsmtpdlog(const char *head, const char *result, const char *reason, const char *detail, const char *statuscode) {
++  char *x;
++  char *ch;
++  int i, r;
++  stralloc lst = {0};
++  int isenvelope = 0;
++  
++  void outqlog(char *s, unsigned int n) {
++    while (n > 0) {
++      substdio_put(&sslog,((*s > 32) && (*s <= 126)) ? s : "_",1);
++      --n;
++      ++s;
++    }
++  }
++  void outsqlog(s) char *s; { outqlog(s,str_len(s)); }
++
++  stralloc_copys(&lst,head);
++  if (stralloc_starts(&lst,"qlogenvelope")) isenvelope = 1;
++  substdio_puts(&sslog, head);
++  substdio_puts(&sslog, ":");
++
++  substdio_puts(&sslog, " result="); if (result) outsqlog(result);
++  substdio_puts(&sslog, " code="); if (detail) outsqlog(statuscode);
++  substdio_puts(&sslog, " reason="); if (reason) outsqlog(reason);
++  substdio_puts(&sslog, " detail="); if (detail) outsqlog(detail);
++  substdio_puts(&sslog, " helo="); if (helohost.len) outsqlog(helohost.s);
++  substdio_puts(&sslog, " mailfrom=");
++  if (mailfrom.len) outsqlog(mailfrom.s);
++  else if ( (envelopepos==2) && (addr.len) ) outsqlog(addr.s); // qlog called in smtp_mail() doesn't have mailfrom.s defined yet
++
++  substdio_puts(&sslog, " rcptto=");
++  if ((rcptto.len) && (!isenvelope)) {
++    ch = rcptto.s;
++    outsqlog(ch+1);
++    while (*ch++);
++    while (ch < (rcptto.s + rcptto.len)) {
++      outsqlog(",");
++      outsqlog(ch+1);
++      while (*ch++);
++    }
++  }
++  else if ( (envelopepos==3) && (addr.len) ) outsqlog(addr.s); // qlog was probably called at the beginning of smtp_rcpt and addr.s contains the recipient
++
++  substdio_puts(&sslog, " relay="); if (relayclient) outsqlog("yes"); else outsqlog("no");
++
++  // only log rcpthosts value in smtp_rcpt(), that is for a single recipient, this field is meaningless for multiple recipients
++  substdio_puts(&sslog, " rcpthosts="); if (isenvelope && addr.len && (envelopepos==3)) { if (addrinrcpthosts) outsqlog("yes"); else outsqlog("no"); }
++
++  substdio_puts(&sslog, " size=");
++  if (bytestooverflow) {
++    char *p,text[20];
++    if ((databytes - bytestooverflow) >= 0)
++      sprintf(text,"%d",databytes - bytestooverflow);
++    else
++      sprintf(text,"");
++    p = text;
++    outsqlog(p);
++  }
++
++  substdio_puts(&sslog, " authuser="); if (user.len) outsqlog(user.s);
++  substdio_puts(&sslog, " authtype="); x = env_get("SMTPAUTHMETHOD"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " encrypted="); if (smtps) outsqlog("ssl"); else if (flagtls) outsqlog("tls");
++
++  substdio_puts(&sslog, " sslverified=");
++#ifdef TLS
++  if (ssl_verified) outsqlog("yes"); else outsqlog("no");
++#endif
++/*
++  substdio_puts(&sslog, " sslproto=");
++#ifdef TLS
++  if (proto.len) outsqlog(proto.s);
++#endif
++*/
++  substdio_puts(&sslog, " localip="); x = env_get("TCPLOCALIP"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " localport="); x = env_get("TCPLOCALPORT"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " remoteip="); x = env_get("TCPREMOTEIP"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " remoteport="); x = env_get("TCPREMOTEPORT"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " remotehost="); x = env_get("TCPREMOTEHOST"); if (x) outsqlog(x);
++  substdio_puts(&sslog, " qp="); if (strnumqp) outsqlog(strnumqp);
++  substdio_puts(&sslog, " pid="); if (strnumpid) outsqlog(strnumpid);
++  substdio_putsflush(&sslog, "\n");
++}
++/* qsmtpdlog: end */
++
++void main(argc,argv)
++int argc;
++char **argv;
+ {
++  int n, m;
++  childargs = argv + 1;
+   sig_pipeignore();
+   if (chdir(auto_qmail) == -1) die_control();
++
++  pid_buf[fmt_ulong(pid_buf,getpid())]=0;
++  if (!stralloc_copys(&title,"qmail-smtpd[")) die_nomem();
++  if (!stralloc_cats(&title,pid_buf)) die_nomem();
++  if (!stralloc_cats(&title,"]: ")) die_nomem();
++  if (!stralloc_0(&title)) die_nomem();
++
+   setup();
+   if (ipme_init() != 1) die_ipme();
++  if (!relayclient && greetdelay) {
++    if (drop_pre_greet) {
++      n = timeoutread(greetdelay ? greetdelay : 1, 0, ssinbuf, sizeof(ssinbuf));
++      if(n == -1) {
++        if (errno != error_timeout)
++          strerr_die3sys(1, "GREETDELAY from ", remoteip, ": ");
++      } else if (n == 0) {
++        strerr_die3x(1, "GREETDELAY from ", remoteip, ": client disconnected");
++      } else {
++        strerr_warn3("GREETDELAY from ", remoteip, ": client sent data before greeting", 0);
++        die_pre_greet();
++      }
++    }
++    else {
++      strerr_warn3("GREETDELAY: ", greetdelay, "s", 0);
++      sleep(greetdelay);
++      m = 0;
++      for (;;) {
++        n = timeoutread(0, 0, ssinbuf, sizeof(ssinbuf));
++        if (n <= 0)
++          break;
++        if (n > 0 && m == 0) {
++          strerr_warn3("GREETDELAY from ", remoteip, ": client sent data before greeting. ignoring", 0);
++          m = 1;
++        }
++      }
++    }
++  }
++
+   smtp_greet("220 ");
+   out(" ESMTP\r\n");
+   if (commands(&ssin,&smtpcommands) == 0) die_read();
+diff -ruN ../netqmail-1.06-original/qmail-start.c netqmail-1.06/qmail-start.c
+--- ../netqmail-1.06-original/qmail-start.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail-start.c	2016-11-22 21:03:57.125527665 +0100
+@@ -8,6 +8,9 @@
+ char *(qcargs[]) = { "qmail-clean", 0 };
+ char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
+ char *(qrargs[]) = { "qmail-rspawn", 0 };
++#ifdef EXTERNAL_TODO
++char *(qtargs[]) = { "qmail-todo", 0};
++#endif
+ 
+ void die() { _exit(111); }
+ 
+@@ -18,13 +21,28 @@
+ int pi4[2];
+ int pi5[2];
+ int pi6[2];
+-
+-void close23456() { close(2); close(3); close(4); close(5); close(6); }
++#ifdef EXTERNAL_TODO
++int pi7[2];
++int pi8[2];
++int pi9[2];
++int pi10[2];
++#endif
++
++void close23456() { 
++  close(2); close(3); close(4); close(5); close(6); 
++#ifdef EXTERNAL_TODO
++  close(7); close(8);
++#endif
++}
+ 
+ void closepipes() {
+   close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]);
+   close(pi3[0]); close(pi3[1]); close(pi4[0]); close(pi4[1]);
+   close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]);
++#ifdef EXTERNAL_TODO
++  close(pi7[0]); close(pi7[1]); close(pi8[0]); close(pi8[1]);
++	close(pi9[0]); close(pi9[1]); close(pi10[0]); close(pi10[1]);
++#endif
+ }
+ 
+ void main(argc,argv)
+@@ -40,6 +58,10 @@
+   if (fd_copy(4,0) == -1) die();
+   if (fd_copy(5,0) == -1) die();
+   if (fd_copy(6,0) == -1) die();
++#ifdef EXTERNAL_TODO
++  if (fd_copy(7,0) == -1) die();
++  if (fd_copy(8,0) == -1) die();
++#endif
+ 
+   if (argv[1]) {
+     qlargs[1] = argv[1];
+@@ -70,6 +92,12 @@
+   if (pipe(pi4) == -1) die();
+   if (pipe(pi5) == -1) die();
+   if (pipe(pi6) == -1) die();
++#ifdef EXTERNAL_TODO
++  if (pipe(pi7) == -1) die();
++  if (pipe(pi8) == -1) die();
++  if (pipe(pi9) == -1) die();
++  if (pipe(pi10) == -1) die();
++#endif
+  
+   switch(fork()) {
+     case -1: die();
+@@ -106,6 +134,34 @@
+       die();
+   }
+  
++#ifdef EXTERNAL_TODO
++  switch(fork()) {
++    case -1: die();
++    case 0:
++      if (prot_uid(auto_uids) == -1) die();
++      if (fd_copy(0,pi7[0]) == -1) die();
++      if (fd_copy(1,pi8[1]) == -1) die();
++      close23456();
++      if (fd_copy(2,pi9[1]) == -1) die();
++      if (fd_copy(3,pi10[0]) == -1) die();
++      closepipes();
++      execvp(*qtargs,qtargs);
++      die();
++  }
++
++  switch(fork()) {
++    case -1: die();
++    case 0:
++      if (prot_uid(auto_uidq) == -1) die();
++      if (fd_copy(0,pi9[0]) == -1) die();
++      if (fd_copy(1,pi10[1]) == -1) die();
++      close23456();
++      closepipes();
++      execvp(*qcargs,qcargs);
++      die();
++  }
++#endif
++ 
+   if (prot_uid(auto_uids) == -1) die();
+   if (fd_copy(0,1) == -1) die();
+   if (fd_copy(1,pi1[1]) == -1) die();
+@@ -114,6 +170,10 @@
+   if (fd_copy(4,pi4[0]) == -1) die();
+   if (fd_copy(5,pi5[1]) == -1) die();
+   if (fd_copy(6,pi6[0]) == -1) die();
++#ifdef EXTERNAL_TODO
++  if (fd_copy(7,pi7[1]) == -1) die();
++  if (fd_copy(8,pi8[0]) == -1) die();
++#endif
+   closepipes();
+   execvp(*qsargs,qsargs);
+   die();
+diff -ruN ../netqmail-1.06-original/qmail-todo.c netqmail-1.06/qmail-todo.c
+--- ../netqmail-1.06-original/qmail-todo.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qmail-todo.c	2016-11-22 21:03:57.126527632 +0100
+@@ -0,0 +1,703 @@
++#include <sys/types.h>
++#include <sys/stat.h>
++#include "alloc.h"
++#include "auto_qmail.h"
++#include "byte.h"
++#include "constmap.h"
++#include "control.h"
++#include "direntry.h"
++#include "error.h"
++#include "exit.h"
++#include "fmt.h"
++#include "fmtqfn.h"
++#include "getln.h"
++#include "open.h"
++#include "ndelay.h"
++#include "now.h"
++#include "readsubdir.h"
++#include "readwrite.h"
++#include "scan.h"
++#include "select.h"
++#include "str.h"
++#include "stralloc.h"
++#include "substdio.h"
++#include "trigger.h"
++
++/* critical timing feature #1: if not triggered, do not busy-loop */
++/* critical timing feature #2: if triggered, respond within fixed time */
++/* important timing feature: when triggered, respond instantly */
++#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
++#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
++#define SLEEP_FOREVER 86400 /* absolute maximum time spent in select() */
++#define SLEEP_SYSFAIL 123
++
++stralloc percenthack = {0};
++struct constmap mappercenthack;
++stralloc locals = {0};
++struct constmap maplocals;
++stralloc vdoms = {0};
++struct constmap mapvdoms;
++stralloc envnoathost = {0};
++
++char strnum[FMT_ULONG];
++
++/* XXX not good, if qmail-send.c changes this has to be updated */
++#define CHANNELS 2
++char *chanaddr[CHANNELS] = { "local/", "remote/" };
++
++datetime_sec recent;
++
++void log1(char *x);
++void log3(char* x, char* y, char* z);
++
++int flagstopasap = 0;
++void sigterm(void)
++{
++  if (flagstopasap == 0)
++    log1("status: qmail-todo stop processing asap\n");
++  flagstopasap = 1;
++}
++
++int flagreadasap = 0; void sighup(void) { flagreadasap = 1; }
++int flagsendalive = 1; void senddied(void) { flagsendalive = 0; }
++
++void nomem() { log1("alert: out of memory, sleeping...\n"); sleep(10); }
++void pausedir(dir) char *dir;
++{ log3("alert: unable to opendir ",dir,", sleeping...\n"); sleep(10); }
++
++void cleandied()
++{ 
++  log1("alert: qmail-todo: oh no! lost qmail-clean connection! dying...\n");
++  flagstopasap = 1;
++}
++
++
++/* this file is not so long ------------------------------------- FILENAMES */
++
++stralloc fn = {0};
++
++void fnmake_init(void)
++{
++ while (!stralloc_ready(&fn,FMTQFN)) nomem();
++}
++
++void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
++void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,1); }
++void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
++void fnmake_chanaddr(unsigned long id, int c)
++{ fn.len = fmtqfn(fn.s,chanaddr[c],id,1); }
++
++
++/* this file is not so long ------------------------------------- REWRITING */
++
++stralloc rwline = {0};
++
++/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */
++/* may trash recip. must set up rwline, between a T and a \0. */
++int rewrite(char *recip)
++{
++  int i;
++  int j;
++  char *x;
++  static stralloc addr = {0};
++  int at;
++
++  if (!stralloc_copys(&rwline,"T")) return 0;
++  if (!stralloc_copys(&addr,recip)) return 0;
++
++  i = byte_rchr(addr.s,addr.len,'@');
++  if (i == addr.len) {
++    if (!stralloc_cats(&addr,"@")) return 0;
++    if (!stralloc_cat(&addr,&envnoathost)) return 0;
++  }
++
++  while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) {
++    j = byte_rchr(addr.s,i,'%');
++    if (j == i) break;
++    addr.len = i;
++    i = j;
++    addr.s[i] = '@';
++  }
++
++  at = byte_rchr(addr.s,addr.len,'@');
++
++  if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) {
++    if (!stralloc_cat(&rwline,&addr)) return 0;
++    if (!stralloc_0(&rwline)) return 0;
++    return 1;
++  }
++
++  for (i = 0;i <= addr.len;++i)
++    if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.')))
++      if (x = constmap(&mapvdoms,addr.s + i,addr.len - i)) {
++        if (!*x) break;
++        if (!stralloc_cats(&rwline,x)) return 0;
++        if (!stralloc_cats(&rwline,"-")) return 0;
++        if (!stralloc_cat(&rwline,&addr)) return 0;
++        if (!stralloc_0(&rwline)) return 0;
++        return 1;
++      }
++ 
++  if (!stralloc_cat(&rwline,&addr)) return 0;
++  if (!stralloc_0(&rwline)) return 0;
++  return 2;
++}
++
++/* this file is not so long --------------------------------- COMMUNICATION */
++
++substdio sstoqc; char sstoqcbuf[1024];
++substdio ssfromqc; char ssfromqcbuf[1024];
++stralloc comm_buf = {0};
++int comm_pos;
++int fdout = -1;
++int fdin = -1;
++
++void comm_init(void)
++{
++ substdio_fdbuf(&sstoqc,write,2,sstoqcbuf,sizeof(sstoqcbuf));
++ substdio_fdbuf(&ssfromqc,read,3,ssfromqcbuf,sizeof(ssfromqcbuf));
++
++ fdout = 1; /* stdout */
++ fdin = 0;  /* stdin */
++ if (ndelay_on(fdout) == -1)
++ /* this is so stupid: NDELAY semantics should be default on write */
++   senddied(); /* drastic, but better than risking deadlock */
++
++ while (!stralloc_ready(&comm_buf,1024)) nomem();
++}
++
++int comm_canwrite(void)
++{
++ /* XXX: could allow a bigger buffer; say 10 recipients */
++ /* XXX: returns true if there is something in the buffer */
++ if (!flagsendalive) return 0;
++ if (comm_buf.s && comm_buf.len) return 1;
++ return 0;
++}
++
++void log1(char* x)
++{
++  int pos;
++  
++  pos = comm_buf.len;
++  if (!stralloc_cats(&comm_buf,"L")) goto fail;
++  if (!stralloc_cats(&comm_buf,x)) goto fail;
++  if (!stralloc_0(&comm_buf)) goto fail;
++  return;
++  
++fail:
++  /* either all or nothing */
++  comm_buf.len = pos;
++}
++
++void log3(char* x, char *y, char *z)
++{
++  int pos;
++  
++  pos = comm_buf.len;
++  if (!stralloc_cats(&comm_buf,"L")) goto fail;
++  if (!stralloc_cats(&comm_buf,x)) goto fail;
++  if (!stralloc_cats(&comm_buf,y)) goto fail;
++  if (!stralloc_cats(&comm_buf,z)) goto fail;
++  if (!stralloc_0(&comm_buf)) goto fail;
++  return;
++  
++fail:
++  /* either all or nothing */
++  comm_buf.len = pos;
++}
++
++void comm_write(unsigned long id, int local, int remote)
++{
++  int pos;
++  char *s;
++  
++  if(local && remote) s="B";
++  else if(local) s="L";
++  else if(remote) s="R";
++  else s="X";
++  
++  pos = comm_buf.len;
++  strnum[fmt_ulong(strnum,id)] = 0;
++  if (!stralloc_cats(&comm_buf,"D")) goto fail;
++  if (!stralloc_cats(&comm_buf,s)) goto fail;
++  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
++  if (!stralloc_0(&comm_buf)) goto fail;
++  return;
++  
++fail:
++  /* either all or nothing */
++  comm_buf.len = pos;
++}
++
++static int issafe(char ch)
++{
++ if (ch == '%') return 0; /* general principle: allman's code is crap */
++ if (ch < 33) return 0;
++ if (ch > 126) return 0;
++ return 1;
++}
++
++void comm_info(unsigned long id, unsigned long size, char* from, unsigned long pid, unsigned long uid)
++{
++  int pos;
++  int i;
++  
++  pos = comm_buf.len;
++  if (!stralloc_cats(&comm_buf,"Linfo msg ")) goto fail;
++  strnum[fmt_ulong(strnum,id)] = 0;
++  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
++  if (!stralloc_cats(&comm_buf,": bytes ")) goto fail;
++  strnum[fmt_ulong(strnum,size)] = 0;
++  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
++  if (!stralloc_cats(&comm_buf," from <")) goto fail;
++  i = comm_buf.len;
++  if (!stralloc_cats(&comm_buf,from)) goto fail;
++  for (;i < comm_buf.len;++i)
++    if (comm_buf.s[i] == '\n')
++      comm_buf.s[i] = '/';
++    else
++      if (!issafe(comm_buf.s[i]))
++	comm_buf.s[i] = '_';
++  if (!stralloc_cats(&comm_buf,"> qp ")) goto fail;
++  strnum[fmt_ulong(strnum,pid)] = 0;
++  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
++  if (!stralloc_cats(&comm_buf," uid ")) goto fail;
++  strnum[fmt_ulong(strnum,uid)] = 0;
++  if (!stralloc_cats(&comm_buf,strnum)) goto fail;
++  if (!stralloc_cats(&comm_buf,"\n")) goto fail;
++  if (!stralloc_0(&comm_buf)) goto fail;
++  return;
++  
++fail:
++  /* either all or nothing */
++  comm_buf.len = pos;
++}
++
++void comm_exit(void)
++{
++  int w;
++  
++  /* if it fails exit, we have already stoped */
++  if (!stralloc_cats(&comm_buf,"X")) _exit(1);
++  if (!stralloc_0(&comm_buf)) _exit(1);
++}
++
++void comm_selprep(int *nfds, fd_set *wfds, fd_set *rfds)
++{
++  if (flagsendalive) {
++    if (flagstopasap && comm_canwrite() == 0)
++      comm_exit();
++    if (comm_canwrite()) {
++      FD_SET(fdout,wfds);
++      if (*nfds <= fdout)
++	*nfds = fdout + 1;
++    }
++    FD_SET(fdin,rfds);
++    if (*nfds <= fdin)
++      *nfds = fdin + 1;
++  }
++}
++
++void comm_do(fd_set *wfds, fd_set *rfds)
++{
++  /* first write then read */
++  if (flagsendalive)
++    if (comm_canwrite())
++      if (FD_ISSET(fdout,wfds)) {
++	int w;
++	int len;
++	len = comm_buf.len;
++	w = write(fdout,comm_buf.s + comm_pos,len - comm_pos);
++	if (w <= 0) {
++	  if ((w == -1) && (errno == error_pipe))
++	    senddied();
++	} else {
++	  comm_pos += w;
++	  if (comm_pos == len) {
++	    comm_buf.len = 0;
++	    comm_pos = 0;
++	  }
++	}
++      }
++  if (flagsendalive)
++    if (FD_ISSET(fdin,rfds)) {
++      /* there are only two messages 'H' and 'X' */
++      char c;
++      int r;
++      r = read(fdin, &c, 1);
++      if (r <= 0) {
++	if ((r == -1) && (errno != error_intr))
++	  senddied();
++      } else {
++	switch(c) {
++	  case 'H':
++	    sighup();
++	    break;
++	  case 'X':
++	    sigterm();
++	    break;
++	  default:
++	    log1("warning: qmail-todo: qmail-send speaks an obscure dialect\n");
++	    break;
++	}
++      }
++    }
++}
++
++/* this file is not so long ------------------------------------------ TODO */
++
++datetime_sec nexttodorun;
++/* DIR *tododir;  if 0, have to opendir again */
++int flagtododir = 0; /* if 0, have to readsubdir_init again */
++readsubdir todosubdir;
++stralloc todoline = {0};
++char todobuf[SUBSTDIO_INSIZE];
++char todobufinfo[512];
++char todobufchan[CHANNELS][1024];
++
++void todo_init(void)
++{
++/*  tododir = 0; */
++ flagtododir = 0;
++ nexttodorun = now();
++ trigger_set();
++}
++
++void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup)
++{
++ if (flagstopasap) return;
++ trigger_selprep(nfds,rfds);
++/*  if (tododir) *wakeup = 0; */
++ if (flagtododir) *wakeup = 0;
++ if (*wakeup > nexttodorun) *wakeup = nexttodorun;
++}
++
++void todo_do(fd_set *rfds)
++{
++ struct stat st;
++ substdio ss; int fd;
++ substdio ssinfo; int fdinfo;
++ substdio sschan[CHANNELS];
++ int fdchan[CHANNELS];
++ int flagchan[CHANNELS];
++ char ch;
++ int match;
++ unsigned long id;
++/* unsigned int len;
++ direntry *d; */
++ int z;
++ int c;
++ unsigned long uid;
++ unsigned long pid;
++
++ fd = -1;
++ fdinfo = -1;
++ for (c = 0;c < CHANNELS;++c) fdchan[c] = -1;
++
++ if (flagstopasap) return;
++
++/* if (!tododir) */
++ if (!flagtododir)
++  {
++   if (!trigger_pulled(rfds))
++     if (recent < nexttodorun)
++       return;
++   trigger_set();
++/*   tododir = opendir("todo");
++   if (!tododir)
++    {
++     pausedir("todo");
++     return;
++    } */
++   readsubdir_init(&todosubdir, "todo", pausedir);
++   flagtododir = 1;
++   nexttodorun = recent + SLEEP_TODO;
++  }
++
++/* d = readdir(tododir);
++ if (!d) */
++ switch(readsubdir_next(&todosubdir, &id))
++  {
++/*   closedir(tododir);
++   tododir = 0;
++   return; */
++	case 1:
++        break;
++       case 0:
++	flagtododir = 0;
++       default:
++	 return;
++  }
++/* if (str_equal(d->d_name,".")) return;
++ if (str_equal(d->d_name,"..")) return;
++ len = scan_ulong(d->d_name,&id);
++ if (!len || d->d_name[len]) return;
++*/
++ fnmake_todo(id);
++
++ fd = open_read(fn.s);
++ if (fd == -1) { log3("warning: qmail-todo: unable to open ",fn.s,"\n"); return; }
++
++ fnmake_mess(id);
++ /* just for the statistics */
++ if (stat(fn.s,&st) == -1)
++  { log3("warning: qmail-todo: unable to stat ",fn.s,"\n"); goto fail; }
++
++ for (c = 0;c < CHANNELS;++c)
++  {
++   fnmake_chanaddr(id,c);
++   if (unlink(fn.s) == -1) if (errno != error_noent)
++    { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
++  }
++
++ fnmake_info(id);
++ if (unlink(fn.s) == -1) if (errno != error_noent)
++  { log3("warning: qmail-todo: unable to unlink ",fn.s,"\n"); goto fail; }
++
++ fdinfo = open_excl(fn.s);
++ if (fdinfo == -1)
++  { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
++
++ strnum[fmt_ulong(strnum,id)] = 0;
++ log3("new msg ",strnum,"\n");
++
++ for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
++
++ substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf));
++ substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo));
++
++ uid = 0;
++ pid = 0;
++
++ for (;;)
++  {
++   if (getln(&ss,&todoline,&match,'\0') == -1)
++    {
++     /* perhaps we're out of memory, perhaps an I/O error */
++     fnmake_todo(id);
++     log3("warning: qmail-todo: trouble reading ",fn.s,"\n"); goto fail;
++    }
++   if (!match) break;
++
++   switch(todoline.s[0])
++    {
++     case 'u':
++       scan_ulong(todoline.s + 1,&uid);
++       break;
++     case 'p':
++       scan_ulong(todoline.s + 1,&pid);
++       break;
++     case 'F':
++       if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1)
++	{
++	 fnmake_info(id);
++         log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
++	}
++	comm_info(id, (unsigned long) st.st_size, todoline.s + 1, pid, uid);
++       break;
++     case 'T':
++       switch(rewrite(todoline.s + 1))
++	{
++	 case 0: nomem(); goto fail;
++	 case 2: c = 1; break;
++	 default: c = 0; break;
++        }
++       if (fdchan[c] == -1)
++	{
++	 fnmake_chanaddr(id,c);
++	 fdchan[c] = open_excl(fn.s);
++	 if (fdchan[c] == -1)
++          { log3("warning: qmail-todo: unable to create ",fn.s,"\n"); goto fail; }
++	 substdio_fdbuf(&sschan[c]
++	   ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c]));
++	 flagchan[c] = 1;
++	}
++       if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1)
++        {
++	 fnmake_chanaddr(id,c);
++         log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail;
++        }
++       break;
++     default:
++       fnmake_todo(id);
++       log3("warning: qmail-todo: unknown record type in ",fn.s,"\n"); goto fail;
++    }
++  }
++
++ close(fd); fd = -1;
++
++ fnmake_info(id);
++ if (substdio_flush(&ssinfo) == -1)
++  { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
++ if (fsync(fdinfo) == -1)
++  { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
++ close(fdinfo); fdinfo = -1;
++
++ for (c = 0;c < CHANNELS;++c)
++   if (fdchan[c] != -1)
++    {
++     fnmake_chanaddr(id,c);
++     if (substdio_flush(&sschan[c]) == -1)
++      { log3("warning: qmail-todo: trouble writing to ",fn.s,"\n"); goto fail; }
++     if (fsync(fdchan[c]) == -1)
++      { log3("warning: qmail-todo: trouble fsyncing ",fn.s,"\n"); goto fail; }
++     close(fdchan[c]); fdchan[c] = -1;
++    }
++
++ fnmake_todo(id);
++ if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
++ if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
++ if (ch != '+')
++  {
++   log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
++   return;
++  }
++
++ comm_write(id, flagchan[0], flagchan[1]);
++ 
++ return;
++ 
++ fail:
++ if (fd != -1) close(fd);
++ if (fdinfo != -1) close(fdinfo);
++ for (c = 0;c < CHANNELS;++c)
++   if (fdchan[c] != -1) close(fdchan[c]);
++}
++
++/* this file is too long ---------------------------------------------- MAIN */
++
++int getcontrols(void)
++{
++ if (control_init() == -1) return 0;
++ if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
++ if (control_readfile(&locals,"control/locals",1) != 1) return 0;
++ if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0;
++ switch(control_readfile(&percenthack,"control/percenthack",0))
++  {
++   case -1: return 0;
++   case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break;
++   case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break;
++  }
++ switch(control_readfile(&vdoms,"control/virtualdomains",0))
++  {
++   case -1: return 0;
++   case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break;
++   case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break;
++  }
++ return 1;
++}
++
++stralloc newlocals = {0};
++stralloc newvdoms = {0};
++
++void regetcontrols(void)
++{
++ int r;
++
++ if (control_readfile(&newlocals,"control/locals",1) != 1)
++  { log1("alert: qmail-todo: unable to reread control/locals\n"); return; }
++ r = control_readfile(&newvdoms,"control/virtualdomains",0);
++ if (r == -1)
++  { log1("alert: qmail-todo: unable to reread control/virtualdomains\n"); return; }
++
++ constmap_free(&maplocals);
++ constmap_free(&mapvdoms);
++
++ while (!stralloc_copy(&locals,&newlocals)) nomem();
++ while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem();
++
++ if (r)
++  {
++   while (!stralloc_copy(&vdoms,&newvdoms)) nomem();
++   while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem();
++  }
++ else
++   while (!constmap_init(&mapvdoms,"",0,1)) nomem();
++}
++
++void reread(void)
++{
++ if (chdir(auto_qmail) == -1)
++  {
++   log1("alert: qmail-todo: unable to reread controls: unable to switch to home directory\n");
++   return;
++  }
++ regetcontrols();
++ while (chdir("queue") == -1)
++  {
++   log1("alert: qmail-todo: unable to switch back to queue directory; HELP! sleeping...\n");
++   sleep(10);
++  }
++}
++
++void main()
++{
++ datetime_sec wakeup;
++ fd_set rfds;
++ fd_set wfds;
++ int nfds;
++ struct timeval tv;
++ int r;
++ char c;
++
++ if (chdir(auto_qmail) == -1)
++  { log1("alert: qmail-todo: cannot start: unable to switch to home directory\n"); _exit(111); }
++ if (!getcontrols())
++  { log1("alert: qmail-todo: cannot start: unable to read controls\n"); _exit(111); }
++ if (chdir("queue") == -1)
++  { log1("alert: qmail-todo: cannot start: unable to switch to queue directory\n"); _exit(111); }
++ sig_pipeignore();
++ umask(077);
++
++ fnmake_init();
++
++ todo_init();
++ comm_init();
++ 
++ do {
++   r = read(fdin, &c, 1);
++   if ((r == -1) && (errno != error_intr))
++     _exit(100); /* read failed probably qmail-send died */
++ } while (r =! 1); /* we assume it is a 'S' */
++ 
++ for (;;)
++  {
++   recent = now();
++
++   if (flagreadasap) { flagreadasap = 0; reread(); }
++   if (!flagsendalive) {
++     /* qmail-send finaly exited, so do the same. */
++     if (flagstopasap) _exit(0);
++     /* qmail-send died. We can not log and we can not work therefor _exit(1). */
++     _exit(1);
++   }
++
++   wakeup = recent + SLEEP_FOREVER;
++   FD_ZERO(&rfds);
++   FD_ZERO(&wfds);
++   nfds = 1;
++
++   todo_selprep(&nfds,&rfds,&wakeup);
++   comm_selprep(&nfds,&wfds,&rfds);
++
++   if (wakeup <= recent) tv.tv_sec = 0;
++   else tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
++   tv.tv_usec = 0;
++
++   if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1)
++     if (errno == error_intr)
++       ;
++     else
++       log1("warning: qmail-todo: trouble in select\n");
++   else
++    {
++     recent = now();
++
++     todo_do(&rfds);
++     comm_do(&wfds, &rfds);
++    }
++  }
++  /* NOTREACHED */
++}
++
+diff -ruN ../netqmail-1.06-original/qmail.c netqmail-1.06/qmail.c
+--- ../netqmail-1.06-original/qmail.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/qmail.c	2016-11-22 21:03:57.126527632 +0100
+@@ -23,22 +23,32 @@
+ {
+   int pim[2];
+   int pie[2];
++  int pic[2], errfd;
++  char *x;
+ 
+   setup_qqargs();
+ 
+   if (pipe(pim) == -1) return -1;
+   if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
+- 
++  if (pipe(pic) == -1) { close(pim[0]); close(pim[1]); close(pie[0]); close(pie[1]); return -1; }
++
+   switch(qq->pid = vfork()) {
+     case -1:
+       close(pim[0]); close(pim[1]);
+       close(pie[0]); close(pie[1]);
+-      return -1;
++      close(pic[0]); close(pic[1]);
++    return -1;
+     case 0:
+       close(pim[1]);
+       close(pie[1]);
++      close(pic[0]); /*- we want to receive data */
+       if (fd_move(0,pim[0]) == -1) _exit(120);
+       if (fd_move(1,pie[0]) == -1) _exit(120);
++      if (!(x = env_get("ERROR_FD")))
++        errfd = CUSTOM_ERR_FD;
++      else
++        scan_int(x, &errfd);
++      if (fd_move(errfd, pic[1]) == -1) _exit(120);
+       if (chdir(auto_qmail) == -1) _exit(61);
+       execv(*binqqargs,binqqargs);
+       _exit(120);
+@@ -46,6 +56,7 @@
+ 
+   qq->fdm = pim[1]; close(pim[0]);
+   qq->fde = pie[1]; close(pie[0]);
++  qq->fdc = pic[0]; close(pic[1]);
+   substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf));
+   qq->flagerr = 0;
+   return 0;
+@@ -93,11 +104,27 @@
+ {
+   int wstat;
+   int exitcode;
++  char ch;
++  static char errstr[256];
++  int len = 0;
+ 
+   qmail_put(qq,"",1);
+   if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
+   close(qq->fde);
+ 
++  substdio_fdbuf(&qq->ss, read, qq->fdc, qq->buf, sizeof(qq->buf));
++
++  while (substdio_bget(&qq->ss, &ch, 1) && len < 255)
++  {
++    errstr[len]=ch;
++    len++;
++  }
++
++  if (len > 0) errstr[len]='\0'; /* add str-term */
++ /* dkim +     errstr[len] = 0; */  /* add str-term */
++
++  close(qq->fdc);
++
+   if (wait_pid(&wstat,qq->pid) != qq->pid)
+     return "Zqq waitpid surprise (#4.3.0)";
+   if (wait_crashed(wstat))
+@@ -108,6 +135,7 @@
+     case 115: /* compatibility */
+     case 11: return "Denvelope address too long for qq (#5.1.3)";
+     case 31: return "Dmail server permanently rejected message (#5.3.0)";
++    case 32: return "DPrivate key file does not exist (#5.3.5)";
+     case 51: return "Zqq out of memory (#4.3.0)";
+     case 52: return "Zqq timeout (#4.3.0)";
+     case 53: return "Zqq write error or disk full (#4.3.0)";
+@@ -127,10 +155,14 @@
+     case 74: return "Zcommunication with mail server failed (#4.4.2)";
+     case 91: /* fall through */
+     case 81: return "Zqq internal bug (#4.3.0)";
++    case 82: /*- simscan exits with 82 */
++	case 88: /*- custom error */
++		 if (len > 2)
++			return errstr;
+     case 120: return "Zunable to exec qq (#4.3.0)";
+     default:
+       if ((exitcode >= 11) && (exitcode <= 40))
+-	return "Dqq permanent problem (#5.3.0)";
++        return "Dqq permanent problem (#5.3.0)";
+       return "Zqq temporary problem (#4.3.0)";
+   }
+ }
+diff -ruN ../netqmail-1.06-original/qmail.h netqmail-1.06/qmail.h
+--- ../netqmail-1.06-original/qmail.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/qmail.h	2016-11-22 21:03:57.126527632 +0100
+@@ -3,11 +3,13 @@
+ 
+ #include "substdio.h"
+ 
++#define CUSTOM_ERR_FD 4
+ struct qmail {
+   int flagerr;
+   unsigned long pid;
+   int fdm;
+   int fde;
++  int fdc;
+   substdio ss;
+   char buf[1024];
+ } ;
+diff -ruN ../netqmail-1.06-original/qregex.c netqmail-1.06/qregex.c
+--- ../netqmail-1.06-original/qregex.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qregex.c	2016-11-22 21:03:57.126527632 +0100
+@@ -0,0 +1,239 @@
++/*
++ * $Log: qregex.c,v $
++ * Revision 1.13  2007-12-20 13:51:04+05:30  Cprogrammer
++ * removed compiler warning
++ *
++ * Revision 1.12  2005-08-23 17:41:36+05:30  Cprogrammer
++ * regex to be turned on only of QREGEX is defined to non-zero value
++ *
++ * Revision 1.11  2005-04-02 19:07:25+05:30  Cprogrammer
++ * use internal wildmat version
++ *
++ * Revision 1.10  2005-01-22 00:39:04+05:30  Cprogrammer
++ * added missing error handling
++ *
++ * Revision 1.9  2004-10-22 20:29:45+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.8  2004-09-21 23:48:18+05:30  Cprogrammer
++ * made matchregex() visible
++ * introduced dotChar (configurable dot char)
++ *
++ * Revision 1.7  2004-02-05 18:48:48+05:30  Cprogrammer
++ * changed curregex to static
++ *
++ * Revision 1.6  2003-12-23 23:22:53+05:30  Cprogrammer
++ * implicitly use wildcard if address starts with '@'
++ *
++ * Revision 1.5  2003-12-22 18:33:12+05:30  Cprogrammer
++ * added address_match()
++ *
++ * Revision 1.4  2003-12-22 13:21:08+05:30  Cprogrammer
++ * added text and pattern as part of error message
++ *
++ * Revision 1.3  2003-12-22 10:04:04+05:30  Cprogrammer
++ * conditional compilation of qregex
++ *
++ * Revision 1.2  2003-12-21 15:32:18+05:30  Cprogrammer
++ * added regerror
++ *
++ * Revision 1.1  2003-12-20 13:17:16+05:30  Cprogrammer
++ * Initial revision
++ *
++ * qregex (v2)
++ * $Id: qregex.c,v 1.13 2007-12-20 13:51:04+05:30 Cprogrammer Stab mbhangui $
++ *
++ * Author  : Evan Borgstrom (evan at unixpimps dot org)
++ * Created : 2001/12/14 23:08:16
++ * Modified: $Date: 2007-12-20 13:51:04+05:30 $
++ * Revision: $Revision: 1.13 $
++ *
++ * 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 "case.h"
++#include "scan.h"
++#include "stralloc.h"
++#include "constmap.h"
++#include "substdio.h"
++#include "byte.h"
++#include "env.h"
++#include <sys/types.h>
++#include <regex.h>
++#include <unistd.h>
++
++static int      wildmat_match(stralloc *, int, struct constmap *, int, stralloc *);
++static int      regex_match(stralloc *, int, stralloc *);
++int             wildmat_internal(char *, char *);
++
++static char     sserrbuf[512];
++static substdio sserr = SUBSTDIO_FDBUF(write, 2, sserrbuf, sizeof(sserrbuf));
++static char     dotChar = '@';
++
++int
++address_match(stralloc *addr, int bhfok, stralloc *bhf,
++	struct constmap *mapbhf, int bhpok, stralloc *bhp)
++{
++	char           *ptr;
++	int             x = 0;
++
++	case_lowerb(addr->s, addr->len); /*- convert into lower case */
++	if ((ptr = env_get("QREGEX")))
++		scan_int(ptr, &x);
++	if (ptr && x)
++		return (regex_match(addr, bhfok, bhf));
++	else
++		return (wildmat_match(addr, bhfok, mapbhf, bhpok, bhp));
++}
++
++int
++matchregex(char *text, char *regex)
++{
++	regex_t         qreg;
++	char            errbuf[512];
++	int             retval = 0;
++
++#define REGCOMP(X,Y)    regcomp(&X, Y, REG_EXTENDED|REG_ICASE)
++	/*- build the regex */
++	if ((retval = REGCOMP(qreg, regex)) != 0)
++	{
++		regerror(retval, &qreg, errbuf, sizeof(errbuf));
++		regfree(&qreg);
++		if (substdio_puts(&sserr, text) == -1)
++			return (-retval);
++		if (substdio_puts(&sserr, ": ") == -1)
++			return (-retval);
++		if (substdio_puts(&sserr, regex) == -1)
++			return (-retval);
++		if (substdio_puts(&sserr, ": ") == -1)
++			return (-retval);
++		if (substdio_puts(&sserr, errbuf) == -1)
++			return (-retval);
++		if (substdio_puts(&sserr, "\n") == -1)
++			return (-retval);
++		if (substdio_flush(&sserr) == -1)
++			return (-retval);
++		return (-retval);
++	}
++	/*- execute the regex */
++#define REGEXEC(X,Y)    regexec(&X, Y, (size_t) 0, (regmatch_t *) 0, (int) 0)
++	retval = REGEXEC(qreg, text);
++	regfree(&qreg);
++	return (retval == REG_NOMATCH ? 0 : 1);
++}
++
++static int
++wildmat_match(stralloc * addr, int mapfile, struct constmap *ptrmap, int patfile, stralloc *wildcard)
++{
++	int             i = 0;
++	int             j = 0;
++	int             k = 0;
++	char            subvalue;
++
++	if (mapfile)
++	{
++		if (constmap(ptrmap, addr->s, addr->len - 1))
++			return 1;
++		if ((j = byte_rchr(addr->s, addr->len, dotChar)) < addr->len)
++		{
++			if (constmap(ptrmap, addr->s + j, addr->len - j - 1))
++				return 1;
++		}
++	}
++	/*- Include control file control/xxxxpatterns and evaluate with Wildmat check */
++	if (patfile && wildcard)
++	{
++		i = 0;
++		for (j = 0; j < wildcard->len; ++j)
++		{
++			if (!wildcard->s[j])
++			{
++				subvalue = wildcard->s[i] != '!';
++				if (!subvalue)
++					i++;
++				if ((k != subvalue) && wildmat_internal(addr->s, wildcard->s + i))
++					k = subvalue;
++				i = j + 1;
++			}
++		}
++		return k;
++	}
++	return (0);
++}
++
++static int
++regex_match(stralloc * addr, int mapfile, stralloc *map)
++{
++	int             i = 0;
++	int             j = 0;
++	int             k = 0;
++	int             negate = 0, match;
++	static stralloc curregex = { 0 };
++
++	match = 0;
++	if (mapfile)
++	{
++		while (j < map->len)
++		{
++			i = j;
++			while ((map->s[i] != '\0') && (i < map->len))
++				i++;
++			if (map->s[j] == '!')
++			{
++				negate = 1;
++				j++;
++			}
++			if (*(map->s + j) == dotChar)
++			{
++				if (!stralloc_copys(&curregex, ".*"))
++					return(-1);
++				if (!stralloc_catb(&curregex, map->s + j, (i - j)))
++					return(-1);
++			} else
++			if (!stralloc_copyb(&curregex, map->s + j, (i - j)))
++				return(-1);
++			if (!stralloc_0(&curregex))
++				return(-1);
++			if((k = matchregex(addr->s, curregex.s)) == 1)
++			{
++				if (negate)
++					return(0);
++				match = 1;
++			}
++			j = i + 1;
++			negate = 0;
++		}
++	}
++	return (match);
++}
++
++void
++setdotChar(c)
++	char            c;
++{
++	dotChar = c;
++	return;
++}
++
++void
++getversion_qregex_c()
++{
++	static char    *x = "$Id: qregex.c,v 1.13 2007-12-20 13:51:04+05:30 Cprogrammer Stab mbhangui $";
++
++#ifdef INDIMAIL
++	x = sccsidh;
++#else
++	x++;
++#endif
++}
+diff -ruN ../netqmail-1.06-original/qregex.h netqmail-1.06/qregex.h
+--- ../netqmail-1.06-original/qregex.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/qregex.h	2016-11-22 21:03:57.126527632 +0100
+@@ -0,0 +1,24 @@
++/*
++ * $Log: qregex.h,v $
++ * Revision 1.3  2004-09-21 23:49:02+05:30  Cprogrammer
++ * added matchregex() and setdotChar()
++ *
++ * Revision 1.2  2003-12-22 18:35:26+05:30  Cprogrammer
++ * added address_match() function
++ *
++ * Revision 1.1  2003-12-20 13:17:45+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++/*
++ * simple header file for the matchregex prototype 
++ */
++#ifndef _QREGEX_H_
++#define _QREGEX_H_
++#include "constmap.h"
++#include "stralloc.h"
++
++int             address_match(stralloc *, int, stralloc *, struct constmap *, int, stralloc *);
++int             matchregex(char *, char *);
++void            setdotChar(char);
++#endif
+diff -ruN ../netqmail-1.06-original/readwrite.h netqmail-1.06/readwrite.h
+--- ../netqmail-1.06-original/readwrite.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/readwrite.h	2016-11-22 21:03:57.126527632 +0100
+@@ -1,7 +1,6 @@
+ #ifndef READWRITE_H
+ #define READWRITE_H
+ 
+-extern int read();
+-extern int write();
++#include <unistd.h>
+ 
+ #endif
+diff -ruN ../netqmail-1.06-original/received.c netqmail-1.06/received.c
+--- ../netqmail-1.06-original/received.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/received.c	2016-11-22 21:03:57.127527599 +0100
+@@ -21,6 +21,9 @@
+   return 0;
+ }
+ 
++char *relayclient;
++int relayclientlen;
++
+ void safeput(qqt,s)
+ struct qmail *qqt;
+ char *s;
+@@ -58,9 +61,12 @@
+   qmail_puts(qqt," (");
+   if (remoteinfo) {
+     safeput(qqt,remoteinfo);
+-    qmail_puts(qqt,"@");
+   }
+-  safeput(qqt,remoteip);
++  relayclient = env_get("RELAYCLIENT");
++  if (!relayclient) {
++    if (remoteinfo) { qmail_puts(qqt,"@"); }
++     safeput(qqt,remoteip);
++  }
+   qmail_puts(qqt,")\n  by ");
+   safeput(qqt,local);
+   qmail_puts(qqt," with ");
+diff -ruN ../netqmail-1.06-original/remoteinfo.c netqmail-1.06/remoteinfo.c
+--- ../netqmail-1.06-original/remoteinfo.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/remoteinfo.c	2016-11-22 21:03:57.127527599 +0100
+@@ -44,12 +44,12 @@
+   s = socket(AF_INET,SOCK_STREAM,0);
+   if (s == -1) return 0;
+  
+-  byte_zero(&sin,sizeof(sin));
++/*  byte_zero(&sin,sizeof(sin));
+   sin.sin_family = AF_INET;
+   byte_copy(&sin.sin_addr,4,ipl);
+   sin.sin_port = 0;
+-  if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
+-  if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; }
++  if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } */
++  if (timeoutconn(s,ipr,ipl,113,timeout) == -1) { close(s); return 0; }
+   fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY);
+  
+   len = 0;
+diff -ruN ../netqmail-1.06-original/scan.h netqmail-1.06/scan.h
+--- ../netqmail-1.06-original/scan.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/scan.h	2018-03-31 14:54:40.767441567 +0200
+@@ -2,6 +2,7 @@
+ #define SCAN_H
+ 
+ extern unsigned int scan_uint();
++extern unsigned int scan_int();
+ extern unsigned int scan_xint();
+ extern unsigned int scan_nbbint();
+ extern unsigned int scan_ushort();
+diff -ruN ../netqmail-1.06-original/scan_ulong.c netqmail-1.06/scan_ulong.c
+--- ../netqmail-1.06-original/scan_ulong.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/scan_ulong.c	2016-11-22 21:03:57.127527599 +0100
+@@ -9,3 +9,43 @@
+     { result = result * 10 + c; ++pos; }
+   *u = result; return pos;
+ }
++
++unsigned int
++scan_int(s, i)
++	register char  *s;
++	register int   *i;
++{
++	register unsigned int pos;
++	register int result;
++	register unsigned char c;
++	int             sign;
++
++	pos = 0;
++	result = 0;
++	sign = 1;
++	/*-
++	 * determine sign of the number
++	 */
++	switch (s[0])
++	{
++		case '\0':
++			return 0;
++		case '-':
++			++pos;
++			sign = -1;
++			break;
++		case '+':
++			++pos;
++			sign = 1;
++			break;
++		default:
++			break;
++	}
++	while ((c = (unsigned char)(s[pos] - '0')) < 10)
++	{
++		result = result * 10 + c;
++		++pos;
++	}
++	*i = result * sign;
++	return pos;
++}
+diff -ruN ../netqmail-1.06-original/scan_xlong.c netqmail-1.06/scan_xlong.c
+--- ../netqmail-1.06-original/scan_xlong.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/scan_xlong.c	2016-11-22 21:03:57.127527599 +0100
+@@ -0,0 +1,47 @@
++/*
++ * $Log: scan_xlong.c,v $
++ * Revision 1.2  2005-06-15 22:35:48+05:30  Cprogrammer
++ * added RCS version information
++ *
++ * Revision 1.1  2005-06-15 22:11:59+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include "scan.h"
++
++static int
++fromhex(unsigned char c)
++{
++	if (c >= '0' && c <= '9')
++		return c - '0';
++	else
++	if (c >= 'A' && c <= 'F')
++		return c - 'A' + 10;
++	else
++	if (c >= 'a' && c <= 'f')
++		return c - 'a' + 10;
++	return -1;
++}
++
++unsigned int
++scan_xlong(char *src, unsigned long *dest)
++{
++	register const char *tmp = src;
++	register int    l = 0;
++	register unsigned char c;
++	while ((c = fromhex(*tmp)) < 16)
++	{
++		l = (l << 4) + c;
++		++tmp;
++	}
++	*dest = l;
++	return tmp - src;
++}
++
++void
++getversion_scan_xlong_c()
++{
++	static char    *x = "$Id: scan_xlong.c,v 1.2 2005-06-15 22:35:48+05:30 Cprogrammer Stab mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/select.h2 netqmail-1.06/select.h2
+--- ../netqmail-1.06-original/select.h2	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/select.h2	2016-11-22 21:03:57.127527599 +0100
+@@ -1,6 +1,12 @@
+ #ifndef SELECT_H
+ #define SELECT_H
+ 
++#include <features.h>
++#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
++# include <bits/types.h>
++# undef __FD_SETSIZE
++# define __FD_SETSIZE 131077
++#endif 
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/select.h>
+diff -ruN ../netqmail-1.06-original/socket_v4mappedprefix.c netqmail-1.06/socket_v4mappedprefix.c
+--- ../netqmail-1.06-original/socket_v4mappedprefix.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/socket_v4mappedprefix.c	2016-11-22 21:03:57.127527599 +0100
+@@ -0,0 +1,9 @@
++/*
++ * $Log: socket_v4mappedprefix.c,v $
++ * Revision 1.1  2005-06-15 22:12:51+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#ifdef IPV6
++unsigned char V4mappedprefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
++#endif
+diff -ruN ../netqmail-1.06-original/socket_v6any.c netqmail-1.06/socket_v6any.c
+--- ../netqmail-1.06-original/socket_v6any.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/socket_v6any.c	2016-11-22 21:03:57.127527599 +0100
+@@ -0,0 +1,9 @@
++/*
++ * $Log: socket_v6loopback.c,v $
++ * Revision 1.1  2005-06-15 22:13:07+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#ifdef IPV6
++const unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
++#endif
+diff -ruN ../netqmail-1.06-original/softwarelicense1-1.html netqmail-1.06/softwarelicense1-1.html
+--- ../netqmail-1.06-original/softwarelicense1-1.html	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/softwarelicense1-1.html	2016-11-22 21:03:57.128527565 +0100
+@@ -0,0 +1,59 @@
++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
++<html>
++<head>
++<title>Yahoo! DomainKeys Public License Agreement v1.0</title>
++<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
++</head>
++
++<body>
++Yahoo! DomainKeys Public License Agreement v1.1<br>
++(this &quot;Agreement&quot;)
++<p>Copyright (c) 2004, Yahoo! Inc.<br>
++ All rights reserved.</p>
++
++<br>
++<a href=http://domainkeys.sourceforge.net/license/softwarelicense1-1.html>(Available online)</a>
++<br>
++
++
++<p>This Agreement is between Licensor and You.  You agree to be bound by all the terms and conditions set forth below, and, subject to those terms and conditions, You may use the intellectual property described below. </p>
++<p>1.    LICENSE GRANT. </p>
++<p>1.1. Subject to the terms and conditions of this Agreement, each DomainKeys Developer hereby grants You a royalty-free, perpetual, worldwide, sublicensable, non-exclusive license to use, reproduce, modify, publicly display, publicly perform, and distribute the Licensed Code.</p>
++<p>1.2. Subject to the terms and conditions of this Agreement, Licensor hereby grants You a royalty-free, perpetual, worldwide, sublicensable, non-exclusive license under its rights to the Yahoo! Patent Claims to make, use, sell, offer for sale, and/or import the Licensed Code for the sole purpose of implementing a sender verification solution in connection with e-mail. </p>
++<p>2.    DEFINITIONS. </p>
++<p>2.1. &quot;Contributions&quot; means any modifications to the Licensed Code, and/or any portions thereof, that are distributed under this Agreement.  A Contribution includes, without limitation, any addition to or deletion from the contents of a file containing any Licensed Code, or any new file that contains any part of the Licensed Code.</p>
++<p>2.2. &quot;DomainKeys Developer(s)&quot; means Yahoo, Inc. (&quot;Yahoo!&quot;), Licensor, and/or any other individual or entity who distributes code under this Agreement.</p>
++<p>2.3. &quot;Licensed Code&quot; means the Original Code, any Contributions (whether made by You or any DomainKeys Developer other than You), and the combination of Original Code and any such Contributions.</p>
++<p>2.4. &quot;Licensor&quot; means Yahoo! or any other individual or entity that elects to use this Agreement to license intellectual property to any licensee.</p>
++<p>2.5. &quot;Original Code&quot; means the source code and binary code that is based on the Specifications and distributed by or on behalf of Yahoo! under this Agreement for the sole purpose of implementing a sender verification solution in connection with e-mail, including any updates or upgrades to such code made available by Yahoo!.</p>
++<p>2.6. &quot;Specifications&quot; means the specification having submission ID &quot;draft-delany-domainkeys-base-01.txt&quot; dated Aug 2004 published through the IETF (Internet Engineering Task Force). The Specifications may be found at the following link: <br>
++<a href="http://antispam.yahoo.com/domainkeys/draft-delany-domainkeys-base-02.txt">http://antispam.yahoo.com/domainkeys/draft-delany-domainkeys-base-02.txt</a></p>
++<p>
++ 2.7. &quot;Yahoo! Patent Claims&quot; shall mean those claims of all Yahoo! foreign and domestic patents and patent applications that base their priority on U.S. Provisional Patent Application Ser. Nos. 60/497,794, filed Aug. 26, 2003, or 60/553,300, filed Mar. 15, 2004, or U.S. Patent Application Ser. Nos. 10/671,319, filed Sep. 24, 2003, or 10/805,181, filed Mar. 19, 2004.  </p>
++<p>2.8. &quot;You&quot; or &quot;Your&quot; means an individual, company, or other legal entity exercising any rights under this Agreement.  Any individual who accepts the terms and conditions of this Agreement on behalf of a company or other legal entity represents and warrants that the individual has the authority to enter into this Agreement on behalf of the company or other legal entity. </p>
++<p>3.    TERMS. </p>
++<p>3.1. You agree not to assert against Yahoo!, any other DomainKeys Developer or any of their respective licensees under Section 3.4, a patent infringement claim based on the manufacture, use, sale, offer for sale and/or importation of any of the specific portions of a hardware or software implementation expressly required to be compliant with the Specifications for the sole purpose of implementing a sender verification solution in connection with e-mail (&quot;Licensed Code IP Claim&quot;).</p>
++<p>3.2. To indicate your assent to the terms and conditions of this Agreement and in order to obtain a license to use, reproduce, modify, publicly display, publicly perform, distribute, and sublicense Licensed Code, You must:</p>
++<p>(a) include, attach or preserve the following prominently displayed statement in the Licensed Code: &quot;This code incorporates intellectual property owned by Yahoo! and licensed pursuant to the Yahoo! DomainKeys Public License Agreement.&quot;; </p>
++<p>(b) preserve the copyright and other proprietary notices and disclaimers of DomainKeys Developers as they appear in the Licensed Code; and  </p>
++<p>(c) if the Licensed Code developed by You is distributed in source form, You must identify Yourself, in the source code of such Licensed Code, as the originator of any modifications in a manner that reasonably allows subsequent DomainKeys Developers or their licensees to identify the originator of the modifications.</p>
++<p>3.3. You will not use the name of Yahoo! to endorse or promote any products, services, or Licensed Code without specific prior written permission of Yahoo!.  &quot;DomainKeys&quot; is a trademark of Yahoo!.  However, You may state Your Licensed Code is &quot;DomainKeys compliant&quot;, &quot;supports DomainKeys&quot;, or is &quot;DomainKeys-enabled&quot;, without citation to Yahoo!.  You must create Your own product or service names or trademarks for Your Licensed Code and You agree not to use the term &quot;DomainKeys&quot; in or as part of a name or trademark for Your Licensed Code.</p>
++<p>3.4. You may choose to distribute Licensed Code or modifications under this Agreement or a different agreement, provided that:</p>
++<p>(a) a copy of this Agreement or the different agreement is included with each copy of the Licensed Code or modifications along with the following prominently displayed statement: &quot;By using, reproducing, modifying, publicly displaying, publicly performing, distributing, and/or sublicensing this code as permitted, you agree to the terms and conditions of the Yahoo! DomainKeys Public License Agreement or other agreement contained herein.&quot;; and</p>
++<p>(b) if distributed under a different agreement, such different agreement contains terms and conditions that (i) provide no fewer rights, privileges and immunities to DomainKeys Developers than the terms and conditions of this Agreement, including, without limitation, Sections 1.2, 3.1, 3.4, 3.7, 4.1, 4.2, and 4.3, except that You may alter the terms and conditions of Section 1.1 and (ii) apply such terms and conditions to the Licensed Code and/or modifications made by You.</p>
++<p>3.5. You acknowledge that Licensed Code may be subject to U.S. export restriction and other applicable national and international laws.  You agree to comply with all export, re-export, or import restrictions, laws, or regulations. </p>
++<p>3.6. Yahoo!, and only Yahoo!, may, from time to time and at its sole discretion, update or modify the terms of this Agreement.  If Yahoo! makes any such modifications, You may continue under the terms and conditions of this Agreement or agree to the updated or modified terms and conditions.  For the most recent version of this Agreement please contact Yahoo!.</p>
++<p>3.7. This Agreement and the rights hereunder will terminate: <br>
++ (a) automatically without notice from Yahoo!, if You at any time during the term of this Agreement assert any Licensed Code IP Claim against Yahoo!; </p>
++<p>(b) upon written notice from Yahoo!, if You at any time during the term of this Agreement assert any Licensed Code IP Claim against any DomainKeys Developer (other than Yahoo!) or any licensees of any DomainKeys Developer; or </p>
++<p>(c) where (a) or (b) do not apply, automatically without notice from Yahoo!, if You fail to comply with any term(s) of this Agreement and fail to cure such breach within 30 days of You becoming aware of such breach. </p>
++<p>3.8. This Agreement constitutes the entire agreement between the parties with respect to the subject matter hereof.  This Agreement shall be governed by and construed under the laws of the United States and the State of California without giving effect to California conflict of law provisions or to construction provisions favoring either party.  All actions arising out of or relating to this Agreement that involve Yahoo! as a party will be adjudicated exclusively by the Superior Court of the State of California for the County of Santa Clara or the United States District Court for the Northern District of California. </p>
++<p>3.9. In the event that any provision of this Agreement is deemed to be invalid, such invalidity shall not affect the remainder of this Agreement.</p>
++<p>4.    <b>LEGAL DISCLAIMERS. </b></p>
++<p>4.1. <b>THE YAHOO! PATENT CLAIMS, THIS AGREEMENT, LICENSED CODE, THE DOMAINKEYS TRADEMARK, AND THE SPECIFICATIONS ARE PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.</b>  You are solely responsible for determining the appropriateness of exercising any rights under this Agreement and using the Specifications, Licensed Code, and the DomainKeys trademark and assume all risks associated in connection therewith, including, but not limited to, the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. </p>
++<p>4.2. You expressly acknowledge and agree that no assurances are provided by DomainKeys Developers with respect to the validity of the Yahoo! Patent Claims or that the Specifications, Licensed Code, the DomainKeys trademark or any implementations related to the Specifications, Licensed Code or the DomainKeys trademark do not infringe or misappropriate the patent, trademark or other intellectual property rights of any other entity.  DomainKeys Developers disclaim any liability to You for claims brought by any other person or entity based on infringement or misappropriation of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, You hereby assume sole responsibility to secure any other intellectual property rights needed. </p>
++<p>4.3. <b>DOMAINKEYS DEVELOPERS SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE EXERCISE OF ANY RIGHTS UNDER THIS AGREEMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, AND EVEN IF THE REMEDIES PROVIDED FOR IN THIS AGREEMENT FAIL OF THEIR ESSENTIAL PURPOSE.</b></p>
++
++</body>
++</html>
++
+diff -ruN ../netqmail-1.06-original/spawn-filter.9 netqmail-1.06/spawn-filter.9
+--- ../netqmail-1.06-original/spawn-filter.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/spawn-filter.9	2016-11-22 21:03:57.128527565 +0100
+@@ -0,0 +1,103 @@
++.TH spawn-filter 8
++.SH NAME
++spawn-filter \- Helper for running filters for qmail-local and qmail-remote
++.SH SYNOPSIS
++.B spawn-filter args
++.SH DESCRIPTION
++.B spawn-filter
++is a utility to help qmail run any filter during local or remote delivery. It
++can run any filter which expects to read mess on fd 0 and writes back the message on fd 1.
++The filter can be turned on individually for local and remote mails by defining
++.B QMAILLOCAL
++and
++.B QMAILREMOTE
++environment variables respectively in
++.B qmail-send
++supervise or rc script. If spawn-filter is invoked as qmail-local, it executes the
++original
++.B qmail-local
++after runing the mail through the filter. If spawn-filter is invoked as qmail-remote, it
++executes the original
++.B qmail-remote
++after running the mail through the filter. Hence QMAILLOCAL should be set as QMAILHOME/bin/spawn-filter
++for filtering local mails and QMAILREMOTE as QMAILHOME/bin/spawn-filter for filtering
++remote mails.
++
++Filters can be run by setting the environment variable
++.B FILTERARGS
++or by using a control file
++.BR filterargs.
++The environment variable overrides the control file.
++.B spawn-filter
++uses /bin/sh to run the filter (with arguments) specified by the FILTERARGS environment variable or the control file
++.BR filterargs .
++The environment variable FILTERARGS apply to both local and remote mails. For individual domain level control,
++it is best to set using the control file filterargs.
++
++.TP 5
++.I filterargs
++The format of this file is of the form
++.B domain:args
++for both local and remote mails.
++.B domain:remote:args
++for remote mails and
++.B domain:local:args
++for local mails.
++
++.EX
++indimail.org:remote:QMAILHOME/bin/dk-filter
++.EE
++
++.TP 0
++The sequence in which the filter program is run is given below
++
++.TP 5
++1. create two pipes and fork
++.TP 5
++2. dup write end of the first pipe to descriptor 1, dup write end of the second pipe to descriptor 2 in the child and exec the filter program
++.TP 5
++3. dup read end of the pipe to descriptor 0 in parent and exec qmail-local for local mails and qmail-remote for remote mails.
++.TP 5
++4. Wait for filter to exit and read read end of second pipe for any error messages.
++.TP 5
++5. Report success or failure
++.TP 0
++
++This gives the ability for the any filter program to read the mail message from descriptor 0 before
++passing it to qmail-local/qmail-remote through the pipe.
++
++.B spawn-filter
++will attempt to make the descriptor 0 seekable if the environment variable MAKE_SEEKABLE
++is defined. This may be necessary for certain filter programs which could do lseek().
++
++.B spawn-filter
++sets the environment variable
++.B DOMAIN
++to the recipient domain. This can be conveniently used in programs/scripts which get invoked by
++setting
++.B FILTERARGS
++environment variable or by rules in the control file
++.BR filterargs .
++
++.SH "EXIT CODES"
++.B spawn-filter
++exits 111 for any error or if it is not able to exec
++QMAILHOME/bin/qmail-local (for local mails) or
++QMAILHOME/bin/qmail-remote (for remote mails).
++
++.SH "SEE ALSO"
++qmail-lspawn(8),
++qmail-rspawn(8),
++qmail-local(8),
++qmail-remote(8),
++qmail-smtpd(8),
++qmail-control(5),
++qmail-queue(8)
++
++.SH "AUTHORS"
++
++Manvendra Bhangui.
++.SH PROBLEMS
++Problems with
++.B spawn-filter
++should be forwarded to "Manvendra Bhangui" <mbhangui@gmail.com>
+diff -ruN ../netqmail-1.06-original/spawn-filter.c netqmail-1.06/spawn-filter.c
+--- ../netqmail-1.06-original/spawn-filter.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/spawn-filter.c	2016-11-22 21:03:57.128527565 +0100
+@@ -0,0 +1,546 @@
++/*
++ * netqmail-version without spam filter
++ *
++ * $Log: spawn-filter.c,v $
++ * Revision 1.41  2009-04-03 11:42:48+05:30  Cprogrammer
++ * create pipe for error messages
++ *
++ * Revision 1.40  2009-04-02 15:17:54+05:30  Cprogrammer
++ * unset QMAILLOCAL in qmail-remote and unset QMAILREMOTE in qmail-local
++ *
++ * Revision 1.39  2008-06-12 08:40:55+05:30  Cprogrammer
++ * added rulesfile argument
++ *
++ * Revision 1.38  2008-05-25 17:16:43+05:30  Cprogrammer
++ * made message more readable by adding a blank space
++ *
++ * Revision 1.37  2007-12-20 13:51:54+05:30  Cprogrammer
++ * avoid loops with FILTERARGS, SPAMFILTERARGS
++ * removed compiler warning
++ *
++ * Revision 1.36  2006-06-07 14:11:28+05:30  Cprogrammer
++ * added SPAMEXT, SPAMHOST, SPAMSENDER, QQEH environment variable
++ * unset FILTERARGS before calling filters
++ *
++ * Revision 1.35  2006-01-22 10:14:45+05:30  Cprogrammer
++ * BUG fix for spam mails wrongly getting blackholed
++ *
++ * Revision 1.34  2005-08-23 17:36:48+05:30  Cprogrammer
++ * gcc 4 compliance
++ * delete sender in spam notification
++ *
++ * Revision 1.33  2005-04-02 19:07:47+05:30  Cprogrammer
++ * use internal wildmat version
++ *
++ * Revision 1.32  2004-11-22 19:50:53+05:30  Cprogrammer
++ * include regex.h after sys/types.h to avoid compilation prob on RH 7.3
++ *
++ * Revision 1.31  2004-10-22 20:30:35+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.30  2004-10-21 21:56:21+05:30  Cprogrammer
++ * change for two additional arguments to strerr_die()
++ *
++ * Revision 1.29  2004-10-11 14:06:14+05:30  Cprogrammer
++ * use control_readulong instead of control_readint
++ *
++ * Revision 1.28  2004-09-22 23:14:20+05:30  Cprogrammer
++ * replaced atoi() with scan_int()
++ *
++ * Revision 1.27  2004-09-08 10:54:49+05:30  Cprogrammer
++ * incorrect exit code in report() function for remote
++ * mails. Caused qmail-rspawn to report "Unable to run qmail-remote"
++ *
++ * Revision 1.26  2004-07-17 21:23:31+05:30  Cprogrammer
++ * change qqeh code in qmail-remote
++ *
++ * Revision 1.25  2004-07-15 23:40:46+05:30  Cprogrammer
++ * fixed compilation warning
++ *
++ * Revision 1.24  2004-07-02 16:15:25+05:30  Cprogrammer
++ * override control files rejectspam, spamredirect by
++ * environment variables REJECTSPAM and SPAMREDIRECT
++ * allow patterns in domain specification in the control files
++ * spamfilterargs, filterargs, rejectspam and spamredirect
++ *
++ * Revision 1.23  2004-06-03 22:58:34+05:30  Cprogrammer
++ * fixed compilation problem without indimail
++ *
++ * Revision 1.22  2004-05-23 22:18:17+05:30  Cprogrammer
++ * added envrules filename as argument
++ *
++ * Revision 1.21  2004-05-19 23:15:07+05:30  Cprogrammer
++ * added comments
++ *
++ * Revision 1.20  2004-05-12 22:37:47+05:30  Cprogrammer
++ * added check DATALIMIT check
++ *
++ * Revision 1.19  2004-05-03 22:17:36+05:30  Cprogrammer
++ * use QUEUE_BASE instead of auto_qmail
++ *
++ * Revision 1.18  2004-02-13 14:51:24+05:30  Cprogrammer
++ * added envrules
++ *
++ * Revision 1.17  2004-01-20 06:56:56+05:30  Cprogrammer
++ * unset FILTERARGS for notifications
++ *
++ * Revision 1.16  2004-01-20 01:52:08+05:30  Cprogrammer
++ * report string length corrected
++ *
++ * Revision 1.15  2004-01-10 09:44:36+05:30  Cprogrammer
++ * added comment for exit codes of bogofilter
++ *
++ * Revision 1.14  2004-01-08 00:32:49+05:30  Cprogrammer
++ * use TMPDIR environment variable for temporary directory
++ * send spam reports to central spam logger
++ *
++ * Revision 1.13  2003-12-30 00:44:42+05:30  Cprogrammer
++ * set argv[0] from spamfilterprog
++ *
++ * Revision 1.12  2003-12-22 18:34:25+05:30  Cprogrammer
++ * replaced spfcheck() with address_match()
++ *
++ * Revision 1.11  2003-12-20 01:35:06+05:30  Cprogrammer
++ * added wait_pid to prevent zombies
++ *
++ * Revision 1.10  2003-12-17 23:33:39+05:30  Cprogrammer
++ * improved logic for getting remote/local tokens
++ *
++ * Revision 1.9  2003-12-16 10:38:24+05:30  Cprogrammer
++ * fixed incorrect address being returned if filterargs contained local: or
++ * remote: directives
++ *
++ * Revision 1.8  2003-12-15 20:46:19+05:30  Cprogrammer
++ * added case 100 to bounce mail
++ *
++ * Revision 1.7  2003-12-15 13:51:44+05:30  Cprogrammer
++ * code to run additional filters using /bin/sh
++ *
++ * Revision 1.6  2003-12-14 11:36:18+05:30  Cprogrammer
++ * added option to blackhole spammers
++ *
++ * Revision 1.5  2003-12-13 21:08:46+05:30  Cprogrammer
++ * extensive rewrite
++ * common report() function for local/remote mails to report errors
++ *
++ * Revision 1.4  2003-12-12 20:20:55+05:30  Cprogrammer
++ * use -a option to prevent using header addresses
++ *
++ * Revision 1.3  2003-12-09 23:37:16+05:30  Cprogrammer
++ * change for spawn-filter to be called as qmail-local or qmail-remote
++ *
++ * Revision 1.2  2003-12-08 23:48:23+05:30  Cprogrammer
++ * new function getDomainToken() to retrieve domain specific values
++ * read rejectspam and spamredirect only if SPAMEXITCODE is set
++ *
++ * Revision 1.1  2003-12-07 13:02:00+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include "fmt.h"
++#include "str.h"
++#include "strerr.h"
++#include "env.h"
++#include "substdio.h"
++#include "subfd.h"
++#include "stralloc.h"
++#include "error.h"
++#include "control.h"
++#include "wait.h"
++#include "qregex.h"
++#include "auto_qmail.h"
++#include <regex.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <fcntl.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)
++
++static int      mkTempFile(int);
++static void     report(int, char *, char *, char *, char *, char *, char *);
++char           *getDomainToken(char *, stralloc *);
++static int      run_mailfilter(char *, char *, char **);
++int             wildmat_internal(char *, char *);
++static int      check_size(char *);
++
++static int      remotE;
++stralloc        sender = { 0 };
++stralloc        recipient = { 0 };
++
++static int
++check_size(char *size)
++{
++	char           *x;
++	unsigned long   databytes = -1, msgsize;
++
++	if (!(x = env_get("DATABYTES")))
++	{
++		if (control_readulong(&databytes, "databytes") == -1)
++			report(111, "spawn-filter: Unable to read databytes: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	} else
++		scan_ulong(x, &databytes);
++	if (databytes == -1)
++		return (0);
++	scan_ulong(size, &msgsize);
++	if (msgsize > databytes)
++		return(1);
++	else
++		return(0);
++}
++
++static void
++report(int errCode, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6)
++{
++	if (!remotE) /*- strerr_die does not return */
++		strerr_die(errCode, s1, s2, s3, s4, s5, s6, 0, 0, (struct strerr *) 0);
++	/*- h - hard, s - soft */
++	if (substdio_put(subfdoutsmall, errCode == 111 ? "s" : "h", 1) == -1)
++		_exit(111);
++	if (s1 && substdio_puts(subfdoutsmall, s1) == -1)
++		_exit(111);
++	if (s2 && substdio_puts(subfdoutsmall, s2) == -1)
++		_exit(111);
++	if (s3 && substdio_puts(subfdoutsmall, s3) == -1)
++		_exit(111);
++	if (s4 && substdio_puts(subfdoutsmall, s4) == -1)
++		_exit(111);
++	if (s5 && substdio_puts(subfdoutsmall, s5) == -1)
++		_exit(111);
++	if (s6 && substdio_puts(subfdoutsmall, s6) == -1)
++		_exit(111);
++	if (substdio_put(subfdoutsmall, "\0", 1) == -1)
++		_exit(111);
++	if (substdio_puts(subfdoutsmall, 
++		errCode == 111 ?  "Zspawn-filter said: Message deferred" : "DGiving up on spawn-filter\n") == -1)
++		_exit(111);
++	if (substdio_put(subfdoutsmall, "\0", 1) == -1)
++		_exit(111);
++	substdio_flush(subfdoutsmall);
++	/*- For qmail-rspawn to stop complaining unable to run qmail-remote */
++	_exit(0);
++}
++
++void
++set_environ(char *host, char *sender, char *recipient)
++{
++	if (!env_put2("DOMAIN", host)) 
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (!env_put2("_SENDER", sender))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (!env_put2("_RECIPIENT", recipient))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	return;
++}
++
++static int
++run_mailfilter(char *domain, char *mailprog, char **argv)
++{
++	char            strnum[FMT_ULONG];
++	pid_t           filt_pid;
++	int             pipefd[2], pipefe[2];
++	int             wstat, filt_exitcode, len = 0;
++	char           *filterargs;
++	static stralloc filterdefs = { 0 };
++	static char     errstr[1024];
++	char            inbuf[1024];
++	char            ch;
++	static substdio errbuf;
++
++	if (!(filterargs = env_get("FILTERARGS")))
++	{
++		if (control_readfile(&filterdefs, "control/filterargs", 0) == -1)
++			report(111, "spawn-filter: Unable to read filterargs: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		filterargs = getDomainToken(domain, &filterdefs);
++	}
++	if (!filterargs)
++	{
++		execv(mailprog, argv);
++		report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
++		_exit(111); /*- To make compiler happy */
++	}
++	if (pipe(pipefd) == -1)
++		report(111, "spawn-filter: Trouble creating pipes: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (pipe(pipefe) == -1)
++		report(111, "spawn-filter: Trouble creating pipes: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	switch ((filt_pid = fork()))
++	{
++	case -1:
++		report(111, "spawn-filter: Trouble creating child filter: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	case 0: /*- Filter Program */
++		set_environ(domain, sender.s, recipient.s);
++		/*- Mail content read from fd 0 */
++		if (mkTempFile(0))
++			report(111, "spawn-filter: lseek error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		/*- stdout will go here */
++		if (dup2(pipefd[1], 1) == -1 || close(pipefd[0]) == -1)
++			report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (pipefd[1] != 1)
++			close(pipefd[1]);
++		/*- stderr will go here */
++		if (dup2(pipefe[1], 2) == -1 || close(pipefe[0]) == -1)
++			report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (pipefe[1] != 2)
++			close(pipefe[1]);
++		/*- Avoid loop if program(s) defined by FILTERARGS call qmail-inject, etc */
++		if (!env_unset("FILTERARGS") || !env_unset("SPAMFILTER"))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		execl("/bin/sh", "IndiMailfilter", "-c", filterargs, (char *) 0);
++		report(111, "spawn-filter: could not exec /bin/sh: ",  filterargs, ": ", error_str(errno), ". (#4.3.0)", 0);
++	default:
++		close(pipefe[1]);
++		close(pipefd[1]);
++		if (dup2(pipefd[0], 0))
++		{
++			close(pipefd[0]);
++			close(pipefe[0]);
++			wait_pid(&wstat, filt_pid);
++			report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		}
++		if (pipefd[0] != 0)
++			close(pipefd[0]);
++		if (mkTempFile(0))
++		{
++			close(0);
++			close(pipefe[0]);
++			wait_pid(&wstat, filt_pid);
++			report(111, "spawn-filter: lseek error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		}
++		break;
++	}
++	/*- Process message if exit code is 0, bounce if 100 */
++	if (wait_pid(&wstat, filt_pid) != filt_pid)
++	{
++		close(0);
++		close(pipefe[0]);
++		report(111, "spawn-filter: waitpid surprise: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	}
++	if (wait_crashed(wstat))
++	{
++		close(0);
++		close(pipefe[0]);
++		report(111, "spawn-filter: filter crashed: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	}
++	switch (filt_exitcode = wait_exitcode(wstat))
++	{
++	case 0:
++		execv(mailprog, argv);
++		report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
++	case 100:
++		report(100, "Mail Rejected (#5.7.1)", 0, 0, 0, 0, 0);
++	default:
++		substdio_fdbuf(&errbuf, read, pipefe[0], inbuf, sizeof(inbuf));
++		for (len = 0; substdio_bget(&errbuf, &ch, 1) && len < (sizeof(errstr) - 1); len++)
++			errstr[len] = ch;
++		errstr[len] = 0;
++		strnum[fmt_ulong(strnum, filt_exitcode)] = 0;
++		report(111, filterargs, ": (spawn-filter) exit code: ", strnum, *errstr ? ": " : 0, *errstr ? errstr : 0, ". (#4.3.0)");
++	}
++	/*- Not reached */
++	return(111);
++}
++
++char           *
++getDomainToken(char *domain, stralloc *sa)
++{
++	regex_t         qreg;
++	int             len, n, retval;
++	char           *ptr, *p;
++	char            errbuf[512];
++
++	for (len = 0, ptr = sa->s;len < sa->len;)
++	{
++		len += ((n = str_len(ptr)) + 1);
++		for (p = ptr;*p && *p != ':';p++);
++		if (*p == ':')
++		{
++			*p = 0;
++			/*- build the regex */
++			if ((retval = str_diff(ptr, domain)))
++			{
++				if (env_get("QREGEX"))
++				{
++					if ((retval = REGCOMP(qreg, ptr)) != 0)
++					{
++						regerror(retval, &qreg, errbuf, sizeof(errbuf));
++						regfree(&qreg);
++						report(111, "spawn-filter: ", ptr, ": ", errbuf, ". (#4.3.0)", 0);
++					}
++					retval = REGEXEC(qreg, domain);
++					regfree(&qreg);
++				} else
++					retval = !wildmat_internal(domain, ptr);
++			}
++			*p = ':';
++			if (!retval) /*- match occurred for domain or wildcard */
++			{
++				/* check for local/remote directives */
++				if (remotE)
++				{
++					if (!str_diffn(p + 1, "remote:", 7))
++						return (p + 8);
++					if (!str_diffn(p + 1, "local:", 6))
++					{
++						ptr = sa->s + len;
++						continue; /*- skip local directives for remote mails */
++					}
++				} else
++				{
++					if (!str_diffn(p + 1, "local:", 6))
++						return (p + 7);
++					if (!str_diffn(p + 1, "remote:", 7))
++					{
++						ptr = sa->s + len;
++						continue; /*- skip remote directives for remote mails */
++					}
++				}
++				return (p + 1);
++			}
++		}
++		ptr = sa->s + len;
++	}
++	return ((char *) 0);
++}
++
++int
++mkTempFile(int seekfd)
++{
++	char            inbuf[2048], outbuf[2048], strnum[FMT_ULONG];
++	char           *tmpdir;
++	static stralloc tmpFile = {0};
++	struct substdio _ssin;
++	struct substdio _ssout;
++	int             fd;
++
++	if (lseek(seekfd, 0, SEEK_SET) == 0)
++		return (0);
++	if (errno == EBADF)
++	{
++		strnum[fmt_ulong(strnum, seekfd)] = 0;
++		report(111, "spawn-filter: fd ", strnum, ": ", error_str(errno), ". (#4.3.0)", 0);
++	}
++	if (!(tmpdir = env_get("TMPDIR")))
++		tmpdir = "/tmp";
++	if (!stralloc_copys(&tmpFile, tmpdir))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (!stralloc_cats(&tmpFile, "/qmailFilterXXX"))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (!stralloc_catb(&tmpFile, strnum, fmt_ulong(strnum, (unsigned long) getpid())))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (!stralloc_0(&tmpFile))
++		report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if ((fd = open(tmpFile.s, O_RDWR | O_EXCL | O_CREAT, 0600)) == -1)
++		report(111, "spawn-filter: ", tmpFile.s, ": ", error_str(errno), ". (#4.3.0)", 0);
++	unlink(tmpFile.s);
++	substdio_fdbuf(&_ssout, write, fd, outbuf, sizeof(outbuf));
++	substdio_fdbuf(&_ssin, read, seekfd, inbuf, sizeof(inbuf));
++	switch (substdio_copy(&_ssout, &_ssin))
++	{
++	case -2: /*- read error */
++		report(111, "spawn-filter: read error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	case -3: /*- write error */
++		report(111, "spawn-filter: write error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	}
++	if (substdio_flush(&_ssout) == -1)
++		report(111, "spawn-filter: write error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (dup2(fd, seekfd) == -1)
++		report(111, "spawn-filter: dup2 error: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	if (lseek(seekfd, 0, SEEK_SET) != 0)
++		report(111, "spawn-filter: lseek: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	return (0);
++}
++
++int
++main(int argc, char **argv)
++{
++	char           *ptr, *mailprog, *domain, *errStr = 0, *size = "0", *qqeh, *ext;
++	char            sizebuf[FMT_ULONG];
++	struct stat     statbuf;
++	int             len;
++
++	len = str_len(argv[0]);
++	for (ptr = argv[0] + len;*ptr != '/' && ptr != argv[0];ptr--);
++	if (*ptr && *ptr == '/')
++		ptr++;
++	ptr += 6;
++	if (*ptr == 'l') /*- qmail-local Filter */
++	{
++		mailprog = "bin/qmail-local";
++		domain = argv[7];
++		ext = argv[6];
++		qqeh = argv[10];
++		remotE = 0;
++		if (!env_unset("QMAILREMOTE"))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!fstat(0, &statbuf)) 
++		{
++			sizebuf[fmt_ulong(sizebuf, statbuf.st_size)] = 0;
++			size = sizebuf;
++		} else
++			size = "0";
++		/*- sender */
++		if (!stralloc_copys(&sender, argv[8]))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_0(&sender))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!env_unset("QMAILREMOTE"))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		/*- recipient */
++		if (*ext) /*- EXT */
++		{
++			if (!stralloc_copys(&recipient, ext))
++				report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		} else /*- user */
++			if (!stralloc_copys(&recipient, argv[2]))
++				report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_cats(&recipient, "@"))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_cats(&recipient, domain))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_0(&recipient))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	} else
++	if (*ptr == 'r') /*- qmail-remote Filter */
++	{
++		mailprog = "bin/qmail-remote";
++		domain = argv[1];
++		ext = argv[5];
++		qqeh = argv[3];
++		size = argv[4];
++		remotE = 1;
++		if (!env_unset("QMAILLOCAL"))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		/*- sender */
++		if (!stralloc_copys(&sender, argv[2]))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_0(&sender))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		/*- recipient */
++		if (!stralloc_copys(&recipient, argv[5]))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++		if (!stralloc_0(&recipient))
++			report(111, "spawn-filter: out of mem: ", error_str(errno), ". (#4.3.0)", 0, 0, 0);
++	} else
++	{
++		report(111, "spawn-filter: Incorrect usage. ", argv[0], " (#4.3.0)", 0, 0, 0);
++		_exit(111);
++	}
++	if (chdir(auto_qmail) == -1)
++		report(111, "spawn-filter: Unable to switch to ", auto_qmail, ": ", error_str(errno), ". (#4.3.0)", 0);
++	/*- DATABYTES Check */
++	if (check_size(size))
++		report(100, "sorry, that message size exceeds my databytes limit (#5.3.4)", 0, 0, 0, 0, 0);
++	run_mailfilter(domain, mailprog, argv);
++	report(111, "spawn-filter: could not exec ", mailprog, ": ", error_str(errno), ". (#4.3.0)", 0);
++	/*- Not reached */
++	return(0);
++}
++
++void
++getversion_qmail_spawn_filter_c()
++{
++	static char    *x = "$Id: spawn-filter.c,v 1.41 2009-04-03 11:42:48+05:30 Cprogrammer Stab mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/spawn.c netqmail-1.06/spawn.c
+--- ../netqmail-1.06-original/spawn.c	2007-11-30 21:22:54.000000000 +0100
++++ netqmail-1.06/spawn.c	2016-11-22 21:03:57.128527565 +0100
+@@ -1,4 +1,4 @@
+-#include <sys/types.h>
++#include "select.h"
+ #include <sys/stat.h>
+ #include "sig.h"
+ #include "wait.h"
+@@ -7,7 +7,6 @@
+ #include "str.h"
+ #include "alloc.h"
+ #include "stralloc.h"
+-#include "select.h"
+ #include "exit.h"
+ #include "coe.h"
+ #include "open.h"
+@@ -64,7 +63,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 +73,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 +156,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 +205,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 +241,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 -ruN ../netqmail-1.06-original/spf.c netqmail-1.06/spf.c
+--- ../netqmail-1.06-original/spf.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/spf.c	2016-11-22 21:03:57.129527532 +0100
+@@ -0,0 +1,877 @@
++#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 *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(char *remoteip)
++{
++	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 -ruN ../netqmail-1.06-original/spf.h netqmail-1.06/spf.h
+--- ../netqmail-1.06-original/spf.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/spf.h	2016-11-22 21:03:57.129527532 +0100
+@@ -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 -ruN ../netqmail-1.06-original/spfquery.c netqmail-1.06/spfquery.c
+--- ../netqmail-1.06-original/spfquery.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/spfquery.c	2016-11-22 21:03:57.129527532 +0100
+@@ -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 -ruN ../netqmail-1.06-original/srs.c netqmail-1.06/srs.c
+--- ../netqmail-1.06-original/srs.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/srs.c	2016-11-22 21:03:57.129527532 +0100
+@@ -0,0 +1,166 @@
++#include <sys/types.h>
++#include <sys/stat.h>
++#include </usr/local/include/srs2.h>
++#include "auto_qmail.h"
++#include "stralloc.h"
++#include "srs.h"
++
++static stralloc srs_domain = {0};
++static stralloc srs_secrets = {0};
++static unsigned int srs_maxage = 0;
++static unsigned int srs_hashlength = 0;
++static unsigned int srs_hashmin = 0;
++static unsigned int srs_alwaysrewrite = 0;
++static stralloc srs_separator = {0};
++
++stralloc srs_result = {0};
++stralloc srs_error = {0};
++
++static int setup_ok = 0;
++static int srs_secrets_ok = 0;
++
++static int setup(int with_rcpthosts) {
++
++  if (setup_ok == 1) return 1;
++
++  if (chdir(auto_qmail) == -1) return -1;
++  if (control_init() == -1) return -1;
++
++  if (control_readline(&srs_domain,"control/srs_domain") == -1) return -1;
++  if (srs_domain.len) {
++    if (!stralloc_0(&srs_domain)) return -2;
++  } else {
++    return 0;
++  }
++
++  srs_secrets_ok = control_readfile(&srs_secrets,"control/srs_secrets",0);
++  if (srs_secrets_ok == -1) return -1;
++  
++  if (control_readint(&srs_maxage,"control/srs_maxage") == -1) return 0;
++  if (control_readint(&srs_hashlength,"control/srs_hashlength") == -1) return 0;
++  if (control_readint(&srs_hashmin,"control/srs_hashmin") == -1) return 0;
++  if (srs_hashmin > srs_hashlength) srs_hashmin = srs_hashlength;
++  
++  if (control_readint(&srs_alwaysrewrite,"control/srs_alwaysrewrite") == -1) return 0;
++  
++  if (control_readline(&srs_separator,"control/srs_separator") == -1) return -1;
++  if (srs_separator.len && !stralloc_0(&srs_separator)) return -2;
++  if (srs_separator.len && srs_separator.s[0] != '-' && srs_separator.s[0] != '+' && srs_separator.s[0] != '=') {
++    if (!stralloc_copys(&srs_separator,"")) return -2;
++  }
++  
++  if (!srs_alwaysrewrite) {
++    if (with_rcpthosts && rcpthosts_init() == -1) return -1;
++  }
++
++  setup_ok = 1;
++  return 1;
++  
++}
++
++static int srs_error_str(int code) {
++  if (!stralloc_copys(&srs_error,"SRS: ")) return -2;
++  if (!stralloc_cats(&srs_error,srs_strerror(code))) return -2;
++  if (!stralloc_0(&srs_error)) return -2;   
++  return -3;
++}
++
++
++int srsforward(char *address) {
++  int x = 0;
++
++  /* Return if setup was unsucessfull */
++  x = setup(1);
++  if (x < 1) return(x);
++  
++  /* Return zero if null-sender */
++  x = str_len(address);
++  if (x <= 1) return 0;
++
++  /* Return zero if local address */
++  if (!srs_alwaysrewrite && rcpthosts(address,x) == 1) return 0;  
++  
++  /* Now it's time to rewrite the envelope */
++  char srsaddress[1000];
++
++  srs_t *srs; 
++  srs = srs_new();
++  if (srs_maxage > 0) srs->maxage = srs_maxage;
++  if (srs_hashlength > 0) srs->hashlength = srs_hashlength;
++  if (srs_hashmin > 0) srs->hashmin = srs_hashmin;
++  
++  if (srs_alwaysrewrite){  
++    x = srs_set_alwaysrewrite(srs, TRUE);
++    if (x != SRS_SUCCESS) return srs_error_str(x);
++  }
++  
++  if (srs_separator.len) {
++    x = srs_set_separator(srs, srs_separator.s[0]); 
++    if (x != SRS_SUCCESS) return srs_error_str(x);
++  }
++  
++  int i = 0;
++  int j = 0;
++  for (j = 0;j < srs_secrets.len;++j)
++    if (!srs_secrets.s[j]) {
++      x = srs_add_secret(srs, srs_secrets.s + i);
++      if (x != SRS_SUCCESS) return srs_error_str(x);
++      i = j + 1;
++    }
++  
++  x = srs_forward(srs, srsaddress, 1000, address, srs_domain.s);
++  if (x != SRS_SUCCESS) return srs_error_str(x);
++  
++  if (!stralloc_copys(&srs_result,srsaddress)) return -2;
++  if (!stralloc_0(&srs_result)) return -2;
++  
++  srs_free(srs);
++  
++  return 1;
++}
++
++int srsreverse(char *srsaddress) {
++  int x = 0;
++
++  /* Return if setup was unsucessfull */
++  x = setup(0);
++  if (x < 1) return(x);
++  
++  /* Return error if null-sender */
++  x = str_len(srsaddress);
++  if (x <= 1) return -3;
++  
++  /* Now it's time to rewrite the envelope */
++  char address[1000];
++
++  srs_t *srs;
++  srs = srs_new();
++  if (srs_maxage > 0) srs->maxage = srs_maxage;
++  if (srs_hashlength > 0) srs->hashlength = srs_hashlength;
++  if (srs_hashmin > 0) srs->hashmin = srs_hashmin;
++  
++  if (srs_separator.len) {
++    x = srs_set_separator(srs, srs_separator.s[0]); 
++    if (x != SRS_SUCCESS) return srs_error_str(x);
++  }
++
++  int i = 0;
++  int j = 0;
++  for (j = 0;j < srs_secrets.len;++j)
++    if (!srs_secrets.s[j]) {
++      x = srs_add_secret(srs, srs_secrets.s + i);
++      if (x != SRS_SUCCESS) return srs_error_str(x);
++      i = j + 1;
++    }
++    
++  x = srs_reverse(srs, address, 1000, srsaddress);
++  if (x != SRS_SUCCESS) return srs_error_str(x);
++  
++  if (!stralloc_copys(&srs_result,address)) return -2;
++  if (!stralloc_0(&srs_result)) return -2;
++  
++  srs_free(srs);
++  
++  return 1;
++}
++
+diff -ruN ../netqmail-1.06-original/srs.h netqmail-1.06/srs.h
+--- ../netqmail-1.06-original/srs.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/srs.h	2016-11-22 21:03:57.129527532 +0100
+@@ -0,0 +1,9 @@
++#ifndef SRS_H
++#define SRS_H
++
++extern stralloc srs_result;
++extern stralloc srs_error;
++extern int srsforward(char *);
++extern int srsreverse(char *);
++
++#endif
+diff -ruN ../netqmail-1.06-original/srsfilter.c netqmail-1.06/srsfilter.c
+--- ../netqmail-1.06-original/srsfilter.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/srsfilter.c	2016-11-22 21:03:57.129527532 +0100
+@@ -0,0 +1,137 @@
++#include "sig.h"
++#include "readwrite.h"
++#include "exit.h"
++#include "env.h"
++#include "qmail.h"
++#include "strerr.h"
++#include "substdio.h"
++#include "fmt.h"
++#include "stralloc.h"
++#include "srs.h"
++
++#define FATAL "srsfilter: fatal: "
++#define IGNORE "srsfilter: ignore: "
++
++void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
++
++struct qmail qqt;
++
++stralloc line = {0};
++int flagbody = 0;
++int flagnewline = 0;
++int flagto = 0;
++int seento = 0;
++
++void newheader() {
++  if (!stralloc_copyb(&line,"To: ",4)) die_nomem();
++  if (!stralloc_cat(&line,&srs_result)) die_nomem();
++  ++flagto; ++seento;
++}
++
++void skipheader() {
++  if (!stralloc_copys(&line,"")) die_nomem();
++}
++
++void printheader() {
++  qmail_put(&qqt, line.s, line.len);
++  qmail_put(&qqt,"\n",1);
++  if (!stralloc_copys(&line,"")) die_nomem();
++}
++
++int mywrite(fd,buf,len) int fd; char *buf; int len;
++{
++  int i;
++  if (flagbody) {
++    qmail_put(&qqt,buf,len);
++    return len;
++  } else {
++    i = 0;
++    while (buf[i]) {
++      if (buf[i] == '\n') {
++        if (flagnewline) {
++          if (!seento) { newheader(); printheader(); }
++          qmail_put(&qqt,"\n",1); i++; flagbody = 1; continue;
++        }
++        if (flagto && (line.s[0] == ' ' || line.s[0] == '\t')) {
++          skipheader(); i++; continue;
++        }
++        if (line.len > 2 && line.s[2] == ':' && (line.s[1] == 'o' ||
++        line.s[1] == 'O') && (line.s[0] == 'T' || line.s[0] == 't')) {
++          if (seento) { skipheader(); i++; continue; }
++          newheader();
++        } else { flagto = 0; }
++        printheader();
++        flagnewline = 1;
++      } else {
++        if (!stralloc_append(&line,&buf[i])) die_nomem();
++        flagnewline = 0;
++      }
++      ++i;
++    }
++    return len;
++  }
++}
++
++char inbuf[SUBSTDIO_INSIZE];
++char outbuf[1];
++substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
++substdio ssout = SUBSTDIO_FDBUF(mywrite,-1,outbuf,sizeof outbuf);
++
++char num[FMT_ULONG];
++
++void main(argc,argv)
++int argc;
++char **argv;
++{
++  char *ext2;
++  char *host;
++  char *sender;
++  char *qqx;
++ 
++  sig_pipeignore();
++ 
++  sender = env_get("SENDER");
++  if (!sender)
++    strerr_die2x(100,FATAL,"SENDER not set");
++  if (str_len(sender)) {
++    /* Return zero, the message will not bounce back */
++    strerr_die2x(0,IGNORE,"SENDER must be empty");
++  }
++  ext2 = env_get("EXT2");
++  if (!ext2)
++    strerr_die2x(100,FATAL,"EXT2 not set");
++  host = env_get("HOST");
++  if (!host)
++    strerr_die2x(100,FATAL,"HOST not set");
++    
++  switch(srsreverse(ext2)) {
++    case -3: strerr_die2x(100,FATAL,srs_error.s); break;
++    case -2: die_nomem(); break;
++    case -1: strerr_die2x(111,FATAL,"unable to read controls"); break;
++    case 0: strerr_die2x(100,FATAL,"unable to rewrite envelope"); break;
++  }
++ 
++  if (qmail_open(&qqt) == -1)
++    strerr_die2x(111,FATAL,"unable to fork");
++  if (substdio_copy(&ssout,&ssin) != 0)
++    strerr_die2x(111,FATAL,"unable to read message");
++  substdio_flush(&ssout);
++  
++  if (!flagbody) {
++    qmail_fail(&qqt);
++    strerr_die2x(100,FATAL,"unable to read message body");
++  }
++
++  num[fmt_ulong(num,qmail_qp(&qqt))] = 0;
++
++  /* Always from nullsender */
++  qmail_from(&qqt,"");
++  
++  qmail_to(&qqt,srs_result.s);
++  
++  qqx = qmail_close(&qqt);
++  if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
++  strerr_die2x(0,"srsfilter: qp ",num);
++
++}
++
+diff -ruN ../netqmail-1.06-original/ssl_timeoutio.c netqmail-1.06/ssl_timeoutio.c
+--- ../netqmail-1.06-original/ssl_timeoutio.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/ssl_timeoutio.c	2016-11-22 21:03:57.129527532 +0100
+@@ -0,0 +1,95 @@
++#include "select.h"
++#include "error.h"
++#include "ndelay.h"
++#include "now.h"
++#include "ssl_timeoutio.h"
++
++int ssl_timeoutio(int (*fun)(),
++  int t, int rfd, int wfd, SSL *ssl, char *buf, int len)
++{
++  int n;
++  const datetime_sec end = (datetime_sec)t + now();
++
++  do {
++    fd_set fds;
++    struct timeval tv;
++
++    const int r = buf ? fun(ssl, buf, len) : fun(ssl);
++    if (r > 0) return r;
++
++    t = end - now();
++    if (t < 0) break;
++    tv.tv_sec = (time_t)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(int 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(int 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(int 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(int 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(int 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 -ruN ../netqmail-1.06-original/ssl_timeoutio.h netqmail-1.06/ssl_timeoutio.h
+--- ../netqmail-1.06-original/ssl_timeoutio.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/ssl_timeoutio.h	2016-11-22 21:03:57.130527499 +0100
+@@ -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(int t, int rfd, int wfd, SSL *ssl);
++int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl);
++int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl);
++
++int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++
++int ssl_timeoutio(
++  int (*fun)(), int t, int rfd, int wfd, SSL *ssl, char *buf, int len);
++
++#endif
+diff -ruN ../netqmail-1.06-original/str.h netqmail-1.06/str.h
+--- ../netqmail-1.06-original/str.h	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/str.h	2016-11-22 21:03:57.130527499 +0100
+@@ -2,6 +2,11 @@
+ #define STR_H
+ 
+ extern unsigned int str_copy();
++
++/* DKIM 1.10
++extern unsigned int str_copyb();
++   end DKIM 1.10 */
++
+ extern int str_diff();
+ extern int str_diffn();
+ extern unsigned int str_len();
+@@ -9,6 +14,11 @@
+ extern unsigned int str_rchr();
+ extern int str_start();
+ 
++/* DKIM 1.10 */
++#include <sys/types.h>
++extern size_t str_cspn();
++/* end DKIM 1.10 */
++
+ #define str_equal(s,t) (!str_diff((s),(t)))
+ 
+ #endif
+diff -ruN ../netqmail-1.06-original/str_cpyb.c netqmail-1.06/str_cpyb.c
+--- ../netqmail-1.06-original/str_cpyb.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/str_cpyb.c	2016-11-22 21:03:57.130527499 +0100
+@@ -0,0 +1,53 @@
++/*
++ * $Log: str_cpyb.c,v $
++ * Revision 1.2  2004-10-22 20:30:54+05:30  Cprogrammer
++ * added RCS id
++ *
++ * Revision 1.1  2004-08-15 19:52:35+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#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;
++}
++
++void
++getversion_str_cpyb_c()
++{
++      static char    *x = "$Id: str_cpyb.c,v 1.2 2004-10-22 20:30:54+05:30 Cprogrammer Stab mbhangui $";
++      x++;
++}
++
+diff -ruN ../netqmail-1.06-original/str_cspn.c netqmail-1.06/str_cspn.c
+--- ../netqmail-1.06-original/str_cspn.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/str_cspn.c	2016-11-22 21:03:57.130527499 +0100
+@@ -0,0 +1,40 @@
++/*
++ * $Log: str_cspn.c,v $
++ * Revision 1.1  2011-07-12 20:42:00+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include "str.h"
++/*
++ * Span the complement of string s2.
++ */
++size_t
++str_cspn(s1, s2)
++	const char *s1;
++	register const char *s2;
++{
++	register const char *p, *spanp;
++	register char c, sc;
++
++	/*
++	 * Stop as soon as we find any character from s2.  Note that there
++	 * must be a NUL in s2; it suffices to stop when we find that, too.
++	 */
++	for (p = s1;;) {
++		c = *p++;
++		spanp = s2;
++		do {
++			if ((sc = *spanp++) == c)
++				return (p - 1 - s1);
++		} while (sc != 0);
++	}
++	/* NOTREACHED */
++}
++
++void
++getversion_str_cspn_c()
++{
++	static char    *x = "$Id: str_cspn.c,v 1.1 2011-07-12 20:42:00+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/strpidt.c netqmail-1.06/strpidt.c
+--- ../netqmail-1.06-original/strpidt.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/strpidt.c	2016-11-22 21:03:57.130527499 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/strsalloc.c netqmail-1.06/strsalloc.c
+--- ../netqmail-1.06-original/strsalloc.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/strsalloc.c	2016-11-22 21:03:57.130527499 +0100
+@@ -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 -ruN ../netqmail-1.06-original/strsalloc.h netqmail-1.06/strsalloc.h
+--- ../netqmail-1.06-original/strsalloc.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/strsalloc.h	2016-11-22 21:03:57.130527499 +0100
+@@ -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 -ruN ../netqmail-1.06-original/strtimet.c netqmail-1.06/strtimet.c
+--- ../netqmail-1.06-original/strtimet.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/strtimet.c	2016-11-22 21:03:57.130527499 +0100
+@@ -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: qmail-maildir++.patch,v 1.1.1.1.2.1 2005/01/19 23:35:23 tomcollins 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 -ruN ../netqmail-1.06-original/surblfilter.9 netqmail-1.06/surblfilter.9
+--- ../netqmail-1.06-original/surblfilter.9	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/surblfilter.9	2016-11-22 21:03:57.130527499 +0100
+@@ -0,0 +1,80 @@
++.TH surblfilter 8
++.SH NAME
++surblfilter \- qmail SURBL blocklist interface
++.SH SYNOPSIS
++.B surblfilter
++[
++.B \-v
++]
++[
++.B \-c
++]
++[
++.B \-t
++]
++.SH DESCRIPTION
++\fBSURBL\fRs are lists of web sites that have appeared in unsolicited messages. Unlike most lists,
++SURBLs are not lists of message senders.
++
++Web sites seen in unsolicited messages tend to be more stable than the rapidly changing botnet
++IP addresses used to send the vast majority of them. Sender lists like zen.spamhaus.org can be
++used in a first stage filter to help identify 80% to 90% of unsolicited messages. SURBLs can
++help find about 75% of the otherwise difficult, remaining unsolicited messages in a second
++stage filter. Used together with sender lists, SURBLs have proven to be a highly-effective way
++to detect 95% of unsolicited messages.
++
++\fBsurblfilter\fR reads an rfc822 email on stdin, extracts URL and checks them against SURBL.
++\fBsurblfilter\fR can be used as a filter using \fBqmail-qfilter(1)\fR. It can also be used
++as a qmail-queue(8) frontend by setting QMAILQUEUE environment variable to a wrapper
++QMAILHOME/bin/surblqueue. You can define \fBSURBLQUEUE\fR environment variable to make
++\fBsurblqueue\fR execute something other than \fBqmail-queue\fR(8).
++
++\fBsurblfilter\fR uses \fBQMAILRCPTS\fR environment variable to get the recipient list. You can
++whitelist recipients by having the email addresses in \fIsurblrcpt\fR control file. You can
++change the name of this control file by setting \fBSURBLRCPT\fR environment variable.
++.PP
++\fBsurblfilter\fR uses the control file \fIsurbldomainwhite\fR to whitelist a domain.
++
++.PP
++The default SURBL list that is used is \fBmulti.surbl.org\fR. You can use a different list
++by setting the \fIsurbldomain\fR control file.
++
++.PP
++\fBsurblfilter\fR caches results in QMAILHOME/control/cache. The filename represents the domain.
++If a file as permission 0600, it means that the domain was blacklisted. The entries are
++cached for a default of 300 seconds. You can change this by setting \fIcachelifetime\fR
++control file. This directory should be owned by the uid set for running qmail-smtpd(8).
++
++\fBsurblfilter\fR removes all leading host names, subdomains, www., randomized subdomains, etc. In
++order to determine the level of domain check, it uses the control files \fBlevel3-tlds\fR and
++\fBlevel2-tlds\fR. For any domain found in \fBlevel3-tlds\fR, it checks the domain at level4. For any
++domain found in \fBlevel2-tlds\fR, it checks the domain at level3. For all domains not found in
++these two control files, it checks the domain at level2. Please look at http://www.surbl.org/guidelines
++
++for more details.
++
++.SH OPTIONS
++.PP
++.TP
++\fB-v\fR
++Use debug mode
++
++.TP
++\fB-c\fR
++Do not cache results
++
++.TP
++\fB-t\fR
++Do dns text query to get the reason. This option will slow \fBsurblfilter\fR. Remember that
++last octet of the IP address obtained for the domain gives you the reason for the block
++
++.SH RETURN VALUE
++\fBsurbfilter\fR returns 88 if the domain is blocked and prints the reason on standard error.
++This allows for qmail-smtpd(8) to print a permanent error during a SMTP session.
++It returns 111 for all temporary errors. It returns 0 if the message does not contain any
++domain blocked by SURBL
++
++.SH "SEE ALSO"
++qmail-smtpd(8),
++qmail-queue(8),
++qmail-qfilter(1)
+diff -ruN ../netqmail-1.06-original/surblfilter.c netqmail-1.06/surblfilter.c
+--- ../netqmail-1.06-original/surblfilter.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/surblfilter.c	2017-05-10 21:54:26.719100696 +0200
+@@ -0,0 +1,881 @@
++/*
++ * $Log: surblfilter.c,v $
++ * Revision 1.3  2011-07-13 22:11:13+05:30  Cprogrammer
++ * skip surblrcpt if QMAILRCPTS is not defined
++ *
++ * Revision 1.2  2011-07-13 22:02:13+05:30  Cprogrammer
++ * added surblrcpt functionality
++ *
++ * Revision 1.1  2011-07-13 20:56:34+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#include <unistd.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <ctype.h>
++#include <time.h>
++#include <sys/stat.h>
++
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#ifdef DARWIN
++#include <nameser8_compat.h>
++#endif
++#include <arpa/nameser.h>
++#include <resolv.h>
++#include <netdb.h>
++
++#include "alloc.h"
++#include "sgetopt.h"
++#include "error.h"
++#include "scan.h"
++#include "str.h"
++#include "case.h"
++#include "constmap.h"
++#include "auto_qmail.h"
++#include "stralloc.h"
++#include "env.h"
++#include "control.h"
++#include "strerr.h"
++#include "substdio.h"
++#include "getln.h"
++#include "byte.h"
++#include "dns.h"
++#include "ip.h"
++#include "ipalloc.h"
++#include "mess822.h"
++#include "base64.h"
++
++#define FATAL "surblfilter: fatal: "
++
++char           *dns_text(char *);
++
++stralloc        line = { 0 };
++int             debug = 0, do_text = 0, do_cache = 1;
++static int      cachelifetime = 300;
++stralloc        whitelist = { 0 };
++stralloc        surbldomain = { 0 };
++
++/*- SURBL: RCPT whitelist. */
++stralloc        srw = { 0 };
++int             srwok = 0;
++struct constmap mapsrw;
++
++/*- 2 level tld */
++stralloc        l2 = { 0 };
++int             l2ok = 0;
++struct constmap mapl2;
++/*- 3 level tld */
++stralloc        l3 = { 0 };
++int             l3ok = 0;
++struct constmap mapl3;
++
++static char     ssinbuf[1024];
++static substdio ssin = SUBSTDIO_FDBUF(read, 0, ssinbuf, sizeof ssinbuf);
++static char     ssoutbuf[512];
++static substdio ssout = SUBSTDIO_FDBUF(write, 1, ssoutbuf, sizeof ssoutbuf);
++static char     sserrbuf[512];
++static substdio sserr = SUBSTDIO_FDBUF(write, 2, sserrbuf, sizeof(sserrbuf));
++
++void
++out(char *str)
++{
++	if (!str || !*str)
++		return;
++	if (substdio_puts(&ssout, str) == -1)
++		strerr_die2sys(111, FATAL, "write: ");
++	return;
++}
++
++void
++print_debug(char *arg1, char *arg2, char *arg3)
++{
++	if (!debug)
++		return;
++	if (arg1 && substdio_puts(&sserr, arg1) == -1)
++		_exit(1);
++	if (arg2 && substdio_puts(&sserr, arg2) == -1)
++		_exit(1);
++	if (arg3 && substdio_puts(&sserr, arg3) == -1)
++		_exit(1);
++	if ((arg1 || arg2 || arg3) && substdio_puts(&sserr, "\n"))
++		_exit(1);
++	if (substdio_flush(&sserr) == -1)
++		_exit(1);
++}
++
++void
++die_write()
++{
++	strerr_die2sys(111, FATAL, "write: ");
++	return;
++}
++
++void
++flush()
++{
++	if (substdio_flush(&ssout) == -1)
++		strerr_die2sys(111, FATAL, "write: ");
++	return;
++}
++
++void
++logerr(char *s)
++{
++	if (substdio_puts(&sserr, s) == -1)
++		_exit(1);
++}
++
++void
++logerrf(char *s)
++{
++	if (substdio_puts(&sserr, s) == -1)
++		_exit(1);
++	if (substdio_flush(&sserr) == -1)
++		_exit(1);
++}
++
++void
++my_error(char *s1, char *s2, int exit_val)
++{
++	logerr(s1);
++	if (s2) {
++		logerr(": ");
++		logerr(s2);
++	}
++	if (exit_val > 0) {
++		logerr(": ");
++		logerr(error_str(errno));
++	}
++	logerrf("\n");
++	_exit(exit_val > 0 ? exit_val : 0 - exit_val);
++}
++
++void
++die_nomem()
++{
++	substdio_flush(&ssout);
++	substdio_puts(&sserr, "surblfilter: out of memory\n");
++	substdio_flush(&sserr);
++	_exit(1);
++}
++
++void
++die_soft()
++{
++	substdio_flush(&ssout);
++	substdio_puts(&sserr, "surblfilter: DNS temporary failure\n");
++	substdio_flush(&sserr);
++	_exit(1);
++}
++
++void
++die_hard()
++{
++	substdio_flush(&ssout);
++	substdio_puts(&sserr, "surblfilter: DNS permanent failure\n");
++	substdio_flush(&sserr);
++	_exit(1);
++}
++
++void
++die_control()
++{
++	substdio_flush(&ssout);
++	substdio_puts(&sserr, "surblfilter: unable to read controls\n");
++	substdio_flush(&sserr);
++	_exit(1);
++}
++
++static unsigned short
++getshort(unsigned char *cp)
++{
++	return (cp[0] << 8) | cp[1];
++}
++
++static char *
++strdup(const char *str)
++{
++	size_t siz;
++	char *copy;
++
++	siz = str_len((char *) str) + 1;
++	if (!(copy = alloc(siz)))
++		return((char *) 0);
++	byte_copy(copy, siz, (char *) str);
++	return(copy);
++}
++
++/*
++ * we always return a null-terminated string which has been malloc'ed.  The string
++ * is always in the tag=value form.  If a temporary or permanent error occurs,
++ * the string will be exactly "e=perm;" or "e=temp;".
++ * Note that it never returns NULL.
++ */
++char           *
++dns_text(char *dn)
++{
++        u_char          response[PACKETSZ + PACKETSZ + 1];      /* response */
++	int             responselen;			/* buffer length */
++	int             rc;				/* misc variables */
++	int             ancount, qdcount;		/* answer count and query count */
++	u_short         type, rdlength;			/* fields of records returned */
++	u_char         *eom, *cp;
++	u_char          buf[PACKETSZ + 1];		/* we're storing a TXT record here, not just a DNAME */
++	u_char         *bufptr;
++
++        for (rc = 0, responselen = PACKETSZ;rc < 2;rc++) {
++                if ((responselen = res_query(dn, C_IN, T_TXT, response, responselen)) < 0) {
++                        if (h_errno == TRY_AGAIN)
++                                return strdup("e=temp;");
++                        else
++                                return strdup("e=perm;");
++                }
++                if (responselen <= PACKETSZ)
++                        break;
++		else
++                if (responselen >= (2 * PACKETSZ))
++			return strdup("e=perm;");
++	}
++	qdcount = getshort(response + 4);	/* http://crynwr.com/rfc1035/rfc1035.html#4.1.1. */
++	ancount = getshort(response + 6);
++	eom = response + responselen;
++	cp = response + HFIXEDSZ;
++	while (qdcount-- > 0 && cp < eom) {
++		rc = dn_expand(response, eom, cp, (char *) buf, MAXDNAME);
++		if (rc < 0)
++			return strdup("e=perm;");
++		cp += rc + QFIXEDSZ;
++	}
++	while (ancount-- > 0 && cp < eom) {
++		if ((rc = dn_expand(response, eom, cp, (char *) buf, MAXDNAME)) < 0)
++			return strdup("e=perm;");
++		cp += rc;
++		if (cp + RRFIXEDSZ >= eom)
++			return strdup("e=perm;");
++		type = getshort(cp + 0);	/* http://crynwr.com/rfc1035/rfc1035.html#4.1.3. */
++		rdlength = getshort(cp + 8);
++		cp += RRFIXEDSZ;
++		if (type != T_TXT) {
++			cp += rdlength;
++			continue;
++		}
++		bufptr = buf;
++		while (rdlength && cp < eom) {
++			unsigned int    cnt;
++
++			cnt = *cp++;		/* http://crynwr.com/rfc1035/rfc1035.html#3.3.14. */
++                        if (bufptr - buf + cnt + 1 >= (2 * PACKETSZ))
++				return strdup("e=perm;");
++			if (cp + cnt > eom)
++				return strdup("e=perm;");
++			byte_copy((char *) bufptr, cnt, (char *) cp);
++			rdlength -= cnt + 1;
++			bufptr += cnt;
++			cp += cnt;
++			*bufptr = '\0';
++		}
++		return (char *) strdup((char *) buf);
++	}
++	return strdup("e=perm;");
++}
++
++static char    *
++uri_decode(char *str, size_t str_len, char **strend)
++{
++	size_t          i = 0, j = 0, found;
++	int             pasthostname = 0;
++	char           *str_bits = "\r\n\t \'\"<>()";
++
++	for (i = 0; i < str_len; i++, j++) {
++		if (str[i] == '%' || (!pasthostname && str[i] == '=')) {
++			if (i + 2 < str_len) {
++				if (isxdigit(str[i + 1]) && isxdigit(str[i + 2])) {
++					int             c1 = str[i + 1];
++					int             c2 = str[i + 2];
++					int             num = (	/* first character */
++											  ((c1 & 0xF)	/* take right half */
++											   +(9 * (c1 >> 6)))	/* add 9 if character is a-f or A-F */
++											  <<4	/* pack into the left half of the byte */
++						) | (	/* second character */
++								(c2 & 0xF)
++								+ (9 * (c2 >> 6))
++						);		/* leave it as the left half */
++					str[j] = tolower(num);
++					i += 2;
++					continue;
++				}
++			}
++		}
++		if (!pasthostname && (str[i] == '?' || str[i] == '/' || str[i] == '\\'))
++			pasthostname = 1;
++		if (i + 1 < str_len) {
++			if (str[i] == '=' && str[i + 1] == '\n') {
++				j -= 1;
++				i += 1;
++				continue;
++			}
++		}
++		if (i + 2 < str_len) {
++			if (str[i] == '=' && str[i + 1] == '\r' && str[i + 2] == '\n') {
++				j -= 1;
++				i += 2;
++				continue;
++			}
++		}
++		found = str_chr(str_bits, str[i]);
++		if (str_bits[found])
++			break;
++		str[j] = tolower(str[i]);
++	}
++	str[j] = '\0';
++	*strend = str + j + 1;
++	return str;
++}
++
++/*
++ * Returns:
++ * -1 on error
++ *  0 if domain wasn't cached
++ *  1 if domain was cached, and not blacklisted
++ *  2 if domain was cached, and blacklisted.
++ *
++ * text != NULL: host blacklisted, text == reason.
++ */
++static int
++cachefunc(char *uri, size_t urilen, char **text, int flag)
++{
++	static char     inbuf[2048];
++	static stralloc cachefile = { 0 }, reason = { 0 };
++	int             fd, i, n, textlen, match;
++	struct stat     st;
++	substdio        ss;
++
++	if (!do_cache)
++		return (0);
++	if (uri[i = str_chr(uri, '/')]) {
++		errno = EINVAL;
++		return (-1);
++	}
++	if (!stralloc_copys(&cachefile, "control/cache", 13))
++		die_nomem();
++	if (!stralloc_0(&cachefile))
++		die_nomem();
++	if (access(cachefile.s, F_OK))
++		return (0);
++	cachefile.len--;
++	if (!stralloc_append(&cachefile, "/"))
++		die_nomem();
++	if (!stralloc_cats(&cachefile, uri))
++		die_nomem();
++	if (!stralloc_0(&cachefile))
++		die_nomem();
++	if (flag) { /*- add the cache */
++		if (!access(cachefile.s, F_OK))
++			return (0);
++		if ((fd = open(cachefile.s, O_CREAT|O_WRONLY, *text ? 0600 : 0644)) == -1)
++			my_error(cachefile.s, 0, 2);
++		if (*text) {
++			textlen = str_len(*text);
++			if ((n = write(fd, *text, textlen)) == -1) {
++				close(fd);
++				my_error("write", 0, 1);
++			}
++		}
++		if (close(fd))
++			my_error(cachefile.s, 0, 1);
++	} else {
++		if (stat(cachefile.s, &st) == -1) {
++			if (errno == ENOENT)
++				return (0);
++			my_error("stat", 0, 1);
++			return -1;
++		}
++		if (time(0) > st.st_mtime + cachelifetime) {
++			if (unlink(cachefile.s)) {
++				my_error("unlink", 0, 1);
++				return -1;
++			}
++			return (0);
++		}
++		if ((fd = open(cachefile.s, O_RDONLY)) == -1)
++			my_error(cachefile.s, 0, 2);
++		substdio_fdbuf(&ss, read, fd, inbuf, sizeof(inbuf));
++		if (getln(&ss, &reason, &match, '\n') == -1) {
++			close(fd);
++			return -1;
++		}
++		*text = reason.s;
++		close(fd);
++		return (((st.st_mode & 07777) == 0600) ? 2 : 1);
++	}
++	return (0);
++}
++
++static int
++getdnsip(stralloc *ip, stralloc *domain, int *code)
++{
++	char            x[IPFMT];
++	ipalloc         ia = { 0 };
++	int             len;
++
++	if (!stralloc_copys(ip, ""))
++		die_nomem();
++	switch(dns_ip(&ia, domain))
++	{
++	case DNS_MEM:
++		die_nomem();
++	case DNS_SOFT:
++		die_soft();
++	case DNS_HARD:
++		return 0;
++	case 1:
++		if (ia.len <= 0)
++			die_soft();
++	}
++	if (code)
++		*code = *(&ia.ix->ip.d[3]);
++	len = ip_fmt(x, &ia.ix->ip);
++	if (!stralloc_copyb(ip, x, len))
++		die_nomem();
++	return 0;
++}
++
++/*- SURBL: Check surbl rcpt whitelist.  */
++int
++srwcheck(char *arg, int len)
++{
++	int             j;
++
++	if (!srwok)
++		return 0;
++	if (constmap(&mapsrw, arg, len))
++		return 1;
++	if ((j = byte_rchr(arg, len, '@')) < (len - 1)) {
++		if (constmap(&mapsrw, arg + j, len - j))
++			return 1;
++	}
++	return 0;
++}
++
++int
++l2check(char *arg, int len)
++{
++	if (!l2ok)
++		return (0);
++	if (constmap(&mapl2, arg, len))
++		return 1;
++	return (0);
++}
++
++int
++l3check(char *arg, int len)
++{
++	if (!l3ok)
++		return (0);
++	if (constmap(&mapl3, arg, len))
++		return 1;
++	return (0);
++}
++
++/*
++ * Returns -1 on error.
++ * Returns 0 if host does not exist.
++ * Returns 1 if host exists.
++ */
++static int
++checkwhitelist(char *hostname, int hostlen)
++{
++	int             len;
++	char           *ptr;
++
++	for (ptr = whitelist.s, len = 0;len < whitelist.len;) {
++		if (!str_diffn(hostname, ptr, hostlen))
++			return (1);
++		len += (str_len(ptr) + 1);
++		ptr = whitelist.s + len;
++	}
++	return (0);
++}
++
++static int
++getreason(int code, char **text)
++{
++	static stralloc reason = { 0 };
++
++	if (!stralloc_copyb(&reason, "blacklisted by ", 15))
++		die_nomem();
++	if (code & 64 && !stralloc_cats(&reason, debug ? "prolocation/jwspamspy" : "[jp]"))
++		die_nomem();
++	if (code & 32 && !stralloc_cats(&reason, debug ? "abusebutler " : "[ab]"))
++		die_nomem();
++	if (code & 16 && !stralloc_cats(&reason, debug ? "outblaze " : "[ob]"))
++		die_nomem();
++	if (code & 8 && !stralloc_cats(&reason, debug ? "phising " : "[ph]"))
++		die_nomem();
++	if (code & 2 && !stralloc_cats(&reason, debug ? "spamcop " : "[sc]"))
++		die_nomem();
++	if (code & 4 && !stralloc_cats(&reason, debug ? "w.stearns " : "[ws]"))
++		die_nomem();
++	if (!stralloc_0(&reason))
++		die_nomem();
++	*text = reason.s;
++	return (code >= 2);
++}
++
++static int
++checksurbl(char *uri, int urilen, char *surbldomain, char **text)
++{
++	static stralloc ip = { 0 };
++	static stralloc host = { 0 };
++	int             i, code = 0;
++
++	if ((i = checkwhitelist(uri, urilen)) == -1)
++		return -1;
++	else
++	if (i)
++		return (0);
++	if (stralloc_copys(&host, uri) == 0)
++		die_nomem();
++	if (stralloc_append(&host, ".") == 0)
++		die_nomem();
++	if (stralloc_cats(&host, surbldomain) == 0)
++		die_nomem();
++	if (!stralloc_0(&host))
++		die_nomem();
++	if (getdnsip(&ip, &host, &code) == -1)
++		return -1;
++	if (do_text && ip.len > 0) {
++		if (text) {
++			if ((*text = dns_text(host.s)))
++				return 2;
++		}
++		return 1;
++	}
++	if (code > 1)
++		return (getreason(code, text) ? 2 : 0);
++	return 0;
++}
++
++static int
++num_domains(const char *s)
++{
++	int             r = *s ? 1 : 0;
++
++	while (*s) {
++		if (*s++ == '.')
++			++r;
++	}
++	return r;
++}
++
++static char *
++remove_subdomains(char *orig, int output_domains)
++{
++	char           *s = orig + str_len((char *) orig);
++	int             dots = 0;
++
++	while (s > orig) {
++		if (*s == '.')
++			++dots;
++		if (dots == output_domains) {
++			++s;
++			break;
++		}
++		--s;
++	}
++	return s;
++}
++
++/*
++ * Returns 0 if URI was erronous.
++ *         1 if URI was not blacklisted.
++ *         2 if URI was blacklisted.
++ */
++static int
++checkuri(char **ouri, char **text, size_t textlen)
++{
++	char           *uri = *ouri, *uriend, *ptr;
++	char            ipuri[IPFMT];
++	size_t          urilen = 0;
++	ip_addr         ip;
++	int             cached, blacklisted, i, level;
++
++	if (case_diffb(uri, 4, "http"))
++		return 0;
++	uri += 4;
++
++	/*- Check and skip http[s]?:[/\\][/\\]?  */
++	if (*uri == 's')
++		uri++;
++	if (*uri == ':' && (uri[1] == '/' || uri[1] == '\\'))
++		uri += 2;
++	else 
++		return 0;
++	if (*uri == '/' || *uri == '\\')
++		uri++;
++	if (!isalpha(*uri) && !isdigit(*uri))
++		return 0;
++	uri_decode(uri, textlen, &uriend);
++	*ouri = uriend;
++	print_debug("Full    URI: ", uri, 0);
++	uri[(urilen = str_cspn(uri, "/\\?"))] = '\0';
++	if (uri[i = str_chr(uri, '@')])
++		uri += (i + 1);
++	uri[i = str_chr(uri, ':')] = 0;
++	if (ip_scan(uri, &ip)) {
++		ip_fmt(ipuri, &ip);
++		uri = ipuri;
++		print_debug("Proper IP: ", uri, 0);
++	} else {
++		urilen = str_len(uri);
++		print_debug("Full domain: ", uri, 0);
++		level = num_domains(uri);
++		if (level > 2) {
++			ptr = remove_subdomains(uri, 3);
++			if (l3check(ptr, str_len(ptr)))
++				uri = remove_subdomains(uri, 4);
++			else {
++				ptr = remove_subdomains(uri, 2);
++				if (l2check(ptr, str_len(ptr)))
++					uri = remove_subdomains(uri, 3);
++				else
++					uri = remove_subdomains(uri, 2);
++			}
++		} else
++		if (level > 1) {
++			ptr = remove_subdomains(uri, 2);
++			if (l2check(ptr, str_len(ptr)))
++				uri = remove_subdomains(uri, 3);
++			else
++				uri = remove_subdomains(uri, 2);
++		}
++		print_debug("       Part: ", uri, 0);
++	}
++	urilen = str_len(uri);
++	cached = 1;
++	blacklisted = 0;
++	switch (cachefunc(uri, urilen, text, 0))
++	{
++	case 0:
++		cached = 0;
++		break;
++	case 1:
++		blacklisted = 0;
++		break;
++	case 2:
++		blacklisted = 1;
++		break;
++	}
++	if (cached == 0) {
++		switch (checksurbl(uri, urilen, surbldomain.s, text))
++		{
++		case -1:
++			return -1;
++		case 0:
++			blacklisted = 0;
++			*text = (char *) 0;
++			print_debug(uri, ": not blacklisted", 0);
++			break;
++		case 1:
++			*text = "No reason given";
++			blacklisted = 1;
++			print_debug(uri, ": blacklisted. reason - ", *text);
++			break;
++		case 2:
++			blacklisted = 2;
++			print_debug(uri, ": blacklisted. reason - ", *text);
++			break;
++		}
++		cachefunc(uri, urilen, text, 1);
++	}
++	return (blacklisted);
++}
++
++#define DEF_SURBL_DOMAIN "multi.surbl.org"
++
++static int      do_surbl = 1;
++
++static void
++setup()
++{
++	char           *x, *y, *rcpt;
++	int             i;
++
++	if ((rcpt = env_get("QMAILRCPTS"))) {
++		if ((srwok = control_readfile(&srw, "control/surblrcpt", 0)) == -1)
++			die_control();
++		if (srwok && !constmap_init(&mapsrw, srw.s, srw.len, 0))
++			die_nomem();
++	}
++	for (x = y = rcpt, i = 0;rcpt && *x;x++, i++) {
++		if (*x == '\n') {
++			*x = 0;
++			if (srwcheck(y, i)) {
++				do_surbl = 0;
++				return;
++			}
++			y = x + 1;
++			*x = '\n';
++			i = 0;
++		}
++	}
++	if ((l2ok = control_readfile(&l2, "control/level2-tlds", 0)) == -1)
++		die_control();
++	if (l2ok && !constmap_init(&mapl2, l2.s, l2.len, 0))
++		die_nomem();
++	if ((l3ok = control_readfile(&l3, "control/level3-tlds", 0)) == -1)
++		die_control();
++	if (l3ok && !constmap_init(&mapl3, l3.s, l3.len, 0))
++		die_nomem();
++	switch (control_readline(&surbldomain, "control/surbldomain"))
++	{
++	case -1:
++		die_control();
++	case 0:
++		if (!stralloc_copys(&surbldomain, DEF_SURBL_DOMAIN))
++			die_nomem();
++		/*- flow through */
++	case 1:
++		if (!stralloc_0(&surbldomain))
++			die_nomem();
++	}
++	if ((x = env_get("CACHELIFETIME")))
++		scan_int(x, &cachelifetime);
++	else
++	if (control_readint(&cachelifetime, "control/cachelifetime") == -1)
++		die_control();
++	if (control_readfile(&whitelist, "control/surbldomainwhite", 0) == -1)
++		die_control();
++	return;
++}
++
++int
++main(int argc, char **argv)
++{
++	stralloc        base64out = { 0 }, boundary = { 0 };
++	stralloc       *ptr;
++	char           *x, *reason = 0;
++	int             opt, in_header = 1, i, total_bl = 0, blacklisted, match, html_plain_text,
++					base64_decode, found_content_type = 0;
++
++	if (!(x = env_get("SURBL")))
++		do_surbl = 0;
++	while ((opt = getopt(argc, argv, "vtc")) != opteof) {
++		switch (opt) {
++		case 'c':
++			do_cache = 0;
++			break;
++		case 'v':
++			debug = 1;
++			break;
++		case 't':
++			do_text = 1;
++			break;
++		}
++	}
++	if (chdir(auto_qmail) == -1)
++		die_control();
++	if (do_surbl)
++		setup();
++	for (html_plain_text = base64_decode = 0;;) {
++		if (getln(&ssin, &line, &match, '\n') == -1)
++			my_error("getln: ", 0, 1);
++		if (!match && line.len == 0)
++			break;
++		if (substdio_put(&ssout, line.s, line.len))
++			die_write();
++		if (!do_surbl)
++			continue;
++		if (in_header) {
++			if (!str_diffn(line.s, "Content-Type: ", 14)) {
++				found_content_type = 1;
++			}
++			if (found_content_type) {
++				for (i = 0;i < line.len; i++) {
++					if (case_startb(line.s + i, line.len - i, "boundary=")) {
++						if (line.s[i + 9] == '\"' && line.s[line.len -2] == '\"')
++						{
++							if (!stralloc_copyb(&boundary, line.s + i + 10, line.len -i - 12))
++								die_nomem();
++						} else
++						if (!stralloc_copyb(&boundary, line.s + i + 9, line.len - i - 10))
++							die_nomem();
++						if (!stralloc_0(&boundary))
++							die_nomem();
++						boundary.len--;
++					}
++				}
++			}
++			if (!mess822_ok(&line))
++				in_header = 0;
++		} else {
++			if (!str_diffn(line.s, "Content-Type: ", 14)) {
++				if (!str_diffn(line.s + 14, "message/rfc822", 14) ||
++					!str_diffn(line.s + 14, "text/html", 9) ||
++					!str_diffn(line.s + 14, "text/plain", 10))
++						html_plain_text = 1;
++				else
++						html_plain_text = 0;
++			}
++			if (html_plain_text && !str_diffn(line.s, "Content-Transfer-Encoding: ", 27)) {
++				if (!str_diffn(line.s + 27, "base64", 6))
++					base64_decode = 1;
++				else
++					base64_decode = 0;
++			}
++			if (line.len == 1)
++				continue;
++			if (base64_decode) {
++				if (!str_diffn(line.s, "Content-", 8))
++					continue;
++				if (!str_diffn(line.s + 2, boundary.s, boundary.len)) {
++					base64_decode = 0;
++					continue;
++				}
++				if (b64decode((const unsigned char *) line.s, line.len - 1, &base64out) == -1)
++					die_nomem();
++				ptr = &base64out;
++			} else
++				ptr = &line;
++			for (blacklisted = -1, i = 0;i < ptr->len; i++) {
++				if (case_startb(line.s + i, ptr->len - i, "http:")) {
++					x = ptr->s + i;
++					switch (checkuri(&x, &reason, ptr->len - i))
++					{
++					case -1:
++						my_error("checkuri", 0, 111);
++					case 0: /*- no valid uri in line */
++						blacklisted = 0;
++						break;
++					case 1:
++					case 2:
++						blacklisted = 1;
++						break;
++					}
++				}
++				if (blacklisted == 1) {
++					total_bl++;
++					break;
++				}
++			}
++		}
++	} /*- for (html_plain_text = base64_decode = 0;;) { */
++	if (substdio_flush(&ssout) == -1)
++		die_write();
++	if (do_surbl && total_bl) {
++		logerrf("Dmessage contains an URL listed in SURBL blocklist");
++		_exit (88); /*- custom error */
++	}
++	return (0);
++}
++
++void
++getversion_surblfilter_c()
++{
++	static char    *x = "$Id: surblfilter.c,v 1.4 2011-07-13 22:28:32+05:30 Cprogrammer Exp mbhangui $";
++
++	x++;
++}
+diff -ruN ../netqmail-1.06-original/surblqueue.sh netqmail-1.06/surblqueue.sh
+--- ../netqmail-1.06-original/surblqueue.sh	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/surblqueue.sh	2016-11-22 21:03:57.131527465 +0100
+@@ -0,0 +1,33 @@
++#!/bin/sh
++# I should be called by qmail-smtpd or anything that calls qmail-queue
++#
++if [ -f /bin/mktemp ] ; then
++	MKTEMP=/bin/mktemp
++elif [ -f /usr/bin/mktemp ] ; then
++	MKTEMP=/usr/bin/mktemp
++else
++	MKTEMP=mktemp
++fi
++out=`$MKTEMP -t surblXXXXXXXXXX`
++if [ $? -ne 0 ] ; then
++	echo "mktemp: unable to create temp files" 1>&2
++	exit 111
++fi
++#
++# Redirect standard error to 4 so that qmail_open() will pick up the error
++#
++QMAIL/bin/surblfilter > $out 2>&4
++status=$?
++if [ $status -eq 0 ] ; then
++	exec 0<$out
++	/bin/rm -f $out
++	# use SURBLQUEUE to execute queue program (thanks Roberto Puzzanghera)
++       if [ "$SURBLQUEUE" != "" -a -x "$SURBLQUEUE" ]; then
++		exec $SURBLQUEUE
++	else
++		exec QMAIL/bin/qmail-queue
++	fi
++else
++	/bin/rm -f $out
++	exit $status
++fi
+diff -ruN ../netqmail-1.06-original/tai.h netqmail-1.06/tai.h
+--- ../netqmail-1.06-original/tai.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/tai.h	2016-11-22 21:03:57.131527465 +0100
+@@ -0,0 +1,34 @@
++/*
++ * $Log: tai.h,v $
++ * Revision 1.3  2004-10-11 14:15:10+05:30  Cprogrammer
++ * added function prototypes
++ *
++ * Revision 1.2  2004-09-19 22:49:23+05:30  Cprogrammer
++ * added tai_unix macro
++ *
++ * Revision 1.1  2004-06-16 01:20:25+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#ifndef TAI_H
++#define TAI_H
++
++#include "uint64.h"
++
++struct tai
++{
++	uint64          x;
++};
++
++#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u)))
++#define tai_approx(t) ((double) ((t)->x))
++#define tai_less(t,u) ((t)->x < (u)->x)
++#define TAI_PACK 8
++
++void            tai_now(struct tai *);
++void            tai_add();
++void            tai_sub(struct tai *, struct tai *, struct tai *);
++void            tai_pack(char *, struct tai *);
++void            tai_unpack(char *, struct tai *);
++
++#endif
+diff -ruN ../netqmail-1.06-original/tcp-env.c netqmail-1.06/tcp-env.c
+--- ../netqmail-1.06-original/tcp-env.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/tcp-env.c	2016-11-22 21:03:57.131527465 +0100
+@@ -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"
+@@ -34,6 +35,7 @@
+ int argc;
+ char *argv[];
+ {
++ strsalloc ssa = {0};
+  int dummy;
+  char *proto;
+  int opt;
+@@ -74,12 +76,13 @@
+    temp[ip_fmt(temp,&iplocal)] = 0;
+    if (!env_put2("TCPLOCALIP",temp)) die();
+ 
+-   switch(dns_ptr(&localname,&iplocal))
++   switch(dns_ptr(&ssa,&iplocal))
+     {
+      case DNS_MEM: die();
+      case DNS_SOFT:
+        if (!stralloc_copys(&localname,"softdnserror")) die();
+      case 0:
++       if (!stralloc_copy(&localname,&ssa.sa[0])) die();
+        if (!stralloc_0(&localname)) die();
+        case_lowers(localname.s);
+        if (!env_put2("TCPLOCALHOST",localname.s)) die();
+@@ -99,12 +102,13 @@
+    temp[ip_fmt(temp,&ipremote)] = 0;
+    if (!env_put2("TCPREMOTEIP",temp)) die();
+ 
+-   switch(dns_ptr(&remotename,&ipremote))
++   switch(dns_ptr(&ssa,&ipremote))
+     {
+      case DNS_MEM: die();
+      case DNS_SOFT:
+        if (!stralloc_copys(&remotename,"softdnserror")) die();
+      case 0:
++       if (!stralloc_copy(&remotename,&ssa.sa[0])) die();
+        if (!stralloc_0(&remotename)) die();
+        case_lowers(remotename.s);
+        if (!env_put2("TCPREMOTEHOST",remotename.s)) die();
+diff -ruN ../netqmail-1.06-original/timeoutconn.c netqmail-1.06/timeoutconn.c
+--- ../netqmail-1.06-original/timeoutconn.c	1998-06-15 12:53:16.000000000 +0200
++++ netqmail-1.06/timeoutconn.c	2016-11-22 21:03:57.131527465 +0100
+@@ -10,9 +10,10 @@
+ #include "byte.h"
+ #include "timeoutconn.h"
+ 
+-int timeoutconn(s,ip,port,timeout)
++int timeoutconn(s,ip,outip,port,timeout)
+ int s;
+ struct ip_address *ip;
++struct ip_address *outip;
+ unsigned int port;
+ int timeout;
+ {
+@@ -22,6 +23,13 @@
+   fd_set wfds;
+   struct timeval tv;
+  
++  /* bind() an outgoing ipaddr */
++  byte_zero(&sin,sizeof(sin));
++  byte_copy(&sin.sin_addr.s_addr,4,outip);
++  sin.sin_family = AF_INET;
++
++  if (-1 == bind(s,(struct sockaddr *) &sin,sizeof(sin))) return -1;
++
+   byte_zero(&sin,sizeof(sin));
+   byte_copy(&sin.sin_addr,4,ip);
+   x = (char *) &sin.sin_port;
+diff -ruN ../netqmail-1.06-original/tls.c netqmail-1.06/tls.c
+--- ../netqmail-1.06-original/tls.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/tls.c	2016-11-22 21:03:57.131527465 +0100
+@@ -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 -ruN ../netqmail-1.06-original/tls.h netqmail-1.06/tls.h
+--- ../netqmail-1.06-original/tls.h	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/tls.h	2016-11-22 21:03:57.132527432 +0100
+@@ -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 -ruN ../netqmail-1.06-original/tryulong64.c netqmail-1.06/tryulong64.c
+--- ../netqmail-1.06-original/tryulong64.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/tryulong64.c	2016-11-22 21:03:57.132527432 +0100
+@@ -0,0 +1,47 @@
++/*
++ * $Log: tryulong64.c,v $
++ * Revision 1.1  2004-05-14 00:45:23+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++void
++main()
++{
++	unsigned long   u;
++	u = 1;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	u += u;
++	if (!u)
++		_exit(1);
++	_exit(0);
++}
+diff -ruN ../netqmail-1.06-original/uint64.h1 netqmail-1.06/uint64.h1
+--- ../netqmail-1.06-original/uint64.h1	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/uint64.h1	2016-11-22 21:03:57.132527432 +0100
+@@ -0,0 +1,12 @@
++/*
++ * $Log: uint64.h1,v $
++ * Revision 1.1  2004-10-22 15:00:08+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#ifndef UINT64_H
++#define UINT64_H
++
++typedef unsigned long uint64;
++
++#endif
+diff -ruN ../netqmail-1.06-original/uint64.h2 netqmail-1.06/uint64.h2
+--- ../netqmail-1.06-original/uint64.h2	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/uint64.h2	2016-11-22 21:03:57.132527432 +0100
+@@ -0,0 +1,12 @@
++/*
++ * $Log: uint64.h2,v $
++ * Revision 1.1  2004-10-22 15:00:36+05:30  Cprogrammer
++ * Initial revision
++ *
++ */
++#ifndef UINT64_H
++#define UINT64_H
++
++typedef unsigned long long uint64;
++
++#endif
+diff -ruN ../netqmail-1.06-original/update_tmprsadh.sh netqmail-1.06/update_tmprsadh.sh
+--- ../netqmail-1.06-original/update_tmprsadh.sh	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/update_tmprsadh.sh	2016-11-22 21:03:57.132527432 +0100
+@@ -0,0 +1,22 @@
++#!/bin/sh
++
++# Update temporary RSA and DH keys
++# Frederik Vermeulen 2004-05-31 GPL
++#
++# Slightly modified by Roberto Puzzanghera
++# to chown the .pem files to vpopmail
++
++umask 0077 || exit 0
++
++export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin"
++
++openssl genrsa -out QMAIL/control/rsa2048.new 2048 &&
++chmod 600 QMAIL/control/rsa2048.new &&
++chown vpopmail:vchkpw QMAIL/control/rsa2048.new &&
++mv -f QMAIL/control/rsa2048.new QMAIL/control/rsa2048.pem
++
++openssl dhparam -2 -out QMAIL/control/dh2048.new 2048 &&
++chmod 600 QMAIL/control/dh2048.new &&
++chown vpopmail:vchkpw QMAIL/control/dh2048.new &&
++mv -f QMAIL/control/dh2048.new QMAIL/control/dh2048.pem
++
+diff -ruN ../netqmail-1.06-original/wildmat.c netqmail-1.06/wildmat.c
+--- ../netqmail-1.06-original/wildmat.c	1970-01-01 01:00:00.000000000 +0100
++++ netqmail-1.06/wildmat.c	2016-11-22 21:03:57.132527432 +0100
+@@ -0,0 +1,173 @@
++/*-** wildmat.c.orig	Wed Dec  3 11:46:31 1997
++ * $Revision: 1.6 $
++ * Do shell-style pattern matching for ?, \, [], and * characters.
++ * Might not be robust in face of malformed patterns; e.g., "foo[a-"
++ * could cause a segmentation violation.  It is 8bit clean.
++ * 
++ * Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
++ * Rich $alz is now <rsalz@osf.org>.
++ * April, 1991:  Replaced mutually-recursive calls with in-line code
++ * for the star character.
++ *
++ * Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
++ * This can greatly speed up failing wildcard patterns.  For example:
++ * pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
++ * text 1:  -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
++ * text 2:  -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
++ * Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
++ * the ABORT code, it takes 22310 calls to fail.  Ugh.  The following
++ * explanation is from Lars:
++ * The precondition that must be fulfilled is that DoMatch will consume
++ * at least one character in text.  This is true if *p is neither '*' no
++ * '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
++ * behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
++ * FALSE, each star-loop has to run to the end of the text; with ABORT
++ * only the last one does.
++ * 
++ * Once the control of one instance of DoMatch enters the star-loop, that
++ * instance will return either TRUE or ABORT, and any calling instance
++ * will therefore return immediately after (without calling recursively
++ * again).  In effect, only one star-loop is ever active.  It would be
++ * possible to modify the code to maintain this context explicitly,
++ * eliminating all recursive calls at the cost of some complication and
++ * loss of clarity (and the ABORT stuff seems to be unclear enough by
++ * itself).  I think it would be unwise to try to get this into a
++ * released version unless you have a good test data base to try it out
++ * on.
++ */
++#define TRUE			 1
++#define FALSE			 0
++#define ABORT			-1
++
++
++/*- What character marks an inverted character class?  */
++#define NEGATE_CLASS		'^'
++/*- Is "*" a common pattern?  */
++#define OPTIMIZE_JUST_STAR
++/*- Do tar(1) matching rules, which ignore a trailing slash?  */
++#undef MATCH_TAR_PATTERN
++
++
++/*- Match text and p, return TRUE, FALSE, or ABORT.  */
++static int
++DoMatch(text, p)
++	register char  *text;
++	register char  *p;
++{
++	register int    last;
++	register int    matched;
++	register int    reverse;
++
++	for (; *p; text++, p++)
++	{
++		if (*text == '\0' && *p != '*')
++			return ABORT;
++		switch (*p)
++		{
++		case '\\': /*- Literal match with following character.  */
++			p++;
++			/*- FALLTHROUGH */
++		default:
++			if (*text != *p)
++				return FALSE;
++			continue;
++		case '?': /*- Match anything. */
++			continue;
++		case '*':
++			/*- Consecutive stars act just like one.  */
++			while (*++p == '*')
++				continue;
++			/*- Trailing star matches everything.  */
++			if (*p == '\0')
++				return TRUE;
++			while (*text)
++				if ((matched = DoMatch(text++, p)) != FALSE)
++					return matched;
++			return ABORT;
++		case '[':
++			reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
++			/*- Inverted character class.  */
++			if (reverse)
++				p++;
++			matched = FALSE;
++			if (p[1] == ']' || p[1] == '-')
++			{
++				if (*++p == *text)
++					matched = TRUE;
++			}
++			for (last = *p; *++p && *p != ']'; last = *p)
++			{
++				/*- This next line requires a good C compiler.  */
++				if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
++					matched = TRUE;
++			}
++			if (matched == reverse)
++				return FALSE;
++			continue;
++		}
++	}
++
++#ifdef	MATCH_TAR_PATTERN
++	if (*text == '/')
++		return TRUE;
++#endif /*- MATCH_TAR_ATTERN */
++	return *text == '\0';
++}
++
++
++/*- User-level routine.  Returns TRUE or FALSE.  */
++int
++wildmat_internal(text, p)
++	char           *text;
++	char           *p;
++{
++#ifdef	OPTIMIZE_JUST_STAR
++	if (p[0] == '*' && p[1] == '\0')
++		return TRUE;
++#endif /*- OPTIMIZE_JUST_STAR */
++	return DoMatch(text, p) == TRUE;
++}
++
++#if	defined(TEST)
++include < stdio.h >
++/*- Yes, we use gets not fgets.  Sue me.  */
++
++int
++main()
++{
++	char            p[80];
++	char            text[80];
++
++	printf("Wildmat tester.  Enter pattern, then strings to test.\n");
++	printf("A blank line gets prompts for a new pattern; a blank pattern\n");
++	printf("exits the program.\n");
++	for (;;)
++	{
++		printf("\nEnter pattern:  ");
++		(void) fflush(stdout);
++		if (gets(p) == NULL || p[0] == '\0')
++			break;
++		for (;;)
++		{
++			printf("Enter text:  ");
++			(void) fflush(stdout);
++			if (gets(text) == NULL)
++				exit(0);
++			/*- Blank line; go back and get a new pattern.  */
++			if (text[0] == '\0')
++				break;
++			printf("      %s\n", wildmat_internal(text, p) ? "YES" : "NO");
++		}
++	}
++	exit(0);
++	/*- NOTREACHED */
++}
++#endif /*- defined(TEST) */
++
++void
++getversion_wildmat_internal_c()
++{
++	static char    *x = "$Id: wildmat.c,v 1.6 2008-08-03 18:26:33+05:30 Cprogrammer Stab mbhangui $";
++	x++;
++	x--;
++}
Index: l/mailserver/netqmail/syn3-dagent
===================================================================
--- npl/mailserver/netqmail/syn3-dagent	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ 	(revision )
@@ -1,71 +1,0 @@
-#!/bin/bash
-
-USER="$1"
-SENDER="$2"
-INMAIL=/tmp/syn3-dagent.$$
-SCANMAIL=/tmp/syn3-dagent-scanned.$$
-
-
-#cleanup and exit
-end()
-{
-	rm $INMAIL 2>/dev/null
-	rm $SCANMAIL 2>/dev/null
-	exit $1
-}
-
-# some kind of ldap problem, try again later
-id "Administrator" >/dev/null || end 111
-
-#does the user exists?
-if ! id "$USER" >/dev/null; then
-	#we're sure theres no ldap problem?
-	id "Administrator" >/dev/null || end 111
-	#probably a bounce spammer, drop mail silently
-	echo "User does not exist, dropping mail."
-	end 0
-fi
-
-#store mail temporary
-cat > $INMAIL || end 1
-
-#pipe trough personal spamfilter of this user
-if ! grep "VIRUS.*IN MAIL TO YOU" $INMAIL >/dev/null && /usr/bin/dspamc --user "$USER" --deliver=innocent,spam --mail-from="$SENDER" --stdout >$SCANMAIL <$INMAIL; then
-	#it worked
-	if grep "^X-DSPAM-Result: Spam" $SCANMAIL >/dev/null; then
-		SPAM=1
-	else
-		SPAM=
-	fi
-	MAIL=$SCANMAIL
-else
-	#spam filter is broken, or it was just a virus notification
-	MAIL=$INMAIL
-	SPAM=
-fi
-
-#check cyrus is up, and deliver it there:
-if /usr/bin/pgrep -f -x /usr/cyrus/bin/master ; then
-	if [ "$SPAM" ]; then
-		/usr/cyrus/bin/deliver -a "$USER" -m Spam "$USER" < $MAIL
-		end $?
-	else
-		/usr/cyrus/bin/deliver -a "$USER" "$USER" < $MAIL
-		end $?
-	fi
-fi
-
-#check zarafa is up, and deliver it there:
-if pidof zarafa-server >/dev/null; then
-	if [ "$SPAM" ]; then
-		/usr/bin/zarafa-dagent "$USER" -q -j < $MAIL
-		end $?
-	else
-		/usr/bin/zarafa-dagent "$USER" -q < $MAIL
-		end $?
-	fi
-fi
-
-#no backend mailstorage up, so fail temporary
-echo "All mailbackends are down, retry again later..."
-end 111
Index: npl/mailserver/netqmail_conf/netqmail_conf.SlackBuild
===================================================================
--- npl/mailserver/netqmail_conf/netqmail_conf.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/netqmail_conf.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+#######Essential package info.
+#Change these if autodetection fails.
+
+#Name of the Syn-3 package that we are going to create
+NAME=`basename $0|sed 's/.SlackBuild//'`
+
+VER=7.1
+
+ARCH=noarch
+
+
+mkdir /tmp/pkg
+cp -r root/* /tmp/pkg || exit 1
+find /tmp/pkg -name .svn -exec rm -r "{}" \; 
+
+
+#make main package
+syn3_makepkg /tmp/pkg $NAME $VER $ARCH || exit 1
+
+
Index: npl/mailserver/netqmail_conf/netqmail_conf.arch
===================================================================
--- npl/mailserver/netqmail_conf/netqmail_conf.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/netqmail_conf.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+noarch
Index: npl/mailserver/netqmail_conf/netqmail_conf.build
===================================================================
--- npl/mailserver/netqmail_conf/netqmail_conf.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/netqmail_conf.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+46
Index: npl/mailserver/netqmail_conf/netqmail_conf.md5
===================================================================
--- npl/mailserver/netqmail_conf/netqmail_conf.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/netqmail_conf.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,32 @@
+2d22069ace446e9f5cbf6890d9cbbb4d  ./netqmail_conf.pkg
+f4f9e3673e49bd56810ee75e666f51a0  ./netqmail_conf.SlackBuild
+5373229d903d2c91059d1b6f4bbc690f  ./netqmail_conf.SlackBuild.log.gz
+47946b00d0dd8e0d1c6c87867496bf85  ./root/etc/postinst.d/post.qmail_conf
+efed79f2f7840be05415132dd99e005a  ./root/etc/qmail.permissions
+a781066c2d8b2e42e4eae0cd0545391b  ./root/etc/qmail.rc.config
+08a3c19c4116da0ec38365484fa1f988  ./root/home/system/firewall/services.qmailsubmission.new
+fa8a0fae93de6a2013dc46a1f6bc81a2  ./root/home/system/qmail/alias/.qmail-default
+1dcca23355272056f04fe8bf20edfce0  ./root/home/system/qmail/control/concurrencyincoming.new
+d41d8cd98f00b204e9800998ecf8427e  ./root/home/system/qmail/control/defaultdomain.new
+919d117956d3135c4c683ff021352f5c  ./root/home/system/qmail/control/maxrcpt.new
+2909a2c64757ce93daa60e3cfc653ef1  ./root/home/system/qmail/control/qmqpservers.new
+d41d8cd98f00b204e9800998ecf8427e  ./root/home/system/qmail/control/rcpthosts.new
+063221b732091cd47898d4f4de0d3a86  ./root/home/system/qmail/control/relaylimits.new
+7f06a0bdfe40105eb7150c89ca23fe0a  ./root/home/system/qmail/control/softlimit.new
+6d7fce9fee471194aa8b5b6e47267f03  ./root/home/system/qmail/control/spfbehavior.new
+d41d8cd98f00b204e9800998ecf8427e  ./root/home/system/qmail/control/virtualdomains.new
+d41d8cd98f00b204e9800998ecf8427e  ./root/home/system/qmail/queue/lock/sendmutex
+0f343b0931126a20f133d67c2b018a3b  ./root/home/system/qmail/queue/lock/tcpto
+5e6055ce99316030e416d8f7243e99cd  ./root/home/system/qmail/tcp.smtp.new
+0361f8191be2fc0c7a64208973181e81  ./root/home/system/qmail/tcp.submission.new
+c373bf047e4be7894e0eb539ecade81e  ./root/home/system/qmail/users/assign.new
+a85ddde2346842cfb84c449322334cf6  ./root/usr/bin/syn3-dagent
+997aa1db669e5946bc88187056e5983e  ./root/var/qmail/bin/qmailctl
+d219929668d14245324a90cc8889a953  ./root/var/qmail/bin/rcptcheck-overlimit.sh
+b6d113884ec042aa912297837d7e1711  ./root/var/qmail/rc
+d2264d4a1eb480b446148386491d6d96  ./root/var/qmail/supervise/qmail-send/log/run
+ce8344b9f086b8d80deedd97999af4a2  ./root/var/qmail/supervise/qmail-send/run
+664eb748dcf70763bbb8af153a60f4fc  ./root/var/qmail/supervise/qmail-smtpd/log/run
+d1b75635cf714be5a03ae4b559eabff7  ./root/var/qmail/supervise/qmail-smtpd/run
+0c00964a4500bb13bcba905b59954802  ./root/var/qmail/supervise/qmail-submission/log/run
+00df93e4a56a546880039677deb50a30  ./root/var/qmail/supervise/qmail-submission/run
Index: npl/mailserver/netqmail_conf/netqmail_conf.version
===================================================================
--- npl/mailserver/netqmail_conf/netqmail_conf.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/netqmail_conf.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+7.1
Index: npl/mailserver/netqmail_conf/root/etc/postinst.d/post.qmail_conf
===================================================================
--- npl/mailserver/netqmail_conf/root/etc/postinst.d/post.qmail_conf	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/etc/postinst.d/post.qmail_conf	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+
+### http://notes.sagredo.eu/en/qmail-notes-185/configuring-qmail-83.html
+
+# create groups and users
+. /etc/qmail.rc.config
+qmail_user() {
+  for I in _0 _1 _2 _3 _4 _5 _6; do
+    eval CUR_USER=\$QMAIL_USER$I
+    USER=`echo "$CUR_USER" | cut -d ':' -f 1`
+    grep "$USER" /etc/passwd > /dev/null && userdel $USER
+  done
+  for I in _0 _1; do
+    eval CUR_GROUP=\$QMAIL_GROUP$I
+    GROUP=`echo "$CUR_GROUP" | cut -d ':' -f 1`
+    grep "$GROUP" /etc/group > /dev/null && groupdel $GROUP
+  done
+  for I in _0 _1; do
+    eval CUR_GROUP=\$QMAIL_GROUP$I
+    GROUP=`echo "$CUR_GROUP" | cut -d ':' -f 1`
+    CGID=`echo "$CUR_GROUP" | cut -d ':' -f 2`
+    groupadd -g $CGID $GROUP
+  done
+  for I in _0 _1 _2 _3 _4 _5 _6; do
+    eval CUR_USER=\$QMAIL_USER$I
+    USER=`echo "$CUR_USER" | cut -d ':' -f 1`
+    CUID=`echo "$CUR_USER" | cut -d ':' -f 2`
+    GROUP=`echo "$CUR_USER" | cut -d ':' -f 3`
+    HOME=`echo "$CUR_USER" | cut -d ':' -f 4`
+    useradd -u $CUID -g $GROUP -d $HOME -s /bin/false $USER
+  done
+}
+svcstop /service/nscd #this script doesnt like caching
+qmail_user
+svcreset /service/nscd
+
+
+# logging via syslog in /var/log/maillog from now on
+rm -rf /var/log/qmail/
+
+
+# permissions
+. /etc/qmail.permissions
+qmail_permissions
+
+
+#stuff
+svc -d /service/qmail-*
+svcstop /service/nscd/
+svcreset /service/nscd/
+touch /var/qmail/control/smtpplugins
+svc -dx /service/qmail-*
+
+#update old config?
+if ! grep "127.0.0.3" /etc/qmail/tcp.smtp; then
+    mv /etc/qmail/tcp.smtp.new /etc/qmail/tcp.smtp
+fi
+
+
+#regenerate cdb
+tcprules /etc/qmail/tcp.smtp.cdb /etc/qmail/tcp.smtp.tmp < /etc/qmail/tcp.smtp
+tcprules /etc/qmail/tcp.submission.cdb /etc/qmail/tcp.submission.tmp < /etc/qmail/tcp.submission
+
+
+#TLS configuration
+if ! [ -e /var/qmail/control/dh1024.pem ]; then
+    openssl dhparam -out /var/qmail/control/dh1024.pem.tmp 1024 || exit 1
+    chown qmaild /var/qmail/control/dh1024.pem.tmp || exit 1
+    chmod 400 /var/qmail/control/dh1024.pem.tmp || exit 1
+    mv /var/qmail/control/dh1024.pem.tmp /var/qmail/control/dh1024.pem || exit 1
+fi
+
+#certificate
+if ! [ -e  /var/qmail/control/servercert.pem ]; then
+    if cat /usr/webint/ssl/server.crt /usr/webint/ssl/server.pem  > /var/qmail/control/servercert.pem.tmp; then
+        mv  /var/qmail/control/servercert.pem.tmp  /var/qmail/control/servercert.pem
+    fi
+fi
+
+
+
+
+#enable scripts (x is disble to prevent starting up after first installation of binary)
+chmod +x /service/qmail-smtpd/run /service/qmail-send/run /service/qmail-send/log/run /service/qmail-smtpd/log/run /service/qmail-submission/run /service/qmail-submission/log/run
Index: npl/mailserver/netqmail_conf/root/etc/qmail
===================================================================
--- npl/mailserver/netqmail_conf/root/etc/qmail	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/etc/qmail	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/home/system/qmail
Index: npl/mailserver/netqmail_conf/root/etc/qmail.permissions
===================================================================
--- npl/mailserver/netqmail_conf/root/etc/qmail.permissions	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/etc/qmail.permissions	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,192 @@
+# qmail permissions - generated by Guilherme Balena Versiani
+# used GNU stat 5.0 by Michael Meskes
+
+qmail_permissions() {
+  chown root.qmail /var/qmail; chmod 755 /var/qmail
+  chown root.root /var/qmail/rc; chmod 700 /var/qmail/rc
+  chown root.qmail /var/qmail/bin; chmod 755 /var/qmail/bin
+  chown root.qmail /var/qmail/bin/elq; chmod 755 /var/qmail/bin/elq
+  chown root.qmail /var/qmail/bin/pinq; chmod 755 /var/qmail/bin/pinq
+  chown root.qmail /var/qmail/bin/qail; chmod 755 /var/qmail/bin/qail
+  chown root.root /var/qmail/bin/checkpassword; chmod 700 /var/qmail/bin/checkpassword
+  chown root.qmail /var/qmail/bin/qmail-showctl; chmod 755 /var/qmail/bin/qmail-showctl
+  chown root.root /var/qmail/bin/printforward; chmod 755 /var/qmail/bin/printforward
+  chown root.qmail /var/qmail/bin/datemail; chmod 755 /var/qmail/bin/datemail
+  chown root.qmail /var/qmail/bin/condredirect; chmod 755 /var/qmail/bin/condredirect
+  chown root.qmail /var/qmail/bin/qsmhook; chmod 755 /var/qmail/bin/qsmhook
+  chown root.root /var/qmail/bin/dot-forward; chmod 755 /var/qmail/bin/dot-forward
+  chown root.qmail /var/qmail/bin/qbiff; chmod 755 /var/qmail/bin/qbiff
+  chown root.qmail /var/qmail/bin/qreceipt; chmod 755 /var/qmail/bin/qreceipt
+  chown root.qmail /var/qmail/bin/splogger; chmod 711 /var/qmail/bin/splogger
+  chown root.root /var/qmail/bin/newaliases; chmod 755 /var/qmail/bin/newaliases
+  chown root.root /var/qmail/bin/qmail-smtpd-conf; chmod 755 /var/qmail/bin/qmail-smtpd-conf
+  chown root.qmail /var/qmail/bin/mailsubj; chmod 755 /var/qmail/bin/mailsubj
+  chown root.qmail /var/qmail/bin/tcp-env; chmod 755 /var/qmail/bin/tcp-env
+  chown root.root /var/qmail/bin/qmail-delivery-conf; chmod 755 /var/qmail/bin/qmail-delivery-conf
+  chown root.root /var/qmail/bin/setmaillist; chmod 755 /var/qmail/bin/setmaillist
+  chown root.root /var/qmail/bin/qmail-pop3d-conf; chmod 755 /var/qmail/bin/qmail-pop3d-conf
+  chown root.qmail /var/qmail/bin/qmail-clean; chmod 711 /var/qmail/bin/qmail-clean
+  chown root.qmail /var/qmail/bin/qmail-getpw; chmod 711 /var/qmail/bin/qmail-getpw
+  chown root.qmail /var/qmail/bin/qmail-local; chmod 711 /var/qmail/bin/qmail-local
+  chown root.qmail /var/qmail/bin/qmail-pop3d; chmod 755 /var/qmail/bin/qmail-pop3d
+  chown root.qmail /var/qmail/bin/qmail-popup; chmod 711 /var/qmail/bin/qmail-popup
+  chown root.qmail /var/qmail/bin/qmail-qmqpc; chmod 755 /var/qmail/bin/qmail-qmqpc
+  chown root.qmail /var/qmail/bin/qmail-qmqpd; chmod 755 /var/qmail/bin/qmail-qmqpd
+  chown root.qmail /var/qmail/bin/qmail-qmtpd; chmod 755 /var/qmail/bin/qmail-qmtpd
+  chown root.qmail /var/qmail/bin/qmail-qread; chmod 755 /var/qmail/bin/qmail-qread
+  chown root.qmail /var/qmail/bin/qmail-qstat; chmod 755 /var/qmail/bin/qmail-qstat
+  chown qmailq.qmail /var/qmail/bin/qmail-queue; chmod 4711 /var/qmail/bin/qmail-queue
+  chown root.qmail /var/qmail/bin/qmail-smtpd; chmod 755 /var/qmail/bin/qmail-smtpd
+  chown root.qmail /var/qmail/bin/qmail-tcpok; chmod 755 /var/qmail/bin/qmail-tcpok
+  chown root.qmail /var/qmail/bin/qmail-tcpto; chmod 755 /var/qmail/bin/qmail-tcpto
+  chown root.qmail /var/qmail/bin/qmail-start; chmod 700 /var/qmail/bin/qmail-start
+  chown root.root /var/qmail/bin/newinclude; chmod 755 /var/qmail/bin/newinclude
+  chown root.root /var/qmail/bin/fastforward; chmod 755 /var/qmail/bin/fastforward
+  chown root.root /var/qmail/bin/config; chmod 755 /var/qmail/bin/config
+  chown root.qmail /var/qmail/bin/maildir2mbox; chmod 755 /var/qmail/bin/maildir2mbox
+  chown root.qmail /var/qmail/bin/forward; chmod 755 /var/qmail/bin/forward
+  chown root.root /var/qmail/bin/qmail-lint; chmod 755 /var/qmail/bin/qmail-lint
+  chown root.qmail /var/qmail/bin/qmail-newu; chmod 700 /var/qmail/bin/qmail-newu
+  chown root.qmail /var/qmail/bin/qmail-pw2u; chmod 711 /var/qmail/bin/qmail-pw2u
+  chown root.qmail /var/qmail/bin/qmail-send; chmod 711 /var/qmail/bin/qmail-send
+  chown root.qmail /var/qmail/bin/except; chmod 755 /var/qmail/bin/except
+  chown root.qmail /var/qmail/bin/qmail-inject; chmod 755 /var/qmail/bin/qmail-inject
+  chown root.qmail /var/qmail/bin/maildirwatch; chmod 755 /var/qmail/bin/maildirwatch
+  chown root.qmail /var/qmail/bin/qmail-lspawn; chmod 700 /var/qmail/bin/qmail-lspawn
+  chown root.qmail /var/qmail/bin/qmail-newmrh; chmod 700 /var/qmail/bin/qmail-newmrh
+  chown root.root /var/qmail/bin/config-fast; chmod 755 /var/qmail/bin/config-fast
+  chown root.root /var/qmail/bin/setforward; chmod 755 /var/qmail/bin/setforward
+  chown root.root /var/qmail/bin/printmaillist; chmod 755 /var/qmail/bin/printmaillist
+  chown root.qmail /var/qmail/bin/maildirmake; chmod 755 /var/qmail/bin/maildirmake
+  chown root.qmail /var/qmail/bin/qmail-remote; chmod 711 /var/qmail/bin/qmail-remote
+  chown root.qmail /var/qmail/bin/qmail-rspawn; chmod 711 /var/qmail/bin/qmail-rspawn
+  chown root.qmail /var/qmail/bin/bouncesaying; chmod 755 /var/qmail/bin/bouncesaying
+  chown root.qmail /var/qmail/bin/sendmail; chmod 755 /var/qmail/bin/sendmail
+  chown root.root /var/qmail/bin/qmail-qmtpd-conf; chmod 755 /var/qmail/bin/qmail-qmtpd-conf
+  chown root.qmail /var/qmail/bin/predate; chmod 755 /var/qmail/bin/predate
+  chown root.qmail /var/qmail/bin/preline; chmod 755 /var/qmail/bin/preline
+  chown root.root /var/qmail/bin/qmail-qmqpd-conf; chmod 755 /var/qmail/bin/qmail-qmqpd-conf
+  chown root.qmail /var/qmail/boot; chmod 755 /var/qmail/boot
+  chown root.qmail /var/qmail/boot/binm1+df; chmod 755 /var/qmail/boot/binm1+df
+  chown root.qmail /var/qmail/boot/binm2+df; chmod 755 /var/qmail/boot/binm2+df
+  chown root.qmail /var/qmail/boot/binm3+df; chmod 755 /var/qmail/boot/binm3+df
+  chown root.qmail /var/qmail/boot/home; chmod 755 /var/qmail/boot/home
+  chown root.qmail /var/qmail/boot/proc; chmod 755 /var/qmail/boot/proc
+  chown root.qmail /var/qmail/boot/binm1; chmod 755 /var/qmail/boot/binm1
+  chown root.qmail /var/qmail/boot/binm2; chmod 755 /var/qmail/boot/binm2
+  chown root.qmail /var/qmail/boot/binm3; chmod 755 /var/qmail/boot/binm3
+  chown root.qmail /var/qmail/boot/home+df; chmod 755 /var/qmail/boot/home+df
+  chown root.qmail /var/qmail/boot/proc+df; chmod 755 /var/qmail/boot/proc+df
+  chown root.qmail /home/system/qmail/control; chmod 755 /home/system/qmail/control
+  chown alias.qmail /home/system/qmail/alias; chmod 2755 /home/system/qmail/alias
+  chown qmailq.qmail /home/system/qmail/queue; chmod 750 /home/system/qmail/queue
+  chown qmailq.qmail /home/system/qmail/queue/pid; chmod 700 /home/system/qmail/queue/pid
+  chown qmails.qmail /home/system/qmail/queue/info; chmod 700 /home/system/qmail/queue/info
+  chown qmails.qmail /home/system/qmail/queue/info/0; chmod 700 /home/system/qmail/queue/info/0
+  chown qmails.qmail /home/system/qmail/queue/info/1; chmod 700 /home/system/qmail/queue/info/1
+  chown qmails.qmail /home/system/qmail/queue/info/2; chmod 700 /home/system/qmail/queue/info/2
+  chown qmails.qmail /home/system/qmail/queue/info/3; chmod 700 /home/system/qmail/queue/info/3
+  chown qmails.qmail /home/system/qmail/queue/info/4; chmod 700 /home/system/qmail/queue/info/4
+  chown qmails.qmail /home/system/qmail/queue/info/5; chmod 700 /home/system/qmail/queue/info/5
+  chown qmails.qmail /home/system/qmail/queue/info/6; chmod 700 /home/system/qmail/queue/info/6
+  chown qmails.qmail /home/system/qmail/queue/info/7; chmod 700 /home/system/qmail/queue/info/7
+  chown qmails.qmail /home/system/qmail/queue/info/8; chmod 700 /home/system/qmail/queue/info/8
+  chown qmails.qmail /home/system/qmail/queue/info/9; chmod 700 /home/system/qmail/queue/info/9
+  chown qmails.qmail /home/system/qmail/queue/info/10; chmod 700 /home/system/qmail/queue/info/10
+  chown qmails.qmail /home/system/qmail/queue/info/11; chmod 700 /home/system/qmail/queue/info/11
+  chown qmails.qmail /home/system/qmail/queue/info/12; chmod 700 /home/system/qmail/queue/info/12
+  chown qmails.qmail /home/system/qmail/queue/info/13; chmod 700 /home/system/qmail/queue/info/13
+  chown qmails.qmail /home/system/qmail/queue/info/14; chmod 700 /home/system/qmail/queue/info/14
+  chown qmails.qmail /home/system/qmail/queue/info/15; chmod 700 /home/system/qmail/queue/info/15
+  chown qmails.qmail /home/system/qmail/queue/info/16; chmod 700 /home/system/qmail/queue/info/16
+  chown qmails.qmail /home/system/qmail/queue/info/17; chmod 700 /home/system/qmail/queue/info/17
+  chown qmails.qmail /home/system/qmail/queue/info/18; chmod 700 /home/system/qmail/queue/info/18
+  chown qmails.qmail /home/system/qmail/queue/info/19; chmod 700 /home/system/qmail/queue/info/19
+  chown qmails.qmail /home/system/qmail/queue/info/20; chmod 700 /home/system/qmail/queue/info/20
+  chown qmails.qmail /home/system/qmail/queue/info/21; chmod 700 /home/system/qmail/queue/info/21
+  chown qmails.qmail /home/system/qmail/queue/info/22; chmod 700 /home/system/qmail/queue/info/22
+  chown qmailq.qmail /home/system/qmail/queue/intd; chmod 700 /home/system/qmail/queue/intd
+  chown qmailq.qmail /home/system/qmail/queue/intd/*; chmod 700 /home/system/qmail/queue/intd/*
+  chown qmailq.qmail /home/system/qmail/queue/lock; chmod 750 /home/system/qmail/queue/lock
+  chown qmailr.qmail /home/system/qmail/queue/lock/tcpto; chmod 644 /home/system/qmail/queue/lock/tcpto
+  chown qmails.qmail /home/system/qmail/queue/lock/sendmutex; chmod 600 /home/system/qmail/queue/lock/sendmutex
+  chown qmails.qmail /home/system/qmail/queue/lock/trigger; chmod 622 /home/system/qmail/queue/lock/trigger
+  chown qmailq.qmail /home/system/qmail/queue/mess; chmod 750 /home/system/qmail/queue/mess
+  chown qmailq.qmail /home/system/qmail/queue/mess/0; chmod 750 /home/system/qmail/queue/mess/0
+  chown qmailq.qmail /home/system/qmail/queue/mess/1; chmod 750 /home/system/qmail/queue/mess/1
+  chown qmailq.qmail /home/system/qmail/queue/mess/2; chmod 750 /home/system/qmail/queue/mess/2
+  chown qmailq.qmail /home/system/qmail/queue/mess/3; chmod 750 /home/system/qmail/queue/mess/3
+  chown qmailq.qmail /home/system/qmail/queue/mess/4; chmod 750 /home/system/qmail/queue/mess/4
+  chown qmailq.qmail /home/system/qmail/queue/mess/5; chmod 750 /home/system/qmail/queue/mess/5
+  chown qmailq.qmail /home/system/qmail/queue/mess/6; chmod 750 /home/system/qmail/queue/mess/6
+  chown qmailq.qmail /home/system/qmail/queue/mess/7; chmod 750 /home/system/qmail/queue/mess/7
+  chown qmailq.qmail /home/system/qmail/queue/mess/8; chmod 750 /home/system/qmail/queue/mess/8
+  chown qmailq.qmail /home/system/qmail/queue/mess/9; chmod 750 /home/system/qmail/queue/mess/9
+  chown qmailq.qmail /home/system/qmail/queue/mess/10; chmod 750 /home/system/qmail/queue/mess/10
+  chown qmailq.qmail /home/system/qmail/queue/mess/11; chmod 750 /home/system/qmail/queue/mess/11
+  chown qmailq.qmail /home/system/qmail/queue/mess/12; chmod 750 /home/system/qmail/queue/mess/12
+  chown qmailq.qmail /home/system/qmail/queue/mess/13; chmod 750 /home/system/qmail/queue/mess/13
+  chown qmailq.qmail /home/system/qmail/queue/mess/14; chmod 750 /home/system/qmail/queue/mess/14
+  chown qmailq.qmail /home/system/qmail/queue/mess/15; chmod 750 /home/system/qmail/queue/mess/15
+  chown qmailq.qmail /home/system/qmail/queue/mess/16; chmod 750 /home/system/qmail/queue/mess/16
+  chown qmailq.qmail /home/system/qmail/queue/mess/17; chmod 750 /home/system/qmail/queue/mess/17
+  chown qmailq.qmail /home/system/qmail/queue/mess/18; chmod 750 /home/system/qmail/queue/mess/18
+  chown qmailq.qmail /home/system/qmail/queue/mess/19; chmod 750 /home/system/qmail/queue/mess/19
+  chown qmailq.qmail /home/system/qmail/queue/mess/20; chmod 750 /home/system/qmail/queue/mess/20
+  chown qmailq.qmail /home/system/qmail/queue/mess/21; chmod 750 /home/system/qmail/queue/mess/21
+  chown qmailq.qmail /home/system/qmail/queue/mess/22; chmod 750 /home/system/qmail/queue/mess/22
+  chown qmailq.qmail /home/system/qmail/queue/todo; chmod 750 /home/system/qmail/queue/todo
+  chown qmailq.qmail /home/system/qmail/queue/todo/*; chmod 750 /home/system/qmail/queue/todo/*
+  chown qmails.qmail /home/system/qmail/queue/local; chmod 700 /home/system/qmail/queue/local
+  chown qmails.qmail /home/system/qmail/queue/local/0; chmod 700 /home/system/qmail/queue/local/0
+  chown qmails.qmail /home/system/qmail/queue/local/1; chmod 700 /home/system/qmail/queue/local/1
+  chown qmails.qmail /home/system/qmail/queue/local/2; chmod 700 /home/system/qmail/queue/local/2
+  chown qmails.qmail /home/system/qmail/queue/local/3; chmod 700 /home/system/qmail/queue/local/3
+  chown qmails.qmail /home/system/qmail/queue/local/4; chmod 700 /home/system/qmail/queue/local/4
+  chown qmails.qmail /home/system/qmail/queue/local/5; chmod 700 /home/system/qmail/queue/local/5
+  chown qmails.qmail /home/system/qmail/queue/local/6; chmod 700 /home/system/qmail/queue/local/6
+  chown qmails.qmail /home/system/qmail/queue/local/7; chmod 700 /home/system/qmail/queue/local/7
+  chown qmails.qmail /home/system/qmail/queue/local/8; chmod 700 /home/system/qmail/queue/local/8
+  chown qmails.qmail /home/system/qmail/queue/local/9; chmod 700 /home/system/qmail/queue/local/9
+  chown qmails.qmail /home/system/qmail/queue/local/10; chmod 700 /home/system/qmail/queue/local/10
+  chown qmails.qmail /home/system/qmail/queue/local/11; chmod 700 /home/system/qmail/queue/local/11
+  chown qmails.qmail /home/system/qmail/queue/local/12; chmod 700 /home/system/qmail/queue/local/12
+  chown qmails.qmail /home/system/qmail/queue/local/13; chmod 700 /home/system/qmail/queue/local/13
+  chown qmails.qmail /home/system/qmail/queue/local/14; chmod 700 /home/system/qmail/queue/local/14
+  chown qmails.qmail /home/system/qmail/queue/local/15; chmod 700 /home/system/qmail/queue/local/15
+  chown qmails.qmail /home/system/qmail/queue/local/16; chmod 700 /home/system/qmail/queue/local/16
+  chown qmails.qmail /home/system/qmail/queue/local/17; chmod 700 /home/system/qmail/queue/local/17
+  chown qmails.qmail /home/system/qmail/queue/local/18; chmod 700 /home/system/qmail/queue/local/18
+  chown qmails.qmail /home/system/qmail/queue/local/19; chmod 700 /home/system/qmail/queue/local/19
+  chown qmails.qmail /home/system/qmail/queue/local/20; chmod 700 /home/system/qmail/queue/local/20
+  chown qmails.qmail /home/system/qmail/queue/local/21; chmod 700 /home/system/qmail/queue/local/21
+  chown qmails.qmail /home/system/qmail/queue/local/22; chmod 700 /home/system/qmail/queue/local/22
+  chown qmails.qmail /home/system/qmail/queue/bounce; chmod 700 /home/system/qmail/queue/bounce
+  chown qmails.qmail /home/system/qmail/queue/remote; chmod 700 /home/system/qmail/queue/remote
+  chown qmails.qmail /home/system/qmail/queue/remote/0; chmod 700 /home/system/qmail/queue/remote/0
+  chown qmails.qmail /home/system/qmail/queue/remote/1; chmod 700 /home/system/qmail/queue/remote/1
+  chown qmails.qmail /home/system/qmail/queue/remote/2; chmod 700 /home/system/qmail/queue/remote/2
+  chown qmails.qmail /home/system/qmail/queue/remote/3; chmod 700 /home/system/qmail/queue/remote/3
+  chown qmails.qmail /home/system/qmail/queue/remote/4; chmod 700 /home/system/qmail/queue/remote/4
+  chown qmails.qmail /home/system/qmail/queue/remote/5; chmod 700 /home/system/qmail/queue/remote/5
+  chown qmails.qmail /home/system/qmail/queue/remote/6; chmod 700 /home/system/qmail/queue/remote/6
+  chown qmails.qmail /home/system/qmail/queue/remote/7; chmod 700 /home/system/qmail/queue/remote/7
+  chown qmails.qmail /home/system/qmail/queue/remote/8; chmod 700 /home/system/qmail/queue/remote/8
+  chown qmails.qmail /home/system/qmail/queue/remote/9; chmod 700 /home/system/qmail/queue/remote/9
+  chown qmails.qmail /home/system/qmail/queue/remote/10; chmod 700 /home/system/qmail/queue/remote/10
+  chown qmails.qmail /home/system/qmail/queue/remote/11; chmod 700 /home/system/qmail/queue/remote/11
+  chown qmails.qmail /home/system/qmail/queue/remote/12; chmod 700 /home/system/qmail/queue/remote/12
+  chown qmails.qmail /home/system/qmail/queue/remote/13; chmod 700 /home/system/qmail/queue/remote/13
+  chown qmails.qmail /home/system/qmail/queue/remote/14; chmod 700 /home/system/qmail/queue/remote/14
+  chown qmails.qmail /home/system/qmail/queue/remote/15; chmod 700 /home/system/qmail/queue/remote/15
+  chown qmails.qmail /home/system/qmail/queue/remote/16; chmod 700 /home/system/qmail/queue/remote/16
+  chown qmails.qmail /home/system/qmail/queue/remote/17; chmod 700 /home/system/qmail/queue/remote/17
+  chown qmails.qmail /home/system/qmail/queue/remote/18; chmod 700 /home/system/qmail/queue/remote/18
+  chown qmails.qmail /home/system/qmail/queue/remote/19; chmod 700 /home/system/qmail/queue/remote/19
+  chown qmails.qmail /home/system/qmail/queue/remote/20; chmod 700 /home/system/qmail/queue/remote/20
+  chown qmails.qmail /home/system/qmail/queue/remote/21; chmod 700 /home/system/qmail/queue/remote/21
+  chown qmails.qmail /home/system/qmail/queue/remote/22; chmod 700 /home/system/qmail/queue/remote/22
+  chown root.qmail /home/system/qmail/users; chmod 755 /home/system/qmail/users
+  chown root.root /var/qmail/service; chmod 755 /var/qmail/service
+  chown qmaill /var/log/qmail; chmod 755 /var/log/qmail
+}
Index: npl/mailserver/netqmail_conf/root/etc/qmail.rc.config
===================================================================
--- npl/mailserver/netqmail_conf/root/etc/qmail.rc.config	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/etc/qmail.rc.config	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,24 @@
+#
+# Qmail configuration file
+# 
+# Author:
+# 	Guilherme Balena Versiani, guibv@yahoo.com
+#
+# Last Update: Mon Sep 03 18:57:44 BRT 2001
+
+#
+# Qmail users (you should not change these!)
+#
+QMAIL_USER_0="alias:50:nofiles:/var/qmail/alias"
+QMAIL_USER_1="qmaild:51:nofiles:/var/qmail"
+QMAIL_USER_2="qmaill:52:nofiles:/var/qmail"
+QMAIL_USER_3="qmailp:53:nofiles:/var/qmail"
+QMAIL_USER_4="qmailq:54:qmail:/var/qmail"
+QMAIL_USER_5="qmailr:55:qmail:/var/qmail"
+QMAIL_USER_6="qmails:56:qmail:/var/qmail"
+
+#
+# Qmail groups (you should not change these!)
+#
+QMAIL_GROUP_0="nofiles:55"
+QMAIL_GROUP_1="qmail:56"
Index: npl/mailserver/netqmail_conf/root/home/system/firewall/services.qmailsubmission.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/firewall/services.qmailsubmission.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/firewall/services.qmailsubmission.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+587/tcp,Email traffic,Mail submission via authenticated SMTP (tls)
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/alias/.qmail-default
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/alias/.qmail-default	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/alias/.qmail-default	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+|/usr/bin/syn3-dagent "$LOCAL" "$SENDER"
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/concurrencyincoming.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/concurrencyincoming.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/concurrencyincoming.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+5
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/locals
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/locals	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/locals	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+me
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/maxrcpt.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/maxrcpt.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/maxrcpt.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+100
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/qmqpservers.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/qmqpservers.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/qmqpservers.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+127.0.0.1
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/relaylimits.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/relaylimits.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/relaylimits.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+#:1000
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/softlimit.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/softlimit.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/softlimit.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+150000000
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/control/spfbehavior.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/control/spfbehavior.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/control/spfbehavior.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+3
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.smtp.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.smtp.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.smtp.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,22 @@
+127.0.0.1:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-queue"
+127.0.0.2:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+127.0.0.3:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.16.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.17.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.18.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.19.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.20.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.21.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.22.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.23.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.24.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.25.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.26.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.27.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.28.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.29.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.30.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+172.31.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+192.168.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+10.:allow,RELAYCLIENT="",QMAILQUEUE="bin/qmail-qmqpc"
+:allow,QMAILQUEUE="bin/qmail-qmqpc",CHKUSER_WRONGRCPTLIMIT="3"
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.submission.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.submission.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/tcp.submission.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+:allow,QMAILQUEUE="bin/qmail-qmqpc",CHKUSER_WRONGRCPTLIMIT="3"
Index: npl/mailserver/netqmail_conf/root/home/system/qmail/users/assign.new
===================================================================
--- npl/mailserver/netqmail_conf/root/home/system/qmail/users/assign.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/home/system/qmail/users/assign.new	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,2 @@
++:alias:50:55:/var/qmail/alias:-::
+.
Index: npl/mailserver/netqmail_conf/root/service/qmail-send
===================================================================
--- npl/mailserver/netqmail_conf/root/service/qmail-send	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/service/qmail-send	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/var/qmail/supervise/qmail-send
Index: npl/mailserver/netqmail_conf/root/service/qmail-smtpd
===================================================================
--- npl/mailserver/netqmail_conf/root/service/qmail-smtpd	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/service/qmail-smtpd	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/var/qmail/supervise/qmail-smtpd
Index: npl/mailserver/netqmail_conf/root/service/qmail-submission
===================================================================
--- npl/mailserver/netqmail_conf/root/service/qmail-submission	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/service/qmail-submission	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/var/qmail/supervise/qmail-submission
Index: npl/mailserver/netqmail_conf/root/usr/bin/syn3-dagent
===================================================================
--- npl/mailserver/netqmail_conf/root/usr/bin/syn3-dagent	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/usr/bin/syn3-dagent	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+USER="$1"
+SENDER="$2"
+INMAIL=/tmp/syn3-dagent.$$
+SCANMAIL=/tmp/syn3-dagent-scanned.$$
+
+
+#cleanup and exit
+end()
+{
+	rm $INMAIL 2>/dev/null
+	rm $SCANMAIL 2>/dev/null
+	exit $1
+}
+
+# some kind of ldap problem, try again later
+id "Administrator" >/dev/null || end 111
+
+#does the user exists?
+if ! id "$USER" >/dev/null; then
+	#we're sure theres no ldap problem?
+	id "Administrator" >/dev/null || end 111
+	#probably a bounce spammer, drop mail silently
+	echo "User does not exist, dropping mail."
+	end 0
+fi
+
+#store mail temporary
+cat > $INMAIL || end 1
+
+#pipe trough personal spamfilter of this user
+if ! grep "VIRUS.*IN MAIL TO YOU" $INMAIL >/dev/null && /usr/bin/dspamc --user "$USER" --deliver=innocent,spam --mail-from="$SENDER" --stdout >$SCANMAIL <$INMAIL; then
+	#it worked
+	if grep "^X-DSPAM-Result: Spam" $SCANMAIL >/dev/null; then
+		SPAM=1
+	else
+		SPAM=
+	fi
+	MAIL=$SCANMAIL
+else
+	#spam filter is broken, or it was just a virus notification
+	MAIL=$INMAIL
+	SPAM=
+fi
+
+# #check cyrus is up, and deliver it there:
+# if /usr/bin/pgrep -f -x /usr/cyrus/bin/master ; then
+# 	if [ "$SPAM" ]; then
+# 		/usr/cyrus/bin/deliver -a "$USER" -m Spam "$USER" < $MAIL
+# 		end $?
+# 	else
+# 		/usr/cyrus/bin/deliver -a "$USER" "$USER" < $MAIL
+# 		end $?
+# 	fi
+# fi
+
+#check zarafa is up, and deliver it there:
+if pidof zarafa-server >/dev/null; then
+	if [ "$SPAM" ]; then
+		/usr/bin/zarafa-dagent "$USER" -q -j < $MAIL
+		end $?
+	else
+		/usr/bin/zarafa-dagent "$USER" -q < $MAIL
+		end $?
+	fi
+fi
+
+#check kopano is up, and deliver it there:
+if pidof kopano-server >/dev/null; then
+	if [ "$SPAM" ]; then
+		/usr/bin/kopano-dagent "$USER" -q -j < $MAIL
+		end $?
+	else
+		/usr/bin/kopano-dagent "$USER" -q < $MAIL
+		end $?
+	fi
+fi
+
+#no backend mailstorage up, so fail temporary
+echo "All mailbackends are down, retry again later..."
+end 111
Index: npl/mailserver/netqmail_conf/root/var/qmail/alias
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/alias	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/alias	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/home/system/qmail/alias
Index: npl/mailserver/netqmail_conf/root/var/qmail/bin/qmailctl
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/bin/qmailctl	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/bin/qmailctl	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,195 @@
+#!/bin/sh
+#
+# tx Sam Tang
+
+# Put here the services you want to manage
+svclist="qmail-smtpd qmail-submission qmail-send vpopmaild"
+# Put here the services want monitoring
+servicelist="dovecot clamd freshclam spamd vusaged httpd mariadb fail2ban"
+
+PATH=/var/qmail/bin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin
+export PATH
+
+QMAILDUID=`id -u qmaild`
+NOFILESGID=`id -g qmaild`
+
+function show_uptime() {
+	org="$(svstat /service/$1 | awk '{print $2,$3,$4;}' | sed 's/up/[ up ]/g' | sed 's/down/[ down ]/g' | sed ''/up/s//`printf "\033[1\;32mup\033[0m"`/'' | sed ''/down/s//`printf "\033[1\;31mdown\033[0m"`/'')"
+	sec="$(svstat /service/$1 | awk '{print $5;}')"
+	d=$(( $sec / 86400))
+	h=$(( $(($sec - $d * 86400)) / 3600 ))
+	m=$(( $(($sec -d * 86400 - $h * 3600)) / 60 ))
+	s=$(($sec -d * 86400 - $h * 3600 - $m * 60))
+	if [ $sec -le 60 ]; then
+		printf "%-22s %s %s %s %s %s %s seconds\n" "$1:" $org $s
+	else
+		printf "%-22s %s %s %s %s %s %3s day(s), %02d:%02d:%02d\n" "$1:" $org $d $h $m $s
+	fi
+}
+
+case "$1" in
+  start)
+    echo "Starting qmail"
+
+    for svc in $svclist ; do
+    	if svok /service/$svc ; then
+     		svc -u /service/$svc
+     	else
+     		echo $svc service not running
+     	fi
+    done 
+
+    if [ -d /var/lock/subsys ]; then
+      touch /var/lock/subsys/qmail
+    fi
+    ;;
+  stop)
+    echo "Stopping qmail..."
+    for svc in $svclist ; do
+      echo " $svc"
+      svc -d /service/$svc
+    done
+    if [ -f /var/lock/subsys/qmail ]; then
+    rm /var/lock/subsys/qmail
+    fi
+    ;;
+  stat)
+    for svc in $svclist ; do
+      show_uptime $svc
+      show_uptime "$svc/log"
+    done
+    echo ""
+    for service in $servicelist ; do
+      printf "%-22s " "$service status:"
+      if (( $(ps -ef | grep -v grep | grep $service | wc -l) > 0 ))
+      then 
+          echo -e "[ \033[1;32mup\033[m ]"
+      else
+          echo -e "[ \033[1;31mdown\033[m ]"
+      fi
+    done
+    if [ -f /var/qmail/control/simversions.cdb ]; then
+    	printf "\nClamAV database updated at: "
+	stat --printf=%y /var/qmail/control/simversions.cdb | cut -d. -f1
+    fi
+    if [ -f /var/qmail/users/assign ]; then
+	printf "Total Domains: "
+	wc -l < /var/qmail/users/assign
+    fi
+    echo ""
+    qmail-qstat
+    ;; 
+  doqueue|alrm|flush)
+    echo "Sending ALRM signal to qmail-send."
+    svc -a /service/qmail-send
+    ;;
+  queue)
+    qmail-qstat
+    qmail-qread
+    ;;
+  reload|hup)
+    echo "Sending HUP signal to qmail-send."
+    svc -h /service/qmail-send
+    ;;
+  pause)
+    for svc in $svclist ; do
+      echo "Pausing $svc"
+      svc -p /service/$svc
+    done
+    ;; 
+  cont)
+	  for svc in $svclist ; do
+	    echo "Continuing $svc"
+	    svc -c /service/$svc
+	  done
+    ;; 
+  restart)
+    echo "Restarting qmail:"
+    for svc in $svclist ; do
+      if [ "$svc" != "qmail-send" ] ; then
+        echo "* Stopping $svc."
+        svc -d /service/$svc
+      fi
+    done
+    echo "* Sending qmail-send SIGTERM and restarting."
+    svc -t /service/qmail-send
+    for svc in $svclist ; do
+      if [ "$svc" != "qmail-send" ] ; then
+        echo "* Restarting $svc."
+        svc -u /service/$svc
+      fi
+    done
+    ;;
+  cdb)
+    if ! grep '\#define POP_AUTH_OPEN_RELAY 1' ~vpopmail/include/config.h >/dev/null; then
+      (cd ~vpopmail/etc ; cat tcp.smtp | tcprules tcp.smtp.cdb tcp.smtp.tmp)
+      echo "Updated tcp.smtp.cdb."
+      (cd ~vpopmail/etc ; cat tcp.submission | tcprules tcp.submission.cdb tcp.submission.tmp)
+      echo "Updated tcp.submission.cdb."
+    else
+      ~vpopmail/bin/clearopensmtp
+      echo "Ran clearopensmtp."
+    fi
+    ;;
+  clear)
+    echo "Clearing readproctitle service errors with ................."
+    svc -o /service/clear
+    ;;
+  kill)
+    echo "First stopping services ... "
+    for svc in $svclist ; do
+    	if svok /service/$svc ; then
+            svc -d /service/$svc
+            svc -d /service/$svc/log
+    	fi
+    done
+    echo "Now sending processes the kill signal ... "
+        killall -g svscanboot
+    echo "done"
+    ;;
+  boot)
+    echo "Starting qmail"
+    /command/svscanboot &
+    ;;
+  reboot)
+    echo "First stopping services ... "
+    for svc in $svclist ; do
+        if svok /service/$svc ; then
+            svc -d /service/$svc
+            svc -d /service/$svc/log
+        fi
+    done
+    echo "Now sending processes the kill signal ... "
+        killall -g svscanboot
+    echo "done"
+    echo "Starting qmail"
+    /command/svscanboot &
+    ;;
+  help)
+    cat <<HELP
+    stop -- stops mail service (smtp connections refused, nothing goes out)
+   start -- starts mail service (smtp connection accepted, mail can go out)
+   pause -- temporarily stops mail service (connections accepted, nothing leaves)
+    cont -- continues paused mail service
+    stat -- displays status of mail service
+     cdb -- rebuild the tcpserver cdb file for smtp
+ restart -- stops and restarts smtp, sends qmail-send a TERM & restarts it
+ doqueue -- sends qmail-send ALRM, scheduling queued messages for delivery
+  reload -- sends qmail-send HUP, rereading locals and virtualdomains
+   queue -- shows status of queue
+    alrm -- same as doqueue
+   flush -- same as doqueue
+     hup -- same as reload
+   clear -- clears the readproctitle service errors with .....................
+    kill -- svc -d processes in svclist, then do 'killall -g svscanboot'
+    boot -- Boots qmail and all services in /service running /command/svscanboot
+  reboot -- kill & boot commands in sequence
+HELP
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart|doqueue|flush|reload|stat|pause|cont|cdb|queue|clear|kill|boot|reboot|help}"
+    exit 1
+    ;;
+esac
+
+exit 0 
Index: npl/mailserver/netqmail_conf/root/var/qmail/bin/rcptcheck-overlimit.sh
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/bin/rcptcheck-overlimit.sh	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/bin/rcptcheck-overlimit.sh	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,76 @@
+#!/bin/bash
+# rcptcheck-overlimit v0.3
+# Digitalmind 2017-08-23
+# This script limits the number of emails sent by relayclients (authusers or ip with RELAYCLIENT in tcprules)
+# You must define the variable RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh AND RCPTCHECKRELAYCLIENT="1"
+# This script will be called for every accepted rcptto.
+# If RELAYCLIENT is not defined the script terminates with the exit code 112 (ignore/accept).
+# Messages sent to domains in rcpthosts will NOT be accounted for.
+# For every accepted rcptto with RELAYCLIENT defined, a char 'X' will be appended to a file in the directory $OVERLIMITDIR;
+# this file name will be the authuser, if defined, or  the client ip address.
+# The script will look for an entry corresponding to the client (authuser or ip) in $LIMITSCONTROLFILE and use the number found
+# as the maximum number of allowed outgoing emails.
+# If the OVERLIMITDIR is not writable by the user running qmail-smtpd or the LIMITSCONTROLFILE cannot be read, the script terminates with 112 (ignore/accept).
+# In case of overlimit, an exit code 113 (reject/overlimit) will be returned to qmail-smtpd and the connection will be dropped with a 421.
+# $LIMITSCONTROLFILEFILE can contain comments, '0' means unlimited, the entry starting with ':' will be considered the default limit.
+# If the default entry can't be found, the default will be set to unlimited.
+# In case more lines match the client name, only the last will be used.
+# A cronjob must be created to periodically cleanup files in $OVERLIMITDIR: to use daily limits, schedule the job once a day.
+#
+# Cronjob example:
+#   # find /var/qmail/overlimit/ -type f -exec rm -f "{}" \;
+#
+# $LIMITSCONTROLFILE example:
+# -----
+#:1000
+#1.2.3.4:3000
+#test@example.com:0
+# -----
+# Known bugs:
+# - the line 'info@example.com:1000' also matches the client name 'testinfo@example.com'.
+
+EXITIGNORE=112
+EXITOVERLIMIT=113
+
+LIMITSCONTROLFILE=/var/qmail/control/relaylimits
+OVERLIMITDIR=/var/qmail/overlimit
+DEBUGLOG=/var/log/overlimit/debug.log
+
+if [ -z "${RELAYCLIENT+x}" ]; then exit $EXITIGNORE; fi
+if [ ! -r "$LIMITSCONTROLFILE" ]; then exit $EXITIGNORE; fi
+if [ ! -w "$OVERLIMITDIR" ]; then exit $EXITIGNORE; fi
+
+# Read config file removing comments, blank lines, spaces and tabs
+PREFILTER="sed -e 's/#.*$//g' -e '/^$/d' -e 's/[ \t]*//g' $LIMITSCONTROLFILE"
+
+# SMTPAUTHUSER should be already validated, but just to be safe leave only alphanum, -.', '_', '-' and '@'
+FILTEREDSMTPAUTHUSER=$(echo "$SMTPAUTHUSER" | tr -cd '[:alnum:].-_@')
+
+if [ -n "${RCPTHOSTS}" ]; then
+  logger -t qmail-overlimit -p mail.info "RELAYCLIENT and RCPTHOSTS: mailfrom=$SENDER rcptto=$RECIPIENT authuser=${FILTEREDAUTHUSER} remoteip=${TCPREMOTEIP}"
+  exit $EXITIGNORE
+fi
+
+if [ -n "${FILTEREDSMTPAUTHUSER}" ]; then
+  value=$(eval ${PREFILTER} | grep -Fi "$FILTEREDSMTPAUTHUSER:" | tail -1); limit="${value##*:}" # specific authuser
+  ##if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep -Fi "${FILTEREDSMTPAUTHUSER##*@}:" | tail -1); limit="${value##*:}"; fi # domain part
+  client="${FILTEREDSMTPAUTHUSER}"
+else
+  value=$(eval ${PREFILTER} | grep -Fi "$TCPREMOTEIP:" | tail -1); limit="${value##*:}" # specific ip address
+  client="${TCPREMOTEIP}"
+fi
+if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep "^:" | tail -1); limit="${value##*:}"; fi  # default ':value'
+if [ -z "${limit}" ]; then limit=0; fi # if nothing else
+
+currentnum=$(stat -c%s $OVERLIMITDIR/$client 2>/dev/null)
+if [ -z "$currentnum" ]; then currentnum=1; fi
+
+logger -t qmail-overlimit -p mail.info "client=$client limit=$limit current=$currentnum"
+
+if [ "$currentnum" -gt "$limit" ] && [ "$limit" -ne "0" ]; then
+  logger -t qmail-overlimit -p mail.info "REJECTED $client "
+  exit $EXITOVERLIMIT
+else
+  echo -n "X" >> "$OVERLIMITDIR/$client" 2>/dev/null
+fi
+exit $EXITIGNORE
Index: npl/mailserver/netqmail_conf/root/var/qmail/control
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/control	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/control	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/home/system/qmail/control
Index: npl/mailserver/netqmail_conf/root/var/qmail/queue
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/queue	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/queue	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/home/system/qmail/queue
Index: npl/mailserver/netqmail_conf/root/var/qmail/rc
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/rc	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/rc	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Using stdout for logging
+# Using control/defaultdelivery from qmail-local to deliver messages by default
+
+# DKIM signign
+#exec env - PATH="/var/qmail/bin:$PATH" \
+#QMAILREMOTE=/var/qmail/bin/spawn-filter  \
+#FILTERARGS=/var/qmail/bin/dk-filter \
+#qmail-start "`cat /var/qmail/control/defaultdelivery`" 
+
+exec env - PATH="/var/qmail/bin:$PATH" \
+qmail-start "`cat /var/qmail/control/defaultdelivery`"
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/log/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec /usr/bin/setuidgid qmaill logger -t qmail-send -p mail.info
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-send/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,8 @@
+#!/bin/sh
+exec 2>&1
+
+#dynamic update of hostname
+hostname -f > /var/qmail/control/me
+#zet de assign file om naar binair formaat.
+/var/qmail/bin/qmail-newu
+exec /var/qmail/rc
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/log/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec /usr/bin/setuidgid qmaill logger -t qmail-smtpd -p mail.info
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-smtpd/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+exec 2>&1
+
+##### OUD
+# QMAILDUID=`id -u qmaild`
+# NOFILESGID=`id -g qmaild`
+# MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`
+# LOCAL=`head -1 /var/qmail/control/me`
+# if [ -z "$QMAILDUID" -o -z "$NOFILESGID" -o -z "$MAXSMTPD" -o -z "$LOCAL" ]; then
+#     echo QMAILDUID, NOFILESGID, MAXSMTPD, or LOCAL is unset in
+#     echo /var/qmail/supervise/qmail-smtpd/run
+#     exit 1
+# fi
+# if [ ! -f /var/qmail/control/rcpthosts ]; then
+#     echo "No /var/qmail/control/rcpthosts!"
+#     echo "Refusing to start SMTP listener because it'll create an open relay"
+#     exit 1
+# fi
+# exec /usr/bin/softlimit -m 150000000 /usr/bin/tcpserver -v -R -l "$LOCAL" -x /etc/qmail/tcp.smtp.cdb -c "$MAXSMTPD" -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp /usr/bin/rblsmtpd -r cbl.abuseat.org -r bl.spamcop.net /usr/bin/fixcrio /var/qmail/bin/qmail-smtpd 2>&1
+######
+
+QMAILDUID=`id -u qmaild`
+NOFILESGID=`id -g qmaild`
+MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`
+SOFTLIMIT=`cat /var/qmail/control/softlimit`
+LOCAL=`head -1 /var/qmail/control/me`
+
+# This enables greetdelay for qmail-smtpd
+export SMTPD_GREETDELAY=20
+export DROP_PRE_GREET=1
+
+# This enables chkuser
+export CHKUSER_START=ALWAYS
+
+# DKIM - SURBL configuration
+# DKIMQUEUE and SURBLQUEUE are front-ends of qmail-queue
+#export SURBL=1                               # Comment out to enable SURBL filtering
+#export QMAILQUEUE=/var/qmail/bin/surblqueue  # executes surblfilter
+#export SURBLQUEUE=/var/qmail/bin/qmail-dkim  # executes qmail-dkim afer sublfilter
+#export DKIMQUEUE=/var/qmail/bin/simscan      # simscan is executed after qmail-dkim
+# DKIM verification. Use carefully
+#export DKIMVERIFY="FGHKLMNOQRTVWjp"
+# This is to avoid verification of outgoing messages
+#export RELAYCLIENT_NODKIMVERIFY=1
+
+# This turns off TLS on port 25
+# export DISABLETLS="1"
+
+# Requires that authenticated user and 'mail from' are identical
+#export FORCEAUTHMAILFROM="1"
+
+# rcptcheck-overlimit. Limits the number of emails sent by relayclients
+export RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh
+export RCPTCHECKRELAYCLIENT="1"
+
+# This enables simscan debug
+#export SIMSCAN_DEBUG=4
+
+exec /usr/bin/softlimit -m "$SOFTLIMIT" \
+    /usr/bin/tcpserver -v -H -R -l "$LOCAL" \
+    -x /etc/qmail/tcp.smtp.cdb -c "$MAXSMTPD" \
+    -u "$QMAILDUID" -g "$NOFILESGID" 0 25 \
+    /var/qmail/bin/qmail-smtpd 2>&1
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/log/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/log/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec /usr/bin/setuidgid qmaill logger -t qmail-submission -p mail.info
Index: npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/run
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/supervise/qmail-submission/run	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+exec 2>&1
+
+QMAILDUID=`id -u qmaild`
+NOFILESGID=`id -g qmaild`
+MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`
+SOFTLIMIT=`cat /var/qmail/control/softlimit`
+LOCAL=`head -1 /var/qmail/control/me`
+
+# You MUST export this, otherwise you'd get a 30 sec timeout
+# "!" if you want the submission feature (auth required)
+export SMTPAUTH="!"
+
+# This enables greetdelay for qmail-smtpd.
+export SMTPD_GREETDELAY=3
+export DROP_PRE_GREET=1
+
+# This enables chkuser
+export CHKUSER_START=ALWAYS
+
+# This makes qmail to allow connections without TLS (default 1)
+#export FORCETLS=0
+
+# This turns off TLS on port 587 (default 0)
+#export DISABLETLS=1
+
+# Requires that authenticated user and 'mail from' are identical (default 0)
+# export FORCEAUTHMAILFROM=1
+
+# rcptcheck-overlimit. Limits the number of emails sent by relayclients
+#export RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh
+#export RCPTCHECKRELAYCLIENT=1
+
+exec /usr/bin/softlimit -m "$SOFTLIMIT" \
+    /usr/bin/tcpserver -v -H -R -l "$LOCAL" \
+    -x /etc/qmail/tcp.submission.cdb -c "$MAXSMTPD" \
+    -u "$QMAILDUID" -g "$NOFILESGID" 0 587 \
+    /var/qmail/bin/qmail-smtpd \
+    /usr/bin/checkpassword-pam -H --noenv -s qmail 2>&1
Index: npl/mailserver/netqmail_conf/root/var/qmail/users
===================================================================
--- npl/mailserver/netqmail_conf/root/var/qmail/users	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/netqmail_conf/root/var/qmail/users	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+/home/system/qmail/users
Index: npl/mailserver/vpopmail/vpopmail.SlackBuild
===================================================================
--- npl/mailserver/vpopmail/vpopmail.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+##NEED:...
+##DEP:..
+#NEED:netqmail
+##DEP:openldap
+
+
+#######Essential package info.
+#Change these if autodetection fails.
+
+#Name of the Syn-3 package that we are going to create
+NAME=`basename $0|sed 's/.SlackBuild//'`
+
+#Archive of the sourcefiles to unpack
+SRC_ARC=`ls *.tar.* *.zip 2>/dev/null`
+
+#Version of the sourcefiles
+VER=`echo $SRC_ARC| sed 's/.*-//g' | sed 's/\.tar\..*$//g' | sed 's/\.zip$//g'`
+
+#Architecture that the created binaries run on.
+#Use noarch for scripts.
+ARCH=`uname -m`
+
+#from this point on, exit on errors:
+set -e
+
+########Build and create the pacakge.
+#Uncomment the stuff that you dont want or need
+
+#Unpack source
+#(uncomment if not needed)
+syn3_unpack $SRC_ARC
+
+#Directory where the sourcefiles are unpacked.
+#(you might have to adjust this if autodetection fails)
+SRC_DIR=`ls -c|head -1`
+
+#apply patches
+#patch -p1 -d $SRC_DIR < fluxkiosk.patch || exit 1
+
+pushd $SRC_DIR
+
+groupadd -g 89 vchkpw
+useradd -g vchkpw -u 89 -d /home/vpopmail vpopmail
+#AUTOMAKE: Configure
+#Some usefull stuff you sometimes need to set:
+#export LDFLAGS="-L/usr/X11/lib/ -L/usr/lib/mysql/"
+#export LD_LIBRARY_PATH=/usr/lib/mysql
+#export VPATH=$LD_LIBRARY_PATH
+#export CFLAGS="-std=c89"
+#export CFLAGS="-fgnu89-inline" #If "multiple definition of `foo'" Also see http://gcc.gnu.org/gcc-4.3/porting_to.html
+MAKE_OPTS=""
+./configure \
+		--prefix=/usr \
+        --enable-qmaildir=/var/qmail/ \
+        --enable-qmail-newu=/var/qmail/bin/qmail-newu \
+        --enable-qmail-inject=/var/qmail/bin/qmail-inject \
+        --enable-qmail-newmrh=/var/qmail/bin/qmail-newmrh \
+        --disable-roaming-users \
+        --enable-libdir=/usr/lib \
+        --enable-logging=p \
+        --disable-clear-passwd \
+        --enable-auth-logging \
+        --disable-valias \
+        --disable-passwd \
+        --enable-qmail-ext \
+        --enable-learn-passwords
+
+
+#AUTOMAKE: Compile
+make $MAKE_OPTS || exit 1
+
+
+#AUTOMAKE: Install
+mkdir -p /tmp/pkg &>/dev/null
+make pkgconfigdir=/usr/lib/pkgconfig install_prefix=/tmp/pkg DESTDIR=/tmp/pkg INSTALL_ROOT=/tmp/pkg install_root=/tmp/pkg $MAKE_OPTS install || exit 1
+popd
+
+#strip bins and other stuff
+syn3_strip /tmp/pkg || exit 1
+
+#move development stuff and create seperate development package
+syn3_move_dev /tmp/pkg /tmp/pkgdev || exit 1
+syn3_makepkg /tmp/pkgdev $NAME""_dev $VER $ARCH || exit 1
+
+#make main package
+syn3_makepkg /tmp/pkg $NAME $VER $ARCH || exit 1
Index: npl/mailserver/vpopmail/vpopmail.arch
===================================================================
--- npl/mailserver/vpopmail/vpopmail.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/vpopmail/vpopmail.build
===================================================================
--- npl/mailserver/vpopmail/vpopmail.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+3
Index: npl/mailserver/vpopmail/vpopmail.md5
===================================================================
--- npl/mailserver/vpopmail/vpopmail.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,5 @@
+0b5c8febc20f543d2ad835f3f789a9fc  ./vpopmail-5.4.33.tar.gz
+027c54871b165377c218eb875e664883  ./vpopmail_dev.pkg
+2cabb116fa7175ec8e486c5e17d809be  ./vpopmail.pkg
+34c7dfd742f4608cdc663b3dc6ac6f32  ./vpopmail.SlackBuild
+26ee8ff81c125982c255e2d684609475  ./vpopmail.SlackBuild.log.gz
Index: npl/mailserver/vpopmail/vpopmail.version
===================================================================
--- npl/mailserver/vpopmail/vpopmail.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+5.4.33
Index: npl/mailserver/vpopmail/vpopmail_dev.arch
===================================================================
--- npl/mailserver/vpopmail/vpopmail_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail_dev.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/mailserver/vpopmail/vpopmail_dev.build
===================================================================
--- npl/mailserver/vpopmail/vpopmail_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+3
Index: npl/mailserver/vpopmail/vpopmail_dev.version
===================================================================
--- npl/mailserver/vpopmail/vpopmail_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/mailserver/vpopmail/vpopmail_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+5.4.33
Index: npl/overig/checkpassword_pam/checkpassword_pam.SlackBuild
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.SlackBuild	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+##NEED:...
+##DEP:..
+#DEP:Linux_PAM
+
+#######Essential package info.
+#Change these if autodetection fails.
+
+#Name of the Syn-3 package that we are going to create
+NAME=`basename $0|sed 's/.SlackBuild//'`
+
+#Archive of the sourcefiles to unpack 
+SRC_ARC=`ls *.tar.* *.zip 2>/dev/null`
+
+#Version of the sourcefiles
+VER=`echo $SRC_ARC| sed 's/.*-//g' | sed 's/\.tar\..*$//g' | sed 's/\.zip$//g'`
+
+#Architecture that the created binaries run on.
+#Use noarch for scripts.
+ARCH=`uname -m`
+
+#from this point on, exit on errors:
+set -e
+
+########Build and create the pacakge.
+#Uncomment the stuff that you dont want or need
+
+#Unpack source 
+#(uncomment if not needed)
+syn3_unpack $SRC_ARC 
+
+#Directory where the sourcefiles are unpacked. 
+#(you might have to adjust this if autodetection fails)
+SRC_DIR=`ls -c|head -1`
+
+#apply patches
+#patch -p1 -d $SRC_DIR < fluxkiosk.patch || exit 1
+
+pushd $SRC_DIR 
+
+#AUTOMAKE: Configure
+#Some usefull stuff you sometimes need to set:
+#export LDFLAGS="-L/usr/X11/lib/ -L/usr/lib/mysql/"
+#export LD_LIBRARY_PATH=/usr/lib/mysql
+#export VPATH=$LD_LIBRARY_PATH
+#export CFLAGS="-std=c89"
+#export CFLAGS="-fgnu89-inline" #If "multiple definition of `foo'" Also see http://gcc.gnu.org/gcc-4.3/porting_to.html
+MAKE_OPTS=""
+./configure --prefix=/usr  || exit 1
+
+#AUTOMAKE: Compile
+make $MAKE_OPTS || exit 1
+
+#AUTOMAKE: Test (optional)
+if grep ^test: Makefile; then
+	make pkgconfigdir=/usr/lib/pkgconfig $MAKE_OPTS install || exit 1
+	make $MAKE_OPTS test || exit 1
+elif grep ^check: Makefile; then
+	make pkgconfigdir=/usr/lib/pkgconfig $MAKE_OPTS install || exit 1
+	make $MAKE_OPTS check || exit 1 
+fi
+
+#AUTOMAKE: Install
+mkdir -p /tmp/pkg &>/dev/null
+make pkgconfigdir=/usr/lib/pkgconfig install_prefix=/tmp/pkg DESTDIR=/tmp/pkg INSTALL_ROOT=/tmp/pkg install_root=/tmp/pkg $MAKE_OPTS install || exit 1
+popd
+
+#strip bins and other stuff
+syn3_strip /tmp/pkg || exit 1
+
+#move development stuff and create seperate development package
+syn3_move_dev /tmp/pkg /tmp/pkgdev || exit 1
+syn3_makepkg /tmp/pkgdev $NAME""_dev $VER $ARCH || exit 1
+
+#make main package
+syn3_makepkg /tmp/pkg $NAME $VER $ARCH || exit 1
+
+
+
Index: npl/overig/checkpassword_pam/checkpassword_pam.arch
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.arch	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+i586
Index: npl/overig/checkpassword_pam/checkpassword_pam.build
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+1
Index: npl/overig/checkpassword_pam/checkpassword_pam.depver
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.depver	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.depver	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+Linux_PAM	1
Index: npl/overig/checkpassword_pam/checkpassword_pam.md5
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,4 @@
+4db3b5f287010ebb4c6e6f3a6c64ce3f  ./checkpassword-pam-0.99.zip
+f3c073ce0798ac5095cd041c6c510362  ./checkpassword_pam.pkg
+6db126a5a8042ef345c64e824a325882  ./checkpassword_pam.SlackBuild
+f227464aad25025b0535c5e6fee3802e  ./checkpassword_pam.SlackBuild.log.gz
Index: npl/overig/checkpassword_pam/checkpassword_pam.version
===================================================================
--- npl/overig/checkpassword_pam/checkpassword_pam.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
+++ npl/overig/checkpassword_pam/checkpassword_pam.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -0,0 +1,1 @@
+0.99
Index: npl/system/openssl/openssl.SlackBuild.orig
===================================================================
--- npl/system/openssl/openssl.SlackBuild.orig	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl.SlackBuild.orig	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,7 +1,7 @@
-#!/bin/sh
+#!/bin/bash
 
 # Copyright 2000 BSDi, Inc. Concord, CA, USA
 # Copyright 2001, 2002 Slackware Linux, Inc.  Concord, CA, USA
-# Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014  Patrick J. Volkerding, Sebeka, MN, USA
+# Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2018  Patrick J. Volkerding, Sebeka, MN, USA
 # All rights reserved.
 #
@@ -23,11 +23,11 @@
 #  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
 # Set initial variables:
-CWD=$(pwd)
+cd $(dirname $0) ; CWD=$(pwd)
 TMP=${TMP:-/tmp}
 
+PKGNAM=openssl
 VERSION=${VERSION:-$(echo openssl-*.tar.gz | rev | cut -f 3- -d . | cut -f 1 -d - | rev)}
-BUILD=${BUILD:-1}
+BUILD=${BUILD:-2}
 
 # Automatically determine the architecture we're building on:
@@ -46,7 +46,15 @@
 NAME2=openssl-solibs-$VERSION-$ARCH-$BUILD
 
+# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
+# the name of the created package would be, and then exit. This information
+# could be useful to other scripts.
+if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
+  echo "${NAME1}.txz"
+  echo "${NAME2}.txz"
+  exit 0
+fi
+
 # Parallel build doesn't link properly.
 #NUMJOBS=${NUMJOBS:--j6}
-NUMJOBS=-j1
 
 # So that ls has the right field counts for parsing...
@@ -63,8 +71,13 @@
 
 # Use .so.1, not .so.1.0.0:
-zcat $CWD/openssl.soname.diff.gz | patch -p1 --backup --verbose --suffix=.orig || exit 1
+sed -i "s/soname=\$\$SHLIB\$\$SHLIB_SOVER\$\$SHLIB_SUFFIX/soname=\$\$SHLIB.1/g" Makefile.shared
+
 if [ "$ARCH" = "i586" ]; then
   # Build with -march=i586 -mtune=i686:
-  zcat $CWD/openssl.optsx86.diff.gz | patch -p1 --backup --verbose --suffix=.orig || exit 1
+  sed -i "/linux-elf/s/fomit-frame-pointer/fomit-frame-pointer -march=i586 -mtune=i686/g" Configure
+  LIBDIRSUFFIX=""
+elif [ "$ARCH" = "i686" ]; then
+  # Build with -march=i686 -mtune=i686:
+  sed -i "/linux-elf/s/fomit-frame-pointer/fomit-frame-pointer -march=i686 -mtune=i686/g" Configure
   LIBDIRSUFFIX=""
 elif [ "$ARCH" = "x86_64" ]; then
@@ -77,7 +90,7 @@
 # what they were compiled against, whether or not the ABI has changed.
 #
-# So, we will use the OPENSSL_VERSION_NUMBER from openssl-1.0.1c unless ABI
+# So, we will use the OPENSSL_VERSION_NUMBER from openssl-1.0.2e unless ABI
 # breakage forces it to change.  Yes, we're finally using this old trick.  :)
-sed -i "s/#define OPENSSL_VERSION_NUMBER.*/\/* Use 0x1000103fL (1.0.1c) below to avoid pointlessly breaking the ABI *\/\n#define OPENSSL_VERSION_NUMBER 0x1000103fL/g" crypto/opensslv.h || exit 1
+sed -i "s/#define OPENSSL_VERSION_NUMBER.*/\/* Use 0x1000205fL (1.0.2e) below to avoid pointlessly breaking the ABI *\/\n#define OPENSSL_VERSION_NUMBER 0x1000205fL/g" crypto/opensslv.h || exit 1
 
 chown -R root:root .
@@ -98,19 +111,28 @@
 # These are the known patent issues with OpenSSL:
 # name   #         expires
-# MDC-2: 4,908,861  2007-03-13, included.  :-)
+# MDC-2: 4,908,861  2007-03-13, not included.
 # IDEA:  5,214,703  2010-05-25, not included.
 # RC5:   5,724,428  2015-03-03, not included.
+#
+# Although all of the above are expired, it's still probably
+# not a good idea to include them as there are better
+# algorithms to use.
 
 ./config \
  --prefix=/usr \
  --openssldir=/etc/ssl \
+ no-mdc2 \
  no-idea \
  no-rc5 \
  no-sse2 \
+ no-ssl2 \
+ no-weak-ssl-ciphers \
  shared
 
-make $NUMJOBS depend || make -j1  depend || exit 1
-
-make $NUMJOBS || make -j 1 || exit 1
+make $NUMJOBS depend || make depend || exit 1
+
+make $NUMJOBS || make || exit 1
+
+make test -j1 || exit 1
 
 make install INSTALL_PREFIX=$PKG1 || exit 1
@@ -144,7 +166,36 @@
 
 mv $PKG1/etc/ssl/man $PKG1/usr
-( cd $PKG1/usr/man/man1 ; mv passwd.1 ssl_passwd.1 )
-( cd $PKG1/usr/man/man3 ; mv rand.3 ssl_rand.3 )
-( cd $PKG1/usr/man/man3 ; mv err.3 ssl_err.3 )
+# Fix manpage name collisions, and relink anything that linked to the old name:
+( cd $PKG1/usr/man/man1
+  mv passwd.1 ssl_passwd.1
+  for file in *.1 ; do
+    if [ -L $file ]; then
+      if [ "$(readlink $file)" = "passwd.1" ]; then
+        rm -f $file
+        ln -sf ssl_passwd.1 $file
+      fi
+    fi
+  done )
+( cd $PKG1/usr/man/man3
+  mv rand.3 ssl_rand.3
+  for file in *.3 ; do
+    if [ -L $file ]; then
+      if [ "$(readlink $file)" = "rand.3" ]; then
+        rm -f $file
+        ln -sf ssl_rand.3 $file
+      fi
+    fi
+  done )
+( cd $PKG1/usr/man/man3
+  mv err.3 ssl_err.3
+  for file in *.3 ; do
+    if [ -L $file ]; then
+      if [ "$(readlink $file)" = "err.3" ]; then
+        rm -f $file
+        ln -sf ssl_err.3 $file
+      fi
+    fi
+  done )
+
 # Compress and symlink the man pages:
 if [ -d $PKG1/usr/man ]; then
Index: npl/system/openssl/openssl.build
===================================================================
--- npl/system/openssl/openssl.build	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-6526
+6528
Index: npl/system/openssl/openssl.md5
===================================================================
--- npl/system/openssl/openssl.md5	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl.md5	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -2,14 +2,12 @@
 1e6908ae51dcc3d1d9d5be0bad6bf803  ./doinst.sh-openssl.gz
 24389791b9e637dff90b350d9ba0e028  ./doinst.sh-openssl-solibs.gz
-130bb19745db2a5a09f22ccbbf7e69d0  ./openssl-1.0.1u.tar.gz
-696ff921e8d4ea2a2ab0105f95eb14a1  ./openssl_dev.pkg
-70d9c041f5c7de50bf5427b7366936f3  ./openssl.optsx86.diff.gz
-103544fe5a3d9606bccdcec53137e449  ./openssl.pkg
+44279b8557c3247cbe324e2322ecd114  ./openssl-1.0.2o.tar.gz
+1e1428b10e4bda1288610a541c0a31fb  ./openssl_dev.pkg
+4ad33ab343bd5cad7c14cd06a21ac109  ./openssl.pkg
 66f195b9f817484bd708cb1c71ea7b51  ./openssl.SlackBuild
-32df63a8e8907c3d0ff387833bc07b17  ./openssl.SlackBuild.log.gz
-5e1eaffc28a65b9108e30e8aed1ed981  ./openssl.SlackBuild.orig
-b3303a5b0c4d92f810ad5676d9d59563  ./openssl.soname.diff.gz
-eee205b1466225d1f33a483e83e6e62b  ./ossllibs_dev.pkg
-003f995b9c404708a03d69118b1ebf01  ./ossllibs.pkg
+504f35e0d315d81bcd2b5595fdfaeda2  ./openssl.SlackBuild.log.gz
+cae6039d35f7acfbbe81c84f24da06d1  ./openssl.SlackBuild.orig
+bda755739fe6595647aae17dc11a1505  ./ossllibs_dev.pkg
+f685f01dfa1d81ff2e055975a08327a9  ./ossllibs.pkg
 c179fc570282afc12c3a6eee101ced0d  ./slack-desc.openssl
 4b7562095ddf28453d54af0ad455a9a5  ./slack-desc.openssl-solibs
Index: npl/system/openssl/openssl.version
===================================================================
--- npl/system/openssl/openssl.version	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-1.0.1u
+1.0.2o
Index: npl/system/openssl/openssl_dev.build
===================================================================
--- npl/system/openssl/openssl_dev.build	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-6526
+6528
Index: npl/system/openssl/openssl_dev.version
===================================================================
--- npl/system/openssl/openssl_dev.version	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/openssl_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-1.0.1u
+1.0.2o
Index: npl/system/openssl/ossllibs.build
===================================================================
--- npl/system/openssl/ossllibs.build	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/ossllibs.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-6526
+6528
Index: npl/system/openssl/ossllibs.version
===================================================================
--- npl/system/openssl/ossllibs.version	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/ossllibs.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-1.0.1u
+1.0.2o
Index: npl/system/openssl/ossllibs_dev.build
===================================================================
--- npl/system/openssl/ossllibs_dev.build	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/ossllibs_dev.build	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-6526
+6528
Index: npl/system/openssl/ossllibs_dev.version
===================================================================
--- npl/system/openssl/ossllibs_dev.version	(revision 94ad01e5261c8d8f3fa81273039ebd3fba801443)
+++ npl/system/openssl/ossllibs_dev.version	(revision a39aa4cd130e528b10cb08b7f1ad03429f123c12)
@@ -1,1 +1,1 @@
-1.0.1u
+1.0.2o
