diff -d -p -P -U 3 -r -N qmail-1.03/Makefile qmail-1.03-bgs/Makefile
--- qmail-1.03/Makefile	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/Makefile	2003-04-14 18:05:59.000000000 +0200
@@ -800,8 +800,8 @@ ipalloc.h ip.h gen_alloc.h exit.h
 it: \
 qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \
 qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \
-predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
-qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
+predate datemail mailsubj qmail-upq qmail-showctl qmail-BGSshowctl qmail-newu \
+qmail-pw2u qmail-qread qmail-qstat qmail-BGSqstat 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 \
@@ -1414,6 +1414,11 @@ warn-auto.sh qmail-qstat.sh conf-qmail c
 	> qmail-qstat
 	chmod 755 qmail-qstat
 
+qmail-BGSqstat: \
+qmail-BGSqstat
+        chmod 755 qmail-BGSqstat
+
+
 qmail-qstat.0: \
 qmail-qstat.8
 	nroff -man qmail-qstat.8 > qmail-qstat.0
@@ -1520,6 +1525,16 @@ auto_patrn.o auto_spawn.o auto_split.o
 	auto_qmail.o auto_break.o auto_patrn.o auto_spawn.o \
 	auto_split.o 
 
+qmail-BGSshowctl: \
+load qmail-BGSshowctl.o auto_uids.o control.o open.a getln.a stralloc.a \
+alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
+auto_patrn.o auto_spawn.o auto_split.o
+	./load qmail-BGSshowctl auto_uids.o control.o open.a getln.a \
+	stralloc.a alloc.a substdio.a error.a str.a fs.a \
+	auto_qmail.o auto_break.o auto_patrn.o auto_spawn.o \
+	auto_split.o 
+
+
 qmail-showctl.0: \
 qmail-showctl.8
 	nroff -man qmail-showctl.8 > qmail-showctl.0
@@ -1531,17 +1546,25 @@ auto_uids.h auto_qmail.h auto_break.h au
 auto_split.h
 	./compile qmail-showctl.c
 
+qmail-BGSshowctl.o: \
+compile qmail-BGSshowctl.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
+	./compile qmail-BGSshowctl.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 \
+open.a sig.a case.a env.a stralloc.a alloc.a strerr.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 \
+	alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
 	socket.lib`
 
 qmail-smtpd.0: \
@@ -1776,7 +1799,7 @@ qreceipt.1 splogger.8 tcp-env.1 config.s
 qmail-clean.c qmail-getpw.c qmail-inject.c qmail-local.c \
 qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \
 qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
-qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
+qmail-qread.c qmail-qstat.sh qmail-BGSqstat 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 \
diff -d -p -P -U 3 -r -N qmail-1.03/README.DELE_access qmail-1.03-bgs/README.DELE_access
--- qmail-1.03/README.DELE_access	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/README.DELE_access	2003-04-14 17:37:09.000000000 +0200
@@ -0,0 +1,27 @@
+
+
+ The DELE_access patch is a very simple patch that allows you some 
+control on users deleting mails. This can be useful in some cases 
+when more than one user is accessing the mailboxes. 
+
+ The usage is very simple. qmail-pop3d checks for the DELE_NOTIFY 
+and DELE_DENY environment variables. If DELE_NOTIFY is set every
+DELE command will be logged with syslog() with LOG_ALERT with the IP
+of the client. If DELE_DENY is set, all DELE commands are denied
+and the attempt is logged like in the DELE_NOTIFY case. In addition
+the contents of the DELE_DENY is returned with the ERR line.
+
+ You can set these parameters through a tcp wrapper like tcpserver.
+With selective tcp settings you can allow for example a single user 
+to remove mail from the common mailboxes. 
+
+ This can also be useful with some mail archive systems like 'march' 
+(check http://bgslinux.info).
+
+This patch is under the GPL license. You can freely use it for non 
+profit purposes. If you use it, please drop me a line.
+
+
+
+Author: Bgs <bgs@bgslinux.info>
+Keywords: qmail dele pop3 deny notify
diff -d -p -P -U 3 -r -N qmail-1.03/README.bgs_bundle qmail-1.03-bgs/README.bgs_bundle
--- qmail-1.03/README.bgs_bundle	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/README.bgs_bundle	2003-04-14 18:03:47.000000000 +0200
@@ -0,0 +1,63 @@
+
+bgs_bundle patch 0.1d
+2003.04.14.
+bgs@bgslinux.info
+http://bgslinux.info
+
+
+ The bgs_bundle patch includes several patches joined to form a
+usefull general patch for a reliable and secure smtp server. Some 
+of the patches are my own, some are gathered from the net or are 
+other's patches modified by me. (For faster scanning I use the
+following notation: * my patch, & other's patch, + other's patch
+modified by me). In addition there are a few little pre-tunings 
+listed after the patches.
+
+ Here is the list of patches:
+
+
+* DELE_access.patch: Read README.DELE_access
+
+* qmail-BGSshowctl.patch: A simple patch to an alternative showctl.
+  (It also shows the newly added controls.)
+
++ tarpit.patch: A tarpitting patch by Chris Johnson
+  <cjohnson-qmail@palomine.net> modified by me. The modification
+  is about a NOTARPIT environtment variable. If set tarpitting is
+  disabled regardless of the tarpitcount/tarpitdelay control files.
+  Usefull for defense, but still allowing some hosts to send bunchmail.
+  
+
++ high_injection_rate.patch: A patch by UNKOWN <opi@nrg4u.com> to limit
+  qmail-send's queue rescan overhead with high injection rate. My 
+  modification is the use of control/minqueuedelay to override the default
+  5 second setting.
+
+& logrelay.patch: Patch by UNKNOWN <UNKNOWN> to log failed relay attempts.
+
+
+
+Tunings:
+
+ - queuelifetime default value changed to 172800 (2 days). In most cases
+   a week without problem notification is way too long. Two days seems 
+   more adequate. (If network is down for more than a day on either sender
+   or recipient side you have bigger problems. A one week delay before 
+   knowing that you mail didn't get there is a much more irritating and
+   more frequent problem).
+
+Scripts :
+(some of the scripts use zsh!)
+
+ * qmail-BGSqstat: alternative qmail-qstat script.
+
+ & qmail-reinject: from UNKNOWN <UNKNOW> move a message from state 5 to 
+   state 4 ie. from preprocessed to queued stat useful when a message is 
+   "stuck" in the wrong queue (local or remote) or to force a delivery 
+   retry usage: 
+
+    qmail-reinject [-v] inode
+
+   reinjects the message int ~qmail/queue/mess/xx/inode
+
+ 
\ No newline at end of file
diff -d -p -P -U 3 -r -N qmail-1.03/README.qmail-reinject qmail-1.03-bgs/README.qmail-reinject
--- qmail-1.03/README.qmail-reinject	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/README.qmail-reinject	2003-04-14 17:37:09.000000000 +0200
@@ -0,0 +1,8 @@
+Taken from the script:
+
+ qmail-reinject: move a message from state 5 to state 4
+ ie from preprocessed to queued stat
+ useful when a message is "stuck" in the wrong queue
+ (local or remote) or to force a delivery retry
+ usage: qmail-reinject [-v] inode
+ reinjects the message int ~qmail/queue/mess/xx/inode
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-BGSqstat qmail-1.03-bgs/qmail-BGSqstat
--- qmail-1.03/qmail-BGSqstat	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/qmail-BGSqstat	2003-04-14 18:02:42.000000000 +0200
@@ -0,0 +1,28 @@
+#!/bin/zsh
+
+QUEUE=/var/qmail/queue
+
+messfiles=$(find $QUEUE/mess/ -type f)
+todofiles=$(find $QUEUE/todo/ -type f)
+
+
+[[ ! -z $messfiles ]] && {
+ messsize=$(du -cs $(echo $messfiles) | tail -1)
+ messsize=$messsize[(w)1];
+} || {
+ messsize=0
+}
+
+
+[[ ! -z $todofiles ]] && {
+ todosize=$(du -cs $(echo $todofiles) | tail -1)
+ todosize=$todosize[(w)1];
+} || {
+ todosize=0
+}
+
+
+echo "number of messages in queue:\t\t\t\t$(($(echo $messfiles|wc -w)))"
+echo "total size of messages in queue (kB):\t\t\t$messsize"
+echo "number of unprocessed messages in queue:\t\t$(($(echo $todofiles| wc -w)))"
+echo "total size of unprocessed messages in queue (kB):\t$todosize"
\ No newline at end of file
Binary files qmail-1.03/qmail-BGSshowctl and qmail-1.03-bgs/qmail-BGSshowctl differ
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-BGSshowctl.c qmail-1.03-bgs/qmail-BGSshowctl.c
--- qmail-1.03/qmail-BGSshowctl.c	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/qmail-BGSshowctl.c	2003-04-14 17:38:01.000000000 +0200
@@ -0,0 +1,270 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+#include "fmt.h"
+#include "str.h"
+#include "control.h"
+#include "constmap.h"
+#include "stralloc.h"
+#include "direntry.h"
+#include "auto_uids.h"
+#include "auto_qmail.h"
+#include "auto_break.h"
+#include "auto_patrn.h"
+#include "auto_spawn.h"
+#include "auto_split.h"
+
+stralloc me = {0};
+int meok;
+
+stralloc line = {0};
+char num[FMT_ULONG];
+
+void safeput(buf,len)
+char *buf;
+unsigned int len;
+{
+  char ch;
+
+  while (len > 0) {
+    ch = *buf;
+    if ((ch < 32) || (ch > 126)) ch = '?';
+    substdio_put(subfdout,&ch,1);
+    ++buf;
+    --len;
+  }
+}
+
+void do_int(fn,def,pre,post)
+char *fn;
+char *def;
+char *pre;
+char *post;
+{
+  int i;
+  substdio_puts(subfdout,"\n");
+  substdio_puts(subfdout,fn);
+  substdio_puts(subfdout,": ");
+  switch(control_readint(&i,fn)) {
+    case 0:
+      substdio_puts(subfdout,"(Default.) ");
+      substdio_puts(subfdout,pre);
+      substdio_puts(subfdout,def);
+      substdio_puts(subfdout,post);
+      substdio_puts(subfdout,".\n");
+      break;
+    case 1:
+      if (i < 0) i = 0;
+      substdio_puts(subfdout,pre);
+      substdio_put(subfdout,num,fmt_uint(num,i));
+      substdio_puts(subfdout,post);
+      substdio_puts(subfdout,".\n");
+      break;
+    default:
+      substdio_puts(subfdout,"Oops! Trouble reading this file.\n");
+      break;
+  }
+}
+
+void do_str(fn,flagme,def,pre)
+char *fn;
+int flagme;
+char *def;
+char *pre;
+{
+  substdio_puts(subfdout,"\n");
+  substdio_puts(subfdout,fn);
+  substdio_puts(subfdout,": ");
+  switch(control_readline(&line,fn)) {
+    case 0:
+      substdio_puts(subfdout,"(Default.) ");
+      if (!stralloc_copys(&line,def)) {
+	substdio_puts(subfdout,"Oops! Out of memory.\n");
+	break;
+      }
+      if (flagme && meok)
+	if (!stralloc_copy(&line,&me)) {
+	  substdio_puts(subfdout,"Oops! Out of memory.\n");
+	  break;
+	}
+    case 1:
+      substdio_puts(subfdout,pre);
+      safeput(line.s,line.len);
+      substdio_puts(subfdout,".\n");
+      break;
+    default:
+      substdio_puts(subfdout,"Oops! Trouble reading this file.\n");
+      break;
+  }
+}
+
+int do_lst(fn,def,pre,post)
+char *fn;
+char *def;
+char *pre;
+char *post;
+{
+  int i;
+  int j;
+
+  substdio_puts(subfdout,"\n");
+  substdio_puts(subfdout,fn);
+  substdio_puts(subfdout,": ");
+  switch(control_readfile(&line,fn)) {
+    case 0:
+      substdio_puts(subfdout,"(Default.) ");
+      substdio_puts(subfdout,def);
+      substdio_puts(subfdout,"\n");
+      return 0;
+    case 1:
+      substdio_puts(subfdout,"\n");
+      i = 0;
+      for (j = 0;j < line.len;++j)
+	if (!line.s[j]) {
+          substdio_puts(subfdout,pre);
+          safeput(line.s + i,j - i);
+          substdio_puts(subfdout,post);
+          substdio_puts(subfdout,"\n");
+	  i = j + 1;
+	}
+      return 1;
+    default:
+      substdio_puts(subfdout,"Oops! Trouble reading this file.\n");
+      return -1;
+  }
+}
+
+void main()
+{
+  DIR *dir;
+  direntry *d;
+  struct stat stmrh;
+  struct stat stmrhcdb;
+
+  if (chdir(auto_qmail) == -1) {
+    substdio_puts(subfdout,"Oops! Unable to chdir to ");
+    substdio_puts(subfdout,auto_qmail);
+    substdio_puts(subfdout,".\n");
+    substdio_flush(subfdout);
+    _exit(111);
+  }
+  if (chdir("control") == -1) {
+    substdio_puts(subfdout,"Oops! Unable to chdir to control.\n");
+    substdio_flush(subfdout);
+    _exit(111);
+  }
+
+  dir = opendir(".");
+  if (!dir) {
+    substdio_puts(subfdout,"Oops! Unable to open current directory.\n");
+    substdio_flush(subfdout);
+    _exit(111);
+  }
+
+  meok = control_readline(&me,"me");
+  if (meok == -1) {
+    substdio_puts(subfdout,"Oops! Trouble reading control/me.");
+    substdio_flush(subfdout);
+    _exit(111);
+  }
+
+  substdio_puts(subfdout,"\n\tCurrent server configuration:\n");
+  substdio_flush(subfdout);
+          
+
+  do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM.");
+  do_lst("badmailto","Any RCPT TO is allowed.",""," not accepted in RCPT TO.");
+  do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is ");
+  do_str("bouncehost",1,"bouncehost","Bounce host name is ");
+  do_int("concurrencylocal","10","Local concurrency is ","");
+  do_int("concurrencyremote","20","Remote concurrency is ","");
+  do_int("databytes","0","SMTP DATA limit is "," bytes");
+  do_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: ");
+  do_str("doublebounceto",0,"postmaster","2B recipient user: ");
+  do_str("envnoathost",1,"envnoathost","Presumed domain name is ");
+  do_str("helohost",1,"helohost","SMTP client HELO host name is ");
+  do_str("idhost",1,"idhost","Message-ID host name is ");
+  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("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: ",".");
+  do_int("queuedelay","5","Minimal time between queue reruns: "," seconds");
+  do_int("queuelifetime","172800","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 ",".");
+  else
+    do_lst("morercpthosts","No rcpthosts; morercpthosts is irrelevant.","No rcpthosts; doesn't matter that morercpthosts has ",".");
+  /* XXX: check morercpthosts.cdb contents */
+  substdio_puts(subfdout,"\nmorercpthosts.cdb: ");
+  if (stat("morercpthosts",&stmrh) == -1)
+    if (stat("morercpthosts.cdb",&stmrhcdb) == -1)
+      substdio_puts(subfdout,"(Default.) No effect.\n");
+    else
+      substdio_puts(subfdout,"Oops! morercpthosts.cdb exists but morercpthosts doesn't.\n");
+  else
+    if (stat("morercpthosts.cdb",&stmrhcdb) == -1)
+      substdio_puts(subfdout,"Oops! morercpthosts exists but morercpthosts.cdb doesn't.\n");
+    else
+      if (stmrh.st_mtime > stmrhcdb.st_mtime)
+        substdio_puts(subfdout,"Oops! morercpthosts.cdb is older than morercpthosts.\n");
+      else
+        substdio_puts(subfdout,"Modified recently enough; hopefully up to date.\n");
+
+  do_str("smtpgreeting",1,"smtpgreeting","SMTP greeting: 220 ");
+  do_lst("smtproutes","No artificial SMTP routes.","SMTP route: ","");
+  do_int("tarpitcount","Tarpitting not enabled.", "Tarpitting triggered at: ", "");
+  do_int("tarpitdelay", "5", "Tarpitting delay set to: ", "seconds");
+  do_int("timeoutconnect","60","SMTP client connection timeout is "," seconds");
+  do_int("timeoutremote","1200","SMTP client data timeout is "," seconds");
+  do_int("timeoutsmtpd","1200","SMTP server data timeout is "," seconds");
+  do_lst("virtualdomains","No virtual domains.","Virtual domain: ","");
+
+  while (d = readdir(dir)) {
+    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,"concurrencylocal")) continue;
+    if (str_equal(d->d_name,"concurrencyremote")) continue;
+    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,"doublebouncehost")) continue;
+    if (str_equal(d->d_name,"doublebounceto")) continue;
+    if (str_equal(d->d_name,"envnoathost")) 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;
+    if (str_equal(d->d_name,"locals")) continue;
+    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,"percenthack")) continue;
+    if (str_equal(d->d_name,"plusdomain")) 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;
+    if (str_equal(d->d_name,"smtpgreeting")) continue;
+    if (str_equal(d->d_name,"smtproutes")) continue;
+    if (str_equal(d->d_name,"timeoutconnect")) continue;
+    if (str_equal(d->d_name,"timeoutremote")) continue;
+    if (str_equal(d->d_name,"timeoutsmtpd")) continue;
+    if (str_equal(d->d_name,"virtualdomains")) continue;
+    substdio_puts(subfdout,"\n");
+    substdio_puts(subfdout,d->d_name);
+    substdio_puts(subfdout,": I have no idea what this file does.\n");
+  }
+
+  substdio_flush(subfdout);
+  _exit(0);
+}
Binary files qmail-1.03/qmail-BGSshowctl.o and qmail-1.03-bgs/qmail-BGSshowctl.o differ
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-control.9 qmail-1.03-bgs/qmail-control.9
--- qmail-1.03/qmail-control.9	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-control.9	2003-04-14 17:37:09.000000000 +0200
@@ -55,6 +55,7 @@ control	default	used by
 .I idhost	\fIme	\fRqmail-inject
 .I localiphost	\fIme	\fRqmail-smtpd
 .I locals	\fIme	\fRqmail-send
+.I minqueuedelay	\fR2	\fRqmail-send
 .I morercpthosts	\fR(none)	\fRqmail-smtpd
 .I percenthack	\fR(none)	\fRqmail-send
 .I plusdomain	\fIme	\fRqmail-inject
@@ -63,6 +64,8 @@ control	default	used by
 .I rcpthosts	\fR(none)	\fRqmail-smtpd
 .I smtpgreeting	\fIme	\fRqmail-smtpd
 .I smtproutes	\fR(none)	\fRqmail-remote
+.I tarpitcount	\fR0	\fRqmail-smtpd
+.I tarpitdelay	\fR5	\fRqmail-smtpd
 .I timeoutconnect	\fR60	\fRqmail-remote
 .I timeoutremote	\fR1200	\fRqmail-remote
 .I timeoutsmtpd	\fR1200	\fRqmail-smtpd
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-pop3d.8 qmail-1.03-bgs/qmail-pop3d.8
--- qmail-1.03/qmail-pop3d.8	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-pop3d.8	2003-04-14 17:37:09.000000000 +0200
@@ -37,6 +37,25 @@ to work around serious bugs in certain c
 
 .B qmail-pop3d
 is based on a program contributed by Russ Nelson.
+
+.B qmail-pop3d
+sends a notification through syslog with
+.IR LOG_ALERT
+if the environment variable
+.IR DELE_NOTIFY
+is set.
+
+.B qmail-pop3d
+denies DELE commands (delete mail) if the environment variable
+.IR DELE_DENY
+is set. It sends a log through syslog (similar to 
+.IR DELE_NOTIFY )
+and returns an 
+.IR -ERR 
+to the client with the contents of 
+.IR DELE_DENY .
+
+
 .SH "SEE ALSO"
 maildir(5),
 qmail-local(8),
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-pop3d.c qmail-1.03-bgs/qmail-pop3d.c
--- qmail-1.03/qmail-pop3d.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-pop3d.c	2003-04-14 17:37:09.000000000 +0200
@@ -1,5 +1,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <syslog.h>
+#include <stdlib.h>
 #include "commands.h"
 #include "sig.h"
 #include "getln.h"
@@ -17,6 +19,7 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 
+
 void die() { _exit(0); }
 
 int saferead(fd,buf,len) int fd; char *buf; int len;
@@ -212,8 +215,19 @@ void pop3_dele(arg) char *arg;
   int i;
   i = msgno(arg);
   if (i == -1) return;
-  m[i].flagdeleted = 1;
+if ((getenv("DELE_DENY")) == NULL) { 
+  m[i].flagdeleted = 1; 
+ } else {
+  openlog("qmail-pop3d",0,LOG_MAIL);
+  syslog(LOG_ALERT, "DELE denied for user from %s", getenv("TCPREMOTEIP"));  
+  err(getenv("DELE_DENY"));
+ }
   if (i + 1 > last) last = i + 1;
+if ((getenv("DELE_NOTIFY")) != NULL) {
+  openlog("qmail-pop3d",0,LOG_MAIL);
+  syslog(LOG_ALERT, "User from %s issued DELE command !", getenv("TCPREMOTEIP"));  
+  closelog();
+ }
   okay();
 }
 
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-reinject qmail-1.03-bgs/qmail-reinject
--- qmail-1.03/qmail-reinject	1970-01-01 01:00:00.000000000 +0100
+++ qmail-1.03-bgs/qmail-reinject	2003-04-14 17:37:09.000000000 +0200
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# qmail-reinject: move a message from state 5 to state 4
+# ie from preprocessed to queued stat
+# useful when a message is "stuck" in the wrong queue 
+# (local or remote) or to force a delivery retry
+# usage: qmail-reinject [-v] inode
+# reinjects the message int ~qmail/queue/mess/xx/inode
+#
+
+function die() {
+  rm -f "$1"; shift
+  echo ${1+"$@"}
+  exit 1
+}
+
+if [ "$1" = "-v" ]; then
+  v=verbose
+  shift;
+fi
+if [ $# = 0 ]; then
+  echo usage: fixit [options] inode
+  echo options: -v verbose
+  exit
+fi
+q=/opt/qmail/queue
+u=$UID
+i=$1; echo $i | grep [^0-9] &>/dev/null && die "" "'$i' is not an inode"
+p=$$
+if [ -n "$v" ]; then
+  echo my uid is $UID and my pid is $p
+  echo looking for message with inode $i
+fi
+F=$(cat $q/info/*/$i 2>/dev/null); [ -z "$F" ] && die "" bogus F
+T=$(cat $q/remote/*/$i 2>/dev/null); [ -z "$F" ] && die "" bogus T
+r=$(echo $q/mess/*/$i | sed "s@^$q/mess/@@;s@/$i@@"); [ -f $q/mess/$r/$i ] || die "" "Can't find mess subdirectory"
+w=$(echo $q/local}/$r/$i | sed "s@^$q/@@;s@/$r/$i@@")
+[ -f $q/$q/$r/$i ] || w=$(echo $q/remote/$r/$i | sed "s@^$q/@@;s@/$r/$i@@")
+[ -f $q/$w/$r/$i ] || die "" "Can't find local or remote (looking for '$w')"
+if [ -n "$v" ]; then
+  echo message lives in mess/$r
+  echo from ${F##F} to ${T##T}
+fi
+
+# make todo
+[ -n "$v" ] && echo writing pid/$p
+printf 'u%s\0p%s\0%s\0%s\0' $u $p $F $T > $q/pid/$p
+[ $? = 0 ] || die $q/pid/$p failed to create todo
+[ -n "$v" ] && echo changing permission of pid/$p to 644 qmailq.users
+chown qmailq.users $q/pid/$p && chmod 644 $q/pid/$p
+[ $? = 0 ] || die $q/pid/$p failed to set ownership of todo
+[ -n "$v" ] && echo linking pid/$p to todo/$r/$p
+ln $q/pid/$p $q/todo/$r/$i
+[ $? = 0 ] || die $q/pid/$p failed to link todo
+[ -n "$v" ] && echo unlinking pid/$p
+rm $q/pid/$p
+
+# make intd
+[ -n "$v" ] && echo copying todo/$r/$p to intd/$r/$i
+cp -p $q/todo/$r/$i $q/intd/$r/$i
+[ $? = 0 ] || die "" failed to create intd
+
+# lose info and remote
+[ -n "$v" ] && echo unlinking info/$r/$i and $w/$r/$i
+rm -f $q/info/$r/$i $q/$w/$r/$i
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-send.9 qmail-1.03-bgs/qmail-send.9
--- qmail-1.03/qmail-send.9	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-send.9	2003-04-14 17:37:09.000000000 +0200
@@ -147,6 +147,14 @@ is considered local if
 is listed in
 .IR locals .
 .TP 5
+.I minqueuedelay
+Minimum time before
+.B qmail-send 
+is allowed to re-run the queue, regardless to
+new incoming mail. Default:
+.IR 2
+seconds.
+.TP 5
 .I percenthack
 List of domain names where the percent hack is applied.
 If
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-send.c qmail-1.03-bgs/qmail-send.c
--- qmail-1.03/qmail-send.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-send.c	2003-04-14 17:37:09.000000000 +0200
@@ -36,13 +36,15 @@
 /* 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 ONCEEVERY 10 /* run todo maximal once every N seconds */
 #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_CLEANUP 76431 /* time between cleanups */
 #define SLEEP_SYSFAIL 123
 #define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24 hours) */
 
-int lifetime = 604800;
+int lifetime = 172800;
+int minqueuedelay = 2;
 
 stralloc percenthack = {0};
 struct constmap mappercenthack;
@@ -1215,7 +1217,7 @@ void pass_do()
 
 /* this file is too long ---------------------------------------------- TODO */
 
-datetime_sec nexttodorun;
+datetime_sec nexttodorun, lasttodorun;
 DIR *tododir; /* if 0, have to opendir again */
 stralloc todoline = {0};
 char todobuf[SUBSTDIO_INSIZE];
@@ -1225,6 +1227,7 @@ char todobufchan[CHANNELS][1024];
 void todo_init()
 {
  tododir = 0;
+ lasttodorun = 0;
  nexttodorun = now();
  trigger_set();
 }
@@ -1265,6 +1268,39 @@ fd_set *rfds;
 
  if (flagexitasap) return;
 
+ /*
+  * qmail normally does a queue run for every injected message and then
+  * schedules it for local/remote delivery.
+  * If we get too many injections the queue runs will stall scheduling
+  * of local/remote deliveries. Usually we see a sharp drop in concurrent
+  * deliveries while new messages arrive at high rate in the queue.
+  * In such a situation it doesn't make sense to process the queue after
+  * each and every injection. It is more important to fill the delivery
+  * slots with work to drain the queue.
+  * This patch will allow for only one queue run every N seconds. It
+  * remembers the last complete queue run and will just return if we
+  * get triggered before last queue run plus N seconds. If we get
+  * triggered before N seconds it will schedule a forced queue run at
+  * last complete queue run plus N seconds to not miss the new additions
+  * to the queue.
+  * Some more thoughts:
+  *  - This is proof of concept and should be made at least dynamically
+  *    configureable through a control file (and reread with -HUP)
+  *  - This could even be made selftuning by measuring the time it takes
+  *    to do a queue run and do the run delay only after a certain
+  *    threshold has been reached
+  *  - the optimal values for delaying have to found
+  *
+  *  20011108, Initial revision, opi@nrg4u.com
+  */
+
+ /* run todo maximal once every N seconds */
+ if (recent < (lasttodorun + minqueuedelay))
+  {
+   nexttodorun = lasttodorun + minqueuedelay; /* do this to wake us up in N secs */
+   return; /* skip todo run this time */
+  }
+
  if (!tododir)
   {
    if (!trigger_pulled(rfds))
@@ -1277,6 +1313,7 @@ fd_set *rfds;
      pausedir("todo");
      return;
     }
+   lasttodorun = recent;
    nexttodorun = recent + SLEEP_TODO;
   }
 
@@ -1443,6 +1480,7 @@ fd_set *rfds;
 
 int getcontrols() { if (control_init() == -1) return 0;
  if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0;
+ if (control_readint(&minqueuedelay,"control/minqueuedelay") == -1) return 0;
  if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0;
  if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0;
  if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-smtpd.8 qmail-1.03-bgs/qmail-smtpd.8
--- qmail-1.03/qmail-smtpd.8	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-smtpd.8	2003-04-14 17:37:09.000000000 +0200
@@ -164,6 +164,24 @@ The first word of
 .I smtpgreeting
 should be the current host's name.
 .TP 5
+.I tarpitcount
+Number of 
+.IR RCPT 
+.IR TO:
+commands before 
+.IR tarpidelay
+starts delaying additional rcpts. Zero means disabled. The NOTARPIT
+environment variable overrides a non-zero 
+.IR tarpitcount
+Default:
+.IR 0
+.TP 5
+.IR tarpitdelay
+Wait this many seconds between 
+.IR RCPT
+.IR TO:
+commands if tarpitting is triggered.
+.TP 5
 .I timeoutsmtpd
 Number of seconds
 .B qmail-smtpd
diff -d -p -P -U 3 -r -N qmail-1.03/qmail-smtpd.c qmail-1.03-bgs/qmail-smtpd.c
--- qmail-1.03/qmail-smtpd.c	1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03-bgs/qmail-smtpd.c	2003-04-14 17:37:09.000000000 +0200
@@ -1,3 +1,4 @@
+#include <stdlib.h>
 #include "sig.h"
 #include "readwrite.h"
 #include "stralloc.h"
@@ -23,6 +24,7 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "strerr.h"
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -96,6 +98,8 @@ stralloc liphost = {0};
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
+int tarpitcount = 0;
+int tarpitdelay = 5;
 
 void setup()
 {
@@ -110,6 +114,15 @@ void setup()
   if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
   if (timeout <= 0) timeout = 1;
 
+  if (control_readint(&tarpitcount,"control/tarpitcount") == -1) die_control();
+  if (tarpitcount < 0) tarpitcount = 0;
+  x = env_get("TARPITCOUNT");
+  if (x) { scan_ulong(x,&u); tarpitcount = u; };
+  if (control_readint(&tarpitdelay,"control/tarpitdelay") == -1) die_control();
+  if (tarpitdelay < 0) tarpitdelay = 0;
+  x = env_get("TARPITDELAY");
+  if (x) { scan_ulong(x,&u); tarpitdelay = u; };
+
   if (rcpthosts_init() == -1) die_control();
 
   bmfok = control_readfile(&bmf,"control/badmailfrom",0);
@@ -221,6 +234,7 @@ int seenmail = 0;
 int flagbarf; /* defined if seenmail */
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
+int rcptcount;
 
 void smtp_helo(arg) char *arg;
 {
@@ -245,6 +259,7 @@ void smtp_mail(arg) char *arg;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
   if (!stralloc_0(&mailfrom)) die_nomem();
+  rcptcount = 0;
   out("250 ok\r\n");
 }
 void smtp_rcpt(arg) char *arg; {
@@ -257,10 +272,15 @@ void smtp_rcpt(arg) char *arg; {
     if (!stralloc_0(&addr)) die_nomem();
   }
   else
-    if (!addrallowed()) { err_nogateway(); return; }
+    if (!addrallowed()) {
+      strerr_warn6("qmail-smtpd: Attempted relay from ",mailfrom.s," at ",remoteip," to ",addr.s,0);
+      err_nogateway();
+      return;
+  }
   if (!stralloc_cats(&rcptto,"T")) die_nomem();
   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
   if (!stralloc_0(&rcptto)) die_nomem();
+  if ((tarpitcount && ++rcptcount >= tarpitcount) && (getenv("NOTARPIT") == NULL) ) while (sleep(tarpitdelay)); 
   out("250 ok\r\n");
 }
 
