Upstream qmail 1.03 djb djb/1.03
authorMark Wooding <mdw@distorted.org.uk>
Sun, 28 Jun 1998 14:46:53 +0000 (15:46 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 13 Feb 2006 23:55:29 +0000 (23:55 +0000)
152 files changed:
BIN.Makefile [new file with mode: 0644]
BIN.README [new file with mode: 0644]
BLURB2
BLURB3
BLURB4
CHANGES
FAQ
FILES
INSTALL
INSTALL.alias
INSTALL.boot [deleted file]
INSTALL.ctl
INSTALL.ids
INSTALL.maildir [new file with mode: 0644]
INSTALL.mbox
INSTALL.qsmhook [deleted file]
INSTALL.vsm [new file with mode: 0644]
INTERNALS
Makefile
PIC.local2alias [new file with mode: 0644]
PIC.local2ext [new file with mode: 0644]
PIC.local2local [new file with mode: 0644]
PIC.local2rem [new file with mode: 0644]
PIC.local2virt [new file with mode: 0644]
PIC.nullclient [new file with mode: 0644]
PIC.relaybad [new file with mode: 0644]
PIC.relaygood [new file with mode: 0644]
PIC.rem2local [new file with mode: 0644]
README
REMOVE.binmail [new file with mode: 0644]
REMOVE.sendmail [new file with mode: 0644]
RFCHCSC [deleted file]
RFCLOOPS [deleted file]
RFCMXPS [deleted file]
RFCNETSTR [deleted file]
RFCNRUDT [deleted file]
RFCQMTP [deleted file]
RFCQSBMF [deleted file]
RFCVERP [deleted file]
SECURITY
SENDMAIL [new file with mode: 0644]
TARGETS
TEST.deliver [new file with mode: 0644]
TEST.receive [new file with mode: 0644]
THANKS
THOUGHTS
TODO
UPGRADE
VERSION
binm1+df.sh [new file with mode: 0644]
binm1.sh [new file with mode: 0644]
binm2+df.sh [new file with mode: 0644]
binm2.sh [new file with mode: 0644]
binm3+df.sh [new file with mode: 0644]
binm3.sh [new file with mode: 0644]
bouncesaying.1 [new file with mode: 0644]
bouncesaying.c [new file with mode: 0644]
commands.c [new file with mode: 0644]
commands.h [new file with mode: 0644]
condredirect.1
condredirect.c
conf-patrn
conf-qmail
config-fast.sh [new file with mode: 0644]
config.sh [moved from qmail-config.sh with 100% similarity]
constmap.c
constmap.h
control.c
dns.c
dot-qmail.9
except.1 [new file with mode: 0644]
except.c [new file with mode: 0644]
forgeries.7
forward.c
hfield.c
hfield.h
hier.c [new file with mode: 0644]
home+df.sh [new file with mode: 0644]
home.sh [new file with mode: 0644]
idedit.c [new file with mode: 0644]
install-big.c [new file with mode: 0644]
install.c
instcheck.c
maildir.5
maildirmake.c
ndelay.c
ndelay_off.c
predate.c
preline.c
proc+df.sh [new file with mode: 0644]
proc.sh [new file with mode: 0644]
qlist.1 [deleted file]
qlist.c [deleted file]
qlist2.sh [deleted file]
qmail-command.8
qmail-control.9
qmail-getpw.9
qmail-getpw.c
qmail-header.5
qmail-hier.c [deleted file]
qmail-inject.8
qmail-inject.c
qmail-local.8
qmail-local.c
qmail-log.5
qmail-lspawn.8
qmail-newmrh.9 [new file with mode: 0644]
qmail-newmrh.c [new file with mode: 0644]
qmail-pop3d.8
qmail-pop3d.c
qmail-popup.c
qmail-pw2u.9
qmail-pw2u.c
qmail-qmqpc.8 [new file with mode: 0644]
qmail-qmqpc.c [new file with mode: 0644]
qmail-qmqpd.8 [new file with mode: 0644]
qmail-qmqpd.c [new file with mode: 0644]
qmail-qmtpd.8
qmail-qmtpd.c
qmail-qstat.sh
qmail-queue.8
qmail-queue.c
qmail-remote.8
qmail-remote.c
qmail-send.9
qmail-send.c
qmail-showctl.c
qmail-smtpd.8
qmail-smtpd.c
qmail-start.9
qmail-tcpok.8 [new file with mode: 0644]
qmail-tcpok.c [new file with mode: 0644]
qmail-tcpto.8
qmail-upgrade.9 [deleted file]
qmail.7
qmail.c
qmail.h
qreceipt.c
quote.c
rcpthosts.c [new file with mode: 0644]
rcpthosts.h [new file with mode: 0644]
remoteinfo.c
scan_nbblong.c [deleted file]
sendmail.c
slurpclose.c
substdio.h
timeoutread.c
timeoutread.h
timeoutwrite.c
timeoutwrite.h
token822.c
wait_pid.c

diff --git a/BIN.Makefile b/BIN.Makefile
new file mode 100644 (file)
index 0000000..f46c537
--- /dev/null
@@ -0,0 +1,24 @@
+SHELL=/bin/sh
+
+# Files are edited in the installation directory, then copied.
+# There are 40 arguments to idedit after the filename,
+# showing the positions of each byte in the following ten ints:
+# uida, uidd, uidl, uido, uidp, uidq, uidr, uids, gidq, gidn.
+# Normal little-endian positions are n n+1 n+2 ... n+39 for some n.
+# Normal big-endian positions are n+3 n+2 n+1 n n+7 ... n+36 for some n.
+
+setup:
+       mkdir /var/qmail
+       ./idedit install-big XXX
+       ./idedit qmail-lspawn XXX
+       ./idedit qmail-queue XXX
+       ./idedit qmail-rspawn XXX
+       ./idedit qmail-showctl XXX
+       ./idedit qmail-start XXX
+       ./install-big
+       cp /var/qmail/boot/binm1+df /var/qmail/rc
+       chmod 755 /var/qmail/rc
+       echo '|fastforward -d /etc/aliases.cdb' > /var/qmail/alias/.qmail-default
+       chmod 644 /var/qmail/alias/.qmail-default
+       hostname | grep -q '\.'
+       ./config-fast `hostname`
diff --git a/BIN.README b/BIN.README
new file mode 100644 (file)
index 0000000..6beeee1
--- /dev/null
@@ -0,0 +1,19 @@
+Like any other piece of software (and information generally), qmail
+comes with NO WARRANTY.
+
+Configuration: The qmail home directory is /var/qmail. (This must be a
+local directory, not shared among machines. Under Linux, make sure that
+all mail-handling filesystems are mounted with synchronous metadata.)
+The user-ext delimiter is -. The silent concurrency limit is 120. The
+queue subdirectory split is 23.
+
+To install:
+       # make setup
+
+To set up qmail to receive and deliver mail, follow the instructions in
+/var/qmail/doc/fastforward/ALIASES, and then start at step 9 of
+/var/qmail/doc/INSTALL.
+
+Compilation environment: Oops, the package creator forgot to edit this!
+He's supposed to list his OS version, compiler version, hardware, and
+name.
diff --git a/BLURB2 b/BLURB2
index a63f21c..1a98d0e 100644 (file)
--- a/BLURB2
+++ b/BLURB2
@@ -16,11 +16,11 @@ out-of-the-box configuration.
 
 * qmail automatically prevents mailing list loops, even across hosts.
 
-* qlist, included in the qmail package, deals with subscription requests
-safely and automatically.
-
 * qmail allows inconceivably gigantic mailing lists. No random limits.
 
 * qmail handles aliasing and forwarding with the same simple mechanism.
 For example, Postmaster is controlled by ~alias/.qmail-postmaster. This
 means that cross-host loop detection also applies to aliases.
+
+* qmail supports the ezmlm mailing list manager, which easily and
+automatically handles bounces, subscription requests, and archives.
diff --git a/BLURB3 b/BLURB3
index db3b699..5f8af6d 100644 (file)
--- a/BLURB3
+++ b/BLURB3
@@ -3,7 +3,7 @@ Here are some of qmail's features.
 Setup:
 *  automatic adaptation to your UNIX variant---no configuration needed
 *  AIX, BSD/OS, FreeBSD, HP/UX, Irix, Linux, OSF/1, SunOS, Solaris, and more
-*  automatic per-host configuration (qmail-config)
+*  automatic per-host configuration (config, config-fast)
 *  quick installation---no big list of decisions to make
 
 Security:
@@ -16,11 +16,12 @@ Security:
 Message construction (qmail-inject):
 *  RFC 822, RFC 1123
 *  full support for address groups
-*  automatic conversion of old-style headers to RFC 822 format
+*  automatic conversion of old-style address lists to RFC 822 format
+*  sendmail hook for compatibility with current user agents
 *  header line length limited only by memory
 *  host masquerading (control/defaulthost)
-*  user masquerading (MAILUSER, MAILHOST)
-*  sendmail hook for compatibility with current user agents
+*  user masquerading ($MAILUSER, $MAILHOST)
+*  automatic Mail-Followup-To creation ($QMAILMFTFILE)
 
 SMTP service (qmail-smtpd):
 *  RFC 821, RFC 1123, RFC 1651, RFC 1652, RFC 1854
@@ -67,11 +68,13 @@ SMTP delivery (qmail-remote):
 
 Forwarding and mailing lists (qmail-local):
 *  address wildcards (.qmail-default, .qmail-foo-default, etc.)
-*  sendmail/smail /etc/aliases compatibility (qmsmac, available separately)
+*  sendmail .forward compatibility (dot-forward, available separately)
+*  fast forwarding databases (fastforward, available separately)
+*  sendmail /etc/aliases compatibility (fastforward/newaliases)
 *  mailing list owners---automatically divert bounces and vacation messages
 *  VERPs---automatic recipient identification for mailing list bounces
 *  Delivered-To---automatic loop prevention, even across hosts
-*  automatic subscription management (qlist)
+*  automatic mailing list management (ezmlm, available separately)
 
 Local delivery (qmail-local):
 *  user-controlled address hierarchy---fred controls fred-anything
@@ -80,7 +83,7 @@ Local delivery (qmail-local):
 *  user-controlled program delivery: procmail etc. (qmail-command)
 *  optional new-mail notification (qbiff)
 *  optional NRUDT return receipts (qreceipt)
-*  conditional filtering (condredirect)
+*  conditional filtering (condredirect, bouncesaying)
 
 POP3 service (qmail-popup, qmail-pop3d):
 *  RFC 1939
diff --git a/BLURB4 b/BLURB4
index 35d2cd3..6c4eaac 100644 (file)
--- a/BLURB4
+++ b/BLURB4
@@ -4,7 +4,7 @@ against the competition in five different speed measurements.
 
 * Scheduling: I sent a message to 8192 ``trash'' recipients on my home
 machine. All the deliveries were done in a mere 78 seconds---a rate of
-over 9 MILLION deliveries a day! Compare this to the speed advertised
+over 9 million deliveries a day! Compare this to the speed advertised
 for Zmailer's scheduling: 1.1 million deliveries a day on a
 SparcStation-10/50. (My home machine is a 16MB Pentium-100 under BSD/OS,
 with the default qmail configuration. qmail's logs were piped through
@@ -14,7 +14,7 @@ accustamp and written to disk as usual.)
 it physically writes the message to disk before it announces success---
 that way, mail doesn't get lost if the power goes out. I tried sending a
 message to 1024 local mailboxes on the same disk on my home machine; all
-the deliveries were done in 25.5 seconds. That's more than 3.4 MILLION
+the deliveries were done in 25.5 seconds. That's more than 3.4 million
 deliveries a day! Sending 1024 copies to a _single_ mailbox was just as
 fast. Compare these figures to Zmailer's advertised rate for throwing
 recipients away without even delivering the message---only 0.48 million
diff --git a/CHANGES b/CHANGES
index 6abdaf3..6bfa516 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,259 @@
+19980615 version: qmail 1.03.
+19980614 doc: eliminated BIN.setup in favor of a web page.
+19980614 code: added other auto* to qmail-showctl output.
+19980614 doc: added pointer to immhf.html in qmail-header.5.
+19980614 doc: added note to TEST.receive about SMTP command format.
+19980614 doc: added FAQ 5.6 on qmail-qmqpd.
+19980614 code: removed unused variables in idedit.c.
+19980613 code: changed conf-patrn to 002.
+19980613 doc: moved SENDMAIL lower in INSTALL.
+19980612 code: added install-big.
+19980612 code: added BIN.Makefile.
+19980612 doc: added BIN.README, BIN.setup.
+19980612 code: switched to new install.
+19980611 code: added idedit.
+19980611 doc: added FAQ 1.3 on $QMAILMFTFILE.
+19980611 doc: used bouncesaying in FAQ 5.5.
+19980611 code: added except.
+19980611 code: added bouncesaying.
+19980611 code: allowed unbracketed IP addresses in dns_ipplus() and
+         dns_mxip().
+19980611 code: allowed spaces after colon in non-bracketed addresses in
+         qmail-smtpd.
+19980611 doc: cleaned up UPGRADE.
+19980528 bug: qmail-smtpd skips first character in rcpthosts() call.
+         tnx NND. impact: qmail-smtpd crashes on empty address; and it
+        allows relaying to ""@any.host. fix: use addr.s.
+19980515 doc: expanded flock discussion in INSTALL.mbox.
+19980515 doc: eliminated flock warning from INSTALL.maildir.
+19980515 doc: split REMOVE.binmail out of INSTALL.
+19980515 doc: split REMOVE.sendmail out of INSTALL.
+19980515 doc: split TEST.deliver and TEST.receive out of INSTALL and
+         UPGRADE.
+19980515 doc: integrated INSTALL.boot into INSTALL.
+19980515 code: cleaned up final output in qmail-qmqpd.c.
+19980514 doc: updated procmail notes in INSTALL.mbox. tnx JRM.
+19980514 doc: changed FAQ 4.4 to point to INSTALL.mbox for procmail.
+         tnx JRM.
+19980514 code: separated HELO and EHLO; single-line response for HELO.
+         tnx to various people.
+19980430 version: qmail 1.02.
+19980430 doc: updated SECURITY.
+19980430 doc: fixed FAQ 4.9. tnx KB.
+19980430 code: changed quote2() to avoid quoting <>.
+19980429 code: changed quote_need() to quote empty local parts. tnx HHO.
+19980428 doc: added status notes to INSTALL and UPGRADE.
+19980428 code: skip setting environment in sendmail.c if PROTO is set.
+19980428 code: eliminated recipientmap.
+19980428 code: added virtual users to qmail-send.c. tnx RN.
+19980428 code: eliminated domain from rewrite() in qmail-send.c.
+19980428 code: added binm1, binm1+df, binm2, binm2+df, binm3, binm3+df.
+19980428 doc: eliminated most Mailbox references from INSTALL, UPGRADE.
+19980428 code: added config-fast.
+19980428 code: renamed qmail-config as config.
+19980428 code: supported QMAILMFTFILE in qmail-inject.c.
+19980428 code: recognized Mail-Followup-To in hfield.c.
+19980428 code: replaced rwrecip() with rwappend() in qmail-inject.c.
+19980428 code: cleaned up doheaderfile() in qmail-inject.c.
+19980426 code: eliminated -type test from qmail-qstat to speed it up.
+         tnx FT.
+19980421 doc: eliminated remove-rcpthosts comments from FAQ.
+19980421 doc: updated FAQ 4.3 to point to Russ Allbery's FAQ. 
+19980421 doc: took account of /var/qmail/boot in INSTALL, UPGRADE, and
+         INSTALL.vsm.
+19980421 code: added /var/qmail/boot, with home, home+df, proc, proc+df.
+19980421 doc: skipped make and make man in INSTALL.
+19980420 doc: cleaned up mbox description in SENDMAIL.
+19980420 code: changed QMQP port to official port 628.
+19980402 doc: updated qmsmac references to fastforward.
+19980402 doc: replaced qmail-upgrade man page with doc/SENDMAIL.
+19980402 code: added qmqpservers output to qmail-showctl.
+19980402 code: added qmail-qmqpd.
+19980402 code: added qmail-qmqpc.
+19980304 code: eliminated del_saywhynoexit in qmail-send.c.
+19980304 code: eliminated concurrencynodel in qmail-send.c.
+19980222 code: added status() to qmail-send.c.
+19980222 code: added concurrencyused to qmail-send.c.
+19980128 doc: added note to qmail-getpw.9 about ETXTBSY.
+19980127 code: eliminated err_seenmail() in qmail-smtpd.c. tnx PO.
+19980126 doc: used $DEFAULT in FAQ where possible.
+19980126 code: added DEFAULT in qmail-local.
+19980126 code: added -/ to qmail-pw2u.
+19980126 code: revamped qmeopen() as qmesearch() with more sensible
+         semantics, separating dash from ext cleanly.
+19980126 code: split qmeexists() out of qmeopen() in qmail-local.c.
+19980126 code: introduced safeext in qmail-local.c.
+19980126 code: changed ~alias to mode 2755, to put files into group
+         qmail rather than group nofiles under System V.
+19980126 doc: switched to /var/qmail/rc in INSTALL*, UPGRADE, FAQ.
+19980126 code: added rc.
+19980119 doc: added .qmail creation warning to condredirect.1.
+19980118 code: made auto_uids.c creation atomic in Makefile. tnx HHO.
+19980118 doc: added PIC.*.
+19980117 portability problem: Solaris 2.5.1 incorrectly converts
+         O_NDELAY into O_NONBLOCK for sockets, so that ndelay_off()
+        fails to undo ndelay_on(). impact: none, since all the network
+        readers here use select() via timeoutread(). fix: use
+        O_NONBLOCK if it is defined.
+19980115 code: reformatted qmail-qmtpd.c.
+19980115 doc: changed tcpcontrol references in FAQ.
+19980115 doc: documented morercpthosts in qmail-qmtpd.9.
+19980115 code: eliminated unused datetime in qmail-qmtpd.c.
+19980115 code: eliminated sigalrm() in qmail-qmtpd.c.
+19980115 code: used rcpthosts() in qmail-smtpd.c, qmail-qmtpd.c.
+19980115 code: introduced rcpthosts.c.
+19980115 code: added morercpthosts.cdb support to qmail-showctl.
+19980115 code: added morercpthosts support to qmail-showctl.
+19980115 code: do_lst now returns file-exists in qmail-showctl.
+19980112 doc: documented morercpthosts in qmail-smtpd.9.
+19980112 code: added qmail-newmrh.
+19980112 code: used commands.c in qmail-popup.
+19980112 code: used commands.c in qmail-pop3d.
+19980112 code: introduced fakehelo in qmail-smtpd.
+19980112 code: moved flagbarf setting out of bmfcheck().
+19980112 code: allowed more address misformatting in qmail-smtpd.
+19980112 code: eliminated qmail@pobox.com help address in qmail-smtpd.
+19980112 code: reorganized qmail-smtpd.
+19980112 code: reformatted qmail-smtpd.
+19980112 code: used commands.c in qmail-smtpd.
+19980112 code: switched from 0 to "" for no arg in commands().
+19980112 code: added commands.c.
+19971230 doc: added -s to FreeBSD commands in INSTALL.ids. tnx TM.
+19971224 doc: added pointer to qmail pictures in README.
+19971223 doc: added note in FAQ about qmail-pop3d using maildir.
+19971219 code: added HOST2, HOST3, HOST4.
+19971219 code: renamed extx as x in qmail-local.c.
+19971219 doc: partitioned qmail-command.0.
+19971219 doc: updated FAQ 4.3 to point to newer majordomo patches.
+19971219 doc: eliminated qlist2 from FAQ.
+19971219 doc: eliminated qlist discussion from SECURITY.
+19971219 code: moved qlist, qlist2 to separate package.
+19971213 doc: added FAQ 4.10 on qmail-users generally.
+19971213 doc: added FAQ 4.9 on dealing with NFS outages.
+19971031 doc: added Linux and FreeBSD commands to INSTALL.ids. tnx TM.
+19971026 doc: added note about smtplf in qmail-smtpd.8. tnx S2S.
+19971014 doc: some tweaks to THOUGHTS.
+19971012 doc: used MAILER-DAEMON in UUCP example in INSTALL.
+19971003 code: eliminated dataline and getln() from qmail-remote.c.
+19971003 code: revamped blast() in qmail-remote.c.
+19971002 doc: added FAQ entries for .forward and /etc/aliases.
+19971002 doc: rewrote INSTALL.mbox and INSTALL.vsm.
+19971002 doc: renamed INSTALL.qsmhook as INSTALL.vsm.
+19971002 doc: emphasized the qmail-popup argv0 in FAQ.
+19971001 doc: added dot-forward note to BLURB3.
+19971001 doc: added more configuration notes to qmail-upgrade.9.
+19971001 doc: added note in INSTALL.qsmhook about dot-forward.
+19970930 code: token822_parse() now supports backslash as a quoting
+         character in atoms.
+19970929 doc: suggested symbolic links in INSTALL.mbox.
+19970925 doc: added note to INTERNALS about bounce stability.
+19970925 doc: added section to THOUGHTS discussing CNAME lookups.
+19970925 code: qmail-remote no longer does CNAME lookup on sender. tnx
+         C2F.
+19970923 portability problem: under SCO OSR5, splogger needs socket
+         libraries. impact: couldn't compile. fix: socket.lib. tnx RB.
+19970906 portability problem: under RISC/OS, Mail invokes sendmail -bm.
+         impact: can't send mail using Mail on RISC/OS. fix: ignore -bm.
+        tnx NW.
+19970813 code: implemented databytes in qmail-qmtpd.
+19970813 code: implemented databytes. tnx M4S for sample code.
+19970813 code: replaced execvp() with execv() for sh in qmail-local.
+19970813 doc: said in qmail-control.9 that recipientmap allows comments.
+19970813 code: used strerr in qmail-local.c.
+19970813 code: changed timeoutread(), timeoutwrite() interface.
+19970813 code: eliminated shutdown() in timeoutread(), timeoutwrite().
+19970813 code: revamped I/O in qmail-smtpd.c.
+19970813 code: used timeoutread(), timeoutwrite() in qmail-smtpd.c.
+19970813 code: simplified getcontrol() logic in qmail-remote.c; some
+         out-of-memory messages are now cannot-read-control messages.
+19970813 code: eliminated scan_nbblong().
+19970813 code: reformatted qmail-remote.c.
+19970813 code: renamed flaganyrecipok as flagbother in qmail-remote.c.
+19970813 code: integrated status report into quit() in qmail-remote.c.
+19970813 code: revamped smtpcode() in qmail-remote.c.
+19970813 code: added flagcritical in qmail-remote.c. eliminates
+         possible-duplicate warning if dot has not yet been sent.
+19970813 code: revamped I/O in qmail-remote.c.
+19970813 code: quit immediately after sending QUIT in qmail-remote.c.
+19970813 code: made many more globals in qmail-remote.c.
+19970813 code: switched qmail-remote.c from subfdin to home-grown.
+19970813 code: switched qmail-remote.c from subfdout to subfdoutsmall.
+19970813 code: added LAST support to qmail-pop3d.
+19970812 code: changed qmail_close() success return from 0 to "".
+19970812 code: revamped I/O in qmail-qmtpd.c.
+19970812 code: added qmail-tcpok.
+19970812 code: used strerr in maildirmake.c.
+19970812 code: reformatted maildirmake.c.
+19970812 code: printed qp in condredirect.c.
+19970812 code: printed qqx in condredirect.c.
+19970812 code: revamped I/O in condredirect.c.
+19970812 code: reformatted condredirect.c.
+19970812 code: used strerr in preline.c.
+19970812 code: revamped I/O in preline.c.
+19970812 code: reformatted preline.c.
+19970812 code: printed qp in forward.c.
+19970812 code: printed qqx in forward.c.
+19970812 code: revamped I/O in forward.c.
+19970812 code: used strerr in forward.c.
+19970812 code: reformatted forward.c.
+19970812 code: used strerr in predate.c.
+19970812 code: forced failure in qmail-qmtpd if no recipients; saves
+         time for qmail-send.
+19970812 code: added smtpd() to sendmail.c.
+19970812 code: added mailq() to sendmail.c.
+19970812 code: added die_usage() to sendmail.c.
+19970812 code: reformatted sendmail.c.
+19970812 code: used byte_zero() in qmail-popup.c.
+19970812 code: reformatted qmail-popup.c.
+19970812 code: eliminated unused header files in qmail-popup.c.
+19970812 code: changed I/O system in qmail-popup.c to match qmail-pop3d. 
+19970812 doc: pointed people to the mailing list in INSTALL and UPGRADE.
+19970810 code: added TXTBSY check to qmail-getpw.c. this gives vendors
+         the opportunity to make getpwnam() reliable.
+19970810 code: moved non-deleted messages from new/ to cur/ in
+         qmail-pop3d. tnx to various people.
+19970810 code: introduced list() in qmail-pop3d.c.
+19970810 code: reformatted qmail-pop3d.c.
+19970810 code: merged dataline and newname into line in qmail-pop3d.c.
+19970810 code: chopped filenames in qmail-pop3d at colons for UIDL. tnx
+         to various people.
+19970810 code: eliminated printint(), printlong() in qmail-pop3d.c.
+19970810 code: revamped I/O in qmail-pop3d.c.
+19970810 code: used timeoutread(), timeoutwrite() in qmail-pop3d.c.
+19970810 code: eliminated die_prot() in qmail-pop3d.c.
+19970810 code: eliminated unused header files in qmail-pop3d.c.
+19970810 code: switched qmail-pop3d to use maildir.c. tnx MD.
+19970809 code: added uid/gid printing to qmail-showctl. tnx PGF.
+19970808 code: switched control.c from scan_nbblong to scan_ulong.
+19970808 code: cleaned up wait_pid to use waitpid() when possible, and
+         to support at least one extra child otherwise.
+19970807 code: in qmail-smtpd, treat long envelope addresses as a syntax
+         error, instead of waiting for qmail-queue to reject them.
+19970803 code: changed condredirect, forward, qlist, qmail-inject,
+         qmail-local, qmail-qmtpd, qmail-send, qmail-smtpd, qreceipt for
+        new qmail_close() interface.
+19970803 code: revised qmail_close() to handle qmail-queue exit codes.
+19970802 doc: documented SMTP-related exit codes in qmail-queue.8.
+19970802 doc: documented qmail-queue exit codes in qmail-queue.8.
+19970802 code: revamped qmail-queue exit codes.
+19970802 doc: noted linking restrictions in qmail-queue.8.
+19970802 doc: rewrote INSTALL.mbox.
+19970802 doc: split INSTALL.maildir off of INSTALL.mbox.
+19970802 code: added /var/qmail/doc/ creation to qmail-hier.
+19970802 doc: added ezmlm note to FAQ.
+19970802 doc: replaced qlist blurbs with ezmlm blurbs in BLURB*.
+19970802 doc: added various notes to qmail-start.9.
+19970728 doc: eliminated RFC*.
+19970714 doc: added daemontools notes to FAQ.
+19970714 code: eliminated ESMTP parameter syntax checking.
+19970701 doc: changed ``forwarded'' to ``resent'' in qmail-header.5.
+19970629 code: reformatted constmap.c.
+19970628 code: changed straynewline() message in qmail-smtpd.c to point
+         to http://pobox.com/~djb/smtplf.html. tnx RDM.
+19970609 doc: added preline to vacation example in dot-qmail.9. tnx C2S.
+19970421 code: cleaned up slurpclose to handle interrupts.
+19970421 code: set qmail-popup to mode 711. tnx MD.
+19970421 doc: fixed qmail-local -n example in dot-qmail.9.
 19970415 version: qmail 1.01.
 19970414 doc: tightened up qmail-upgrade.7.
 19970414 code: rewrote rewrite().
diff --git a/FAQ b/FAQ
index 214cc1b..8540dbd 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -1,6 +1,7 @@
 1. Controlling the appearance of outgoing messages
 1.1. How do I set up host masquerading?
 1.2. How do I set up user masquerading?
+1.3. How do I set up Mail-Followup-To automatically?
 
 2. Routing outgoing messages
 2.1. How do I send local messages to another host?
 4.4. How do I use procmail with qmail?
 4.5. How do I use elm's filter with qmail?
 4.6. How do I create aliases with dots?
+4.7. How do I use sendmail's .forward files with qmail?
+4.8. How do I use sendmail's /etc/aliases with qmail?
+4.9. How do I make qmail defer messages during NFS or NIS outages?
+4.10. How do I change which account controls an address?
 
 5. Setting up servers
 5.1. How do I run qmail-smtpd under tcpserver?
 5.3. How do I set up qmail-pop3d?
 5.4. How do I allow selected clients to use this host as a relay?
 5.5. How do I fix up messages from broken SMTP clients?
+5.6. How do I set up qmail-qmqpd?
 
 6. Configuring MUAs to work with qmail
 6.1. How do I make BSD mail generate a Date with the local time zone?
-6.2. How do I stop pine from crashing?
+6.2. How do I make pine work with qmail?
 6.3. How do I make MH work with qmail?
 6.4. How do I stop Sun's dtcm from hanging?
 
@@ -41,6 +47,8 @@
 7.3. How do I rejuvenate a message?
 7.4. How do I organize a big network?
 7.5. How do I back up and restore the queue disk?
+7.6. How do I run a supervised copy of qmail?
+7.7. How do I avoid syslog?
 
 8. Miscellany
 8.1. How do I tell qmail to do more deliveries at once?
@@ -69,6 +77,14 @@ override From lines supplied by your MUA, add QMAILINJECT=f to your
 environment.
 
 
+1.3. How do I set up Mail-Followup-To automatically? When I send a
+message to the sos@heaven.af.mil mailing list, I'd like to include
+``Mail-Followup-To: sos@heaven.af.mil''.
+
+Answer: Add QMAILMFTFILE=$HOME/.lists to your environment, and put
+sos@heaven.af.mil into ~/.lists.
+
+
 
 2. Routing outgoing messages
 
@@ -102,11 +118,11 @@ Answer: Put
 
 into control/virtualdomains and
 
-   |preline -df /usr/bin/uux - -r -gC -a"$SENDER" gonzo!rmail "($EXT2@$HOST)"
+   |preline -df /usr/bin/uux - -r -gC
+      -a"${SENDER:-MAILER-DAEMON}" gonzo!rmail "($DEFAULT@$HOST)"
 
-into ~alias/.qmail-uucp-default. (For some UUCP software you will need
-to use -d instead of -df. Also, you may need to insert a space between
--a and "$SENDER" for bounces to work properly.) If qmail-send is
+(all on one line) into ~alias/.qmail-uucp-default. (For some UUCP
+software you will need to use -d instead of -df.) If qmail-send is
 running, give it a HUP.
 
 
@@ -120,9 +136,9 @@ showed that a message was deferred for this reason. Why is qmail doing
 CNAME lookups, anyway?
 
 Answer: The SMTP standard does not permit aliased hostnames, so qmail
-has to do a CNAME lookup in DNS for every sender and recipient host. If
-the relevant DNS server is down, qmail defers the message. It will try
-again soon.
+has to do a CNAME lookup in DNS for every recipient host. If the
+relevant DNS server is down, qmail defers the message. It will try again
+soon.
 
 
 
@@ -135,7 +151,8 @@ an MX from af.mil to pokey.af.mil, but how do I get pokey to treat
 af.mil as a name for the local host?
 
 Answer: Add af.mil to /var/qmail/control/locals and to
-/var/qmail/control/rcpthosts. If qmail-send is running, give it a HUP.
+/var/qmail/control/rcpthosts. If qmail-send is running, give it a HUP
+(or do svc -h /var/run/qmail if qmail is supervised).
 
 
 3.2. How do I set up a virtual domain? I'd like any mail for
@@ -147,7 +164,8 @@ Answer: Put
    nowhere.mil:bob
 
 into control/virtualdomains. Add nowhere.mil to control/rcpthosts. If
-qmail-send is running, give it a HUP.
+qmail-send is running, give it a HUP (or do svc -h /var/run/qmail if
+qmail is supervised).
 
 Now mail for whatever@nowhere.mil will be delivered locally to
 bob-whatever. Bob can set up ~bob/.qmail-default to catch all the
@@ -165,7 +183,8 @@ Answer: Put two lines into control/virtualdomains:
    everywhere.org:bob-everywhere
 
 Add nowhere.mil and everywhere.org to control/rcpthosts. If qmail-send
-is running, give it a HUP.
+is running, give it a HUP (or do svc -h /var/run/qmail if qmail is
+supervised).
 
 Now Bob can set up separate .qmail-nowhere-* and everywhere-* files. He
 can even set up .qmail-nowhere-default and .qmail-everywhere-default.
@@ -191,21 +210,22 @@ forwarded to a bunch of people.
 Answer: Put a list of addresses into ~me/.qmail-sos, one per line. Then
 incoming mail for me-sos will be forwarded to each of those addresses.
 You should also touch ~me/.qmail-sos-owner so that bounces come back to
-you rather than the original sender. If you want subscriptions to be
-handled automatically, put
-
-   | qlist2 sos my.host.name
+you rather than the original sender.
 
-into ~me/.qmail-sos-request. Anyone who wants to subscribe can simply
-send a message to me-sos-request@my.host.name.
+Alternative: ezmlm (http://pobox.com/~djb/ezmlm.html) is a modern
+mailing list manager, supporting automatic subscriptions, confirmations,
+archives, fully automatic bounce handling (including warnings to
+subscribers saying which messages they've missed), and more.
 
 
 4.3. How do I use majordomo with qmail?
 
-Answer: You need to patch majordomo so that it creates qmail-style
-lists. See ftp://koobera.math.uic.edu/pub/software/majordomo+qmail.gz.
-Exception: qmsmac understands sendmail-style :include: files, so you
-shouldn't patch majordomo if you're using qmsmac.
+Answer: See ftp://ftp.eyrie.org/pub/software/majordomo/mjqmail and
+http://www.qmail.org for various methods. majordomo 2.0 is expected to
+support qmail directly.
+
+Beware that majordomo's lists are not crashproof.
+
 
 
 4.4. How do I use procmail with qmail?
@@ -216,8 +236,8 @@ Answer: Put
 
 into ~/.qmail. You'll have to use a full path for procmail unless
 procmail is in the system's startup PATH. Note that procmail will try to
-deliver to /usr/spool/mail/$USER by default; to change this, change
-SYSTEM_MBOX in procmail's config.h.
+deliver to /var/spool/mail/$USER by default; to change this, see
+INSTALL.mbox.
 
 
 4.5. How do I use elm's filter with qmail?
@@ -237,6 +257,48 @@ Answer: Use .qmail-p:d:q:bach. Dots are converted to colons, and
 uppercase is converted to lowercase.
 
 
+4.7. How do I use sendmail's .forward files with qmail?
+
+Answer: Install the dot-forward package
+(http://pobox.com/~djb/dot-forward.html).
+
+
+4.8. How do I use sendmail's /etc/aliases with qmail?
+
+Answer: Install the fastforward package
+(http://pobox.com/~djb/fastforward.html).
+
+
+4.9. How do I make qmail defer messages during NFS or NIS outages? If
+~joe suddenly disappears, I'd like mail for joe to be deferred.
+
+Answer: Build a qmail-users database, so that qmail no longer checks
+home directories and the password database. This takes three steps.
+First, put your complete user list (including local and NIS passwords)
+into /var/qmail/users/passwd. Second, run
+
+   # qmail-pw2u -h < /var/qmail/users/passwd > /var/qmail/users/assign
+
+Here -h means that every user must have a home directory; if you happen
+to run qmail-pw2u during an NFS outage, it will print an error message
+and stop. Third, run
+
+   # qmail-newu
+
+Make sure to rebuild the database whenever you change your user list.
+
+
+4.10. How do I change which account controls an address? I set up
+~alias/.qmail-www, but qmail is looking at ~www/.qmail instead.
+
+Answer: If you do
+
+   # chown root ~www
+
+then qmail will no longer consider www to be a user; see qmail-getpw.0.
+For more precise control over address assignments, see qmail-users.0.
+
+
 
 5. Setting up servers
 
@@ -281,20 +343,23 @@ If you have tcpserver installed, skip the inetd step, and set up
    tcpserver -u 7770 -g 2108 0 qmtp /var/qmail/bin/qmail-qmtpd &
 
 replacing 7770 and 2108 with the qmaild uid and nofiles gid. See
-question 5.1 for more details.
+question 5.1 for more details on tcpserver.
 
 
-5.3. How do I set up qmail-pop3d?
+5.3. How do I set up qmail-pop3d? My old POP server works with mbox
+delivery; I'd like to switch to maildir delivery.
 
 Answer: Four steps. First, install the checkpassword program
 (http://pobox.com/~djb/checkpwd.html). Second, make sure you have a
 
    pop3 110/tcp
 
-line in /etc/services. Third, put (all on one line)
+line in /etc/services. Third, put (all on one line, including
+qmail-popup twice)
 
-   pop3 stream tcp nowait root /var/qmail/bin/qmail-popup
-   qmail-popup YOURHOST /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir
+   pop3 stream tcp nowait root
+   /var/qmail/bin/qmail-popup qmail-popup
+   YOURHOST /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir
 
 into /etc/inetd.conf, and give inetd a HUP; replace YOURHOST with your
 host's fully qualified domain name. Fourth, set up Maildir delivery for
@@ -307,7 +372,7 @@ lines)
    /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir &
 
 replacing YOURHOST with your host's fully qualified domain name. See
-question 5.1 for more details.
+question 5.1 for more details on tcpserver.
 
 Security note: pop3d should be used only within a secure network;
 otherwise an eavesdropper can steal passwords.
@@ -315,8 +380,7 @@ otherwise an eavesdropper can steal passwords.
 
 5.4. How do I allow selected clients to use this host as a relay? I see
 that qmail-smtpd rejects messages to any host not listed in
-control/rcpthosts. I know I could entirely disable this feature by
-removing control/rcpthosts, but I want to be more selective.
+control/rcpthosts.
 
 Answer: Three steps. First, install tcp-wrappers, available separately,
 including hosts_options. Second, change your qmail-smtpd line in
@@ -336,29 +400,29 @@ ignores control/rcpthosts when RELAYCLIENT is set. (It also appends
 RELAYCLIENT to each envelope recipient address. See question 5.5 for an
 application.)
 
-Alternative procedure, if you are using tcpserver: Install tcpcontrol
-(http://pobox.com/~djb/tcpcontrol.html). Create /etc/tcp.smtp containing
+Alternative procedure, if you are using tcpserver 0.80 or above: Create
+/etc/tcp.smtp containing
 
    1.2.3.6:allow,RELAYCLIENT=""
    127.:allow,RELAYCLIENT=""
 
 to allow clients with IP addresses 1.2.3.6 and 127.*. Run
 
-   tcpmakectl /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
+   tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
 
 Finally, insert
 
-   tcpcontrol /etc/tcp.smtp.cdb
+   -x /etc/tcp.smtp.cdb
 
-before /var/qmail/bin/qmail-smtpd in your tcpserver line.
+after tcpserver in your qmail-smtpd invocation.
 
 
 5.5. How do I fix up messages from broken SMTP clients?
 
 Answer: Three steps. First, put
 
-   | [ "@$HOST" = "@fixme" ] || ( echo Permission denied; exit 100 )
-   | qmail-inject -f "$SENDER" -- "$EXT2"
+   | bouncesaying 'Permission denied' [ "@$HOST" != "@fixme" ]
+   | qmail-inject -f "$SENDER" -- "$DEFAULT"
 
 into ~alias/.qmail-fixup-default. Second, put
 
@@ -371,12 +435,34 @@ string ``@fixme'':
    tcp-env: 1.2.3.6, 1.2.3.7: setenv = RELAYCLIENT @fixme
 
 Here 1.2.3.6 and 1.2.3.7 are the clients' IP addresses. If you are using
-tcpserver and tcpcontrol instead of inetd and tcpd, put
+tcpserver instead of inetd and tcpd, put
 
    1.2.3.6:allow,RELAYCLIENT="@fixme"
    1.2.3.7:allow,RELAYCLIENT="@fixme"
 
-into /etc/tcp.smtp, and run tcpmakectl as in question 5.4.
+into /etc/tcp.smtp, and run tcprules as in question 5.4.
+
+
+5.6. How do I set up qmail-qmqpd? I'd like to allow fast queueing of
+outgoing mail from authorized clients.
+
+Answer: Make sure you have installed tcpserver 0.80 or above. Create
+/etc/qmqp.tcp in tcprules format to allow connections from authorized
+hosts. For example, if queueing is allowed from 1.2.3.*:
+
+   1.2.3.:allow
+   :deny
+
+Convert /etc/qmqp.tcp to /etc/qmqp.cdb:
+
+   tcprules /etc/qmqp.cdb /etc/qmqp.tmp < /etc/qmqp.tcp
+
+Finally, set up
+
+   tcpserver -x /etc/qmqp.cdb -u 7770 -g 2108 0 628 /var/qmail/bin/qmail-qmqpd &
+
+replacing 7770 and 2108 with the qmaild uid and nofiles gid. See
+question 5.1 for more details on tcpserver.
 
 
 
@@ -395,8 +481,7 @@ into your .mailrc or your system-wide Mail.rc. Beware that BSD mail is
 neither secure nor reliable.
 
 
-6.2. How do I stop pine from crashing? When I ask any version of pine
-past 3.91 to send mail, it crashes.
+6.2. How do I make pine work with qmail?
 
 Answer: Put
 
@@ -432,14 +517,25 @@ sendmail, it was always tricky to kill sendmail without risking the loss
 of current deliveries; what should I do with qmail-send?
 
 Answer: Go ahead and kill the qmail-send process. It will shut down
-cleanly. Wait for ``exiting'' to show up in the log. To restart it, run
-qmail-start the same way as it's run from your system boot scripts.
+cleanly. Wait for ``exiting'' to show up in the log. To restart qmail,
+run /var/qmail/rc the same way it is run from your system boot scripts,
+with the proper PATH, resource limits, etc.
+
+Alternative, if qmail is supervised: svc -t /var/run/qmail. The
+supervise process will kill qmail, wait for it to stop, and restart it.
+Use -d instead of -t if you don't want qmail to restart automatically;
+to manually restart it, use -u.
 
 
 7.2. How do I manually run the queue? I'd like qmail to try delivering
 all the remote messages right now.
 
-Answer: Give the qmail-send process an ALRM.
+Answer: Give the qmail-send process an ALRM. (Do svc -a /var/run/qmail
+if qmail is supervised.)
+
+You may want to run qmail-tcpok first, to guarantee that qmail-remote
+will try all addresses. Normally, if an address fails repeatedly,
+qmail-remote leaves it alone for an hour.
 
 
 7.3. How do I rejuvenate a message? Somebody broke into Eric's computer
@@ -521,6 +617,42 @@ battery backups. RAID boxes let you replace dead disks without losing
 any data.
 
 
+7.6. How do I run a supervised copy of qmail? svc sounds useful.
+
+Answer: Install daemontools (http://pobox.com/~djb/daemontools.html).
+Create a /var/run/qmail directory. Change
+
+   /var/qmail/rc
+
+to
+
+   supervise /var/run/qmail /var/qmail/rc
+
+in your boot scripts. Make sure that supervise is in the startup PATH.
+Now you can use svc to stop or restart qmail, and svstat to check
+whether qmail is running.
+
+
+7.7. How do I avoid syslog? It chews up a lot of CPU time and isn't
+reliable.
+
+Answer: Install daemontools (http://pobox.com/~djb/daemontools.html).
+Make a /var/log/qmail directory, owned by qmaill, mode 2700. Do
+
+   qmail-start ./Mailbox /usr/local/bin/accustamp \
+   | setuser qmaill /usr/local/bin/cyclog /var/log/qmail &
+
+in /var/qmail/rc.
+
+If you are logging tcpserver connections, make a /var/log/smtpd
+directory, and use cyclog /var/log/smtpd for tcpserver. You shouldn't
+run several copies of cyclog with the same log directory.
+
+By default, cyclog keeps 10 automatically rotated log files, each
+containing up to 100KB of log data. To keep 20 files with 1MB each, use
+cyclog -s 1000000 -n 20.
+
+
 
 8. Miscellany
 
diff --git a/FILES b/FILES
index b581fac..bbf25c2 100644 (file)
--- a/FILES
+++ b/FILES
@@ -6,31 +6,40 @@ README
 FAQ
 INSTALL
 INSTALL.alias
-INSTALL.boot
 INSTALL.ctl
 INSTALL.ids
+INSTALL.maildir
 INSTALL.mbox
-INSTALL.qsmhook
+INSTALL.vsm
+REMOVE.sendmail
+REMOVE.binmail
+TEST.deliver
+TEST.receive
 UPGRADE
 THOUGHTS
 TODO
 THANKS
 CHANGES
-RFCHCSC
-RFCLOOPS
-RFCMXPS
-RFCNETSTR
-RFCNRUDT
-RFCQMTP
-RFCQSBMF
-RFCVERP
 SECURITY
 INTERNALS
+SENDMAIL
+PIC.local2alias
+PIC.local2ext
+PIC.local2local
+PIC.local2rem
+PIC.local2virt
+PIC.nullclient
+PIC.relaybad
+PIC.relaygood
+PIC.rem2local
 FILES
 VERSION
 SYSDEPS
 TARGETS
 Makefile
+BIN.README
+BIN.Makefile
+idedit.c
 conf-break
 auto_break.h
 conf-spawn
@@ -46,6 +55,8 @@ auto_uids.h
 auto_usera.h
 extra.h
 addresses.5
+except.1
+bouncesaying.1
 condredirect.1
 dot-qmail.9
 envelopes.5
@@ -58,7 +69,6 @@ mailsubj.1
 mbox.5
 preline.1
 qbiff.1
-qlist.1
 qmail-clean.8
 qmail-command.8
 qmail-control.9
@@ -69,10 +79,13 @@ qmail-limits.9
 qmail-local.8
 qmail-log.5
 qmail-lspawn.8
+qmail-newmrh.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
@@ -83,24 +96,27 @@ qmail-send.9
 qmail-showctl.8
 qmail-smtpd.8
 qmail-start.9
+qmail-tcpok.8
 qmail-tcpto.8
-qmail-upgrade.9
 qmail-users.9
 qmail.7
 qreceipt.1
 splogger.8
 tcp-env.1
+config.sh
+config-fast.sh
 qmail-clean.c
-qmail-config.sh
 qmail-getpw.c
-qmail-hier.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
@@ -111,6 +127,7 @@ qmail-send.c
 qmail-showctl.c
 qmail-smtpd.c
 qmail-start.c
+qmail-tcpok.c
 qmail-tcpto.c
 spawn.c
 dnscname.c
@@ -122,13 +139,14 @@ hostname.c
 ipmeprint.c
 tcp-env.c
 sendmail.c
-qlist.c
 qreceipt.c
 qsmhook.c
 qbiff.c
 forward.c
 preline.c
 predate.c
+except.c
+bouncesaying.c
 condredirect.c
 maildirmake.c
 maildir2mbox.c
@@ -137,13 +155,14 @@ splogger.c
 qail.sh
 elq.sh
 pinq.sh
-qlist2.sh
 qmail-upq.sh
 datemail.sh
 mailsubj.sh
 qlx.h
-constmap.h
-constmap.c
+rcpthosts.h
+rcpthosts.c
+commands.h
+commands.c
 dnsdoe.h
 dnsdoe.c
 fmtqfn.h
@@ -171,6 +190,16 @@ trynpbg1.c
 trysyslog.c
 conf-cc
 conf-ld
+home.sh
+home+df.sh
+proc.sh
+proc+df.sh
+binm1.sh
+binm2.sh
+binm3.sh
+binm1+df.sh
+binm2+df.sh
+binm3+df.sh
 find-systype.sh
 make-compile.sh
 make-load.sh
@@ -182,8 +211,10 @@ auto-int.c
 auto-int8.c
 auto-gid.c
 auto-uid.c
+hier.c
 install.c
 instcheck.c
+install-big.c
 alloc.3
 alloc.h
 alloc.c
@@ -348,7 +379,6 @@ fmt_ulong.c
 scan.h
 scan_ulong.c
 scan_8long.c
-scan_nbblong.c
 slurpclose.h
 slurpclose.c
 quote.h
@@ -399,3 +429,5 @@ maildir.5
 maildir.h
 maildir.c
 tcp-environ.5
+constmap.h
+constmap.c
diff --git a/INSTALL b/INSTALL
index 314e94a..e3b0f09 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -12,170 +12,73 @@ directory, edit conf-qmail now.
 names, edit conf-users and conf-groups now.
 
 
-Installation steps that won't interfere with sendmail:
+To create /var/qmail and configure qmail (won't interfere with sendmail):
 
  1. Create the qmail home directory:
        # mkdir /var/qmail
+
  2. Read INSTALL.ids. You must set up the qmail group and the qmail
     users before compiling the programs.
- 3. Compile the programs:
-       # make
- 4. Create the formatted man pages, *.0:
-       # make man
- 5. Create the qmail directory tree:
-       # make setup
- 6. Run instcheck to make sure it doesn't print any warnings:
-       # make check
- 7. Read INSTALL.ctl and FAQ. Minimal survival command:
-       # ./qmail-config
- 8. Read INSTALL.alias. Minimal survival command:
+
+ 3. Compile the programs and create the qmail directory tree:
+       # make setup check
+
+ 4. Read INSTALL.ctl and FAQ. Minimal survival command:
+       # ./config
+
+ 5. Read INSTALL.alias. Minimal survival command:
        # (cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root)
        # chmod 644 ~alias/.qmail*
- 9. Read INSTALL.mbox.
-10. Read qmail-upgrade.0. This is what your users will need to know
-    about the switch from sendmail to qmail.
-
-
-Pre-upgrade tests:
-
-11. Enable deliveries of messages injected into qmail:
-       # env - PATH="/var/qmail/bin:$PATH" \
-       qmail-start ./Mailbox splogger qmail &
-    Make sure to include the ./ in ./Mailbox.
-12. Look for a
-            qmail: running
-    line in syslog. qmail-send always prints either ``cannot start'' or
-    ``running''. (The big number is a splogger timestamp.)
-13. Do a ps and look for the qmail daemons. There should be four of
-    them, all idle: qmail-send, running as qmails; qmail-lspawn, running
-    as root; qmail-rspawn, running as qmailr; and qmail-clean, running
-    as qmailq. You will also see the splogger process.
-14. Local-local test: Send yourself an empty message. (Replace ``me''
-    with your username. Make sure to include the ``to:'' colon.)
-       % echo to: me | /var/qmail/bin/qmail-inject
-    The message will show up immediately in ~/Mailbox, and syslog will
-    show something like this:
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666
-            qmail: starting delivery 1: msg 53 to local me@domain 
-            qmail: delivery 1: success: did_1+0+0/
-            qmail: end msg 53 
-    (53 is an inode number; 20345 is a process ID; your numbers will
-    probably be different.)
-15. Local-error test: Send a message to a nonexistent local address.
-       % echo to: nonexistent | /var/qmail/bin/qmail-inject
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666
-            qmail: starting delivery 2: msg 53 to local nonexistent@domain
-            qmail: delivery 2: failure: No_such_address.__#5.1.1_/
-           qmail: bounce msg 53 qp 20357
-            qmail: end msg 53 
-            qmail: new msg 54 
-            qmail: info msg 54: bytes 743 from <> qp 20357 uid 666
-            qmail: starting delivery 3: msg 54 to local me@domain
-            qmail: delivery 3: success: did_1+0+0/
-            qmail: end msg 54 
-    You will now have a bounce message in ~/Mailbox.
-16. Local-remote test: Send an empty message to your account on another
-    machine.
-       % echo to: me@wherever | /var/qmail/bin/qmail-inject
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666
-            qmail: starting delivery 4: msg 53 to remote me@wherever
-            qmail: delivery 4: success: 1.2.3.4_accepted_message./...
-            qmail: end msg 53 
-    There will be a pause between ``starting delivery'' and ``success'';
-    SMTP is slow. Check that the message is in your mailbox on the other
-    machine.
-17. Local-postmaster test: Send mail to postmaster, any capitalization.
-       % echo to: POSTmaster | /var/qmail/bin/qmail-inject
-    Look for the message in ~alias/Mailbox.
-18. Double-bounce test: Send a message with a completely bad envelope.
-       % /var/qmail/bin/qmail-inject -f nonexistent
-       To: unknownuser
-       Subject: testing
-
-       This is a test. This is only a test.
-       %
-    (Use end-of-file, not dot, to end the message.) Look for the double
-    bounce in ~alias/Mailbox.
-19. Group membership test:
-       % cat > ~me/.qmail-groups
-       |groups >> MYGROUPS; exit 0
-       % /var/qmail/bin/qmail-inject me-groups < /dev/null
-       % cat ~me/MYGROUPS
-    MYGROUPS will show your normal gid and nothing else. (Under Solaris,
-    make sure to use /usr/ucb/groups; /usr/bin/groups is broken.)
-
-
-Upgrading from sendmail to qmail:
-
-20. Read INSTALL.boot. You must replace the sendmail invocation in your
-    boot scripts with an appropriate qmail invocation.
-21. Kill the sendmail daemon. You should first kill -STOP the daemon; if
-    any children are running, you should kill -CONT, wait, kill -STOP
-    again, and repeat ad nauseam. If there aren't any children, kill
-    -TERM and then kill -CONT.
-22. Replace sendmail with a link to qmail's ``sendmail'' wrapper:
-       # mv /usr/lib/sendmail /usr/lib/sendmail.bak
+
+ 6. Read INSTALL.mbox and INSTALL.vsm.
+
+ 7. Read INSTALL.maildir.
+
+ 8. Copy /var/qmail/boot/home (or proc) to /var/qmail/rc.
+
+
+To test qmail deliveries (won't interfere with sendmail):
+
+ 9. Enable deliveries of messages injected into qmail:
+       # csh -cf '/var/qmail/rc &'
+
+10. Read TEST.deliver.
+
+
+To upgrade from sendmail to qmail:
+
+11. Read SENDMAIL. This is what your users will want to know about the
+    switch from sendmail to qmail.
+
+12. Read REMOVE.sendmail. You must remove sendmail before installing
+    qmail.
+
+13. Read REMOVE.binmail.
+
+14. Add
+            csh -cf '/var/qmail/rc &'
+    to your boot scripts, so that the qmail daemons are restarted
+    whenever your system reboots. Make sure you include the &.
+
+15. Make qmail's ``sendmail'' wrapper available to MUAs:
        # ln -s /var/qmail/bin/sendmail /usr/lib/sendmail
-23. Set up qmail-smtpd in /etc/inetd.conf (all on one line):
+       # ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail
+    /usr/sbin might not exist on your system.
+
+16. Set up qmail-smtpd in /etc/inetd.conf (all on one line):
             smtp stream tcp nowait qmaild /var/qmail/bin/tcp-env
-           tcp-env /var/qmail/bin/qmail-smtpd
-    Also comment out comsat in /etc/inetd.conf.
-24. Reboot. (Or kill -HUP your inetd and make sure the qmail daemons
+            tcp-env /var/qmail/bin/qmail-smtpd
+
+17. Reboot. (Or kill -HUP your inetd and make sure the qmail daemons
     are running.)
-25. Try to flush the sendmail queue:
-       # /usr/lib/sendmail.bak -q
-    You can safely run sendmail.bak -q (or even sendmail.bak -q15m)
-    while qmail is running. Do this until the sendmail queue is empty.
-    This may take several days.
-26. Disable all the sendmail and binmail programs in your system. The
-    safest approach is to chmod 0 everything. Some locations to check:
-    /usr/sbin/sendmail, /usr/lib/sendmail.bak, /usr/lib/sendmail.mx,
-    /bin/mail, /usr/libexec/mail.local.
-27. Make sure that ``mail'' still invokes a reasonable mailer. Under
-    SVR4 you may want to link mail to mailx.
-
-
-Post-upgrade tests (can be done immediately after step 24):
-
-28. SMTP server test: Forge some mail locally via SMTP.
-       % telnet 127.0.0.1 25
-       Trying 127.0.0.1...
-       Connected to 127.0.0.1.
-       Escape character is '^]'.
-       220 domain ESMTP
-       helo dude
-       250-domain
-       250-PIPELINING
-       250 8BITMIME
-       mail <me@domain>
-       250 ok
-       rcpt <me@domain>
-       250 ok
-       data
-       354 go ahead
-       Subject: testing
-       
-       This is a test.
-       .
-       250 ok 812345679 qp 12345
-       quit
-       221 domain
-       Connection closed by foreign host.
-       %
-    Look for the message in your mailbox.
-29. Remote-local test: Send yourself some mail from another machine.
-30. Remote-error test: I think you can figure this one out.
-31. UA test: Try sending mail, first to a local account, then to a
-    remote account, with your normal user agent.
-32. Remote-postmaster test: Send mail from another machine to
-    PoStMaStEr@domain. Look for the message in ~alias/Mailbox.
+
+18. Read TEST.receive.
+
 
 
 That's it! To report success:
-       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \
-         | mail djb-qst@koobera.math.uic.edu
-Replace First M. Last with your name. If you have questions about qmail,
-contact qmail@pobox.com.
+       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to
+Replace First M. Last with your name.
+
+If you have questions about qmail, join the qmail mailing list; see
+http://pobox.com/~djb/qmail.html.
index 5721da1..672365a 100644 (file)
@@ -2,12 +2,12 @@ qmail lets each user control all addresses of the form user-anything.
 Addresses that don't start with a username are controlled by a special
 user, alias. Delivery instructions for foo go into ~alias/.qmail-foo;
 delivery instructions for user-foo go into ~user/.qmail-foo. See
-qmail-upgrade.0 and dot-qmail.0 for the full story.
+dot-qmail.0 for the full story.
 
 qmail doesn't have any built-in support for /etc/aliases. If you have a
-big /etc/aliases and you'd like to keep it, install the qmsmac package,
-available separately. /etc/aliases should already include the aliases
-discussed below---Postmaster, MAILER-DAEMON, and root.
+big /etc/aliases and you'd like to keep it, install the fastforward
+package, available separately. /etc/aliases should already include the
+aliases discussed below---Postmaster, MAILER-DAEMON, and root.
 
 If you don't have a big /etc/aliases, you'll find it easier to use
 qmail's native alias mechanism. Here's a checklist of aliases you should
diff --git a/INSTALL.boot b/INSTALL.boot
deleted file mode 100644 (file)
index 0010288..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-The qmail daemons have to be restarted whenever your system reboots.
-Meanwhile, sendmail doesn't have to be started any more. Here's what you
-should do.
-
-Find sendmail in your boot scripts. It's usually in either /etc/rc or
-/etc/init.d/sendmail. It looks like
-
-        sendmail -bd -q15m
-
--q15m means it should run the queue every 15 minutes; you may see a
-different number. Comment out this line, and replace it with
-
-        env - PATH="/var/qmail/bin:$PATH" \
-       csh -cf 'qmail-start ./Mailbox splogger qmail &'
-
-That's it. (Make sure you include the ./ and the &.)
index f493fcf..00ce689 100644 (file)
@@ -10,13 +10,22 @@ But this is all optional---if control/smtpgreeting doesn't exist, qmail
 will do something reasonable by default. You shouldn't worry much about
 configuration right now. You can always come back and tune things later.
 
-There's one big exception. You MUST tell qmail your hostname. The easy
-way to do this is to run the qmail-config script:
+There's one big exception. You MUST tell qmail your hostname. Just run
+the config-fast script:
 
-   # ./qmail-config
+   # ./config-fast your.full.host.name
 
-qmail-config finds your fully-qualified hostname in DNS and puts it into
-control/me. It also selects good defaults for a few other controls.
+config-fast puts your.full.host.name into control/me. It also puts it
+into control/locals and control/rcpthosts, so that qmail will accept
+mail for your.full.host.name.
+
+You can instead use the config script, which looks up your host name in
+DNS:
+
+   # ./config
+
+config also looks up your local IP addresses in DNS to decide which
+hosts to accept mail for.
 
 (Why doesn't qmail do these lookups on the fly? This was a deliberate
 design decision. qmail does all its local functions---header rewriting,
index e0e4ee2..a50e10d 100644 (file)
@@ -1,6 +1,7 @@
 Here's how to set up the qmail groups and the qmail users.
 
-On some systems there are commands that make this easy. Solaris:
+On some systems there are commands that make this easy. Solaris and
+Linux:
 
    # groupadd nofiles
    # useradd -g nofiles -d /var/qmail/alias alias
@@ -12,6 +13,18 @@ On some systems there are commands that make this easy. Solaris:
    # useradd -g qmail -d /var/qmail qmailr
    # useradd -g qmail -d /var/qmail qmails
 
+FreeBSD 2.2:
+
+   # pw groupadd nofiles
+   # pw useradd alias -g nofiles -d /var/qmail/alias -s /nonexistent
+   # pw useradd qmaild -g nofiles -d /var/qmail -s /nonexistent
+   # pw useradd qmaill -g nofiles -d /var/qmail -s /nonexistent
+   # pw useradd qmailp -g nofiles -d /var/qmail -s /nonexistent
+   # pw groupadd qmail
+   # pw useradd qmailq -g qmail -d /var/qmail -s /nonexistent
+   # pw useradd qmailr -g qmail -d /var/qmail -s /nonexistent
+   # pw useradd qmails -g qmail -d /var/qmail -s /nonexistent
+
 BSDI 2.0:
 
    # addgroup nofiles
diff --git a/INSTALL.maildir b/INSTALL.maildir
new file mode 100644 (file)
index 0000000..72373aa
--- /dev/null
@@ -0,0 +1,59 @@
+This file points out some reasons that you might want to switch from
+mbox format to a new format, maildir.
+
+
+1. The trouble with mbox
+
+The mbox format---the format of ~user/Mailbox, understood by BSD Mail
+and lots of other MUAs---is inherently unreliable.
+
+Think about it: what happens if the system crashes while a program is
+appending a new message to ~user/Mailbox? The message will be truncated.
+Even worse, if it was truncated in the middle of a line, it will end up
+being merged with the next message! Sure, the mailer understands that it
+wasn't successful, so it'll try delivering the message again later, but
+it can't fix your corrupted mbox.
+
+Other formats, such as mh folders, are just as unreliable.
+
+qmail supports maildir, a crashproof format for incoming mail messages.
+maildir is fast and easy for MUAs to use. Even better, maildir works
+wonders over NFS---see below.
+
+I don't want to cram maildir down people's throats, so it's not the
+default. Nevertheless, I encourage you to start asking for maildir
+versions of your favorite MUAs, and to switch over to maildir as soon as
+you can.
+
+
+2. Sun's Network F_\bail_\bu_\bre System
+
+Anyone who tells you that mail can be safely delivered in mbox format
+over NFS is pulling your leg---as explained above, mbox format is
+inherently unreliable even on a single machine.
+
+Anyway, NFS is the most unreliable computing environment ever invented,
+and qmail doesn't even pretend to support mbox over NFS.
+
+You should switch to maildir, which works fine over NFS without any
+locking. You can safely read your mail over NFS if it's in maildir
+format. Any number of machines can deliver mail to you at the same time.
+(On the other hand, for efficiency, it's better to get NFS out of the
+picture---your mail should be delivered on the server that contains your
+home directory.)
+
+Here's how to set up qmail to use maildir for your incoming mail:
+
+   % maildirmake $HOME/Maildir
+   % echo ./Maildir/ > ~/.qmail
+
+Make sure you include the trailing slash on Maildir/.
+
+The system administrator can set up Maildir as the default for everybody
+by creating a maildir in the new-user template directory and replacing
+./Mailbox with ./Maildir/ in /var/qmail/rc.
+
+Until your MUA supports maildir, you'll probably want to convert maildir
+format to (gaaack) mbox format. I've supplied a maildir2mbox utility
+that does the trick, along with some tiny qail and elq and pinq wrappers
+that call maildir2mbox before calling Mail or elm or pine.
index a62a181..93ca16c 100644 (file)
@@ -2,111 +2,52 @@ The qmail package includes a local delivery agent, qmail-local, which
 provides user-controlled mailing lists, cross-host alias loop detection,
 and many other important qmail features.
 
-There's one part of qmail-local that you need to know about right now:
-qmail-local doesn't support an insecure central mail spool. It delivers
-mail by default into ~user/Mailbox (in mbox format).
+There's one important difference between qmail-local and binmail:
+qmail-local delivers mail by default into ~user/Mailbox, rather than
+/var/spool/mail/user. It uses mbox format, with lockf locking on systems
+that don't have flock (HP/UX, Solaris), and flock locking otherwise.
 
-This file explains what you should do to deal with this change. It also
-points out some reasons that you might want to make an even bigger
-change, switching from mbox format to a new format, maildir.
+This file explains how to switch your system to ~user/Mailbox. You
+aren't required to do this; for further discussion of /var/spool/mail,
+and an explanation of how to continue using binmail for local
+deliveries, see INSTALL.vsm.
 
-If you desperately don't want to change anything, see INSTALL.qsmhook.
+The basic procedure for switching to ~user/Mailbox is simple:
 
+   * Move each /var/spool/mail/user to ~user/Mailbox. For safety, do
+     this in single-user mode.
 
-Contents:
-1. Throw away /usr/spool/mail!
-2. The trouble with mbox
-3. Sun's Network F_\bail_\bu_\bre System
+   * As root, set up a symbolic link from /var/spool/mail/user to
+     ~user/Mailbox for each user. /var/spool/mail should be mode 1777,
+     so users will not be able to accidentally remove these links.
 
+A few mail programs are unable to handle symbolic links, so you will
+have to configure them to look at ~user/Mailbox directly:
 
-1. Throw away /usr/spool/mail!
+   * procmail: Change SYSTEM_MBOX in config.h and recompile; or, with
+     recent versions, define MAILSPOOLHOME in src/authenticate.c.
 
-/usr/spool/mail, often called /var/spool/mail or /var/mail, is a
-security disaster. A user's mailbox belongs in his home directory, not a
-shared directory. Even if you don't install qmail, you should destroy
-/usr/spool/mail. This takes four steps:
+An alternative to symbolic links is hlfsd. Consult the documentation for
+hlfsd if it is included in your operating system.
 
-   A. Convince your local mailer to deliver to ~user/Mailbox. If you're
-   using something like procmail, this is easy---just change SYSTEM_MBOX
-   in config.h. If you're installing qmail, you don't have to do
-   anything. Otherwise, take a look at hlfsd from
-   ftp.cs.columbia.edu/pub/amd.
+If /var/spool/mail is large, you can gain extra speed by configuring
+all your mail software to look at ~user/Mailbox directly:
 
-   B. Move each /usr/spool/mail/user to ~user/Mailbox. For safety, do
-   this in single-user mode---you don't want to risk corrupting
-   mailboxes. (qmail makes it easy to turn off deliveries temporarily:
-   just kill the qmail-send daemon. But you aren't running qmail yet.)
-   When you're done, remove /usr/spool/mail.
+   * Most MUAs: Put ``setenv MAIL $HOME/Mailbox'' in your system-wide
+     .cshrc and ``MAIL=$HOME/Mailbox; export MAIL'' in your system-wide
+     .profile.
 
-   C. Put ``setenv MAIL $HOME/Mailbox'' in your system-wide .cshrc,
-   ``MAIL=$HOME/Mailbox; export MAIL'' in your system-wide .profile,
-   ``inbox-path=Mailbox'' in your system-wide pine.conf. If you're using
-   qpopper 2.2, you'll have to recompile with -DHOMEDIRMAIL in CFLAGS
-   and with /.mail changed to /Mailbox in pop_dropcopy.c. If you're
-   using elm on a multiuser system, you'll have to recompile elm with
-   "mailbox" changed to "Mailbox" around line 388 of newmbox.c.
+   * elm: Change "mailbox" to "Mailbox" around line 388 of newmbox.c and
+     recompile. (elm looks at $MAIL, but without this change elm will
+     fail if two users try to read mail simultaneously.)
 
-   D. Announce the change.
+   * pine: Put ``inbox-path=Mailbox'' in your system-wide pine.conf.
+     (For pine versions more recent than 3.91, see also FAQ 6.2.)
 
-Some vendors, in a misguided attempt to solve the security problems of
-/usr/spool/mail, have made all MUAs (e.g., /usr/ucb/Mail) setgid mail.
-After you get rid of /usr/spool/mail, you can also disable those
-setgid-mail bits.
-
-
-2. The trouble with mbox
-
-The mbox format---the format of ~user/Mailbox, understood by BSD Mail
-and lots of other MUAs---is inherently unreliable.
-
-Think about it: what happens if the system crashes while a program is
-appending a new message to ~user/Mailbox? The message will be truncated.
-Even worse, if it was truncated in the middle of a line, it will end up
-being merged with the next message! Sure, the mailer understands that it
-wasn't successful, so it'll try delivering the message again later, but
-it can't fix your corrupted mbox.
-
-Other formats, such as mh folders, are just as unreliable.
-
-qmail supports maildir, a crashproof format for incoming mail messages.
-maildir is fast and easy for MUAs to use. Even better, maildir works
-wonders over NFS---see below.
-
-I don't want to cram maildir down people's throats, so it's not the
-default. Nevertheless, I encourage you to start asking for maildir
-versions of your favorite MUAs, and to switch over to maildir as soon as
-you can.
-
-WARNING: qmail uses flock() to lock ~user/Mailbox. This agrees with the
-modern mail.local locking choice. If your MUA doesn't use flock(), your
-best bet is to switch to maildir, and to set up synchronous maildir2mbox
-execution, as described below.
+   * qpopper 2.2: Change /.mail to /Mailbox in pop_dropcopy.c and
+     recompile with -DHOMEDIRMAIL in CFLAGS.
 
-
-3. Sun's Network F_\bail_\bu_\bre System
-
-Anyone who tells you that mail can be safely delivered in mbox format
-over NFS is pulling your leg---as explained above, mbox format is
-inherently unreliable even on a single machine.
-
-Anyway, NFS is the most unreliable computing environment ever invented,
-and qmail doesn't even pretend to support mbox over NFS.
-
-You should switch to maildir, which works fine over NFS without any
-locking. You can safely read your mail over NFS if it's in maildir
-format. Any number of machines can deliver mail to you at the same time.
-(On the other hand, for efficiency, it's better to get NFS out of the
-picture---your mail should be delivered on the server that contains your
-home directory.)
-
-Here's how to set up qmail to use maildir for your incoming mail:
-
-   % maildirmake $HOME/Maildir
-   % echo ./Maildir/ > ~/.qmail
-
-Make sure you include the trailing slash on Maildir/.
-
-Until your MUA supports maildir, you'll probably want to convert maildir
-format to (gaaack) mbox format. I've supplied a maildir2mbox utility
-that does the trick, along with some tiny qail and elq and pinq wrappers
-that call maildir2mbox before calling Mail or elm or pine.
+Some vendors, in a misguided attempt to solve the security problems of
+/var/spool/mail, have made all their mail software setgid mail. After
+you move the mailboxes, you can---and, for security, should---remove
+those setgid-mail bits.
diff --git a/INSTALL.qsmhook b/INSTALL.qsmhook
deleted file mode 100644 (file)
index 952fcd2..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-You can set up qmail to use the same local delivery agent as sendmail,
-through a mechanism called qsmhook. This file says how.
-
-Before you do this, may I ask why? If you simply don't want the hassle
-of moving user mailboxes from /usr/spool/mail to ~, please reconsider---
-/usr/spool/mail has always been a big security problem. See, for
-example, CERT advisory 95:02.
-
-If you're trying to preserve /etc/aliases and ~user/.forward, you're
-looking the wrong way---those are handled by sendmail internally, not by
-the local delivery agent. You can use your old /etc/aliases with qmail
-by installing the qmsmac package.
-
-Perhaps you've set up an advanced agent like procmail. But most people
-use procmail for nothing more than sorting mail into several mailboxes;
-and that's much easier with qmail's local forwarding mechanism, which
-gives each user control over user-anything. If you have a few users who
-really do need procmail, they can easily run procmail from their own
-.qmail files.
-
-Do you still want to set up qsmhook? Send me some e-mail and let me know
-why. Perhaps I can provide something for you in a future qmail release.
-
-Here's what to do. First, tack ``:alias'' onto the end of each address
-in /var/qmail/control/locals, and put the results into
-/var/qmail/control/virtualdomains. For example, if control/locals has
-
-   localhost
-   silverton.berkeley.edu
-
-then control/virtualdomains should now have (without extra spaces)
-
-   localhost:alias
-   silverton.berkeley.edu:alias
-
-Second, cp /dev/null control/locals.
-
-Third, put a line into ~alias/.qmail-default, based on sendmail's Mlocal
-line. For example, if sendmail.cf has
-
-   Mlocal, P=/bin/mail, F=lsDFMPrmn, S=10, R=20, A=mail -d $u
-
-then ~alias/.qmail-default should have
-
-   |qsmhook -x alias- -lsDFMPmn /bin/mail -r %g -d %u
-
-As another example, if sendmail.cf has
-
-   Mlocal, P=/usr/lib/mail.local, F=flsSDFMmnP, S=10, R=20, A=mail.local -d $u
-
-then ~alias/.qmail-default should have
-
-   |qsmhook -x alias- -lsDFMmnP /usr/lib/mail.local -f %g -d %u
diff --git a/INSTALL.vsm b/INSTALL.vsm
new file mode 100644 (file)
index 0000000..cf6a6cc
--- /dev/null
@@ -0,0 +1,50 @@
+UNIX has traditionally delivered mail into a central spool directory,
+/var/spool/mail. (The original name was /usr/spool/mail; some systems
+now use /var/mail.) There are two basic problems with /var/spool/mail:
+
+   * It's slow. On systems with thousands of users, /var/spool/mail has
+     thousands of entries. A few UNIX systems support fast operations on
+     large directories, but most don't.
+
+   * It's insecure. Writing code that works safely in a world-writable
+     directory is not easy. See, for example, CERT advisory 95:02.
+
+These may not be problems at your site, so you may want to leave your
+mailboxes in /var/spool/mail.
+
+This file explains several ways that you can configure qmail to use
+existing /var/spool/mail delivery tools. Please note that I do not vouch
+for the security or reliability of any of those tools.
+
+
+1. What to configure
+
+The qmail system is started from /var/qmail/rc with
+
+   qmail-start ./Mailbox splogger qmail
+
+The first argument to qmail-start, ./Mailbox, is the default delivery
+instruction. You can change it to run a program such as binmail or
+procmail. (See dot-qmail.0 for the format of delivery instructions.)
+
+
+2. Using procmail
+
+You may already have installed procmail for mail filtering. procmail
+delivers to /var/spool/mail by default.
+
+To set up qmail to use procmail, simply copy /var/qmail/boot/proc to
+/var/qmail/rc.
+
+Note that procmail must be in your system's boot PATH; if it isn't, you
+will have edit /var/qmail/rc to include the full path.
+
+
+3. Using sendmail's delivery agent
+
+sendmail uses binmail to deliver to /var/spool/mail. binmail is shipped
+with the operating system as /bin/mail or /usr/libexec/mail.local.
+
+There is some variation in binmail syntax among systems. The most common
+interfaces are shown in /var/qmail/boot/binm1, /var/qmail/boot/binm2,
+and /var/qmail/boot/binm3.
index ee80517..e668ae8 100644 (file)
--- a/INTERNALS
+++ b/INTERNALS
@@ -96,7 +96,8 @@ qmail-send may at its leisure try to deliver a message to a NOT DONE
 address. If the message is successfully delivered, qmail-send marks the
 address as DONE. If the delivery attempt meets with permanent failure,
 qmail-send first appends a note to bounce/457, creating bounce/457 if
-necessary; then it marks the address as DONE.
+necessary; then it marks the address as DONE. Note that bounce/457 is
+not crashproof.
 
 qmail-send may handle bounce/457 at any time, as follows: it (1) injects
 a new bounce message, created from bounce/457 and mess/457; (2) deletes
index 96a352c..9230887 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+# Don't edit Makefile! Use conf-* for configuration.
+
 SHELL=/bin/sh
 
 default: it
@@ -11,11 +13,11 @@ makelib alloc.o alloc_re.o
        ./makelib alloc.a alloc.o alloc_re.o
 
 alloc.o: \
-compile alloc.c alloc.h alloc.c error.h alloc.c
+compile alloc.c alloc.h error.h
        ./compile alloc.c
 
 alloc_re.o: \
-compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c
+compile alloc_re.c alloc.h byte.h
        ./compile alloc_re.c
 
 auto-ccld.sh: \
@@ -30,9 +32,8 @@ load auto-gid.o substdio.a error.a str.a fs.a
        ./load auto-gid substdio.a error.a str.a fs.a 
 
 auto-gid.o: \
-compile auto-gid.c auto-gid.c auto-gid.c subfd.h substdio.h subfd.h \
-auto-gid.c substdio.h substdio.h auto-gid.c readwrite.h auto-gid.c \
-exit.h auto-gid.c scan.h auto-gid.c fmt.h auto-gid.c
+compile auto-gid.c subfd.h substdio.h substdio.h readwrite.h exit.h \
+scan.h fmt.h
        ./compile auto-gid.c
 
 auto-int: \
@@ -40,8 +41,7 @@ load auto-int.o substdio.a error.a str.a fs.a
        ./load auto-int substdio.a error.a str.a fs.a 
 
 auto-int.o: \
-compile auto-int.c substdio.h auto-int.c readwrite.h auto-int.c \
-exit.h auto-int.c scan.h auto-int.c fmt.h auto-int.c
+compile auto-int.c substdio.h readwrite.h exit.h scan.h fmt.h
        ./compile auto-int.c
 
 auto-int8: \
@@ -49,8 +49,7 @@ load auto-int8.o substdio.a error.a str.a fs.a
        ./load auto-int8 substdio.a error.a str.a fs.a 
 
 auto-int8.o: \
-compile auto-int8.c substdio.h auto-int8.c readwrite.h auto-int8.c \
-exit.h auto-int8.c scan.h auto-int8.c fmt.h auto-int8.c
+compile auto-int8.c substdio.h readwrite.h exit.h scan.h fmt.h
        ./compile auto-int8.c
 
 auto-str: \
@@ -58,8 +57,7 @@ load auto-str.o substdio.a error.a str.a
        ./load auto-str substdio.a error.a str.a 
 
 auto-str.o: \
-compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \
-exit.h auto-str.c
+compile auto-str.c substdio.h readwrite.h exit.h
        ./compile auto-str.c
 
 auto-uid: \
@@ -67,9 +65,8 @@ load auto-uid.o substdio.a error.a str.a fs.a
        ./load auto-uid substdio.a error.a str.a fs.a 
 
 auto-uid.o: \
-compile auto-uid.c auto-uid.c auto-uid.c subfd.h substdio.h subfd.h \
-auto-uid.c substdio.h substdio.h auto-uid.c readwrite.h auto-uid.c \
-exit.h auto-uid.c scan.h auto-uid.c fmt.h auto-uid.c
+compile auto-uid.c subfd.h substdio.h substdio.h readwrite.h exit.h \
+scan.h fmt.h
        ./compile auto-uid.c
 
 auto_break.c: \
@@ -125,7 +122,7 @@ auto-uid auto-gid conf-users conf-groups
        &&./auto-uid auto_uids `head -8 conf-users | tail -1` \
        &&./auto-gid auto_gidq `head -1 conf-groups` \
        &&./auto-gid auto_gidn `head -2 conf-groups | tail -1` \
-       ) > auto_uids.c
+       ) > auto_uids.c.tmp && mv auto_uids.c.tmp auto_uids.c
 
 auto_uids.o: \
 compile auto_uids.c
@@ -139,28 +136,83 @@ auto_usera.o: \
 compile auto_usera.c
        ./compile auto_usera.c
 
+binm1: \
+binm1.sh conf-qmail
+       cat binm1.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm1
+       chmod 755 binm1
+
+binm1+df: \
+binm1+df.sh conf-qmail
+       cat binm1+df.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm1+df
+       chmod 755 binm1+df
+
+binm2: \
+binm2.sh conf-qmail
+       cat binm2.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm2
+       chmod 755 binm2
+
+binm2+df: \
+binm2+df.sh conf-qmail
+       cat binm2+df.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm2+df
+       chmod 755 binm2+df
+
+binm3: \
+binm3.sh conf-qmail
+       cat binm3.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm3
+       chmod 755 binm3
+
+binm3+df: \
+binm3+df.sh conf-qmail
+       cat binm3+df.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > binm3+df
+       chmod 755 binm3+df
+
+bouncesaying: \
+load bouncesaying.o strerr.a error.a substdio.a str.a wait.a
+       ./load bouncesaying strerr.a error.a substdio.a str.a \
+       wait.a 
+
+bouncesaying.0: \
+bouncesaying.1
+       nroff -man bouncesaying.1 > bouncesaying.0
+
+bouncesaying.o: \
+compile bouncesaying.c fork.h strerr.h error.h wait.h sig.h exit.h
+       ./compile bouncesaying.c
+
 byte_chr.o: \
-compile byte_chr.c byte.h byte_chr.c
+compile byte_chr.c byte.h
        ./compile byte_chr.c
 
 byte_copy.o: \
-compile byte_copy.c byte.h byte_copy.c
+compile byte_copy.c byte.h
        ./compile byte_copy.c
 
 byte_cr.o: \
-compile byte_cr.c byte.h byte_cr.c
+compile byte_cr.c byte.h
        ./compile byte_cr.c
 
 byte_diff.o: \
-compile byte_diff.c byte.h byte_diff.c
+compile byte_diff.c byte.h
        ./compile byte_diff.c
 
 byte_rchr.o: \
-compile byte_rchr.c byte.h byte_rchr.c
+compile byte_rchr.c byte.h
        ./compile byte_rchr.c
 
 byte_zero.o: \
-compile byte_zero.c byte.h byte_zero.c
+compile byte_zero.c byte.h
        ./compile byte_zero.c
 
 case.a: \
@@ -170,23 +222,23 @@ case_starts.o
        case_lowers.o case_starts.o
 
 case_diffb.o: \
-compile case_diffb.c case.h case_diffb.c
+compile case_diffb.c case.h
        ./compile case_diffb.c
 
 case_diffs.o: \
-compile case_diffs.c case.h case_diffs.c
+compile case_diffs.c case.h
        ./compile case_diffs.c
 
 case_lowerb.o: \
-compile case_lowerb.c case.h case_lowerb.c
+compile case_lowerb.c case.h
        ./compile case_lowerb.c
 
 case_lowers.o: \
-compile case_lowers.c case.h case_lowers.c
+compile case_lowers.c case.h
        ./compile case_lowers.c
 
 case_starts.o: \
-compile case_starts.c case.h case_starts.c
+compile case_starts.c case.h
        ./compile case_starts.c
 
 cdb.a: \
@@ -194,16 +246,15 @@ makelib cdb_hash.o cdb_unpack.o cdb_seek.o
        ./makelib cdb.a cdb_hash.o cdb_unpack.o cdb_seek.o
 
 cdb_hash.o: \
-compile cdb_hash.c cdb.h uint32.h cdb.h cdb_hash.c
+compile cdb_hash.c cdb.h uint32.h
        ./compile cdb_hash.c
 
 cdb_seek.o: \
-compile cdb_seek.c cdb_seek.c cdb_seek.c cdb.h uint32.h cdb.h \
-cdb_seek.c
+compile cdb_seek.c cdb.h uint32.h
        ./compile cdb_seek.c
 
 cdb_unpack.o: \
-compile cdb_unpack.c cdb.h uint32.h cdb.h cdb_unpack.c
+compile cdb_unpack.c cdb.h uint32.h
        ./compile cdb_unpack.c
 
 cdbmake.a: \
@@ -212,33 +263,32 @@ makelib cdbmake_pack.o cdbmake_hash.o cdbmake_add.o
        cdbmake_add.o
 
 cdbmake_add.o: \
-compile cdbmake_add.c cdbmake.h uint32.h cdbmake.h cdbmake_add.c
+compile cdbmake_add.c cdbmake.h uint32.h
        ./compile cdbmake_add.c
 
 cdbmake_hash.o: \
-compile cdbmake_hash.c cdbmake.h uint32.h cdbmake.h cdbmake_hash.c
+compile cdbmake_hash.c cdbmake.h uint32.h
        ./compile cdbmake_hash.c
 
 cdbmake_pack.o: \
-compile cdbmake_pack.c cdbmake.h uint32.h cdbmake.h cdbmake_pack.c
+compile cdbmake_pack.c cdbmake.h uint32.h
        ./compile cdbmake_pack.c
 
 cdbmss.o: \
-compile cdbmss.c readwrite.h cdbmss.c seek.h cdbmss.c alloc.h \
-cdbmss.c cdbmss.h cdbmake.h uint32.h cdbmake.h cdbmss.h substdio.h \
-cdbmss.h cdbmss.c
+compile cdbmss.c readwrite.h seek.h alloc.h cdbmss.h cdbmake.h \
+uint32.h substdio.h
        ./compile cdbmss.c
 
 check: \
-it man conf-qmail
-       ./qmail-hier | ./instcheck `head -1 conf-qmail`
+it man
+       ./instcheck
 
 chkshsgr: \
 load chkshsgr.o
        ./load chkshsgr 
 
 chkshsgr.o: \
-compile chkshsgr.c exit.h chkshsgr.c
+compile chkshsgr.c exit.h
        ./compile chkshsgr.c
 
 chkspawn: \
@@ -246,10 +296,8 @@ load chkspawn.o substdio.a error.a str.a fs.a auto_spawn.o
        ./load chkspawn substdio.a error.a str.a fs.a auto_spawn.o 
 
 chkspawn.o: \
-compile chkspawn.c substdio.h chkspawn.c subfd.h substdio.h \
-substdio.h subfd.h chkspawn.c fmt.h chkspawn.c select.h select.h \
-select.h select.h chkspawn.c exit.h chkspawn.c auto_spawn.h \
-chkspawn.c
+compile chkspawn.c substdio.h subfd.h substdio.h fmt.h select.h \
+exit.h auto_spawn.h
        ./compile chkspawn.c
 
 clean: \
@@ -257,9 +305,14 @@ TARGETS
        rm -f `cat TARGETS`
 
 coe.o: \
-compile coe.c coe.c coe.h coe.c
+compile coe.c coe.h
        ./compile coe.c
 
+commands.o: \
+compile commands.c commands.h substdio.h stralloc.h gen_alloc.h str.h \
+case.h
+       ./compile commands.c
+
 compile: \
 make-compile warn-auto.sh systype
        ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
@@ -267,39 +320,49 @@ make-compile warn-auto.sh systype
        chmod 755 compile
 
 condredirect: \
-load condredirect.o qmail.o fd.a sig.a wait.a seek.a env.a alloc.a \
-substdio.a error.a str.a auto_qmail.o
-       ./load condredirect qmail.o fd.a sig.a wait.a seek.a env.a \
-       alloc.a substdio.a error.a str.a auto_qmail.o 
+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 
 
 condredirect.0: \
 condredirect.1
        nroff -man condredirect.1 > condredirect.0
 
 condredirect.o: \
-compile condredirect.c sig.h condredirect.c readwrite.h \
-condredirect.c exit.h condredirect.c env.h condredirect.c error.h \
-condredirect.c fork.h condredirect.c wait.h condredirect.c seek.h \
-condredirect.c qmail.h substdio.h qmail.h condredirect.c stralloc.h \
-gen_alloc.h stralloc.h condredirect.c subfd.h substdio.h substdio.h \
-subfd.h condredirect.c substdio.h substdio.h condredirect.c
+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
        ./compile condredirect.c
 
+config: \
+warn-auto.sh config.sh conf-qmail conf-break conf-split
+       cat warn-auto.sh config.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       | sed s}BREAK}"`head -1 conf-break`"}g \
+       | sed s}SPLIT}"`head -1 conf-split`"}g \
+       > config
+       chmod 755 config
+
+config-fast: \
+warn-auto.sh config-fast.sh conf-qmail conf-break conf-split
+       cat warn-auto.sh config-fast.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       | sed s}BREAK}"`head -1 conf-break`"}g \
+       | sed s}SPLIT}"`head -1 conf-split`"}g \
+       > config-fast
+       chmod 755 config-fast
+
 constmap.o: \
-compile constmap.c constmap.h constmap.c alloc.h constmap.c case.h \
-constmap.c
+compile constmap.c constmap.h alloc.h case.h
        ./compile constmap.c
 
 control.o: \
-compile control.c readwrite.h control.c open.h control.c getln.h \
-control.c stralloc.h gen_alloc.h stralloc.h control.c substdio.h \
-control.c error.h control.c control.h control.c alloc.h control.c \
-scan.h control.c
+compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \
+substdio.h error.h control.h alloc.h scan.h
        ./compile control.c
 
 date822fmt.o: \
-compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \
-date822fmt.h date822fmt.c
+compile date822fmt.c datetime.h fmt.h date822fmt.h
        ./compile date822fmt.c
 
 datemail: \
@@ -316,11 +379,11 @@ makelib datetime.o datetime_un.o
        ./makelib datetime.a datetime.o datetime_un.o
 
 datetime.o: \
-compile datetime.c datetime.h datetime.c
+compile datetime.c datetime.h
        ./compile datetime.c
 
 datetime_un.o: \
-compile datetime_un.c datetime.h datetime_un.c
+compile datetime_un.c datetime.h
        ./compile datetime_un.c
 
 direntry.h: \
@@ -339,10 +402,8 @@ alloc.a error.a fs.a str.a
        rm -f tryrsolv.o tryrsolv
 
 dns.o: \
-compile dns.c dns.c dns.c dns.c dns.c dns.c dns.c dns.c ip.h dns.c \
-ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h dns.c fmt.h dns.c \
-alloc.h dns.c str.h dns.c stralloc.h gen_alloc.h stralloc.h dns.c \
-dns.h dns.c case.h dns.c
+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
 
 dnscname: \
@@ -353,15 +414,12 @@ substdio.a error.a str.a fs.a dns.lib socket.lib
        socket.lib`
 
 dnscname.o: \
-compile dnscname.c substdio.h dnscname.c subfd.h substdio.h \
-substdio.h subfd.h dnscname.c stralloc.h gen_alloc.h stralloc.h \
-dnscname.c dns.h dnscname.c dnsdoe.h dnscname.c readwrite.h \
-dnscname.c exit.h dnscname.c
+compile dnscname.c substdio.h subfd.h substdio.h stralloc.h \
+gen_alloc.h dns.h dnsdoe.h readwrite.h exit.h
        ./compile dnscname.c
 
 dnsdoe.o: \
-compile dnsdoe.c substdio.h dnsdoe.c subfd.h substdio.h substdio.h \
-subfd.h dnsdoe.c exit.h dnsdoe.c dns.h dnsdoe.c dnsdoe.h dnsdoe.c
+compile dnsdoe.c substdio.h subfd.h substdio.h exit.h dns.h dnsdoe.h
        ./compile dnsdoe.c
 
 dnsfq: \
@@ -372,10 +430,8 @@ substdio.a error.a str.a fs.a dns.lib socket.lib
        socket.lib`
 
 dnsfq.o: \
-compile dnsfq.c substdio.h dnsfq.c subfd.h substdio.h substdio.h \
-subfd.h dnsfq.c stralloc.h gen_alloc.h stralloc.h dnsfq.c dns.h \
-dnsfq.c dnsdoe.h dnsfq.c ip.h dnsfq.c ipalloc.h ip.h ip.h ipalloc.h \
-gen_alloc.h ipalloc.h dnsfq.c exit.h dnsfq.c
+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
 
 dnsip: \
@@ -386,10 +442,8 @@ substdio.a error.a str.a fs.a dns.lib socket.lib
        socket.lib`
 
 dnsip.o: \
-compile dnsip.c substdio.h dnsip.c subfd.h substdio.h substdio.h \
-subfd.h dnsip.c stralloc.h gen_alloc.h stralloc.h dnsip.c dns.h \
-dnsip.c dnsdoe.h dnsip.c ip.h dnsip.c ipalloc.h ip.h ip.h ipalloc.h \
-gen_alloc.h ipalloc.h dnsip.c exit.h dnsip.c
+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
 
 dnsmxip: \
@@ -400,11 +454,9 @@ substdio.a error.a str.a fs.a dns.lib socket.lib
        dns.lib` `cat socket.lib`
 
 dnsmxip.o: \
-compile dnsmxip.c substdio.h dnsmxip.c subfd.h substdio.h substdio.h \
-subfd.h dnsmxip.c stralloc.h gen_alloc.h stralloc.h dnsmxip.c fmt.h \
-dnsmxip.c dns.h dnsmxip.c dnsdoe.h dnsmxip.c ip.h dnsmxip.c ipalloc.h \
-ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h dnsmxip.c now.h datetime.h \
-now.h dnsmxip.c exit.h dnsmxip.c
+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 \
+now.h datetime.h exit.h
        ./compile dnsmxip.c
 
 dnsptr: \
@@ -415,10 +467,8 @@ substdio.a error.a str.a fs.a dns.lib socket.lib
        socket.lib`
 
 dnsptr.o: \
-compile dnsptr.c substdio.h dnsptr.c subfd.h substdio.h substdio.h \
-subfd.h dnsptr.c stralloc.h gen_alloc.h stralloc.h dnsptr.c str.h \
-dnsptr.c scan.h dnsptr.c dns.h dnsptr.c dnsdoe.h dnsptr.c ip.h \
-dnsptr.c exit.h dnsptr.c
+compile dnsptr.c substdio.h subfd.h substdio.h stralloc.h gen_alloc.h \
+str.h scan.h dns.h dnsdoe.h ip.h exit.h
        ./compile dnsptr.c
 
 dot-qmail.0: \
@@ -447,7 +497,7 @@ makelib env.o envread.o
        ./makelib env.a env.o envread.o
 
 env.o: \
-compile env.c str.h env.c alloc.h env.c env.h env.c
+compile env.c str.h alloc.h env.h
        ./compile env.c
 
 envelopes.0: \
@@ -455,7 +505,7 @@ envelopes.5
        nroff -man envelopes.5 > envelopes.0
 
 envread.o: \
-compile envread.c env.h envread.c str.h envread.c
+compile envread.c env.h str.h
        ./compile envread.c
 
 error.a: \
@@ -463,31 +513,43 @@ makelib error.o error_str.o error_temp.o
        ./makelib error.a error.o error_str.o error_temp.o
 
 error.o: \
-compile error.c error.c error.h error.c
+compile error.c error.h
        ./compile error.c
 
 error_str.o: \
-compile error_str.c error_str.c error.h error_str.c
+compile error_str.c error.h
        ./compile error_str.c
 
 error_temp.o: \
-compile error_temp.c error_temp.c error.h error_temp.c
+compile error_temp.c error.h
        ./compile error_temp.c
 
+except: \
+load except.o strerr.a error.a substdio.a str.a wait.a
+       ./load except strerr.a error.a substdio.a str.a wait.a 
+
+except.0: \
+except.1
+       nroff -man except.1 > except.0
+
+except.o: \
+compile except.c fork.h strerr.h wait.h error.h exit.h
+       ./compile except.c
+
 fd.a: \
 makelib fd_copy.o fd_move.o
        ./makelib fd.a fd_copy.o fd_move.o
 
 fd_copy.o: \
-compile fd_copy.c fd_copy.c fd.h fd_copy.c
+compile fd_copy.c fd.h
        ./compile fd_copy.c
 
 fd_move.o: \
-compile fd_move.c fd.h fd_move.c
+compile fd_move.c fd.h
        ./compile fd_move.c
 
 fifo.o: \
-compile fifo.c fifo.c fifo.c hasmkffo.h fifo.c fifo.h fifo.c
+compile fifo.c hasmkffo.h fifo.h
        ./compile fifo.c
 
 find-systype: \
@@ -496,28 +558,27 @@ find-systype.sh auto-ccld.sh
        chmod 755 find-systype
 
 fmt_str.o: \
-compile fmt_str.c fmt.h fmt_str.c
+compile fmt_str.c fmt.h
        ./compile fmt_str.c
 
 fmt_strn.o: \
-compile fmt_strn.c fmt.h fmt_strn.c
+compile fmt_strn.c fmt.h
        ./compile fmt_strn.c
 
 fmt_uint.o: \
-compile fmt_uint.c fmt.h fmt_uint.c
+compile fmt_uint.c fmt.h
        ./compile fmt_uint.c
 
 fmt_uint0.o: \
-compile fmt_uint0.c fmt.h fmt_uint0.c
+compile fmt_uint0.c fmt.h
        ./compile fmt_uint0.c
 
 fmt_ulong.o: \
-compile fmt_ulong.c fmt.h fmt_ulong.c
+compile fmt_ulong.c fmt.h
        ./compile fmt_ulong.c
 
 fmtqfn.o: \
-compile fmtqfn.c fmtqfn.h fmtqfn.c fmt.h fmtqfn.c auto_split.h \
-fmtqfn.c
+compile fmtqfn.c fmtqfn.h fmt.h auto_split.h
        ./compile fmtqfn.c
 
 forgeries.0: \
@@ -532,40 +593,36 @@ compile load tryvfork.c fork.h1 fork.h2
        rm -f tryvfork.o tryvfork
 
 forward: \
-load forward.o stralloc.a alloc.a qmail.o fd.a wait.a sig.a env.a \
-substdio.a error.a str.a auto_qmail.o
-       ./load forward stralloc.a alloc.a qmail.o fd.a wait.a \
-       sig.a env.a substdio.a error.a str.a auto_qmail.o 
+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 
 
 forward.0: \
 forward.1
        nroff -man forward.1 > forward.0
 
 forward.o: \
-compile forward.c sig.h forward.c readwrite.h forward.c exit.h \
-forward.c env.h forward.c qmail.h substdio.h qmail.h forward.c \
-stralloc.h gen_alloc.h stralloc.h forward.c subfd.h substdio.h \
-substdio.h subfd.h forward.c substdio.h substdio.h forward.c
+compile forward.c sig.h readwrite.h exit.h env.h qmail.h substdio.h \
+strerr.h substdio.h fmt.h
        ./compile forward.c
 
 fs.a: \
 makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \
-scan_ulong.o scan_8long.o scan_nbblong.o
+scan_ulong.o scan_8long.o
        ./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \
-       fmt_ulong.o scan_ulong.o scan_8long.o scan_nbblong.o
+       fmt_ulong.o scan_ulong.o scan_8long.o
 
 getln.a: \
 makelib getln.o getln2.o
        ./makelib getln.a getln.o getln2.o
 
 getln.o: \
-compile getln.c substdio.h getln.c byte.h getln.c stralloc.h \
-gen_alloc.h stralloc.h getln.c getln.h getln.c
+compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h
        ./compile getln.c
 
 getln2.o: \
-compile getln2.c substdio.h getln2.c stralloc.h gen_alloc.h \
-stralloc.h getln2.c byte.h getln2.c getln.h getln2.c
+compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h
        ./compile getln2.c
 
 getopt.a: \
@@ -573,7 +630,7 @@ makelib subgetopt.o sgetopt.o
        ./makelib getopt.a subgetopt.o sgetopt.o
 
 gfrom.o: \
-compile gfrom.c str.h gfrom.c gfrom.h gfrom.c
+compile gfrom.c str.h gfrom.h
        ./compile gfrom.c
 
 hasflock.h: \
@@ -636,68 +693,97 @@ trywaitp.c compile load
        rm -f trywaitp.o trywaitp
 
 headerbody.o: \
-compile headerbody.c stralloc.h gen_alloc.h stralloc.h headerbody.c \
-substdio.h headerbody.c getln.h headerbody.c hfield.h headerbody.c \
-headerbody.h headerbody.c
+compile headerbody.c stralloc.h gen_alloc.h substdio.h getln.h \
+hfield.h headerbody.h
        ./compile headerbody.c
 
 hfield.o: \
-compile hfield.c hfield.h hfield.c
+compile hfield.c hfield.h
        ./compile hfield.c
 
+hier.o: \
+compile hier.c auto_qmail.h auto_split.h auto_uids.h fmt.h fifo.h
+       ./compile hier.c
+
+home: \
+home.sh conf-qmail
+       cat home.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > home
+       chmod 755 home
+
+home+df: \
+home+df.sh conf-qmail
+       cat home+df.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > home+df
+       chmod 755 home+df
+
 hostname: \
 load hostname.o substdio.a error.a str.a dns.lib socket.lib
        ./load hostname substdio.a error.a str.a  `cat dns.lib` \
        `cat socket.lib`
 
 hostname.o: \
-compile hostname.c substdio.h hostname.c subfd.h substdio.h \
-substdio.h subfd.h hostname.c readwrite.h hostname.c exit.h \
-hostname.c
+compile hostname.c substdio.h subfd.h substdio.h readwrite.h exit.h
        ./compile hostname.c
 
+idedit: \
+load idedit.o strerr.a substdio.a error.a str.a fs.a wait.a open.a \
+seek.a
+       ./load idedit strerr.a substdio.a error.a str.a fs.a \
+       wait.a open.a seek.a 
+
+idedit.o: \
+compile idedit.c readwrite.h exit.h scan.h fmt.h strerr.h open.h \
+seek.h fork.h
+       ./compile idedit.c
+
 install: \
-load install.o fifo.o getln.a strerr.a substdio.a stralloc.a alloc.a \
-open.a error.a str.a fs.a
-       ./load install fifo.o getln.a strerr.a substdio.a \
-       stralloc.a alloc.a open.a error.a str.a fs.a 
+load install.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \
+strerr.a substdio.a open.a error.a str.a fs.a
+       ./load install fifo.o hier.o auto_qmail.o auto_split.o \
+       auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a 
+
+install-big: \
+load install-big.o fifo.o install.o auto_qmail.o auto_split.o \
+auto_uids.o strerr.a substdio.a open.a error.a str.a fs.a
+       ./load install-big fifo.o install.o auto_qmail.o \
+       auto_split.o auto_uids.o strerr.a substdio.a open.a error.a \
+       str.a fs.a 
+
+install-big.o: \
+compile install-big.c auto_qmail.h auto_split.h auto_uids.h fmt.h \
+fifo.h
+       ./compile install-big.c
 
 install.o: \
-compile install.c substdio.h install.c stralloc.h gen_alloc.h \
-stralloc.h install.c getln.h install.c readwrite.h install.c exit.h \
-install.c open.h install.c error.h install.c strerr.h install.c \
-byte.h install.c fifo.h install.c
+compile install.c substdio.h strerr.h error.h open.h readwrite.h \
+exit.h
        ./compile install.c
 
 instcheck: \
-load instcheck.o getln.a strerr.a substdio.a stralloc.a alloc.a \
-error.a str.a fs.a
-       ./load instcheck getln.a strerr.a substdio.a stralloc.a \
-       alloc.a error.a str.a fs.a 
+load instcheck.o fifo.o hier.o auto_qmail.o auto_split.o auto_uids.o \
+strerr.a substdio.a error.a str.a fs.a
+       ./load instcheck fifo.o hier.o auto_qmail.o auto_split.o \
+       auto_uids.o strerr.a substdio.a error.a str.a fs.a 
 
 instcheck.o: \
-compile instcheck.c instcheck.c instcheck.c substdio.h instcheck.c \
-stralloc.h gen_alloc.h stralloc.h instcheck.c getln.h instcheck.c \
-readwrite.h instcheck.c exit.h instcheck.c error.h instcheck.c \
-strerr.h instcheck.c byte.h instcheck.c
+compile instcheck.c strerr.h error.h readwrite.h exit.h
        ./compile instcheck.c
 
 ip.o: \
-compile ip.c fmt.h ip.c scan.h ip.c ip.h ip.c
+compile ip.c fmt.h scan.h ip.h
        ./compile ip.c
 
 ipalloc.o: \
-compile ipalloc.c alloc.h ipalloc.c gen_allocdefs.h gen_allocdefs.h \
-gen_allocdefs.h ipalloc.c ip.h ipalloc.c ipalloc.h ip.h ip.h \
-ipalloc.h gen_alloc.h ipalloc.h ipalloc.c
+compile ipalloc.c alloc.h gen_allocdefs.h ip.h ipalloc.h ip.h \
+gen_alloc.h
        ./compile ipalloc.c
 
 ipme.o: \
-compile ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c ipme.c \
-hassalen.h ipme.c byte.h ipme.c ip.h ipme.c ipalloc.h ip.h ip.h \
-ipalloc.h gen_alloc.h ipalloc.h ipme.c stralloc.h gen_alloc.h \
-stralloc.h ipme.c ipme.h ip.h ip.h ipme.h ipalloc.h ipalloc.h ipme.h \
-ipme.c ipme.c
+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
 
 ipmeprint: \
@@ -707,21 +793,22 @@ error.a str.a fs.a socket.lib
        substdio.a error.a str.a fs.a  `cat socket.lib`
 
 ipmeprint.o: \
-compile ipmeprint.c subfd.h substdio.h subfd.h ipmeprint.c substdio.h \
-substdio.h ipmeprint.c ip.h ipmeprint.c ipme.h ip.h ip.h ipme.h \
-ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h ipme.h \
-ipmeprint.c exit.h ipmeprint.c
+compile ipmeprint.c subfd.h substdio.h substdio.h ip.h ipme.h ip.h \
+ipalloc.h ip.h gen_alloc.h exit.h
        ./compile ipmeprint.c
 
 it: \
 qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \
 qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \
-predate datemail mailsubj qmail-upq qmail-config qmail-showctl \
-qmail-newu qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-pop3d \
-qmail-popup qmail-qmtpd qmail-smtpd sendmail tcp-env dnscname dnsptr \
-dnsip dnsmxip dnsfq hostname ipmeprint qlist qlist2 qreceipt qsmhook \
-qbiff forward preline condredirect maildirmake maildir2mbox \
-maildirwatch qail elq pinq qmail-hier install instcheck
+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 \
+forward preline condredirect bouncesaying except maildirmake \
+maildir2mbox maildirwatch qail elq pinq idedit install-big install \
+instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \
+binm3 binm3+df
 
 load: \
 make-load warn-auto.sh systype
@@ -733,18 +820,15 @@ makelib lock_ex.o lock_exnb.o lock_un.o
        ./makelib lock.a lock_ex.o lock_exnb.o lock_un.o
 
 lock_ex.o: \
-compile lock_ex.c lock_ex.c lock_ex.c lock_ex.c hasflock.h lock_ex.c \
-lock.h lock_ex.c
+compile lock_ex.c hasflock.h lock.h
        ./compile lock_ex.c
 
 lock_exnb.o: \
-compile lock_exnb.c lock_exnb.c lock_exnb.c lock_exnb.c hasflock.h \
-lock_exnb.c lock.h lock_exnb.c
+compile lock_exnb.c hasflock.h lock.h
        ./compile lock_exnb.c
 
 lock_un.o: \
-compile lock_un.c lock_un.c lock_un.c lock_un.c hasflock.h lock_un.c \
-lock.h lock_un.c
+compile lock_un.c hasflock.h lock.h
        ./compile lock_un.c
 
 maildir.0: \
@@ -752,11 +836,9 @@ maildir.5
        nroff -man maildir.5 > maildir.0
 
 maildir.o: \
-compile maildir.c maildir.c maildir.c prioq.h datetime.h prioq.h \
-gen_alloc.h prioq.h maildir.c env.h maildir.c stralloc.h gen_alloc.h \
-stralloc.h maildir.c direntry.h direntry.h direntry.h maildir.c \
-datetime.h datetime.h maildir.c now.h datetime.h datetime.h now.h \
-maildir.c str.h maildir.c maildir.h strerr.h maildir.h maildir.c
+compile maildir.c prioq.h datetime.h gen_alloc.h env.h stralloc.h \
+gen_alloc.h direntry.h datetime.h now.h datetime.h str.h maildir.h \
+strerr.h
        ./compile maildir.c
 
 maildir2mbox: \
@@ -772,28 +854,22 @@ maildir2mbox.1
        nroff -man maildir2mbox.1 > maildir2mbox.0
 
 maildir2mbox.o: \
-compile maildir2mbox.c readwrite.h maildir2mbox.c prioq.h datetime.h \
-prioq.h gen_alloc.h prioq.h maildir2mbox.c env.h maildir2mbox.c \
-stralloc.h gen_alloc.h stralloc.h maildir2mbox.c subfd.h substdio.h \
-subfd.h maildir2mbox.c substdio.h substdio.h maildir2mbox.c getln.h \
-maildir2mbox.c error.h maildir2mbox.c open.h maildir2mbox.c lock.h \
-maildir2mbox.c gfrom.h maildir2mbox.c str.h maildir2mbox.c exit.h \
-maildir2mbox.c myctime.h maildir2mbox.c maildir.h strerr.h maildir.h \
-maildir2mbox.c
+compile maildir2mbox.c readwrite.h prioq.h datetime.h gen_alloc.h \
+env.h stralloc.h gen_alloc.h subfd.h substdio.h substdio.h getln.h \
+error.h open.h lock.h gfrom.h str.h exit.h myctime.h maildir.h \
+strerr.h
        ./compile maildir2mbox.c
 
 maildirmake: \
-load maildirmake.o substdio.a error.a str.a
-       ./load maildirmake substdio.a error.a str.a 
+load maildirmake.o strerr.a substdio.a error.a str.a
+       ./load maildirmake strerr.a substdio.a error.a str.a 
 
 maildirmake.0: \
 maildirmake.1
        nroff -man maildirmake.1 > maildirmake.0
 
 maildirmake.o: \
-compile maildirmake.c subfd.h substdio.h subfd.h maildirmake.c \
-substdio.h substdio.h maildirmake.c error.h maildirmake.c exit.h \
-maildirmake.c
+compile maildirmake.c strerr.h exit.h
        ./compile maildirmake.c
 
 maildirwatch: \
@@ -809,13 +885,9 @@ maildirwatch.1
        nroff -man maildirwatch.1 > maildirwatch.0
 
 maildirwatch.o: \
-compile maildirwatch.c getln.h maildirwatch.c substdio.h \
-maildirwatch.c subfd.h substdio.h substdio.h subfd.h maildirwatch.c \
-prioq.h datetime.h prioq.h gen_alloc.h prioq.h maildirwatch.c \
-stralloc.h gen_alloc.h stralloc.h maildirwatch.c str.h maildirwatch.c \
-exit.h maildirwatch.c hfield.h maildirwatch.c readwrite.h \
-maildirwatch.c open.h maildirwatch.c headerbody.h maildirwatch.c \
-maildir.h strerr.h maildir.h maildirwatch.c
+compile maildirwatch.c getln.h substdio.h subfd.h substdio.h prioq.h \
+datetime.h gen_alloc.h stralloc.h gen_alloc.h str.h exit.h hfield.h \
+readwrite.h open.h headerbody.h maildir.h strerr.h
        ./compile maildirwatch.c
 
 mailsubj: \
@@ -856,11 +928,12 @@ man: \
 qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \
 qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \
 qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \
-qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-pop3d.0 \
-qmail-popup.0 qmail-qmtpd.0 qmail-smtpd.0 tcp-env.0 qlist.0 \
-qreceipt.0 qbiff.0 forward.0 preline.0 condredirect.0 maildirmake.0 \
-maildir2mbox.0 maildirwatch.0 qmail.0 qmail-upgrade.0 qmail-limits.0 \
-qmail-log.0 qmail-control.0 qmail-header.0 qmail-users.0 dot-qmail.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 \
+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
 
@@ -869,8 +942,7 @@ mbox.5
        nroff -man mbox.5 > mbox.0
 
 myctime.o: \
-compile myctime.c datetime.h myctime.c fmt.h myctime.c myctime.h \
-myctime.c
+compile myctime.c datetime.h fmt.h myctime.h
        ./compile myctime.c
 
 ndelay.a: \
@@ -878,22 +950,20 @@ makelib ndelay.o ndelay_off.o
        ./makelib ndelay.a ndelay.o ndelay_off.o
 
 ndelay.o: \
-compile ndelay.c ndelay.c ndelay.c ndelay.h ndelay.c
+compile ndelay.c ndelay.h
        ./compile ndelay.c
 
 ndelay_off.o: \
-compile ndelay_off.c ndelay_off.c ndelay_off.c ndelay.h ndelay_off.c
+compile ndelay_off.c ndelay.h
        ./compile ndelay_off.c
 
 newfield.o: \
-compile newfield.c fmt.h newfield.c datetime.h newfield.c stralloc.h \
-gen_alloc.h stralloc.h newfield.c date822fmt.h newfield.c newfield.h \
-stralloc.h stralloc.h newfield.h newfield.c
+compile newfield.c fmt.h datetime.h stralloc.h gen_alloc.h \
+date822fmt.h newfield.h stralloc.h
        ./compile newfield.c
 
 now.o: \
-compile now.c now.c datetime.h now.c now.h datetime.h datetime.h \
-now.h now.c
+compile now.c datetime.h now.h datetime.h
        ./compile now.c
 
 open.a: \
@@ -903,24 +973,23 @@ open_write.o
        open_trunc.o open_write.o
 
 open_append.o: \
-compile open_append.c open_append.c open_append.c open.h \
-open_append.c
+compile open_append.c open.h
        ./compile open_append.c
 
 open_excl.o: \
-compile open_excl.c open_excl.c open_excl.c open.h open_excl.c
+compile open_excl.c open.h
        ./compile open_excl.c
 
 open_read.o: \
-compile open_read.c open_read.c open_read.c open.h open_read.c
+compile open_read.c open.h
        ./compile open_read.c
 
 open_trunc.o: \
-compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c
+compile open_trunc.c open.h
        ./compile open_trunc.c
 
 open_write.o: \
-compile open_write.c open_write.c open_write.c open.h open_write.c
+compile open_write.c open.h
        ./compile open_write.c
 
 pinq: \
@@ -933,43 +1002,52 @@ warn-auto.sh pinq.sh conf-qmail conf-break conf-split
        chmod 755 pinq
 
 predate: \
-load predate.o datetime.a sig.a fd.a wait.a substdio.a error.a str.a \
-fs.a
-       ./load predate datetime.a sig.a fd.a wait.a substdio.a \
-       error.a str.a fs.a 
+load predate.o datetime.a strerr.a sig.a fd.a wait.a substdio.a \
+error.a str.a fs.a
+       ./load predate datetime.a strerr.a sig.a fd.a wait.a \
+       substdio.a error.a str.a fs.a 
 
 predate.o: \
-compile predate.c predate.c predate.c datetime.h predate.c fork.h \
-predate.c wait.h predate.c fd.h predate.c fmt.h predate.c substdio.h \
-predate.c subfd.h substdio.h substdio.h subfd.h predate.c readwrite.h \
-predate.c exit.h predate.c
+compile predate.c datetime.h fork.h wait.h fd.h fmt.h strerr.h \
+substdio.h subfd.h substdio.h readwrite.h exit.h
        ./compile predate.c
 
 preline: \
-load preline.o fd.a wait.a sig.a env.a getopt.a substdio.a error.a \
-str.a
-       ./load preline fd.a wait.a sig.a env.a getopt.a substdio.a \
-       error.a str.a 
+load preline.o strerr.a fd.a wait.a sig.a env.a getopt.a substdio.a \
+error.a str.a
+       ./load preline strerr.a fd.a wait.a sig.a env.a getopt.a \
+       substdio.a error.a str.a 
 
 preline.0: \
 preline.1
        nroff -man preline.1 > preline.0
 
 preline.o: \
-compile preline.c fd.h preline.c sgetopt.h subgetopt.h sgetopt.h \
-preline.c readwrite.h preline.c subfd.h substdio.h subfd.h preline.c \
-substdio.h substdio.h preline.c exit.h preline.c fork.h preline.c \
-wait.h preline.c env.h preline.c sig.h preline.c error.h preline.c
+compile preline.c fd.h sgetopt.h subgetopt.h readwrite.h strerr.h \
+substdio.h exit.h fork.h wait.h env.h sig.h error.h
        ./compile preline.c
 
 prioq.o: \
-compile prioq.c alloc.h prioq.c gen_allocdefs.h gen_allocdefs.h \
-gen_allocdefs.h prioq.c prioq.h datetime.h prioq.h gen_alloc.h \
-prioq.h prioq.c
+compile prioq.c alloc.h gen_allocdefs.h prioq.h datetime.h \
+gen_alloc.h
        ./compile prioq.c
 
+proc: \
+proc.sh conf-qmail
+       cat proc.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > proc
+       chmod 755 proc
+
+proc+df: \
+proc+df.sh conf-qmail
+       cat proc+df.sh \
+       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
+       > proc+df
+       chmod 755 proc+df
+
 prot.o: \
-compile prot.c hasshsgr.h prot.c prot.h prot.c
+compile prot.c hasshsgr.h prot.h
        ./compile prot.c
 
 qail: \
@@ -992,45 +1070,10 @@ qbiff.1
        nroff -man qbiff.1 > qbiff.0
 
 qbiff.o: \
-compile qbiff.c qbiff.c qbiff.c qbiff.c readwrite.h qbiff.c \
-stralloc.h gen_alloc.h stralloc.h qbiff.c substdio.h qbiff.c subfd.h \
-substdio.h substdio.h subfd.h qbiff.c open.h qbiff.c byte.h qbiff.c \
-str.h qbiff.c headerbody.h qbiff.c hfield.h qbiff.c env.h qbiff.c \
-exit.h qbiff.c
+compile qbiff.c readwrite.h stralloc.h gen_alloc.h substdio.h subfd.h \
+substdio.h open.h byte.h str.h headerbody.h hfield.h env.h exit.h
        ./compile qbiff.c
 
-qlist: \
-load qlist.o headerbody.o hfield.o token822.o qmail.o getln.a env.a \
-case.a sig.a fd.a wait.a open.a lock.a stralloc.a alloc.a substdio.a \
-error.a str.a auto_qmail.o
-       ./load qlist headerbody.o hfield.o token822.o qmail.o \
-       getln.a env.a case.a sig.a fd.a wait.a open.a lock.a \
-       stralloc.a alloc.a substdio.a error.a str.a auto_qmail.o 
-
-qlist.0: \
-qlist.1
-       nroff -man qlist.1 > qlist.0
-
-qlist.o: \
-compile qlist.c sig.h qlist.c readwrite.h qlist.c substdio.h qlist.c \
-stralloc.h gen_alloc.h stralloc.h qlist.c subfd.h substdio.h \
-substdio.h subfd.h qlist.c getln.h qlist.c alloc.h qlist.c str.h \
-qlist.c env.h qlist.c hfield.h qlist.c case.h qlist.c token822.h \
-gen_alloc.h token822.h qlist.c error.h qlist.c gen_alloc.h qlist.c \
-gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qlist.c headerbody.h \
-qlist.c exit.h qlist.c open.h qlist.c lock.h qlist.c qmail.h \
-substdio.h substdio.h qmail.h qlist.c qlist.c
-       ./compile qlist.c
-
-qlist2: \
-warn-auto.sh qlist2.sh conf-qmail conf-break conf-split
-       cat warn-auto.sh qlist2.sh \
-       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
-       | sed s}BREAK}"`head -1 conf-break`"}g \
-       | sed s}SPLIT}"`head -1 conf-split`"}g \
-       > qlist2
-       chmod 755 qlist2
-
 qmail-clean: \
 load qmail-clean.o fmtqfn.o now.o getln.a sig.a stralloc.a alloc.a \
 substdio.a error.a str.a fs.a auto_qmail.o auto_split.o
@@ -1043,29 +1086,15 @@ qmail-clean.8
        nroff -man qmail-clean.8 > qmail-clean.0
 
 qmail-clean.o: \
-compile qmail-clean.c qmail-clean.c qmail-clean.c readwrite.h \
-qmail-clean.c sig.h qmail-clean.c now.h datetime.h now.h \
-qmail-clean.c str.h qmail-clean.c direntry.h direntry.h direntry.h \
-qmail-clean.c getln.h qmail-clean.c stralloc.h gen_alloc.h stralloc.h \
-qmail-clean.c substdio.h qmail-clean.c subfd.h substdio.h substdio.h \
-subfd.h qmail-clean.c byte.h qmail-clean.c scan.h qmail-clean.c fmt.h \
-qmail-clean.c error.h qmail-clean.c exit.h qmail-clean.c fmtqfn.h \
-qmail-clean.c auto_qmail.h qmail-clean.c
+compile qmail-clean.c readwrite.h sig.h now.h datetime.h str.h \
+direntry.h getln.h stralloc.h gen_alloc.h substdio.h subfd.h \
+substdio.h byte.h scan.h fmt.h error.h exit.h fmtqfn.h auto_qmail.h
        ./compile qmail-clean.c
 
 qmail-command.0: \
 qmail-command.8
        nroff -man qmail-command.8 > qmail-command.0
 
-qmail-config: \
-warn-auto.sh qmail-config.sh conf-qmail conf-break conf-split
-       cat warn-auto.sh qmail-config.sh \
-       | sed s}QMAIL}"`head -1 conf-qmail`"}g \
-       | sed s}BREAK}"`head -1 conf-break`"}g \
-       | sed s}SPLIT}"`head -1 conf-split`"}g \
-       > qmail-config
-       chmod 755 qmail-config
-
 qmail-control.0: \
 qmail-control.5
        nroff -man qmail-control.5 > qmail-control.0
@@ -1097,59 +1126,36 @@ qmail-getpw.9 conf-break conf-spawn
        > qmail-getpw.8
 
 qmail-getpw.o: \
-compile qmail-getpw.c qmail-getpw.c qmail-getpw.c qmail-getpw.c \
-readwrite.h qmail-getpw.c substdio.h qmail-getpw.c subfd.h substdio.h \
-substdio.h subfd.h qmail-getpw.c error.h qmail-getpw.c exit.h \
-qmail-getpw.c byte.h qmail-getpw.c str.h qmail-getpw.c case.h \
-qmail-getpw.c fmt.h qmail-getpw.c auto_usera.h qmail-getpw.c \
-auto_break.h qmail-getpw.c qlx.h qmail-getpw.c
+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 \
+qlx.h
        ./compile qmail-getpw.c
 
 qmail-header.0: \
 qmail-header.5
        nroff -man qmail-header.5 > qmail-header.0
 
-qmail-hier: \
-load qmail-hier.o substdio.a error.a str.a fs.a auto_split.o \
-auto_uids.o
-       ./load qmail-hier substdio.a error.a str.a fs.a \
-       auto_split.o auto_uids.o 
-
-qmail-hier.o: \
-compile qmail-hier.c subfd.h substdio.h subfd.h qmail-hier.c \
-substdio.h substdio.h qmail-hier.c auto_split.h qmail-hier.c \
-auto_uids.h qmail-hier.c fmt.h qmail-hier.c
-       ./compile qmail-hier.c
-
 qmail-inject: \
 load qmail-inject.o headerbody.o hfield.o newfield.o quote.o now.o \
-control.o date822fmt.o qmail.o 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
+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 \
-       quote.o now.o control.o date822fmt.o qmail.o 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 
+       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 
 
 qmail-inject.0: \
 qmail-inject.8
        nroff -man qmail-inject.8 > qmail-inject.0
 
 qmail-inject.o: \
-compile qmail-inject.c sig.h qmail-inject.c substdio.h qmail-inject.c \
-stralloc.h gen_alloc.h stralloc.h qmail-inject.c subfd.h substdio.h \
-substdio.h subfd.h qmail-inject.c sgetopt.h subgetopt.h sgetopt.h \
-qmail-inject.c getln.h qmail-inject.c alloc.h qmail-inject.c str.h \
-qmail-inject.c fmt.h qmail-inject.c hfield.h qmail-inject.c \
-token822.h gen_alloc.h token822.h qmail-inject.c control.h \
-qmail-inject.c env.h qmail-inject.c gen_alloc.h qmail-inject.c \
-gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qmail-inject.c \
-error.h qmail-inject.c qmail.h substdio.h substdio.h qmail.h \
-qmail-inject.c now.h datetime.h now.h qmail-inject.c exit.h \
-qmail-inject.c quote.h qmail-inject.c headerbody.h qmail-inject.c \
-auto_qmail.h qmail-inject.c newfield.h stralloc.h stralloc.h \
-newfield.h qmail-inject.c
+compile qmail-inject.c sig.h substdio.h stralloc.h gen_alloc.h \
+subfd.h substdio.h sgetopt.h subgetopt.h getln.h alloc.h str.h fmt.h \
+hfield.h token822.h gen_alloc.h control.h env.h gen_alloc.h \
+gen_allocdefs.h error.h qmail.h substdio.h now.h datetime.h exit.h \
+quote.h headerbody.h auto_qmail.h newfield.h stralloc.h constmap.h
        ./compile qmail-inject.c
 
 qmail-limits.0: \
@@ -1167,31 +1173,24 @@ qmail-limits.9 conf-break conf-spawn
 qmail-local: \
 load qmail-local.o qmail.o quote.o now.o gfrom.o myctime.o \
 slurpclose.o case.a getln.a getopt.a sig.a open.a seek.a lock.a fd.a \
-wait.a env.a stralloc.a alloc.a substdio.a error.a str.a fs.a \
-datetime.a auto_qmail.o auto_patrn.o socket.lib
+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 \
        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 substdio.a \
-       error.a str.a fs.a datetime.a auto_qmail.o auto_patrn.o  \
-       `cat socket.lib`
+       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`
 
 qmail-local.0: \
 qmail-local.8
        nroff -man qmail-local.8 > qmail-local.0
 
 qmail-local.o: \
-compile qmail-local.c qmail-local.c qmail-local.c readwrite.h \
-qmail-local.c sig.h qmail-local.c env.h qmail-local.c byte.h \
-qmail-local.c exit.h qmail-local.c fork.h qmail-local.c open.h \
-qmail-local.c wait.h qmail-local.c lock.h qmail-local.c seek.h \
-qmail-local.c substdio.h qmail-local.c getln.h qmail-local.c subfd.h \
-substdio.h substdio.h subfd.h qmail-local.c sgetopt.h subgetopt.h \
-sgetopt.h qmail-local.c alloc.h qmail-local.c error.h qmail-local.c \
-stralloc.h gen_alloc.h stralloc.h qmail-local.c fmt.h qmail-local.c \
-str.h qmail-local.c now.h datetime.h now.h qmail-local.c case.h \
-qmail-local.c quote.h qmail-local.c qmail.h substdio.h substdio.h \
-qmail.h qmail-local.c slurpclose.h qmail-local.c myctime.h \
-qmail-local.c gfrom.h qmail-local.c auto_patrn.h qmail-local.c
+compile qmail-local.c readwrite.h sig.h env.h byte.h exit.h fork.h \
+open.h wait.h lock.h seek.h substdio.h getln.h strerr.h subfd.h \
+substdio.h sgetopt.h subgetopt.h alloc.h error.h stralloc.h \
+gen_alloc.h fmt.h str.h now.h datetime.h case.h quote.h qmail.h \
+substdio.h slurpclose.h myctime.h gfrom.h auto_patrn.h
        ./compile qmail-local.c
 
 qmail-log.0: \
@@ -1212,15 +1211,36 @@ qmail-lspawn.8
        nroff -man qmail-lspawn.8 > qmail-lspawn.0
 
 qmail-lspawn.o: \
-compile qmail-lspawn.c fd.h qmail-lspawn.c wait.h qmail-lspawn.c \
-prot.h qmail-lspawn.c substdio.h qmail-lspawn.c stralloc.h \
-gen_alloc.h stralloc.h qmail-lspawn.c scan.h qmail-lspawn.c exit.h \
-qmail-lspawn.c fork.h qmail-lspawn.c error.h qmail-lspawn.c cdb.h \
-uint32.h cdb.h qmail-lspawn.c case.h qmail-lspawn.c slurpclose.h \
-qmail-lspawn.c auto_qmail.h qmail-lspawn.c auto_uids.h qmail-lspawn.c \
-qlx.h qmail-lspawn.c
+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
        ./compile qmail-lspawn.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
+       ./load qmail-newmrh 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-newmrh.0: \
+qmail-newmrh.8
+       nroff -man qmail-newmrh.8 > qmail-newmrh.0
+
+qmail-newmrh.8: \
+qmail-newmrh.9 conf-break conf-spawn
+       cat qmail-newmrh.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-newmrh.8
+
+qmail-newmrh.o: \
+compile qmail-newmrh.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-newmrh.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
@@ -1241,54 +1261,47 @@ qmail-newu.9 conf-break conf-spawn
        > qmail-newu.8
 
 qmail-newu.o: \
-compile qmail-newu.c stralloc.h gen_alloc.h stralloc.h qmail-newu.c \
-subfd.h substdio.h subfd.h qmail-newu.c getln.h qmail-newu.c \
-substdio.h substdio.h qmail-newu.c cdbmss.h cdbmake.h uint32.h \
-cdbmake.h cdbmss.h substdio.h substdio.h cdbmss.h qmail-newu.c exit.h \
-qmail-newu.c readwrite.h qmail-newu.c open.h qmail-newu.c error.h \
-qmail-newu.c case.h qmail-newu.c auto_qmail.h qmail-newu.c
+compile qmail-newu.c stralloc.h gen_alloc.h subfd.h substdio.h \
+getln.h substdio.h cdbmss.h cdbmake.h uint32.h substdio.h exit.h \
+readwrite.h open.h error.h case.h auto_qmail.h
        ./compile qmail-newu.c
 
 qmail-pop3d: \
-load qmail-pop3d.o prioq.o now.o sig.a open.a getln.a stralloc.a \
-alloc.a substdio.a error.a str.a fs.a
-       ./load qmail-pop3d prioq.o now.o sig.a open.a getln.a \
-       stralloc.a alloc.a substdio.a error.a str.a fs.a 
+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
+       ./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`
 
 qmail-pop3d.0: \
 qmail-pop3d.8
        nroff -man qmail-pop3d.8 > qmail-pop3d.0
 
 qmail-pop3d.o: \
-compile qmail-pop3d.c qmail-pop3d.c qmail-pop3d.c direntry.h \
-direntry.h direntry.h qmail-pop3d.c sig.h qmail-pop3d.c getln.h \
-qmail-pop3d.c stralloc.h gen_alloc.h stralloc.h qmail-pop3d.c \
-substdio.h qmail-pop3d.c alloc.h qmail-pop3d.c datetime.h \
-qmail-pop3d.c prot.h qmail-pop3d.c open.h qmail-pop3d.c prioq.h \
-datetime.h datetime.h prioq.h gen_alloc.h prioq.h qmail-pop3d.c \
-scan.h qmail-pop3d.c fmt.h qmail-pop3d.c error.h qmail-pop3d.c str.h \
-qmail-pop3d.c exit.h qmail-pop3d.c now.h datetime.h datetime.h now.h \
-qmail-pop3d.c readwrite.h qmail-pop3d.c
+compile qmail-pop3d.c commands.h sig.h getln.h stralloc.h gen_alloc.h \
+substdio.h alloc.h open.h prioq.h datetime.h gen_alloc.h scan.h fmt.h \
+str.h exit.h maildir.h strerr.h readwrite.h timeoutread.h \
+timeoutwrite.h
        ./compile qmail-pop3d.c
 
 qmail-popup: \
-load qmail-popup.o now.o fd.a sig.a wait.a getln.a stralloc.a alloc.a \
-substdio.a error.a str.a fs.a
-       ./load qmail-popup now.o fd.a sig.a wait.a getln.a \
-       stralloc.a alloc.a substdio.a error.a str.a fs.a 
+load qmail-popup.o commands.o timeoutread.o timeoutwrite.o now.o \
+case.a fd.a sig.a wait.a stralloc.a alloc.a substdio.a error.a str.a \
+fs.a socket.lib
+       ./load qmail-popup commands.o timeoutread.o timeoutwrite.o \
+       now.o case.a fd.a sig.a wait.a stralloc.a alloc.a \
+       substdio.a error.a str.a fs.a  `cat socket.lib`
 
 qmail-popup.0: \
 qmail-popup.8
        nroff -man qmail-popup.8 > qmail-popup.0
 
 qmail-popup.o: \
-compile qmail-popup.c qmail-popup.c qmail-popup.c fd.h qmail-popup.c \
-sig.h qmail-popup.c getln.h qmail-popup.c stralloc.h gen_alloc.h \
-stralloc.h qmail-popup.c substdio.h qmail-popup.c subfd.h substdio.h \
-substdio.h subfd.h qmail-popup.c alloc.h qmail-popup.c datetime.h \
-qmail-popup.c error.h qmail-popup.c wait.h qmail-popup.c str.h \
-qmail-popup.c now.h datetime.h datetime.h now.h qmail-popup.c fmt.h \
-qmail-popup.c exit.h qmail-popup.c readwrite.h qmail-popup.c
+compile qmail-popup.c commands.h fd.h sig.h stralloc.h gen_alloc.h \
+substdio.h alloc.h wait.h str.h byte.h now.h datetime.h fmt.h exit.h \
+readwrite.h timeoutread.h timeoutwrite.h
        ./compile qmail-popup.c
 
 qmail-pw2u: \
@@ -1312,38 +1325,65 @@ qmail-pw2u.9 conf-break conf-spawn
        > qmail-pw2u.8
 
 qmail-pw2u.o: \
-compile qmail-pw2u.c qmail-pw2u.c qmail-pw2u.c substdio.h \
-qmail-pw2u.c readwrite.h qmail-pw2u.c subfd.h substdio.h substdio.h \
-subfd.h qmail-pw2u.c sgetopt.h subgetopt.h sgetopt.h qmail-pw2u.c \
-control.h qmail-pw2u.c constmap.h qmail-pw2u.c stralloc.h gen_alloc.h \
-stralloc.h qmail-pw2u.c fmt.h qmail-pw2u.c str.h qmail-pw2u.c scan.h \
-qmail-pw2u.c open.h qmail-pw2u.c error.h qmail-pw2u.c getln.h \
-qmail-pw2u.c auto_break.h qmail-pw2u.c auto_qmail.h qmail-pw2u.c \
-auto_usera.h qmail-pw2u.c
+compile qmail-pw2u.c substdio.h readwrite.h subfd.h substdio.h \
+sgetopt.h subgetopt.h control.h constmap.h stralloc.h gen_alloc.h \
+fmt.h str.h scan.h open.h error.h getln.h auto_break.h auto_qmail.h \
+auto_usera.h
        ./compile qmail-pw2u.c
 
+qmail-qmqpc: \
+load qmail-qmqpc.o slurpclose.o timeoutread.o timeoutwrite.o \
+timeoutconn.o ip.o control.o auto_qmail.o sig.a ndelay.a open.a \
+getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a socket.lib
+       ./load qmail-qmqpc slurpclose.o timeoutread.o \
+       timeoutwrite.o timeoutconn.o ip.o control.o auto_qmail.o \
+       sig.a ndelay.a open.a getln.a substdio.a stralloc.a alloc.a \
+       error.a str.a fs.a  `cat socket.lib`
+
+qmail-qmqpc.0: \
+qmail-qmqpc.8
+       nroff -man qmail-qmqpc.8 > qmail-qmqpc.0
+
+qmail-qmqpc.o: \
+compile qmail-qmqpc.c substdio.h getln.h readwrite.h exit.h \
+stralloc.h gen_alloc.h slurpclose.h error.h sig.h ip.h timeoutconn.h \
+timeoutread.h timeoutwrite.h auto_qmail.h control.h fmt.h
+       ./compile qmail-qmqpc.c
+
+qmail-qmqpd: \
+load qmail-qmqpd.o received.o now.o date822fmt.o qmail.o auto_qmail.o \
+env.a substdio.a sig.a error.a wait.a fd.a str.a datetime.a fs.a
+       ./load qmail-qmqpd received.o now.o date822fmt.o qmail.o \
+       auto_qmail.o env.a substdio.a sig.a error.a wait.a fd.a \
+       str.a datetime.a fs.a 
+
+qmail-qmqpd.0: \
+qmail-qmqpd.8
+       nroff -man qmail-qmqpd.8 > qmail-qmqpd.0
+
+qmail-qmqpd.o: \
+compile qmail-qmqpd.c auto_qmail.h qmail.h substdio.h received.h \
+sig.h substdio.h readwrite.h exit.h now.h datetime.h fmt.h env.h
+       ./compile qmail-qmqpd.c
+
 qmail-qmtpd: \
-load qmail-qmtpd.o control.o constmap.o received.o date822fmt.o now.o \
-qmail.o fd.a wait.a datetime.a open.a getln.a sig.a case.a env.a \
-stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o
-       ./load qmail-qmtpd control.o constmap.o received.o \
-       date822fmt.o now.o qmail.o fd.a wait.a datetime.a open.a \
-       getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a \
-       error.a str.a fs.a auto_qmail.o 
+load qmail-qmtpd.o rcpthosts.o control.o constmap.o received.o \
+date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a open.a \
+getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \
+str.a fs.a auto_qmail.o
+       ./load qmail-qmtpd rcpthosts.o control.o constmap.o \
+       received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
+       datetime.a open.a getln.a sig.a case.a env.a stralloc.a \
+       alloc.a substdio.a error.a str.a fs.a auto_qmail.o 
 
 qmail-qmtpd.0: \
 qmail-qmtpd.8
        nroff -man qmail-qmtpd.8 > qmail-qmtpd.0
 
 qmail-qmtpd.o: \
-compile qmail-qmtpd.c stralloc.h gen_alloc.h stralloc.h qmail-qmtpd.c \
-substdio.h qmail-qmtpd.c subfd.h substdio.h substdio.h subfd.h \
-qmail-qmtpd.c qmail.h substdio.h substdio.h qmail.h qmail-qmtpd.c \
-now.h datetime.h now.h qmail-qmtpd.c str.h qmail-qmtpd.c fmt.h \
-qmail-qmtpd.c env.h qmail-qmtpd.c sig.h qmail-qmtpd.c auto_qmail.h \
-qmail-qmtpd.c now.h qmail-qmtpd.c datetime.h datetime.h qmail-qmtpd.c \
-date822fmt.h qmail-qmtpd.c readwrite.h qmail-qmtpd.c control.h \
-qmail-qmtpd.c constmap.h qmail-qmtpd.c received.h qmail-qmtpd.c
+compile qmail-qmtpd.c stralloc.h gen_alloc.h substdio.h qmail.h \
+substdio.h now.h datetime.h str.h fmt.h env.h sig.h rcpthosts.h \
+auto_qmail.h readwrite.h control.h received.h
        ./compile qmail-qmtpd.c
 
 qmail-qread: \
@@ -1359,14 +1399,10 @@ qmail-qread.8
        nroff -man qmail-qread.8 > qmail-qread.0
 
 qmail-qread.o: \
-compile qmail-qread.c qmail-qread.c qmail-qread.c stralloc.h \
-gen_alloc.h stralloc.h qmail-qread.c substdio.h qmail-qread.c subfd.h \
-substdio.h substdio.h subfd.h qmail-qread.c fmt.h qmail-qread.c str.h \
-qmail-qread.c getln.h qmail-qread.c fmtqfn.h qmail-qread.c \
-readsubdir.h direntry.h direntry.h direntry.h readsubdir.h \
-qmail-qread.c auto_qmail.h qmail-qread.c open.h qmail-qread.c \
-datetime.h qmail-qread.c date822fmt.h qmail-qread.c readwrite.h \
-qmail-qread.c error.h qmail-qread.c exit.h qmail-qread.c
+compile qmail-qread.c stralloc.h gen_alloc.h substdio.h subfd.h \
+substdio.h fmt.h str.h getln.h fmtqfn.h readsubdir.h direntry.h \
+auto_qmail.h open.h datetime.h date822fmt.h readwrite.h error.h \
+exit.h
        ./compile qmail-qread.c
 
 qmail-qstat: \
@@ -1396,13 +1432,9 @@ qmail-queue.8
        nroff -man qmail-queue.8 > qmail-queue.0
 
 qmail-queue.o: \
-compile qmail-queue.c qmail-queue.c qmail-queue.c readwrite.h \
-qmail-queue.c sig.h qmail-queue.c exit.h qmail-queue.c open.h \
-qmail-queue.c seek.h qmail-queue.c fmt.h qmail-queue.c alloc.h \
-qmail-queue.c substdio.h qmail-queue.c datetime.h qmail-queue.c now.h \
-datetime.h datetime.h now.h qmail-queue.c triggerpull.h qmail-queue.c \
-extra.h qmail-queue.c auto_qmail.h qmail-queue.c auto_uids.h \
-qmail-queue.c date822fmt.h qmail-queue.c fmtqfn.h qmail-queue.c
+compile qmail-queue.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
+alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
+auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
        ./compile qmail-queue.c
 
 qmail-remote: \
@@ -1421,21 +1453,11 @@ qmail-remote.8
        nroff -man qmail-remote.8 > qmail-remote.0
 
 qmail-remote.o: \
-compile qmail-remote.c qmail-remote.c qmail-remote.c qmail-remote.c \
-qmail-remote.c sig.h qmail-remote.c getln.h qmail-remote.c stralloc.h \
-gen_alloc.h stralloc.h qmail-remote.c substdio.h qmail-remote.c \
-subfd.h substdio.h substdio.h subfd.h qmail-remote.c scan.h \
-qmail-remote.c case.h qmail-remote.c error.h qmail-remote.c \
-auto_qmail.h qmail-remote.c control.h qmail-remote.c dns.h \
-qmail-remote.c alloc.h qmail-remote.c quote.h qmail-remote.c ip.h \
-qmail-remote.c ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h \
-qmail-remote.c ipme.h ip.h ip.h ipme.h ipalloc.h ipalloc.h ipme.h \
-qmail-remote.c gen_alloc.h qmail-remote.c gen_allocdefs.h \
-gen_allocdefs.h gen_allocdefs.h qmail-remote.c str.h qmail-remote.c \
-now.h datetime.h now.h qmail-remote.c exit.h qmail-remote.c \
-constmap.h qmail-remote.c tcpto.h qmail-remote.c timeoutconn.h \
-qmail-remote.c timeoutread.h qmail-remote.c timeoutwrite.h \
-qmail-remote.c
+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 \
+gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \
+tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h
        ./compile qmail-remote.c
 
 qmail-rspawn: \
@@ -1452,9 +1474,8 @@ qmail-rspawn.8
        nroff -man qmail-rspawn.8 > qmail-rspawn.0
 
 qmail-rspawn.o: \
-compile qmail-rspawn.c fd.h qmail-rspawn.c wait.h qmail-rspawn.c \
-substdio.h qmail-rspawn.c exit.h qmail-rspawn.c fork.h qmail-rspawn.c \
-error.h qmail-rspawn.c tcpto.h qmail-rspawn.c
+compile qmail-rspawn.c fd.h wait.h substdio.h exit.h fork.h error.h \
+tcpto.h
        ./compile qmail-rspawn.c
 
 qmail-send: \
@@ -1482,68 +1503,57 @@ qmail-send.9 conf-break conf-spawn
        > qmail-send.8
 
 qmail-send.o: \
-compile qmail-send.c qmail-send.c qmail-send.c readwrite.h \
-qmail-send.c sig.h qmail-send.c direntry.h direntry.h direntry.h \
-qmail-send.c control.h qmail-send.c select.h select.h select.h \
-select.h qmail-send.c open.h qmail-send.c seek.h qmail-send.c exit.h \
-qmail-send.c lock.h qmail-send.c ndelay.h qmail-send.c now.h \
-datetime.h now.h qmail-send.c getln.h qmail-send.c substdio.h \
-qmail-send.c alloc.h qmail-send.c error.h qmail-send.c stralloc.h \
-gen_alloc.h stralloc.h qmail-send.c str.h qmail-send.c byte.h \
-qmail-send.c fmt.h qmail-send.c scan.h qmail-send.c case.h \
-qmail-send.c auto_qmail.h qmail-send.c trigger.h qmail-send.c \
-newfield.h stralloc.h stralloc.h newfield.h qmail-send.c quote.h \
-qmail-send.c qmail.h substdio.h substdio.h qmail.h qmail-send.c \
-qsutil.h qmail-send.c prioq.h datetime.h datetime.h prioq.h \
-gen_alloc.h prioq.h qmail-send.c constmap.h qmail-send.c fmtqfn.h \
-qmail-send.c readsubdir.h direntry.h readsubdir.h qmail-send.c
+compile qmail-send.c readwrite.h sig.h direntry.h control.h select.h \
+open.h seek.h exit.h lock.h ndelay.h now.h datetime.h getln.h \
+substdio.h alloc.h error.h stralloc.h gen_alloc.h str.h byte.h fmt.h \
+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
 
 qmail-showctl: \
-load qmail-showctl.o control.o open.a getln.a stralloc.a alloc.a \
-substdio.a error.a str.a fs.a auto_qmail.o
-       ./load qmail-showctl control.o open.a getln.a stralloc.a \
-       alloc.a substdio.a error.a str.a fs.a auto_qmail.o 
+load qmail-showctl.o auto_uids.o control.o open.a getln.a stralloc.a \
+alloc.a substdio.a error.a str.a fs.a auto_qmail.o auto_break.o \
+auto_patrn.o auto_spawn.o auto_split.o
+       ./load qmail-showctl auto_uids.o control.o open.a getln.a \
+       stralloc.a alloc.a substdio.a error.a str.a fs.a \
+       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
 
 qmail-showctl.o: \
-compile qmail-showctl.c substdio.h qmail-showctl.c subfd.h substdio.h \
-substdio.h subfd.h qmail-showctl.c exit.h qmail-showctl.c fmt.h \
-qmail-showctl.c str.h qmail-showctl.c control.h qmail-showctl.c \
-constmap.h qmail-showctl.c stralloc.h gen_alloc.h stralloc.h \
-qmail-showctl.c direntry.h direntry.h direntry.h qmail-showctl.c \
-auto_qmail.h qmail-showctl.c
+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
        ./compile qmail-showctl.c
 
 qmail-smtpd: \
-load qmail-smtpd.o ip.o ipme.o ipalloc.o control.o constmap.o \
-received.o date822fmt.o now.o qmail.o fd.a wait.a datetime.a open.a \
-getln.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a \
-str.a fs.a auto_qmail.o socket.lib
-       ./load qmail-smtpd ip.o ipme.o ipalloc.o control.o \
-       constmap.o received.o date822fmt.o now.o qmail.o fd.a \
-       wait.a datetime.a open.a getln.a sig.a case.a env.a \
-       stralloc.a alloc.a substdio.a error.a str.a fs.a \
-       auto_qmail.o  `cat socket.lib`
+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`
 
 qmail-smtpd.0: \
 qmail-smtpd.8
        nroff -man qmail-smtpd.8 > qmail-smtpd.0
 
 qmail-smtpd.o: \
-compile qmail-smtpd.c sig.h qmail-smtpd.c readwrite.h qmail-smtpd.c \
-getln.h qmail-smtpd.c stralloc.h gen_alloc.h stralloc.h qmail-smtpd.c \
-substdio.h qmail-smtpd.c alloc.h qmail-smtpd.c auto_qmail.h \
-qmail-smtpd.c control.h qmail-smtpd.c received.h qmail-smtpd.c \
-constmap.h qmail-smtpd.c error.h qmail-smtpd.c ipme.h ip.h ipme.h \
-ipalloc.h ip.h ip.h ipalloc.h gen_alloc.h ipalloc.h ipme.h \
-qmail-smtpd.c ip.h ip.h qmail-smtpd.c qmail.h substdio.h substdio.h \
-qmail.h qmail-smtpd.c str.h qmail-smtpd.c fmt.h qmail-smtpd.c byte.h \
-qmail-smtpd.c case.h qmail-smtpd.c env.h qmail-smtpd.c now.h \
-datetime.h now.h qmail-smtpd.c exit.h qmail-smtpd.c
+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
        ./compile qmail-smtpd.c
 
 qmail-start: \
@@ -1563,10 +1573,24 @@ qmail-start.9 conf-break conf-spawn
        > qmail-start.8
 
 qmail-start.o: \
-compile qmail-start.c fd.h qmail-start.c prot.h qmail-start.c exit.h \
-qmail-start.c fork.h qmail-start.c auto_uids.h qmail-start.c
+compile qmail-start.c fd.h prot.h exit.h fork.h auto_uids.h
        ./compile qmail-start.c
 
+qmail-tcpok: \
+load qmail-tcpok.o open.a lock.a strerr.a substdio.a error.a str.a \
+auto_qmail.o
+       ./load qmail-tcpok open.a lock.a strerr.a substdio.a \
+       error.a str.a auto_qmail.o 
+
+qmail-tcpok.0: \
+qmail-tcpok.8
+       nroff -man qmail-tcpok.8 > qmail-tcpok.0
+
+qmail-tcpok.o: \
+compile qmail-tcpok.c strerr.h substdio.h lock.h open.h readwrite.h \
+auto_qmail.h exit.h
+       ./compile qmail-tcpok.c
+
 qmail-tcpto: \
 load qmail-tcpto.o ip.o now.o open.a lock.a substdio.a error.a str.a \
 fs.a auto_qmail.o
@@ -1578,25 +1602,10 @@ qmail-tcpto.8
        nroff -man qmail-tcpto.8 > qmail-tcpto.0
 
 qmail-tcpto.o: \
-compile qmail-tcpto.c substdio.h qmail-tcpto.c subfd.h substdio.h \
-substdio.h subfd.h qmail-tcpto.c auto_qmail.h qmail-tcpto.c fmt.h \
-qmail-tcpto.c ip.h qmail-tcpto.c lock.h qmail-tcpto.c error.h \
-qmail-tcpto.c exit.h qmail-tcpto.c datetime.h qmail-tcpto.c now.h \
-datetime.h datetime.h now.h qmail-tcpto.c
+compile qmail-tcpto.c substdio.h subfd.h substdio.h auto_qmail.h \
+fmt.h ip.h lock.h error.h exit.h datetime.h now.h datetime.h
        ./compile qmail-tcpto.c
 
-qmail-upgrade.0: \
-qmail-upgrade.7
-       nroff -man qmail-upgrade.7 > qmail-upgrade.0
-
-qmail-upgrade.7: \
-qmail-upgrade.9 conf-break conf-spawn
-       cat qmail-upgrade.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-upgrade.7
-
 qmail-upq: \
 warn-auto.sh qmail-upq.sh conf-qmail conf-break conf-split
        cat warn-auto.sh qmail-upq.sh \
@@ -1623,9 +1632,8 @@ qmail.7
        nroff -man qmail.7 > qmail.0
 
 qmail.o: \
-compile qmail.c substdio.h qmail.c readwrite.h qmail.c wait.h qmail.c \
-exit.h qmail.c fork.h qmail.c fd.h qmail.c qmail.h substdio.h \
-substdio.h qmail.h qmail.c auto_qmail.h qmail.c
+compile qmail.c substdio.h readwrite.h wait.h exit.h fork.h fd.h \
+qmail.h substdio.h auto_qmail.h
        ./compile qmail.c
 
 qreceipt: \
@@ -1641,14 +1649,10 @@ qreceipt.1
        nroff -man qreceipt.1 > qreceipt.0
 
 qreceipt.o: \
-compile qreceipt.c sig.h qreceipt.c env.h qreceipt.c substdio.h \
-qreceipt.c stralloc.h gen_alloc.h stralloc.h qreceipt.c subfd.h \
-substdio.h substdio.h subfd.h qreceipt.c getln.h qreceipt.c alloc.h \
-qreceipt.c str.h qreceipt.c hfield.h qreceipt.c token822.h \
-gen_alloc.h token822.h qreceipt.c error.h qreceipt.c gen_alloc.h \
-qreceipt.c gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h qreceipt.c \
-headerbody.h qreceipt.c exit.h qreceipt.c open.h qreceipt.c quote.h \
-qreceipt.c qmail.h substdio.h substdio.h qmail.h qreceipt.c
+compile qreceipt.c sig.h env.h substdio.h stralloc.h gen_alloc.h \
+subfd.h substdio.h getln.h alloc.h str.h hfield.h token822.h \
+gen_alloc.h error.h gen_alloc.h gen_allocdefs.h headerbody.h exit.h \
+open.h quote.h qmail.h substdio.h
        ./compile qreceipt.c
 
 qsmhook: \
@@ -1658,54 +1662,46 @@ alloc.a substdio.a error.a str.a
        stralloc.a alloc.a substdio.a error.a str.a 
 
 qsmhook.o: \
-compile qsmhook.c fd.h qsmhook.c stralloc.h gen_alloc.h stralloc.h \
-qsmhook.c readwrite.h qsmhook.c sgetopt.h subgetopt.h sgetopt.h \
-qsmhook.c wait.h qsmhook.c env.h qsmhook.c byte.h qsmhook.c str.h \
-qsmhook.c alloc.h qsmhook.c exit.h qsmhook.c fork.h qsmhook.c case.h \
-qsmhook.c subfd.h substdio.h subfd.h qsmhook.c error.h qsmhook.c \
-substdio.h substdio.h qsmhook.c sig.h qsmhook.c
+compile qsmhook.c fd.h stralloc.h gen_alloc.h readwrite.h sgetopt.h \
+subgetopt.h wait.h env.h byte.h str.h alloc.h exit.h fork.h case.h \
+subfd.h substdio.h error.h substdio.h sig.h
        ./compile qsmhook.c
 
 qsutil.o: \
-compile qsutil.c stralloc.h gen_alloc.h stralloc.h qsutil.c \
-readwrite.h qsutil.c substdio.h qsutil.c qsutil.h qsutil.c
+compile qsutil.c stralloc.h gen_alloc.h readwrite.h substdio.h \
+qsutil.h
        ./compile qsutil.c
 
 quote.o: \
-compile quote.c stralloc.h gen_alloc.h stralloc.h quote.c str.h \
-quote.c quote.h quote.c
+compile quote.c stralloc.h gen_alloc.h str.h quote.h
        ./compile quote.c
 
+rcpthosts.o: \
+compile rcpthosts.c cdb.h uint32.h byte.h open.h error.h control.h \
+constmap.h stralloc.h gen_alloc.h rcpthosts.h
+       ./compile rcpthosts.c
+
 readsubdir.o: \
-compile readsubdir.c readsubdir.h direntry.h direntry.h direntry.h \
-readsubdir.h readsubdir.c fmt.h readsubdir.c scan.h readsubdir.c \
-str.h readsubdir.c auto_split.h readsubdir.c
+compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \
+auto_split.h
        ./compile readsubdir.c
 
 received.o: \
-compile received.c fmt.h received.c qmail.h substdio.h qmail.h \
-received.c now.h datetime.h now.h received.c datetime.h datetime.h \
-received.c date822fmt.h received.c received.h received.c
+compile received.c fmt.h qmail.h substdio.h now.h datetime.h \
+datetime.h date822fmt.h received.h
        ./compile received.c
 
 remoteinfo.o: \
-compile remoteinfo.c remoteinfo.c remoteinfo.c remoteinfo.c \
-remoteinfo.c byte.h remoteinfo.c substdio.h remoteinfo.c ip.h \
-remoteinfo.c fmt.h remoteinfo.c timeoutconn.h remoteinfo.c \
-timeoutread.h remoteinfo.c timeoutwrite.h remoteinfo.c remoteinfo.h \
-remoteinfo.c
+compile remoteinfo.c byte.h substdio.h ip.h fmt.h timeoutconn.h \
+timeoutread.h timeoutwrite.h remoteinfo.h
        ./compile remoteinfo.c
 
 scan_8long.o: \
-compile scan_8long.c scan.h scan_8long.c
+compile scan_8long.c scan.h
        ./compile scan_8long.c
 
-scan_nbblong.o: \
-compile scan_nbblong.c scan.h scan_nbblong.c
-       ./compile scan_nbblong.c
-
 scan_ulong.o: \
-compile scan_ulong.c scan.h scan_ulong.c
+compile scan_ulong.c scan.h
        ./compile scan_ulong.c
 
 seek.a: \
@@ -1714,19 +1710,19 @@ makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o
        seek_trunc.o
 
 seek_cur.o: \
-compile seek_cur.c seek_cur.c seek.h seek_cur.c
+compile seek_cur.c seek.h
        ./compile seek_cur.c
 
 seek_end.o: \
-compile seek_end.c seek_end.c seek.h seek_end.c
+compile seek_end.c seek.h
        ./compile seek_end.c
 
 seek_set.o: \
-compile seek_set.c seek_set.c seek.h seek_set.c
+compile seek_set.c seek.h
        ./compile seek_set.c
 
 seek_trunc.o: \
-compile seek_trunc.c seek_trunc.c seek.h seek_trunc.c
+compile seek_trunc.c seek.h
        ./compile seek_trunc.c
 
 select.h: \
@@ -1742,57 +1738,62 @@ auto_qmail.o
        str.a auto_qmail.o 
 
 sendmail.o: \
-compile sendmail.c sgetopt.h subgetopt.h sgetopt.h sendmail.c \
-substdio.h sendmail.c subfd.h substdio.h substdio.h subfd.h \
-sendmail.c alloc.h sendmail.c auto_qmail.h sendmail.c exit.h \
-sendmail.c env.h sendmail.c str.h sendmail.c
+compile sendmail.c sgetopt.h subgetopt.h substdio.h subfd.h \
+substdio.h alloc.h auto_qmail.h exit.h env.h str.h
        ./compile sendmail.c
 
 setup: \
-it man conf-qmail
-       ./qmail-hier | ./install `head -1 conf-qmail`
+it man
+       ./install
 
 sgetopt.o: \
-compile sgetopt.c substdio.h sgetopt.c subfd.h substdio.h substdio.h \
-subfd.h sgetopt.c sgetopt.h sgetopt.h subgetopt.h sgetopt.h sgetopt.c \
-subgetopt.h subgetopt.h sgetopt.c
+compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \
+subgetopt.h
        ./compile sgetopt.c
 
 shar: \
 FILES BLURB BLURB2 BLURB3 BLURB4 README FAQ INSTALL INSTALL.alias \
-INSTALL.boot INSTALL.ctl INSTALL.ids INSTALL.mbox INSTALL.qsmhook \
-UPGRADE THOUGHTS TODO THANKS CHANGES RFCHCSC RFCLOOPS RFCMXPS \
-RFCNETSTR RFCNRUDT RFCQMTP RFCQSBMF RFCVERP SECURITY INTERNALS FILES \
-VERSION SYSDEPS TARGETS Makefile conf-break auto_break.h conf-spawn \
+INSTALL.ctl INSTALL.ids INSTALL.maildir INSTALL.mbox INSTALL.vsm \
+REMOVE.sendmail REMOVE.binmail TEST.deliver TEST.receive UPGRADE \
+THOUGHTS TODO THANKS CHANGES SECURITY INTERNALS SENDMAIL \
+PIC.local2alias PIC.local2ext PIC.local2local PIC.local2rem \
+PIC.local2virt PIC.nullclient PIC.relaybad PIC.relaygood \
+PIC.rem2local FILES VERSION SYSDEPS TARGETS Makefile BIN.README \
+BIN.Makefile BIN.setup idedit.c conf-break auto_break.h conf-spawn \
 auto_spawn.h chkspawn.c conf-split auto_split.h conf-patrn \
 auto_patrn.h conf-users conf-groups auto_uids.h auto_usera.h extra.h \
-addresses.5 condredirect.1 dot-qmail.9 envelopes.5 forgeries.7 \
-forward.1 maildir2mbox.1 maildirmake.1 maildirwatch.1 mailsubj.1 \
-mbox.5 preline.1 qbiff.1 qlist.1 qmail-clean.8 qmail-command.8 \
-qmail-control.5 qmail-getpw.9 qmail-header.5 qmail-inject.8 \
-qmail-limits.9 qmail-local.8 qmail-log.5 qmail-lspawn.8 qmail-newu.8 \
-qmail-pop3d.8 qmail-popup.8 qmail-pw2u.9 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 qmail-start.8 \
-qmail-tcpto.8 qmail-upgrade.9 qmail-users.5 qmail.7 qreceipt.1 \
-splogger.8 tcp-env.1 qmail-clean.c qmail-config.sh qmail-getpw.c \
-qmail-hier.c qmail-inject.c qmail-local.c qmail-lspawn.c qmail-newu.c \
-qmail-pop3d.c qmail-popup.c qmail-pw2u.c qmail-qmtpd.c qmail-qread.c \
-qmail-qstat.sh qmail-queue.c qmail-remote.c qmail-rspawn.c \
-qmail-send.c qmail-showctl.c qmail-smtpd.c qmail-start.c \
-qmail-tcpto.c spawn.c dnscname.c dnsfq.c dnsip.c dnsmxip.c dnsptr.c \
-hostname.c ipmeprint.c tcp-env.c sendmail.c qlist.c qreceipt.c \
-qsmhook.c qbiff.c forward.c preline.c predate.c condredirect.c \
-maildirmake.c maildir2mbox.c maildirwatch.c splogger.c qail.sh elq.sh \
-pinq.sh qlist2.sh qmail-upq.sh datemail.sh mailsubj.sh qlx.h \
-constmap.h constmap.c dnsdoe.h dnsdoe.c fmtqfn.h fmtqfn.c gfrom.h \
-gfrom.c myctime.h myctime.c newfield.h newfield.c qsutil.h qsutil.c \
+addresses.5 except.1 bouncesaying.1 condredirect.1 dot-qmail.9 \
+envelopes.5 forgeries.7 forward.1 maildir2mbox.1 maildirmake.1 \
+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-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 \
+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-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
+qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
+qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
+qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \
+dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \
+sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \
+except.c bouncesaying.c condredirect.c maildirmake.c maildir2mbox.c \
+maildirwatch.c splogger.c qail.sh elq.sh pinq.sh qmail-upq.sh \
+datemail.sh mailsubj.sh qlx.h rcpthosts.h rcpthosts.c commands.h \
+commands.c dnsdoe.h dnsdoe.c fmtqfn.h fmtqfn.c gfrom.h gfrom.c \
+myctime.h myctime.c newfield.h newfield.c qsutil.h qsutil.c \
 readsubdir.h readsubdir.c received.h received.c tcpto.h tcpto.c \
 tcpto_clean.c trigger.h trigger.c triggerpull.h triggerpull.c \
-trynpbg1.c trysyslog.c conf-cc conf-ld find-systype.sh \
-make-compile.sh make-load.sh make-makelib.sh trycpp.c warn-auto.sh \
-auto-str.c auto-int.c auto-int8.c auto-gid.c auto-uid.c install.c \
-instcheck.c alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h \
+trynpbg1.c trysyslog.c conf-cc conf-ld home.sh home+df.sh proc.sh \
+proc+df.sh binm1.sh binm2.sh binm3.sh binm1+df.sh binm2+df.sh \
+binm3+df.sh find-systype.sh make-compile.sh make-load.sh \
+make-makelib.sh trycpp.c warn-auto.sh auto-str.c auto-int.c \
+auto-int8.c auto-gid.c auto-uid.c hier.c install.c instcheck.c \
+install-big.c alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h \
 case_diffb.c case_diffs.c case_lowerb.c case_lowers.c case_starts.c \
 cdb.3 cdb.h cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h \
 cdbmake_add.c cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 \
@@ -1819,14 +1820,14 @@ getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \
 subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \
 error.h error.c error_str.c error_temp.c fmt.h fmt_str.c fmt_strn.c \
 fmt_uint.c fmt_uint0.c fmt_ulong.c scan.h scan_ulong.c scan_8long.c \
-scan_nbblong.c slurpclose.h slurpclose.c quote.h quote.c hfield.h \
-hfield.c headerbody.h headerbody.c token822.h token822.c control.h \
-control.c datetime.3 datetime.h datetime.c datetime_un.c prioq.h \
-prioq.c date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c \
-ip.h ip.c ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h \
-ndelay.c 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
+slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \
+headerbody.h headerbody.c token822.h token822.c control.h control.c \
+datetime.3 datetime.h datetime.c datetime_un.c prioq.h prioq.c \
+date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c ip.h ip.c \
+ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \
+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
        shar -m `cat FILES` > shar
        chmod 400 shar
 
@@ -1838,51 +1839,48 @@ sig_child.o sig_hup.o sig_term.o sig_bug.o sig_misc.o
        sig_bug.o sig_misc.o
 
 sig_alarm.o: \
-compile sig_alarm.c sig_alarm.c sig.h sig_alarm.c
+compile sig_alarm.c sig.h
        ./compile sig_alarm.c
 
 sig_block.o: \
-compile sig_block.c sig_block.c sig.h sig_block.c hassgprm.h \
-sig_block.c
+compile sig_block.c sig.h hassgprm.h
        ./compile sig_block.c
 
 sig_bug.o: \
-compile sig_bug.c sig_bug.c sig.h sig_bug.c
+compile sig_bug.c sig.h
        ./compile sig_bug.c
 
 sig_catch.o: \
-compile sig_catch.c sig_catch.c sig.h sig_catch.c hassgact.h \
-sig_catch.c
+compile sig_catch.c sig.h hassgact.h
        ./compile sig_catch.c
 
 sig_child.o: \
-compile sig_child.c sig_child.c sig.h sig_child.c
+compile sig_child.c sig.h
        ./compile sig_child.c
 
 sig_hup.o: \
-compile sig_hup.c sig_hup.c sig.h sig_hup.c
+compile sig_hup.c sig.h
        ./compile sig_hup.c
 
 sig_misc.o: \
-compile sig_misc.c sig_misc.c sig.h sig_misc.c
+compile sig_misc.c sig.h
        ./compile sig_misc.c
 
 sig_pause.o: \
-compile sig_pause.c sig_pause.c sig.h sig_pause.c hassgprm.h \
-sig_pause.c
+compile sig_pause.c sig.h hassgprm.h
        ./compile sig_pause.c
 
 sig_pipe.o: \
-compile sig_pipe.c sig_pipe.c sig.h sig_pipe.c
+compile sig_pipe.c sig.h
        ./compile sig_pipe.c
 
 sig_term.o: \
-compile sig_term.c sig_term.c sig.h sig_term.c
+compile sig_term.c sig.h
        ./compile sig_term.c
 
 slurpclose.o: \
-compile slurpclose.c stralloc.h gen_alloc.h stralloc.h slurpclose.c \
-readwrite.h slurpclose.c slurpclose.h slurpclose.c
+compile slurpclose.c stralloc.h gen_alloc.h readwrite.h slurpclose.h \
+error.h
        ./compile slurpclose.c
 
 socket.lib: \
@@ -1893,28 +1891,24 @@ trylsock.c compile load
        rm -f trylsock.o trylsock
 
 spawn.o: \
-compile chkspawn spawn.c spawn.c spawn.c sig.h spawn.c wait.h spawn.c \
-substdio.h spawn.c byte.h spawn.c str.h spawn.c stralloc.h \
-gen_alloc.h stralloc.h spawn.c select.h select.h select.h select.h \
-spawn.c exit.h spawn.c coe.h spawn.c open.h spawn.c error.h spawn.c \
-auto_qmail.h spawn.c auto_uids.h spawn.c auto_spawn.h spawn.c
+compile chkspawn spawn.c sig.h wait.h substdio.h byte.h str.h \
+stralloc.h gen_alloc.h select.h exit.h coe.h open.h error.h \
+auto_qmail.h auto_uids.h auto_spawn.h
        ./chkspawn
        ./compile spawn.c
 
 splogger: \
-load splogger.o substdio.a error.a str.a fs.a syslog.lib
+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 \
-       syslog.lib`
+       syslog.lib` `cat socket.lib`
 
 splogger.0: \
 splogger.8
        nroff -man splogger.8 > splogger.0
 
 splogger.o: \
-compile splogger.c splogger.c splogger.c splogger.c error.h \
-splogger.c substdio.h splogger.c subfd.h substdio.h substdio.h \
-subfd.h splogger.c exit.h splogger.c str.h splogger.c scan.h \
-splogger.c fmt.h splogger.c
+compile splogger.c error.h substdio.h subfd.h substdio.h exit.h str.h \
+scan.h fmt.h
        ./compile splogger.c
 
 str.a: \
@@ -1926,31 +1920,31 @@ byte_cr.o byte_zero.o
        byte_diff.o byte_copy.o byte_cr.o byte_zero.o
 
 str_chr.o: \
-compile str_chr.c str.h str_chr.c
+compile str_chr.c str.h
        ./compile str_chr.c
 
 str_cpy.o: \
-compile str_cpy.c str.h str_cpy.c
+compile str_cpy.c str.h
        ./compile str_cpy.c
 
 str_diff.o: \
-compile str_diff.c str.h str_diff.c
+compile str_diff.c str.h
        ./compile str_diff.c
 
 str_diffn.o: \
-compile str_diffn.c str.h str_diffn.c
+compile str_diffn.c str.h
        ./compile str_diffn.c
 
 str_len.o: \
-compile str_len.c str.h str_len.c
+compile str_len.c str.h
        ./compile str_len.c
 
 str_rchr.o: \
-compile str_rchr.c str.h str_rchr.c
+compile str_rchr.c str.h
        ./compile str_rchr.c
 
 str_start.o: \
-compile str_start.c str.h str_start.c
+compile str_start.c str.h
        ./compile str_start.c
 
 stralloc.a: \
@@ -1963,50 +1957,41 @@ stralloc_catb.o stralloc_arts.o
        stralloc_arts.o
 
 stralloc_arts.o: \
-compile stralloc_arts.c byte.h stralloc_arts.c str.h stralloc_arts.c \
-stralloc.h gen_alloc.h stralloc.h stralloc_arts.c
+compile stralloc_arts.c byte.h str.h stralloc.h gen_alloc.h
        ./compile stralloc_arts.c
 
 stralloc_cat.o: \
-compile stralloc_cat.c byte.h stralloc_cat.c stralloc.h gen_alloc.h \
-stralloc.h stralloc_cat.c
+compile stralloc_cat.c byte.h stralloc.h gen_alloc.h
        ./compile stralloc_cat.c
 
 stralloc_catb.o: \
-compile stralloc_catb.c stralloc.h gen_alloc.h stralloc.h \
-stralloc_catb.c byte.h stralloc_catb.c
+compile stralloc_catb.c stralloc.h gen_alloc.h byte.h
        ./compile stralloc_catb.c
 
 stralloc_cats.o: \
-compile stralloc_cats.c byte.h stralloc_cats.c str.h stralloc_cats.c \
-stralloc.h gen_alloc.h stralloc.h stralloc_cats.c
+compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h
        ./compile stralloc_cats.c
 
 stralloc_copy.o: \
-compile stralloc_copy.c byte.h stralloc_copy.c stralloc.h gen_alloc.h \
-stralloc.h stralloc_copy.c
+compile stralloc_copy.c byte.h stralloc.h gen_alloc.h
        ./compile stralloc_copy.c
 
 stralloc_eady.o: \
-compile stralloc_eady.c alloc.h stralloc_eady.c stralloc.h \
-gen_alloc.h stralloc.h stralloc_eady.c gen_allocdefs.h \
-gen_allocdefs.h gen_allocdefs.h stralloc_eady.c
+compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
        ./compile stralloc_eady.c
 
 stralloc_opyb.o: \
-compile stralloc_opyb.c stralloc.h gen_alloc.h stralloc.h \
-stralloc_opyb.c byte.h stralloc_opyb.c
+compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h
        ./compile stralloc_opyb.c
 
 stralloc_opys.o: \
-compile stralloc_opys.c byte.h stralloc_opys.c str.h stralloc_opys.c \
-stralloc.h gen_alloc.h stralloc.h stralloc_opys.c
+compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h
        ./compile stralloc_opys.c
 
 stralloc_pend.o: \
-compile stralloc_pend.c alloc.h stralloc_pend.c stralloc.h \
-gen_alloc.h stralloc.h stralloc_pend.c gen_allocdefs.h \
-gen_allocdefs.h gen_allocdefs.h stralloc_pend.c
+compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
        ./compile stralloc_pend.c
 
 strerr.a: \
@@ -2014,47 +1999,39 @@ makelib strerr_sys.o strerr_die.o
        ./makelib strerr.a strerr_sys.o strerr_die.o
 
 strerr_die.o: \
-compile strerr_die.c substdio.h strerr_die.c subfd.h substdio.h \
-substdio.h subfd.h strerr_die.c exit.h strerr_die.c strerr.h \
-strerr_die.c
+compile strerr_die.c substdio.h subfd.h substdio.h exit.h strerr.h
        ./compile strerr_die.c
 
 strerr_sys.o: \
-compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c
+compile strerr_sys.c error.h strerr.h
        ./compile strerr_sys.c
 
 subfderr.o: \
-compile subfderr.c readwrite.h subfderr.c substdio.h subfderr.c \
-subfd.h substdio.h substdio.h subfd.h subfderr.c
+compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
        ./compile subfderr.c
 
 subfdin.o: \
-compile subfdin.c readwrite.h subfdin.c substdio.h subfdin.c subfd.h \
-substdio.h substdio.h subfd.h subfdin.c
+compile subfdin.c readwrite.h substdio.h subfd.h substdio.h
        ./compile subfdin.c
 
 subfdins.o: \
-compile subfdins.c readwrite.h subfdins.c substdio.h subfdins.c \
-subfd.h substdio.h substdio.h subfd.h subfdins.c
+compile subfdins.c readwrite.h substdio.h subfd.h substdio.h
        ./compile subfdins.c
 
 subfdout.o: \
-compile subfdout.c readwrite.h subfdout.c substdio.h subfdout.c \
-subfd.h substdio.h substdio.h subfd.h subfdout.c
+compile subfdout.c readwrite.h substdio.h subfd.h substdio.h
        ./compile subfdout.c
 
 subfdouts.o: \
-compile subfdouts.c readwrite.h subfdouts.c substdio.h subfdouts.c \
-subfd.h substdio.h substdio.h subfd.h subfdouts.c
+compile subfdouts.c readwrite.h substdio.h subfd.h substdio.h
        ./compile subfdouts.c
 
 subgetopt.o: \
-compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c
+compile subgetopt.c subgetopt.h
        ./compile subgetopt.c
 
 substdi.o: \
-compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \
-substdi.c
+compile substdi.c substdio.h byte.h error.h
        ./compile substdi.c
 
 substdio.a: \
@@ -2065,16 +2042,15 @@ subfdouts.o subfdin.o subfdins.o substdio_copy.o
        substdio_copy.o
 
 substdio.o: \
-compile substdio.c substdio.h substdio.c
+compile substdio.c substdio.h
        ./compile substdio.c
 
 substdio_copy.o: \
-compile substdio_copy.c substdio.h substdio_copy.c
+compile substdio_copy.c substdio.h
        ./compile substdio_copy.c
 
 substdo.o: \
-compile substdo.c substdio.h substdo.c str.h substdo.c byte.h \
-substdo.c error.h substdo.c
+compile substdo.c substdio.h str.h byte.h error.h
        ./compile substdo.c
 
 syslog.lib: \
@@ -2102,11 +2078,8 @@ tcp-env.1
        nroff -man tcp-env.1 > tcp-env.0
 
 tcp-env.o: \
-compile tcp-env.c tcp-env.c tcp-env.c tcp-env.c tcp-env.c sig.h \
-tcp-env.c stralloc.h gen_alloc.h stralloc.h tcp-env.c str.h tcp-env.c \
-env.h tcp-env.c fmt.h tcp-env.c scan.h tcp-env.c subgetopt.h \
-tcp-env.c ip.h tcp-env.c dns.h tcp-env.c byte.h tcp-env.c \
-remoteinfo.h tcp-env.c exit.h tcp-env.c case.h tcp-env.c
+compile tcp-env.c sig.h stralloc.h gen_alloc.h str.h env.h fmt.h \
+scan.h subgetopt.h ip.h dns.h byte.h remoteinfo.h exit.h case.h
        ./compile tcp-env.c
 
 tcp-environ.0: \
@@ -2114,50 +2087,38 @@ tcp-environ.5
        nroff -man tcp-environ.5 > tcp-environ.0
 
 tcpto.o: \
-compile tcpto.c tcpto.h tcpto.c open.h tcpto.c lock.h tcpto.c seek.h \
-tcpto.c now.h datetime.h now.h tcpto.c ip.h tcpto.c byte.h tcpto.c \
-datetime.h datetime.h tcpto.c readwrite.h tcpto.c
+compile tcpto.c tcpto.h open.h lock.h seek.h now.h datetime.h ip.h \
+byte.h datetime.h readwrite.h
        ./compile tcpto.c
 
 tcpto_clean.o: \
-compile tcpto_clean.c tcpto.h tcpto_clean.c open.h tcpto_clean.c \
-substdio.h tcpto_clean.c readwrite.h tcpto_clean.c
+compile tcpto_clean.c tcpto.h open.h substdio.h readwrite.h
        ./compile tcpto_clean.c
 
 timeoutconn.o: \
-compile timeoutconn.c timeoutconn.c timeoutconn.c timeoutconn.c \
-timeoutconn.c ndelay.h timeoutconn.c select.h select.h select.h \
-select.h timeoutconn.c error.h timeoutconn.c readwrite.h \
-timeoutconn.c ip.h timeoutconn.c byte.h timeoutconn.c timeoutconn.h \
-timeoutconn.c
+compile timeoutconn.c ndelay.h select.h error.h readwrite.h ip.h \
+byte.h timeoutconn.h
        ./compile timeoutconn.c
 
 timeoutread.o: \
-compile timeoutread.c timeoutread.h timeoutread.c select.h select.h \
-select.h select.h timeoutread.c error.h timeoutread.c readwrite.h \
-timeoutread.c
+compile timeoutread.c timeoutread.h select.h error.h readwrite.h
        ./compile timeoutread.c
 
 timeoutwrite.o: \
-compile timeoutwrite.c timeoutwrite.h timeoutwrite.c select.h \
-select.h select.h select.h timeoutwrite.c error.h timeoutwrite.c \
-readwrite.h timeoutwrite.c
+compile timeoutwrite.c timeoutwrite.h select.h error.h readwrite.h
        ./compile timeoutwrite.c
 
 token822.o: \
-compile token822.c stralloc.h gen_alloc.h stralloc.h token822.c \
-alloc.h token822.c str.h token822.c token822.h gen_alloc.h token822.h \
-token822.c gen_allocdefs.h gen_allocdefs.h gen_allocdefs.h token822.c
+compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
+gen_alloc.h gen_allocdefs.h
        ./compile token822.c
 
 trigger.o: \
-compile trigger.c select.h select.h select.h select.h trigger.c \
-open.h trigger.c trigger.h trigger.c hasnpbg1.h trigger.c
+compile trigger.c select.h open.h trigger.h hasnpbg1.h
        ./compile trigger.c
 
 triggerpull.o: \
-compile triggerpull.c ndelay.h triggerpull.c open.h triggerpull.c \
-triggerpull.h triggerpull.c
+compile triggerpull.c ndelay.h open.h triggerpull.h
        ./compile triggerpull.c
 
 uint32.h: \
@@ -2172,10 +2133,9 @@ makelib wait_pid.o wait_nohang.o
        ./makelib wait.a wait_pid.o wait_nohang.o
 
 wait_nohang.o: \
-compile wait_nohang.c wait_nohang.c wait_nohang.c haswaitp.h \
-wait_nohang.c
+compile wait_nohang.c haswaitp.h
        ./compile wait_nohang.c
 
 wait_pid.o: \
-compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c
+compile wait_pid.c error.h haswaitp.h
        ./compile wait_pid.c
diff --git a/PIC.local2alias b/PIC.local2alias
new file mode 100644 (file)
index 0000000..75cff56
--- /dev/null
@@ -0,0 +1,37 @@
+                Original message:
+                   
+                   To: help
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to help@heaven.af.mil
+     |             From: joe@heaven.af.mil
+     |             To: help@heaven.af.mil
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, help@heaven.af.mil.
+     |          Is heaven.af.mil in locals? Yes.
+     |          Deliver locally to help@heaven.af.mil.
+     V          
+                   
+qmail-lspawn ./Mailbox
+                   
+     |          Look at mailbox name, help.
+     |          Is help listed in qmail-users? No.
+     |          Is there a help account? No.
+     |          Give control of the message to alias.
+     |          Run qmail-local.
+     V          
+                   
+qmail-local alias ~alias help - help heaven.af.mil joe@heaven.af.mil ./Mailbox
+                   
+               Does ~alias/.qmail-help exist? Yes: "john".
+               Forward message to john.
diff --git a/PIC.local2ext b/PIC.local2ext
new file mode 100644 (file)
index 0000000..a8bf644
--- /dev/null
@@ -0,0 +1,41 @@
+                Original message:
+                   
+                   To: fred-sos
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to fred-sos@heaven.af.mil
+     |             From: joe@heaven.af.mil
+     |             To: fred-sos@heaven.af.mil
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, fred-sos@heaven.af.mil.
+     |          Is heaven.af.mil in locals? Yes.
+     |          Deliver locally to fred-sos@heaven.af.mil.
+     V          
+                   
+qmail-lspawn ./Mailbox
+                   
+     |          Look at mailbox name, fred-sos.
+     |          Is fred-sos listed in qmail-users? No.
+     |          Is there a fred-sos account? No.
+     |          Is there a fred account? Yes.
+     |          Is fred's uid nonzero? Yes.
+     |          Is ~fred visible to the qmailp user? Yes.
+     |          Is ~fred owned by fred? Yes.
+     |          Give control of the message to fred.
+     |          Run qmail-local.
+     V          
+                   
+qmail-local fred ~fred fred-sos - sos heaven.af.mil joe@heaven.af.mil ./Mailbox
+                   
+                Does ~fred/.qmail-sos exist? Yes: "./Extramail".
+                Write message to ./Extramail in mbox format.
diff --git a/PIC.local2local b/PIC.local2local
new file mode 100644 (file)
index 0000000..3a067e0
--- /dev/null
@@ -0,0 +1,40 @@
+                Original message:
+                   
+                   To: fred
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to fred@heaven.af.mil
+     |             From: joe@heaven.af.mil
+     |             To: fred@heaven.af.mil
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, fred@heaven.af.mil.
+     |          Is heaven.af.mil in locals? Yes.
+     |          Deliver locally to fred@heaven.af.mil.
+     V          
+                   
+qmail-lspawn ./Mailbox
+                   
+     |          Look at mailbox name, fred.
+     |          Is fred listed in qmail-users? No.
+     |          Is there a fred account? Yes.
+     |          Is fred's uid nonzero? Yes.
+     |          Is ~fred visible to the qmailp user? Yes.
+     |          Is ~fred owned by fred? Yes.
+     |          Give control of the message to fred.
+     |          Run qmail-local.
+     V          
+                   
+qmail-local fred ~fred fred '' '' heaven.af.mil joe@heaven.af.mil ./Mailbox
+                   
+                Does ~fred/.qmail exist? No.
+                Write message to ./Mailbox in mbox format.
diff --git a/PIC.local2rem b/PIC.local2rem
new file mode 100644 (file)
index 0000000..6857af5
--- /dev/null
@@ -0,0 +1,38 @@
+                Original message:
+                   
+                   To: bill@irs.gov
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to bill@irs.gov
+     |             From: joe@heaven.af.mil
+     |             To: bill@irs.gov
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, bill@irs.gov.
+     |          Is irs.gov in locals? No.
+     |          Is bill@irs.gov in virtualdomains? No.
+     |          Is irs.gov in virtualdomains? No.
+     |          Is .gov in virtualdomains? No.
+     |          Deliver remotely to bill@irs.gov.
+     V          
+                   
+qmail-rspawn    Run qmail-remote.
+
+     |             
+     V             
+
+qmail-remote    Look at host name, irs.gov.
+                Is irs.gov listed in smtproutes? No.
+               Look up DNS MX/A for irs.gov and connect to it by SMTP:
+                   
+                   MAIL FROM:<joe@heaven.af.mil>
+                   RCPT TO:<bill@irs.gov>
diff --git a/PIC.local2virt b/PIC.local2virt
new file mode 100644 (file)
index 0000000..60f80c8
--- /dev/null
@@ -0,0 +1,44 @@
+                Original message:
+                   
+                   To: dude@tommy.gov
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to dude@tommy.gov
+     |             From: joe@heaven.af.mil
+     |             To: dude@tommy.gov
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, dude@tommy.gov.
+     |          Is tommy.gov in locals? No.
+     |          Is dude@tommy.gov in virtualdomains? No.
+     |          Is tommy.gov in virtualdomains? Yes: "tommy.gov:fred".
+     |          Deliver locally to fred-dude@tommy.gov.
+     V          
+                   
+qmail-lspawn ./Mailbox
+                   
+     |          Look at mailbox name, fred-dude.
+     |          Is fred-dude listed in qmail-users? No.
+     |          Is there a fred-dude account? No.
+     |          Is there a fred account? Yes.
+     |          Is fred's uid nonzero? Yes.
+     |          Is ~fred visible to the qmailp user? Yes.
+     |          Is ~fred owned by fred? Yes.
+     |          Give control of the message to fred.
+     |          Run qmail-local.
+     V          
+                   
+qmail-local fred ~fred fred-dude - dude tommy.gov joe@heaven.af.mil ./Mailbox
+                   
+                Does ~fred/.qmail-dude exist? No.
+                Does ~fred/.qmail-default exist? Yes: "./Mail.tommy".
+                Write message to ./Mail.tommy in mbox format.
diff --git a/PIC.nullclient b/PIC.nullclient
new file mode 100644 (file)
index 0000000..a90d7cb
--- /dev/null
@@ -0,0 +1,38 @@
+                Original message:
+                   
+                   To: bill@irs.gov
+                   Hi.
+                   
+qmail-inject    Fill in the complete envelope and header:
+                   
+     |             (envelope) from joe@heaven.af.mil to bill@irs.gov
+     |             From: joe@heaven.af.mil
+     |             To: bill@irs.gov
+     |             
+     |             Hi.
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, bill@irs.gov.
+     |          Is irs.gov in locals? No.
+     |          Is bill@irs.gov in virtualdomains? No.
+     |          Is irs.gov in virtualdomains? No.
+     |          Is .gov in virtualdomains? No.
+     |          Deliver remotely to bill@irs.gov.
+     V          
+                   
+qmail-rspawn    Run qmail-remote.
+
+     |             
+     V             
+
+qmail-remote    Look at host name, irs.gov.
+                Is irs.gov listed in smtproutes? Yes: ":bigbang.af.mil".
+                Look up DNS A for bigbang.af.mil and connect by SMTP:
+                   
+                   MAIL FROM:<joe@heaven.af.mil>
+                   RCPT TO:<bill@irs.gov>
diff --git a/PIC.relaybad b/PIC.relaybad
new file mode 100644 (file)
index 0000000..513f74f
--- /dev/null
@@ -0,0 +1,8 @@
+qmail-smtpd     Receive message by SMTP from another host:
+                   
+                   MAIL FROM:<spammer@aol.com>
+                   RCPT TO:<bill@irs.gov>
+                
+                Is $RELAYCLIENT set? No.
+                Is irs.gov in rcpthosts? No.
+                Reject RCPT.
diff --git a/PIC.relaygood b/PIC.relaygood
new file mode 100644 (file)
index 0000000..0d62fa9
--- /dev/null
@@ -0,0 +1,33 @@
+qmail-smtpd     Receive message by SMTP from another host:
+                   
+     |             MAIL FROM:<joe@heaven.af.mil>
+     |             RCPT TO:<bill@irs.gov>
+     |          
+     |          Is $RELAYCLIENT set? Yes: "".
+     |          Accept RCPT.  
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, bill@irs.gov.
+     |          Is irs.gov in locals? No.
+     |          Is bill@irs.gov in virtualdomains? No.
+     |          Is irs.gov in virtualdomains? No.
+     |          Is .gov in virtualdomains? No.
+     |          Deliver remotely to bill@irs.gov.
+     V          
+                   
+qmail-rspawn    Run qmail-remote.
+
+     |             
+     V             
+
+qmail-remote    Look at host name, irs.gov.
+                Is irs.gov listed in smtproutes? No.
+               Look up DNS MX/A for irs.gov and connect to it by SMTP:
+                   
+                   MAIL FROM:<joe@heaven.af.mil>
+                   RCPT TO:<bill@irs.gov>
diff --git a/PIC.rem2local b/PIC.rem2local
new file mode 100644 (file)
index 0000000..62fe61a
--- /dev/null
@@ -0,0 +1,36 @@
+qmail-smtpd     Receive message by SMTP from another host:
+                   
+     |             MAIL FROM:<bill@irs.gov>
+     |             RCPT TO:<joe@heaven.af.mil>
+     |          
+     |          Is $RELAYCLIENT set? No.
+     |          Is heaven.af.mil in rcpthosts? Yes.
+     |          Accept RCPT.  
+     V             
+                   
+qmail-queue     Store message safely on disk.
+                Trigger qmail-send.
+     |             
+     V             
+                   
+qmail-send      Look at envelope recipient, joe@heaven.af.mil.
+     |          Is heaven.af.mil in locals? Yes.
+     |          Deliver locally to joe@heaven.af.mil.
+     V          
+                   
+qmail-lspawn ./Mailbox
+                   
+     |          Look at mailbox name, joe.
+     |          Is joe listed in qmail-users? No.
+     |          Is there a joe account? Yes.
+     |          Is joe's uid nonzero? Yes.
+     |          Is ~joe visible to the qmailp user? Yes.
+     |          Is ~joe owned by joe? Yes.
+     |          Give control of the message to joe.
+     |          Run qmail-local.
+     V          
+                   
+qmail-local joe ~joe joe '' '' heaven.af.mil bill@irs.gov ./Mailbox
+                   
+                Does ~joe/.qmail exist? No.
+                Write message to ./Mailbox in mbox format.
diff --git a/README b/README
index 929e25a..5208eaf 100644 (file)
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-qmail 1.01
-19970413
-Copyright 1997
+qmail 1.03
+19980615
+Copyright 1998
 D. J. Bernstein, qmail@pobox.com
 
 qmail is a secure, reliable, efficient, simple message transfer agent.
@@ -8,192 +8,262 @@ It is meant as a replacement for the entire sendmail-binmail system on
 typical Internet-connected UNIX hosts. See BLURB, BLURB2, BLURB3, and
 BLURB4 for more detailed advertisements.
 
-INSTALL says how to set up and test qmail. If you're upgrading from
-1.00, read UPGRADE instead.
+INSTALL says how to set up and test qmail. If you're upgrading from a
+previous version, read UPGRADE instead.
+
+See PIC.* for some ``end-to-end'' pictures of mail flowing through the
+qmail system.
 
 See http://pobox.com/~djb/qmail.html for other qmail-related software
 and a pointer to the qmail mailing list.
 
-Other documentation here: RFC* explain solutions to several Internet
-mail problems; all of these except RFCMXPS are implemented in qmail.
-CHANGES and THANKS show how qmail has changed since it was first
-released. SECURITY, INTERNALS, THOUGHTS, and TODO record many of the
-qmail design decisions.
+Other documentation: http://pobox.com/~djb/proto.html shows solutions to
+several Internet mail problems; many of these solutions are implemented
+in qmail. CHANGES and THANKS show how qmail has changed since it was
+first released. SECURITY, INTERNALS, THOUGHTS, and TODO record many of
+the qmail design decisions.
 
 The rest of this file is a list of systypes where various versions of
-qmail have been reported to work. 0.90 was the first gamma version. 0.96
-was the final gamma version. 1.00 had exactly the same code as 0.96. To
-see your systype, make systype; cat systype.
+qmail have been reported to work. 0.96 was the final gamma version; 1.00
+had exactly the same code as 0.96. To see your systype, make systype;
+cat systype.
 
 1.00: a.ux-3.0-svr2-:-:-:mc68030-:- (tnx RF)
-0.96: aix-3-2-:-:-:000011216700-:- (tnx JLB)
-0.91: aix-3-2-:-:-:000109257500-:-
-0.96: aix-4-1-:-:-:000088581000-:- (tnx HJB)
-0.95: aix-4-1-:-:-:00061176a600-:- (tnx JS)
-1.00: aix-4-1-:-:-:00910033a000-:- (tnx K2J)
-0.91: aix-4-2-:-:-:006030934c00-:-
-1.00: bsd.os-2.0.1-:i386-:-:i486-:- (tnx KR)
-0.93: bsd.os-2.0.1-:i386-:-:pentium-:-
+1.01: aix-3-2-:-:-:000000406300-:- (tnx DG)
+1.01: aix-3-2-:-:-:000011216700-:- (tnx JLB)
+1.01: aix-4-1-:-:-:000041574c00-:- (tnx M2H)
+1.01: aix-4-1-:-:-:000088581000-:- (tnx HJB)
+1.01: aix-4-1-:-:-:002b51134c00-:- (tnx MP)
+1.00: aix-4-1-:-:-:00910033a000-:- (tnx KJJ)
+1.01: aix-4-2-:-:-:000055247900-:- (tnx JLB)
+1.01: aix-4-2-:-:-:000062295800-:- (tnx TD)
+1.01: aix-4-2-:-:-:000136094c00-:- (tnx T2U)
+1.00: aix-4-2-:-:-:000205254600-:- (tnx MGM)
+1.01: aix-4-2-:-:-:005255bc4c00-:- (tnx DS)
+1.01: aix-4-2-:-:-:006030944c00-:-
+1.01: bsd.386-1.1-0-:i386-:-:i386-:- (tnx T2M)
+1.01: bsd.os-2.0-:i386-:-:pentium-:- (tnx MSS)
+1.01: bsd.os-2.0.1-:i386-:-:i486-:- (tnx KR)
 0.96: bsd.os-2.1-:i386-:-:-:- (tnx DAR)
 1.00: bsd.os-2.1-:i386-:-:i486-:- (tnx RJC)
-0.96: bsd.os-2.1-:i386-:-:pentium-:- (tnx DAR)
+0.96: bsd.os-2.1-:i386-:-:pentium-:- (tnx UO)
+1.01: bsd.os-3.0-:i386-:-:-:- (tnx VU)
+1.01: bsd.os-3.0-:i386-:-:pentium-:- (tnx RJO)
+1.01: bsd.os-3.1-:i386-:-:pentium-:- (tnx ABC)
+1.01: bsd.os-3.1-:i386-:-:pentium.ii-:- (tnx UO)
 0.96: dgux-5.4r2.01-generic-:-:-:aviion-:- (tnx HWM)
-0.93: dgux-5.4r3.10-generic-:-:-:aviion-:- (tnx HWM)
-0.91: freebsd-2.0.5-release-:i386-:-:-:- (tnx TG)
-0.92: freebsd-2.1-stable-:i386-:-:pentium.815\100-:-
-0.90: freebsd-2.1.0-release-:i386-:-:cy486dlc-:- (tnx G2A)
-1.00: freebsd-2.1.0-release-:i386-:-:i486-dx2-:- (tnx JLB)
-1.00: freebsd-2.1.0-release-:i386-:-:i486-dx-:- (tnx chrisj=???)
-0.96: freebsd-2.1.0-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MBS)
-0.95: freebsd-2.1.5-release-:i386-:-:-:- (tnx NAA)
-0.96: freebsd-2.1.5-release-:i386-:-:i486-dx-:- (tnx FN)
-0.95: freebsd-2.1.5-release-:i386-:-:pentium.510\60.or.567\66-:- (tnx M2L)
-0.95: freebsd-2.1.5-release-:i386-:-:pentium.735\90-:- (tnx AG)
-0.92: freebsd-2.1.5-stable-:i386-:-:pentium.735\90.or.815\100-:- (tnx FE)
+1.01: freebsd-2.1.0-release-:i386-:-:i486-dx-:- (tnx VV)
+1.01: freebsd-2.1.0-release-:i386-:-:i486.dx2-:- (tnx JLB)
+1.00: freebsd-2.1.0-release-:i386-:-:i486dx-:- (tnx chrisj=???)
+1.01: freebsd-2.1.0-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MBS)
+1.01: freebsd-2.1.5-release-:i386-:-:i486-dx-:- (tnx B1F)
+0.96: freebsd-2.1.5-release-:i386-:-:i486dx-:- (tnx FN)
+1.01: freebsd-2.1.5-release-:i386-:-:unknown.-:- (tnx BMF)
 1.00: freebsd-2.1.6-release-:i386-:-:-:- (tnx TM)
 0.96: freebsd-2.1.6-release-:i386-:-:Pentium-Pro.150-:- (tnx CH)
-0.96: freebsd-2.1.6-release-:i386-:-:i486-dx-:- (tnx HCJ)
-0.95: freebsd-2.1.6-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx M2L)
+1.01: freebsd-2.1.6-release-:i386-:-:cy486dlc-:- (tnx M3H)
 0.96: freebsd-2.1.6.1-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx MF)
+1.01: freebsd-2.1.7-release-:i386-:-:i486-dx-:- (tnx AAF)
 1.00: freebsd-2.1.7-release-:i386-:-:pentium.735\90.or.815\100-:- (tnx JBB)
-0.95: freebsd-2.2-beta_a-:i386-:-:i486-dx2-:- (tnx DA)
-0.91: freebsd-2.2-current-:i386-:-:i486-dx-:- (tnx DC)
+1.01: freebsd-2.1.7-release-:i386-:-:pentium.815\100-:- (tnx B1F)
+1.01: freebsd-2.2-970422-releng-:i386-:-:-:- (tnx TM)
 1.00: freebsd-2.2-release-:i386-:-:-:- (tnx MT)
-1.00: freebsd-2.2.1-release-:i386-:-:-:- (tnx TM)
-1.00: freebsd-2.2.1-release-:i386-:-:i486-dx2-:- (tnx BR)
-1.00: freebsd-2.2.1-release-:i386-:-:pentium-:- (tnx IW)
-0.92: freebsd-3.0-current-:i386-:-:pentium-:- (tnx J2M)
+1.01: freebsd-2.2-stable-:i386-:-:cyrix.5x86-:- (tnx A2B)
+1.01: freebsd-2.2-stable-:i386-:-:pentium-:- (tnx gary@systemics=???)
+1.01: freebsd-2.2.1-release-:i386-:-:-:- (tnx M2R)
+1.01: freebsd-2.2.1-release-:i386-:-:i486-dx-:- (tnx PGR)
+1.00: freebsd-2.2.1-release-:i386-:-:i486.dx2-:- (tnx BR)
+1.01: freebsd-2.2.1-release-:i386-:-:pentium-:- (tnx REB)
+1.01: freebsd-2.2.1-release-:i386-:-:pentium.pro-:- (tnx JS)
+1.01: freebsd-2.2.2-release-:i386-:-:amd.am5x86.write-through-:- (tnx AGB)
+1.01: freebsd-2.2.2-release-:i386-:-:i486-dx-:- (tnx A2L)
+1.01: freebsd-2.2.2-release-:i386-:-:i486.dx2-:- (tnx D3S)
+1.01: freebsd-2.2.2-release-:i386-:-:pentium-:- (tnx B2F)
+1.01: freebsd-2.2.2-release-:i386-:-:pentium.pro-:- (tnx M2G)
+1.01: freebsd-2.2.5-release-:i386-:-:i486-dx-:- (tnx R2N)
+1.01: freebsd-2.2.5-release-:i386-:-:i486.dx2-:- (tnx AY)
+1.01: freebsd-2.2.5-release-:i386-:-:pentium.pro-:- (tnx AI)
+1.01: freebsd-2.2.5-stable-:i386-:-:i486.dx2-:- (tnx JK)
+1.01: freebsd-2.2.5-stable-:i386-:-:pentium-:- (tnx root@defiant=???)
+1.01: freebsd-2.2.6-release-:i386-:-:-:- (tnx TM)
+1.01: freebsd-2.2.6-release-:i386-:-:amd.am5x86.write-through-:- (tnx root@skully=???)
+1.00: freebsd-3.0-970209-snap-:i386-:-:-:- (tnx YF)
+1.01: freebsd-3.0-970428-snap-:i386-:-:pentium-:- (tnx M3S)
+1.01: freebsd-3.0-970807-snap-:i386-:-:amd.k6-:- (tnx KMD)
+1.01: freebsd-3.0-980309-snap-:i386-:-:pentium-:- (tnx MM)
+1.01: freebsd-3.0-current-:i386-:-:pentium-:- (tnx KB)
+1.01: hp-ux-a.09.05-a-:-:-:9000.712-:- (tnx SV)
+1.01: hp-ux-a.09.07-a-:-:-:9000.712-:- (tnx LB)
 1.00: hp-ux-b.09.00-a-:-:-:9000.360-:- (tnx VV)
-0.91: hp-ux-b.10.01-a-:-:-:9000.712-:- (tnx S2R)
-0.94: hp-ux-b.10.01-a-:-:-:9000.715-:- (tnx BG)
-0.91: hp-ux-b.10.01-a-:-:-:9000.801-:- (tnx S2T)
-0.93: irix-5.3-02091401-:-:-:ip22-:- (tnx PW)
-0.91: irix-5.3-11091811-:sgi-:-:ip19-:- (tnx BS)
-0.96: irix-5.3-11091812-:-:-:ip22-:- (tnx JL)
-1.00: irix-6.2-03131015-:-:-:ip22-:- (tnx SAS)
-0.92: linux-1.2.13-:i386-:-:i386-:- (tnx RN)
-1.00: linux-1.2.13-:i386-:-:i486-:- (tnx RF)
-0.96: linux-1.2.13-:i386-:-:pentium-:- (tnx MEE)
-0.91: linux-1.3.90-:alpha-:-:alpha-:- (tnx ES)
-0.93: linux-1.99.6-:i386-:-:pentium-:- (tnx TG)
-0.94: linux-2.0.0-:i386-:-:i486-:- (tnx PCO)
-1.00: linux-2.0.0-:i386-:-:pentium-:- (tnx JJR)
-0.91: linux-2.0.1-:alpha-:-:alpha-:- (tnx BET)
-0.90: linux-2.0.1-:i386-:-:i486-:- (tnx DF)
-0.93: linux-2.0.1-:i386-:-:pentium-:- (tnx FW)
-0.95: linux-2.0.6-:i386-:-:pentium-:-
+1.01: hp-ux-b.10.20-a-:-:-:9000.755-:- (tnx BCK)
+1.01: irix-5.3-11091812-:-:-:ip22-:- (tnx JL)
+1.01: irix-6.2-03131015-:-:-:ip22-:- (tnx DS)
+1.01: irix64-6.2-03131016-:-:-:ip19-:- (tnx AH)
+1.01: irix64-6.2-06101031-:-:-:ip28-:- (tnx DB)
+1.01: linux-1.2.13-:i386-:-:i486-:- (tnx RF)
+1.01: linux-1.2.13-:i386-:-:pentium-:- (tnx MEE)
+1.01: linux-1.99.4-:i386-:-:pentium-:- (tnx C2H)
+1.01: linux-2.0.0-:i386-:-:i486-:- (tnx kragen@gentle=???)
+1.01: linux-2.0.0-:i386-:-:pentium-:- (tnx MJD)
+1.01: linux-2.0.6-:i386-:-:pentium-:-
 1.00: linux-2.0.6-:i386-:-:ppro-:- (tnx MR)
-0.96: linux-2.0.7-:i386-:-:i486-:- (tnx TLM)
-0.90: linux-2.0.7-:i386-:-:pentium-:- (tnx K2J)
-0.94: linux-2.0.8-:i386-:-:i486-:- (tnx EP)
-0.90: linux-2.0.9-:i386-:-:pentium-:- (tnx JM)
-0.90: linux-2.0.10-:i386-:-:i486-:- (tnx JL)
-0.90: linux-2.0.10-:i386-:-:pentium-:- (tnx S2R)
-0.90: linux-2.0.11-:i386-:-:i486-:- (tnx ET)
-0.92: linux-2.0.12-:i386-:-:i486-:- (tnx TRR)
-0.90: linux-2.0.12-:i386-:-:ppro-:- (tnx SS)
+1.01: linux-2.0.7-:i386-:-:i486-:- (tnx TLM)
+1.01: linux-2.0.9-:i386-:-:i486-:- (tnx VBM)
 0.96: linux-2.0.13-:i386-:-:pentium-:- (tnx BW)
-0.90: linux-2.0.14-:i386-:-:pentium-:- (tnx PS)
-0.91: linux-2.0.15-:i386-:-:pentium-:- (tnx CL)
-0.90: linux-2.0.16-:i386-:-:i486-:- (tnx AP)
-0.91: linux-2.0.17-:i386-:-:i486-:- (tnx JL)
-0.91: linux-2.0.17-:i386-:-:pentium-:- (tnx SS)
-0.95: linux-2.0.18-:i386-:-:i386-:- (tnx RN)
-1.00: linux-2.0.18-:i386-:-:i486-:- (tnx JMS)
-1.00: linux-2.0.18-:i386-:-:pentium-:- (tnx D2S)
-0.92: linux-2.0.19-:alpha-:-:alpha-:- (tnx BET)
-0.92: linux-2.0.20-:i386-:-:pentium-:- (tnx RJH)
-0.92: linux-2.0.21-:i386-:-:i486-:- (tnx DCC)
-0.91: linux-2.0.21-:i386-:-:pentium-:- (tnx root@contact=???)
-0.92: linux-2.0.22-:i386-:-:i486-:- (tnx root@attila=???)
+1.01: linux-2.0.15-:i386-:-:i486-:- (tnx JCD)
+1.01: linux-2.0.18-:i386-:-:i486-:- (tnx tk@avalon=???)
+1.01: linux-2.0.18-:i386-:-:pentium-:- (tnx root@webtvchat=???)
 1.00: linux-2.0.22-:i386-:-:pentium-:- (tnx MDI)
 1.00: linux-2.0.23-:i386-:-:i486-:- (tnx B2L)
-0.93: linux-2.0.23-:i386-:-:pentium-:- (tnx IW)
-0.93: linux-2.0.24-:i386-:-:i486-:- (tnx root@cerberus=???)
+1.01: linux-2.0.24-:i386-:-:i486-:- (tnx GLM)
 1.00: linux-2.0.24-:i386-:-:pentium-:- (tnx VV)
 0.96: linux-2.0.25-:i386-:-:i486-:- (tnx BDB)
-1.00: linux-2.0.25-:i386-:-:pentium-:- (tnx AP)
-0.93: linux-2.0.25-:i386-:-:ppro-:- (tnx CS)
-0.93: linux-2.0.26-:i386-:-:i486-:- (tnx blynch=???)
-0.96: linux-2.0.26-:i386-:-:pentium-:- (tnx ESM)
-0.93: linux-2.0.26-:i386-:-:ppro-:- (tnx modus@enews=???)
+1.01: linux-2.0.25-:i386-:-:pentium-:- (tnx KA)
+0.93: linux-2.0.26-:i386-:-:i486-:- (tnx blynch@texas=???)
+1.01: linux-2.0.26-:i386-:-:pentium-:- (tnx robbie@opus=???)
 1.00: linux-2.0.27-:-:-:sparc-:- (tnx SVD)
-1.00: linux-2.0.27-:i386-:-:i486-:- (tnx FPL)
-1.00: linux-2.0.27-:i386-:-:pentium-:- (tnx  root@bullwinkle=???)
-1.00: linux-2.0.27-:i386-:-:ppro-:- (tnx DE)
-1.00: linux-2.0.28-:i386-:-:i486-:- (tnx H2S)
+1.00: linux-2.0.27-:i386-:-:i386-:- (tnx ECG)
+1.01: linux-2.0.27-:i386-:-:i486-:- (tnx BN)
+1.01: linux-2.0.27-:i386-:-:pentium-:- (tnx EK)
+1.01: linux-2.0.27-:i386-:-:ppro-:- (tnx L3L)
+1.01: linux-2.0.28-:i386-:-:i486-:- (tnx AAF)
 1.00: linux-2.0.28-:i386-:-:pentium-:- (tnx root@duggy=???)
-1.00: linux-2.0.28-:i386-:-:ppro-:- (tnx KJS)
-1.00: linux-2.0.29-:i386-:-:i486-:- (tnx PK)
-1.00: linux-2.0.29-:i386-:-:pentium-:- (tnx CL)
+1.01: linux-2.0.28-:i386-:-:ppro-:- (tnx S3T)
+1.01: linux-2.0.28-osfmach3-:-:-:ppc-:- (tnx CG)
+1.01: linux-2.0.29-:alpha-:-:alpha-:- (tnx MB)
+1.01: linux-2.0.29-:i386-:-:i386-:- (tnx AJK)
+1.01: linux-2.0.29-:i386-:-:i486-:- (tnx FPL)
+1.01: linux-2.0.29-:i386-:-:pentium-:- (tnx FW)
 1.00: linux-2.0.29-:i386-:-:ppro-:- (tnx MMM)
-0.92: linux-2.1.1-:i386-:-:i486-:- (tnx nick@sga2=???)
-0.92: linux-2.1.7-:i386-:-:ppro-:- (tnx JL)
-0.92: linux-2.1.9-:i386-:-:pentium-:- (tnx AC)
-0.92: linux-2.1.10-:i386-:-:ppro-:- (tnx S3T)
+1.01: linux-2.0.30-:-:-:sparc-:- (tnx J2P)
+1.01: linux-2.0.30-:alpha-:-:alpha-:- (tnx WS)
+1.01: linux-2.0.30-:i386-:-:i386-:- (tnx OK)
+1.00: linux-2.0.30-:i386-:-:i486-:- (tnx KUT)
+1.01: linux-2.0.30-:i386-:-:i486-:- (tnx PK)
+1.01: linux-2.0.30-:i386-:-:pentium-:- (tnx AV)
+1.00: linux-2.0.30-:i386-:-:ppro-:- (tnx root@gate=???)
+1.01: linux-2.0.30-osfmach3-:-:-:ppc-:- (tnx PTW)
+1.01: linux-2.0.30u11-:i386-:-:pentium-:- (tnx JTB)
+1.01: linux-2.0.31-:i386-:-:i486-:- (tnx SAE)
+1.01: linux-2.0.31-:i386-:-:pentium-:- (tnx B3W)
+1.01: linux-2.0.31-:i386-:-:ppro-:- (tnx JAK)
+1.01: linux-2.0.32-:-:-:ie86-:- (tnx root@vmlinuz=???)
+1.01: linux-2.0.32-:alpha-:-:alpha-:- (tnx NR)
+1.01: linux-2.0.32-:i386-:-:i486-:- (tnx SC)
+1.01: linux-2.0.32-:i386-:-:pentium-:- (tnx HT)
+1.01: linux-2.0.32-:i386-:-:ppro-:- (tnx RK)
+1.01: linux-2.0.33-:i386-:-:i486-:- (tnx RAB)
+1.01: linux-2.0.33-:i386-:-:pentium-:- (tnx AF)
+1.01: linux-2.0.33-:i386-:-:ppro-:- (tnx B2W)
+1.01: linux-2.1.9-:i386-:-:i486-:- (tnx SJB)
+1.01: linux-2.1.10-:i386-:-:i486-:- (tnx JB)
 0.96: linux-2.1.13-:i386-:-:i486-:- (tnx ML)
-0.93: linux-2.1.13-:i386-:-:ppro-:- (tnx JL)
 0.96: linux-2.1.14-:i386-:-:pentium-:- (tnx SCW)
 0.96: linux-2.1.23-:i386-:-:pentium-:- (tnx JF)
+1.01: linux-2.1.24-:-:-:ppc-:- (tnx meta=???)
 0.96: linux-2.1.25-:i386-:-:i486-:- (tnx JBF)
 0.96: linux-2.1.25-:i386-:-:pentium-:- (tnx UO)
 1.00: linux-2.1.26-:i386-:-:i486-:- (tnx DK)
 1.00: linux-2.1.27-:i386-:-:pentium-:- (tnx JF)
+1.01: linux-2.1.28-:i386-:-:i486-:- (tnx HDG)
 1.00: linux-2.1.28-:i386-:-:pentium-:- (tnx RGS)
 1.00: linux-2.1.29-:i386-:-:i486-:- (tnx SJW)
-0.93: netbsd-1.2-:amiga-:-:amiga.4000.(m68040.cpu/mmu/fpu)-:- (tnx OS)
+1.01: linux-2.1.35-:i386-:-:pentium-:- (tnx JF)
+1.01: linux-2.1.36-:i386-:-:i486-:- (tnx ML)
+1.01: linux-2.1.42-:i386-:-:i486-:- (tnx wtanaka=???)
+1.01: linux-2.1.46-:i386-:-:pentium-:- (tnx VR)
+1.01: linux-2.1.51-:i386-:-:pentium-:- (tnx KO)
+1.01: linux-2.1.61-:i386-:-:i486-:- (tnx RO)
+1.01: linux-2.1.65-:i386-:-:i486-:- (tnx F2T)
+1.01: linux-2.1.71-:i386-:-:ppro-:- (tnx MJG)
+1.01: linux-2.1.78-:i386-:-:pentium-:- (tnx AS)
+1.01: linux-2.1.82-:i386-:-:pentium-:- (tnx AY)
+1.01: linux-2.1.85-:i386-:-:pentium-:- (tnx PJH)
+1.00: machten-4-0.4-:-:-:powerpc-:- (tnx RAM)
+1.01: netbsd-1.1-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GL)
+1.01: netbsd-1.2-:hp300-:-:-:- (tnx ML)
+1.01: netbsd-1.2-:i386-:-:i486dx.(genuineintel.486-class.cpu)-:- (tnx T2K)
 0.96: netbsd-1.2-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx GH)
-0.91: netbsd-1.2-:mac68k-:-:apple.macintosh.se/30..(68030)-:- (tnx hauke=???)
-0.92: netbsd-1.2b-:i386-:-:-:- (tnx MG)
-0.93: netbsd-1.2b-:i386-:-:pentium.(genuineintel.586-class.cpu)-:- (tnx MG)
+1.01: netbsd-1.2.1-:mac68k-:-:apple.macintosh.se/30..(68030)-:- (tnx HM)
+1.01: netbsd-1.2.1-:sparc-:-:fmi,mb86904.@.110.mhz,.on-chip.fpu-:- (tnx ZU)
 0.96: netbsd-1.2c-:pmax-:-:-:- (tnx JLW)
-0.92: nextstep-3.3-:hppa-:-:7100lc-:-
-0.92: nextstep-3.3-:i386-:-:pentium-:-
-0.91: openbsd-1.2-:openbsd.m68k-:-:mac68k-:- (tnx AKB)
-0.95: openbsd-2.0-:openbsd.i386-:-:i386-:- (tnx JPH)
-0.96: openbsd-2.0-:openbsd.m68k-:-:mac68k-:- (tnx AKB)
+1.01: netbsd-1.3-:hp300-:-:hp.9000/433.(33mhz.mc68040.cpu+mmu+fpu,.4k.on-chip.physical.i/d.caches)-:- (tnx TB)
+1.01: netbsd-1.3.1-:sun3-:-:sun.3/60-:- (tnx MBS)
+1.01: netbsd-1.3_alpha-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GL)
+1.01: nextstep-3.1-:mc680x0-:-:68040-:- (tnx JRY)
+1.01: nextstep-3.3-:hppa-:-:7100lc-:-
+1.01: nextstep-3.3-:i386-:-:pentium-:- (tnx HM)
+1.01: nextstep-3.3-:mc680x0-:-:68040-:- (tnx WEB)
+1.01: nextstep-4.1-:mc680x0-:-:68040-:- (tnx FN)
 1.00: openbsd-2.0-hoth#0-:openbsd.i386-:-:i386-:- (tnx MBS)
-1.00: openbsd-2.0-mr_potatoe_head#2-:openbsd.i386-:-:i386-:- (JJMK)
-0.96: openbsd-2.0-puma#1-:openbsd.m68k-:-:mac68k-:- (tnx AB)
-0.92: osf1-v3.0-347-:-:-:alpha-:- (tnx B2H)
-0.92: osf1-v4.0-386-:-:-:alpha-:- (tnx WW)
-0.96: sco_sv-3.2-2-:-:-:i386-:- (tnx DEH)
-0.96: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4c-:sun4c- (tnx MBS)
-0.91: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4m-:sun4m- (tnx IS)
-0.92: sunos-4.1.3_u1-2-:sparc-:sun4-:sun4c-:sun4c- (tnx ANR)
-0.93: sunos-4.1.3_u1-4-:sparc-:sun4-:sun4m-:sun4m- (tnx J2B)
+1.00: openbsd-2.0-mr_potatoe_head#2-:openbsd.i386-:-:i386-:- (tnx JJMK)
+0.96: openbsd-2.0-puma#1-:openbsd.m68k-:-:mac68k-:- (tnx AKB)
+1.01: openbsd-2.1-asgard#1-:openbsd.i386-:-:i386-:- (tnx ETT)
+1.01: openbsd-2.1-generic#71-:openbsd.sparc-:-:sparc-:- (tnx MMM2)
+1.01: openbsd-2.1-katana#2-:openbsd.i386-:-:i386-:- (tnx CHR)
+1.01: openbsd-2.1-puma#0-:openbsd.m68k-:-:mac68k-:- (tnx AKB)
+1.01: openbsd-2.2-ele#2-:openbsd.i386-:-:i386-:- (tnx RC)
+1.01: openbsd-2.2-generic#424-:openbsd.i386-:-:i386-:- (tnx ETT)
+1.01: osf1-v2.0-240-:-:-:alpha-:- (tnx JF)
+1.00: osf1-v3.2-148-:-:-:alpha-:- (tnx DL)
+1.01: osf1-v3.2-148-:-:-:alpha-:- (tnx RSK)
+1.01: osf1-v3.2-41-:-:-:alpha-:- (tnx MSD)
+1.01: osf1-v3.2-mp-4.2-:-:-:alpha-:- (tnx MSD)
+1.01: osf1-v4.0-386-:-:-:alpha-:- (tnx TEE)
+1.01: osf1-v4.0-464-:-:-:alpha-:- (tnx AWB)
+1.01: osf1-v4.0-564-:-:-:alpha-:- (tnx A2P)
+1.01: osf1-v4.0-564.32-:-:-:alpha-:- (tnx TLF)
+1.01: osf1-v4.0-878-:-:-:alpha-:- (tnx BJM)
+1.01: sco_sv-3.2-2-:-:-:i386-:- (tnx PW)
+1.01: sinix-l-5.41-d0005-:-:-:mx300i-:- (tnx IH)
+1.01: sunos-4.1.1-1-:mc68020-:sun3-:sun3-:sun3- (tnx JWB)
+1.01: sunos-4.1.1-1-:mc68020-:sun3-:sun3x-:sun3x- (tnx TT)
+1.01: sunos-4.1.3-jl-2-:sparc-:sun4-:sun4c-:sun4c- (tnx T2K)
+1.01: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4c-:sun4c- (tnx MBS)
+1.01: sunos-4.1.3_u1-1-:sparc-:sun4-:sun4m-:sun4m- (tnx RSK)
+1.01: sunos-4.1.3_u1-10-:sparc-:sun4-:sun4m-:sun4m- (tnx aoki=???)
 1.00: sunos-4.1.3_u1-4-:unknown-:sun4-:sun4m-:sun4m- (tnx J2B)
-0.91: sunos-4.1.3_u1-9-:sparc-:sun4-:sun4m-:sun4m- (tnx TA)
-0.91: sunos-4.1.4-2-:sparc-:sun4-:sun4c-:sun4c- (tnx ST)
-0.95: sunos-4.1.4-2-:sparc-:sun4-:sun4m-:sun4m- (tnx TG)
-0.95: sunos-4.1c-4.1.3-:sparc-:sun4-:sun4-:s4000- (tnx DBK)
-0.91: sunos-5.4-generic-:sparc-:sun4-:sun4m-:sun4m-
+1.01: sunos-4.1.3_u1-6-:sparc-:sun4-:sun4m-:sun4m- (tnx RD)
+1.01: sunos-4.1.4-1-:unknown-:sun4-:sun4m-:sun4m- (tnx M3S)
+1.01: sunos-4.1.4-2-:sparc-:sun4-:sun4m-:sun4m-
+1.01: sunos-5.3-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx JDJ)
+1.01: sunos-5.4-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx jimo=???)
 0.96: sunos-5.4-generic_101945-10-:sparc-:sun4-:sun4m-:sun4m- (tnx W2K)
-0.93: sunos-5.4-generic_101945-23-:-:sun4-:sun4m-:sun4m- (tnx JP)
-0.92: sunos-5.4-generic_101945-23-:sparc-:-:sun4c-:- (tnx BH)
 1.00: sunos-5.4-generic_101945-34-:sparc-:sun4-:sun4m-:sun4m- (tnx ACB)
-0.92: sunos-5.4-generic_101945-36-:-:sun4-:sun4c-:sun4c- (tnx JP)
-0.95: sunos-5.4-generic_101945-43-:-:sun4-:sun4m-:sun4m- (tnx JP)
-0.90: sunos-5.4-generic_101946-07-:-:i86pc-:i86pc-:i86pc- (tnx CR)
 0.96: sunos-5.4-generic_101946-35-:i386-:i86pc-:i86pc-:i86pc- (tnx CK)
-0.96: sunos-5.5-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx M2G)
-0.93: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG)
-1.00: sunos-5.5-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx SG)
-1.00: sunos-5.5-generic_103093-02-:sparc-:sun4-:sun4m-:sun4m- (tnx RF)
-0.91: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4d-:sun4d- (tnx M3S)
+1.01: sunos-5.5-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx seong=???)
+1.01: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx SPM)
+1.01: sunos-5.5-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM)
+1.01: sunos-5.5-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx YC)
+1.01: sunos-5.5-generic_103093-02-:sparc-:sun4-:sun4m-:sun4m- (tnx RF)
 0.96: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4m-:sun4m- (tnx RDM)
-0.91: sunos-5.5-generic_103093-03-:sparc-:sun4-:sun4u-:sun4u- (tnx olav=???)
-0.92: sunos-5.5-generic_103093-05-:sparc-:sun4-:sun4m-:sun4m- (tnx KE)
-0.93: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4d-:sun4d- (tnx KT)
-1.00: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (tnx TEE)
-0.94: sunos-5.5-generic_103094-01-:i386-:i86pc-:i86pc-:i86pc- (tnx MD)
-0.91: sunos-5.5-generic_103094-03-:i386-:i86pc-:i86pc-:i86pc- (tnx ding=???)
-1.00: sunos-5.5.1-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx DML)
-1.00: sunos-5.5.1-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx JMT)
-1.00: sunos-5.5.1-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx TH)
+1.01: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (tnx ERH)
+1.01: sunos-5.5-generic_103093-10-:sparc-:sun4-:sun4d-:sun4d- (tnx KT)
+1.01: sunos-5.5-generic_103094-05-:i386-:i86pc-:i86pc-:i86pc- (tnx M2G)
+1.01: sunos-5.5.1-generic-:i386-:i86pc-:i86pc-:i86pc- (tnx cro=???)
+1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx CG)
+1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx MBS)
+1.01: sunos-5.5.1-generic-:sparc-:sun4-:sun4u-:sun4u-
 0.96: sunos-5.5.1-generic_103640-02-:sparc-:sun4-:sun4m-:sun4m- (tnx SGC)
-0.95: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4m-:sun4m- (tnx MRG)
 1.00: sunos-5.5.1-generic_103640-03-:sparc-:sun4-:sun4u-:sun4u- (tnx EG)
 1.00: sunos-5.5.1-generic_103640-05-:sparc-:sun4-:sun4m-:sun4m- (tnx L2L)
-0.96: sunos-5.5.1-generic_patch-:i386-:i86pc-:i86pc-:i86pc- (tnx DK)
+1.01: sunos-5.5.1-generic_103640-05-:sparc-:sun4-:sun4u-:sun4u- (tnx KY)
+1.01: sunos-5.5.1-generic_103640-06-:sparc-:sun4-:sun4u-:sun4u- (tnx RA)
+1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4c-:sun4c- (tnx RA)
+1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4d-:sun4d- (tnx MS)
+1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4m-:sun4m- (tnx S2P)
+1.01: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4u-:sun4u- (tnx CM)
+1.01: sunos-5.5.1-generic_103640-12-:sparc-:sun4-:sun4m-:sun4m- (tnx IK)
+1.01: sunos-5.5.1-generic_103640-18-:sparc-:sun4-:sun4u-:sun4u- (tnx PMH)
+1.01: sunos-5.5.1-generic_103641-08-:i386-:i86pc-:i86pc-:i86pc- (tnx TL)
+1.01: sunos-5.5.1-generic_103641-12-:i386-:i86pc-:i86pc-:i86pc- (tnx JS)
+1.01: sunos-5.5.1-generic_105428-01-:sparc-:sun4-:sun4u-:sun4u- (tnx BCM)
+0.96: sunos-5.5.1-generic_patch-:i386-:i86pc-:i86pc-:i86pc- (tnx D2K)
+1.01: sunos-5.6-generic-:sparc-:sun4-:sun4c-:sun4c- (tnx DS)
+1.01: sunos-5.6-generic-:sparc-:sun4-:sun4m-:sun4m- (tnx BDM)
+1.01: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (tnx RPS)
+1.01: sunos-5.6-generic_105182-01-:i386-:i86pc-:i86pc-:i86pc- (tnx JFK)
+1.01: sunos-5.6-generic_105182-04-:i386-:i86pc-:i86pc-:i86pc- (tnx YC)
 0.96: ultrix-4.3-1-:pmax-:-:risc-:- (tnx YF)
+1.01: ultrix-4.4-0-:-:-:risc-:- (tnx RSK)
+1.01: unix_sv-4.2mp-2.1.2-:i386-:-:i386-:- (tnx J2W)
diff --git a/REMOVE.binmail b/REMOVE.binmail
new file mode 100644 (file)
index 0000000..9532ac9
--- /dev/null
@@ -0,0 +1,16 @@
+Here's how to remove binmail from your system. Don't do this if you have
+configured qmail to use binmail for local delivery.
+
+
+1. Find the binmail binary on your system: /usr/libexec/mail.local if
+   that exists, otherwise /bin/mail.
+
+2. Remove permissions from the binmail binary:
+      # chmod 0 /usr/libexec/mail.local
+
+3. If the binmail binary was /bin/mail, make sure that ``mail'' still
+   invokes a usable mailer. Under SVR4 you may want to link mail to
+   mailx.
+
+4. Comment out the comsat line in /etc/inetd.conf, and kill -HUP your
+   inetd.
diff --git a/REMOVE.sendmail b/REMOVE.sendmail
new file mode 100644 (file)
index 0000000..5be6e78
--- /dev/null
@@ -0,0 +1,28 @@
+Here's how to remove sendmail from your system.
+
+1. Find sendmail in your boot scripts. It's usually in either /etc/rc or
+   /etc/init.d/sendmail. It looks like
+           sendmail -bd -q15m
+   -q15m means that it should run the queue every 15 minutes; you may
+   see a different number. Comment out this line.
+
+2. Kill the sendmail daemon. You should first kill -STOP the daemon; if
+   any children are running, you should kill -CONT, wait, kill -STOP
+   again, and repeat ad nauseam. If there aren't any children, kill
+   -TERM and then kill -CONT.
+
+3. Check whether you have any messages in the sendmail queue,
+   /var/spool/mqueue. If you do, you will have to try flushing them with
+   sendmail.bak -q. If necessary, wait a while and run sendmail.bak -q
+   again. Repeat until the queue is empty. This may take several days.
+
+4. Remove the setuid bit on the sendmail binary, to prevent local users
+   from gaining extra privileges through sendmail's security holes. The
+   binary may be at several different locations:
+      # chmod 0 /usr/lib/sendmail
+      # chmod 0 /usr/sbin/sendmail
+      # chmod 0 /usr/lib/sendmail.mx
+
+5. Move the sendmail binary out of the way:
+      # mv /usr/lib/sendmail /usr/lib/sendmail.bak
+      # mv /usr/sbin/sendmail /usr/sbin/sendmail.bak
diff --git a/RFCHCSC b/RFCHCSC
deleted file mode 100644 (file)
index fba3184..0000000
--- a/RFCHCSC
+++ /dev/null
@@ -1,37 +0,0 @@
-The Hash Convention For Mail System Status Codes (HCMSSC)
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   RFC 1893 defines codes for mail delivery failures. For example,
-   code 5.1.1 means that the specified mailbox does not exist.
-
-   The qmail package sprays these codes all over the place, by adding a
-   code to the text of every error message, preceded by a hash mark and
-   surrounded by parentheses. It avoids using hash marks elsewhere.
-
-
-2. Examples
-
-   Here is a typical HCMSSC SMTP error message:
-
-      421 load average too high, please come back later (#4.3.2)
-
-   Here is part of a typical HCMSSC bounce message:
-
-      <mail-loop@silverton.berkeley.edu>:
-      This is looping; it already has my Delivered-To line. (#5.7.1)
-
-   But qmail doesn't use HCMSSC when it repeats another MTA's error
-   message:
-
-      <foo@heaven.af.mil>:
-      127.3.4.5 does not like recipient.
-      Remote host said: 550 <foo>... User unknown (#5.1.1)
-
-
-3. Security considerations
-
-   Don't take drastic action upon seeing "(#"; it might not be HCMSSC.
diff --git a/RFCLOOPS b/RFCLOOPS
deleted file mode 100644 (file)
index 0c4c91a..0000000
--- a/RFCLOOPS
+++ /dev/null
@@ -1,338 +0,0 @@
-Tools in the war on mail loops
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   An automailer means any program that receives a mail message and
-   automatically sends one or more mail messages. This term is meant to
-   include not only a mail-based server, such as a mailing list exploder
-   or a vacation program, but also an SMTP server, which receives a
-   message from the network and relays it to a local or remote user.
-
-   In a network full of automailers, any mistake can cause a mail loop.
-   Since some automailers generate several outputs in response to a
-   single input, a loop can produce an exponential explosion of mail.
-
-   All the automailers in the qmail package follow a general philosophy
-   designed to prevent mail loops and limit the damage from any loops
-   that do occur. These automailers have been repeatedly observed to
-   fail safe: they stop loops in the face of typical failures by other
-   hosts. This document explains the philosophy and describes the
-   automailers.
-
-   To some extent the philosophy here simply repeats and amplifies
-   standard practice as codified in RFC 974 and RFC 1123. Unfortunately,
-   the standards do not adequately control bounce loops, since they do
-   not recognize that postmasters want to see double bounces; they do
-   not adequately control relaying loops; and they do not prevent
-   cross-host forwarding loops.
-
-   Terminology: The mail message received by an automailer is called
-   input. The mail messages sent by an automailer are called outputs.
-   For simplicity, this document focuses on the case that the input has
-   just one envelope recipient.
-
-   REMINDER: This document describes the automailers in the qmail
-   package. Other packages include automailers that do not fit the
-   descriptions given here.
-
-   Beware that the war on mail loops can never be won: any method of
-   preventing mail loops can be subverted by other hosts. I welcome
-   further development of techniques that work well in practice.
-
-
-2. Basics
-
-   The output from an automailer is always further down the following
-   list than the input.
-
-      0 hops, <sender> is neither <> nor <#@[]>  normal messages
-      1 hop, <sender> is neither <> nor <#@[]>
-      2 hops, <sender> is neither <> nor <#@[]>
-      etc.
-      0 hops, <sender> is <>                     bounces
-      1 hop, <sender> is <>
-      2 hops, <sender> is <>
-      etc.
-      0 hops, <sender> is <#@[]>                 double bounces
-      1 hop, <sender> is <#@[]>
-      2 hops, <sender> is <#@[]>
-      etc.
-
-   Here sender means the envelope sender address. Hops means the number
-   of Received and Delivered-To fields in the header. See sections 3.3
-   and 3.4 for an explanation of <> and <#@[]>.
-
-   Consequently, no automailer ever generates an entirely new normal
-   message in response to a normal message. If the output is a normal
-   message, it always has more hops than the input.
-
-   When input and output are both normal messages, both bounces, or both
-   double bounces, the output header is essentially the same as the
-   input header. However, when an automailer moves from a normal message
-   to a bounce, or from a bounce to a double bounce, it generates an
-   entirely new header.
-
-   An automailer may refuse to operate if the input has too many hops.
-   The definition of too many hops depends on the automailer. This
-   practice is called hop counting. Note that some existing messages
-   legitimately take as many as 20 hops. One automailer uses a limit of
-   100 hops; this will be adequate for all messages in the foreseeable
-   future.
-
-   Hop counting is a weapon of last resort. It will, if correctly
-   implemented, prevent all infinite loops; however, even a finite loop
-   can do practically infinite damage, as illustrated in section 4.3.
-
-
-3. Pre-delivery automailers
-
-   Conceptually: The input is a message that has not yet reached its
-   envelope recipient address. It is fed to a relay, which attempts to
-   deliver the message directly to, or at least closer to, that address;
-   if the relay fails permanently, the message is fed to a bouncer or a
-   double-bouncer. Relays, bouncers, and double-bouncers are examples of
-   pre-delivery automailers.
-
-   A pre-delivery automailer produces at most one output.
-
-   The basic weapon against pre-delivery mail loops is gravity. A normal
-   message always moves closer to its envelope recipient, according to a
-   notion of distance defined in section 3.1. If it bounces before
-   reaching the recipient, it turns into a bounce message, which always
-   moves closer to the original envelope sender. If that in turn
-   bounces, it turns into a double bounce, which always moves closer to
-   a local postmaster. (Triple bounces do not exist.)
-
-
-3.1. Distance
-
-   The distance from a DNS domain D to a recipient U@R is defined as
-   follows, when R has an MX list: the minimum preference of D in the
-   MX list, or 100000 if D does not appear in the list.
-
-   When R has no MX records, the distance from R to U@R is defined as 0,
-   and the distance from any other domain to U@R is defined as 100000.
-
-   Exception: If R is an alias, i.e., if R has a CNAME record, the
-   distance from any domain to U@R is defined as 500000.
-
-   The distance from a host H to U@R is defined as the minimum distance
-   to U@R from any domain that touches H. (``D touches H'' means ``D has
-   an A record listing one of H's IP addresses.'')
-
-   Exception: If H does not accept mail from the network, its distance
-   to any recipient is defined as 999999.
-
-
-3.2. Relays
-
-   A relay is a pre-delivery automailer that sends the output towards
-   the envelope recipient. What this means for intra-host relays is not
-   discussed here. What this means for cross-host relays is the
-   following: if the relay is at host H, and it sends its output to host
-   T, then the distance from T to the output envelope recipient is
-   always smaller than the distance from H to the input envelope
-   recipient.
-
-   The following facts guarantee that certain cross-host relay behavior
-   is safe. For proofs of these facts, see Appendix A.
-
-      Fact 1: If R is an alias for X, X is not an alias, D touches T,
-      and T accepts mail from the network, then the distance from T to
-      U@X is smaller than the distance from H to U@R.
-
-      Fact 2: If R is not an alias, R has no MX records, H is not
-      touched by R, T is touched by R, and T accepts mail from the
-      network, then T is closer to U@R than H is.
-
-      Fact 3: If R is not an alias, R has an MX record with domain X and
-      preference p, H is not touched by any of the domains in the MX
-      list for R with preference <= p, T is touched by X, and T accepts
-      mail from the network, then T is closer to U@R than H is.
-
-   Also, a host that does not accept mail from the network can relay
-   messages to a nearby hub.
-
-   A relay adds a new Received header field to the top of the output.
-   Other than this, the output header, body, and envelope are exactly
-   the same as the input header, body, and envelope. Exception: If the
-   input envelope recipient is U@R, R is an alias for X, and X is not
-   an alias, the output envelope recipient is U@X.
-
-
-3.3. Bouncers
-
-   A bouncer is a pre-delivery automailer that lets the envelope sender
-   know what happened to a message. Most bouncers send failure notices.
-   Some bouncers, such as vacation servers and echo servers, send
-   success notices.
-
-   In a bouncer's output, the envelope sender is <>, and the envelope
-   recipient is the input envelope sender. A bouncer refuses to operate
-   if the input envelope sender is <> or <#@[]>.
-
-   Some mailers on the Internet do not understand the <> convention. In
-   fact, some mailers will rewrite <> as <@host>. So any message with an
-   envelope recipient of <> or <@host> is discarded upon local delivery.
-
-   Unlike a relay, a bouncer produces output with a new header, not
-   simply a copy of the input header. For example:
-
-      (envelope) from <> to <djb@silverton.berkeley.edu>
-      Date: 2 Jan 1996 03:38:25 GMT
-      From: DELIVERY NOTICE SYSTEM <MAILER-DAEMON@heaven.af.mil>
-      To: djb@silverton.berkeley.edu
-      Subject: failure notice
-
-   However, the body of the bounce indicates the relevant input envelope
-   recipient, as well as the Message-ID of the input, if the input had a
-   Message-ID. The body of a failure notice includes a copy of the
-   entire input message.
-
-
-3.4. Double-bouncers
-
-   A double-bouncer is a pre-delivery automailer that informs a local
-   postmaster of permanent failures to deliver bounce messages. Such
-   failures are generally caused by poorly configured hosts that produce
-   normal messages with faulty envelope sender addresses.
-
-   A double-bouncer refuses to operate unless the input envelope sender
-   is <>. The output envelope sender from a double-bouncer is <#@[]>;
-   note that <#@[]> cannot be used as an SMTP envelope sender under
-   RFC 821. The output envelope recipient is predetermined.
-
-   Note that double bounces are not suggested by RFC 1123. However,
-   faulty envelope sender addresses are usually configuration errors
-   that can and should be fixed. Some postmasters, faced with mail
-   software that throws away double bounces, resort to keeping copies of
-   all bounces; but single bounces are rarely the postmaster's problem.
-
-
-4. Post-delivery automailers
-
-   Conceptually: The input is a message that has reached its envelope
-   recipient address. It is fed to a post-delivery automailer at that
-   address.
-
-   The basic weapon against post-delivery loops is a new header field,
-   Delivered-To, tracing all the forwarders and mailing lists that a
-   message has been through. This field has the side benefit of making
-   it much easier for a user (or for a postmaster seeing a bounce) to
-   figure out the path that the message took. Delivered-To is similar to
-   RFC 1327's DL-Expansion-History, but (1) it omits the time stamp,
-   removing any need for parsing, and (2) it has a much better name.
-
-
-4.1. Exploders and repliers
-
-   There are two basic types of post-delivery automailers: exploders,
-   where the output envelope recipients are predetermined; and repliers,
-   where there is just one output, with envelope recipient determined
-   from the input.
-
-   Repliers normally determine the output envelope recipient as either
-   the input Reply-To header field, if it exists; or else the input
-   From header field, if it exists; or else the envelope sender. A
-   replier never produces an output to <> or <#@[]>.
-
-   Exploders are classified into mailing lists, where the output
-   envelope senders are predetermined, and forwarders, where every
-   output has envelope sender equal to the original envelope sender.
-
-   Exception: if the input envelope sender is <> or <#@[]>, then the
-   output envelope senders are equal to the input envelope sender, even
-   for a mailing list.
-
-   Note that, if the envelope sender of a mailing list with M bad
-   addresses is another exploder with E bad addresses, the local
-   postmaster will receive EM double bounces for each message to the
-   mailing list.
-
-
-4.2. Delivered-To
-
-   Every post-delivery automailer adds a new Delivered-To header field
-   to the top of each output.
-
-   The contents of the Delivered-To field are typically the address of
-   the automailer, i.e., the input envelope recipient, conventionally
-   without any quoting. The contents of the Delivered-To field are in
-   any case entirely predetermined. The automailer checks if exactly the
-   same Delivered-To field already appears in the header; if so, it
-   refuses to operate. 
-
-   A post-delivery automailer preserves existing Delivered-To and
-   Received fields. In fact, a post-delivery automailer generally
-   preserves all header fields. The exceptions are limited to known
-   fields that are not used for loop detection and that must be removed
-   for correct operation. For example, a replier generally changes the
-   body of a message and thus should not preserve the SVR4
-   Content-Length field.
-
-
-4.3. An example
-
-   Aliases and mailing lists are highly dangerous, because they can
-   generate several outputs for each input.
-
-   Here is an extreme example. A user has three accounts, and wants any
-   message to any of the accounts to be delivered to all three. So he
-   forwards luser@host1 to luser@host2 and luser@host3, forwards
-   luser@host2 to luser@host1 and luser@host3, and forwards luser@host3
-   to luser@host1 and luser@host2.
-
-   Without Delivered-To, someone who sends a message to luser@host1 will
-   receive a practically infinite series of bounces. For example, with a
-   hop count limit of 50, the sender will receive 1125899906842624
-   bounces.
-
-   If all the hosts, or two out of the three, support Delivered-To, the
-   message will bounce just a few times. If just one of the hosts
-   supports Delivered-To, it will be the unfortunate victim of a loop
-   between the other two hosts---although the total number of bounces
-   will drop from practically infinite down to a few hundred, with
-   typical hop count limits.
-
-
-Appendix A. Proofs of correctness for MX handling
-
-   Section 3.2 states three facts about the notion of distance defined
-   in section 3.1. Here are mathematical proofs of those facts.
-
-   Symbols: D, E, R, and X are domains; H and T are hosts; p and q are
-   nonnegative integers. {} is the empty set.
-
-   Hypotheses: M(R), the ``MX list for R,'' is a set of pairs (p,D)
-   where p <= 65535. There is a set A of domains, called ``aliases.''
-   There is a relation D->H, called ``D touches H.'' There is a set N of
-   hosts, called ``hosts that accept mail from the network.''
-
-   Definitions: m(D,R) = min { p: p = 100000 or (p,D) in M(R) } when
-   M(R) is nonempty. When M(R) is empty, m(D,R) is 0 if D = R, 100000
-   otherwise. f(D,R) is defined as 500000 if R is in A, m(D,R)
-   otherwise; this is the ``distance from D to U@R,'' for any U. g(H,R)
-   is defined as min { f(D,R): D->H } if H is in N, 999999 otherwise;
-   this is the ``distance from H to U@R,'' for any U.
-
-   Fact 1 (generalized): If R is in A, X is not in A, D->T, and T is in
-   N, then g(T,X) < g(H,R). Proof: R is in A, so f(E,R) = 500000 for any
-   E; thus g(H,R) >= 500000. X is not in A, so f(D,X) = m(D,X) <=
-   100000; hence g(T,X) <= f(D,X) <= 100000 < g(H,R).
-
-   Fact 2: If R is not in A, M(R) = {}, R->T, T is in N, and not R->H,
-   then g(T,R) < g(H,R). Proof: f(R,R) = m(R,R) = 0 since R is not in A
-   and M(R) = {}. T is in N so g(T,R) <= f(R,R) = 0 so g(T,R) = 0.
-   Suppose that g(H,R) <= g(T,R). Then g(H,R) = 0, so f(D,R) = 0 for
-   some D with D->H, so m(D,R) = 0. But then D = R by definition of m,
-   so R->H. Contradiction. Thus g(T,R) < g(H,R).
-
-   Fact 3: If R is not in A, (p,X) is in M(R), X->T, T is in N, and
-   (q,D) is not in M(R) whenever D->H and q <= p, then g(T,R) < g(H,R).
-   Proof: First m(X,R) <= p. R is not in A, so f(X,R) = m(X,R). T is in
-   N, so g(T,R) <= f(X,R). Thus g(T,R) <= p. Suppose that g(H,R) <= p.
-   Then f(D,R) <= p for some D with D->H, so m(D,R) <= p. But then
-   (m(D,R),D) is in M(R). Contradiction. Thus g(T,R) <= p < g(H,R).
diff --git a/RFCMXPS b/RFCMXPS
deleted file mode 100644 (file)
index d0d3a70..0000000
--- a/RFCMXPS
+++ /dev/null
@@ -1,122 +0,0 @@
-The Mail Exchanger Protocol Switch (MXPS)
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   Mail messages today are transferred through the Simple Mail Transfer
-   Protocol (SMTP). One can imagine other protocols that achieve the
-   same results as SMTP but that, for example, use the network more
-   efficiently.
-
-   The Mail Exchanger Protocol Switch (MXPS) lets other protocols
-   compete with SMTP. A receiver can announce its support for another
-   protocol while operating properly with MXPS-ignorant senders. A
-   sender can check for support, with no overhead, while operating
-   properly with MXPS-ignorant receivers.
-
-   All receivers must support SMTP, i.e., must be able to receive
-   messages via SMTP. Similarly, all senders must be able to send
-   messages via SMTP.
-
-
-2. The protocol switch
-
-   MXPS abuses the preference field of MX records. A protocol is
-   assigned to each possible preference.
-
-   SMTP is assigned to preferences 0 through 10000.
-
-   The initial MXPS experiment will involve preferences between 12800
-   and 13055 inclusive. These preferences are sliced into 16 portions:
-
-      12800, 12816, 12832, 12848, 12864, ..., 13040: slice #0 (SMTP)
-      12801, 12817, 12833, 12849, 12865, ..., 13041: slice #1 (QMTP)
-      12802, 12818, 12834, 12850, 12866, ..., 13042: slice #2
-      ...
-      12815, 12831, 12847, 12863, 12879, ..., 13055: slice #15
-
-   Preferences in slice #0 are assigned SMTP. Preferences in slice #1
-   are assigned the Quick Mail Transfer Protocol (QMTP). Preferences in
-   the remaining slices may be assigned protocols in the future.
-
-   A receiver must support the protocol assigned to its preference. More
-   precisely, if an MX record points to domain D, and the MX preference
-   is assigned protocol P, then every host listed as an A record for D
-   must support protocol P.
-
-   When a sender, following the procedure outlined in RFC 974 (and
-   modified by RFC 1123), attempts to deliver a mail message as
-   specified by that MX record, it may use protocol P instead of SMTP.
-   If it does not support protocol P, it may treat the attempt as a
-   temporary failure and go on to the next MX record. However, the
-   sender must not skip every MX record.
-
-   MX records must never use unassigned preferences. A sender may treat
-   an unassigned preference as referring to SMTP.
-
-   Example: 
-
-      A.EXAMPLE.ORG  IN  MX  12801  A.EXAMPLE.ORG
-      B.EXAMPLE.ORG  IN  MX  12801  A.EXAMPLE.ORG
-                     IN  MX  12816  C.EXAMPLE.ORG
-
-   A sender with a message for A.EXAMPLE.ORG will try A.EXAMPLE.ORG by
-   QMTP. If it does not support QMTP, it will try SMTP instead. Note
-   that A.EXAMPLE.ORG must support both QMTP and SMTP.
-
-   A sender with a message for B.EXAMPLE.ORG will try A.EXAMPLE.ORG by
-   QMTP, then C.EXAMPLE.ORG by SMTP. If it does not support QMTP, it may
-   try SMTP instead of QMTP, or it may skip A.EXAMPLE.ORG.
-
-   Some of the above requirements might be violated if current
-   MXPS-ignorant domains use any preferences above 10000. Mail could be
-   unnecessarily rejected if any existing MXPS-ignorant domains have a
-   best-preference MX above 10000. I do not know any examples of such
-   domains.
-
-
-3. Protocol requirements
-
-   MXPS operates purely at the link level. It does not change the
-   fundamental nature of Internet mail.
-
-   The function of a mail transfer protocol is to transmit a message, as
-   described below, together with an envelope sender address and one or
-   more envelope recipient addresses.
-
-   A recipient address is a sequence of characters---i.e., nonnegative
-   integers---including an ASCII @ (64). It is parsed as box@dom, where
-   dom does not contain an @. The interpretation of box is up to the
-   hosts listed as MX records for dom. A sender address may contain an
-   @, in which case it is also of the form box@dom; or it may be a
-   special address, such as the empty string.
-
-   A mail message is structured as a sequence of lines. A line is a
-   sequence of characters. Every mail transfer protocol must be able to
-   transmit all sufficiently short boring mail messages. A boring mail
-   message is one where (1) no line has more than 80 characters and (2)
-   each character is either 9 or between 32 and 127 inclusive. Note that
-   RFC 1341 defines a mechanism for encoding a message with characters
-   between 0 and 255 inclusive as a boring mail message of similar
-   length.
-
-   The receiver must indicate, for each recipient address, either
-   acceptance, permanent rejection, or temporary rejection of the
-   message. Acceptance means that the receiver has taken responsibility,
-   in the sense of RFC 1123, section 5.3.3, for delivering the message
-   to that recipient. Rejection means that the receiver will not deliver
-   the message to that recipient.
-
-   Mail transfer protocols may vary in many details, such as line
-   encodings, the means of expressing acceptance or rejection, the
-   maximum number of allowable recipients per envelope, the encoding of
-   envelope addresses, the nature of optional protocol extensions, etc.
-
-
-4. Security considerations
-
-   MXPS does not change the following facts: An attacker who can subvert
-   the Domain Name System can steal or forge mail. An attacker who can
-   subvert TCP/IP can also steal or forge mail.
diff --git a/RFCNETSTR b/RFCNETSTR
deleted file mode 100644 (file)
index 6c02506..0000000
--- a/RFCNETSTR
+++ /dev/null
@@ -1,88 +0,0 @@
-Netstrings
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   A netstring is a self-delimiting encoding of a string. Netstrings are
-   very easy to generate and to parse. Any string may be encoded as a
-   netstring; there are no restrictions on length or on allowed bytes.
-   Another virtue of a netstring is that it declares the string size up
-   front. Thus an application can check in advance whether it has enough
-   space to store the entire string.
-
-   Netstrings may be used as a basic building block for reliable network
-   protocols. Most high-level protocols, in effect, transmit a sequence
-   of strings; those strings may be encoded as netstrings and then
-   concatenated into a sequence of characters, which in turn may be
-   transmitted over a reliable stream protocol such as TCP.
-
-   Note that netstrings can be used recursively. The result of encoding
-   a sequence of strings is a single string. A series of those encoded
-   strings may in turn be encoded into a single string. And so on.
-
-   In this document, a string of 8-bit bytes may be written in two
-   different forms: as a series of hexadecimal numbers between angle
-   brackets, or as a sequence of ASCII characters between double quotes.
-   For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of
-   length 12; it is the same as the string "hello world!".
-
-   Although this document restricts attention to strings of 8-bit bytes,
-   netstrings could be used with any 6-bit-or-larger character set.
-
-
-2. Definition
-
-   Any string of 8-bit bytes may be encoded as [len]":"[string]",".
-   Here [string] is the string and [len] is a nonempty sequence of ASCII
-   digits giving the length of [string] in decimal. The ASCII digits are
-   <30> for 0, <31> for 1, and so on up through <39> for 9. Extra zeros
-   at the front of [len] are prohibited: [len] begins with <30> exactly
-   when [string] is empty.
-
-   For example, the string "hello world!" is encoded as <31 32 3a 68
-   65 6c 6c 6f 20 77 6f 72 6c 64 21 2c>, i.e., "12:hello world!,". The
-   empty string is encoded as "0:,".
-
-   [len]":"[string]"," is called a netstring. [string] is called the
-   interpretation of the netstring.
-
-
-3. Sample code
-
-   The following C code starts with a buffer buf of length len and
-   prints it as a netstring.
-
-      if (printf("%lu:",len) < 0) barf();
-      if (fwrite(buf,1,len,stdout) < len) barf();
-      if (putchar(',') < 0) barf();
-
-   The following C code reads a netstring and decodes it into a
-   dynamically allocated buffer buf of length len.
-
-      if (scanf("%9lu",&len) < 1) barf();  /* >999999999 bytes is bad */
-      if (getchar() != ':') barf();
-      buf = malloc(len + 1);       /* malloc(0) is not portable */
-      if (!buf) barf();
-      if (fread(buf,1,len,stdin) < len) barf();
-      if (getchar() != ',') barf();
-
-   Both of these code fragments assume that the local character set is
-   ASCII, and that the relevant stdio streams are in binary mode.
-
-
-4. Security considerations
-
-   The famous Finger security hole may be blamed on Finger's use of the
-   CRLF encoding. In that encoding, each string is simply terminated by
-   CRLF. This encoding has several problems. Most importantly, it does
-   not declare the string size in advance. This means that a correct
-   CRLF parser must be prepared to ask for more and more memory as it is
-   reading the string. In the case of Finger, a lazy implementor found
-   this to be too much trouble; instead he simply declared a fixed-size
-   buffer and used C's gets() function. The rest is history.
-
-   In contrast, as the above sample code shows, it is very easy to
-   handle netstrings without risking buffer overflow. Thus widespread
-   use of netstrings may improve network security.
diff --git a/RFCNRUDT b/RFCNRUDT
deleted file mode 100644 (file)
index 4f3196a..0000000
--- a/RFCNRUDT
+++ /dev/null
@@ -1,89 +0,0 @@
-Notice-Requested-Upon-Delivery-To (NRUDT)
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   The UNIX sendmail program has for many years supported a
-   Return-Receipt-To (RRT) header field that requests a notice of
-   successful final delivery.
-
-   Notice-Requested-Upon-Delivery-To (NRUDT) has the same basic
-   function. The big difference is that RRT lists the sender's address,
-   while NRUDT lists the recipient's address.
-
-   This change is critical. RRT works poorly for messages to multiple
-   recipients, because it requests a notice from every recipient. RRT in
-   a message to a large mailing list produces a giant, usually
-   unintentional, flood of mail. This problem is so severe that RRT has
-   been disabled in recent versions of sendmail.
-
-   NRUDT is designed to be adopted immediately, with minimal disruption,
-   as a solution to the problems of RRT. Note that NRUDT is merely a
-   request for notification; unlike the link-level Delivery Status
-   Notification SMTP extension, NRUDT does not provide a guarantee of
-   notification.
-
-   NRUDT is supported by the qreceipt program in the qmail package.
-
-
-2. Syntax
-
-   NRUDT is a field in the header of an RFC 822 mail message. It has the
-   following syntax:
-
-      "Notice-Requested-Upon-Delivery-To" ":" 1#address
-
-   See RFC 822 for more information about header fields and addresses.
-
-   NRUDT requests that, upon final delivery of the message to any of the
-   specified addresses, the sender be notified. Note that more than one
-   address can appear in a single NRUDT header field. Multiple NRUDT
-   header fields should not appear in a single message.
-
-
-3. Response
-
-   Upon successful final delivery of a message to any address listed in
-   an NRUDT header field, the host performing delivery may, if desired,
-   generate a success notice.
-
-   The success notice is similar to a failure notice as described in RFC
-   1123. Its envelope sender is <>. Its envelope recipient is the
-   envelope sender of the original message; however, if the envelope
-   sender of the original message is <>, a success notice is not sent.
-
-   The body of the success notice does not contain a copy of the
-   original message, but it does indicate the Message-ID of the original
-   message, as well as the relevant recipient address.
-
-   A success notice may indicate delivery to several addresses. For
-   example, given the following message:
-
-      (envelope) from djb@silverton.berkeley.edu 
-      (envelope) to god@heaven.af.mil, angels@heaven.af.mil
-      Date: 1 Jan 1996 21:43:34 GMT
-      From: "D. J. Bernstein" <djb@silverton.berkeley.edu>
-      Message-Id: <19960101214334.8529.qmail@silverton.berkeley.edu>
-      Notice-Requested-Upon-Delivery-To: God <god@heaven.af.mil>,
-        angels@heaven.af.mil (You Know Who You Are)
-      ...
-
-   a host may respond as follows:
-
-      (envelope) from <> to djb@silverton.berkeley.edu
-      Date: 1 Jan 1996 21:43:37 GMT
-      From: DELIVERY NOTICE SYSTEM <MAILER-DAEMON@heaven.af.mil>
-      To: djb@silverton.berkeley.edu
-      Subject: success notice
-
-      I delivered <19960101214334.8529.qmail@silverton.berkeley.edu>
-      to the following local mailboxes:
-
-         god@heaven.af.mil
-         angels@heaven.af.mil
-
-      Thanks for asking.
-
-   However, a success notice is never merged with a failure notice.
diff --git a/RFCQMTP b/RFCQMTP
deleted file mode 100644 (file)
index 6c48e98..0000000
--- a/RFCQMTP
+++ /dev/null
@@ -1,229 +0,0 @@
-Quick Mail Transfer Protocol (QMTP)
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   The Quick Mail Transfer Protocol (QMTP) is a replacement for the
-   Simple Mail Transfer Protocol (SMTP). QMTP eliminates any need for
-   end-of-line scanning between hosts with the same end-of-line
-   convention. It features automatic pipelining and chunking, 8-bit
-   transmission, prior declaration of the message size, and efficient
-   batching. It is designed to be very easy to implement.
-
-   QMTP is supported by the qmail-qmtpd and maildir2qmtp programs in the
-   qmail package.
-
-   In this document, a string of 8-bit bytes may be written in two
-   different forms: as a series of hexadecimal numbers between angle
-   brackets, or as a sequence of ASCII characters between double quotes.
-   For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of
-   length 12; it is the same as the string "hello world!". Note that
-   these notations are part of this document, not part of the protocol.
-
-
-2. Protocol
-
-   A QMTP client connects to a QMTP server, as discussed in section 7,
-   over a reliable stream protocol allowing transmission of 8-bit bytes.
-
-   Protocol outline: the client sends one or more packages; after each
-   package, the server sends back some responses.
-
-   The client begins by sending a package. A package contains a mail
-   message, an envelope sender address, and one or more envelope
-   recipient addresses. See section 4 for the format of a package.
-
-   When the server sees the end of the package, it sends back a series
-   of responses, one response for each envelope recipient address, in
-   the same order as given by the client. The server is not permitted to
-   change the order under any circumstances, even if two addresses are
-   the same. See section 5 for the format of a response.
-
-   The server is not permitted to send any portion of its responses to a
-   package until the client has sent the final byte of the package. The
-   client is permitted to close the connection before sending the final
-   byte of the package; in this case, the server must throw away the
-   package without attempting to deliver the message. However, the
-   server must not throw away previously accepted messages.
-
-   The client does NOT need to wait for a server response before sending
-   another package. The server must NOT throw away incoming data when it
-   sends a response. It is the client's responsibility to avoid
-   deadlock: if it sends a package before receiving all expected server
-   responses, it must continuously watch for those responses. The server
-   is permitted to delay its responses if further data has already shown
-   up from the client; while it is delaying responses, it must not pause
-   to wait for further data for the client.
-
-   The server is permitted to close the connection at any time, although
-   high-quality servers will try to avoid doing so. Any response not
-   received by the client indicates a temporary failure.
-
-   A QMTP session should take at most 1 hour. Both sides are expected
-   to close the connection after this time.
-
-
-3. Messages
-
-   In this document, an ``8-bit mail message'' means a sequence of
-   lines. Each line is a string of zero or more 8-bit bytes.
-
-   A message is called ``safe'' if none of its bytes are <0a>.
-
-   Implementation note: Here is the intended interpretation of text
-   files as messages under some current operating systems. Under DOS, a
-   message is stored on disk as
-
-      first line, <0d 0a>, second line, <0d 0a> ... <0d 0a>, last line.
-
-   Under UNIX, a message is stored on disk as
-
-      first line, <0a>, second line, <0a> ... <0a>, last line.
-
-   Notice that both of these encodings are reversible for safe messages.
-
-   In practice, it is very common for the last line to be empty. Many
-   existing utilities refer to the last line as a ``partial line'' and
-   ignore it whether or not it is empty.
-
-
-4. Packages
-
-   A package is the concatenation of three strings:
-
-      first, an encoded 8-bit mail message;
-      second, an encoded envelope sender address;
-      third, an encoded series of encoded envelope recipient addresses.
-
-   Each envelope address is a string of 8-bit bytes. The interpretation
-   of addresses depends on the environment in which QMTP is used and is
-   outside the scope of this document. Each address is encoded as a
-   netstring, as discussed in section 6. The series of encoded recipient
-   addresses is in turn encoded as a netstring.
-
-   A message is encoded as a string of 8-bit bytes in one of two ways:
-
-      Encoding #1 is <0d>, the first line, <0d 0a>, the second line,
-      <0d 0a>, the third line, ..., <0d 0a>, the last line.
-
-      Encoding #2 is <0a>, the first line, <0a>, the second line, <0a>,
-      the third line, ..., <0a>, the last line.
-
-   This string of 8-bit bytes is in turn encoded as a netstring, as
-   discussed in section 6.
-
-   Every server must be prepared to handle encoding #1 and encoding #2.
-   A server must not reject a message merely because of its encoding.
-
-   Implementation note: The intent of encoding #1 and encoding #2 is to
-   allow very straightforward handling of text files under DOS and UNIX
-   respectively. The programmer can print <0d> or <0a> and then simply
-   copy the file.
-
-
-5. Responses
-
-   Each response is a nonempty string of 8-bit bytes, encoded as a
-   netstring. The first byte of the string is one of the following:
-
-      "K" The message has been accepted for delivery to this envelope
-          recipient. This is morally equivalent to the 250 response to
-          DATA in SMTP; it is subject to the reliability requirements
-          of RFC 1123, section 5.3.3.
-
-      "Z" Temporary failure. The client should try again later.
-
-      "D" Permanent failure.
-
-   The remaining bytes are a description of what happened. It is
-   expected that the description, when interpreted as UTF-2 characters,
-   (1) will be human-readable, (2) will not repeat the envelope
-   recipient address, and (3) will not include formatting characters
-   other than <20>. However, these expectations are not requirements,
-   and the client should be ready for arbitrary bytes from the server.
-
-   Descriptions beginning with <20> are reserved for future extensions.
-   In descriptions not beginning with <20>, the character "#" must not
-   appear except in HCMSSC codes.
-
-   A server must NOT accept a safe message unless it can store the
-   message without corruption. More precisely: if the encoded message
-   sent by the client matches the encoding of some safe message M, then
-   acceptance means that the server is accepting responsibility to
-   deliver M to the envelope recipient. (There is at most one
-   possibility for M, since encodings are reversible on safe messages.)
-   Deletion of nulls is NOT permissible; a server that deletes nulls
-   must reject any message containing nulls. Folding of long lines and
-   high-bit stripping are also NOT permissible.
-
-   Servers are permitted to change unsafe messages.
-
-
-6. Netstrings
-
-   Any string of 8-bit bytes may be encoded as [len]":"[string]",".
-   Here [string] is the string and [len] is a nonempty sequence of ASCII
-   digits giving the length of [string] in decimal. The ASCII digits are
-   <30> for 0, <31> for 1, and so on up through <39> for 9. Extra zeros
-   at the front of [len] are prohibited: [len] begins with <30> exactly
-   when [string] is empty.
-
-   For example, the string "hello world!" is encoded as <31 32 3a 68
-   65 6c 6c 6f 20 77 6f 72 6c 64 21 2c>, i.e., "12:hello world!,". The
-   empty string is encoded as "0:,".
-
-   [len]":"[string]"," is called a netstring. [string] is called the
-   interpretation of the netstring.
-
-
-7. Encapsulation
-
-   QMTP may be used on top of TCP. A QMTP-over-TCP server listens for
-   TCP connections on port 209.
-
-
-8. Examples
-
-   A client opens a connection and sends the concatenation of the
-   following strings:
-
-      "246:" <0a>
-         "Received: (qmail-queue invoked by uid 0);"
-         " 29 Jul 1996 09:36:40 -0000" <0a>
-         "Date: 29 Jul 1996 11:35:35 -0000" <0a>
-         "Message-ID: <19960729113535.375.qmail@heaven.af.mil>" <0a>
-         "From: God@heaven.af.mil" <0a>
-         "To: djb@silverton.berkeley.edu (D. J. Bernstein)" <0a>
-         <0a>
-         "This is a test." <0a> ","
-      "24:" "God-DSN-37@heaven.af.mil" ","
-      "30:" "26:djb@silverton.berkeley.edu," ","
-
-      "356:" <0d>
-         "From: MAILER-DAEMON@heaven.af.mil" <0d 0a>
-         "To:" <0d 0a>
-         "   Hate." <22> "The Quoting" <22>
-        "@SILVERTON.berkeley.edu," <0d 0a>
-         "   " <22> "\\Backslashes!" <22>
-        "@silverton.BERKELEY.edu" <0d 0a>
-         <0d 0a>
-         "The recipient addresses here could"
-        " have been encoded in SMTP as" <0d 0a>
-         "" <0d 0a>
-         "   RCPT TO:<Hate.The\ Quoting@silverton.berkeley.EDU>" <0d 0a>
-         "   RCPT TO:<\\Backslashes!@silverton.berkeley.edu>" <0d 0a>
-         <0d 0a>
-         "This ends with a partial last line, right here" ","
-      "0:" ","
-      "83:" "39:Hate.The Quoting@silverton.berkeley.edu,"
-         "36:\Backslashes!@silverton.berkeley.EDU," ","
-      
-   The server sends the following response, indicating acceptance:
-
-      "21:Kok 838640135 qp 1390,"
-      "21:Kok 838640135 qp 1391,"
-      "21:Kok 838640135 qp 1391,"
-
-   The client closes the connection.
diff --git a/RFCQSBMF b/RFCQSBMF
deleted file mode 100644 (file)
index de132a7..0000000
--- a/RFCQSBMF
+++ /dev/null
@@ -1,155 +0,0 @@
-The qmail-send Bounce Message Format (QSBMF)
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   When a message transport agent (MTA) finds itself permanently unable
-   to deliver a mail message, it generates a new message, generally
-   known as a bounce message, back to the envelope sender.
-
-   Bounce messages produced by the qmail-send program display the list
-   of failed recipient addresses, an explanation for each address, and a
-   copy of the original message, in a format that is easy for both
-   humans and programs to read. For example:
-
-      Date: 17 Mar 1996 03:54:40 -0000
-      From: MAILER-DAEMON@silverton.berkeley.edu
-      To: djb@silverton.berkeley.edu
-      Subject: failure notice
-      
-      Hi. This is the qmail-send program at silverton.berkeley.edu.
-      I'm afraid I wasn't able to deliver your message to the
-      following addresses. This is a permanent error; I've given up.
-      Sorry it didn't work out.
-      
-      <god@heaven.af.mil>:
-      Sorry, I couldn't find any host by that name.
-      
-      --- Below this line is a copy of the message.
-      
-      Return-Path: <djb@silverton.berkeley.edu>
-      Received: (qmail 317 invoked by uid 7); 17 Mar 1996 03:54:38 -0000
-      Date: 17 Mar 1996 03:54:38 -0000
-      Message-ID: <19960317035438.316.qmail@silverton.berkeley.edu>
-      From: djb@silverton.berkeley.edu (D. J. Bernstein)
-      To: god@heaven.af.mil
-      Subject: are you there?
-      
-      Just checking.
-
-   This document defines qmail-send's format for bounce messages.
-
-   In this document, a string of 8-bit bytes may be written in two
-   different forms: as a series of hexadecimal numbers between angle
-   brackets, or as a sequence of ASCII characters between double quotes.
-   For example, <68 65 6c 6c 6f 20 77 6f 72 6c 64 21> is a string of
-   length 12; it is the same as the string "hello world!".
-
-
-2. Format
-
-   A bounce message may be recognized as QSBMF as follows: its body
-   begins with the characters "Hi. This is the" exactly as shown.
-
-   The body of the message has four pieces: an introductory paragraph,
-   zero or more recipient paragraphs, a break paragraph, and the
-   original message.
-
-   Each paragraph is a series of non-blank lines followed by a single
-   blank line. The break paragraph begins with the character "-". All
-   other paragraphs begin with characters other than "-". The break
-   paragraph is human-readable but provides no interesting information.
-
-   The introductory paragraph is human-readable. It gives the name and
-   human-comprehensible location of the MTA, but parsers should not
-   attempt to use this information.
-
-   The only type of recipient paragraph described here is a failure
-   paragraph, which begins with the character "<". Paragraphs beginning
-   with other characters are reserved for future extensions.
-
-   The first line of a failure paragraph ends with the characters ">:".
-   Everything between the leading "<" and the trailing ">:" is an
-   (unquoted) Internet mail address.
-
-   A failure paragraph asserts that the MTA was permanently unable to
-   deliver the message to the mail address shown on the first line; the
-   MTA will not attempt further deliveries to that address. The
-   remaining lines of the paragraph give a human-readable description of
-   the reason for failure. Descriptions beginning with <20>, and
-   descriptions containing "#", are reserved for future extensions.
-
-   The envelope sender might not have sent his message to the address
-   shown. There are two reasons for this. First, the MTA may freely
-   replace unprintable characters with "_". Second, the original 
-   recipient address may have been an alias for the address shown.
-
-   The original message is an exact copy of the message received by the
-   MTA, including both header and body, preceded by a Return-Path field
-   showing the envelope sender.
-
-
-3. Comparison with 1892/1894
-
-   RFC 1892 and RFC 1894 together describe a format for delivery status
-   notifications. I have decided not to use that format, because I
-   believe that its complexity will prevent wide implementation and
-   increase the burden on people who manage mailing lists.
-
-   QSBMF is dedicated to failure reports, whereas RFC 1894 allows
-   success reports and deferral reports. Although it would be possible
-   to add deferral paragraphs and success paragraphs to QSBMF, it would
-   be even easier to design separate formats for such notices. I have
-   trouble reading mixed failure/deferral reports.
-
-   QSBMF always returns the entire original message. RFC 1892 allows
-   the MTA to return nothing or to return just the headers; it states
-   ``Return of content may be wasteful of network bandwidth.'' However,
-   failure notices are very rare, so the overall loss of bandwidth in
-   this case is insignificant. A much more important issue is storage
-   space: someone who manages a big mailing list does not want to have
-   to store several copies of each message in the form of bounces. The
-   best solution is to have each bounce automatically fed through a
-   program that stores only the critical information. I expect such
-   programs to spring up quickly for QSBMF.
-
-   RFC 1894 provides language-independent error messages, as described
-   by RFC 1893. One can achieve the same results more easily by adding
-   structure to the human-readable failure descriptions, for example
-   with HCMSSC.
-
-   RFC 1894 is able to communicate an ``envelope ID'' and the original
-   envelope recipient address specified by the sender. Unfortunately,
-   this information will almost never be available, since it requires
-   support by every intermediate MTA. All of the applications of this
-   information can be handled reliably, right now, with VERPs; this
-   requires support from the sender's MTA but not from other hosts.
-
-   RFC 1894 includes several pieces of information that might be of
-   human interest but can be seen just as easily from Received lines:
-   the name of the MTA where delivery failed, the name of the previous
-   MTA, timestamps, etc.
-
-   All of these RFC 1894 features have a cost: complexity. A program
-   cannot parse an 1894 report without parsing RFC 822 header fields
-   and understanding quite a bit of MIME. This will limit the
-   availability of parsing software. In the meantime, such reports are
-   annoying to mailing list maintainers, since they are full of
-   uninteresting information and are difficult to parse visually.
-
-
-4. Security considerations
-
-   Bounce messages may be forged. Never remove someone from a mailing
-   list without sending him a message stating that you are doing so,
-   even if the reason for removal is a series of apparent bounce
-   messages from his address.
-
-   If you send a message along a secret path, you should change the
-   envelope sender address of the message to yourself, so that a bounce
-   will not reveal anything to the original sender. In other words: for
-   secret forwarding, use a mailing list, not a forwarder.
-
-   See RFC 1894 for further discussion of these points.
diff --git a/RFCVERP b/RFCVERP
deleted file mode 100644 (file)
index 6299a44..0000000
--- a/RFCVERP
+++ /dev/null
@@ -1,88 +0,0 @@
-Variable Envelope Return Paths
-D. J. Bernstein, djb@pobox.com
-19970201
-
-
-1. Introduction
-
-   The fundamental problem in managing a large mailing list is matching
-   bounce messages to subscription addresses.
-
-   Often a bounce message refers to a failing address that does not
-   appear on the mailing list. One of the mailing list subscribers is
-   forwarding messages to that address. Which subscriber? As the list
-   grows, this question becomes more and more difficult to answer.
-
-   Sometimes a bounce message doesn't identify the address that failed.
-   On occasion it doesn't even include a copy of the original message.
-   See RFC 1211 for an extensive collection of horror stories.
-
-   In theory, one could solve this problem with the DSN option and DSN
-   format described in RFC 1891, RFC 1892, and RFC 1894. Unfortunately,
-   the DSN option is useless unless it is supported by every
-   intermediate MTA. The complexity of RFC 1891 means that it will be
-   many years, perhaps infinitely many, before DSNs are universally
-   supported. Furthermore, the complexity of RFC 1894 means that parsing
-   the subscriber address is difficult even on the occasions that the
-   address is available.
-
-   Variable envelope return paths (VERPs) completely eliminate this
-   problem _right now_. They automatically and reliably identify the
-   subscription address relevant to each bounce message. They provide
-   the address in a form that is trivial for automated bounce handlers
-   to parse. They require support from the local mailer, but they do not
-   require support from any other hosts.
-
-
-2. Variable envelope return paths
-
-   Here is how VERPs work: each recipient of the message sees a
-   different envelope sender address. When a message to the
-   djb-sos@silverton.berkeley.edu mailing list is sent to
-   God@heaven.af.mil, for example, it has the following envelope sender:
-
-      djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu
-
-   If the message bounces, the bounce message will be sent back to
-   djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu.
-
-   If God is forwarding His mail, the bounce message will still go to
-   djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu. No matter how
-   uninformative the bounce message is, it will display God's
-   subscription address in its envelope.
-
-   Another benefit of VERPs is that God Himself can see what address He
-   used to subscribe.
-
-   Making VERPs work requires two pieces of local software support.
-   First: it must be easy to modify the outgoing sender address
-   separately for each envelope recipient. For example, with one mailer,
-   qmail, a user can simply touch ~/.qmail-list-owner and
-   ~/.qmail-list-owner-default to apply VERPs to user-list.
-
-   Second, and more important: it must be easy to identify a collection
-   of addresses, such as djb-sos-owner-*, and send all mail for those
-   addresses to one place, while preserving the * information. Under
-   qmail, all user-list-owner-* mail will be sent to the user once he
-   touches ~/.qmail-list-owner-default. Sending the mail through an
-   automated bounce-handling program is just as easy.
-
-   With older mailers, applying VERPs would require setting up a new
-   user-list-owner-recipient alias for each new recipient. This
-   inconvenience has prevented VERPs from being widely exploited, even
-   though the idea is not new.
-
-
-3. Per-message VERPs
-
-   VERPs are not restricted to distinguishing mailing list subscribers;
-   they can also be used to distinguish messages.
-
-   For example, a user can send one message with an envelope sender
-   address of user-dsn-1, the next message with user-dsn-2, and so on.
-   As long as the local mailer gives all user-dsn-* back to that user,
-   he can reliably match up incoming bounces with outgoing messages.
-
-   Per-message VERPs can be combined with per-recipient VERPs. Every
-   application of RFC 1891's ORCPT and ENVID can be handled with
-   VERPs---easily, reliably, and right now.
index 218830d..098f124 100644 (file)
--- a/SECURITY
+++ b/SECURITY
@@ -5,6 +5,11 @@ discovered; sendmail's design means that any minor bug in 46000 lines of
 code is a major security risk. Other popular mailers, such as Smail, and
 even mailing-list managers, such as Majordomo, seem nearly as bad.
 
+Note added in 1998: I wrote the above paragraph in December 1995, when
+the latest version of sendmail was 8.6.12 (with 41000 lines of code).
+Fourteen security holes were discovered from sendmail 8.6.12 through
+8.8.5. See http://pobox.com/~djb/docs/maildisasters/sendmail.html.
+
 I started working on qmail because I was sick of this cycle of doom.
 Here are some of the things I did to make sure that qmail will never let
 an intruder into your machine.
@@ -38,7 +43,7 @@ timers, signals, and more. Even worse, the list of controlled items
 varies from one vendor's UNIX to the next, so it is very difficult to
 write portable code that cleans up everything.
 
-Of the twelve most recent sendmail security holes, six worked only
+Of the twenty most recent sendmail security holes, eleven worked only
 because the entire sendmail system is setuid.
 
 Only one qmail program is setuid: qmail-queue. Its only purpose is to
@@ -95,7 +100,7 @@ and the quoter both misinterpret the interface in the same way.
 When the original data is controlled by a malicious user, many of these
 bugs translate into security holes. Some examples: the Linux login
 -froot security hole; the classic find | xargs rm security hole; the
-recent Majordomo security hole. Even a simple parser like getopt is
+Majordomo injection security hole. Even a simple parser like getopt is
 complicated enough for people to screw up the quoting.
 
 In qmail, all the internal file structures are incredibly simple: text0
@@ -107,11 +112,6 @@ All the complexity of parsing RFC 822 address lists and rewriting
 headers is in the qmail-inject program, which runs without privileges
 and is essentially part of the UA.
 
-The only nasty case is .qmail, qmail's answer to .forward. I tried to
-make this as simple as possible, but unfortunately it still has to be
-edited by users. As a result, the qlist mailing-list-management program
-has to be careful to exclude subscriber addresses that contain newlines.
-
 
 6. Keep it simple, stupid.
 
@@ -127,5 +127,5 @@ I've mostly given up on the standard C library. Many of its facilities,
 particularly stdio, seem designed to encourage bugs. A big chunk of
 qmail is stolen from a basic C library that I've been developing for
 several years for a variety of applications. The stralloc concept and
-getline2() make it very easy to avoid buffer overruns, memory leaks,
-and artificial line length limits.
+getln() make it very easy to avoid buffer overruns, memory leaks, and
+artificial line length limits.
diff --git a/SENDMAIL b/SENDMAIL
new file mode 100644 (file)
index 0000000..9280c24
--- /dev/null
+++ b/SENDMAIL
@@ -0,0 +1,76 @@
+This document explains what you, as a user, will notice when the system
+switches from sendmail to qmail.
+
+This is a global document, part of the qmail package, not reflecting the
+decisions made by your system administrator. For details on
+
+   * which local delivery agent qmail is configured to use,
+   * whether qmail is configured to use dot-forward,
+   * whether ezmlm is installed,
+   * whether fastforward is installed, and
+   * all other local configuration features,
+
+see your local sendmail-qmail upgrade announcement (which your system
+administrator may have placed into /var/qmail/doc/ANNOUNCE).
+
+
+--- Mailbox location
+
+If your system administrator has configured qmail to use binmail for
+local deliveries, your mailbox will be in /var/spool/mail/you, just as
+it was under sendmail.
+
+If your system administrator has configured qmail to use qmail-local for
+local deliveries, your mailbox will be moved to ~you/Mailbox. There is a
+symbolic link from /var/spool/mail/you to ~you/Mailbox, so your mail
+reader will find the mailbox at its new location.
+
+
+--- Loop control
+
+qmail-local automatically adds a Delivered-To field at the top of every
+delivered message. It uses Delivered-To to prevent mail forwarding
+loops, including cross-host mailing-list loops.
+
+
+--- Outgoing messages
+
+qmail lets you use environment variables to control the appearance of
+your outgoing mail, supplementing the features offered by your MUA. For
+example, qmail-inject will set up Mail-Followup-To for you automatically
+if you tell it which mailing lists you are subscribed to. See
+qmail-inject(8) for a complete list of features.
+
+If you're at (say) sun.ee.movie.edu, qmail lets you type joe@mac for
+joe@mac.ee.movie.edu, and joe@mac+ for joe@mac.movie.edu without the ee.
+sendmail has a different interpretation of hostnames without dots.
+
+
+--- Forwarding and mailing lists
+
+qmail gives you the power to set up your own mailing lists without
+pestering your system administrator.
+
+Under qmail, you are in charge of all addresses of the form
+you-anything. The delivery of you-anything is controlled by
+~you/.qmail-anything, a file in your home directory.
+
+For example, if you want to set up a bug-of-the-month-club mailing list,
+you can put a list of addresses into ~you/.qmail-botmc. Any mail to
+you-botmc will be forwarded to all of those addresses. Mail directly to
+you is controlled by ~you/.qmail. You can even set up a catch-all,
+~you/.qmail-default, to handle unknown you- addresses.
+
+See dot-qmail(5) for the complete story. Beware that the syntax of
+.qmail is different from the syntax of sendmail's .forward file.
+
+If your system administrator has configured qmail to use the dot-forward
+compatibility tool, you can put forwarding addresses (and programs) into
+.forward the same way you did with sendmail.
+
+If your system administrator has installed ezmlm, you can use ezmlm-make
+to instantly set up a professional-quality mailing list, handling
+subscriptions and archives automatically.
+
+If your system administrator has installed fastforward, you can easily
+manage a large database of forwarding addresses.
diff --git a/TARGETS b/TARGETS
index 12054c0..facdad7 100644 (file)
--- a/TARGETS
+++ b/TARGETS
@@ -8,58 +8,13 @@ compile
 fork.h
 qmail-local.o
 qmail.o
-auto-str.o
-make-makelib
-makelib
-substdio.o
-substdi.o
-substdo.o
-subfderr.o
-subfdout.o
-subfdouts.o
-subfdin.o
-subfdins.o
-substdio_copy.o
-substdio.a
-error.o
-error_str.o
-error_temp.o
-error.a
-str_len.o
-str_diff.o
-str_diffn.o
-str_cpy.o
-str_chr.o
-str_rchr.o
-str_start.o
-byte_chr.o
-byte_rchr.o
-byte_diff.o
-byte_copy.o
-byte_cr.o
-byte_zero.o
-str.a
-auto-str
-auto_qmail.c
-auto_qmail.o
-auto-int8.o
-fmt_str.o
-fmt_strn.o
-fmt_uint.o
-fmt_uint0.o
-fmt_ulong.o
-scan_ulong.o
-scan_8long.o
-scan_nbblong.o
-fs.a
-auto-int8
-auto_patrn.c
-auto_patrn.o
 quote.o
 now.o
 gfrom.o
 myctime.o
 slurpclose.o
+make-makelib
+makelib
 case_diffb.o
 case_diffs.o
 case_lowerb.o
@@ -104,8 +59,8 @@ lock.a
 fd_copy.o
 fd_move.o
 fd.a
-wait_pid.o
 haswaitp.h
+wait_pid.o
 wait_nohang.o
 wait.a
 env.o
@@ -124,24 +79,66 @@ stralloc.a
 alloc.o
 alloc_re.o
 alloc.a
+strerr_sys.o
+strerr_die.o
+strerr.a
+substdio.o
+substdi.o
+substdo.o
+subfderr.o
+subfdout.o
+subfdouts.o
+subfdin.o
+subfdins.o
+substdio_copy.o
+substdio.a
+error.o
+error_str.o
+error_temp.o
+error.a
+str_len.o
+str_diff.o
+str_diffn.o
+str_cpy.o
+str_chr.o
+str_rchr.o
+str_start.o
+byte_chr.o
+byte_rchr.o
+byte_diff.o
+byte_copy.o
+byte_cr.o
+byte_zero.o
+str.a
+fmt_str.o
+fmt_strn.o
+fmt_uint.o
+fmt_uint0.o
+fmt_ulong.o
+scan_ulong.o
+scan_8long.o
+fs.a
 datetime.o
 datetime_un.o
 datetime.a
+auto-str.o
+auto-str
+auto_qmail.c
+auto_qmail.o
+auto-int8.o
+auto-int8
+auto_patrn.c
+auto_patrn.o
+socket.lib
 qmail-local
 uint32.h
 qmail-lspawn.o
-auto-uid.o
-auto-uid
-auto-gid.o
-auto-gid
-auto_uids.c
-auto_uids.o
+select.h
+chkspawn.o
 auto-int.o
 auto-int
 auto_spawn.c
 auto_spawn.o
-select.h
-chkspawn.o
 chkspawn
 spawn.o
 chkshsgr.o
@@ -153,6 +150,12 @@ cdb_hash.o
 cdb_unpack.o
 cdb_seek.o
 cdb.a
+auto-uid.o
+auto-uid
+auto-gid.o
+auto-gid
+auto_uids.c
+auto_uids.o
 qmail-lspawn
 qmail-getpw.o
 auto_break.c
@@ -175,7 +178,6 @@ ipme.o
 ndelay.o
 ndelay_off.o
 ndelay.a
-socket.lib
 dns.lib
 qmail-remote
 qmail-rspawn.o
@@ -183,9 +185,9 @@ tcpto_clean.o
 qmail-rspawn
 direntry.h
 qmail-clean.o
+fmtqfn.o
 auto_split.c
 auto_split.o
-fmtqfn.o
 qmail-clean
 qmail-send.o
 qsutil.o
@@ -216,7 +218,6 @@ predate
 datemail
 mailsubj
 qmail-upq
-qmail-config
 qmail-showctl.o
 qmail-showctl
 qmail-newu.o
@@ -233,12 +234,21 @@ qmail-qread
 qmail-qstat
 qmail-tcpto.o
 qmail-tcpto
+qmail-tcpok.o
+qmail-tcpok
 qmail-pop3d.o
+commands.o
+maildir.o
 qmail-pop3d
 qmail-popup.o
 qmail-popup
-qmail-qmtpd.o
+qmail-qmqpc.o
+qmail-qmqpc
+qmail-qmqpd.o
 received.o
+qmail-qmqpd
+qmail-qmtpd.o
+rcpthosts.o
 qmail-qmtpd
 qmail-smtpd.o
 qmail-smtpd
@@ -247,6 +257,10 @@ sendmail
 tcp-env.o
 remoteinfo.o
 tcp-env
+qmail-newmrh.o
+qmail-newmrh
+config
+config-fast
 dnscname.o
 dnsdoe.o
 dnscname
@@ -262,9 +276,6 @@ hostname.o
 hostname
 ipmeprint.o
 ipmeprint
-qlist.o
-qlist
-qlist2
 qreceipt.o
 qreceipt
 qsmhook.o
@@ -277,25 +288,38 @@ preline.o
 preline
 condredirect.o
 condredirect
+bouncesaying.o
+bouncesaying
+except.o
+except
 maildirmake.o
 maildirmake
 maildir2mbox.o
-maildir.o
-strerr_sys.o
-strerr_die.o
-strerr.a
 maildir2mbox
 maildirwatch.o
 maildirwatch
 qail
 elq
 pinq
-qmail-hier.o
-qmail-hier
+idedit.o
+idedit
+install-big.o
 install.o
+install-big
+hier.o
 install
 instcheck.o
 instcheck
+home
+home+df
+proc
+proc+df
+binm1
+binm1+df
+binm2
+binm2+df
+binm3
+binm3+df
 it
 qmail-local.0
 qmail-lspawn.0
@@ -306,40 +330,48 @@ qmail-rspawn.0
 qmail-clean.0
 qmail-send.8
 qmail-send.0
+qmail-start.8
 qmail-start.0
 splogger.0
 qmail-queue.0
 qmail-inject.0
 mailsubj.0
 qmail-showctl.0
+qmail-newu.8
 qmail-newu.0
 qmail-pw2u.8
 qmail-pw2u.0
 qmail-qread.0
 qmail-qstat.0
 qmail-tcpto.0
+qmail-tcpok.0
 qmail-pop3d.0
 qmail-popup.0
+qmail-qmqpc.0
+qmail-qmqpd.0
 qmail-qmtpd.0
 qmail-smtpd.0
 tcp-env.0
-qlist.0
+qmail-newmrh.8
+qmail-newmrh.0
 qreceipt.0
 qbiff.0
 forward.0
 preline.0
 condredirect.0
+bouncesaying.0
+except.0
 maildirmake.0
 maildir2mbox.0
 maildirwatch.0
 qmail.0
-qmail-upgrade.7
-qmail-upgrade.0
 qmail-limits.7
 qmail-limits.0
 qmail-log.0
+qmail-control.5
 qmail-control.0
 qmail-header.0
+qmail-users.5
 qmail-users.0
 dot-qmail.5
 dot-qmail.0
@@ -351,3 +383,5 @@ addresses.0
 envelopes.0
 forgeries.0
 man
+setup
+check
diff --git a/TEST.deliver b/TEST.deliver
new file mode 100644 (file)
index 0000000..4fc4c32
--- /dev/null
@@ -0,0 +1,82 @@
+You can do several tests of qmail delivery without setting up qmail to
+accept messages through SMTP or through /usr/lib/sendmail:
+
+1. After you start qmail, look for a
+           qmail: status: local 0/10 remote 0/20
+   line in syslog. qmail-send always prints either ``cannot start'' or
+   ``status''. (The big number is a splogger timestamp.)
+
+2. Do a ps and look for the qmail daemons. There should be four of
+   them, all idle: qmail-send, running as qmails; qmail-lspawn, running
+   as root; qmail-rspawn, running as qmailr; and qmail-clean, running
+   as qmailq. You will also see splogger, running as qmaill.
+
+3. Local-local test: Send yourself an empty message. (Replace ``me''
+   with your username. Make sure to include the ``to:'' colon.)
+      % echo to: me | /var/qmail/bin/qmail-inject
+   The message will show up immediately in your mailbox, and syslog
+   will show something like this:
+           qmail: new msg 53 
+           qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666
+           qmail: starting delivery 1: msg 53 to local me@domain 
+           qmail: status: local 1/10 remote 0/20
+           qmail: delivery 1: success: did_1+0+0/
+           qmail: status: local 0/10 remote 0/20
+           qmail: end msg 53 
+   (53 is an inode number; 20345 is a process ID; your numbers will
+   probably be different.)
+
+4. Local-error test: Send a message to a nonexistent local address.
+      % echo to: nonexistent | /var/qmail/bin/qmail-inject
+           qmail: new msg 53 
+           qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666
+           qmail: starting delivery 2: msg 53 to local nonexistent@domain
+           qmail: status: local 1/10 remote 0/20
+           qmail: delivery 2: failure: No_such_address.__#5.1.1_/
+           qmail: status: local 0/10 remote 0/20
+           qmail: bounce msg 53 qp 20357
+           qmail: end msg 53 
+           qmail: new msg 54 
+           qmail: info msg 54: bytes 743 from <> qp 20357 uid 666
+           qmail: starting delivery 3: msg 54 to local me@domain
+           qmail: status: local 1/10 remote 0/20
+           qmail: delivery 3: success: did_1+0+0/
+           qmail: status: local 0/10 remote 0/20
+           qmail: end msg 54 
+   You will now have a bounce message in your mailbox.
+
+5. Local-remote test: Send an empty message to your account on another
+   machine.
+      % echo to: me@wherever | /var/qmail/bin/qmail-inject
+           qmail: new msg 53 
+           qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666
+           qmail: starting delivery 4: msg 53 to remote me@wherever
+           qmail: status: local 0/10 remote 1/20
+           qmail: delivery 4: success: 1.2.3.4_accepted_message./...
+           qmail: status: local 0/10 remote 0/20
+           qmail: end msg 53 
+   There will be a pause between ``starting delivery'' and ``success'';
+   SMTP is slow. Check that the message is in your mailbox on the other
+   machine.
+
+6. Local-postmaster test: Send mail to postmaster, any capitalization.
+      % echo to: POSTmaster | /var/qmail/bin/qmail-inject
+   Look for the message in the alias mailbox, normally ~alias/Mailbox.
+
+7. Double-bounce test: Send a message with a completely bad envelope.
+      % /var/qmail/bin/qmail-inject -f nonexistent
+      To: unknownuser
+      Subject: testing
+
+      This is a test. This is only a test.
+      %
+   (Use end-of-file, not dot, to end the message.) Look for the double
+   bounce in the alias mailbox.
+
+8. Group membership test:
+      % cat > ~me/.qmail-groups
+      |groups >> MYGROUPS; exit 0
+      % /var/qmail/bin/qmail-inject me-groups < /dev/null
+      % cat ~me/MYGROUPS
+   MYGROUPS will show your normal gid and nothing else. (Under Solaris,
+   make sure to use /usr/ucb/groups; /usr/bin/groups is broken.)
diff --git a/TEST.receive b/TEST.receive
new file mode 100644 (file)
index 0000000..7644845
--- /dev/null
@@ -0,0 +1,41 @@
+You can do several tests of messages entering the qmail system:
+
+1. SMTP server test: Forge some mail locally via SMTP. Replace ``me''
+   with your username and ``domain'' with your host's name.
+       % telnet 127.0.0.1 25
+       Trying 127.0.0.1...
+       Connected to 127.0.0.1.
+       Escape character is '^]'.
+       220 domain ESMTP
+       helo dude
+       250 domain
+       mail <me@domain>
+       250 ok
+       rcpt <me@domain>
+       250 ok
+       data
+       354 go ahead
+       Subject: testing
+       
+       This is a test.
+       .
+       250 ok 812345679 qp 12345
+       quit
+       221 domain
+       Connection closed by foreign host.
+       %
+   Look for the message in your mailbox. (Note for programmers: Most
+   SMTP servers need more text after MAIL and RCPT. See RFC 821.)
+
+2. Remote-local test: Send yourself some mail from another machine.
+   Look for the message in your mailbox.
+
+3. Remote-error test: Send some mail from another machine to
+   nonexistent@domain. Look for a bounce message in the remote mailbox.
+
+4. UA test: Try sending mail, first to a local account, then to a
+   remote account, with your normal user agent.
+
+5. Remote-postmaster test: Send mail from another machine to
+   PoStMaStEr@domain. Look for the message in the alias mailbox,
+   normally ~alias/Mailbox.
diff --git a/THANKS b/THANKS
index c3d5ba0..b1ad88e 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -2,216 +2,336 @@ Thanks to lots of people for success and failure reports, code, ideas,
 and documentation. See CHANGES for details of specific contributions.
 Sorry if I left anyone out.
 
-SA = Satoshi Adachi
-G1A = Graham Adams
-NA = Norm Aleks
-NAA = Nicholas A. Amato
-G2A = Greg Andrews
-TA = Tetsuo Aoki
-DA = Dave Arcuri
-JJB = J. J. Bailey
-J2B = Jos Backus
-SSB = Stik Bakken
-J1B = John Banghart
-GB = Glenn Barry
-JLB = Julie L. Baumler
-SLB = Steven L. Baur
-ALB = Allan L. Bazinet
-JDHB = Johannes D. H. Beekhuizen
-BDB = Boris D. Beletsky
-HJB = Herbert J. Bernstein
-REB = Ronald E. Bickers
-JPB = Joe Block
-BB = Bruce Bodger
-SB = Stephane Bortzmeyer
-PB = Peter Bowyer
-ACB = Andy C. Brandt
+A2B = Are Bryne
+A2L = Ali Lomonaco
+A2P = Andrea Paolini
+AAF = Adam A. Frey
 AB = Alan Briggs
+ABC = Alan B. Clegg
+AC = Arne Coucheron
+ACB = Andy C. Brandt
+AF = Andreas Faerber
+AG = Armin Gruner
+AGB = Andre Grosse Bley
+AH = Amos Hayes
+AI = Akihiro Iijima
+AJ = Alan Jaffray
+AJK = Antti-Juhani Kaijanaho
 AKB = Allen K. Briggs
-JBB = Jason B. Brown
-JAB = Jeremy A. Bussard
-RJC = Robert J. Carter
-EC = Evan Champion
-JC = Jim Clausing
-HCJ = Helio Coelho Jr.
+AL = Andreas Lamprecht
+ALB = Allan L. Bazinet
+ANR = Adriano Nagelschmidt Rodrigues
+AP = Andrew Pam
+AS = Akos Szalkai
+AV = Alex Vostrikov
+AWB = Andy W. Barclay
+AY = Araki Yasuhiro
+B1F = Bo Fussing
+B2F = Brad Forschinger
+B2H = Buck Huppmann
+B2L = Brent Laminack
+B2W = Bil Wendling
+B3W = Boris Wedl
+BB = Bruce Bodger
 BC = Bob Collie
-SGC = Stephen G. Comings
-MC = Michael Cooley
-DCC = Daniel C. Cotey
-AC = Arne Coucheron
-M2C = Mark Crimmins
-DC = Dan Cross
-MD = Mark Delany
-SVD = Stef Van Dessel
-RD = Rahul Dhesi
-MJD = Mark-Jason Dominus
-JD = Joe Doupnik
-FE = Frank Ederveen
-DE = Daniel Egnor
-MWE = Mark W. Eichin
-MEE = Mads E. Eilertsen
-KE = Kenny Elliott
-TEE = Thomas E. Erskine
-ME = Marc Ewing
-JF = Janos Farkas
-DF = Dale Farnsworth
-YF = Yaroslav Faybishenko
-CF = C. Ferree
-JBF = John B. Fleming
-C2F = Chuck Foster
-RF = Rainer Fraedrich
-MF = Massimo Fusaro
-CG = Chris Garrigues
+BCK = Benjamin C. Kite
+BCM = Bill C. Miller
+BDB = Boris D. Beletsky
+BDM = Byron D. Miller
+BEO = Bruce E. O'Neel
+BET = Bennett E. Todd
 BG = Bert Gijsbers
-M2G = Michael R. Gile
-EG = Eivind Gjelseth
-HG = Howard Goldstein
-TG = Tim Goodwin
-HDG = Hans de Graaff
-MG = Michael Graff
-PJG = Paul Graham
-MRG = Matthew R. Green
-SG = Steven Grimm
-AG = Armin Gruner
-CSH = Clayton S. Haapala
-JLH = Jason L. Haar
-MLH = May Liss Haarstad
-CH = Chael Hall
-JPH = Justin P. Hannah
-RJH = Randy Harmon
-PH = Paul Harrington
-DEH = Daniel E. Harris
-RFH = Robert F. Harrison
-D1H = Dieter Heidner
-GH = Gene Hightower
-MH = Markus Hofmann
-D2H = Dan Hollis
-NH = Nick Holloway
-TH = Ton Hospel
 BH = Brad Howes
-TJH = Timothy J. Hunt
-B2H = Buck Huppmann
-MDI = Miguel de Icaza
 BJ = Brian Jackson
-AJ = Alan Jaffray
+BJM = Barry J. Miller
+BL = Brian Litzinger
+BMF = Brian M. Fisk
+BN = Bill Nugent
+BP = Bruce Perens
+BR = Brian J. Reichert
+BS = Bjoern Stabell
+BT = Brad Templeton
+BTW = Brian T. Wightman
+BW = Bill Weinman
+BZ = Blaz Zupan
+C2F = Chuck Foster
+C2H = Christoph Heidermanns
+C2S = Craig Shrimpton
 CEJ = Colin Eric Johnson
-K2J = Kevin Johnson
-K1J = Kyle Jones
-SJ = Sudish Joseph
-W2K = Wolfram Kahl
-JJMK = Jonathan J. M. Katz
+CF = C. Ferree
+CG = Chris Garrigues
+CH = Chael Hall
+CHR = Craig H. Rowland
 CK = Christoph Kaesling
-PK = Petri Kaukasoina
+CL = Carsten Leonhardt
+CLS = Christopher L. Seawood
+CM = Charles Mattair
+CMP = Chase M. Phillips
+CR = Christian Riede
+CS = Cloyce Spradling
+CSH = Clayton S. Haapala
+D1H = Dieter Heidner
+D2H = Dan Hollis
 D2K = Dax Kelson
-TK = Terry Kennedy
+D2S = Dan Senie
+D3S = Don Samek
+DA = Dave Arcuri
+DAR = Daniel A. Reish
+DB = David Buscher
 DBK = Douglas B. Kerry
-WK = Werner Koch
+DC = Dan Cross
+DCC = Daniel C. Cotey
+DE = Daniel Egnor
+DEH = Daniel E. Harris
+DF = Dale Farnsworth
+DG = David Guntner
 DK = Dave Kopper
-J1K = Jost Krieger
-J2K = Johannes Kroeger
-EK = Eric Krohn
-B2L = Brent Laminack
-AL = Andreas Lamprecht
-L2L = Louis Larry
-M3L = Michael Lazarou
-CL = Carsten Leonhardt
-JRL = John R. Levine
+DL = Daniel Lawrence
+DM = David Mazieres
 DML = David M. Lew
-LL = lilo
-FPL = Frederik P. Lindberg
-JL = Jim Littlefield
-BL = Brian Litzinger
-RL = Robert Luce
-ML = Martin Lucina
-M2L = M. Lyons
-TM = Toshinori Maeno
+DP = Dave Platt
+DS = Dave Sill
+DST = Daniel S. Thibadeau
+DWS = David Wayne Summers
+EC = Evan Champion
+ECG = Eric C. Garrison
+EG = Eivind Gjelseth
+EK = Eric Krohn
+EP = Emanuele Pucciarelli
+ERH = Eric R. Hankins
+ES = Eric Smith
 ESM = Edward S. Marshall
-J2M = Joel Maslak
-TLM = Timothy L. Mayo
-DM = David Mazieres
-RM = Rich McClellan
-SM = Shawn McHorse
-JM = Jim Meehan
-HWM = Henry W. Miller
-RDM = Raul Miller
-MMM = Momchil M. Momchev
-JGM = John G. Myers
+ET = Eivind Tagseth
+ETT = Emmanuel T. Tardieu
+F2T = Frank Thieme
+FE = Frank Ederveen
 FN = Faried Nawaz
-RN = Russell Nelson
-TN = Thomas Neumann
-UO = Uwe Ohse
-PCO = Peter C. Olsen
+FPL = Frederik P. Lindberg
+FT = Frank Tegtmeyer
+FW = Frank Wagner
+G1A = Graham Adams
+G2A = Greg Andrews
+GAW = Greg A. Woods
+GB = Glenn Barry
+GH = Gene Hightower
+GL = Giles Lean
+GLM = Grant L. Miller
+H2S = Harley Silver
+HCJ = Helio Coelho Jr.
+HDG = Hans de Graaff
+HG = Howard Goldstein
 HHO = Harald Hanche-Olsen
-BEO = Bruce E. O'Neel
+HJB = Herbert J. Bernstein
+HM = Hirokazu Morikawa
+HS = Harlan Stenn
+HT = Henry Timmerman
+HW = Hal Wine
+HWM = Henry W. Miller
+IH = Ingmar Hupp
+IK = Ivan Kohler
+IKW = Ian Keith Wynne
+IS = Icarus Sparry
+IW = Ian Westcott
+J1B = John Banghart
+J1K = Jost Krieger
+J2B = Jos Backus
+J2K = Johannes Kroeger
+J2M = Joel Maslak
+J2P = John Parker
+J2W = Jim Whitby
+JAB = Jeremy A. Bussard
+JAK = Johan A. Kullstam
+JB = Joshua Buysse
+JBB = Jason B. Brown
+JBF = John B. Fleming
+JC = Jim Clausing
+JCD = Jeffrey C. Dege
+JD = Joe Doupnik
+JDHB = Johannes D. H. Beekhuizen
+JDJ = Joshua D. Juran
+JF = Janos Farkas
+JFK = James F. Kane III
+JGM = John G. Myers
+JJB = J. J. Bailey
+JJMK = Jonathan J. M. Katz
+JJR = Jaron J. Rubenstein
+JK = Jari Kirma
+JL = Jim Littlefield
+JLB = Julie L. Baumler
+JLH = Jason L. Haar
+JLW = Jason L. Wright
+JM = Jim Meehan
+JMS = Jason M. Stokes
+JMT = John M. Twilley
 JP = John Palkovic
-AP = Andrew Pam
-SP = Stephen Parker
-TVP = Tom van Peer
-BP = Bruce Perens
-CMP = Chase M. Phillips
-DP = Dave Platt
-EP = Emanuele Pucciarelli
+JPB = Joe Block
+JPH = Justin P. Hannah
 JPR = Jean-Pierre Radley
-S1R = Satish Ramachandran
-MR = Mosfeq Rashid
-TRR = Tracy R. Reed
-BR = Brian Reichert
-S2R = Sean Reifschneider
-DAR = Daniel A. Reish
-CR = Christian Riede
+JRL = John R. Levine
+JRM = Jason R. Mastaler
+JRY = Jamie R. Yukes
+JS = Jesper Skriver
+JTB = Jonathan T. Bowie
+JW = John Whittaker
+JWB = James W. Birdsall
+K1J = Kyle Jones
+K2J = Kevin Johnson
+KA = Klaus Aigte
+KB = Keith Burdis
+KE = Kenny Elliott
+KJJ = Kevin J. Johnson
+KJS = Kevin J. Sawyer
+KMD = Kevin M. Dulzo
+KO = Keith Owens
 KR = Kenji Rikitake
+KT = Karsten Thygesen
+KUT = Kai Uwe Tempel
+KY = Kentaro Yoshitomi
+L2L = Louis Larry
+L3L = Luis Lopes
+LB = Laurentiu Badea
+LL = lilo
+LW = Lionel Widdifield
+M2C = Mark Crimmins
+M2G = Michael R. Gile
+M2H = Martin Hager
+M2L = M. Lyons
+M2R = Mark Riekenberg
+M2S = Mikael Suokas
+M3H = Michael Holzt
+M3L = Michael Lazarou
+M3S = Morten Skjelland
+M4S = Michael Shields
+MB = Martin Budsj?
+MBS = Michael B. Scher
+MC = Michael Cooley
+MD = Mark Delany
+MDI = Miguel de Icaza
+ME = Marc Ewing
+MEE = Mads E. Eilertsen
+MF = Massimo Fusaro
+MG = Michael Graff
+MGM = Mitchell G. Morris
+MH = Markus Hofmann
+MJD = Mark-Jason Dominus
+MJG = Manuel J. Galan
+ML = Martin Lucina
+MLH = May Liss Haarstad
+MM = Martin Mersberger
+MMM = Momchil M. Momchev
+MMM2 = Marc M. Martinez
+MP = Matt Paduano
+MR = Mosfeq Rashid
+MRG = Matthew R. Green
+MS = Mark Spears
+MSD = Mandell S. Degerness
+MSS = Matthew S. Soffen
+MT = Mark Thompson
+MW = Mate Wierdl
+MWE = Mark W. Eichin
+NA = Norm Aleks
+NAA = Nicholas A. Amato
+NH = Nick Holloway
+NND = N. Dudorov
+NR = Norbert Roeding
+NW = Nicholas Waples
+OK = Oezguer Kesim
 OR = Ollivier Robert
-ANR = Adriano Nagelschmidt Rodrigues
-JJR = Jaron J. Rubenstein
-RS = Robert Sanders
-KJS = Kevin J. Sawyer
-MBS = Mike Scher
-SAS = Steven A. Schrader
-CLS = Christopher L. Seawood
 OS = Oliver Seiler
-D2S = Dan Senie
-SS = Simon Shapiro
-RGS = Richard G. Sharman
-DS = Dave Sill
-H2S = Harley Silver
-M3S = Morten Skjelland
-JS = Jesper Skriver
-ES = Eric Smith
-IS = Icarus Sparry
-CS = Cloyce Spradling
-BS = Bjoern Stabell
-HS = Harlan Stenn
-JMS = Jason M. Stokes
-DWS = David Wayne Summers
-M2S = Mikael Suokas
+PB = Peter Bowyer
+PCO = Peter C. Olsen
+PGF = Paul Fox
+PGR = Phil G. Rorex
+PH = Paul Harrington
+PJG = Paul Graham
+PJH = Peter J. Hunter
+PK = Petri Kaukasoina
+PMH = Peter M. Haworth
+PO = Paul Overell
 PS = Paul Svensson
-ET = Eivind Tagseth
 PT = Paul Taylor
+PTW = P. T. Withington
+PW = Peter Wilkinson
+R2N = Rivo Nurges
+RA = Russ Allbery
+RAB = Randolph Allen Bentson
+RAM = Robin A. McCollum
+RB = Robert Bridgham
+RC = Ryan Crum
+RD = Rahul Dhesi
+RDM = Raul D. Miller
+REB = Ronald E. Bickers
+RF = Rainer Fraedrich
+RFH = Robert F. Harrison
+RGS = Richard G. Sharman
+RJC = Robert J. Carter
+RJH = Randy Harmon
+RJO = Richard J. Ohnemus
+RK = Riho Kurg
+RL = Robert Luce
+RM = Rich McClellan
+RN = Russell Nelson
+RO = Roberto Oppedisano
+RPS = Russell P. Sutherland
+RS = Robert Sanders
+RSK = Robert S. Krzaczek
+S1R = Satish Ramachandran
+S2P = Stefan Puscasu
+S2R = Sean Reifschneider
+S2S = Scott Schwartz
 S2T = Steve Taylor
-BT = Brad Templeton
-DST = Daniel S. Thibadeau
-MT = Mark Thompson
 S3T = Steffen Thorsen
-KT = Karsten Thygesen
-BET = Bennett E. Todd
-JMT = John M. Twilley
+SA = Satoshi Adachi
+SAE = Stefaan A. Eeckels
+SAS = Steven A. Schrader
+SB = Stephane Bortzmeyer
+SC = Stefan Cars
+SCW = Steven C. Work
+SG = Steven Grimm
+SGC = Stephen G. Comings
+SJ = Sudish Joseph
+SJB = SJ Burns
+SJW = Stephen J. White
+SLB = Steven L. Baur
+SM = Shawn McHorse
+SP = Stephen Parker
+SPM = Salvatore P. Miccicke
+SS = Simon Shapiro
+SSB = Stik Bakken
 ST = Steve Tylock
+SV = Sven Velt
+SVD = Stef Van Dessel
+T2K = Tomoya Konishi
+T2M = Toni Mueller
+T2U = Todd Underwood
+TA = Tetsuo Aoki
+TB = Tobias Brox
+TD = Tom Demmer
+TEE = Thomas E. Erskine
+TG = Tim Goodwin
+TH = Ton Hospel
+TJH = Timothy J. Hunt
+TK = Terry Kennedy
+TL = Timothy Lorenc
+TLF = Timo L. Felbinger
+TLM = Timothy L. Mayo
+TM = Toshinori Maeno
+TN = Thomas Neumann
+TRR = Tracy R. Reed
+TT = Takaki Taniguchi
 TU = Tetsu Ushijima
-VV = Vince Vielhaber
 TV = Tommi Virtanen
-FW = Frank Wagner
-BW = Bill Weinman
-IW = Ian Westcott
-SJW = Stephen J. White
-JW = John Whittaker
-LW = Lionel Widdifield
-MW = Mate Wierdl
-BTW = Brian T. Wightman
-PW = Peter Wilkinson
-HW = Hal Wine
-GAW = Greg A. Woods
-SCW = Steven C. Work
-JLW = Jason L. Wright
+TVP = Tom van Peer
+UO = Uwe Ohse
+VBM = Vladimir B. Machulsky
+VR = Vincenzo Romano
+VU = Viriya Upatising
+VV = Vince Vielhaber
+W2K = Wolfram Kahl
+WEB = William E. Baxter
+WK = Werner Koch
+WS = Wilbur Sims
 WW = Wei Wu
-IKW = Ian Keith Wynne
-BZ = Blaz Zupan
+YC = Yuji Chikahiro
+YF = Yaroslav Faybishenko
+ZU = Zin Uda
index 6587084..d6910da 100644 (file)
--- a/THOUGHTS
+++ b/THOUGHTS
@@ -45,9 +45,8 @@ smaller resolver library into qmail. (Bonus: I'd avoid system-specific
 problems with old resolvers.) The problem is that I'd then be writing a
 fundamentally insecure library. I'd no longer be able to blame the BIND
 authors and vendors for the fact that attackers can easily use DNS to
-steal mail. Possible solution: replace dns.c with something that passes
-requests (reliably!) to a local daemon; call the original resolver
-library from that daemon.
+steal mail. Solution: insist that the resolver run on the same host; the
+kernel can guarantee the security of low-numbered 127.0.0.1 UDP ports.
 
 NFS is the primary enemy of security partitioning under UNIX. Here's the
 story. Sun knew from the start that NFS was completely insecure. It
@@ -72,10 +71,10 @@ is, as far as I can tell, always wrong.
 
 2. Injecting mail locally (qmail-inject, sendmail-clone)
 
-RFC 822 section 3.4.9 prohibits certain visual effects in headers.
-qmail-inject doesn't waste the time to enforce this absurd restriction.
-If you will suffer from someone sending you ``flash mail,'' go find a
-better mail reader.
+RFC 822 section 3.4.9 prohibits certain visual effects in headers, and
+the 822bis draft prohibits even more. qmail-inject could enforce these
+absurd restrictions, but why waste the time? If you will suffer from
+someone sending you ``flash mail,'' go find a better mail reader.
 
 qmail-inject's ``Cc: recipient list not shown: ;'' successfully stops
 sendmail from adding Apparently-To. Unfortunately, old versions of
@@ -101,44 +100,47 @@ It is possible to extract non-unique Message-IDs out of qmail-inject.
 Here's how: stop qmail-inject before it gets to the third line of
 main(), then wait until the pids wrap around, then restart qmail-inject
 and blast the message through, then start another qmail-inject with the
-same pid in the same second. I'm not sure how to fix this. (Of course,
-the user could just type in his own non-unique Message-IDs.)
+same pid in the same second. I'm not sure how to fix this without
+system-supplied sequence numbers. (Of course, the user could just type
+in his own non-unique Message-IDs.)
 
 The bat book says: ``Rules that hide hosts in a domain should be applied
 only to sender addresses.'' Recipient masquerading works fine with
 qmail. None of sendmail's pitfalls apply, basically because qmail has a
 straight paper path.
 
-I expect to receive some pressure to make up for the failings of MUA
-writers who don't understand the concept of reliability. (``Like, duh,
-you mean I was supposed to check the sendmail exit code?'')
+I predicted that I would receive some pressure to make up for the
+failings of MUA writers who don't understand the concept of reliability.
+(``Like, duh, you mean I'm supposed to check the sendmail exit code?'')
+I was right.
 
 
 3. Receiving mail from the network (tcp-env, qmail-smtpd)
 
-RFC 1123 requires VRFY support, but says that it's okay if an
-implementation can be configured to not allow VRFY. qmail-smtpd doesn't
-allow VRFY. If you desperately want your SMTP server (i.e., inetd) to
-provide useful information for VRFY, just compile and install sendmail.
-Were the RFC 1123 writers aware of the as-if principle of interface
-specification? ... They say that VRFY and EXPN are important for
-tracking down cross-host mailing list loops. Catch up to the 1990s,
-guys: with Delivered-To, mailing list loops do absolutely no damage,
-_and_ one of the list administrators gets a bounce that shows exactly
-how the loop occurred. Solve the problem, not the symptom. ... There's a
-vastly superior alternative to EXPN. Hint: finger postmaster@ai.mit.edu.
+qmail-smtpd doesn't allow privacy-invading commands like VRFY and EXPN.
+If you really want to publish such information, use a mechanism that
+legitimate users actually know about, such as fingerd or httpd.
+
+RFC 1123 says that VRFY and EXPN are important to track down cross-host
+mailing list loops. With Delivered-To, mailing list loops do no damage,
+_and_ one of the list administrators gets a bounce message that shows
+exactly how the loop occurred. Solve the problem, not the symptom.
 
 Should dns.c make special allowances for 127.0.0.1/localhost?
 
 badmailfrom (like 8BITMIME) is a waste of code space.
 
+In theory a MAIL or RCPT argument can contain unquoted LFs. In practice
+there are a huge number of clients that terminate commands with just LF,
+even if they use CR properly inside DATA.
+
 
 4. Adding messages to the queue (qmail-queue)
 
 Should qmail-queue try to make sure enough disk space is free in
 advance? When qmail-queue is invoked by qmail-local or (with ESMTP)
-qmail-smtpd or qmail-qmtpd, it could be told a size in advance. I wish
-UNIX had an atomic allocate-disk-space routine... 
+qmail-smtpd or qmail-qmtpd or qmail-qmqpd, it could be told a size in
+advance. I wish UNIX had an atomic allocate-disk-space routine... 
 
 The qmail.h interface (reflecting the qmail-queue interface, which in
 turn reflects the current queue file structure) is constitutionally
@@ -152,11 +154,7 @@ Should qmail-queue not bother queueing a message with no recipients?
 
 The queue directory must be local. Mounting it over NFS is extremely
 dangerous---not that this stops people from running sendmail that way!
-Perhaps it is worth putting together a diskless-host qmail package with
-just qmail-inject and an SMTP client in place of qmail-queue. Sending
-mail to the server via SMTP is of course vastly better than trying to do
-anything over NFS. If the NFS server is up but the mail server is down,
-users will just have to wait.
+Diskless hosts should use mini-qmail instead.
 
 Queue reliability demands that single-byte writes be atomic. This is
 true for a fixed-block filesystem such as UFS, and for a logging
@@ -190,11 +188,8 @@ than one deliverable message at any given moment.
 Exception: Even with all the concurrency tricks, qmail-send can end up
 spending a few minutes on a mailing list with thousands of remote
 entries. A user might send a new message to a remote address in the
-meantime. Perhaps qmail-send should limit its time per message to,
-say, thirty recipients. This will require some way to mark recipients
-who were already done on this pass. Possible approach: Maintain two todo
-lists (for both L and R). Always work on the earlier todo list. Move
-deferrals to the other todo list.
+meantime. The simplest way to handle this would be to put big messages
+on a separate channel.
 
 qmail-send will never start a pass for a job that it already has. This
 means that, if one delivery takes longer than the retry interval, the
@@ -207,40 +202,26 @@ Some things that qmail-send does synchronously: queueing a bounce
 message; doing a cleanup via qmail-clean; classifying and rewriting all
 the addresses in a new message. As usual, making these asynchronous
 would require some housekeeping, but could speed things up a bit.
-(Making bounces asynchronous, without POSIX waitpid(), means that
-wait_pid() has to keep a buffer of previous wait()s. Ugh.)
-
-fsync() is a bottleneck. To make this asynchronous would require gobs of
-dedicated output processes whose only purpose in life is to watch data
-get written to the disk. Inconceivable! (``You keep using that word. I
-do not think that word means what you think it means.'')
-
-On the other hand, I could survive without fsync()ing the local and
-remote and info files as long as I don't unlink todo. This would require
-redefining the queue states. I need to see how much speed can be gained.
-
-Currently qmail-send sends at most one bounce message for each incoming
-message. This means that the sender doesn't get flooded with copies of
-his own message. On the other hand, a single slow address can hold up
-bounces for a bunch of fast addresses. It would be easy to call
-injectbounce() more often. What is the best strategy? This feels like
-the TCP-buffering issue... don't want to pepper the other guy with
-little packets, but do want to get the data across.
-
-qmail-stop implementation: setuid to UID_SEND; kill -TERM -1. Given how
-simple this is, I'm not inclined to set up some tricky locking solution
-where qmail-send records its pid etc. But I just know that, if I provide
-this qmail-stop program, someone will screw himself by making another
-uid the same as UID_SEND, or making UID_SEND be root, or whatever.
-Aargh. Maybe use another named pipe... New solution: Run qmail-start
-under an external service controller---it runs in the foreground now.
-
-Bounce messages could include more statistical information in the first
-paragraph: when I received the message, how many recipients I was
-supposed to handle, how many I successfully dealt with, how many I
-already told you about, how many are still in the queue. Have to
-emphasize that the number of recipients _here_ is perhaps less than the
-number of recipients on the original message.
+(I'm willing to assume POSIX waitpid() for asynchronous bounces; putting
+an unbounded buffer into wait_pid() for the sake of NeXTSTEP 3 is not
+worthwhile.)
+
+Disk I/O is a bottleneck; UFS is reliable but it isn't fast. A good
+logging filesystem offers much better performance, but logging
+filesystems aren't widely available. Solution: Keep a journal, separate
+from the queue, adequate to rebuild the queue (with at worst some
+duplicate deliveries). Compress the journal. This would dramatically
+reduce total disk I/O.
+
+Bounce aggregation is a dubious feature. Bounce records aren't
+crashproof; there can be a huge delay between a failure and a bounce;
+the resulting bounce format is unnecessarily complicated. I'm tempted to
+scrap the bounce directory and send one bounce for each failing
+recipient, with appropriate modifications in the accompanying text.
+
+qmail-stop implementation: setuid to UID_SEND; kill -TERM -1. Or run
+qmail-start under an external service controller, such as supervise;
+that's why it runs in the foreground.
 
 The readdir() interface hides I/O errors. Lower-level interfaces would
 lead me into a thicket of portability problems. I'm really not sure what
@@ -270,22 +251,17 @@ messages to multiple recipients at a single host? For typical hosts,
 multiple RCPTs per SMTP aren't an ``efficiency feature''; they're a
 _slowness_ feature. Separate SMTP transactions have much lower latency.
 
-The multiple-RCPT bandwidth gain _might_ be noticeable for a machine
-that sends most messages to a smarthost. It would be easy to have
-qmail-rspawn supply qmail-remote with all the addresses at once, as long
-as qmail-send says when it's about to block... Putting recipients into
-the right order is clearly the UA's job. One multiple-RCPT pitfall is
-that a remote host might not be able to deal with (say) 10 recipients,
-even though RFC 821 says everyone has to be able to handle 100;
-qmail-rspawn would have to notice this and back off. (Not that other
-mailers do. Sometimes I'm amazed Internet mail works at all.)
+I've heard three complaints about bandwidth use from masochists sending
+messages through a modem through a smarthost to thousands of users---
+without sublists! They can get much better performance with QMQP.
 
 In the opposite direction: It's tempting to remove the @host part of the
 qmail-remote recip argument. Or at least avoid double-dns_cname.
 
 There are lots of reasons that qmail-rspawn should take a more active
 role in qmail-remote's activities. It should call separate programs to
-do (1) MX lookups, (2) SMTP connections, (3) QMTP connections.
+do (1) MX lookups, (2) SMTP connections, (3) QMTP connections. (But this
+wouldn't be so important if the DNS library didn't burn so much memory.)
 
 I bounce ambiguous MXs. (An ``ambiguous MX'' is a best-preference MX
 record sending me mail for a host that I don't recognize as local.)
@@ -310,6 +286,15 @@ time across any number of MXs; this idea is due to Mark Delany.
 RFC 821 doesn't say what it means by ``text.'' qmail-remote assumes that
 the server's reply text doesn't contain bare LFs.
 
+RFC 821 and RFC 1123 prohibit host names in MAIL FROM and RCPT TO from
+being aliases. qmail-remote, like sendmail, rewrites aliases in RCPT;
+people who don't list aliases in control/locals or sendmail's Cw are
+implicitly relying on this conversion. It is course quite silly for an
+internal DNS detail to have such an effect on mail delivery, but that's
+how the Internet works. On the other hand, the compatibility arguments
+do not apply to MAIL FROM. qmail-remote no longer bothers with CNAME
+lookups for the envelope sender host.
+
 
 7. Delivering mail locally (qmail-lspawn, qmail-local)
 
@@ -347,7 +332,7 @@ Configurable user database: Yup.
 
 BIND support: Yup.
 
-Keyed files: Yes, in qmsmac.
+Keyed files: Yes, in fastforward.
 
 931/1413/Ident/TAP: Yup.
 
@@ -358,7 +343,9 @@ List-owner handling: Yup.
 
 Dynamic header allocation: Yup.
 
-Minimum number of disk blocks: Yes, via tunefs -m.
+Minimum number of disk blocks: Yes, via tunefs -m. (Or quotas; the right
+setup has qmailq with a small quota, qmails with a larger quota, so that
+qmail-send always has room to work.)
 
 Checkpointing: Yes, but not configurable---qmail always checkpoints.
 
@@ -420,12 +407,6 @@ I should clean up the bput/put choices.
 Some of the stralloc_0()s indicate that certain lower-level routines
 should grok stralloc.
 
-RN suggests having qlist smash the case of the incoming host name.
-
-K1J suggests that mailing list subscription managers should have
-a three-way handshake, to prevent person A from subscribing person B to
-a mailing list. qlist doesn't do this, but ezmlm does.
-
 qmail assumes that all times are positive; that pid_t, time_t and ino_t
 fit into unsigned long; that gid_t fits into int; that the character set
 is ASCII; and that all pointers are interchangeable. Do I care?
diff --git a/TODO b/TODO
index 6101add..5841c0a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,9 +1,23 @@
-do some serious coverage testing, preferably under Purify, without alloc slop
-replace INTERNALS and THOUGHTS with a real paper describing qmail
-reorganize qmail-inject to do most rw on characters, not tokens
-allow concurrency over 255
-handle IPv6
+consider stripping vdoms for VERPs; tnx PJH
+consider ~ in qmail-local for doing defaultdelivery (not recursively)
+consider POP bulletins
 turn qmail-upq into a more serious queue-moving utility
+consider fast-greeting option in qmail-smtpd
+build a returnmail package
+
 expand strerr coverage
+redo control interface
+allow concurrency over 255
+allow more channels at compile time
+test for linux fifo close bug at compile time
+
+eliminate qsmhook
+finish OTBS conversion
+use mess822 in qmail-inject
+use mess822 in qreceipt
+use mess822 in qbiff
+use mess822 in maildirwatch
+eliminate token822, headerbody, hfield
+replace INTERNALS and THOUGHTS with a real paper describing qmail
+handle IPv6
 rewrite everything from scratch
-maybe allow root to clear tcpto on the fly
diff --git a/UPGRADE b/UPGRADE
index c6200ca..d648813 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -3,143 +3,64 @@ information generally), the qmail system comes with NO WARRANTY. It's
 much more secure and reliable than sendmail, but that's not saying much.
 
 
-Here's how to upgrade from qmail 1.00 to qmail 1.01. This procedure will
-overwrite the old qmail binaries. Furthermore, it may begin delivering
-messages from the queue before you have had a chance to test it.
+Here's how to upgrade to qmail 1.03. This procedure will overwrite the
+old qmail binaries. Furthermore, it may begin delivering messages from
+the queue before you have had a chance to test it.
 
 
-WARNING: The qmail-start command line has changed.
+WARNING for upgrades from 1.00 or 1.01: qlist has been split into a
+separate package. You can obtain it from http://pobox.com/~djb/qlist.html
+if you have any users who need it.
+
+WARNING for upgrades from 1.01: recipientmap is gone. The virtualdomains
+mechanism has been expanded to support virtual users.
 
 
 Before starting, compare conf* to your old conf*, and make any necessary
-changes. Do not copy your old conf*; the baseline has changed.
+changes. You can copy conf* from 1.02.
 
 
 How to install:
 
- 1. Compile the programs:
-       # make
- 2. Create the formatted man pages, *.0:
-       # make man
- 3. Inform your users that mail will not be accepted for a few minutes.
4. Disable deliveries by killing your old qmail-send. Wait for it to
+ 1. Compile the programs and create the formatted man pages:
+       # make it man
+
+ 2. Inform your users that mail will not be accepted for a few minutes.
+
3. Disable deliveries by killing your old qmail-send. Wait for it to
     print ``exiting'' in the log.
- 5. Disable SMTP service by commenting out the smtp line in inetd.conf;
+
+ 4. Disable SMTP service by commenting out the smtp line in inetd.conf;
     kill -HUP your inetd. (If you are using tcpserver, simply kill -STOP
-    your tcpserver.) Wait for current qmail-smtpd processes to die. (If
-    you are running a QMTP server, disable that too.)
- 6. Install the new binaries and man pages:
-       # rm /var/qmail/bin/* /var/qmail/man/*/*
-       # make setup
- 7. Run instcheck to make sure it doesn't print any warnings:
-       # make check
- 8. Reenable deliveries:
-       # env - PATH="/var/qmail/bin:$PATH" \
-       qmail-start ./Mailbox splogger qmail &
-    Make sure to include the ./ in ./Mailbox.
- 9. Insert ./Mailbox into the qmail-start line in your boot scripts.
-10. Reenable SMTP service by restoring the smtp line in inetd.conf; kill
+    your tcpserver. If you are running a QMTP server, disable that too.)
+    Wait for current qmail-smtpd processes to die.
+
+ 5. Install the new binaries and man pages:
+       # make setup check
+
+ 6. If your boot scripts are using qmail-start instead of /var/qmail/rc:
+    Copy /var/qmail/boot/home to /var/qmail/rc. (Use home+df instead if
+    you have installed dot-forward; use proc or proc+df if you are using
+    procmail by default for local deliveries.) Compare /var/qmail/rc to
+    your qmail-start boot line, and edit /var/qmail/rc if necessary.
+    Replace your qmail-start boot line with
+            csh -cf '/var/qmail/rc &'
+
+ 7. Reenable deliveries:
+       # csh -cf '/var/qmail/rc &'
+
+ 8. Read TEST.deliver.
+
+ 9. Reenable SMTP service by restoring the smtp line in inetd.conf; kill
     -HUP your inetd. (If you are using tcpserver, simply kill -CONT your
     tcpserver. If you are running a QMTP server, reenable that too.)
 
-
-How to test (steps 11-17 can be done before step 10):
-
-11. Look for a
-            qmail: running
-    line in syslog. (The big number is a splogger timestamp.)
-12. Local-local test: Send yourself an empty message. (Replace ``me''
-    with your username. Make sure to include the ``to:'' colon.)
-       % echo to: me | /var/qmail/bin/qmail-inject
-    The message will show up immediately in ~/Mailbox, and syslog will
-    show something like this:
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20345 uid 666
-            qmail: starting delivery 1: msg 53 to local me@domain 
-            qmail: delivery 1: success: did_1+0+0/
-            qmail: end msg 53 
-    (53 is an inode number; 20345 is a process ID; your numbers will
-    probably be different.)
-13. Local-error test: Send a message to a nonexistent local address.
-       % echo to: nonexistent | /var/qmail/bin/qmail-inject
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20351 uid 666
-            qmail: starting delivery 2: msg 53 to local nonexistent@domain
-            qmail: delivery 2: failure: No_such_address.__#5.1.1_/
-           qmail: bounce msg 53 qp 20357
-            qmail: end msg 53 
-            qmail: new msg 54 
-            qmail: info msg 54: bytes 743 from <> qp 20357 uid 666
-            qmail: starting delivery 3: msg 54 to local me@domain
-            qmail: delivery 3: success: did_1+0+0/
-            qmail: end msg 54 
-    You will now have a bounce message in ~/Mailbox.
-14. Local-remote test: Send an empty message to your account on another
-    machine.
-       % echo to: me@wherever | /var/qmail/bin/qmail-inject
-            qmail: new msg 53 
-            qmail: info msg 53: bytes 246 from <me@domain> qp 20372 uid 666
-            qmail: starting delivery 4: msg 53 to remote me@wherever
-            qmail: delivery 4: success: 1.2.3.4_accepted_message./...
-            qmail: end msg 53 
-    There will be a pause between ``starting delivery'' and ``success'';
-    SMTP is slow. Check that the message is in your mailbox on the other
-    machine.
-15. Local-postmaster test: Send mail to postmaster, any capitalization.
-       % echo to: POSTmaster | /var/qmail/bin/qmail-inject
-    Look for the message in ~alias/Mailbox.
-16. Double-bounce test: Send a message with a completely bad envelope.
-       % /var/qmail/bin/qmail-inject -f nonexistent
-       To: unknownuser
-       Subject: testing
-
-       This is a test. This is only a test.
-       %
-    (Use end-of-file, not dot, to end the message.) Look for the double
-    bounce in ~alias/Mailbox.
-17. Group membership test:
-       % cat > ~me/.qmail-groups
-       |groups >> MYGROUPS; exit 0
-       % /var/qmail/bin/qmail-inject me-groups < /dev/null
-       % cat ~me/MYGROUPS
-    MYGROUPS will show your normal gid and nothing else. (Under Solaris,
-    make sure to use /usr/ucb/groups; /usr/bin/groups is broken.)
-18. SMTP server test: Forge some mail locally via SMTP.
-       % telnet 127.0.0.1 25
-       Trying 127.0.0.1...
-       Connected to 127.0.0.1.
-       Escape character is '^]'.
-       220 domain ESMTP
-       helo dude
-       250-domain
-       250-PIPELINING
-       250 8BITMIME
-       mail <me@domain>
-       250 ok
-       rcpt <me@domain>
-       250 ok
-       data
-       354 go ahead
-       Subject: testing
-       
-       This is a test.
-       .
-       250 ok 812345679 qp 12345
-       quit
-       221 domain
-       Connection closed by foreign host.
-       %
-    Look for the message in your mailbox.
-19. Remote-local test: Send yourself some mail from another machine.
-20. Remote-error test: I think you can figure this one out.
-21. UA test: Try sending mail, first to a local account, then to a
-    remote account, with your normal user agent.
-22. Remote-postmaster test: Send mail from another machine to
-    PoStMaStEr@domain. Look for the message in ~alias/Mailbox.
+10. Read TEST.receive.
 
 
 That's it! To report success:
-       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \
-         | mail djb-qst@koobera.math.uic.edu
-Replace First M. Last with your name. If you have questions about qmail,
-contact qmail@pobox.com.
+       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to
+Replace First M. Last with your name.
+
+If you have questions about qmail, join the qmail mailing list; see
+http://pobox.com/~djb/qmail.html.
diff --git a/VERSION b/VERSION
index 88da7bb..78945e5 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-qmail 1.01
+qmail 1.03
diff --git a/binm1+df.sh b/binm1+df.sh
new file mode 100644 (file)
index 0000000..0ff1a68
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using dot-forward to support sendmail-style ~/.forward files.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using BSD 4.4 binmail interface: /usr/libexec/mail.local -r
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|dot-forward .forward
+|preline -f /usr/libexec/mail.local -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/binm1.sh b/binm1.sh
new file mode 100644 (file)
index 0000000..db79cbd
--- /dev/null
+++ b/binm1.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using BSD 4.4 binmail interface: /usr/libexec/mail.local -r
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start \
+'|preline -f /usr/libexec/mail.local -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/binm2+df.sh b/binm2+df.sh
new file mode 100644 (file)
index 0000000..4f78101
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using dot-forward to support sendmail-style ~/.forward files.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using SVR4 binmail interface: /bin/mail -r
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|dot-forward .forward
+|preline -f /bin/mail -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/binm2.sh b/binm2.sh
new file mode 100644 (file)
index 0000000..7905308
--- /dev/null
+++ b/binm2.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using SVR4 binmail interface: /bin/mail -r
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start \
+'|preline -f /bin/mail -r "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/binm3+df.sh b/binm3+df.sh
new file mode 100644 (file)
index 0000000..3d69401
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using dot-forward to support sendmail-style ~/.forward files.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using V7 binmail interface: /bin/mail -f
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|dot-forward .forward
+|preline -f /bin/mail -f "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/binm3.sh b/binm3.sh
new file mode 100644 (file)
index 0000000..eb139e6
--- /dev/null
+++ b/binm3.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using binmail to deliver messages to /var/spool/mail/$USER by default.
+# Using V7 binmail interface: /bin/mail -f
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start \
+'|preline -f /bin/mail -f "${SENDER:-MAILER-DAEMON}" -d "$USER"' \
+splogger qmail
diff --git a/bouncesaying.1 b/bouncesaying.1
new file mode 100644 (file)
index 0000000..d99a460
--- /dev/null
@@ -0,0 +1,71 @@
+.TH bouncesaying 1
+.SH NAME
+bouncesaying \- perhaps bounce each incoming message
+.SH SYNOPSIS
+in
+.BR .qmail :
+.B |bouncesaying
+.I error
+[
+.I program
+[
+.I arg ...
+]
+]
+.SH DESCRIPTION
+.B bouncesaying
+feeds each new mail message to
+.I program
+with the given arguments.
+If
+.I program
+exits 0,
+.B bouncesaying
+prints
+.I error
+and bounces the message.
+
+If
+.I program
+exits 111,
+.B bouncesaying
+exits 111,
+so delivery will be retried later.
+
+If
+.I program
+exits anything else
+(or does not exist),
+.B bouncesaying
+exits 0,
+so the rest of
+.B .qmail
+will be processed as usual.
+
+Note that
+it is not safe for
+.I program
+to fork a child that
+reads the message in the background.
+
+If
+.I program
+is not supplied,
+.B bouncesaying
+always bounces the message:
+
+.EX
+   |bouncesaying 'This address no longer accepts mail.'
+.EE
+
+.B WARNING:
+If you create a
+.B .qmail
+file to enable
+.BR bouncesaying ,
+make sure to also add a line specifying delivery to your normal mailbox.
+.SH "SEE ALSO"
+condredirect(1),
+except(1),
+dot-qmail(5),
+qmail-command(8)
diff --git a/bouncesaying.c b/bouncesaying.c
new file mode 100644 (file)
index 0000000..c7d0026
--- /dev/null
@@ -0,0 +1,41 @@
+#include "fork.h"
+#include "strerr.h"
+#include "error.h"
+#include "wait.h"
+#include "sig.h"
+#include "exit.h"
+
+#define FATAL "bouncesaying: fatal: "
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  int pid;
+  int wstat;
+
+  if (!argv[1])
+    strerr_die1x(100,"bouncesaying: usage: bouncesaying error [ program [ arg ... ] ]");
+
+  if (argv[2]) {
+    pid = fork();
+    if (pid == -1)
+      strerr_die2sys(111,FATAL,"unable to fork: ");
+    if (pid == 0) {
+      execvp(argv[2],argv + 2);
+      if (error_temp(errno)) _exit(111);
+      _exit(100);
+    }
+    if (wait_pid(&wstat,pid) == -1)
+      strerr_die2x(111,FATAL,"wait failed");
+    if (wait_crashed(wstat))
+      strerr_die2x(111,FATAL,"child crashed");
+    switch(wait_exitcode(wstat)) {
+      case 0: break;
+      case 111: strerr_die2x(111,FATAL,"temporary child error");
+      default: _exit(0);
+    }
+  }
+
+  strerr_die1x(100,argv[1]);
+}
diff --git a/commands.c b/commands.c
new file mode 100644 (file)
index 0000000..b0d3f61
--- /dev/null
@@ -0,0 +1,40 @@
+#include "commands.h"
+#include "substdio.h"
+#include "stralloc.h"
+#include "str.h"
+#include "case.h"
+
+static stralloc cmd = {0};
+
+int commands(ss,c)
+substdio *ss;
+struct commands *c;
+{
+  int i;
+  char *arg;
+
+  for (;;) {
+    if (!stralloc_copys(&cmd,"")) return -1;
+
+    for (;;) {
+      if (!stralloc_readyplus(&cmd,1)) return -1;
+      i = substdio_get(ss,cmd.s + cmd.len,1);
+      if (i != 1) return i;
+      if (cmd.s[cmd.len] == '\n') break;
+      ++cmd.len;
+    }
+
+    if (cmd.len > 0) if (cmd.s[cmd.len - 1] == '\r') --cmd.len;
+
+    cmd.s[cmd.len] = 0;
+
+    i = str_chr(cmd.s,' ');
+    arg = cmd.s + i;
+    while (*arg == ' ') ++arg;
+    cmd.s[i] = 0;
+
+    for (i = 0;c[i].text;++i) if (case_equals(c[i].text,cmd.s)) break;
+    c[i].fun(arg);
+    if (c[i].flush) c[i].flush();
+  }
+}
diff --git a/commands.h b/commands.h
new file mode 100644 (file)
index 0000000..da05a8d
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+struct commands {
+  char *text;
+  void (*fun)();
+  void (*flush)();
+} ;
+
+extern int commands();
+
+#endif
index 7a1292e..9f9d3c4 100644 (file)
@@ -48,7 +48,16 @@ it is not safe for
 .I program
 to fork a child that
 reads the message in the background.
+
+.B WARNING:
+If you create a
+.B .qmail
+file to enable
+.BR condredirect ,
+make sure to also add a line specifying delivery to your normal mailbox.
 .SH "SEE ALSO"
+bouncesaying(1),
+except(1),
 dot-qmail(5),
 qmail-command(8),
 qmail-queue(8)
index c6a2e6d..593d2f5 100644 (file)
@@ -7,81 +7,79 @@
 #include "wait.h"
 #include "seek.h"
 #include "qmail.h"
-#include "stralloc.h"
-#include "subfd.h"
+#include "strerr.h"
 #include "substdio.h"
+#include "fmt.h"
 
-void die_success() { _exit(0); }
-void die_99() { _exit(99); }
-void die_perm(s) char *s; { substdio_putsflush(subfderr,s); _exit(100); }
-void die_temp(s) char *s; { substdio_putsflush(subfderr,s); _exit(111); }
-void die_nomem() { die_temp("condredirect: fatal: out of memory\n"); }
+#define FATAL "condredirect: fatal: "
 
 struct qmail qqt;
 
 int mywrite(fd,buf,len) int fd; char *buf; int len;
 {
- qmail_put(&qqt,buf,len);
- return len;
 qmail_put(&qqt,buf,len);
 return len;
 }
 
-substdio ssin;
-substdio ssout;
 char inbuf[SUBSTDIO_INSIZE];
-char outbuf[16];
+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 *sender;
- char *dtline;
- int pid;
- int wstat;
-
- if (!argv[1] || !argv[2])
-   die_perm("condredirect: usage: condredirect newaddress program arg ...\n");
-
- switch(pid = fork())
-  {
-   case -1: die_temp("condredirect: fatal: unable to fork\n");
-   case 0:
-     execvp(argv[2],argv + 2);
-     if (error_temp(errno)) _exit(111);
-     _exit(100);
+  char *sender;
+  char *dtline;
+  int pid;
+  int wstat;
+  char *qqx;
+  if (!argv[1] || !argv[2])
+    strerr_die1x(100,"condredirect: usage: condredirect newaddress program [ arg ... ]");
+  pid = fork();
+  if (pid == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+  if (pid == 0) {
+    execvp(argv[2],argv + 2);
+    if (error_temp(errno)) _exit(111);
+    _exit(100);
   }
if (wait_pid(&wstat,pid) != pid)
-   die_perm("condredirect: fatal: internal bug\n");
- if (wait_crashed(wstat)) die_temp("condredirect: fatal: child crashed\n");
- switch(wait_exitcode(wstat))
-  {
-   case 0: break;
-   case 111: die_temp("condredirect: fatal: temporary child error\n");
-   default: die_success();
 if (wait_pid(&wstat,pid) == -1)
+    strerr_die2x(111,FATAL,"wait failed");
+  if (wait_crashed(wstat))
+    strerr_die2x(111,FATAL,"child crashed");
+  switch(wait_exitcode(wstat)) {
+    case 0: break;
+    case 111: strerr_die2x(111,FATAL,"temporary child error");
+    default: _exit(0);
   }
 
- if (seek_begin(0) == -1) die_temp("condredirect: fatal: unable to rewind\n");
- sig_pipeignore();
+  if (seek_begin(0) == -1)
+    strerr_die2sys(111,FATAL,"unable to rewind: ");
+  sig_pipeignore();
+  sender = env_get("SENDER");
+  if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+  dtline = env_get("DTLINE");
+  if (!dtline) strerr_die2x(100,FATAL,"DTLINE not set");
+  if (qmail_open(&qqt) == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+  qmail_puts(&qqt,dtline);
+  if (substdio_copy(&ssout,&ssin) != 0)
+    strerr_die2sys(111,FATAL,"unable to read message: ");
+  substdio_flush(&ssout);
+  num[fmt_ulong(num,qmail_qp(&qqt))] = 0;
 
- sender = env_get("SENDER");
- if (!sender) die_perm("condredirect: fatal: SENDER not set\n");
- dtline = env_get("DTLINE");
- if (!dtline) die_perm("condredirect: fatal: DTLINE not set\n");
-
- if (qmail_open(&qqt) == -1) die_temp("condredirect: fatal: unable to fork\n");
- qmail_puts(&qqt,dtline);
- substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
- substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf));
- if (substdio_copy(&ssout,&ssin) != 0)
-   die_temp("condredirect: fatal: error while reading message\n");
- substdio_flush(&ssout);
-
- qmail_from(&qqt,sender);
- qmail_to(&qqt,argv[1]);
- switch(qmail_close(&qqt))
-  {
-   case 0: die_99();
-   case QMAIL_TOOLONG: die_perm("condredirect: fatal: permanent qmail-queue error\n");
-   default: die_temp("condredirect: fatal: temporary qmail-queue error\n");
-  }
+  qmail_from(&qqt,sender);
+  qmail_to(&qqt,argv[1]);
+  qqx = qmail_close(&qqt);
+  if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
+  strerr_die2x(99,"condredirect: qp ",num);
 }
index b0f20b8..70c72af 100644 (file)
@@ -1,5 +1,6 @@
-022
+002
 
-These stat bits are not allowed in ~ and ~/.qmail.
+These stat bits are not allowed in ~ and ~/.qmail. On most systems, the
+default umask is 022 or 077, so 022 will work here.
 
 Note that ~ftp, ~www, ~uucp, etc. should be owned by root.
index 1f4cd67..0267f30 100644 (file)
@@ -2,3 +2,10 @@
 
 This is the qmail home directory. It must be a local directory, not
 shared among machines. This is where qmail queues all mail messages. 
+
+The queue (except for bounce message contents) is crashproof, if the
+filesystem guarantees that single-byte writes are atomic and that
+directory operations are synchronous. These guarantees are provided by
+fixed-block filesystems such as UFS and by journaling filesystems. Under
+Linux, make sure that all mail-handling filesystems are mounted with
+synchronous metadata.
diff --git a/config-fast.sh b/config-fast.sh
new file mode 100644 (file)
index 0000000..d05cda9
--- /dev/null
@@ -0,0 +1,30 @@
+fqdn="$1"
+echo Your fully qualified host name is "$fqdn".
+
+echo Putting "$fqdn" into control/me...
+echo "$fqdn" > QMAIL/control/me
+chmod 644 QMAIL/control/me
+
+( echo "$fqdn" | sed 's/^\([^\.]*\)\.\([^\.]*\)\./\2\./' | (
+  read ddom
+  echo Putting "$ddom" into control/defaultdomain...
+  echo "$ddom" > QMAIL/control/defaultdomain
+  chmod 644 QMAIL/control/defaultdomain
+) )
+
+( echo "$fqdn" | sed 's/^.*\.\([^\.]*\)\.\([^\.]*\)$/\1.\2/' | (
+  read pdom
+  echo Putting "$pdom" into control/plusdomain...
+  echo "$pdom" > QMAIL/control/plusdomain
+  chmod 644 QMAIL/control/plusdomain
+) )
+
+echo Putting "$fqdn" into control/locals...
+echo "$fqdn" >> QMAIL/control/locals
+chmod 644 QMAIL/control/locals
+
+echo Putting "$fqdn" into control/rcpthosts...
+echo "$fqdn" >> QMAIL/control/rcpthosts
+chmod 644 QMAIL/control/rcpthosts
+echo "Now qmail will refuse to accept SMTP messages except to $fqdn."
+echo 'Make sure to change rcpthosts if you add hosts to locals or virtualdomains!'
similarity index 100%
rename from qmail-config.sh
rename to config.sh
index 9a28191..722e3b8 100644 (file)
@@ -6,17 +6,16 @@ static constmap_hash hash(s,len)
 char *s;
 int len;
 {
- unsigned char ch;
- constmap_hash h;
- h = 5381;
- while (len > 0)
-  {
-   ch = *s++ - 'A';
-   if (ch <= 'Z' - 'A') ch += 'a' - 'A';
-   h = ((h << 5) + h) ^ ch;
-   --len;
+  unsigned char ch;
+  constmap_hash h;
+  h = 5381;
+  while (len > 0) {
+    ch = *s++ - 'A';
+    if (ch <= 'Z' - 'A') ch += 'a' - 'A';
+    h = ((h << 5) + h) ^ ch;
+    --len;
   }
- return h;
 return h;
 }
 
 char *constmap(cm,s,len)
@@ -24,19 +23,18 @@ struct constmap *cm;
 char *s;
 int len;
 {
- constmap_hash h;
- int pos;
- h = hash(s,len);
- pos = cm->first[h & cm->mask];
- while (pos != -1)
-  {
-   if (h == cm->hash[pos])
-     if (len == cm->inputlen[pos])
-       if (!case_diffb(cm->input[pos],len,s))
-        return cm->input[pos] + cm->inputlen[pos] + 1;
-   pos = cm->next[pos];
+  constmap_hash h;
+  int pos;
+  h = hash(s,len);
+  pos = cm->first[h & cm->mask];
+  while (pos != -1) {
+    if (h == cm->hash[pos])
+      if (len == cm->inputlen[pos])
+        if (!case_diffb(cm->input[pos],len,s))
+         return cm->input[pos] + cm->inputlen[pos] + 1;
+    pos = cm->next[pos];
   }
- return 0;
 return 0;
 }
 
 int constmap_init(cm,s,len,flagcolon)
@@ -45,79 +43,72 @@ char *s;
 int len;
 int flagcolon;
 {
- int i;
- int j;
- int k;
- int pos;
- constmap_hash h;
-
- cm->num = 0;
- for (j = 0;j < len;++j) if (!s[j]) ++cm->num;
-
- h = 64;
- while (h && (h < cm->num)) h += h;
- cm->mask = h - 1;
-
- cm->first = (int *) alloc(sizeof(int) * h);
- if (cm->first)
-  {
-   cm->input = (char **) alloc(sizeof(char *) * cm->num);
-   if (cm->input)
-    {
-     cm->inputlen = (int *) alloc(sizeof(int) * cm->num);
-     if (cm->inputlen)
-      {
-       cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num);
-       if (cm->hash)
-       {
-        cm->next = (int *) alloc(sizeof(int) * cm->num);
-        if (cm->next)
-         {
-          for (h = 0;h <= cm->mask;++h)
-            cm->first[h] = -1;
-           pos = 0;
-           i = 0;
-           for (j = 0;j < len;++j)
-             if (!s[j])
-              {
-              k = j - i;
-              if (flagcolon)
-               {
-                for (k = i;k < j;++k)
-                  if (s[k] == ':')
-                    break;
-                if (k >= j) { i = j + 1; continue; }
-                k -= i;
+  int i;
+  int j;
+  int k;
+  int pos;
+  constmap_hash h;
+  cm->num = 0;
+  for (j = 0;j < len;++j) if (!s[j]) ++cm->num;
+  h = 64;
+  while (h && (h < cm->num)) h += h;
+  cm->mask = h - 1;
+  cm->first = (int *) alloc(sizeof(int) * h);
+  if (cm->first) {
+    cm->input = (char **) alloc(sizeof(char *) * cm->num);
+    if (cm->input) {
+      cm->inputlen = (int *) alloc(sizeof(int) * cm->num);
+      if (cm->inputlen) {
+        cm->hash = (constmap_hash *) alloc(sizeof(constmap_hash) * cm->num);
+        if (cm->hash) {
+         cm->next = (int *) alloc(sizeof(int) * cm->num);
+         if (cm->next) {
+           for (h = 0;h <= cm->mask;++h)
+             cm->first[h] = -1;
+            pos = 0;
+            i = 0;
+            for (j = 0;j < len;++j)
+              if (!s[j]) {
+               k = j - i;
+               if (flagcolon) {
+                 for (k = i;k < j;++k)
+                   if (s[k] == ':')
+                     break;
+                 if (k >= j) { i = j + 1; continue; }
+                 k -= i;
                }
-               cm->input[pos] = s + i;
-               cm->inputlen[pos] = k;
-               h = hash(s + i,k);
-               cm->hash[pos] = h;
-               h &= cm->mask;
-               cm->next[pos] = cm->first[h];
-               cm->first[h] = pos;
-               ++pos;
-               i = j + 1;
+                cm->input[pos] = s + i;
+                cm->inputlen[pos] = k;
+                h = hash(s + i,k);
+                cm->hash[pos] = h;
+                h &= cm->mask;
+                cm->next[pos] = cm->first[h];
+                cm->first[h] = pos;
+                ++pos;
+                i = j + 1;
               }
-           return 1;
+            return 1;
          }
-        alloc_free(cm->hash);
+         alloc_free(cm->hash);
        }
-       alloc_free(cm->inputlen);
+        alloc_free(cm->inputlen);
       }
-     alloc_free(cm->input);
+      alloc_free(cm->input);
     }
-   alloc_free(cm->first);
+    alloc_free(cm->first);
   }
- return 0;
 return 0;
 }
 
 void constmap_free(cm)
 struct constmap *cm;
 {
- alloc_free(cm->next);
- alloc_free(cm->hash);
- alloc_free(cm->inputlen);
- alloc_free(cm->input);
- alloc_free(cm->first);
 alloc_free(cm->next);
 alloc_free(cm->hash);
 alloc_free(cm->inputlen);
 alloc_free(cm->input);
 alloc_free(cm->first);
 }
index 17fb1cb..3f29179 100644 (file)
@@ -3,8 +3,7 @@
 
 typedef unsigned long constmap_hash;
 
-struct constmap
- {
+struct constmap {
   int num;
   constmap_hash mask;
   constmap_hash *hash;
@@ -12,8 +11,7 @@ struct constmap
   int *next;
   char **input;
   int *inputlen;
- }
-;
+} ;
 
 extern int constmap_init();
 extern void constmap_free();
index 4cc80cf..b655352 100644 (file)
--- a/control.c
+++ b/control.c
@@ -79,7 +79,8 @@ char *fn;
    case 0: return 0;
    case -1: return -1;
   }
- if (scan_nbblong(line.s,line.len,10,0,&u) == 0) return 0;
+ if (!stralloc_0(&line)) return -1;
+ if (!scan_ulong(line.s,&u)) return 0;
  *i = u;
  return 1;
 }
diff --git a/dns.c b/dns.c
index bbb9770..ed42787 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -271,17 +271,16 @@ int pref;
  int r;
  struct ip_mx ix;
 
- if (sa->len && (sa->s[0] == '['))
-  {
-   if (!stralloc_copy(&glue,sa)) return DNS_MEM;
-   if (!stralloc_0(&glue)) return DNS_MEM;
+ 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_scanbracket(glue.s,&ix.ip)])
+   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;
      return 0;
     }
 }
+ }
 
  switch(resolve(sa,T_A))
   {
@@ -316,6 +315,7 @@ unsigned long random;
 {
  int r;
  struct mx { stralloc sa; unsigned short p; } *mx;
+ struct ip_mx ix;
  int nummx;
  int i;
  int j;
@@ -324,18 +324,16 @@ unsigned long random;
  if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
  ia->len = 0;
 
- if (sa->len && (sa->s[0] == '['))
-  {
-   struct ip_mx ix;
-   if (!stralloc_copy(&glue,sa)) return DNS_MEM;
-   if (!stralloc_0(&glue)) return DNS_MEM;
+ 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_scanbracket(glue.s,&ix.ip)])
+   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;
      return 0;
     }
 }
+ }
 
  switch(resolve(sa,T_MX))
   {
index 936067c..4fa1358 100644 (file)
@@ -45,7 +45,7 @@ ignores the line.
 A program line begins with a vertical bar:
 
 .EX
-     |/usr/ucb/vacation djb
+     |preline /usr/ucb/vacation djb
 .EE
 
 .B qmail-local
@@ -173,10 +173,10 @@ If
 is completely empty (0 bytes long), or does not exist,
 .B qmail-local
 follows the
-.I aliasempty
+.I defaultdelivery
 instructions set by your system administrator;
 normally
-.I aliasempty
+.I defaultdelivery
 is
 .BR ./Mailbox ,
 so
@@ -224,7 +224,7 @@ It's a good idea to test your new
 file as follows:
 
 .EX
-     qmail-local -n $USER $HOME $USER '' '' '' ''
+     qmail-local -n $USER ~ $USER '' '' '' '' ./Mailbox
 .EE
 .SH "EXTENSION ADDRESSES"
 In the
@@ -274,7 +274,7 @@ If
 is completely empty,
 .B qmail-local
 follows the
-.I aliasempty
+.I defaultdelivery
 instructions set by your system administrator.
 
 If
diff --git a/except.1 b/except.1
new file mode 100644 (file)
index 0000000..4198cc2
--- /dev/null
+++ b/except.1
@@ -0,0 +1,33 @@
+.TH except 1
+.SH NAME
+except \- reverse the exit code of a program
+.SH SYNOPSIS
+.B except
+.I program
+[
+.I arg ...
+]
+.SH DESCRIPTION
+.B except
+runs
+.I program
+with the given arguments.
+
+If
+.I program
+exits 0,
+.B except
+exits 100.
+If
+.I program
+exits 111,
+.B except
+exits 111.
+If
+.I program
+exits anything else,
+.B except
+exits 0.
+.SH "SEE ALSO"
+bouncesaying(1),
+condredirect(1)
diff --git a/except.c b/except.c
new file mode 100644 (file)
index 0000000..c553b3b
--- /dev/null
+++ b/except.c
@@ -0,0 +1,37 @@
+#include "fork.h"
+#include "strerr.h"
+#include "wait.h"
+#include "error.h"
+#include "exit.h"
+
+#define FATAL "except: fatal: "
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  int pid;
+  int wstat;
+
+  if (!argv[1])
+    strerr_die1x(100,"except: usage: except program [ arg ... ]");
+
+  pid = fork();
+  if (pid == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+  if (pid == 0) {
+    execvp(argv[1],argv + 1);
+    if (error_temp(errno)) _exit(111);
+    _exit(100);
+  }
+
+  if (wait_pid(&wstat,pid) == -1)
+    strerr_die2x(111,FATAL,"wait failed");
+  if (wait_crashed(wstat))
+    strerr_die2x(111,FATAL,"child crashed");
+  switch(wait_exitcode(wstat)) {
+    case 0: _exit(100);
+    case 111: strerr_die2x(111,FATAL,"temporary child error");
+    default: _exit(0);
+  }
+}
index c7517e8..cb99fa7 100644 (file)
@@ -71,7 +71,7 @@ Fortunately, a system administrator can easily obtain a copy of a
 931/1413/Ident/TAP server, such as
 .BR pidentd .
 Unfortunately,
-many incompetent system administrators fail to do this,
+some system administrators fail to do this,
 and are thus unable to figure out which local user
 was responsible for generating a message.
 
index de03773..e7390aa 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -3,56 +3,58 @@
 #include "exit.h"
 #include "env.h"
 #include "qmail.h"
-#include "stralloc.h"
-#include "subfd.h"
+#include "strerr.h"
 #include "substdio.h"
+#include "fmt.h"
 
-void die_success() { _exit(0); }
-void die_perm(s) char *s; { substdio_putsflush(subfderr,s); _exit(100); }
-void die_temp(s) char *s; { substdio_putsflush(subfderr,s); _exit(111); }
-void die_nomem() { die_temp("forward: fatal: out of memory\n"); }
+#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;
 {
- qmail_put(&qqt,buf,len);
- return len;
 qmail_put(&qqt,buf,len);
 return len;
 }
 
-substdio ssin;
-substdio ssout;
 char inbuf[SUBSTDIO_INSIZE];
-char outbuf[16];
+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 *sender;
- char *dtline;
-
- sig_pipeignore();
-
- sender = env_get("NEWSENDER");
- if (!sender) die_perm("forward: fatal: NEWSENDER not set\n");
- dtline = env_get("DTLINE");
- if (!dtline) die_perm("forward: fatal: DTLINE not set\n");
-
- if (qmail_open(&qqt) == -1) die_temp("forward: fatal: unable to fork\n");
- qmail_puts(&qqt,dtline);
- substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
- substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf));
- if (substdio_copy(&ssout,&ssin) != 0)
-   die_temp("forward: fatal: error while reading message\n");
- substdio_flush(&ssout);
-
- qmail_from(&qqt,sender);
- while (*++argv) qmail_to(&qqt,*argv);
- switch(qmail_close(&qqt))
-  {
-   case 0: die_success();
-   case QMAIL_TOOLONG: die_perm("forward: fatal: permanent qmail-queue error\n");
-   default: die_temp("forward: fatal: temporary qmail-queue error\n");
-  }
+  char *sender;
+  char *dtline;
+  char *qqx;
+  sig_pipeignore();
+  sender = env_get("NEWSENDER");
+  if (!sender)
+    strerr_die2x(100,FATAL,"NEWSENDER not set");
+  dtline = env_get("DTLINE");
+  if (!dtline)
+    strerr_die2x(100,FATAL,"DTLINE not set");
+  if (qmail_open(&qqt) == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+  qmail_puts(&qqt,dtline);
+  if (substdio_copy(&ssout,&ssin) != 0)
+    strerr_die2sys(111,FATAL,"unable to read message: ");
+  substdio_flush(&ssout);
+
+  num[fmt_ulong(num,qmail_qp(&qqt))] = 0;
+  qmail_from(&qqt,sender);
+  while (*++argv) qmail_to(&qqt,*argv);
+  qqx = qmail_close(&qqt);
+  if (*qqx) strerr_die2x(*qqx == 'D' ? 100 : 111,FATAL,qqx + 1);
+  strerr_die2x(0,"forward: qp ",num);
 }
index 38ecebc..06de0be 100644 (file)
--- a/hfield.c
+++ b/hfield.c
@@ -29,6 +29,7 @@ static char *(hname[]) = {
 , "content-type"
 , "content-transfer-encoding"
 , "notice-requested-upon-delivery-to"
+, "mail-followup-to"
 , 0
 };
 
index 0f59b82..20b30a5 100644 (file)
--- a/hfield.h
+++ b/hfield.h
@@ -32,6 +32,7 @@ extern int hfield_valid();
 #define H_CONTENTTYPE 25
 #define H_CONTENTTRANSFERENCODING 26
 #define H_NOTICEREQUESTEDUPONDELIVERYTO 27
-#define H_NUM 28
+#define H_MAILFOLLOWUPTO 28
+#define H_NUM 29
 
 #endif
diff --git a/hier.c b/hier.c
new file mode 100644 (file)
index 0000000..28e568d
--- /dev/null
+++ b/hier.c
@@ -0,0 +1,252 @@
+#include "auto_qmail.h"
+#include "auto_split.h"
+#include "auto_uids.h"
+#include "fmt.h"
+#include "fifo.h"
+
+char buf[100 + FMT_ULONG];
+
+void dsplit(base,uid,mode)
+char *base; /* must be under 100 bytes */
+int uid;
+int mode;
+{
+  char *x;
+  unsigned long i;
+
+  d(auto_qmail,base,uid,auto_gidq,mode);
+
+  for (i = 0;i < auto_split;++i) {
+    x = buf;
+    x += fmt_str(x,base);
+    x += fmt_str(x,"/");
+    x += fmt_ulong(x,i);
+    *x = 0;
+
+    d(auto_qmail,buf,uid,auto_gidq,mode);
+  }
+}
+
+void hier()
+{
+  h(auto_qmail,auto_uido,auto_gidq,0755);
+
+  d(auto_qmail,"control",auto_uido,auto_gidq,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);
+  d(auto_qmail,"doc",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755);
+
+  d(auto_qmail,"alias",auto_uida,auto_gidq,02755);
+
+  d(auto_qmail,"queue",auto_uidq,auto_gidq,0750);
+  d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700);
+  d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700);
+  d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750);
+  d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700);
+
+  dsplit("queue/mess",auto_uidq,0750);
+  dsplit("queue/info",auto_uids,0700);
+  dsplit("queue/local",auto_uids,0700);
+  dsplit("queue/remote",auto_uids,0700);
+
+  d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750);
+  z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644);
+  z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600);
+  p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622);
+
+  c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
+
+  c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644);
+  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","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);
+  c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711);
+  c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700);
+  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","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);
+  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-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);
+  c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711);
+  c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755);
+  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","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);
+  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","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);
+  c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755);
+  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);
+
+  c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644);
+}
diff --git a/home+df.sh b/home+df.sh
new file mode 100644 (file)
index 0000000..7885cdf
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using dot-forward to support sendmail-style ~/.forward files.
+# Using qmail-local to deliver messages to ~/Mailbox by default.
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|dot-forward .forward
+./Mailbox' splogger qmail
diff --git a/home.sh b/home.sh
new file mode 100644 (file)
index 0000000..c96c02b
--- /dev/null
+++ b/home.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using qmail-local to deliver messages to ~/Mailbox by default.
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start ./Mailbox splogger qmail
diff --git a/idedit.c b/idedit.c
new file mode 100644 (file)
index 0000000..e6747b5
--- /dev/null
+++ b/idedit.c
@@ -0,0 +1,147 @@
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include "readwrite.h"
+#include "exit.h"
+#include "scan.h"
+#include "fmt.h"
+#include "strerr.h"
+#include "open.h"
+#include "seek.h"
+#include "fork.h"
+
+#define FATAL "idedit: fatal: "
+#define WARNING "idedit: warning: "
+
+int fd;
+
+void byte(pos,value)
+char *pos;
+unsigned int value;
+{
+  unsigned long u;
+  unsigned char ch;
+
+  if (pos[scan_ulong(pos,&u)]) return;
+
+  if (seek_set(fd,(seek_pos) u) == -1)
+    strerr_die2sys(111,FATAL,"unable to seek: ");
+
+  ch = value;
+  if (write(fd,&ch,1) != 1)
+    strerr_die2sys(111,FATAL,"unable to write: ");
+}
+
+char *args[10];
+
+void run()
+{
+  int pid;
+  int wstat;
+
+  pid = fork();
+  if (pid == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
+
+  if (pid == 0) {
+    execv(*args,args);
+    strerr_die4sys(111,WARNING,"unable to run ",*args,": ");
+  }
+
+  if (wait_pid(&wstat,pid) != pid)
+    strerr_die2sys(111,FATAL,"waitpid surprise");
+}
+
+void u(account,group,home,pos0,pos1,pos2,pos3)
+char *account;
+char *group;
+char *home;
+char *pos0;
+char *pos1;
+char *pos2;
+char *pos3;
+{
+  struct passwd *pw;
+  unsigned int value;
+
+  pw = getpwnam(account);
+
+  if (!pw && group) {
+    args[0] = "add-account";
+    args[1] = account;
+    args[2] = group;
+    args[3] = home;
+    args[4] = 0;
+    run();
+    pw = getpwnam(account);
+  }
+
+  if (!pw)
+    strerr_die3x(111,FATAL,"unable to find uid for ",account);
+
+  value = pw->pw_uid;
+  byte(pos0,value); value >>= 8;
+  byte(pos1,value); value >>= 8;
+  byte(pos2,value); value >>= 8;
+  byte(pos3,value); value >>= 8;
+  if (value)
+    strerr_die3x(111,FATAL,"excessively large uid for ",account);
+}
+
+void g(group,pos0,pos1,pos2,pos3)
+char *group;
+char *pos0;
+char *pos1;
+char *pos2;
+char *pos3;
+{
+  struct group *gr;
+  unsigned int value;
+
+  gr = getgrnam(group);
+
+  if (!gr) {
+    args[0] = "add-group";
+    args[1] = group;
+    args[2] = 0;
+    run();
+    gr = getgrnam(group);
+  }
+
+  if (!gr)
+    strerr_die3x(111,FATAL,"unable to find gid for ",group);
+
+  value = gr->gr_gid;
+  byte(pos0,value); value >>= 8;
+  byte(pos1,value); value >>= 8;
+  byte(pos2,value); value >>= 8;
+  byte(pos3,value); value >>= 8;
+  if (value)
+    strerr_die3x(111,FATAL,"excessively large gid for ",group);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  if (argc < 42) _exit(100);
+
+  fd = open_write(argv[1]);
+  if (fd == -1) strerr_die4sys(111,FATAL,"unable to open ",argv[1],": ");
+
+  g("qmail",argv[34],argv[35],argv[36],argv[37]);
+  g("nofiles",argv[38],argv[39],argv[40],argv[41]);
+
+  u("root",(char *) 0,"/",argv[14],argv[15],argv[16],argv[17]);
+
+  u("qmaild","nofiles","/var/qmail",argv[6],argv[7],argv[8],argv[9]);
+  u("qmaill","nofiles","/var/qmail",argv[10],argv[11],argv[12],argv[13]);
+  u("qmailp","nofiles","/var/qmail",argv[18],argv[19],argv[20],argv[21]);
+  u("alias","nofiles","/var/qmail/alias",argv[2],argv[3],argv[4],argv[5]);
+
+  u("qmailq","qmail","/var/qmail",argv[22],argv[23],argv[24],argv[25]);
+  u("qmailr","qmail","/var/qmail",argv[26],argv[27],argv[28],argv[29]);
+  u("qmails","qmail","/var/qmail",argv[30],argv[31],argv[32],argv[33]);
+
+  _exit(0);
+}
diff --git a/install-big.c b/install-big.c
new file mode 100644 (file)
index 0000000..df813df
--- /dev/null
@@ -0,0 +1,285 @@
+#include "auto_qmail.h"
+#include "auto_split.h"
+#include "auto_uids.h"
+#include "fmt.h"
+#include "fifo.h"
+
+char buf[100 + FMT_ULONG];
+
+void dsplit(base,uid,mode)
+char *base; /* must be under 100 bytes */
+int uid;
+int mode;
+{
+  char *x;
+  unsigned long i;
+
+  d(auto_qmail,base,uid,auto_gidq,mode);
+
+  for (i = 0;i < auto_split;++i) {
+    x = buf;
+    x += fmt_str(x,base);
+    x += fmt_str(x,"/");
+    x += fmt_ulong(x,i);
+    *x = 0;
+
+    d(auto_qmail,buf,uid,auto_gidq,mode);
+  }
+}
+
+void hier()
+{
+  h(auto_qmail,auto_uido,auto_gidq,0755);
+
+  d(auto_qmail,"control",auto_uido,auto_gidq,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);
+  d(auto_qmail,"doc",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat1",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat5",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat7",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/cat8",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man1",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man5",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man7",auto_uido,auto_gidq,0755);
+  d(auto_qmail,"man/man8",auto_uido,auto_gidq,0755);
+
+  d(auto_qmail,"alias",auto_uida,auto_gidq,02755);
+
+  d(auto_qmail,"queue",auto_uidq,auto_gidq,0750);
+  d(auto_qmail,"queue/pid",auto_uidq,auto_gidq,0700);
+  d(auto_qmail,"queue/intd",auto_uidq,auto_gidq,0700);
+  d(auto_qmail,"queue/todo",auto_uidq,auto_gidq,0750);
+  d(auto_qmail,"queue/bounce",auto_uids,auto_gidq,0700);
+
+  dsplit("queue/mess",auto_uidq,0750);
+  dsplit("queue/info",auto_uids,0700);
+  dsplit("queue/local",auto_uids,0700);
+  dsplit("queue/remote",auto_uids,0700);
+
+  d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750);
+  z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644);
+  z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600);
+  p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622);
+
+  c(auto_qmail,"boot","home",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","home+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","proc",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","proc+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm1",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm1+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm2",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm2+df",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm3",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755);
+
+  c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.alias",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.ctl",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.ids",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.maildir",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.mbox",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","INSTALL.vsm",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","TEST.deliver",auto_uido,auto_gidq,0644);
+  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","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);
+  c(auto_qmail,"doc","PIC.local2rem",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.local2virt",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.nullclient",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.relaybad",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.relaygood",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711);
+  c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700);
+  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","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);
+  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-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);
+  c(auto_qmail,"bin","datemail",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","mailsubj",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-showctl",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-qread",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-qstat",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-tcpto",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-tcpok",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-pop3d",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","qmail-popup",auto_uido,auto_gidq,0711);
+  c(auto_qmail,"bin","qmail-qmqpc",auto_uido,auto_gidq,0755);
+  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","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);
+  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","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);
+  c(auto_qmail,"bin","except",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildirmake",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildir2mbox",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","maildirwatch",auto_uido,auto_gidq,0755);
+  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);
+
+  c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","envelopes.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","envelopes.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","maildir.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","maildir.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","mbox.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","mbox.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","dot-qmail.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","dot-qmail.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-control.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-control.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-header.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-header.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-log.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-log.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","qmail-users.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","qmail-users.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man5","tcp-environ.5",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat5","tcp-environ.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man7","forgeries.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","forgeries.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man7","qmail-limits.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","qmail-limits.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man7","qmail.7",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat7","qmail.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man1","forward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","forward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","condredirect.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","condredirect.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","bouncesaying.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","bouncesaying.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","except.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","except.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildirmake.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildirmake.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildir2mbox.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildir2mbox.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","maildirwatch.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","maildirwatch.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","mailsubj.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","mailsubj.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","qreceipt.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","qreceipt.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","qbiff.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","qbiff.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","preline.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","preline.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","tcp-env.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","tcp-env.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man8","qmail-local.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-local.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-lspawn.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-lspawn.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-getpw.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-getpw.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-remote.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-remote.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-rspawn.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-rspawn.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-clean.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-clean.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-send.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-send.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-start.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-start.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-showctl.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-newmrh.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-newmrh.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-newu.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-newu.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-pw2u.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-pw2u.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qread.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qread.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qstat.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qstat.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-tcpok.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-tcpok.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-tcpto.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-tcpto.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-pop3d.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-pop3d.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-popup.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-popup.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmqpc.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmqpc.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmqpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmqpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-qmtpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-qmtpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-smtpd.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-smtpd.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-command.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-command.0",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"bin","dot-forward",auto_uido,auto_gidq,0755);
+
+  c(auto_qmail,"man/man1","dot-forward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","dot-forward.0",auto_uido,auto_gidq,0644);
+
+  d(auto_qmail,"doc/fastforward",auto_uido,auto_gidq,0755);
+
+  c(auto_qmail,"bin","fastforward",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","printforward",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","setforward",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","newaliases",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","printmaillist",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","setmaillist",auto_uido,auto_gidq,0755);
+  c(auto_qmail,"bin","newinclude",auto_uido,auto_gidq,0755);
+
+  c(auto_qmail,"doc/fastforward","ALIASES",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/man1","fastforward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","printforward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","setforward.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","newaliases.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","printmaillist.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","setmaillist.1",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man1","newinclude.1",auto_uido,auto_gidq,0644);
+
+  c(auto_qmail,"man/cat1","fastforward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","printforward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","setforward.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","newaliases.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","printmaillist.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","setmaillist.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat1","newinclude.0",auto_uido,auto_gidq,0644);
+}
index ffc09a6..95034f2 100644 (file)
--- a/install.c
+++ b/install.c
 #include "substdio.h"
-#include "stralloc.h"
-#include "getln.h"
+#include "strerr.h"
+#include "error.h"
+#include "open.h"
 #include "readwrite.h"
 #include "exit.h"
-#include "open.h"
-#include "error.h"
-#include "strerr.h"
-#include "byte.h"
-#include "fifo.h"
 
-stralloc target = {0};
-char *to;
+extern void hier();
 
 #define FATAL "install: fatal: "
-void nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+
+int fdsourcedir = -1;
+
+void h(home,uid,gid,mode)
+char *home;
+int uid;
+int gid;
+int mode;
+{
+  if (mkdir(home,0700) == -1)
+    if (errno != error_exist)
+      strerr_die4sys(111,FATAL,"unable to mkdir ",home,": ");
+  if (chown(home,uid,gid) == -1)
+    strerr_die4sys(111,FATAL,"unable to chown ",home,": ");
+  if (chmod(home,mode) == -1)
+    strerr_die4sys(111,FATAL,"unable to chmod ",home,": ");
+}
+
+void d(home,subdir,uid,gid,mode)
+char *home;
+char *subdir;
+int uid;
+int gid;
+int mode;
+{
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  if (mkdir(subdir,0700) == -1)
+    if (errno != error_exist)
+      strerr_die6sys(111,FATAL,"unable to mkdir ",home,"/",subdir,": ");
+  if (chown(subdir,uid,gid) == -1)
+    strerr_die6sys(111,FATAL,"unable to chown ",home,"/",subdir,": ");
+  if (chmod(subdir,mode) == -1)
+    strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",subdir,": ");
+}
+
+void p(home,fifo,uid,gid,mode)
+char *home;
+char *fifo;
+int uid;
+int gid;
+int mode;
+{
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  if (fifo_make(fifo,0700) == -1)
+    if (errno != error_exist)
+      strerr_die6sys(111,FATAL,"unable to mkfifo ",home,"/",fifo,": ");
+  if (chown(fifo,uid,gid) == -1)
+    strerr_die6sys(111,FATAL,"unable to chown ",home,"/",fifo,": ");
+  if (chmod(fifo,mode) == -1)
+    strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",fifo,": ");
+}
 
 char inbuf[SUBSTDIO_INSIZE];
 char outbuf[SUBSTDIO_OUTSIZE];
 substdio ssin;
 substdio ssout;
 
-void doit(line)
-stralloc *line;
+void c(home,subdir,file,uid,gid,mode)
+char *home;
+char *subdir;
+char *file;
+int uid;
+int gid;
+int mode;
 {
-  char *x;
-  unsigned int xlen;
-  unsigned int i;
-  char *type;
-  char *uidstr;
-  char *gidstr;
-  char *modestr;
-  char *mid;
-  char *name;
-  unsigned long uid;
-  unsigned long gid;
-  unsigned long mode;
   int fdin;
   int fdout;
-  unsigned long zlen;
-
-  x = line->s; xlen = line->len;
-
-  type = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  uidstr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  gidstr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  modestr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  mid = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  name = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  if (!stralloc_copys(&target,to)) nomem();
-  if (!stralloc_cats(&target,mid)) nomem();
-  if (!stralloc_cats(&target,name)) nomem();
-  if (!stralloc_0(&target)) nomem();
-
-  uid = -1; if (*uidstr) scan_ulong(uidstr,&uid);
-  gid = -1; if (*gidstr) scan_ulong(gidstr,&gid);
-  scan_8long(modestr,&mode);
-
-  switch(*type) {
-    case 'z':
-      scan_ulong(type + 1,&zlen);
-
-      fdout = open_trunc(target.s);
-      if (fdout == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
-
-      while (zlen--)
-       if (substdio_put(&ssout,"",1) == -1)
-         strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-
-      if (substdio_flush(&ssout) == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      if (fsync(fdout) == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      close(fdout);
-      break;
-
-    case 'p':
-      if (fifo_make(target.s,0700) == -1)
-        if (errno != error_exist)
-         strerr_die4sys(111,FATAL,"unable to mkfifo ",target.s,": ");
-      break;
-
-    case 'd':
-      if (mkdir(target.s,0700) == -1)
-        if (errno != error_exist)
-         strerr_die4sys(111,FATAL,"unable to mkdir ",target.s,": ");
-      break;
-
-    case 'c':
-      fdin = open_read(name);
-      if (fdin == -1)
-       strerr_die4sys(111,FATAL,"unable to read ",name,": ");
-      substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
-
-      fdout = open_trunc(target.s);
-      if (fdout == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
-
-      switch(substdio_copy(&ssout,&ssin)) {
-       case -2:
-         strerr_die4sys(111,FATAL,"unable to read ",name,": ");
-       case -3:
-         strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      }
-
-      close(fdin);
-      if (substdio_flush(&ssout) == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      if (fsync(fdout) == -1)
-       strerr_die4sys(111,FATAL,"unable to write ",target.s,": ");
-      close(fdout);
-      break;
-
-    default:
-      return;
+
+  if (fchdir(fdsourcedir) == -1)
+    strerr_die2sys(111,FATAL,"unable to switch back to source directory: ");
+
+  fdin = open_read(file);
+  if (fdin == -1)
+    strerr_die4sys(111,FATAL,"unable to read ",file,": ");
+  substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof inbuf);
+
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  if (chdir(subdir) == -1)
+    strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": ");
+
+  fdout = open_trunc(file);
+  if (fdout == -1)
+    strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+  substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf);
+
+  switch(substdio_copy(&ssout,&ssin)) {
+    case -2:
+      strerr_die4sys(111,FATAL,"unable to read ",file,": ");
+    case -3:
+      strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
   }
 
-  if (chown(target.s,uid,gid) == -1)
-    strerr_die4sys(111,FATAL,"unable to chown ",target.s,": ");
-  if (chmod(target.s,mode) == -1)
-    strerr_die4sys(111,FATAL,"unable to chmod ",target.s,": ");
+  close(fdin);
+  if (substdio_flush(&ssout) == -1)
+    strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+  if (fsync(fdout) == -1)
+    strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+  if (close(fdout) == -1) /* NFS silliness */
+    strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+
+  if (chown(file,uid,gid) == -1)
+    strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": ");
+  if (chmod(file,mode) == -1)
+    strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": ");
 }
 
-char buf[256];
-substdio in = SUBSTDIO_FDBUF(read,0,buf,sizeof(buf));
-stralloc line = {0};
-
-void main(argc,argv)
-int argc;
-char **argv;
+void z(home,file,len,uid,gid,mode)
+char *home;
+char *file;
+int len;
+int uid;
+int gid;
+int mode;
 {
-  int match;
+  int fdout;
 
-  umask(077);
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+
+  fdout = open_trunc(file);
+  if (fdout == -1)
+    strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": ");
+  substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf);
+
+  while (len-- > 0)
+    if (substdio_put(&ssout,"",1) == -1)
+      strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": ");
+
+  if (substdio_flush(&ssout) == -1)
+    strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": ");
+  if (fsync(fdout) == -1)
+    strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": ");
+  if (close(fdout) == -1) /* NFS silliness */
+    strerr_die6sys(111,FATAL,"unable to write ",home,"/",file,": ");
+
+  if (chown(file,uid,gid) == -1)
+    strerr_die6sys(111,FATAL,"unable to chown ",home,"/",file,": ");
+  if (chmod(file,mode) == -1)
+    strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",file,": ");
+}
 
-  to = argv[1];
-  if (!to) strerr_die2x(100,FATAL,"install: usage: install dir");
+void main()
+{
+  fdsourcedir = open_read(".");
+  if (fdsourcedir == -1)
+    strerr_die2sys(111,FATAL,"unable to open current directory: ");
 
-  for (;;) {
-    if (getln(&in,&line,&match,'\n') == -1)
-      strerr_die2sys(111,FATAL,"unable to read input: ");
-    doit(&line);
-    if (!match)
-      _exit(0);
-  }
+  umask(077);
+  hier();
+  _exit(0);
 }
index 48db531..d41efda 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "substdio.h"
-#include "stralloc.h"
-#include "getln.h"
+#include "strerr.h"
+#include "error.h"
 #include "readwrite.h"
 #include "exit.h"
-#include "error.h"
-#include "strerr.h"
-#include "byte.h"
 
-stralloc target = {0};
-char *to;
+extern void hier();
 
-#define WARNING "instcheck: warning: "
 #define FATAL "instcheck: fatal: "
-void nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+#define WARNING "instcheck: warning: "
 
-void doit(line)
-stralloc *line;
+void perm(prefix1,prefix2,prefix3,file,type,uid,gid,mode)
+char *prefix1;
+char *prefix2;
+char *prefix3;
+char *file;
+int type;
+int uid;
+int gid;
+int mode;
 {
   struct stat st;
-  char *x;
-  unsigned int xlen;
-  unsigned int i;
-  char *type;
-  char *uidstr;
-  char *gidstr;
-  char *modestr;
-  char *mid;
-  char *name;
-  unsigned long uid;
-  unsigned long gid;
-  unsigned long mode;
-  int ftype;
-
-  x = line->s; xlen = line->len;
-
-  type = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  uidstr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  gidstr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  modestr = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  mid = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  name = x;
-  i = byte_chr(x,xlen,':'); if (i == xlen) return;
-  x[i++] = 0; x += i; xlen -= i;
-
-  if (!stralloc_copys(&target,to)) nomem();
-  if (!stralloc_cats(&target,mid)) nomem();
-  if (!stralloc_cats(&target,name)) nomem();
-  if (!stralloc_0(&target)) nomem();
-
-  uid = -1; if (*uidstr) scan_ulong(uidstr,&uid);
-  gid = -1; if (*gidstr) scan_ulong(gidstr,&gid);
-  scan_8long(modestr,&mode);
 
-  switch(*type) {
-    case 'd': ftype = S_IFDIR; break;
-    case 'c': ftype = S_IFREG; break;
-    case 'z': ftype = S_IFREG; break;
-    case 'p': ftype = S_IFIFO; break;
-    default: return;
-  }
-
-  if (stat(target.s,&st) == -1) {
+  if (stat(file,&st) == -1) {
     if (errno == error_noent)
-      strerr_warn3(WARNING,target.s," does not exist",0);
+      strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," does not exist",0);
     else
-      strerr_warn4(WARNING,"unable to stat ",target.s,": ",&strerr_sys);
+      strerr_warn4(WARNING,"unable to stat .../",file,": ",&strerr_sys);
     return;
   }
 
   if ((uid != -1) && (st.st_uid != uid))
-    strerr_warn3(WARNING,target.s," has wrong owner",0);
+    strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong owner",0);
   if ((gid != -1) && (st.st_gid != gid))
-    strerr_warn3(WARNING,target.s," has wrong group",0);
+    strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong group",0);
   if ((st.st_mode & 07777) != mode)
-    strerr_warn3(WARNING,target.s," has wrong permissions",0);
-  if ((st.st_mode & S_IFMT) != ftype)
-    strerr_warn3(WARNING,target.s," has wrong type",0);
+    strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong permissions",0);
+  if ((st.st_mode & S_IFMT) != type)
+    strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong type",0);
 }
 
-char buf[256];
-substdio in = SUBSTDIO_FDBUF(read,0,buf,sizeof(buf));
-stralloc line = {0};
+void h(home,uid,gid,mode)
+char *home;
+int uid;
+int gid;
+int mode;
+{
+  perm("","","",home,S_IFDIR,uid,gid,mode);
+}
+
+void d(home,subdir,uid,gid,mode)
+char *home;
+char *subdir;
+int uid;
+int gid;
+int mode;
+{
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  perm("",home,"/",subdir,S_IFDIR,uid,gid,mode);
+}
 
-void main(argc,argv)
-int argc;
-char **argv;
+void p(home,fifo,uid,gid,mode)
+char *home;
+char *fifo;
+int uid;
+int gid;
+int mode;
 {
-  int match;
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  perm("",home,"/",fifo,S_IFIFO,uid,gid,mode);
+}
 
-  umask(077);
+void c(home,subdir,file,uid,gid,mode)
+char *home;
+char *subdir;
+char *file;
+int uid;
+int gid;
+int mode;
+{
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  if (chdir(subdir) == -1)
+    strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": ");
+  perm(".../",subdir,"/",file,S_IFREG,uid,gid,mode);
+}
 
-  to = argv[1];
-  if (!to) strerr_die2x(100,FATAL,"instcheck: usage: instcheck dir");
+void z(home,file,len,uid,gid,mode)
+char *home;
+char *file;
+int len;
+int uid;
+int gid;
+int mode;
+{
+  if (chdir(home) == -1)
+    strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+  perm("",home,"/",file,S_IFREG,uid,gid,mode);
+}
 
-  for (;;) {
-    if (getln(&in,&line,&match,'\n') == -1)
-      strerr_die2sys(111,FATAL,"unable to read input: ");
-    doit(&line);
-    if (!match)
-      _exit(0);
-  }
+void main()
+{
+  hier();
+  _exit(0);
 }
index 54ddb89..5da9573 100644 (file)
--- a/maildir.5
+++ b/maildir.5
@@ -209,7 +209,7 @@ or rename
 as
 .BR cur/\fIunique:info .
 See
-.B http://pobox.com/~djb/maildir.html
+.B http://pobox.com/~djb/proto/maildir.html
 for the meaning of
 .IR info .
 
index f9822ec..9863fef 100644 (file)
@@ -1,22 +1,24 @@
-#include "subfd.h"
-#include "substdio.h"
-#include "error.h"
+#include "strerr.h"
 #include "exit.h"
 
-void die(s) char *s; { substdio_putsflush(subfderr,s); _exit(111); }
+#define FATAL "maildirmake: fatal: "
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
- umask(077);
- if (!argv[1]) die("usage: maildirmake name\n");
- if (mkdir(argv[1],0700))
-   if (errno == error_exist) die("fatal: directory already exists\n");
-   else die("fatal: unable to mkdir\n");
- if (chdir(argv[1])) die("fatal: unable to chdir\n");
- if (mkdir("tmp",0700)) die("fatal: unable to make tmp/ subdir\n");
- if (mkdir("new",0700)) die("fatal: unable to make new/ subdir\n");
- if (mkdir("cur",0700)) die("fatal: unable to make cur/ subdir\n");
- _exit(0);
+  umask(077);
+  if (!argv[1])
+    strerr_die1x(100,"maildirmake: usage: maildirmake name");
+  if (mkdir(argv[1],0700) == -1)
+    strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],": ");
+  if (chdir(argv[1]) == -1)
+    strerr_die4sys(111,FATAL,"unable to chdir to ",argv[1],": ");
+  if (mkdir("tmp",0700) == -1)
+    strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/tmp: ");
+  if (mkdir("new",0700) == -1)
+    strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/new: ");
+  if (mkdir("cur",0700) == -1)
+    strerr_die4sys(111,FATAL,"unable to mkdir ",argv[1],"/cur: ");
+  _exit(0);
 }
index 207e7f2..438d1d8 100644 (file)
--- a/ndelay.c
+++ b/ndelay.c
@@ -2,8 +2,12 @@
 #include <fcntl.h>
 #include "ndelay.h"
 
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
 int ndelay_on(fd)
 int fd;
 {
-  return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NDELAY);
+  return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
 }
index 2c89dc3..86f8fbf 100644 (file)
@@ -2,8 +2,12 @@
 #include <fcntl.h>
 #include "ndelay.h"
 
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
 int ndelay_off(fd)
 int fd;
 {
-  return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NDELAY);
+  return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
 }
index b011dc5..9648f6e 100644 (file)
--- a/predate.c
+++ b/predate.c
@@ -5,11 +5,14 @@
 #include "wait.h"
 #include "fd.h"
 #include "fmt.h"
+#include "strerr.h"
 #include "substdio.h"
 #include "subfd.h"
 #include "readwrite.h"
 #include "exit.h"
 
+#define FATAL "predate: fatal: "
+
 static char *montab[12] = {
 "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
 };
@@ -34,30 +37,22 @@ char **argv;
 
   sig_pipeignore();
 
-  if (!argv[1]) {
-    substdio_putsflush(subfderr,"predate: usage: predate child\n");
-    _exit(100);
-  }
+  if (!argv[1])
+    strerr_die1x(100,"predate: usage: predate child");
 
-  if (pipe(pi) == -1) {
-    substdio_putsflush(subfderr,"predate: fatal: unable to create pipe\n");
-    _exit(111);
-  }
+  if (pipe(pi) == -1)
+    strerr_die2sys(111,FATAL,"unable to create pipe: ");
 
   switch(pid = fork()) {
     case -1:
-      substdio_putsflush(subfderr,"predate: fatal: unable to fork\n");
-      _exit(111);
+      strerr_die2sys(111,FATAL,"unable to fork: ");
     case 0:
       close(pi[1]);
-      if (fd_move(0,pi[0]) == -1) {
-        substdio_putsflush(subfderr,"predate: fatal: unable to set up fds\n");
-        _exit(111);
-      }
+      if (fd_move(0,pi[0]) == -1)
+       strerr_die2sys(111,FATAL,"unable to set up fds: ");
       sig_pipedefault();
       execvp(argv[1],argv + 1);
-      substdio_putsflush(subfderr,"predate: fatal: unable to exec\n");
-      _exit(111);
+      strerr_die4sys(111,FATAL,"unable to run ",argv[1],": ");
   }
   close(pi[0]);
   substdio_fdbuf(&ss,write,pi[1],outbuf,sizeof(outbuf));
@@ -113,13 +108,9 @@ char **argv;
   substdio_flush(&ss);
   close(pi[1]);
 
-  if (wait_pid(&wstat,pid) == -1) {
-    substdio_putsflush(subfderr,"predate: fatal: wait failed\n");
-    _exit(111);
-  }
-  if (wait_crashed(wstat)) {
-    substdio_putsflush(subfderr,"predate: fatal: child crashed\n");
-    _exit(111);
-  }
+  if (wait_pid(&wstat,pid) == -1)
+    strerr_die2sys(111,FATAL,"wait failed: ");
+  if (wait_crashed(wstat))
+    strerr_die2x(111,FATAL,"child crashed");
   _exit(wait_exitcode(wstat));
 }
index 8e76485..1a4cef8 100644 (file)
--- a/preline.c
+++ b/preline.c
@@ -1,7 +1,7 @@
 #include "fd.h"
 #include "sgetopt.h"
 #include "readwrite.h"
-#include "subfd.h"
+#include "strerr.h"
 #include "substdio.h"
 #include "exit.h"
 #include "fork.h"
 #include "sig.h"
 #include "error.h"
 
-void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); }
-void die_usage() { die(100,"preline: fatal: incorrect usage\n"); }
-void die_temp() { die(111,"preline: fatal: temporary problem\n"); }
-void die_read() { die(111,"preline: fatal: unable to read message\n"); }
-void die_badcmd() { die(100,"preline: fatal: command not found\n"); }
+#define FATAL "preline: fatal: "
+
+void die_usage()
+{
+  strerr_die1x(100,"preline: usage: preline cmd [ arg ... ]");
+}
 
 int flagufline = 1; char *ufline;
 int flagrpline = 1; char *rpline;
 int flagdtline = 1; char *dtline;
 
-substdio ssout;
 char outbuf[SUBSTDIO_OUTSIZE];
-substdio ssin;
 char inbuf[SUBSTDIO_INSIZE];
+substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,sizeof outbuf);
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
- int opt;
- int pi[2];
- int pid;
- int wstat;
-
- sig_pipeignore();
-
- if (!(ufline = env_get("UFLINE"))) die_usage();
- if (!(rpline = env_get("RPLINE"))) die_usage();
- if (!(dtline = env_get("DTLINE"))) die_usage();
-
- while ((opt = getopt(argc,argv,"frdFRD")) != opteof)
-   switch(opt)
-    {
-     case 'f': flagufline = 0; break;
-     case 'r': flagrpline = 0; break;
-     case 'd': flagdtline = 0; break;
-     case 'F': flagufline = 1; break;
-     case 'R': flagrpline = 1; break;
-     case 'D': flagdtline = 1; break;
-     default:
-       _exit(100);
+  int opt;
+  int pi[2];
+  int pid;
+  int wstat;
+  sig_pipeignore();
+  if (!(ufline = env_get("UFLINE"))) die_usage();
+  if (!(rpline = env_get("RPLINE"))) die_usage();
+  if (!(dtline = env_get("DTLINE"))) die_usage();
+  while ((opt = getopt(argc,argv,"frdFRD")) != opteof)
+    switch(opt) {
+      case 'f': flagufline = 0; break;
+      case 'r': flagrpline = 0; break;
+      case 'd': flagdtline = 0; break;
+      case 'F': flagufline = 1; break;
+      case 'R': flagrpline = 1; break;
+      case 'D': flagdtline = 1; break;
+      default: die_usage();
     }
- argc -= optind;
- argv += optind;
- if (!*argv) die_usage();
+  argc -= optind;
+  argv += optind;
+  if (!*argv) die_usage();
+  if (pipe(pi) == -1)
+    strerr_die2sys(111,FATAL,"unable to create pipe: ");
 
- if (pipe(pi) == -1) die_temp();
+  pid = fork();
+  if (pid == -1)
+    strerr_die2sys(111,FATAL,"unable to fork: ");
 
- switch(pid = fork())
-  {
-   case -1:
-     die_temp();
-   case 0:
-     close(pi[1]);
-     if (fd_move(0,pi[0])) die_temp();
-     sig_pipedefault();
-     execvp(*argv,argv);
-     if (error_temp(errno)) die_temp();
-     die_badcmd();
+  if (pid == 0) {
+    close(pi[1]);
+    if (fd_move(0,pi[0]) == -1)
+      strerr_die2sys(111,FATAL,"unable to set up fds: ");
+    sig_pipedefault();
+    execvp(*argv,argv);
+    strerr_die4sys(error_temp(errno) ? 111 : 100,FATAL,"unable to run ",*argv,": ");
   }
- close(pi[0]);
-
- substdio_fdbuf(&ssout,write,pi[1],outbuf,sizeof(outbuf));
- substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
- if (flagufline) substdio_bputs(&ssout,ufline);
- if (flagrpline) substdio_bputs(&ssout,rpline);
- if (flagdtline) substdio_bputs(&ssout,dtline);
- if (substdio_copy(&ssout,&ssin) == -2) die_read();
- substdio_flush(&ssout);
- close(pi[1]);
-
- if (wait_pid(&wstat,pid) == -1) die_temp();
- if (wait_crashed(wstat)) die_temp();
- _exit(wait_exitcode(wstat));
+  close(pi[0]);
+  if (fd_move(1,pi[1]) == -1)
+    strerr_die2sys(111,FATAL,"unable to set up fds: ");
+  if (flagufline) substdio_bputs(&ssout,ufline);
+  if (flagrpline) substdio_bputs(&ssout,rpline);
+  if (flagdtline) substdio_bputs(&ssout,dtline);
+  if (substdio_copy(&ssout,&ssin) != 0)
+    strerr_die2sys(111,FATAL,"unable to copy input: ");
+  substdio_flush(&ssout);
+  close(1);
+  if (wait_pid(&wstat,pid) == -1)
+    strerr_die2sys(111,FATAL,"wait failed: ");
+  if (wait_crashed(wstat))
+    strerr_die2x(111,FATAL,"child crashed");
+  _exit(wait_exitcode(wstat));
 }
diff --git a/proc+df.sh b/proc+df.sh
new file mode 100644 (file)
index 0000000..eb9e92c
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using dot-forward to support sendmail-style ~/.forward files.
+# Using procmail to deliver messages to /var/spool/mail/$USER by default.
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|dot-forward .forward
+|preline procmail' splogger qmail
diff --git a/proc.sh b/proc.sh
new file mode 100644 (file)
index 0000000..3c76220
--- /dev/null
+++ b/proc.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Using splogger to send the log through syslog.
+# Using procmail to deliver messages to /var/spool/mail/$USER by default.
+
+exec env - PATH="QMAIL/bin:$PATH" \
+qmail-start '|preline procmail' splogger qmail
diff --git a/qlist.1 b/qlist.1
deleted file mode 100644 (file)
index 118b53b..0000000
--- a/qlist.1
+++ /dev/null
@@ -1,112 +0,0 @@
-.TH qlist 1
-.SH NAME
-qlist \- handle mailing list subscription requests
-.SH SYNOPSIS
-in
-.BR .qmail-\fIlist-request :
-.br
-.B |qlist
-.I user-list@host
-.I user-list-request@host
-.br
-.B .qmail-\fIlist
-.B .qmail-\fIlist-request
-.B .qtemp-\fIlist
-.br
-.I owner
-[
-.I moreinfo
-]
-.br
-(all on one line)
-.SH DESCRIPTION
-.B qlist
-manages a 
-.B qmail
-mailing list.
-
-When
-.B qlist
-receives a message,
-it looks through the body of the message for commands.
-.B WARNING:
-.B qlist
-looks for a command only at the beginning of a line.
-Exception:
-.B qlist
-also looks at
-.B Subject
-lines.
-
-.B qlist
-supports two commands.
-.B SUBSCRIBE
-adds a new subscription to the mailing list;
-.B UNSUBSCRIBE
-removes a subscription.
-.B qlist
-looks for the subscription address in the
-.BR Reply-To ,
-.BR From ,
-or
-.BR Return-Path
-fields in the message.
-
-.B qlist
-inserts an acknowledgment of each action it took,
-along with general help instructions, into the message.
-It then forwards the message to the subscription address,
-with a copy to
-.IR owner .
-
-.BR qlist 's
-general help instructions identify
-.I user-list@host
-as the address of the mailing list,
-.I user-list-request@host
-as the address of
-.B qlist
-itself, and
-.I owner
-as the address
-of the mailing list owner.
-If
-.I moreinfo
-is supplied,
-it is inserted into the middle of the instructions,
-surrounded by blank lines.
-
-.B qlist
-maintains its address list in
-.BR .qmail-\fIlist ,
-so mail to
-.I user-list
-will be forwarded to each subscription address.
-While
-.B qlist
-is editing
-.BR .qmail-\fIlist ,
-it locks
-.BR .qmail-\fIlist-request .
-It uses
-.B .qtemp-\fIlist
-as a temporary file.
-
-Note that
-.B qlist
-only manipulates lines beginning with an ampersand;
-if you manually add an address without an ampersand,
-it cannot be removed by
-.BR qlist .
-
-.B qlist
-automatically sets the execute bit on
-.BR qmail-\fIlist ,
-so
-.B qmail-local
-will ignore any program or file instructions in
-.BR qmail-\fIlist .
-.SH "SEE ALSO"
-dot-qmail(5),
-envelopes(5),
-qmail-queue(8)
diff --git a/qlist.c b/qlist.c
deleted file mode 100644 (file)
index 230476f..0000000
--- a/qlist.c
+++ /dev/null
@@ -1,333 +0,0 @@
-#include "sig.h"
-#include "readwrite.h"
-#include "substdio.h"
-#include "stralloc.h"
-#include "subfd.h"
-#include "getln.h"
-#include "alloc.h"
-#include "str.h"
-#include "env.h"
-#include "hfield.h"
-#include "case.h"
-#include "token822.h"
-#include "error.h"
-#include "gen_alloc.h"
-#include "gen_allocdefs.h"
-#include "headerbody.h"
-#include "exit.h"
-#include "open.h"
-#include "lock.h"
-#include "qmail.h"
-
-#define ADDRLIMIT 100
-
-void die() { _exit(100); }
-void die_temp() { _exit(111); }
-void die_nomem() {
- substdio_putsflush(subfderr,"qlist: fatal: out of memory\n"); die_temp(); }
-void die_fork() {
- substdio_putsflush(subfderr,"qlist: fatal: unable to fork\n"); die_temp(); }
-void die_nolock() {
- substdio_putsflush(subfderr,"qlist: fatal: unable to open lock file\n"); die_temp(); }
-void die_boing() {
- substdio_putsflush(subfderr,"qlist: fatal: I don't reply to bounces\n"); die(); }
-void die_badaddr() {
- substdio_putsflush(subfderr,"qlist: fatal: sorry, I'm not allowed to use that address\n"); die(); }
-void die_qqperm() {
- substdio_putsflush(subfderr,"qlist: fatal: permanent qmail-queue error\n"); die(); }
-void die_qqtemp() {
- substdio_putsflush(subfderr,"qlist: fatal: temporary qmail-queue error\n"); die_temp(); }
-void die_usage() {
- substdio_putsflush(subfderr,
- "qlist: usage: qlist user-list@host user-list-request@host .qmail-list .qmail-list-request .qtemp-list owner [moreinfo]\n"); die(); }
-void die_read() {
- if (errno == error_nomem) die_nomem();
- substdio_putsflush(subfderr,"qlist: fatal: read error\n"); die_temp(); }
-void doordie(sa,r) stralloc *sa; int r; {
- if (r == 1) return; if (r == -1) die_nomem();
- substdio_putsflush(subfderr,"qlist: fatal: unable to parse this: ");
- substdio_putflush(subfderr,sa->s,sa->len); die(); }
-
-int subjectaction = 0;
-int numcommands;
-
-int fdlock;
-
-struct qmail qqt;
-
-char *target;
-char *listathost;
-char *requestathost;
-char *qmaillist;
-char *qmailrequest;
-char *qtemplist;
-char *owner;
-char *moreinfo;
-
-char *dtline;
-char *returnpath;
-stralloc safrom = {0};
-stralloc sart = {0};
-
-int rwfrom(addr) token822_alloc *addr; { token822_reverse(addr);
- if (token822_unquote(&safrom,addr) != 1) die_nomem();
- token822_reverse(addr); return 1; }
-int rwrt(addr) token822_alloc *addr; { token822_reverse(addr);
- if (token822_unquote(&sart,addr) != 1) die_nomem();
- token822_reverse(addr); return 1; }
-
-GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
-GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
-static stralloc sauninit = {0}; saa savedh = {0};
-void savedh_append(h) stralloc *h; {
- if (!saa_readyplus(&savedh,1)) die_nomem(); savedh.sa[savedh.len] = sauninit;
- if (!stralloc_copy(savedh.sa + savedh.len,h)) die_nomem(); ++savedh.len; }
-void savedh_print() { int i; for (i = 0;i < savedh.len;++i)
- qmail_put(&qqt,savedh.sa[i].s,savedh.sa[i].len); }
-
-void finishheader()
-{
- int i;
-
- if (sart.s)
-  { if (!stralloc_0(&sart)) die_nomem(); target = sart.s; }
- else if (safrom.s)
-  { if (!stralloc_0(&safrom)) die_nomem(); target = safrom.s; }
- else
-   target = returnpath;
-
- for (i = 0;target[i];++i)
-   if (target[i] == '\n')
-     die_badaddr();
- if (i > ADDRLIMIT) die_badaddr();
- if (str_equal(target,"")) die_boing();
- if (str_equal(target,"#@[]")) die_boing();
-
- if (qmail_open(&qqt) == -1) die_fork();
-
- qmail_puts(&qqt,dtline);
- savedh_print();
-
- qmail_puts(&qqt,"\n***** Text inserted by ");
- qmail_puts(&qqt,requestathost);
- qmail_puts(&qqt,"\n\
-*\n\
-* Hi! This is the qlist program. I'm handling subscriptions for the\n\
-* ");
- qmail_puts(&qqt,listathost);
- qmail_puts(&qqt," mailing list.\n\
-*\n");
- if (moreinfo)
-  {
-   qmail_puts(&qqt,"* ");
-   qmail_puts(&qqt,moreinfo);
-   qmail_puts(&qqt,"\n*\n");
-  }
- qmail_puts(&qqt,"* My human owner is ");
- qmail_puts(&qqt,owner);
- qmail_puts(&qqt,".\n\
-*\n\
-* To the recipient: This message was sent to me on your behalf. (Your\n\
-* address was listed in the Reply-To or From field.) For security,\n\
-* I'm forwarding this message to you, along with my notes.\n\
-*\n\
-* Anyway, to subscribe, send me an empty message. To unsubscribe, send me\n\
-* a message with the word UNSUBSCRIBE at the beginning of a line. Remember,\n\
-* my address is ");
- qmail_puts(&qqt,requestathost);
- qmail_puts(&qqt,".\n\
-*\n\
-* Now I'll look for requests inside this message...\n\
-*\n\
-*****\n");
-}
-
-substdio subin; char subinbuf[SUBSTDIO_INSIZE];
-substdio subout; char suboutbuf[SUBSTDIO_OUTSIZE];
-stralloc subline = {0};
-void subscribe(flagadd)
-int flagadd;
-{
- int fdin;
- int fdout;
- int match;
- int flagwasthere;
-
- ++numcommands;
-
- if (lock_ex(fdlock) == -1) goto bad;
- fdin = open_read(qmaillist);
- if (fdin == -1) goto badlock;
- fdout = open_trunc(qtemplist);
- if (fdout == -1) goto badinlock;
- if (chmod(qtemplist,0700) == -1) goto badoutinlock;
-
- flagwasthere = 0;
-
- substdio_fdbuf(&subin,read,fdin,subinbuf,sizeof(subinbuf));
- substdio_fdbuf(&subout,write,fdout,suboutbuf,sizeof(suboutbuf));
- for (;;)
-  {
-   if (getln(&subin,&subline,&match,'\n') == -1) goto badoutinlock;
-   if (!match) break; /* goodbye partial lines */
-   if (subline.len == str_len(target) + 2)
-     if (!str_diffn(subline.s + 1,target,subline.len - 2))
-       if (subline.s[0] == '&')
-        {
-         flagwasthere = 1;
-         if (!flagadd)
-           continue;
-        }
-   if (substdio_put(&subout,subline.s,subline.len) == -1) goto badoutinlock;
-  }
-
- if (flagadd && !flagwasthere)
-  {
-   if (substdio_puts(&subout,"&") == -1) goto badoutinlock;
-   if (substdio_puts(&subout,target) == -1) goto badoutinlock;
-   if (substdio_puts(&subout,"\n") == -1) goto badoutinlock;
-  }
- if (substdio_flush(&subout) == -1) goto badoutinlock;
-
- close(fdout);
- close(fdin);
- if (rename(qtemplist,qmaillist) == -1) goto badlock;
- if (chmod(qmaillist,0500) == -1) goto badlock;
-
- lock_un(fdlock);
-
- qmail_puts(&qqt,"***** Text inserted by ");
- qmail_puts(&qqt,requestathost);
- qmail_puts(&qqt,"\n*\n* ");
- if (flagadd)
-   if (flagwasthere)
-    {
-     qmail_puts(&qqt,"Acknowledgment: ");
-     qmail_puts(&qqt,target);
-     qmail_puts(&qqt," was already a subscriber.\n");
-    }
-   else
-    {
-     qmail_puts(&qqt,"Acknowledgment: ");
-     qmail_puts(&qqt,target);
-     qmail_puts(&qqt," is now a subscriber.\n");
-    }
- else
-   if (flagwasthere)
-    {
-     qmail_puts(&qqt,"Acknowledgment: ");
-     qmail_puts(&qqt,target);
-     qmail_puts(&qqt," is no longer a subscriber.\n");
-    }
-   else
-    {
-     qmail_puts(&qqt,"Hmmm, I don't see ");
-     qmail_puts(&qqt,target);
-     qmail_puts(&qqt," on the subscription list.\n* I'll let my owner know.\n");
-    }
- qmail_puts(&qqt,"*\n*****\n");
- return;
-
-badoutinlock: close(fdout);
-badinlock: close(fdin);
-badlock: lock_un(fdlock);
-bad:
- qmail_puts(&qqt,"***** Text inserted by ");
- qmail_puts(&qqt,requestathost);
- qmail_puts(&qqt,"\n*\n\
-* Oh no! Trouble making the new list. I'll let my owner know.\n\
-*\n\
-*****\n");
-}
-
-void dobody(h) stralloc *h;
-{
- qmail_put(&qqt,h->s,h->len);
- if (case_starts(h->s,"subs")) subscribe(1);
- if (case_starts(h->s,"unsu")) subscribe(0);
-}
-
-stralloc hfbuf = {0};
-token822_alloc hfin = {0};
-token822_alloc hfrewrite = {0};
-token822_alloc hfaddr = {0};
-
-void doheaderfield(h)
-stralloc *h;
-{
- char *x;
- switch(hfield_known(h->s,h->len))
-  {
-   case H_CONTENTLENGTH: /* SVR4 silliness */
-   case H_CONTENTTYPE:
-   case H_CONTENTTRANSFERENCODING: /* A-bombs 4.2.1.5.2 is idiotic */
-     return;
-   case H_FROM:
-     doordie(h,token822_parse(&hfin,h,&hfbuf));
-     doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rwfrom));
-     break;
-   case H_REPLYTO:
-     doordie(h,token822_parse(&hfin,h,&hfbuf));
-     doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rwrt));
-     break;
-   case H_SUBJECT:
-     x = h->s + hfield_skipname(h->s,h->len);
-     if (!case_diffb(x,4,"subs")) subjectaction = 1;
-     if (!case_diffb(x,4,"unsu")) subjectaction = 2;
-     break;
-  }
- savedh_append(h);
-}
-
-void main(argc,argv)
-int argc;
-char **argv;
-{
- sig_pipeignore();
-
- if (!(listathost = argv[1])) die_usage();
- if (!(requestathost = argv[2])) die_usage();
- if (!(qmaillist = argv[3])) die_usage();
- if (!(qmailrequest = argv[4])) die_usage();
- if (!(qtemplist = argv[5])) die_usage();
- if (!(owner = argv[6])) die_usage();
- moreinfo = argv[7];
- if (!(returnpath = env_get("NEWSENDER"))) die_usage();
- if (!(dtline = env_get("DTLINE"))) die_usage();
-
- fdlock = open_append(qmailrequest);
- if (fdlock == -1) die_nolock();
-
- numcommands = 0;
- if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) die_read();
- if (!numcommands)
-  {
-   qmail_puts(&qqt,"***** Text inserted by ");
-   qmail_puts(&qqt,requestathost);
-   qmail_puts(&qqt,"\n*\n* ");
-   if (subjectaction)
-    {
-     qmail_puts(&qqt,"\
-Hmmm, no commands? Let me check the Subject line...\n*\n*****\n");
-     subscribe(subjectaction == 1);
-    }
-   else
-    {
-     qmail_puts(&qqt,"\
-I didn't see any commands. I presume this is a subscription request.\n\
-*\n*****\n");
-     subscribe(1);
-    }
-  }
-
- qmail_from(&qqt,returnpath);
- qmail_to(&qqt,owner);
- qmail_to(&qqt,target);
-
- switch(qmail_close(&qqt))
-  {
-   case 0: _exit(0);
-   case QMAIL_TOOLONG: die_qqperm();
-   default: die_qqtemp();
-  }
-}
diff --git a/qlist2.sh b/qlist2.sh
deleted file mode 100644 (file)
index 9e31a2a..0000000
--- a/qlist2.sh
+++ /dev/null
@@ -1 +0,0 @@
-exec QMAIL/bin/qlist "$USERBREAK$1@$2" "$USERBREAK$1-request@$2" .qmail-"$1" .qmail-"$1"-request .qtemp-"$1" "$USERBREAK$1-owner" ${3+"$3"}
index c22180e..ad46377 100644 (file)
@@ -37,7 +37,7 @@ file, so it is not safe for
 .I command
 to fork a child that
 reads the message in the background while the parent exits.
-
+.SH "EXIT CODES"
 .IR command 's
 exit codes are interpreted as follows:
 0 means that the delivery was successful;
@@ -48,15 +48,21 @@ should ignore all further delivery instructions;
 100 means that the delivery failed permanently (hard error);
 111 means that the delivery failed but should be tried again
 in a little while (soft error).
+
 Currently 64, 65, 70, 76, 77, 78, and 112 are considered hard errors,
 and all other codes are considered soft errors,
 but
 .I command
 should avoid relying on this.
-
+.SH "ENVIRONMENT VARIABLES"
 .B qmail-local
 supplies several useful environment variables to
 .IR command .
+.B WARNING:
+These environment variables are not quoted.
+They may contain special characters.
+They are under the control of a possibly malicious remote user.
+
 .B SENDER
 is the envelope sender address.
 .B NEWSENDER
@@ -82,9 +88,22 @@ is the
 part.
 .B EXT
 is the
-.B .qmail
-extension,
+address extension,
 .IR ext .
+
+.B HOST2
+is the portion of
+.B HOST
+preceding the last dot;
+.B HOST3
+is the portion of
+.B HOST
+preceding the second-to-last dot;
+.B HOST4
+is the portion of
+.B HOST
+preceding the third-to-last dot.
+
 .B EXT2
 is the portion of
 .B EXT
@@ -95,6 +114,18 @@ following the second dash;
 .B EXT4
 is the portion
 following the third dash.
+.B DEFAULT
+is the portion
+corresponding to the
+.B default
+part of the
+.BR .qmail\- ...
+file name;
+.B DEFAULT
+is not set if
+the file name does not end with
+.BR default .
+
 .B DTLINE
 and
 .B RPLINE
@@ -112,11 +143,6 @@ line that
 adds to
 .IR mbox -format
 files.
-
-.B WARNING:
-These environment variables are not quoted.
-They may contain special characters.
-They are under the control of a possibly malicious remote user.
 .SH "SEE ALSO"
 dot-qmail(5),
 envelopes(5),
index 7474a33..503ce93 100644 (file)
@@ -23,6 +23,7 @@ in
 .IR badmailfrom ,
 .IR locals ,
 .IR percenthack ,
+.IR qmqpservers ,
 .IR rcpthosts ,
 .IR smtproutes ,
 and
@@ -46,6 +47,7 @@ control       default used by
 .I concurrencyremote   \fR20   \fRqmail-send
 .I defaultdomain       \fIme   \fRqmail-inject
 .I defaulthost \fIme   \fRqmail-inject
+.I databytes   \fR0    \fRqmail-smtpd
 .I doublebouncehost    \fIme   \fRqmail-send
 .I doublebounceto      \fRpostmaster   \fRqmail-send
 .I envnoathost \fIme   \fRqmail-send
@@ -53,11 +55,12 @@ control     default used by
 .I idhost      \fIme   \fRqmail-inject
 .I localiphost \fIme   \fRqmail-smtpd
 .I locals      \fIme   \fRqmail-send
+.I morercpthosts       \fR(none)       \fRqmail-smtpd
 .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 recipientmap        \fR(none)       \fRqmail-send
 .I smtpgreeting        \fIme   \fRqmail-smtpd
 .I smtproutes  \fR(none)       \fRqmail-remote
 .I timeoutconnect      \fR60   \fRqmail-remote
@@ -68,6 +71,7 @@ control       default used by
 .RE
 .SH "SEE ALSO"
 qmail-inject(8),
+qmail-qmqpc(8),
 qmail-remote(8),
 qmail-send(8),
 qmail-showctl(8),
index 86befb2..0f12e1c 100644 (file)
@@ -42,7 +42,12 @@ The operating system's
 .B getpwnam
 function, which is at the heart of
 .BR qmail-getpw ,
-is inherently unreliable.
+is inherently unreliable:
+it fails to distinguish between temporary errors and nonexistent users.
+Future versions of
+.B getpwnam
+should return ETXTBSY to indicate temporary errors
+and ESRCH to indicate nonexistent users.
 .SH "RULES"
 .B qmail-getpw
 considers an account in
index 4833aac..128c682 100644 (file)
@@ -33,7 +33,9 @@ int userext()
        byte_copy(username,extension - local,local);
        username[extension - local] = 0;
        case_lowers(username);
+       errno = 0;
        pw = getpwnam(username);
+       if (errno == error_txtbsy) _exit(QLX_SYS);
        if (pw)
          if (pw->pw_uid)
            if (stat(pw->pw_dir,&st) == 0) {
index f15c850..d90323a 100644 (file)
@@ -11,7 +11,8 @@ The main function of
 .B qmail-inject
 is to make sure that each outgoing message has an appropriate header.
 
-For more detailed information, see RFC 822 and RFC 1123.
+For more detailed information, see
+.BR http://pobox.com/~djb/proto/immhf.html .
 .SH "MESSAGE STRUCTURE"
 A message contains a series of
 .I header fields\fR,
@@ -239,7 +240,7 @@ does not create any
 fields.
 .SH "RESENT MESSAGES"
 A message is
-.I forwarded
+.I resent
 if it contains any of the following fields:
 .BR Resent-Sender ,
 .BR Resent-From ,
@@ -250,7 +251,7 @@ if it contains any of the following fields:
 .BR Resent-Date ,
 .BR Resent-Message-ID .
 
-If a message is forwarded,
+If a message is resent,
 .B qmail-inject
 changes its behavior as follows.
 
diff --git a/qmail-hier.c b/qmail-hier.c
deleted file mode 100644 (file)
index eff007e..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#include "subfd.h"
-#include "substdio.h"
-#include "auto_split.h"
-#include "auto_uids.h"
-#include "fmt.h"
-
-char strnum[FMT_ULONG];
-
-void uidgid(uid)
-int uid;
-{
-  substdio_put(subfdout,strnum,fmt_ulong(strnum,(unsigned long) uid));
-  substdio_puts(subfdout,":");
-  substdio_put(subfdout,strnum,fmt_ulong(strnum,(unsigned long) auto_gidq));
-  substdio_puts(subfdout,":");
-}
-
-void copy(uid,mode,sub,fn)
-int uid;
-char *mode;
-char *sub;
-char *fn;
-{
-  substdio_puts(subfdout,"c:");
-  uidgid(uid);
-  substdio_puts(subfdout,mode);
-  substdio_puts(subfdout,":");
-  substdio_puts(subfdout,sub);
-  substdio_puts(subfdout,":");
-  substdio_puts(subfdout,fn);
-  substdio_puts(subfdout,":\n");
-}
-
-void dir(uid,mode,fn)
-int uid;
-char *mode;
-char *fn;
-{
-  substdio_puts(subfdout,"d:");
-  uidgid(uid);
-  substdio_puts(subfdout,mode);
-  substdio_puts(subfdout,":");
-  substdio_puts(subfdout,fn);
-  substdio_puts(subfdout,"::\n");
-}
-
-void dirsplit(uid,mode,fn)
-int uid;
-char *mode;
-char *fn;
-{
-  unsigned long i;
-  dir(uid,mode,fn);
-  for (i = 0;i < auto_split;++i) {
-    substdio_puts(subfdout,"d:");
-    uidgid(uid);
-    substdio_puts(subfdout,mode);
-    substdio_puts(subfdout,":");
-    substdio_puts(subfdout,fn);
-    substdio_puts(subfdout,":/");
-    substdio_put(subfdout,strnum,fmt_ulong(strnum,i));
-    substdio_puts(subfdout,":\n");
-  }
-}
-
-void main()
-{
-  dir(auto_uido,"755","");
-  dir(auto_uido,"755","/control");
-  dir(auto_uido,"755","/users");
-  dir(auto_uido,"755","/bin");
-  dir(auto_uido,"755","/man");
-  dir(auto_uido,"755","/man/cat1");
-  dir(auto_uido,"755","/man/cat5");
-  dir(auto_uido,"755","/man/cat7");
-  dir(auto_uido,"755","/man/cat8");
-  dir(auto_uido,"755","/man/man1");
-  dir(auto_uido,"755","/man/man5");
-  dir(auto_uido,"755","/man/man7");
-  dir(auto_uido,"755","/man/man8");
-
-  dir(auto_uida,"755","/alias");
-  dir(auto_uidq,"750","/queue");
-  dir(auto_uidq,"700","/queue/pid");
-  dir(auto_uidq,"700","/queue/intd");
-  dir(auto_uidq,"750","/queue/todo");
-  dir(auto_uidq,"750","/queue/lock");
-  dir(auto_uids,"700","/queue/bounce");
-
-  substdio_puts(subfdout,"z0:");
-  uidgid(auto_uids);
-  substdio_puts(subfdout,"600:/queue/lock/:sendmutex:\n");
-
-  substdio_puts(subfdout,"z1024:");
-  uidgid(auto_uidr);
-  substdio_puts(subfdout,"644:/queue/lock/:tcpto:\n");
-
-  substdio_puts(subfdout,"p:");
-  uidgid(auto_uids);
-  substdio_puts(subfdout,"622:/queue/lock/:trigger:\n");
-
-  dirsplit(auto_uidq,"750","/queue/mess");
-  dirsplit(auto_uids,"700","/queue/info");
-  dirsplit(auto_uids,"700","/queue/local");
-  dirsplit(auto_uids,"700","/queue/remote");
-
-  copy(auto_uidq,"4711","/bin/","qmail-queue");
-  copy(auto_uido,"700","/bin/","qmail-lspawn");
-  copy(auto_uido,"700","/bin/","qmail-start");
-  copy(auto_uido,"711","/bin/","qmail-getpw");
-  copy(auto_uido,"711","/bin/","qmail-local");
-  copy(auto_uido,"711","/bin/","qmail-remote");
-  copy(auto_uido,"711","/bin/","qmail-rspawn");
-  copy(auto_uido,"711","/bin/","qmail-clean");
-  copy(auto_uido,"711","/bin/","qmail-send");
-  copy(auto_uido,"711","/bin/","splogger");
-  copy(auto_uido,"700","/bin/","qmail-newu");
-  copy(auto_uido,"711","/bin/","qmail-pw2u");
-  copy(auto_uido,"755","/bin/","qmail-inject");
-  copy(auto_uido,"755","/bin/","predate");
-  copy(auto_uido,"755","/bin/","datemail");
-  copy(auto_uido,"755","/bin/","mailsubj");
-  copy(auto_uido,"755","/bin/","qmail-showctl");
-  copy(auto_uido,"755","/bin/","qmail-qread");
-  copy(auto_uido,"755","/bin/","qmail-qstat");
-  copy(auto_uido,"755","/bin/","qmail-tcpto");
-  copy(auto_uido,"755","/bin/","qmail-pop3d");
-  copy(auto_uido,"700","/bin/","qmail-popup");
-  copy(auto_uido,"755","/bin/","qmail-qmtpd");
-  copy(auto_uido,"755","/bin/","qmail-smtpd");
-  copy(auto_uido,"755","/bin/","sendmail");
-  copy(auto_uido,"755","/bin/","tcp-env");
-  copy(auto_uido,"755","/bin/","qlist");
-  copy(auto_uido,"755","/bin/","qlist2");
-  copy(auto_uido,"755","/bin/","qreceipt");
-  copy(auto_uido,"755","/bin/","qsmhook");
-  copy(auto_uido,"755","/bin/","qbiff");
-  copy(auto_uido,"755","/bin/","forward");
-  copy(auto_uido,"755","/bin/","preline");
-  copy(auto_uido,"755","/bin/","condredirect");
-  copy(auto_uido,"755","/bin/","maildirmake");
-  copy(auto_uido,"755","/bin/","maildir2mbox");
-  copy(auto_uido,"755","/bin/","maildirwatch");
-  copy(auto_uido,"755","/bin/","qail");
-  copy(auto_uido,"755","/bin/","elq");
-  copy(auto_uido,"755","/bin/","pinq");
-
-  copy(auto_uido,"644","/man/man5/","addresses.5");
-  copy(auto_uido,"644","/man/cat5/","addresses.0");
-  copy(auto_uido,"644","/man/man5/","envelopes.5");
-  copy(auto_uido,"644","/man/cat5/","envelopes.0");
-  copy(auto_uido,"644","/man/man5/","maildir.5");
-  copy(auto_uido,"644","/man/cat5/","maildir.0");
-  copy(auto_uido,"644","/man/man5/","mbox.5");
-  copy(auto_uido,"644","/man/cat5/","mbox.0");
-  copy(auto_uido,"644","/man/man5/","dot-qmail.5");
-  copy(auto_uido,"644","/man/cat5/","dot-qmail.0");
-  copy(auto_uido,"644","/man/man5/","qmail-control.5");
-  copy(auto_uido,"644","/man/cat5/","qmail-control.0");
-  copy(auto_uido,"644","/man/man5/","qmail-header.5");
-  copy(auto_uido,"644","/man/cat5/","qmail-header.0");
-  copy(auto_uido,"644","/man/man5/","qmail-log.5");
-  copy(auto_uido,"644","/man/cat5/","qmail-log.0");
-  copy(auto_uido,"644","/man/man5/","qmail-users.5");
-  copy(auto_uido,"644","/man/cat5/","qmail-users.0");
-  copy(auto_uido,"644","/man/man5/","tcp-environ.5");
-  copy(auto_uido,"644","/man/cat5/","tcp-environ.0");
-
-  copy(auto_uido,"644","/man/man7/","forgeries.7");
-  copy(auto_uido,"644","/man/cat7/","forgeries.0");
-  copy(auto_uido,"644","/man/man7/","qmail-limits.7");
-  copy(auto_uido,"644","/man/cat7/","qmail-limits.0");
-  copy(auto_uido,"644","/man/man7/","qmail-upgrade.7");
-  copy(auto_uido,"644","/man/cat7/","qmail-upgrade.0");
-  copy(auto_uido,"644","/man/man7/","qmail.7");
-  copy(auto_uido,"644","/man/cat7/","qmail.0");
-
-  copy(auto_uido,"644","/man/man1/","forward.1");
-  copy(auto_uido,"644","/man/cat1/","forward.0");
-  copy(auto_uido,"644","/man/man1/","condredirect.1");
-  copy(auto_uido,"644","/man/cat1/","condredirect.0");
-  copy(auto_uido,"644","/man/man1/","maildirmake.1");
-  copy(auto_uido,"644","/man/cat1/","maildirmake.0");
-  copy(auto_uido,"644","/man/man1/","maildir2mbox.1");
-  copy(auto_uido,"644","/man/cat1/","maildir2mbox.0");
-  copy(auto_uido,"644","/man/man1/","maildirwatch.1");
-  copy(auto_uido,"644","/man/cat1/","maildirwatch.0");
-  copy(auto_uido,"644","/man/man1/","mailsubj.1");
-  copy(auto_uido,"644","/man/cat1/","mailsubj.0");
-  copy(auto_uido,"644","/man/man1/","qlist.1");
-  copy(auto_uido,"644","/man/cat1/","qlist.0");
-  copy(auto_uido,"644","/man/man1/","qreceipt.1");
-  copy(auto_uido,"644","/man/cat1/","qreceipt.0");
-  copy(auto_uido,"644","/man/man1/","qbiff.1");
-  copy(auto_uido,"644","/man/cat1/","qbiff.0");
-  copy(auto_uido,"644","/man/man1/","preline.1");
-  copy(auto_uido,"644","/man/cat1/","preline.0");
-  copy(auto_uido,"644","/man/man1/","tcp-env.1");
-  copy(auto_uido,"644","/man/cat1/","tcp-env.0");
-
-  copy(auto_uido,"644","/man/man8/","qmail-local.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-local.0");
-  copy(auto_uido,"644","/man/man8/","qmail-lspawn.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-lspawn.0");
-  copy(auto_uido,"644","/man/man8/","qmail-getpw.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-getpw.0");
-  copy(auto_uido,"644","/man/man8/","qmail-remote.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-remote.0");
-  copy(auto_uido,"644","/man/man8/","qmail-rspawn.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-rspawn.0");
-  copy(auto_uido,"644","/man/man8/","qmail-clean.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-clean.0");
-  copy(auto_uido,"644","/man/man8/","qmail-send.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-send.0");
-  copy(auto_uido,"644","/man/man8/","qmail-start.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-start.0");
-  copy(auto_uido,"644","/man/man8/","splogger.8");
-  copy(auto_uido,"644","/man/cat8/","splogger.0");
-  copy(auto_uido,"644","/man/man8/","qmail-queue.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-queue.0");
-  copy(auto_uido,"644","/man/man8/","qmail-inject.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-inject.0");
-  copy(auto_uido,"644","/man/man8/","qmail-showctl.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-showctl.0");
-  copy(auto_uido,"644","/man/man8/","qmail-newu.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-newu.0");
-  copy(auto_uido,"644","/man/man8/","qmail-pw2u.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-pw2u.0");
-  copy(auto_uido,"644","/man/man8/","qmail-qread.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-qread.0");
-  copy(auto_uido,"644","/man/man8/","qmail-qstat.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-qstat.0");
-  copy(auto_uido,"644","/man/man8/","qmail-tcpto.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-tcpto.0");
-  copy(auto_uido,"644","/man/man8/","qmail-pop3d.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-pop3d.0");
-  copy(auto_uido,"644","/man/man8/","qmail-popup.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-popup.0");
-  copy(auto_uido,"644","/man/man8/","qmail-qmtpd.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-qmtpd.0");
-  copy(auto_uido,"644","/man/man8/","qmail-smtpd.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-smtpd.0");
-  copy(auto_uido,"644","/man/man8/","qmail-command.8");
-  copy(auto_uido,"644","/man/cat8/","qmail-command.0");
-
-  substdio_flush(subfdout);
-  _exit(0);
-}
index 3a05328..59e11a7 100644 (file)
@@ -76,6 +76,21 @@ and
 letters described below.
 Bounces will be sent to this address.
 
+If
+.B QMAILMFTFILE
+is set,
+.B qmail-inject
+reads a list of mailing list addresses,
+one per line,
+from that file.
+If To+Cc includes one of those addresses (without regard to case),
+.B qmail-inject
+adds a Mail-Followup-To field
+with all the To+Cc addresses.
+.B qmail-inject
+does not add Mail-Followup-To
+to a message that already has one.
+
 The
 .B QMAILINJECT
 environment variable
index d6083a7..753c18a 100644 (file)
@@ -21,6 +21,7 @@
 #include "headerbody.h"
 #include "auto_qmail.h"
 #include "newfield.h"
+#include "constmap.h"
 
 #define LINELEN 80
 
@@ -63,14 +64,10 @@ void die_nomem() {
 void die_invalid(sa) stralloc *sa; {
  substdio_putsflush(subfderr,"qmail-inject: fatal: invalid header field: ");
  substdio_putflush(subfderr,sa->s,sa->len); perm(); }
-void die_exec() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: unable to exec qmail-queue\n"); temp(); }
 void die_qqt() {
  substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); }
 void die_chdir() {
  substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
-void die_bug() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
 void die_read() {
  if (errno == error_nomem) die_nomem();
  substdio_putsflush(subfderr,"qmail-inject: fatal: read error\n"); temp(); }
@@ -79,19 +76,6 @@ void doordie(sa,r) stralloc *sa; int r; {
  substdio_putsflush(subfderr,"qmail-inject: fatal: unable to parse this line:\n");
  substdio_putflush(subfderr,sa->s,sa->len); perm(); }
 
-void die_comm() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue lost communications link\n"); temp(); }
-void die_qq() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue died\n"); temp(); }
-void die_qqwrite() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue unable to write message to disk; disk full?\n"); temp(); }
-void die_qqsig() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue was killed\n"); temp(); }
-void die_qqtimeout() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue timed out\n"); temp(); }
-void die_qqtoolong() {
- substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue unhappy with long addresses\n"); perm(); }
-
 GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
 GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
 
@@ -99,12 +83,15 @@ static stralloc sauninit = {0};
 
 saa savedh = {0};
 saa hrlist = {0};
+saa tocclist = {0};
 saa hrrlist = {0};
 saa reciplist = {0};
 int flagresent;
 
 void exitnicely()
 {
+ char *qqx;
+
  if (!flagqueue) substdio_flush(subfdout);
 
  if (flagqueue)
@@ -133,19 +120,22 @@ void exitnicely()
         qmail_to(&qqt,hrlist.sa[i].s);
        }
 
-   switch(qmail_close(&qqt))
-    {
-     case 0: break;
-     case QMAIL_CRASHED: die_qqsig();
-     case QMAIL_USAGE: case QMAIL_BUG: die_bug();
-     case QMAIL_EXECSOFT: die_exec();
-     case QMAIL_NOMEM: die_nomem();
-     case QMAIL_READ: die_comm();
-     case QMAIL_WRITE: die_qqwrite();
-     case QMAIL_TOOLONG: die_qqtoolong();
-     case QMAIL_TIMEOUT: die_qqtimeout();
-     default: die_qq();
-    }
+   qqx = qmail_close(&qqt);
+   if (*qqx)
+     if (*qqx == 'D') {
+       substdio_puts(subfderr,"qmail-inject: fatal: ");
+       substdio_puts(subfderr,qqx + 1);
+       substdio_puts(subfderr,"\n");
+       substdio_flush(subfderr);
+       perm();
+     }
+     else {
+       substdio_puts(subfderr,"qmail-inject: fatal: ");
+       substdio_puts(subfderr,qqx + 1);
+       substdio_puts(subfderr,"\n");
+       substdio_flush(subfderr);
+       temp();
+     }
   }
 
  _exit(0);
@@ -324,11 +314,10 @@ token822_alloc *addr;
  return 1;
 }
 
-void rwrecip(addr,xl)
+void rwappend(addr,xl)
 token822_alloc *addr;
 saa *xl;
 {
- rwgeneric(addr);
  token822_reverse(addr);
  if (!saa_readyplus(xl,1)) die_nomem();
  xl->sa[xl->len] = sauninit;
@@ -338,9 +327,11 @@ saa *xl;
 }
 
 int rwhrr(addr) token822_alloc *addr;
-{ rwrecip(addr,&hrrlist); return 1; }
+{ rwgeneric(addr); rwappend(addr,&hrrlist); return 1; }
 int rwhr(addr) token822_alloc *addr;
-{ rwrecip(addr,&hrlist); return 1; }
+{ rwgeneric(addr); rwappend(addr,&hrlist); return 1; }
+int rwtocc(addr) token822_alloc *addr;
+{ rwgeneric(addr); rwappend(addr,&hrlist); rwappend(addr,&tocclist); return 1; }
 
 int htypeseen[H_NUM];
 stralloc hfbuf = {0};
@@ -351,51 +342,47 @@ token822_alloc hfaddr = {0};
 void doheaderfield(h)
 stralloc *h;
 {
- int htype;
- int flagrewrite;
- int flagrecip;
- int flagrr;
-
- htype = hfield_known(h->s,h->len);
- if (flagdeletefrom) if (htype == H_FROM) return;
- if (flagdeletemessid) if (htype == H_MESSAGEID) return;
- if (flagdeletesender) if (htype == H_RETURNPATH) return;
-
- if (htype)
-   htypeseen[htype] = 1;
- else
-   if (!hfield_valid(h->s,h->len))
-     die_invalid(h);
-
- flagrewrite = 0;
- flagrecip = 0;
- flagrr = 0;
- switch(htype)
-  {
-   case H_R_TO: case H_R_CC: case H_R_BCC:
-     flagrr = 1;
-   case H_TO: case H_CC: case H_BCC: case H_APPARENTLYTO:
-     flagrecip = 1;
-   case H_SENDER: case H_FROM: case H_REPLYTO:
-   case H_RETURNRECEIPTTO: case H_ERRORSTO: case H_RETURNPATH:
-   case H_R_SENDER: case H_R_FROM: case H_R_REPLYTO:
-     flagrewrite = 1;
-     break;
+  int htype;
+  int (*rw)() = 0;
+  htype = hfield_known(h->s,h->len);
+  if (flagdeletefrom) if (htype == H_FROM) return;
+  if (flagdeletemessid) if (htype == H_MESSAGEID) return;
+  if (flagdeletesender) if (htype == H_RETURNPATH) return;
+  if (htype)
+    htypeseen[htype] = 1;
+  else
+    if (!hfield_valid(h->s,h->len))
+      die_invalid(h);
+  switch(htype) {
+    case H_TO: case H_CC:
+      rw = rwtocc; break;
+    case H_BCC: case H_APPARENTLYTO:
+      rw = rwhr; break;
+    case H_R_TO: case H_R_CC: case H_R_BCC:
+      rw = rwhrr; break;
+    case H_RETURNPATH:
+      rw = rwreturn; break;
+    case H_SENDER: case H_FROM: case H_REPLYTO:
+    case H_RETURNRECEIPTTO: case H_ERRORSTO:
+    case H_R_SENDER: case H_R_FROM: case H_R_REPLYTO:
+      rw = rwsender; break;
   }
 
- if (flagrewrite)
-  {
-   doordie(h,token822_parse(&hfin,h,&hfbuf));
-   doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,(htype == H_RETURNPATH) ? rwreturn : (flagrecip ? (flagrr ? rwhrr : rwhr) : rwsender)));
-   if (token822_unparse(h,&hfrewrite,LINELEN) != 1)
-     die_nomem();
+  if (rw) {
+    doordie(h,token822_parse(&hfin,h,&hfbuf));
+    doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rw));
+    if (token822_unparse(h,&hfrewrite,LINELEN) != 1)
+      die_nomem();
   }
-
- if (htype == H_BCC) return;
- if (htype == H_R_BCC) return;
- if (htype == H_RETURNPATH) return;
- if (htype == H_CONTENTLENGTH) return; /* some things are just too stupid */
- savedh_append(h);
 if (htype == H_BCC) return;
 if (htype == H_R_BCC) return;
 if (htype == H_RETURNPATH) return;
 if (htype == H_CONTENTLENGTH) return; /* some things are just too stupid */
 savedh_append(h);
 }
 
 void dobody(h)
@@ -421,7 +408,8 @@ char *s;
      perm();
   }
  token822_reverse(&tr);
- rwrecip(&tr,&reciplist);
+ rwgeneric(&tr);
+ rwappend(&tr,&reciplist);
 }
 
 stralloc defaultfrom = {0};
@@ -526,6 +514,53 @@ void dodefaultreturnpath()
  if (token822_unparse(&defaultreturnpath,&hfrewrite,LINELEN) != 1) die_nomem();
 }
 
+int flagmft = 0;
+stralloc mft = {0};
+struct constmap mapmft;
+
+void mft_init()
+{
+  char *x;
+  int r;
+
+  x = env_get("QMAILMFTFILE");
+  if (!x) return;
+
+  r = control_readfile(&mft,x,0);
+  if (r == -1) die_read(); /*XXX*/
+  if (!r) return;
+
+  if (!constmap_init(&mapmft,mft.s,mft.len,0)) die_nomem();
+  flagmft = 1;
+}
+
+void finishmft()
+{
+  int i;
+  static stralloc sa = {0};
+  static stralloc sa2 = {0};
+
+  if (!flagmft) return;
+  if (htypeseen[H_MAILFOLLOWUPTO]) return;
+
+  for (i = 0;i < tocclist.len;++i)
+    if (constmap(&mapmft,tocclist.sa[i].s,tocclist.sa[i].len))
+      break;
+
+  if (i == tocclist.len) return;
+
+  puts("Mail-Followup-To: ");
+  i = tocclist.len;
+  while (i--) {
+    if (!stralloc_copy(&sa,&tocclist.sa[i])) die_nomem();
+    if (!stralloc_0(&sa)) die_nomem();
+    if (!quote2(&sa2,sa.s)) die_nomem();
+    put(sa2.s,sa2.len);
+    if (i) puts(",\n  ");
+  }
+  puts("\n");
+}
+
 void finishheader()
 {
  flagresent =
@@ -596,6 +631,7 @@ void finishheader()
     }
    if (!htypeseen[H_TO] && !htypeseen[H_CC])
      puts("Cc: recipient list not shown: ;\n");
+   finishmft();
   }
 
  savedh_print();
@@ -606,6 +642,9 @@ void getcontrols()
  static stralloc sa = {0};
  char *x;
 
+ mft_init();
+
+ if (chdir(auto_qmail) == -1) die_chdir();
  if (control_init() == -1) die_read();
 
  if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1)
@@ -688,11 +727,10 @@ char **argv;
  recipstrategy = RECIP_DEFAULT;
  flagqueue = 1;
 
- if (chdir(auto_qmail) == -1)
-   die_chdir();
  getcontrols();
 
  if (!saa_readyplus(&hrlist,1)) die_nomem();
+ if (!saa_readyplus(&tocclist,1)) die_nomem();
  if (!saa_readyplus(&hrrlist,1)) die_nomem();
  if (!saa_readyplus(&reciplist,1)) die_nomem();
 
index 847c39c..c047697 100644 (file)
@@ -13,7 +13,7 @@ qmail-local \- deliver or forward a mail message
 .I ext
 .I domain
 .I sender
-.I aliasempty
+.I defaultdelivery
 .SH DESCRIPTION
 .B qmail-local
 reads a mail message
@@ -69,7 +69,7 @@ treats a nonexistent
 the same way as an empty
 .BR .qmail\fIext :
 namely, following the delivery instructions in
-.IR aliasempty .
+.IR defaultdelivery .
 
 The standard input for
 .B qmail-local
index 5c441cf..cd01602 100644 (file)
@@ -12,6 +12,7 @@
 #include "seek.h"
 #include "substdio.h"
 #include "getln.h"
+#include "strerr.h"
 #include "subfd.h"
 #include "sgetopt.h"
 #include "alloc.h"
 #include "gfrom.h"
 #include "auto_patrn.h"
 
-void err(s) char *s; { substdio_putsflush(subfderr,s); }
-void soft() { _exit(111); }
-void hard() { _exit(100); }
-
-void temp_childcrashed() { err("Aack, child crashed. (#4.3.0)\n"); soft(); }
-void temp_rewind() { err("Unable to rewind message. (#4.3.0)\n"); soft(); }
-void temp_fork() { err("Unable to fork. (#4.3.0)\n"); soft(); }
-void temp_read() { err("Error while reading message. (#4.3.0)\n"); soft(); }
-void temp_write() { err("Error while writing message. (#4.3.0)\n"); soft(); }
-void temp_child() { err("Temporary error in forwarding message. (#4.3.0)\n"); soft(); }
-void temp_maildirtimeout() { err("Timeout on maildir delivery. (#4.3.0)\n"); soft(); }
-void temp_maildir() { err("Temporary error on maildir delivery. (#4.3.0)\n"); soft(); }
-void temp_nomaildir() { err("Unable to chdir to maildir. (#4.2.1)\n"); soft(); }
-void temp_open(fn) char *fn; { err("Unable to open "); err(fn); err(". (#4.2.1)\n"); soft(); }
-
-void temp_blankline() { err("Uh-oh: first line of .qmail file is blank. (#4.2.1)\n"); soft(); }
-void temp_fofile() { err("Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)\n"); soft(); }
-void temp_foprog() { err("Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)\n"); soft(); }
-void temp_nomem() { err("Out of memory. (#4.3.0)\n"); soft(); }
-void temp_chdir() { err("Unable to switch to home directory. (#4.3.0)\n"); soft(); }
-void temp_homestat() { err("Unable to stat home directory. (#4.3.0)\n"); soft(); }
-void temp_homesticky() { err("Home directory is sticky: user is editing his .qmail file. (#4.2.1)\n"); soft(); }
-void temp_homewritable() { err("Uh-oh: home directory is writable. (#4.7.0)\n"); soft(); }
-void temp_qmwritable() { err("Uh-oh: .qmail file is writable. (#4.7.0)\n"); soft(); }
-void temp_nfsqmail() { err("Temporary error trying to open .qmail file. (#4.3.0)\n"); soft(); }
-void temp_denyqmail() { err("Permission error trying to open .qmail file. (#4.3.0)\n"); soft(); }
-void temp_slowlock() { err("File has been locked for 30 seconds straight. (#4.3.0)\n"); soft(); }
-
-void bounce_childperm() { err("Permanent error in forwarding message. (#5.2.4)\n"); hard(); }
-void bounce_loop() { err("This message is looping: it already has my Delivered-To line. (#5.4.6)\n"); hard(); }
-void bounce_ext() { err("Sorry, no mailbox here by that name. (#5.1.1)\n"); hard(); }
-void usage() { err("qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty\n"); hard(); }
-
-void warn_homesticky() { err("Warning: home directory is sticky.\n"); }
+void usage() { strerr_die1x(100,"qmail-local: usage: qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
+
+void temp_nomem() { strerr_die1x(111,"Out of memory. (#4.3.0)"); }
+void temp_rewind() { strerr_die1x(111,"Unable to rewind message. (#4.3.0)"); }
+void temp_childcrashed() { strerr_die1x(111,"Aack, child crashed. (#4.3.0)"); }
+void temp_fork() { strerr_die3x(111,"Unable to fork: ",error_str(errno),". (#4.3.0)"); }
+void temp_read() { strerr_die3x(111,"Unable to read message: ",error_str(errno),". (#4.3.0)"); }
+void temp_slowlock()
+{ strerr_die1x(111,"File has been locked for 30 seconds straight. (#4.3.0)"); }
+void temp_qmail(fn) char *fn;
+{ strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.3.0)"); }
 
 int flagdoit;
 int flag99;
@@ -75,7 +53,7 @@ char *host;
 char *sender;
 char *aliasempty;
 
-stralloc dashext = {0};
+stralloc safeext = {0};
 stralloc ufline = {0};
 stralloc rpline = {0};
 stralloc envrecip = {0};
@@ -172,7 +150,7 @@ char *fn;
      temp_fork();
    case 0:
      maildir_child(fn);
-     soft();
+     _exit(111);
   }
 
  wait_pid(&wstat,child);
@@ -181,15 +159,13 @@ char *fn;
  switch(wait_exitcode(wstat))
   {
    case 0: break;
-   case 2: temp_nomaildir();
-   case 3: temp_maildirtimeout();
-   case 4: temp_read();
-   default: temp_maildir();
+   case 2: strerr_die1x(111,"Unable to chdir to maildir. (#4.2.1)");
+   case 3: strerr_die1x(111,"Timeout on maildir delivery. (#4.3.0)");
+   case 4: strerr_die1x(111,"Unable to read message. (#4.3.0)");
+   default: strerr_die1x(111,"Temporary error on maildir delivery. (#4.3.0)");
   }
 }
 
-void slowlock() { temp_slowlock(); }
-
 void mailfile(fn)
 char *fn;
 {
@@ -203,9 +179,10 @@ char *fn;
  if (seek_begin(0) == -1) temp_rewind();
 
  fd = open_append(fn);
- if (fd == -1) temp_open(fn);
+ if (fd == -1)
+   strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.2.1)");
 
- sig_alarmcatch(slowlock);
+ sig_alarmcatch(temp_slowlock);
  alarm(30);
  flaglocked = (lock_ex(fd) != -1);
  alarm(0);
@@ -222,7 +199,11 @@ char *fn;
  for (;;)
   {
    if (getln(&ss,&messline,&match,'\n') != 0) 
-    { if (flaglocked) seek_trunc(fd,pos); close(fd); temp_read(); }
+    {
+     strerr_warn3("Unable to read message: ",error_str(errno),". (#4.3.0)",0);
+     if (flaglocked) seek_trunc(fd,pos); close(fd);
+     _exit(111);
+    }
    if (!match && !messline.len) break;
    if (gfrom(messline.s,messline.len))
      if (substdio_bput(&ssout,">",1)) goto writeerrs;
@@ -240,9 +221,10 @@ char *fn;
  return;
 
  writeerrs:
+ strerr_warn5("Unable to write ",fn,": ",error_str(errno),". (#4.3.0)",0);
  if (flaglocked) seek_trunc(fd,pos);
  close(fd);
temp_write();
_exit(111);
 }
 
 void mailprogram(prog)
@@ -259,15 +241,10 @@ char *prog;
    case -1:
      temp_fork();
    case 0:
-     args[0] = "sh"; args[1] = "-c"; args[2] = prog; args[3] = 0;
+     args[0] = "/bin/sh"; args[1] = "-c"; args[2] = prog; args[3] = 0;
      sig_pipedefault();
-     execvp(*args,args);
-     if (errno == error_txtbsy) { err("Text busy. (#4.3.0)\n"); soft(); }
-     if (errno == error_nomem) { err("Out of memory. (#4.3.0)\n"); soft(); }
-     if (errno == error_io) { err("I/O error. (#4.3.0)\n"); soft(); }
-     if (error_temp(errno)) { err("Temporary error. (#4.3.0)\n"); soft(); }
-     err("Unable to execute "); err(*args); err(" (#5.2.4)\n");
-     hard();
+     execv(*args,args);
+     strerr_die3x(111,"Unable to run /bin/sh: ",error_str(errno),". (#4.3.0)");
   }
 
  wait_pid(&wstat,child);
@@ -276,10 +253,10 @@ char *prog;
  switch(wait_exitcode(wstat))
   {
    case 100:
-   case 64: case 65: case 70: case 76: case 77: case 78: case 112: hard();
+   case 64: case 65: case 70: case 76: case 77: case 78: case 112: _exit(100);
    case 0: break;
    case 99: flag99 = 1; break;
-   default: soft();
+   default: _exit(111);
   }
 }
 
@@ -289,6 +266,7 @@ void mailforward(recips)
 char **recips;
 {
  struct qmail qqt;
+ char *qqx;
  substdio ss;
  int match;
 
@@ -306,13 +284,9 @@ char **recips;
  while (match);
  qmail_from(&qqt,ueo.s);
  while (*recips) qmail_to(&qqt,*recips++);
- switch(qmail_close(&qqt))
-  {
-   case QMAIL_TOOLONG: bounce_childperm();
-   case QMAIL_READ: temp_read();
-   case 0: return;
-   default: temp_child();
-  }
+ qqx = qmail_close(&qqt);
+ if (!*qqx) return;
+ strerr_die3x(*qqx == 'D' ? 100 : 111,"Unable to forward message: ",qqx + 1,".");
 }
 
 void bouncexf()
@@ -330,7 +304,7 @@ void bouncexf()
      break;
    if (messline.len == dtline.len)
      if (!str_diffn(messline.s,dtline.s,dtline.len))
-       bounce_loop();
+       strerr_die1x(100,"This message is looping: it already has my Delivered-To line. (#5.4.6)");
   }
 }
 
@@ -338,10 +312,15 @@ void checkhome()
 {
  struct stat st;
 
- if (stat(".",&st) == -1) temp_homestat();
- if (st.st_mode & auto_patrn) temp_homewritable();
+ if (stat(".",&st) == -1)
+   strerr_die3x(111,"Unable to stat home directory: ",error_str(errno),". (#4.3.0)");
+ if (st.st_mode & auto_patrn)
+   strerr_die1x(111,"Uh-oh: home directory is writable. (#4.7.0)");
  if (st.st_mode & 01000)
-   if (flagdoit) temp_homesticky(); else warn_homesticky();
+   if (flagdoit)
+     strerr_die1x(111,"Home directory is sticky: user is editing his .qmail file. (#4.2.1)");
+   else
+     strerr_warn1("Warning: home directory is sticky.",0);
 }
 
 int qmeox(dashowner)
@@ -350,54 +329,86 @@ char *dashowner;
  struct stat st;
 
  if (!stralloc_copys(&qme,".qmail")) temp_nomem();
- if (!stralloc_cat(&qme,&dashext)) temp_nomem();
+ if (!stralloc_cats(&qme,dash)) temp_nomem();
+ if (!stralloc_cat(&qme,&safeext)) temp_nomem();
  if (!stralloc_cats(&qme,dashowner)) temp_nomem();
  if (!stralloc_0(&qme)) temp_nomem();
  if (stat(qme.s,&st) == -1)
   {
-   if (error_temp(errno)) temp_nfsqmail();
+   if (error_temp(errno)) temp_qmail(qme.s);
    return -1;
   }
  return 0;
 }
 
-int qmeopen(cutable)
+int qmeexists(fd,cutable)
+int *fd;
 int *cutable;
 {
- int fd;
- struct stat st;
- int i;
+  struct stat st;
 
- i = dashext.len;
- for (;;)
-  {
-   if (!stralloc_copys(&qme,".qmail")) temp_nomem();
-   if (!stralloc_catb(&qme,dashext.s,i)) temp_nomem();
-   if (i < dashext.len) if (!stralloc_cats(&qme,"-default")) temp_nomem();
-   if (!stralloc_0(&qme)) temp_nomem();
-   fd = open_read(qme.s);
-   if (fd == -1)
-    {
-     if (error_temp(errno)) temp_nfsqmail();
-     if (errno == error_perm) temp_denyqmail();
-     if (errno == error_acces) temp_denyqmail();
+  if (!stralloc_0(&qme)) temp_nomem();
+
+  *fd = open_read(qme.s);
+  if (*fd == -1) {
+    if (error_temp(errno)) temp_qmail(qme.s);
+    if (errno == error_perm) temp_qmail(qme.s);
+    if (errno == error_acces) temp_qmail(qme.s);
+    return 0;
+  }
+
+  if (fstat(*fd,&st) == -1) temp_qmail(qme.s);
+  if ((st.st_mode & S_IFMT) == S_IFREG) {
+    if (st.st_mode & auto_patrn)
+      strerr_die1x(111,"Uh-oh: .qmail file is writable. (#4.7.0)");
+    *cutable = !!(st.st_mode & 0100);
+    return 1;
+  }
+  close(*fd);
+  return 0;
+}
+
+/* "" "": "" */
+/* "-/" "": "-/" "-/default" */
+/* "-/" "a": "-/a" "-/default" */
+/* "-/" "a-": "-/a-" "-/a-default" "-/default" */
+/* "-/" "a-b": "-/a-b" "-/a-default" "-/default" */
+/* "-/" "a-b-": "-/a-b-" "-/a-b-default" "-/a-default" "-/default" */
+/* "-/" "a-b-c": "-/a-b-c" "-/a-b-default" "-/a-default" "-/default" */
+
+void qmesearch(fd,cutable)
+int *fd;
+int *cutable;
+{
+  int i;
+
+  if (!stralloc_copys(&qme,".qmail")) temp_nomem();
+  if (!stralloc_cats(&qme,dash)) temp_nomem();
+  if (!stralloc_cat(&qme,&safeext)) temp_nomem();
+  if (qmeexists(fd,cutable)) {
+    if (safeext.len >= 7) {
+      i = safeext.len - 7;
+      if (!byte_diff("default",7,safeext.s + i))
+       if (i <= str_len(ext)) /* paranoia */
+         if (!env_put2("DEFAULT",ext + i)) temp_nomem();
     }
-   else
-    {
-     if (fstat(fd,&st) == -1) temp_nfsqmail();
-     if ((st.st_mode & S_IFMT) == S_IFREG)
-      {
-       if (st.st_mode & auto_patrn) temp_qmwritable();
-       *cutable = !!(st.st_mode & 0100);
-       return fd;
+    return;
+  }
+
+  for (i = safeext.len;i >= 0;--i)
+    if (!i || (safeext.s[i - 1] == '-')) {
+      if (!stralloc_copys(&qme,".qmail")) temp_nomem();
+      if (!stralloc_cats(&qme,dash)) temp_nomem();
+      if (!stralloc_catb(&qme,safeext.s,i)) temp_nomem();
+      if (!stralloc_cats(&qme,"default")) temp_nomem();
+      if (qmeexists(fd,cutable)) {
+       if (i <= str_len(ext)) /* paranoia */
+         if (!env_put2("DEFAULT",ext + i)) temp_nomem();
+        return;
       }
-     close(fd);
     }
-   if (!i) return -1;
-   do
-     if (dashext.s[--i] == '-') break;
-   while (i);
-  }
+
+  *fd = -1;
 }
 
 unsigned long count_file = 0;
@@ -446,7 +457,7 @@ char **argv;
  char **recips;
  datetime_sec starttime;
  int flagforwardonly;
- char *extx;
+ char *x;
 
  umask(077);
  sig_pipeignore();
@@ -459,9 +470,8 @@ char **argv;
     {
      case 'n': flagdoit = 0; break;
      case 'N': flagdoit = 1; break;
-     case '?':
      default:
-       hard();
+       usage();
     }
  argc -= optind;
  argv += optind;
@@ -477,7 +487,8 @@ char **argv;
  if (*argv) usage();
 
  if (homedir[0] != '/') usage();
- if (chdir(homedir) == -1) temp_chdir();
+ if (chdir(homedir) == -1)
+   strerr_die5x(111,"Unable to switch to ",homedir,": ",error_str(errno),". (#4.3.0)");
  checkhome();
 
  if (!env_put2("HOST",host)) temp_nomem();
@@ -542,25 +553,40 @@ char **argv;
  if (!stralloc_0(&foo)) temp_nomem();
  if (!env_put2("UFLINE",foo.s)) temp_nomem();
 
- if (!stralloc_copys(&dashext,dash)) temp_nomem();
- if (!stralloc_cats(&dashext,ext)) temp_nomem();
- for (i = 0;i < dashext.len;++i)
-   if (dashext.s[i] == '.')
-     dashext.s[i] = ':';
- case_lowerb(dashext.s,dashext.len);
-
- extx = ext;
- if (!env_put2("EXT",extx)) temp_nomem();
- extx += str_chr(extx,'-'); if (*extx) ++extx;
- if (!env_put2("EXT2",extx)) temp_nomem();
- extx += str_chr(extx,'-'); if (*extx) ++extx;
- if (!env_put2("EXT3",extx)) temp_nomem();
- extx += str_chr(extx,'-'); if (*extx) ++extx;
- if (!env_put2("EXT4",extx)) temp_nomem();
+ x = ext;
+ if (!env_put2("EXT",x)) temp_nomem();
+ x += str_chr(x,'-'); if (*x) ++x;
+ if (!env_put2("EXT2",x)) temp_nomem();
+ x += str_chr(x,'-'); if (*x) ++x;
+ if (!env_put2("EXT3",x)) temp_nomem();
+ x += str_chr(x,'-'); if (*x) ++x;
+ if (!env_put2("EXT4",x)) temp_nomem();
+
+ if (!stralloc_copys(&safeext,ext)) temp_nomem();
+ case_lowerb(safeext.s,safeext.len);
+ for (i = 0;i < safeext.len;++i)
+   if (safeext.s[i] == '.')
+     safeext.s[i] = ':';
+
+ i = str_len(host);
+ i = byte_rchr(host,i,'.');
+ if (!stralloc_copyb(&foo,host,i)) temp_nomem();
+ if (!stralloc_0(&foo)) temp_nomem();
+ if (!env_put2("HOST2",foo.s)) temp_nomem();
+ i = byte_rchr(host,i,'.');
+ if (!stralloc_copyb(&foo,host,i)) temp_nomem();
+ if (!stralloc_0(&foo)) temp_nomem();
+ if (!env_put2("HOST3",foo.s)) temp_nomem();
+ i = byte_rchr(host,i,'.');
+ if (!stralloc_copyb(&foo,host,i)) temp_nomem();
+ if (!stralloc_0(&foo)) temp_nomem();
+ if (!env_put2("HOST4",foo.s)) temp_nomem();
 
  flagforwardonly = 0;
- fd = qmeopen(&flagforwardonly);
- if (fd == -1) if (*dash) bounce_ext();
+ qmesearch(&fd,&flagforwardonly);
+ if (fd == -1)
+   if (*dash)
+     strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
 
  if (!stralloc_copys(&ueo,sender)) temp_nomem();
  if (str_diff(sender,""))
@@ -625,13 +651,13 @@ char **argv;
       {
        case 0: /* k == i */
         if (i) break;
-        temp_blankline();
+         strerr_die1x(111,"Uh-oh: first line of .qmail file is blank. (#4.2.1)");
        case '#':
          break;
        case '.':
        case '/':
         ++count_file;
-        if (flagforwardonly) temp_fofile();
+        if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)");
         if (cmds.s[k - 1] == '/')
            if (flagdoit) maildir(cmds.s + i);
            else sayit("maildir ",cmds.s + i,k - i);
@@ -641,7 +667,7 @@ char **argv;
          break;
        case '|':
         ++count_program;
-        if (flagforwardonly) temp_foprog();
+        if (flagforwardonly) strerr_die1x(111,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)");
          if (flagdoit) mailprogram(cmds.s + i + 1);
          else sayit("program ",cmds.s + i + 1,k - i - 1);
          break;
index c039156..98cef63 100644 (file)
@@ -5,31 +5,22 @@ qmail-log \- the qmail activity record
 .B qmail-send
 prints a series of lines describing its activities.
 Each possible line is described below.
-.SH "STARTING AND STOPPING"
-.TP 
-.B running
-.B qmail-send
-is ready to deliver messages.
-.TP
-.B local deliveries will be put on hold
-The local concurrency limit is 0, so
-.B qmail-send
-will not perform any local deliveries.
+.SH "STATUS"
 .TP
-.B remote deliveries will be put on hold
-The remote concurrency limit is 0, so
+.B status: local \fIl\fB/\fIL\fB remote \fIr\fB/\fIR\fB ...
 .B qmail-send
-will not perform any remote deliveries.
-.TP
-.B number of deliveries left before exiting: ...
-.B qmail-send
-wants to exit as soon as possible,
-usually because it was sent a
-TERM signal,
-but it has to wait for some deliveries to finish.
-It will not start any new deliveries.
-.TP
-.B exiting
+is waiting for
+.I l
+local deliveries
+and
+.I r
+remote deliveries.
+The concurrency limits are
+.I L
+and
+.IR R .
+.TP
+.B status: exiting
 .B qmail-send
 is done.
 .SH "FATAL PROBLEMS"
index 111329d..da01741 100644 (file)
@@ -3,7 +3,7 @@
 qmail-lspawn \- schedule local deliveries
 .SH SYNOPSIS
 .B qmail-lspawn
-.I aliasempty
+.I defaultdelivery
 .SH DESCRIPTION
 .B qmail-lspawn
 reads a series of local delivery commands from descriptor 0,
@@ -12,7 +12,7 @@ invokes
 to perform the deliveries,
 and prints the results to descriptor 1.
 It passes
-.I aliasempty
+.I defaultdelivery
 to
 .B qmail-local
 as the default delivery instruction.
diff --git a/qmail-newmrh.9 b/qmail-newmrh.9
new file mode 100644 (file)
index 0000000..2f02f10
--- /dev/null
@@ -0,0 +1,41 @@
+.TH qmail-newmrh 8
+.SH NAME
+qmail-newmrh \- prepare morercpthosts for qmail-smtpd
+.SH SYNOPSIS
+.B qmail-newmrh
+.SH DESCRIPTION
+.B qmail-newmrh
+reads the instructions in
+.B QMAILHOME/control/morercpthosts
+and writes them into
+.B QMAILHOME/control/morercpthosts.cdb
+in a binary format suited
+for quick access by
+.BR qmail-smtpd .
+
+If there is a problem with
+.BR control/morercpthosts ,
+.B qmail-newmrh
+complains and leaves
+.B control/morercpthosts.cdb
+alone.
+
+.B qmail-newmrh
+ensures that
+.B control/morercpthosts.cdb
+is updated atomically,
+so
+.B qmail-smtpd
+never has to wait for
+.B qmail-newmrh
+to finish.
+However,
+.B qmail-newmrh
+makes no attempt to protect against two simultaneous updates of
+.BR control/morercpthosts.cdb .
+
+The binary
+.B control/morercpthosts.cdb
+format is portable across machines.
+.SH "SEE ALSO"
+qmail-smtpd(8)
diff --git a/qmail-newmrh.c b/qmail-newmrh.c
new file mode 100644 (file)
index 0000000..25a4a10
--- /dev/null
@@ -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-newmrh: fatal: "
+
+void die_read()
+{
+  strerr_die2sys(111,FATAL,"unable to read control/morercpthosts: ");
+}
+void die_write()
+{
+  strerr_die2sys(111,FATAL,"unable to write to control/morercpthosts.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/morercpthosts");
+  if (fd == -1) die_read();
+
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof inbuf);
+
+  fdtemp = open_trunc("control/morercpthosts.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/morercpthosts.tmp","control/morercpthosts.cdb") == -1)
+    strerr_die2sys(111,FATAL,"unable to move control/morercpthosts.tmp to control/morercpthosts.cdb");
+
+  _exit(0);
+}
index b85abaa..de6b2ba 100644 (file)
@@ -29,7 +29,7 @@ which checks the password and sets up environment variables.
 has a 20-minute idle timeout.
 
 .B qmail-pop3d
-supports UIDL and TOP.
+supports UIDL, TOP, and LAST.
 
 .B qmail-pop3d
 appends an extra blank line to every message
index c3ff0a6..51976c2 100644 (file)
@@ -1,60 +1,69 @@
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "direntry.h"
+#include "commands.h"
 #include "sig.h"
 #include "getln.h"
 #include "stralloc.h"
 #include "substdio.h"
 #include "alloc.h"
-#include "datetime.h"
-#include "prot.h"
 #include "open.h"
 #include "prioq.h"
 #include "scan.h"
 #include "fmt.h"
-#include "error.h"
 #include "str.h"
 #include "exit.h"
-#include "now.h"
+#include "maildir.h"
 #include "readwrite.h"
+#include "timeoutread.h"
+#include "timeoutwrite.h"
 
-int timeout = 1200;
+void die() { _exit(0); }
 
-char ssoutbuf[1024];
-substdio ssout = SUBSTDIO_FDBUF(write,1,ssoutbuf,sizeof(ssoutbuf));
+int saferead(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = timeoutread(1200,fd,buf,len);
+  if (r <= 0) die();
+  return r;
+}
 
-int timeoutread(fd,buf,n) int fd; char *buf; int n;
+int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
- int r; int saveerrno;
- alarm(timeout);
- r = read(fd,buf,n); saveerrno = errno;
- alarm(0);
- errno = saveerrno; return r;
+  int r;
+  r = timeoutwrite(1200,fd,buf,len);
+  if (r <= 0) die();
+  return r;
 }
 
-char ssinbuf[128];
-substdio ssin = SUBSTDIO_FDBUF(timeoutread,0,ssinbuf,sizeof(ssinbuf));
+char ssoutbuf[1024];
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
 
+char ssinbuf[128];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
 
-void die() { _exit(0); }
+void put(buf,len) char *buf; int len;
+{
+  substdio_put(&ssout,buf,len);
+}
 void puts(s) char *s;
 {
if (substdio_puts(&ssout,s) == -1) die();
 substdio_puts(&ssout,s);
 }
 void flush()
 {
if (substdio_flush(&ssout) == -1) die();
 substdio_flush(&ssout);
 }
 void err(s) char *s;
 {
- puts("-ERR ");
- puts(s);
- puts("\r\n");
if (substdio_flush(&ssout) == -1) die();
 puts("-ERR ");
 puts(s);
 puts("\r\n");
 flush();
 }
+
 void die_nomem() { err("out of memory"); die(); }
-void die_prot() { err("protection problem"); die(); }
 void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); }
+void die_scan() { err("unable to scan $HOME/Maildir"); die(); }
 
 void err_syntax() { err("syntax error"); }
 void err_unimpl() { err("unimplemented"); }
@@ -65,333 +74,232 @@ void err_nosuch() { err("unable to open that message"); }
 void err_nounlink() { err("unable to unlink all deleted messages"); }
 
 void okay() { puts("+OK \r\n"); flush(); }
-void pop3_last() { puts("+OK 0\r\n"); flush(); }
 
+void printfn(fn) char *fn;
+{
+  fn += 4;
+  put(fn,str_chr(fn,':'));
+}
 
-stralloc dataline = {0};
+char strnum[FMT_ULONG];
+stralloc line = {0};
+
+void blast(ssfrom,limit)
+substdio *ssfrom;
+unsigned long limit;
+{
+  int match;
+  int inheaders = 1;
+  for (;;) {
+    if (getln(ssfrom,&line,&match,'\n') != 0) die();
+    if (!match && !line.len) break;
+    if (match) --line.len; /* no way to pass this info over POP */
+    if (limit) if (!inheaders) if (!--limit) break;
+    if (!line.len)
+      inheaders = 0;
+    else
+      if (line.s[0] == '.')
+        put(".",1);
+    put(line.s,line.len);
+    put("\r\n",2);
+    if (!match) break;
+  }
+  put("\r\n.\r\n",5);
+  flush();
+}
 
 stralloc filenames = {0};
 prioq pq = {0};
-stralloc newname = {0};
 
-struct message
- {
+struct message {
   int flagdeleted;
   unsigned long size;
   char *fn;
- }
-*m;
+} *m;
 int numm;
 
-substdio ssmsg; char ssmsgbuf[1024];
-
-
-void blast(ssfrom,limit)
-substdio *ssfrom;
-unsigned long limit;
-{
- int match;
- int inheaders = 1;
-
- for (;;)
-  {
-   if (getln(ssfrom,&dataline,&match,'\n') != 0) die();
-   if (!match && !dataline.len) break;
-   if (match) --dataline.len; /* no way to pass this info over POP */
-   if (limit) if (!inheaders) if (!--limit) break;
-   if (!dataline.len)
-     inheaders = 0;
-   else
-     if (dataline.s[0] == '.')
-       substdio_put(&ssout,".",1);
-   if (substdio_put(&ssout,dataline.s,dataline.len) == -1) die();
-   if (substdio_put(&ssout,"\r\n",2) == -1) die();
-   if (!match) break;
-  }
- if (substdio_put(&ssout,"\r\n.\r\n",5) == -1) die();
- if (substdio_flush(&ssout) == -1) die();
-}
+int last = 0;
 
 void getlist()
 {
- unsigned long pos;
- datetime_sec time;
- DIR *dir;
- direntry *d;
- struct prioq_elt pe;
- struct stat st;
- int i;
-
- numm = 0;
-
- time = now();
-
- if (dir = opendir("tmp"))
-  {
-   while (d = readdir(dir))
-    {
-     if (str_equal(d->d_name,".")) continue;
-     if (str_equal(d->d_name,"..")) continue;
-     if (!stralloc_copys(&newname,"tmp/")) die_nomem();
-     if (!stralloc_cats(&newname,d->d_name)) die_nomem();
-     if (!stralloc_0(&newname)) die_nomem();
-     if (stat(newname.s,&st) == 0)
-       if (time > st.st_atime + 129600)
-        unlink(newname.s);
-    }
-   closedir(dir);
-  }
-
- if (!stralloc_copys(&filenames,"")) die_nomem();
-
- if (dir = opendir("new"))
-  {
-   while (d = readdir(dir))
-    {
-     if (str_equal(d->d_name,".")) continue;
-     if (str_equal(d->d_name,"..")) continue;
-     pos = filenames.len;
-     if (!stralloc_cats(&filenames,"new/")) die_nomem();
-     if (!stralloc_cats(&filenames,d->d_name)) die_nomem();
-     if (!stralloc_0(&filenames)) die_nomem();
-     if (stat(filenames.s + pos,&st) == 0)
-      {
-       pe.dt = st.st_mtime;
-       pe.id = pos;
-       if (!prioq_insert(&pq,&pe)) die_nomem();
-       ++numm;
-      }
-    }
-   closedir(dir);
-  }
-
- if (dir = opendir("cur"))
-  {
-   while (d = readdir(dir))
-    {
-     if (str_equal(d->d_name,".")) continue;
-     if (str_equal(d->d_name,"..")) continue;
-     pos = filenames.len;
-     if (!stralloc_cats(&filenames,"cur/")) die_nomem();
-     if (!stralloc_cats(&filenames,d->d_name)) die_nomem();
-     if (!stralloc_0(&filenames)) die_nomem();
-     if (stat(filenames.s + pos,&st) == 0)
-      {
-       pe.dt = st.st_mtime;
-       pe.id = pos;
-       if (!prioq_insert(&pq,&pe)) die_nomem();
-       ++numm;
-      }
-    }
-   closedir(dir);
-  }
-
- m = (struct message *) alloc(numm * sizeof(struct message));
- if (!m) die_nomem();
-
- for (i = 0;i < numm;++i)
-  {
-   if (!prioq_min(&pq,&pe)) { numm = i; break; }
-   prioq_delmin(&pq);
-   m[i].fn = filenames.s + pe.id;
-   m[i].flagdeleted = 0;
-   if (stat(m[i].fn,&st) == -1)
-     m[i].size = 0;
-   else
-     m[i].size = st.st_size;
+  struct prioq_elt pe;
+  struct stat st;
+  int i;
+  maildir_clean(&line);
+  if (maildir_scan(&pq,&filenames,1,1) == -1) die_scan();
+  numm = pq.p ? pq.len : 0;
+  m = (struct message *) alloc(numm * sizeof(struct message));
+  if (!m) die_nomem();
+  for (i = 0;i < numm;++i) {
+    if (!prioq_min(&pq,&pe)) { numm = i; break; }
+    prioq_delmin(&pq);
+    m[i].fn = filenames.s + pe.id;
+    m[i].flagdeleted = 0;
+    if (stat(m[i].fn,&st) == -1)
+      m[i].size = 0;
+    else
+      m[i].size = st.st_size;
   }
 }
 
-char foo[FMT_ULONG];
-
-void printint(u) unsigned int u;
-{
- foo[fmt_uint(foo,u)] = 0;
- puts(foo);
- puts(" ");
-}
-
-void printlong(u) unsigned long u;
-{
- foo[fmt_uint(foo,u)] = 0;
- puts(foo);
- puts("\r\n");
-}
-
-void printfn(fn) char *fn;
+void pop3_stat()
 {
- puts(fn + 4);
- puts("\r\n");
+  int i;
+  unsigned long total;
+  total = 0;
+  for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size;
+  puts("+OK ");
+  put(strnum,fmt_uint(strnum,numm));
+  puts(" ");
+  put(strnum,fmt_ulong(strnum,total));
+  puts("\r\n");
+  flush();
 }
 
-void pop3_stat()
+void pop3_rset()
 {
- int i;
- unsigned long total;
-
- total = 0;
- for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size;
- puts("+OK ");
- printint(numm);
- printlong(total);
- flush();
+  int i;
+  for (i = 0;i < numm;++i) m[i].flagdeleted = 0;
+  last = 0;
+  okay();
 }
 
-void pop3_rset()
+void pop3_last()
 {
- int i;
- for (i = 0;i < numm;++i) m[i].flagdeleted = 0;
- okay();
+  puts("+OK ");
+  put(strnum,fmt_uint(strnum,last));
+  puts("\r\n");
+  flush();
 }
 
 void pop3_quit()
 {
- int i;
- for (i = 0;i < numm;++i)
-   if (m[i].flagdeleted)
-     if (unlink(m[i].fn) == -1) err_nounlink();
- okay();
- die();
+  int i;
+  for (i = 0;i < numm;++i)
+    if (m[i].flagdeleted) {
+      if (unlink(m[i].fn) == -1) err_nounlink();
+    }
+    else
+      if (str_start(m[i].fn,"new/")) {
+       if (!stralloc_copys(&line,"cur/")) die_nomem();
+       if (!stralloc_cats(&line,m[i].fn + 4)) die_nomem();
+       if (!stralloc_cats(&line,":2,")) die_nomem();
+       if (!stralloc_0(&line)) die_nomem();
+       rename(m[i].fn,line.s); /* if it fails, bummer */
+      }
+  okay();
+  die();
 }
 
 int msgno(arg) char *arg;
 {
- unsigned long u;
- if (!arg) { err_syntax(); return -1; }
- if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
- if (!u) { err_nozero(); return -1; }
- --u;
- if (u >= numm) { err_toobig(); return -1; }
- if (m[u].flagdeleted) { err_deleted(); return -1; }
- return u;
+  unsigned long u;
+  if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
+  if (!u) { err_nozero(); return -1; }
+  --u;
+  if (u >= numm) { err_toobig(); return -1; }
+  if (m[u].flagdeleted) { err_deleted(); return -1; }
+  return u;
 }
 
 void pop3_dele(arg) char *arg;
 {
- int i;
+  int i;
+  i = msgno(arg);
+  if (i == -1) return;
+  m[i].flagdeleted = 1;
+  if (i + 1 > last) last = i + 1;
+  okay();
+}
 
- i = msgno(arg);
- if (i == -1) return;
- m[i].flagdeleted = 1;
- okay();
+void list(i,flaguidl)
+int i;
+int flaguidl;
+{
+  put(strnum,fmt_uint(strnum,i + 1));
+  puts(" ");
+  if (flaguidl) printfn(m[i].fn);
+  else put(strnum,fmt_ulong(strnum,m[i].size));
+  puts("\r\n");
 }
 
 void dolisting(arg,flaguidl) char *arg; int flaguidl;
 {
- unsigned int i;
-
- if (arg)
-  {
-   i = msgno(arg);
-   if (i == -1) return;
-   puts("+OK ");
-   printint(i + 1);
-   if (flaguidl) printfn(m[i].fn); else printlong(m[i].size);
+  unsigned int i;
+  if (*arg) {
+    i = msgno(arg);
+    if (i == -1) return;
+    puts("+OK ");
+    list(i,flaguidl);
   }
- else
-  {
-   okay();
-
-   for (i = 0;i < numm;++i)
-     if (!m[i].flagdeleted)
-      {
-       printint(i + 1);
-       if (flaguidl) printfn(m[i].fn); else printlong(m[i].size);
-      }
-   puts(".\r\n");
+  else {
+    okay();
+    for (i = 0;i < numm;++i)
+      if (!m[i].flagdeleted)
+       list(i,flaguidl);
+    puts(".\r\n");
   }
- flush();
 flush();
 }
 
 void pop3_uidl(arg) char *arg; { dolisting(arg,1); }
 void pop3_list(arg) char *arg; { dolisting(arg,0); }
 
+substdio ssmsg; char ssmsgbuf[1024];
+
 void pop3_top(arg) char *arg;
 {
- int i;
- unsigned long limit;
- int fd;
-
- i = msgno(arg);
- if (i == -1) return;
-
- arg += scan_ulong(arg,&limit);
- while (*arg == ' ') ++arg;
- if (scan_ulong(arg,&limit)) ++limit; else limit = 0;
-
- fd = open_read(m[i].fn);
- if (fd == -1) { err_nosuch(); return; }
- okay();
- substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf));
- blast(&ssmsg,limit);
- close(fd);
 int i;
 unsigned long limit;
 int fd;
 i = msgno(arg);
 if (i == -1) return;
 arg += scan_ulong(arg,&limit);
 while (*arg == ' ') ++arg;
 if (scan_ulong(arg,&limit)) ++limit; else limit = 0;
 fd = open_read(m[i].fn);
 if (fd == -1) { err_nosuch(); return; }
 okay();
 substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf));
 blast(&ssmsg,limit);
 close(fd);
 }
 
-static struct { void (*fun)(); char *text; } pop3cmd[] = {
-  { pop3_quit, "quit" }
-, { pop3_stat, "stat" }
-, { pop3_list, "list" }
-, { pop3_uidl, "uidl" }
-, { pop3_dele, "dele" }
-, { pop3_top, "retr" }
-, { pop3_rset, "rset" }
-, { pop3_last, "last" }
-, { pop3_top, "top" }
-, { okay, "noop" }
-, { 0, 0 }
-};
-
-void doit(cmd)
-char *cmd;
-{
- int i;
- int j;
- char ch;
-
- for (i = 0;pop3cmd[i].fun;++i)
-  {
-   for (j = 0;ch = pop3cmd[i].text[j];++j)
-     if ((cmd[j] != ch) && (cmd[j] != ch - 32))
-       break;
-   if (!ch)
-     if (!cmd[j] || (cmd[j] == ' '))
-      {
-       while (cmd[j] == ' ') ++j;
-       if (!cmd[j])
-         pop3cmd[i].fun((char *) 0);
-       else
-         pop3cmd[i].fun(cmd + j);
-       return;
-      }
-  }
- err_unimpl();
-}
+struct commands pop3commands[] = {
+  { "quit", pop3_quit, 0 }
+, { "stat", pop3_stat, 0 }
+, { "list", pop3_list, 0 }
+, { "uidl", pop3_uidl, 0 }
+, { "dele", pop3_dele, 0 }
+, { "retr", pop3_top, 0 }
+, { "rset", pop3_rset, 0 }
+, { "last", pop3_last, 0 }
+, { "top", pop3_top, 0 }
+, { "noop", okay, 0 }
+, { 0, err_unimpl, 0 }
+} ;
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
- static stralloc cmd = {0};
- int match;
-
- sig_alarmcatch(die);
- sig_pipeignore();
-
- if (!argv[1]) die_nomaildir();
- if (chdir(argv[1]) == -1) die_nomaildir();
-
- getlist();
-
- okay();
-
- for (;;)
-  {
-   if (getln(&ssin,&cmd,&match,'\n') == -1) die();
-   if (!match) die();
-   if (cmd.len == 0) die();
-   if (cmd.s[--cmd.len] != '\n') die();
-   if ((cmd.len > 0) && (cmd.s[cmd.len - 1] == '\r')) --cmd.len;
-   cmd.s[cmd.len++] = 0;
-   doit(cmd.s);
-  }
+  sig_alarmcatch(die);
+  sig_pipeignore();
+  if (!argv[1]) die_nomaildir();
+  if (chdir(argv[1]) == -1) die_nomaildir();
+  getlist();
+
+  okay();
+  commands(&ssin,pop3commands);
+  die();
 }
index f8c80a3..fbcc99b 100644 (file)
@@ -1,53 +1,59 @@
-#include <sys/types.h>
-#include <sys/stat.h>
+#include "commands.h"
 #include "fd.h"
 #include "sig.h"
-#include "getln.h"
 #include "stralloc.h"
 #include "substdio.h"
-#include "subfd.h"
 #include "alloc.h"
-#include "datetime.h"
-#include "error.h"
 #include "wait.h"
 #include "str.h"
+#include "byte.h"
 #include "now.h"
 #include "fmt.h"
 #include "exit.h"
 #include "readwrite.h"
+#include "timeoutread.h"
+#include "timeoutwrite.h"
 
-int timeout = 1200;
+void die() { _exit(1); }
 
-int timeoutread(fd,buf,n) int fd; char *buf; int n;
+int saferead(fd,buf,len) int fd; char *buf; int len;
 {
- int r; int saveerrno;
- alarm(timeout);
- r = read(fd,buf,n); saveerrno = errno;
- alarm(0);
- errno = saveerrno; return r;
+  int r;
+  r = timeoutread(1200,fd,buf,len);
+  if (r <= 0) die();
+  return r;
 }
 
-char ssinbuf[128];
-substdio ssin = SUBSTDIO_FDBUF(timeoutread,0,ssinbuf,sizeof(ssinbuf));
+int safewrite(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = timeoutwrite(1200,fd,buf,len);
+  if (r <= 0) die();
+  return r;
+}
 
+char ssoutbuf[128];
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
 
-void die() { _exit(1); }
-void out(s) char *s;
+char ssinbuf[128];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+
+void puts(s) char *s;
 {
if (substdio_puts(subfdoutsmall,s) == -1) die();
 substdio_puts(&ssout,s);
 }
-void outflush(s) char *s; 
+void flush()
 {
- out(s);
- if (substdio_flush(subfdoutsmall) == -1) die();
+  substdio_flush(&ssout);
 }
 void err(s) char *s;
 {
if (substdio_puts(subfdoutsmall,"-ERR ") == -1) die();
if (substdio_puts(subfdoutsmall,s) == -1) die();
if (substdio_puts(subfdoutsmall,"\r\n") == -1) die();
if (substdio_flush(subfdoutsmall) == -1) die();
 puts("-ERR ");
 puts(s);
 puts("\r\n");
 flush();
 }
+
 void die_usage() { err("usage: popup hostname subprogram"); die(); }
 void die_nomem() { err("out of memory"); die(); }
 void die_pipe() { err("unable to open pipe"); die(); }
@@ -60,7 +66,8 @@ void err_syntax() { err("syntax error"); }
 void err_wantuser() { err("USER first"); }
 void err_authoriz() { err("authorization first"); }
 
-void okay() { outflush("+OK \r\n"); }
+void okay() { puts("+OK \r\n"); flush(); }
+void pop3_quit() { okay(); die(); }
 
 
 char unique[FMT_ULONG + FMT_ULONG + 3];
@@ -77,143 +84,100 @@ char *user;
 unsigned int userlen; /* including 0 byte */
 char *pass;
 {
- int child;
- int wstat;
- int pi[2];
- int i;
-
- if (fd_copy(2,1) == -1) die_pipe();
- close(3);
- if (pipe(pi) == -1) die_pipe();
- if (pi[0] != 3) die_pipe();
- switch(child = fork())
-  {
-   case -1:
-     die_fork();
-   case 0:
-     close(pi[1]);
-     sig_pipedefault();
-     execvp(*childargs,childargs);
-     _exit(1);
+  int child;
+  int wstat;
+  int pi[2];
+  if (fd_copy(2,1) == -1) die_pipe();
+  close(3);
+  if (pipe(pi) == -1) die_pipe();
+  if (pi[0] != 3) die_pipe();
+  switch(child = fork()) {
+    case -1:
+      die_fork();
+    case 0:
+      close(pi[1]);
+      sig_pipedefault();
+      execvp(*childargs,childargs);
+      _exit(1);
   }
- close(pi[0]);
substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof(upbuf));
- if (substdio_put(&ssup,user,userlen) == -1) die_write();
- if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write();
- if (substdio_puts(&ssup,"<") == -1) die_write();
- if (substdio_puts(&ssup,unique) == -1) die_write();
- if (substdio_puts(&ssup,hostname) == -1) die_write();
- if (substdio_put(&ssup,">",2) == -1) die_write();
- if (substdio_flush(&ssup) == -1) die_write();
- close(pi[1]);
for (i = 0;pass[i];++i) pass[i] = 0;
for (i = 0;i < sizeof(upbuf);++i) upbuf[i] = 0;
- if (wait_pid(&wstat,child) == -1) die();
- if (wait_crashed(wstat)) die_childcrashed();
- if (wait_exitcode(wstat)) die_badauth();
- die();
 close(pi[0]);
 substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
 if (substdio_put(&ssup,user,userlen) == -1) die_write();
 if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write();
 if (substdio_puts(&ssup,"<") == -1) die_write();
 if (substdio_puts(&ssup,unique) == -1) die_write();
 if (substdio_puts(&ssup,hostname) == -1) die_write();
 if (substdio_put(&ssup,">",2) == -1) die_write();
 if (substdio_flush(&ssup) == -1) die_write();
 close(pi[1]);
 byte_zero(pass,str_len(pass));
 byte_zero(upbuf,sizeof upbuf);
 if (wait_pid(&wstat,child) == -1) die();
 if (wait_crashed(wstat)) die_childcrashed();
 if (wait_exitcode(wstat)) die_badauth();
 die();
 }
 void pop3_greet()
 {
- char *s;
- s = unique;
- s += fmt_uint(s,getpid());
- *s++ = '.';
- s += fmt_ulong(s,(unsigned long) now());
- *s++ = '@';
- *s++ = 0;
-
out("+OK <");
out(unique);
out(hostname);
outflush(">\r\n");
 char *s;
 s = unique;
 s += fmt_uint(s,getpid());
 *s++ = '.';
 s += fmt_ulong(s,(unsigned long) now());
 *s++ = '@';
 *s++ = 0;
+  puts("+OK <");
 puts(unique);
 puts(hostname);
 puts(">\r\n");
 flush();
 }
 void pop3_user(arg) char *arg;
 {
if (!arg) { err_syntax(); return; }
- okay();
- seenuser = 1;
- if (!stralloc_copys(&username,arg)) die_nomem(); 
- if (!stralloc_0(&username)) die_nomem(); 
 if (!*arg) { err_syntax(); return; }
 okay();
 seenuser = 1;
 if (!stralloc_copys(&username,arg)) die_nomem(); 
 if (!stralloc_0(&username)) die_nomem(); 
 }
 void pop3_pass(arg) char *arg;
 {
- if (!seenuser) { err_wantuser(); return; }
if (!arg) { err_syntax(); return; }
- doanddie(username.s,username.len,arg);
 if (!seenuser) { err_wantuser(); return; }
 if (!*arg) { err_syntax(); return; }
 doanddie(username.s,username.len,arg);
 }
 void pop3_apop(arg) char *arg;
 {
- char *space;
- if (!arg) { err_syntax(); return; }
- space = arg + str_chr(arg,' ');
- if (!*space) { err_syntax(); return; }
- *space++ = 0;
- doanddie(arg,space - arg,space);
+  char *space;
+  space = arg + str_chr(arg,' ');
+  if (!*space) { err_syntax(); return; }
+  *space++ = 0;
+  doanddie(arg,space - arg,space);
 }
 
-void pop3_quit() { okay(); die(); }
-
-static struct { void (*fun)(); char *text; } pop3cmd[] = {
-  { pop3_user, "user" }
-, { pop3_pass, "pass" }
-, { pop3_apop, "apop" }
-, { pop3_quit, "quit" }
-, { okay, "noop" }
-, { 0, 0 }
-};
-
-void doit(cmd)
-char *cmd;
-{
- int i;
- int j;
- char ch;
-
- for (i = 0;pop3cmd[i].fun;++i)
-  {
-   for (j = 0;ch = pop3cmd[i].text[j];++j)
-     if ((cmd[j] != ch) && (cmd[j] != ch - 32))
-       break;
-   if (!ch)
-     if (!cmd[j] || (cmd[j] == ' '))
-      {
-       while (cmd[j] == ' ') ++j;
-       if (!cmd[j])
-         pop3cmd[i].fun((char *) 0);
-       else
-         pop3cmd[i].fun(cmd + j);
-       return;
-      }
-  }
- err_authoriz();
-}
+struct commands pop3commands[] = {
+  { "user", pop3_user, 0 }
+, { "pass", pop3_pass, 0 }
+, { "apop", pop3_apop, 0 }
+, { "quit", pop3_quit, 0 }
+, { "noop", okay, 0 }
+, { 0, err_authoriz, 0 }
+} ;
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
- static stralloc cmd = {0};
- int match;
-
- sig_alarmcatch(die);
- sig_pipeignore();
-
- hostname = argv[1];
- if (!hostname) die_usage();
- childargs = argv + 2;
- if (!*childargs) die_usage();
-
- pop3_greet();
-
- for (;;)
-  {
-   if (getln(&ssin,&cmd,&match,'\n') == -1) die();
-   if (!match) die();
-   if (cmd.len == 0) die();
-   if (cmd.s[--cmd.len] != '\n') die();
-   if ((cmd.len > 0) && (cmd.s[cmd.len - 1] == '\r')) --cmd.len;
-   cmd.s[cmd.len++] = 0;
-   doit(cmd.s);
-  }
+  sig_alarmcatch(die);
+  sig_pipeignore();
+  hostname = argv[1];
+  if (!hostname) die_usage();
+  childargs = argv + 2;
+  if (!*childargs) die_usage();
+  pop3_greet();
+  commands(&ssin,pop3commands);
+  die();
 }
index a62df8a..932cd4d 100644 (file)
@@ -4,7 +4,7 @@ qmail-pw2u \- build address assignments from a passwd file
 .SH SYNOPSIS
 .B qmail-pw2u
 [
-.B \-ohHuUC
+.B \-/ohHuUC
 ]
 [
 .B \-c\fIchar
@@ -160,7 +160,7 @@ Each line has the form
 
 .I sub
 will be handled by
-.IR home\fB/.qmail-\fIpre ,
+.IR home\fB/.qmail\-\fIpre ,
 where
 .I home
 is
@@ -168,7 +168,7 @@ is
 home directory;
 .I sub\fBBREAK\fIext
 will be handled by
-.IR home\fB/.qmail-\fIpre\fB-\fIext .
+.IR home\fB/.qmail\-\fIpre\fB\-\fIext .
 .TP
 .B append
 Extra assignments,
@@ -228,6 +228,12 @@ in place of
 .TP
 .B \-C
 Disable the user-extension mechanism.
+.TP
+.B \-/
+Use
+.IR home\fB/.qmail\-/ ...
+instead of
+.IR home\fB/.qmail\- ...
 .SH "SEE ALSO"
 qmail-users(5),
 qmail-lspawn(8),
index 5889f1d..4146067 100644 (file)
@@ -67,6 +67,7 @@ void die_user(s,len) char *s; unsigned int len;
   _exit(111);
 }
 
+char *dashcolon = "-:";
 int flagalias = 0;
 int flagnoupper = 1;
 int homestrategy = 2;
@@ -154,7 +155,8 @@ void doaccount()
   if (str_equal(user.s,auto_usera)) {
     if (substdio_puts(subfdout,"+") == -1) die_write();
     if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write();
-    if (substdio_puts(subfdout,"-::\n") == -1) die_write();
+    if (substdio_puts(subfdout,dashcolon) == -1) die_write();
+    if (substdio_puts(subfdout,":\n") == -1) die_write();
     flagalias = 1;
   }
 
@@ -180,7 +182,8 @@ void doaccount()
       if (substdio_put(subfdout,mailnames,i) == -1) die_write();
       if (substdio_put(subfdout,auto_break,1) == -1) die_write();
       if (substdio_put(subfdout,uugh.s,uugh.len) == -1) die_write();
-      if (substdio_puts(subfdout,"-::\n") == -1) die_write();
+      if (substdio_puts(subfdout,dashcolon) == -1) die_write();
+      if (substdio_puts(subfdout,":\n") == -1) die_write();
     }
 
     mailnames += i;
@@ -206,7 +209,7 @@ void dosubuser()
   if (substdio_puts(subfdout,"=") == -1) die_write();
   if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write();
   if (substdio_puts(subfdout,uugh) == -1) die_write();
-  if (substdio_puts(subfdout,"-:") == -1) die_write();
+  if (substdio_puts(subfdout,dashcolon) == -1) die_write();
   if (substdio_put(subfdout,x,i) == -1) die_write();
   if (substdio_puts(subfdout,":\n") == -1) die_write();
 
@@ -215,7 +218,7 @@ void dosubuser()
     if (substdio_put(subfdout,sub.s,sub.len) == -1) die_write();
     if (substdio_put(subfdout,auto_break,1) == -1) die_write();
     if (substdio_puts(subfdout,uugh) == -1) die_write();
-    if (substdio_puts(subfdout,"-:") == -1) die_write();
+    if (substdio_puts(subfdout,dashcolon) == -1) die_write();
     if (substdio_put(subfdout,x,i) == -1) die_write();
     if (substdio_puts(subfdout,"-:\n") == -1) die_write();
   }
@@ -232,8 +235,9 @@ char **argv;
   int opt;
   int match;
 
-  while ((opt = getopt(argc,argv,"ohHuUc:C")) != opteof)
+  while ((opt = getopt(argc,argv,"/ohHuUc:C")) != opteof)
     switch(opt) {
+      case '/': dashcolon = "-/:"; break;
       case 'o': homestrategy = 2; break;
       case 'h': homestrategy = 1; break;
       case 'H': homestrategy = 0; break;
diff --git a/qmail-qmqpc.8 b/qmail-qmqpc.8
new file mode 100644 (file)
index 0000000..e11a15e
--- /dev/null
@@ -0,0 +1,29 @@
+.TH qmail-qmqpc 8
+.SH NAME
+qmail-qmqpc \- queue a mail message via QMQP
+.SH SYNOPSIS
+.B qmail-qmqpc
+.SH DESCRIPTION
+.B qmail-qmqpc
+offers the same interface as
+.BR qmail-queue ,
+but it gives the message to a QMQP server
+instead of storing it locally.
+
+In a
+.B mini-qmail
+installation,
+.B qmail-queue
+is replaced with a symbolic link to
+.BR qmail-qmqpc .
+.SH "CONTROL FILES"
+.TP 5
+.I qmqpservers
+IP addresses of QMQP servers, one address per line.
+.B qmail-qmqpc
+will try each address in turn until it establishes a QMQP connection
+or runs out of addresses.
+.SH "SEE ALSO"
+qmail-control(5),
+qmail-queue(8),
+qmail-qmqpd(8)
diff --git a/qmail-qmqpc.c b/qmail-qmqpc.c
new file mode 100644 (file)
index 0000000..d5adf05
--- /dev/null
@@ -0,0 +1,159 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "substdio.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "stralloc.h"
+#include "slurpclose.h"
+#include "error.h"
+#include "sig.h"
+#include "ip.h"
+#include "timeoutconn.h"
+#include "timeoutread.h"
+#include "timeoutwrite.h"
+#include "auto_qmail.h"
+#include "control.h"
+#include "fmt.h"
+
+#define PORT_QMQP 628
+
+void die_success() { _exit(0); }
+void die_perm() { _exit(31); }
+void nomem() { _exit(51); }
+void die_read() { if (errno == error_nomem) nomem(); _exit(54); }
+void die_control() { _exit(55); }
+void die_socket() { _exit(56); }
+void die_home() { _exit(61); }
+void die_temp() { _exit(71); }
+void die_conn() { _exit(74); }
+void die_format() { _exit(91); }
+
+int lasterror = 55;
+int qmqpfd;
+
+int saferead(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = timeoutread(60,qmqpfd,buf,len);
+  if (r <= 0) die_conn();
+  return r;
+}
+int safewrite(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = timeoutwrite(60,qmqpfd,buf,len);
+  if (r <= 0) die_conn();
+  return r;
+}
+
+char buf[1024];
+substdio to = SUBSTDIO_FDBUF(safewrite,-1,buf,sizeof buf);
+substdio from = SUBSTDIO_FDBUF(saferead,-1,buf,sizeof buf);
+substdio envelope = SUBSTDIO_FDBUF(read,1,buf,sizeof buf);
+/* WARNING: can use only one of these at a time! */
+
+stralloc beforemessage = {0};
+stralloc message = {0};
+stralloc aftermessage = {0};
+
+char strnum[FMT_ULONG];
+stralloc line = {0};
+
+void getmess()
+{
+  int match;
+
+  if (slurpclose(0,&message,1024) == -1) die_read();
+
+  strnum[fmt_ulong(strnum,(unsigned long) message.len)] = 0;
+  if (!stralloc_copys(&beforemessage,strnum)) nomem();
+  if (!stralloc_cats(&beforemessage,":")) nomem();
+  if (!stralloc_copys(&aftermessage,",")) nomem();
+
+  if (getln(&envelope,&line,&match,'\0') == -1) die_read();
+  if (!match) die_format();
+  if (line.len < 2) die_format();
+  if (line.s[0] != 'F') die_format();
+
+  strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0;
+  if (!stralloc_cats(&aftermessage,strnum)) nomem();
+  if (!stralloc_cats(&aftermessage,":")) nomem();
+  if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem();
+  if (!stralloc_cats(&aftermessage,",")) nomem();
+
+  for (;;) {
+    if (getln(&envelope,&line,&match,'\0') == -1) die_read();
+    if (!match) die_format();
+    if (line.len < 2) break;
+    if (line.s[0] != 'T') die_format();
+
+    strnum[fmt_ulong(strnum,(unsigned long) line.len - 2)] = 0;
+    if (!stralloc_cats(&aftermessage,strnum)) nomem();
+    if (!stralloc_cats(&aftermessage,":")) nomem();
+    if (!stralloc_catb(&aftermessage,line.s + 1,line.len - 2)) nomem();
+    if (!stralloc_cats(&aftermessage,",")) nomem();
+  }
+}
+
+void doit(server)
+char *server;
+{
+  struct ip_address ip;
+  char ch;
+
+  if (!ip_scan(server,&ip)) return;
+
+  qmqpfd = socket(AF_INET,SOCK_STREAM,0);
+  if (qmqpfd == -1) die_socket();
+
+  if (timeoutconn(qmqpfd,&ip,PORT_QMQP,10) != 0) {
+    lasterror = 73;
+    if (errno == error_timeout) lasterror = 72;
+    close(qmqpfd);
+    return;
+  }
+
+  strnum[fmt_ulong(strnum,(unsigned long) (beforemessage.len + message.len + aftermessage.len))] = 0;
+  substdio_puts(&to,strnum);
+  substdio_puts(&to,":");
+  substdio_put(&to,beforemessage.s,beforemessage.len);
+  substdio_put(&to,message.s,message.len);
+  substdio_put(&to,aftermessage.s,aftermessage.len);
+  substdio_puts(&to,",");
+  substdio_flush(&to);
+
+  for (;;) {
+    substdio_get(&from,&ch,1);
+    if (ch == 'K') die_success();
+    if (ch == 'Z') die_temp();
+    if (ch == 'D') die_perm();
+  }
+}
+
+stralloc servers = {0};
+
+main()
+{
+  int i;
+  int j;
+
+  sig_pipeignore();
+
+  if (chdir(auto_qmail) == -1) die_home();
+  if (control_init() == -1) die_control();
+  if (control_readfile(&servers,"control/qmqpservers",0) != 1) die_control();
+
+  getmess();
+
+  i = 0;
+  for (j = 0;j < servers.len;++j)
+    if (!servers.s[j]) {
+      doit(servers.s + i);
+      i = j + 1;
+    }
+
+  _exit(lasterror);
+}
diff --git a/qmail-qmqpd.8 b/qmail-qmqpd.8
new file mode 100644 (file)
index 0000000..5142dfa
--- /dev/null
@@ -0,0 +1,25 @@
+.TH qmail-qmqpd 8
+.SH NAME
+qmail-qmqpd \- receive mail via QMQP
+.SH SYNOPSIS
+.B qmail-qmqpd
+.SH DESCRIPTION
+.B qmail-qmqpd
+receives mail messages via the Quick Mail Queueing Protocol (QMQP)
+and invokes
+.B qmail-queue
+to deposit them into the outgoing queue.
+.B qmail-qmqpd
+must be supplied several environment variables;
+see
+.BR tcp-environ(5) .
+
+.B qmail-qmqpd
+will relay messages to any destination.
+It should be invoked only for connections from preauthorized users.
+.SH "SEE ALSO"
+tcp-env(1),
+tcpserver(1),
+tcp-environ(5),
+qmail-qmqpc(8),
+qmail-queue(8)
diff --git a/qmail-qmqpd.c b/qmail-qmqpd.c
new file mode 100644 (file)
index 0000000..86cb284
--- /dev/null
@@ -0,0 +1,174 @@
+#include "auto_qmail.h"
+#include "qmail.h"
+#include "received.h"
+#include "sig.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "now.h"
+#include "fmt.h"
+#include "env.h"
+
+void resources() { _exit(111); }
+
+int safewrite(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = write(fd,buf,len);
+  if (r <= 0) _exit(0);
+  return r;
+}
+int saferead(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = read(fd,buf,len);
+  if (r <= 0) _exit(0);
+  return r;
+}
+
+char ssinbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+char ssoutbuf[256];
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
+
+unsigned long bytesleft = 100;
+
+void getbyte(ch)
+char *ch;
+{
+  if (!bytesleft--) _exit(100);
+  substdio_get(&ssin,ch,1);
+}
+
+unsigned long getlen()
+{
+  unsigned long len = 0;
+  char ch;
+
+  for (;;) {
+    getbyte(&ch);
+    if (ch == ':') return len;
+    if (len > 200000000) resources();
+    len = 10 * len + (ch - '0');
+  }
+}
+
+void getcomma()
+{
+  char ch;
+  getbyte(&ch);
+  if (ch != ',') _exit(100);
+}
+
+struct qmail qq;
+
+void identify()
+{
+  char *remotehost;
+  char *remoteinfo;
+  char *remoteip;
+  char *local;
+
+  remotehost = env_get("TCPREMOTEHOST");
+  if (!remotehost) remotehost = "unknown";
+  remoteinfo = env_get("TCPREMOTEINFO");
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) remoteip = "unknown";
+  local = env_get("TCPLOCALHOST");
+  if (!local) local = env_get("TCPLOCALIP");
+  if (!local) local = "unknown";
+  received(&qq,"QMQP",local,remoteip,remotehost,remoteinfo,(char *) 0);
+}
+
+char buf[1000];
+char strnum[FMT_ULONG];
+
+int getbuf()
+{
+  unsigned long len;
+  int i;
+
+  len = getlen();
+  if (len >= 1000) {
+    for (i = 0;i < len;++i) getbyte(buf);
+    getcomma();
+    buf[0] = 0;
+    return 0;
+  }
+
+  for (i = 0;i < len;++i) getbyte(buf + i);
+  getcomma();
+  buf[len] = 0;
+  return byte_chr(buf,len,'\0') == len;
+}
+
+int flagok = 1;
+
+main()
+{
+  char *result;
+  unsigned long qp;
+  unsigned long len;
+  char ch;
+
+  sig_pipeignore();
+  sig_alarmcatch(resources);
+  alarm(3600);
+
+  bytesleft = getlen();
+
+  len = getlen();
+
+  if (chdir(auto_qmail) == -1) resources();
+  if (qmail_open(&qq) == -1) resources();
+  qp = qmail_qp(&qq);
+  identify();
+
+  while (len > 0) { /* XXX: could speed this up */
+    getbyte(&ch);
+    --len;
+    qmail_put(&qq,&ch,1);
+  }
+  getcomma();
+
+  if (getbuf())
+    qmail_from(&qq,buf);
+  else {
+    qmail_from(&qq,"");
+    qmail_fail(&qq);
+    flagok = 0;
+  }
+
+  while (bytesleft)
+    if (getbuf())
+      qmail_to(&qq,buf);
+    else {
+      qmail_fail(&qq);
+      flagok = 0;
+    }
+
+  bytesleft = 1;
+  getcomma();
+
+  result = qmail_close(&qq);
+
+  if (!*result) {
+    len = fmt_str(buf,"Kok ");
+    len += fmt_ulong(buf + len,(unsigned long) now());
+    len += fmt_str(buf + len," qp ");
+    len += fmt_ulong(buf + len,qp);
+    buf[len] = 0;
+    result = buf;
+  }
+
+  if (!flagok)
+    result = "Dsorry, I can't accept addresses like that (#5.1.3)";
+
+  substdio_put(&ssout,strnum,fmt_ulong(strnum,(unsigned long) str_len(result)));
+  substdio_puts(&ssout,":");
+  substdio_puts(&ssout,result);
+  substdio_puts(&ssout,",");
+  substdio_flush(&ssout);
+  _exit(0);
+}
index 0b52452..244fdbf 100644 (file)
@@ -16,9 +16,12 @@ see
 
 .B qmail-qmtpd
 supports the
-.I rcpthosts
+.IR rcpthosts ,
+.IR morercpthosts ,
+.BR RELAYCLIENT ,
+.IR databytes ,
 and
-.B RELAYCLIENT
+.B DATABYTES
 mechanisms described in
 .BR qmail-smtpd(8) .
 .SH "SEE ALSO"
index fab2a0d..df911a6 100644 (file)
@@ -1,52 +1,66 @@
 #include "stralloc.h"
 #include "substdio.h"
-#include "subfd.h"
 #include "qmail.h"
 #include "now.h"
 #include "str.h"
 #include "fmt.h"
 #include "env.h"
 #include "sig.h"
+#include "rcpthosts.h"
 #include "auto_qmail.h"
-#include "now.h"
-#include "datetime.h"
-#include "date822fmt.h"
 #include "readwrite.h"
 #include "control.h"
-#include "constmap.h"
 #include "received.h"
 
-struct qmail qqt;
-
-void dropped() { _exit(0); }
 void badproto() { _exit(100); }
 void resources() { _exit(111); }
-void sigalrm() { _exit(111); }
 
-unsigned long getlen()
+int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
- unsigned long len;
- char ch;
+  int r;
+  r = write(fd,buf,len);
+  if (r <= 0) _exit(0);
+  return r;
+}
+
+char ssoutbuf[256];
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
 
- len = 0;
- for (;;)
-  {
-   if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-   if (ch == ':') return len;
-   if (len > 200000000) resources();
-   len = 10 * len + (ch - '0');
+int saferead(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  substdio_flush(&ssout);
+  r = read(fd,buf,len);
+  if (r <= 0) _exit(0);
+  return r;
+}
+
+char ssinbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+
+unsigned long getlen()
+{
+  unsigned long len = 0;
+  char ch;
+  for (;;) {
+    substdio_get(&ssin,&ch,1);
+    if (ch == ':') return len;
+    if (len > 200000000) resources();
+    len = 10 * len + (ch - '0');
   }
 }
 
 void getcomma()
 {
- char ch;
-
- if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
- if (ch != ',') badproto();
+  char ch;
+  substdio_get(&ssin,&ch,1);
+  if (ch != ',') badproto();
 }
 
-struct datetime dt;
+unsigned int databytes = 0;
+unsigned int bytestooverflow = 0;
+struct qmail qq;
+
 char buf[1000];
 char buf2[100];
 
@@ -57,225 +71,198 @@ char *local;
 
 stralloc failure = {0};
 
-int flagrcpthosts;
-stralloc rcpthosts = {0};
-struct constmap maprcpthosts;
 char *relayclient;
 int relayclientlen;
 
-int addrallowed(buf,len) char *buf; int len;
-{
- int j;
- if (!flagrcpthosts) return 1;
- j = byte_rchr(buf,len,'@');
- if (j >= len) return 1;
- if (constmap(&maprcpthosts,buf + j + 1,len - j - 1)) return 1;
- for (;j < len;++j)
-   if (buf[j] == '.')
-     if (constmap(&maprcpthosts,buf + j,len - j)) return 1;
- return 0;
-}
-
 main()
 {
- char ch;
- int i;
- unsigned long biglen;
- unsigned long len;
- int flagdos;
- int flagsenderok;
- unsigned long qp;
- char *result;
-
- sig_pipeignore();
- sig_alarmcatch(sigalrm);
- alarm(3600);
-
- if (chdir(auto_qmail) == -1) resources();
-
- if (control_init() == -1) resources();
- flagrcpthosts = control_readfile(&rcpthosts,"control/rcpthosts",0);
- if (flagrcpthosts == -1) resources();
- if (flagrcpthosts)
-   if (!constmap_init(&maprcpthosts,rcpthosts.s,rcpthosts.len,0)) resources();
- relayclient = env_get("RELAYCLIENT");
- relayclientlen = relayclient ? str_len(relayclient) : 0;
-
- remotehost = env_get("TCPREMOTEHOST");
- if (!remotehost) remotehost = "unknown";
- remoteinfo = env_get("TCPREMOTEINFO");
- remoteip = env_get("TCPREMOTEIP");
- if (!remoteip) remoteip = "unknown";
- local = env_get("TCPLOCALHOST");
- if (!local) local = env_get("TCPLOCALIP");
- if (!local) local = "unknown";
-
- for (;;)
-  {
-   if (!stralloc_copys(&failure,"")) resources();
-   flagsenderok = 1;
-
-   len = getlen();
-   if (len == 0) badproto();
-
-   if (qmail_open(&qqt) == -1) resources();
-   qp = qmail_qp(&qqt);
-
-   if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-   --len;
-
-   if (ch == 10) flagdos = 0;
-   else if (ch == 13) flagdos = 1;
-   else badproto();
-
-   received(&qqt,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0);
-
-   /* XXX: check for loops? only if len is big? */
-
-   if (flagdos)
-     while (len > 0)
-      {
-       if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-       --len;
-       while ((ch == 13) && len)
-        {
-         if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-         --len;
-         if (ch == 10) break;
-         qmail_put(&qqt,"\015",1);
+  char ch;
+  int i;
+  unsigned long biglen;
+  unsigned long len;
+  int flagdos;
+  int flagsenderok;
+  int flagbother;
+  unsigned long qp;
+  char *result;
+  char *x;
+  unsigned long u;
+  sig_pipeignore();
+  sig_alarmcatch(resources);
+  alarm(3600);
+  if (chdir(auto_qmail) == -1) resources();
+  if (control_init() == -1) resources();
+  if (rcpthosts_init() == -1) resources();
+  relayclient = env_get("RELAYCLIENT");
+  relayclientlen = relayclient ? str_len(relayclient) : 0;
+  if (control_readint(&databytes,"control/databytes") == -1) resources();
+  x = env_get("DATABYTES");
+  if (x) { scan_ulong(x,&u); databytes = u; }
+  if (!(databytes + 1)) --databytes;
+  remotehost = env_get("TCPREMOTEHOST");
+  if (!remotehost) remotehost = "unknown";
+  remoteinfo = env_get("TCPREMOTEINFO");
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) remoteip = "unknown";
+  local = env_get("TCPLOCALHOST");
+  if (!local) local = env_get("TCPLOCALIP");
+  if (!local) local = "unknown";
+  for (;;) {
+    if (!stralloc_copys(&failure,"")) resources();
+    flagsenderok = 1;
+    len = getlen();
+    if (len == 0) badproto();
+    if (databytes) bytestooverflow = databytes + 1;
+    if (qmail_open(&qq) == -1) resources();
+    qp = qmail_qp(&qq);
+    substdio_get(&ssin,&ch,1);
+    --len;
+    if (ch == 10) flagdos = 0;
+    else if (ch == 13) flagdos = 1;
+    else badproto();
+    received(&qq,"QMTP",local,remoteip,remotehost,remoteinfo,(char *) 0);
+    /* XXX: check for loops? only if len is big? */
+    if (flagdos)
+      while (len > 0) {
+        substdio_get(&ssin,&ch,1);
+        --len;
+        while ((ch == 13) && len) {
+          substdio_get(&ssin,&ch,1);
+          --len;
+          if (ch == 10) break;
+          if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq);
+          qmail_put(&qq,"\015",1);
         }
-       qmail_put(&qqt,&ch,1);
+        if (bytestooverflow) if (!--bytestooverflow) qmail_fail(&qq);
+        qmail_put(&qq,&ch,1);
       }
-   else
-     while (len > 0) /* XXX: could speed this up, obviously */
-      {
-       if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-       --len;
-       qmail_put(&qqt,&ch,1);
+    else {
+      if (databytes)
+        if (len > databytes) {
+          bytestooverflow = 0;
+          qmail_fail(&qq);
+        }
+      while (len > 0) { /* XXX: could speed this up, obviously */
+        substdio_get(&ssin,&ch,1);
+        --len;
+        qmail_put(&qq,&ch,1);
       }
-   getcomma();
-
-   len = getlen();
-
-   if (len >= 1000)
-    {
-     buf[0] = 0;
-     flagsenderok = 0;
-     for (i = 0;i < len;++i)
-       if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
     }
-   else
-    {
-     for (i = 0;i < len;++i)
-      {
-       if (substdio_get(subfdinsmall,buf + i,1) < 1) dropped();
-       if (!buf[i]) flagsenderok = 0;
+    getcomma();
+    len = getlen();
+    if (len >= 1000) {
+      buf[0] = 0;
+      flagsenderok = 0;
+      for (i = 0;i < len;++i)
+        substdio_get(&ssin,&ch,1);
+    }
+    else {
+      for (i = 0;i < len;++i) {
+        substdio_get(&ssin,buf + i,1);
+        if (!buf[i]) flagsenderok = 0;
       }
-     buf[len] = 0;
+      buf[len] = 0;
     }
-   getcomma();
-
-   qmail_from(&qqt,buf);
-   if (!flagsenderok) qmail_fail(&qqt);
-
-   biglen = getlen();
-   while (biglen > 0)
-    {
-     if (!stralloc_append(&failure,"")) resources();
-
-     len = 0;
-     for (;;)
-      {
-       if (!biglen) badproto();
-       if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
-       --biglen;
-       if (ch == ':') break;
-       if (len > 200000000) resources();
-       len = 10 * len + (ch - '0');
+    getcomma();
+    flagbother = 0;
+    qmail_from(&qq,buf);
+    if (!flagsenderok) qmail_fail(&qq);
+    biglen = getlen();
+    while (biglen > 0) {
+      if (!stralloc_append(&failure,"")) resources();
+      len = 0;
+      for (;;) {
+        if (!biglen) badproto();
+        substdio_get(&ssin,&ch,1);
+        --biglen;
+        if (ch == ':') break;
+        if (len > 200000000) resources();
+        len = 10 * len + (ch - '0');
       }
-     if (len >= biglen) badproto();
-     if (len + relayclientlen >= 1000)
-      {
-       failure.s[failure.len - 1] = 'L';
-       for (i = 0;i < len;++i)
-         if (substdio_get(subfdinsmall,&ch,1) < 1) dropped();
+      if (len >= biglen) badproto();
+      if (len + relayclientlen >= 1000) {
+        failure.s[failure.len - 1] = 'L';
+        for (i = 0;i < len;++i)
+          substdio_get(&ssin,&ch,1);
       }
-     else
-      {
-       for (i = 0;i < len;++i)
-        {
-         if (substdio_get(subfdinsmall,buf + i,1) < 1) dropped();
-         if (!buf[i]) failure.s[failure.len - 1] = 'N';
+      else {
+        for (i = 0;i < len;++i) {
+          substdio_get(&ssin,buf + i,1);
+          if (!buf[i]) failure.s[failure.len - 1] = 'N';
+        }
+        buf[len] = 0;
+        if (relayclient)
+          str_copy(buf + len,relayclient);
+        else
+          switch(rcpthosts(buf,len)) {
+            case -1: resources();
+            case 0: failure.s[failure.len - 1] = 'D';
+          }
+        if (!failure.s[failure.len - 1]) {
+          qmail_to(&qq,buf);
+          flagbother = 1;
         }
-       buf[len] = 0;
-
-       if (relayclient)
-        str_copy(buf + len,relayclient);
-       else
-        if (!addrallowed(buf,len)) failure.s[failure.len - 1] = 'D';
-
-       if (!failure.s[failure.len - 1])
-        qmail_to(&qqt,buf);
       }
-     getcomma();
-     biglen -= (len + 1);
+      getcomma();
+      biglen -= (len + 1);
     }
-   getcomma();
-
-   switch(qmail_close(&qqt))
-    {
-     case 0: result = 0; break;
-     case QMAIL_WAITPID: result = "Zqq waitpid surprise (#4.3.0)"; break;
-     case QMAIL_CRASHED: result = "Zqq crashed (#4.3.0)"; break;
-     case QMAIL_USAGE: result = "Zqq usage surprise (#4.3.0)"; break;
-     case QMAIL_SYS: result = "Zqq system error (#4.3.0)"; break;
-     case QMAIL_READ: result = "Zqq read error (#4.3.0)"; break;
-     case QMAIL_WRITE: result = "Zqq write error or disk full (#4.3.0)"; break;
-     case QMAIL_NOMEM: result = "Zqq out of memory (#4.3.0)"; break;
-     case QMAIL_EXECSOFT: result = "Zcould not exec qq (#4.3.0)"; break;
-     case QMAIL_TIMEOUT: result = "Zqq timeout (#4.3.0)"; break;
-     case QMAIL_TOOLONG: result = "Dqq toolong surprise (#5.1.3)"; break;
-     default: result = "Zqq internal bug (#4.3.0)"; break;
+    getcomma();
+    if (!flagbother) qmail_fail(&qq);
+    result = qmail_close(&qq);
+    if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)";
+    if (databytes) if (!bytestooverflow) result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
+    if (*result)
+      len = str_len(result);
+    else {
+      /* success! */
+      len = 0;
+      len += fmt_str(buf2 + len,"Kok ");
+      len += fmt_ulong(buf2 + len,(unsigned long) now());
+      len += fmt_str(buf2 + len," qp ");
+      len += fmt_ulong(buf2 + len,qp);
+      buf2[len] = 0;
+      result = buf2;
     }
-
-   if (!flagsenderok) result = "Dunacceptable sender (#5.1.7)";
-
-   if (result)
-     len = str_len(result);
-   else
-    {
-     /* success! */
-     len = 0;
-     len += fmt_str(buf2 + len,"Kok ");
-     len += fmt_ulong(buf2 + len,(unsigned long) now());
-     len += fmt_str(buf2 + len," qp ");
-     len += fmt_ulong(buf2 + len,qp);
-     buf2[len] = 0;
-     result = buf2;
-    }
-     
-   len = fmt_ulong(buf,len);
-   buf[len++] = ':';
-   len += fmt_str(buf + len,result);
-   buf[len++] = ',';
-
-   for (i = 0;i < failure.len;++i)
-     switch(failure.s[i])
-      {
-       case 0:
-         if (substdio_put(subfdoutsmall,buf,len) == -1)
-           dropped();
-        break;
-       case 'D':
-         if (substdio_puts(subfdoutsmall,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),") == -1)
-          dropped();
-        break;
-       default:
-         if (substdio_puts(subfdoutsmall,"46:Dsorry, I can't handle that recipient (#5.1.3),") == -1)
-          dropped();
-        break;
+      
+    len = fmt_ulong(buf,len);
+    buf[len++] = ':';
+    len += fmt_str(buf + len,result);
+    buf[len++] = ',';
+    for (i = 0;i < failure.len;++i)
+      switch(failure.s[i]) {
+        case 0:
+          substdio_put(&ssout,buf,len);
+          break;
+        case 'D':
+          substdio_puts(&ssout,"66:Dsorry, that domain isn't in my list of allowed rcpthosts (#5.7.1),");
+          break;
+        default:
+          substdio_puts(&ssout,"46:Dsorry, I can't handle that recipient (#5.1.3),");
+          break;
       }
-
-   /* subfdoutsmall will be flushed when we read from the network again */
+    /* ssout will be flushed when we read from the network again */
   }
 }
index 21a8c00..26a6d3f 100644 (file)
@@ -1,3 +1,7 @@
 cd QMAIL
-echo messages in queue: `find queue/mess -type f -print | wc -l`
-echo messages in queue but not yet preprocessed: `find queue/todo -type f -print | wc -l`
+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`
+echo messages in queue: `expr $messfiles - $messdirs`
+echo messages in queue but not yet preprocessed: `expr $todofiles - $tododirs`
index 33ca546..12eea0c 100644 (file)
@@ -25,7 +25,7 @@ sees end-of-file before the extra 0 byte,
 it aborts without placing the message into the queue.
 
 Every envelope recipient address
-must contain a username,
+should contain a username,
 an @ sign,
 and a fully qualified domain name.
 
@@ -40,19 +40,116 @@ and does not enforce any restrictions on its contents.
 However, the recipients probably expect to see a proper header,
 as described in
 .BR qmail-header(5) .
+.SH "FILESYSTEM RESTRICTIONS"
+.B qmail-queue
+imposes two constraints on the queue structure:
+each
+.B mess
+subdirectory must be in the same filesystem as the
+.B pid
+directory; and each
+.B todo
+subdirectory must be in the same filesystem as the
+.B intd
+directory.
 .SH "EXIT CODES"
-0 if
 .B qmail-queue
-has successfully queued the message,
-nonzero if
+does not print diagnostics.
+It exits
+0 if
+it has successfully queued the message.
+It exits between 1 and 99 if
+it has failed to queue the message.
+
+All
 .B qmail-queue
-has failed to queue the message.
+error codes between 11 and 40
+indicate permanent errors:
+.TP 5
+.B 11
+Address too long.
+.TP
+.B 31
+Mail server permanently refuses to send the message to any recipients.
+(Not used by
+.BR qmail-queue ,
+but can be used by programs offering the same interface.)
+.PP
+All other
 .B qmail-queue
-does not print diagnostics.
+error codes indicate temporary errors:
+.TP 5
+.B 51
+Out of memory.
+.TP
+.B 52
+Timeout.
+.TP
+.B 53
+Write error; e.g., disk full.
+.TP
+.B 54
+Unable to read the message or envelope.
+.TP
+.B 55
+Unable to read a configuration file.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 56
+Problem making a network connection from this host.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 61
+Problem with the qmail home directory.
+.TP
+.B 62
+Problem with the queue directory.
+.TP
+.B 63
+Problem with queue/pid.
+.TP
+.B 64
+Problem with queue/mess.
+.TP
+.B 65
+Problem with queue/intd.
+.TP
+.B 66
+Problem with queue/todo.
+.TP
+.B 71
+Mail server temporarily refuses to send the message to any recipients.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 72
+Connection to mail server timed out.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 73
+Connection to mail server rejected.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 74
+Connection to mail server succeeded,
+but communication failed.
+(Not used by
+.BR qmail-queue .)
+.TP
+.B 81
+Internal bug; e.g., segmentation fault.
+.TP
+.B 91
+Envelope format error.
 .SH "SEE ALSO"
 addresses(5),
 envelopes(5),
 qmail-header(5),
 qmail-inject(8),
+qmail-qmqpc(8),
 qmail-send(8),
 qmail-smtpd(8)
index 26483b2..4b39a8f 100644 (file)
@@ -55,10 +55,10 @@ void cleanup()
 }
 
 void die(e) int e; { _exit(e); }
-void die_write() { cleanup(); die(122); }
-void die_read() { cleanup(); die(121); }
-void sigalrm() { /* thou shalt not clean up here */ die(124); }
-void sigbug() { die(101); }
+void die_write() { cleanup(); die(53); }
+void die_read() { cleanup(); die(54); }
+void sigalrm() { /* thou shalt not clean up here */ die(52); }
+void sigbug() { die(81); }
 
 unsigned int receivedlen;
 char *received;
@@ -93,7 +93,7 @@ void received_setup()
 {
  receivedlen = receivedfmt((char *) 0);
  received = alloc(receivedlen + 1);
- if (!received) die(123);
+ if (!received) die(51);
  receivedfmt(received);
 }
 
@@ -123,7 +123,7 @@ int flagsplit;
  char *s;
 
  s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit));
- if (!s) die(123);
+ if (!s) die(51);
  fmtqfn(s,dirslash,messnum,flagsplit);
  return s;
 }
@@ -136,17 +136,17 @@ void pidopen()
  seq = 1;
  len = pidfmt((char *) 0,seq);
  pidfn = alloc(len);
- if (!pidfn) die(123);
+ if (!pidfn) die(51);
 
  for (seq = 1;seq < 10;++seq)
   {
-   if (pidfmt((char *) 0,seq) > len) die(101); /* paranoia */
+   if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */
    pidfmt(pidfn,seq);
    messfd = open_excl(pidfn);
    if (messfd != -1) return;
   }
 
- die(103);
+ die(63);
 }
 
 char tmp[FMT_ULONG];
@@ -158,8 +158,8 @@ void main()
 
  sig_blocknone();
  umask(033);
- if (chdir(auto_qmail) == -1) die(102);
- if (chdir("queue") == -1) die(102);
+ if (chdir(auto_qmail) == -1) die(61);
+ if (chdir("queue") == -1) die(62);
 
  mypid = getpid();
  uid = getuid();
@@ -176,15 +176,15 @@ void main()
  alarm(DEATH);
 
  pidopen();
- if (fstat(messfd,&pidst) == -1) die(104);
+ if (fstat(messfd,&pidst) == -1) die(63);
 
  messnum = pidst.st_ino;
  messfn = fnnum("mess/",1);
  todofn = fnnum("todo/",0);
  intdfn = fnnum("intd/",0);
 
- if (link(pidfn,messfn) == -1) die(105);
- if (unlink(pidfn) == -1) die(105);
+ if (link(pidfn,messfn) == -1) die(64);
+ if (unlink(pidfn) == -1) die(63);
  flagmademess = 1;
 
  substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
@@ -202,7 +202,7 @@ void main()
  if (fsync(messfd) == -1) die_write();
 
  intdfd = open_excl(intdfn);
- if (intdfd == -1) die(108);
+ if (intdfd == -1) die(65);
  flagmadeintd = 1;
 
  substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf));
@@ -217,7 +217,7 @@ void main()
  if (substdio_bput(&ssout,"",1) == -1) die_write();
 
  if (substdio_get(&ssin,&ch,1) < 1) die_read();
- if (ch != 'F') die(112);
+ if (ch != 'F') die(91);
  if (substdio_bput(&ssout,&ch,1) == -1) die_write();
  for (len = 0;len < ADDR;++len)
   {
@@ -225,7 +225,7 @@ void main()
    if (substdio_put(&ssout,&ch,1) == -1) die_write();
    if (!ch) break;
   }
- if (len >= ADDR) die(115);
+ if (len >= ADDR) die(11);
 
  if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
 
@@ -233,7 +233,7 @@ void main()
   {
    if (substdio_get(&ssin,&ch,1) < 1) die_read();
    if (!ch) break;
-   if (ch != 'T') die(112);
+   if (ch != 'T') die(91);
    if (substdio_bput(&ssout,&ch,1) == -1) die_write();
    for (len = 0;len < ADDR;++len)
     {
@@ -241,13 +241,13 @@ void main()
      if (substdio_bput(&ssout,&ch,1) == -1) die_write();
      if (!ch) break;
     }
-   if (len >= ADDR) die(115);
+   if (len >= ADDR) die(11);
   }
 
  if (substdio_flush(&ssout) == -1) die_write();
  if (fsync(intdfd) == -1) die_write();
 
- if (link(intdfn,todofn) == -1) die(106);
+ if (link(intdfn,todofn) == -1) die(66);
 
  triggerpull();
  die(0);
index 552ac92..08bae85 100644 (file)
@@ -142,8 +142,6 @@ had
 .I relay
 as its only MX.
 (It will also avoid doing any CNAME lookups on
-.I sender
-and
 .IR recip .)
 .I host
 may include a colon and a port number to use instead of the
@@ -203,4 +201,5 @@ envelopes(5),
 qmail-control(5),
 qmail-send(8),
 qmail-smtpd(8),
+qmail-tcpok(8),
 qmail-tcpto(8)
index 4495b69..7d65473 100644 (file)
@@ -3,7 +3,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include "sig.h"
-#include "getln.h"
 #include "stralloc.h"
 #include "substdio.h"
 #include "subfd.h"
@@ -25,6 +24,7 @@
 #include "exit.h"
 #include "constmap.h"
 #include "tcpto.h"
+#include "readwrite.h"
 #include "timeoutconn.h"
 #include "timeoutread.h"
 #include "timeoutwrite.h"
@@ -48,14 +48,13 @@ saa reciplist = {0};
 
 struct ip_address partner;
 
-void out(s) char *s; { if (substdio_puts(subfdout,s) == -1) _exit(0); }
-void zero() { if (substdio_put(subfdout,"\0",1) == -1) _exit(0); }
-void zerodie() { zero(); substdio_flush(subfdout); _exit(0); }
-
+void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
+void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
+void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
 void outsafe(sa) stralloc *sa; { int i; char ch;
 for (i = 0;i < sa->len;++i) {
 ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
-if (substdio_put(subfdout,&ch,1) == -1) _exit(0); } }
+if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
 
 void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
 void temp_oserr() { out("Z\
@@ -87,251 +86,191 @@ Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
 it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
 zerodie(); }
 
-int timeout = 1200;
+void outhost()
+{
+  char x[IPFMT];
+  if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner)) == -1) _exit(0);
+}
+
+int flagcritical = 0;
+
+void dropped() {
+  out("ZConnected to ");
+  outhost();
+  out(" but connection died. ");
+  if (flagcritical) out("Possible duplicate! ");
+  out("(#4.4.2)\n");
+  zerodie();
+}
+
 int timeoutconnect = 60;
+int smtpfd;
+int timeout = 1200;
 
-void getcontrols()
+int saferead(fd,buf,len) int fd; char *buf; int len;
 {
- int r;
- if (control_init() == -1)
-  { if (errno == error_nomem) temp_nomem(); temp_control(); }
-
- if (control_readint(&timeout,"control/timeoutremote") == -1)
-  { if (errno == error_nomem) temp_nomem(); temp_control(); }
- if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
-  { if (errno == error_nomem) temp_nomem(); temp_control(); }
-
- r = control_rldef(&helohost,"control/helohost",1,(char *) 0);
- if (r == -1) if (errno == error_nomem) temp_nomem();
- if (r != 1) temp_control();
-
- switch(control_readfile(&routes,"control/smtproutes",0))
-  {
-   case -1:
-     if (errno == error_nomem) temp_nomem(); temp_control();
-   case 0:
-     if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break;
-   case 1:
-     if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
-  }
+  int r;
+  r = timeoutread(timeout,smtpfd,buf,len);
+  if (r <= 0) dropped();
+  return r;
+}
+int safewrite(fd,buf,len) int fd; char *buf; int len;
+{
+  int r;
+  r = timeoutwrite(timeout,smtpfd,buf,len);
+  if (r <= 0) dropped();
+  return r;
 }
 
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf);
 char smtptobuf[1024];
+substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf);
 char smtpfrombuf[128];
-stralloc smtpline = {0};
+substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf);
+
 stralloc smtptext = {0};
 
-void outsmtptext()
+void get(ch)
+char *ch;
 {
- int i; 
- if (smtptext.s) if (smtptext.len) if (smtptext.len < HUGESMTPTEXT)
-  {
-   if (substdio_puts(subfdout,"Remote host said: ") == -1) _exit(0);
-   for (i = 0;i < smtptext.len;++i)
-     if (!smtptext.s[i]) smtptext.s[i] = '?';
-   if (substdio_put(subfdout,smtptext.s,smtptext.len) == -1) _exit(0);
-   smtptext.len = 0;
-  }
+  substdio_get(&smtpfrom,ch,1);
+  if (*ch != '\r')
+    if (smtptext.len < HUGESMTPTEXT)
+     if (!stralloc_append(&smtptext,ch)) temp_nomem();
 }
 
-unsigned long smtpcode(ss)
-substdio *ss;
+unsigned long smtpcode()
 {
- int match;
- unsigned long code;
-
- if (!stralloc_copys(&smtptext,"")) return 421;
- do
-  {
-   if (getln(ss,&smtpline,&match,'\n') != 0) return 421;
-   if (!match) return 421;
-   if ((smtpline.len >= 2) && (smtpline.s[smtpline.len - 2] == '\r'))
-    {
-     smtpline.s[smtpline.len - 2] = '\n';
-     --smtpline.len;
-    }
-   if (!stralloc_cat(&smtptext,&smtpline)) return 421;
-   if (scan_nbblong(smtpline.s,smtpline.len,10,0,&code) != 3) return 421;
-   if (smtpline.len == 3) return code;
+  unsigned char ch;
+  unsigned long code;
+
+  if (!stralloc_copys(&smtptext,"")) temp_nomem();
+
+  get(&ch); code = ch - '0';
+  get(&ch); code = code * 10 + (ch - '0');
+  get(&ch); code = code * 10 + (ch - '0');
+  for (;;) {
+    get(&ch);
+    if (ch != '-') break;
+    while (ch != '\n') get(&ch);
+    get(&ch);
+    get(&ch);
+    get(&ch);
   }
while (smtpline.s[3] == '-');
 while (ch != '\n') get(&ch);
 
- return code;
 return code;
 }
 
-void outhost()
-{
- char x[IPFMT];
-
- x[ip_fmt(x,&partner)] = 0;
- out(x);
-}
-
-void writeerr()
+void outsmtptext()
 {
- out("ZConnected to "); outhost();
- out(" but communications failed. (#4.4.2)\n");
- zerodie();
+  int i; 
+  if (smtptext.s) if (smtptext.len) {
+    out("Remote host said: ");
+    for (i = 0;i < smtptext.len;++i)
+      if (!smtptext.s[i]) smtptext.s[i] = '?';
+    if (substdio_put(subfdoutsmall,smtptext.s,smtptext.len) == -1) _exit(0);
+    smtptext.len = 0;
+  }
 }
 
-void quit(ssto,ssfrom)
-substdio *ssto;
-substdio *ssfrom;
+void quit(prepend,append)
+char *prepend;
+char *append;
 {
- outsmtptext();
- if (substdio_putsflush(ssto,"QUIT\r\n") != -1)
-   smtpcode(ssfrom); /* protocol design stupidity */
- zerodie();
+  substdio_putsflush(&smtpto,"QUIT\r\n");
+  /* waiting for remote side is just too ridiculous */
+  out(prepend);
+  outhost();
+  out(append);
+  out(".\n");
+  outsmtptext();
+  zerodie();
 }
 
-stralloc dataline = {0};
-
-void blast(ssto,ssfrom)
-substdio *ssto;
-substdio *ssfrom;
+void blast()
 {
- int match;
-
- for (;;)
-  {
-   if (getln(ssfrom,&dataline,&match,'\n') != 0) temp_read();
-   if (!match && !dataline.len) break;
-   if (!match) perm_partialline();
-   --dataline.len;
-   if (dataline.len && (dataline.s[0] == '.'))
-     if (substdio_put(ssto,".",1) == -1) writeerr();
-   if (substdio_put(ssto,dataline.s,dataline.len) == -1) writeerr();
-   if (substdio_put(ssto,"\r\n",2) == -1) writeerr();
+  int r;
+  char ch;
+
+  for (;;) {
+    r = substdio_get(&ssin,&ch,1);
+    if (r == 0) break;
+    if (r == -1) temp_read();
+    if (ch == '.')
+      substdio_put(&smtpto,".",1);
+    while (ch != '\n') {
+      substdio_put(&smtpto,&ch,1);
+      r = substdio_get(&ssin,&ch,1);
+      if (r == 0) perm_partialline();
+      if (r == -1) temp_read();
+    }
+    substdio_put(&smtpto,"\r\n",2);
   }
- if (substdio_put(ssto,".\r\n",3) == -1) writeerr();
- if (substdio_flush(ssto) == -1) writeerr();
+  flagcritical = 1;
+  substdio_put(&smtpto,".\r\n",3);
+  substdio_flush(&smtpto);
 }
 
 stralloc recip = {0};
 
-void smtp(fd)
-int fd;
+void smtp()
 {
- substdio ssto;
- substdio ssfrom;
- unsigned long code;
- int flaganyrecipok;
- int i;
-
- substdio_fdbuf(&ssto,timeoutwrite,TIMEOUTWRITE(timeout,fd),smtptobuf,sizeof(smtptobuf));
- substdio_fdbuf(&ssfrom,timeoutread,TIMEOUTREAD(timeout,fd),smtpfrombuf,sizeof(smtpfrombuf));
-
- if (smtpcode(&ssfrom) != 220)
-  {
-   out("ZConnected to "); outhost(); out(" but greeting failed.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- if (substdio_puts(&ssto,"HELO ") == -1) writeerr();
- if (substdio_put(&ssto,helohost.s,helohost.len) == -1) writeerr();
- if (substdio_puts(&ssto,"\r\n") == -1) writeerr();
- if (substdio_flush(&ssto) == -1) writeerr();
-
- if (smtpcode(&ssfrom) != 250)
-  {
-   out("ZConnected to "); outhost(); out(" but my name was rejected.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- if (substdio_puts(&ssto,"MAIL FROM:<") == -1) writeerr();
- if (substdio_put(&ssto,sender.s,sender.len) == -1) writeerr();
- if (substdio_puts(&ssto,">\r\n") == -1) writeerr();
- if (substdio_flush(&ssto) == -1) writeerr();
-
- code = smtpcode(&ssfrom);
- if (code >= 500)
-  {
-   out("DConnected to "); outhost(); out(" but sender was rejected.\n");
-   quit(&ssto,&ssfrom);
-  }
- if (code >= 400)
-  {
-   out("ZConnected to "); outhost(); out(" but sender was rejected.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- flaganyrecipok = 0;
- for (i = 0;i < reciplist.len;++i)
-  {
-   if (substdio_puts(&ssto,"RCPT TO:<") == -1) writeerr();
-   if (substdio_put(&ssto,reciplist.sa[i].s,reciplist.sa[i].len) == -1) writeerr();
-   if (substdio_puts(&ssto,">\r\n") == -1) writeerr();
-   if (substdio_flush(&ssto) == -1) writeerr();
-
-   code = smtpcode(&ssfrom);
-   if (code == 421)
-    {
-     out("ZConnected to "); outhost(); out(" but connection died.\n");
-     quit(&ssto,&ssfrom);
-    }
-   if (code >= 500)
-    {
-     out("h"); outhost(); out(" does not like recipient.\n");
-     outsmtptext(); zero();
+  unsigned long code;
+  int flagbother;
+  int i;
+  if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
+  substdio_puts(&smtpto,"HELO ");
+  substdio_put(&smtpto,helohost.s,helohost.len);
+  substdio_puts(&smtpto,"\r\n");
+  substdio_flush(&smtpto);
+  if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
+  substdio_puts(&smtpto,"MAIL FROM:<");
+  substdio_put(&smtpto,sender.s,sender.len);
+  substdio_puts(&smtpto,">\r\n");
+  substdio_flush(&smtpto);
+  code = smtpcode();
+  if (code >= 500) quit("DConnected to "," but sender was rejected");
+  if (code >= 400) quit("ZConnected to "," but sender was rejected");
+  flagbother = 0;
+  for (i = 0;i < reciplist.len;++i) {
+    substdio_puts(&smtpto,"RCPT TO:<");
+    substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len);
+    substdio_puts(&smtpto,">\r\n");
+    substdio_flush(&smtpto);
+    code = smtpcode();
+    if (code >= 500) {
+      out("h"); outhost(); out(" does not like recipient.\n");
+      outsmtptext(); zero();
     }
-   else if (code >= 400)
-    {
-     out("s"); outhost(); out(" does not like recipient.\n");
-     outsmtptext(); zero();
+    else if (code >= 400) {
+      out("s"); outhost(); out(" does not like recipient.\n");
+      outsmtptext(); zero();
     }
-   else
-    {
-     out("r"); zero();
-     flaganyrecipok = 1;
+    else {
+      out("r"); zero();
+      flagbother = 1;
     }
   }
-
- if (!flaganyrecipok)
-  {
-   out("DGiving up.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- if (substdio_putsflush(&ssto,"DATA\r\n") == -1) writeerr();
-
- code = smtpcode(&ssfrom);
- if (code == 421)
-  {
-   out("ZConnected to "); outhost(); out(" but connection died.\n");
-   quit(&ssto,&ssfrom);
-  }
- if (code >= 500)
-  {
-   out("D"); outhost(); out(" failed on DATA command.\n");
-   quit(&ssto,&ssfrom);
-  }
- if (code >= 400)
-  {
-   out("Z"); outhost(); out(" failed on DATA command.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- blast(&ssto,subfdin);
-
- code = smtpcode(&ssfrom);
- if (code == 421)
-  {
-   out("ZConnected to "); outhost(); out(" but connection died. Possible duplicate!\n");
-   quit(&ssto,&ssfrom);
-  }
- if (code >= 500)
-  {
-   out("D"); outhost(); out(" failed after I sent the message.\n");
-   quit(&ssto,&ssfrom);
-  }
- if (code >= 400)
-  {
-   out("Z"); outhost(); out(" failed after I sent the message.\n");
-   quit(&ssto,&ssfrom);
-  }
-
- out("K"); outhost(); out(" accepted message.\n");
- quit(&ssto,&ssfrom);
+  if (!flagbother) quit("DGiving up on ","");
+  substdio_putsflush(&smtpto,"DATA\r\n");
+  code = smtpcode();
+  if (code >= 500) quit("D"," failed on DATA command");
+  if (code >= 400) quit("Z"," failed on DATA command");
+  blast();
+  code = smtpcode();
+  flagcritical = 0;
+  if (code >= 500) quit("D"," failed after I sent the message");
+  if (code >= 400) quit("Z"," failed after I sent the message");
+  quit("K"," accepted message");
 }
 
 stralloc canonhost = {0};
@@ -343,138 +282,146 @@ char *s;
 int *flagalias;
 int flagcname;
 {
- int j;
-
- *flagalias = flagcname;
-
- j = str_rchr(s,'@');
- if (!s[j])
-  {
-   if (!stralloc_copys(saout,s)) temp_nomem();
-   return;
+  int j;
+  *flagalias = flagcname;
+  j = str_rchr(s,'@');
+  if (!s[j]) {
+    if (!stralloc_copys(saout,s)) temp_nomem();
+    return;
   }
- if (!stralloc_copys(&canonbox,s)) temp_nomem();
- canonbox.len = j;
- if (!quote(saout,&canonbox)) temp_nomem();
- if (!stralloc_cats(saout,"@")) temp_nomem();
-
- if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem();
- if (flagcname)
-   switch(dns_cname(&canonhost))
-    {
-     case 0: *flagalias = 0; break;
-     case DNS_MEM: temp_nomem();
-     case DNS_SOFT: temp_dnscanon();
-     case DNS_HARD: ; /* alias loop, not our problem */
+  if (!stralloc_copys(&canonbox,s)) temp_nomem();
+  canonbox.len = j;
+  if (!quote(saout,&canonbox)) temp_nomem();
+  if (!stralloc_cats(saout,"@")) temp_nomem();
+  if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem();
+  if (flagcname)
+    switch(dns_cname(&canonhost)) {
+      case 0: *flagalias = 0; break;
+      case DNS_MEM: temp_nomem();
+      case DNS_SOFT: temp_dnscanon();
+      case DNS_HARD: ; /* alias loop, not our problem */
     }
 
- if (!stralloc_cat(saout,&canonhost)) temp_nomem();
+  if (!stralloc_cat(saout,&canonhost)) temp_nomem();
+}
+
+void getcontrols()
+{
+  if (control_init() == -1) temp_control();
+  if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
+  if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
+    temp_control();
+  if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1)
+    temp_control();
+  switch(control_readfile(&routes,"control/smtproutes",0)) {
+    case -1:
+      temp_control();
+    case 0:
+      if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break;
+    case 1:
+      if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
+  }
 }
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
- static ipalloc ip = {0};
- int i;
- 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();
-
- 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))
-       break;
- if (relayhost && !*relayhost) relayhost = 0;
-
- if (relayhost)
-  {
-   i = str_chr(relayhost,':');
-   if (relayhost[i])
-    {
-     scan_ulong(relayhost + i + 1,&port);
-     relayhost[i] = 0;
+  static ipalloc ip = {0};
+  int i;
+  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();
+  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))
+        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 (!stralloc_copys(&host,relayhost)) temp_nomem();
+    if (!stralloc_copys(&host,relayhost)) temp_nomem();
   }
 
 
- addrmangle(&sender,argv[2],&flagalias,!relayhost);
-
- if (!saa_readyplus(&reciplist,0)) temp_nomem();
- if (ipme_init() != 1) temp_oserr();
-
- flagallaliases = 1;
- recips = argv + 3;
- while (*recips)
-  {
-   if (!saa_readyplus(&reciplist,1)) temp_nomem();
-   reciplist.sa[reciplist.len] = sauninit;
-   addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost);
-   if (!flagalias) flagallaliases = 0;
-   ++reciplist.len;
-   ++recips;
+  addrmangle(&sender,argv[2],&flagalias,0);
+  if (!saa_readyplus(&reciplist,0)) temp_nomem();
+  if (ipme_init() != 1) temp_oserr();
+  flagallaliases = 1;
+  recips = argv + 3;
+  while (*recips) {
+    if (!saa_readyplus(&reciplist,1)) temp_nomem();
+    reciplist.sa[reciplist.len] = sauninit;
+    addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost);
+    if (!flagalias) flagallaliases = 0;
+    ++reciplist.len;
+    ++recips;
   }
 
-
- random = now() + (getpid() << 16);
- switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random))
-  {
-   case DNS_MEM: temp_nomem();
-   case DNS_SOFT: temp_dns();
-   case DNS_HARD: perm_dns();
-   case 1:
-     if (ip.len <= 0) temp_dns();
+  random = now() + (getpid() << 16);
+  switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) {
+    case DNS_MEM: temp_nomem();
+    case DNS_SOFT: temp_dns();
+    case DNS_HARD: perm_dns();
+    case 1:
+      if (ip.len <= 0) temp_dns();
   }
-
- if (ip.len <= 0) perm_nomx();
-
- prefme = 100000;
- for (i = 0;i < ip.len;++i)
-   if (ipme_is(&ip.ix[i].ip))
-     if (ip.ix[i].pref < prefme)
-       prefme = ip.ix[i].pref;
-
- if (relayhost) prefme = 300000;
- if (flagallaliases) prefme = 500000;
-
- for (i = 0;i < ip.len;++i)
-   if (ip.ix[i].pref < prefme)
-     break;
-
- if (i >= ip.len)
-   perm_ambigmx();
-
- for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme)
-  {
-   int s;
-
-   if (tcpto(&ip.ix[i].ip)) continue;
-
-   s = socket(AF_INET,SOCK_STREAM,0);
-   if (s == -1) temp_oserr();
-
-   if (timeoutconn(s,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0)
-    {
-     tcpto_err(&ip.ix[i].ip,0);
-     partner = ip.ix[i].ip;
-     smtp(s); /* does not return */
+  if (ip.len <= 0) perm_nomx();
+  prefme = 100000;
+  for (i = 0;i < ip.len;++i)
+    if (ipme_is(&ip.ix[i].ip))
+      if (ip.ix[i].pref < prefme)
+        prefme = ip.ix[i].pref;
+  if (relayhost) prefme = 300000;
+  if (flagallaliases) prefme = 500000;
+  for (i = 0;i < ip.len;++i)
+    if (ip.ix[i].pref < prefme)
+      break;
+  if (i >= ip.len)
+    perm_ambigmx();
+  for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) {
+    if (tcpto(&ip.ix[i].ip)) continue;
+    smtpfd = socket(AF_INET,SOCK_STREAM,0);
+    if (smtpfd == -1) temp_oserr();
+    if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
+      tcpto_err(&ip.ix[i].ip,0);
+      partner = ip.ix[i].ip;
+      smtp(); /* does not return */
     }
-   tcpto_err(&ip.ix[i].ip,errno == error_timeout);
-   close(s);
+    tcpto_err(&ip.ix[i].ip,errno == error_timeout);
+    close(smtpfd);
   }
- temp_noconn();
+  
 temp_noconn();
 }
index 3be8602..acb04d0 100644 (file)
@@ -164,7 +164,7 @@ so the percent hack may be applied repeatedly.
 handles
 .I percenthack
 before
-.IR recipientmap .
+.IR locals .
 .TP 5
 .I queuelifetime
 Number of seconds
@@ -176,42 +176,23 @@ will try the message once more,
 but it will treat any temporary delivery failures as
 permanent failures.
 .TP 5
-.I recipientmap
-List of redirections, one per line.
-Each redirection has the form
-.IR recipient\fB:\fIrewritten ,
-without any extra spaces.
-When
-.B qmail-send
-sees the address
-.IR recipient ,
-it replaces it with
-.IR rewritten .
-Both
-.I recipient
-and
-.I rewritten
-must include domain names.
-.B qmail-send
-handles
-.I recipientmap
-before
-.IR locals .
-.TP 5
 .I virtualdomains
-List of virtual domains, one per line.
-Each virtual domain has the form
-.IR domain\fB:\fIprepend ,
+List of virtual users or domains, one per line.
+A virtual user has the form
+.IR user\fB@\fIdomain\fB:\fIprepend ,
 without any extra spaces.
 When
 .B qmail-send
-sees a recipient address at
-.IR domain ,
-say
+sees the recipient address
 .IR user\fB@\fIdomain ,
 it converts it to
 .I prepend\fB-\fIuser\fB@\fIdomain
 and treats it as local.
+
+A virtual domain has the form
+.IR domain\fB:\fIprepend .
+It applies to any recipient address at
+.IR domain .
 For example, if
 
 .EX
@@ -226,6 +207,7 @@ and a message arrives for
 will rewrite the recipient address as
 .B joeBREAKfoo-info@nowhere.mil
 and deliver the message locally.
+
 .I virtualdomains
 may contain wildcards:
 
index 5f1d1cd..c31b522 100644 (file)
@@ -48,8 +48,6 @@ stralloc percenthack = {0};
 struct constmap mappercenthack;
 stralloc locals = {0};
 struct constmap maplocals;
-stralloc redir = {0};
-struct constmap mapredir;
 stralloc vdoms = {0};
 struct constmap mapvdoms;
 stralloc envnoathost = {0};
@@ -63,10 +61,7 @@ char strnum3[FMT_ULONG];
 
 #define CHANNELS 2
 char *chanaddr[CHANNELS] = { "local/", "remote/" };
-char *channodelmsg[CHANNELS] = {
-  "local deliveries will be put on hold\n"
-, "remote deliveries will be put on hold\n"
-};
+char *chanstatusmsg[CHANNELS] = { " local ", " remote " };
 char *tochan[CHANNELS] = { " to local ", " to remote " };
 int chanfdout[CHANNELS] = { 1, 3 };
 int chanfdin[CHANNELS] = { 2, 4 };
@@ -124,7 +119,7 @@ char *recip;
   int j;
   char *x;
   static stralloc addr = {0};
-  static stralloc domain = {0};
+  int at;
 
   if (!stralloc_copys(&rwline,"T")) return 0;
   if (!stralloc_copys(&addr,recip)) return 0;
@@ -143,38 +138,26 @@ char *recip;
     addr.s[i] = '@';
   }
 
-  if (x = constmap(&mapredir,addr.s,addr.len))
-    if (x[str_chr(x,'@')])
-      if (!stralloc_copys(&addr,x)) return 0;
+  at = byte_rchr(addr.s,addr.len,'@');
 
-  i = byte_rchr(addr.s,addr.len,'@');
-  if (!stralloc_copyb(&domain,addr.s + i + 1,addr.len - i - 1)) return 0;
-  addr.len = i;
-
-  if (constmap(&maplocals,domain.s,domain.len)) {
+  if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) {
     if (!stralloc_cat(&rwline,&addr)) return 0;
-    if (!stralloc_cats(&rwline,"@")) return 0;
-    if (!stralloc_cat(&rwline,&domain)) return 0;
     if (!stralloc_0(&rwline)) return 0;
     return 1;
   }
 
-  for (i = 0;i <= domain.len;++i)
-    if ((i == 0) || (i == domain.len) || (domain.s[i] == '.'))
-      if (x = constmap(&mapvdoms,domain.s + i,domain.len - i)) {
+  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_cats(&rwline,"@")) return 0;
-        if (!stralloc_cat(&rwline,&domain)) return 0;
         if (!stralloc_0(&rwline)) return 0;
         return 1;
       }
  
   if (!stralloc_cat(&rwline,&addr)) return 0;
-  if (!stralloc_cats(&rwline,"@")) return 0;
-  if (!stralloc_cat(&rwline,&domain)) return 0;
   if (!stralloc_0(&rwline)) return 0;
   return 2;
 }
@@ -767,7 +750,7 @@ I tried to deliver a bounce message to this address, but the bounce bounced!\n\
 
    qmail_from(&qqt,bouncesender);
    qmail_to(&qqt,bouncerecip);
-   if (qmail_close(&qqt))
+   if (*qmail_close(&qqt))
     { log1("warning: trouble injecting bounce message, will try later\n"); return 0; }
 
    strnum2[fmt_ulong(strnum2,id)] = 0;
@@ -798,10 +781,26 @@ struct del
 
 unsigned long masterdelid = 1;
 unsigned int concurrency[CHANNELS] = { 10, 20 };
+unsigned int concurrencyused[CHANNELS] = { 0, 0 };
 struct del *d[CHANNELS];
 stralloc dline[CHANNELS];
 char delbuf[2048];
 
+void del_status()
+{
+  int c;
+
+  log1("status:");
+  for (c = 0;c < CHANNELS;++c) {
+    strnum2[fmt_ulong(strnum2,(unsigned long) concurrencyused[c])] = 0;
+    strnum3[fmt_ulong(strnum3,(unsigned long) concurrency[c])] = 0;
+    log2(chanstatusmsg[c],strnum2);
+    log2("/",strnum3);
+  }
+  if (flagexitasap) log1(" exitasap");
+  log1("\n");
+}
+
 void del_init()
 {
  int c;
@@ -816,49 +815,22 @@ void del_init()
    dline[c].s = 0;
    while (!stralloc_copys(&dline[c],"")) nomem();
   }
+ del_status();
 }
 
 int del_canexit()
 {
- int i;
  int c;
  for (c = 0;c < CHANNELS;++c)
    if (flagspawnalive[c]) /* if dead, nothing we can do about its jobs */
-     for (i = 0;i < concurrency[c];++i)
-       if (d[c][i].used) return 0;
+     if (concurrencyused[c]) return 0;
  return 1;
 }
 
-static int del_lastsaid = 0;
-
-void del_saywhynoexit()
-{
- int i;
- int c;
- int n;
- n = 0;
- for (c = 0;c < CHANNELS;++c)
-   if (flagspawnalive[c])
-     for (i = 0;i < concurrency[c];++i)
-       if (d[c][i].used)
-        ++n;
- if (!del_lastsaid || (n < del_lastsaid))
-  {
-   strnum2[fmt_ulong(strnum2,(unsigned long) n)] = 0;
-   log3("number of deliveries left before exiting: ",strnum2,"\n");
-   del_lastsaid = n;
-  }
-}
-
 int del_avail(c)
 int c;
 {
- int i;
-
- if (!flagspawnalive[c]) return 0;
- if (!comm_canwrite(c)) return 0;
- for (i = 0;i < concurrency[c];++i) if (!d[c][i].used) return 1;
- return 0;
+  return flagspawnalive[c] && comm_canwrite(c) && (concurrencyused[c] < concurrency[c]);
 }
 
 void del_start(j,mpos,recip)
@@ -881,7 +853,7 @@ char *recip;
  d[c][i].j = j; ++jo[j].refs;
  d[c][i].delid = masterdelid++;
  d[c][i].mpos = mpos;
- d[c][i].used = 1;
+ d[c][i].used = 1; ++concurrencyused[c];
 
  comm_write(c,i,jo[j].id,jo[j].sender.s,recip);
 
@@ -891,6 +863,7 @@ char *recip;
  log3(": msg ",strnum3,tochan[c]);
  logsafe(recip);
  log1("\n");
+ del_status();
 }
 
 void markdone(c,id,pos)
@@ -975,7 +948,8 @@ int c;
           log3("delivery ",strnum3,": report mangled, will defer\n");
        }
        job_close(d[c][delnum].j);
-       d[c][delnum].used = 0;
+       d[c][delnum].used = 0; --concurrencyused[c];
+       del_status();
       }
      dline[c].len = 0;
     }
@@ -1487,12 +1461,6 @@ int getcontrols() { if (control_init() == -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(&redir,"control/recipientmap",0))
-  {
-   case -1: return 0;
-   case 0: if (!constmap_init(&mapredir,"",0,1)) return 0; break;
-   case 1: if (!constmap_init(&mapredir,redir.s,redir.len,1)) return 0; break;
-  }
  switch(control_readfile(&vdoms,"control/virtualdomains",0))
   {
    case -1: return 0;
@@ -1589,14 +1557,8 @@ void main()
    numjobs += concurrency[c];
   }
 
- log1("running\n");
-
  fnmake_init();
 
- for (c = 0;c < CHANNELS;++c)
-   if (!concurrency[c])
-     log1(channodelmsg[c]);
-
  comm_init();
 
  pqstart();
@@ -1608,8 +1570,6 @@ void main()
 
  while (!flagexitasap || !del_canexit())
   {
-   if (flagexitasap) del_saywhynoexit();
-
    recent = now();
 
    if (flagrunasap) { flagrunasap = 0; pqrun(); }
@@ -1647,6 +1607,6 @@ void main()
     }
   }
  pqfinish();
- log1("exiting\n");
+ log1("status: exiting\n");
  _exit(0);
 }
index 5134ebc..a24aa63 100644 (file)
@@ -1,3 +1,5 @@
+#include <sys/types.h>
+#include <sys/stat.h>
 #include "substdio.h"
 #include "subfd.h"
 #include "exit.h"
@@ -7,7 +9,12 @@
 #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;
@@ -93,7 +100,7 @@ char *pre;
   }
 }
 
-void do_lst(fn,def,pre,post)
+int do_lst(fn,def,pre,post)
 char *fn;
 char *def;
 char *pre;
@@ -110,7 +117,7 @@ char *post;
       substdio_puts(subfdout,"(Default.) ");
       substdio_puts(subfdout,def);
       substdio_puts(subfdout,"\n");
-      break;
+      return 0;
     case 1:
       substdio_puts(subfdout,"\n");
       i = 0;
@@ -122,10 +129,10 @@ char *post;
           substdio_puts(subfdout,"\n");
          i = j + 1;
        }
-      break;
+      return 1;
     default:
       substdio_puts(subfdout,"Oops! Trouble reading this file.\n");
-      break;
+      return -1;
   }
 }
 
@@ -133,10 +140,52 @@ void main()
 {
   DIR *dir;
   direntry *d;
+  struct stat stmrh;
+  struct stat stmrhcdb;
 
-  substdio_puts(subfdout,"The qmail control files are stored in ");
+  substdio_puts(subfdout,"qmail home directory: ");
   substdio_puts(subfdout,auto_qmail);
-  substdio_puts(subfdout,"/control.\n");
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"user-ext delimiter: ");
+  substdio_puts(subfdout,auto_break);
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"paternalism (in decimal): ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_patrn));
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"silent concurrency limit: ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_spawn));
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"subdirectory split: ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_split));
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"user ids: ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uida));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidd));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidl));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uido));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidp));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidq));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uidr));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_uids));
+  substdio_puts(subfdout,".\n");
+
+  substdio_puts(subfdout,"group ids: ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidn));
+  substdio_puts(subfdout,", ");
+  substdio_put(subfdout,num,fmt_ulong(num,(unsigned long) auto_gidq));
+  substdio_puts(subfdout,".\n");
 
   if (chdir(auto_qmail) == -1) {
     substdio_puts(subfdout,"Oops! Unable to chdir to ");
@@ -170,6 +219,7 @@ void main()
   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: ");
@@ -182,9 +232,29 @@ void main()
   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("queuelifetime","604800","Message lifetime in the queue is "," seconds");
-  do_lst("rcpthosts","SMTP clients may send messages to any recipient.","SMTP clients may send messages to recipients at ",".");
-  do_lst("recipientmap","No redirections.","Redirection: ","");
+
+  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("timeoutconnect","60","SMTP client connection timeout is "," seconds");
@@ -202,6 +272,7 @@ void main()
     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;
@@ -212,11 +283,13 @@ void main()
     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,"recipientmap")) 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;
index f1cb4a2..c4640b8 100644 (file)
@@ -28,6 +28,9 @@ supports ESMTP, including the 8BITMIME and PIPELINING options.
 .B qmail-smtpd
 converts the SMTP newline convention into the UNIX newline convention
 by converting CR LF into LF.
+It returns a temporary error and drops the connection on bare LFs;
+see
+.BR http://pobox.com/~djb/docs/smtplf.html .
 
 .B qmail-smtpd
 accepts messages that contain long lines or non-ASCII characters,
@@ -47,6 +50,33 @@ may be of the form
 meaning every address at
 .IR host .
 .TP 5
+.I databytes
+Maximum number of bytes allowed in a message,
+or 0 for no limit.
+Default: 0.
+If a message exceeds this limit,
+.B qmail-smtpd
+returns a permanent error code to the client;
+in contrast, if
+the disk is full or
+.B qmail-smtpd
+hits a resource limit,
+.B qmail-smtpd
+returns a temporary error code.
+
+.I databytes
+counts bytes as stored on disk, not as transmitted through the network.
+It does not count the
+.B qmail-smtpd
+Received line, the
+.B qmail-queue
+Received line, or the envelope.
+
+If the environment variable
+.B DATABYTES
+is set, it overrides
+.IR databytes .
+.TP 5
 .I localiphost
 Replacement host name for local IP addresses.
 Default:
@@ -67,6 +97,29 @@ with
 This is done before
 .IR rcpthosts .
 .TP 5
+.I morercpthosts
+Extra allowed RCPT domains.
+If
+.I rcpthosts
+and
+.I morercpthosts
+both exist,
+.I morercpthosts
+is effectively appended to
+.IR rcpthosts .
+
+You must run
+.B qmail-newmrh
+whenever
+.I morercpthosts
+changes.
+
+Rule of thumb for large sites:
+Put your 50 most commonly used domains into
+.IR rcpthosts ,
+and the rest into
+.IR morercpthosts .
+.TP 5
 .I rcpthosts
 Allowed RCPT domains.
 If
@@ -121,5 +174,6 @@ tcp-env(1),
 tcp-environ(5),
 qmail-control(5),
 qmail-inject(8),
+qmail-newmrh(8),
 qmail-queue(8),
 qmail-remote(8)
index 50cfc0a..1e28c88 100644 (file)
@@ -1,6 +1,5 @@
 #include "sig.h"
 #include "readwrite.h"
-#include "getln.h"
 #include "stralloc.h"
 #include "substdio.h"
 #include "alloc.h"
 #include "qmail.h"
 #include "str.h"
 #include "fmt.h"
+#include "scan.h"
 #include "byte.h"
 #include "case.h"
 #include "env.h"
 #include "now.h"
 #include "exit.h"
+#include "rcpthosts.h"
+#include "timeoutread.h"
+#include "timeoutwrite.h"
+#include "commands.h"
 
 #define MAXHOPS 100
+unsigned int databytes = 0;
 int timeout = 1200;
 
-char ssoutbuf[512];
-substdio ssout = SUBSTDIO_FDBUF(write,1,ssoutbuf,sizeof(ssoutbuf));
-
-void die() { substdio_flush(&ssout); _exit(1); }
-void flush() { if (substdio_flush(&ssout) == -1) _exit(1); }
-void out(s) char *s; { if (substdio_puts(&ssout,s) == -1) die(); }
-
-int timeoutread(fd,buf,n) int fd; char *buf; int n;
+int safewrite(fd,buf,len) int fd; char *buf; int len;
 {
- int r; int saveerrno;
- flush();
- alarm(timeout);
- r = read(fd,buf,n); saveerrno = errno;
- alarm(0);
- errno = saveerrno; return r;
+  int r;
+  r = timeoutwrite(timeout,fd,buf,len);
+  if (r <= 0) _exit(1);
+  return r;
 }
 
-char ssinbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(timeoutread,0,ssinbuf,sizeof(ssinbuf));
+char ssoutbuf[512];
+substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);
 
+void flush() { substdio_flush(&ssout); }
+void out(s) char *s; { substdio_puts(&ssout,s); }
 
-void outofmem() { out("421 out of memory (#4.3.0)\r\n"); die(); }
-void sigalrm() { out("451 timeout (#4.4.2)\r\n"); die(); }
+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); }
 
-struct qmail qqt;
-stralloc greeting = {0};
-int liphostok = 0;
-stralloc liphost = {0};
-int rhok = 0;
-stralloc rcpthosts = {0};
-struct constmap maprcpthosts;
-int bmfok = 0;
-stralloc bmf = {0};
-struct constmap mapbmf;
-int flagbarf; /* defined if seenmail */
+void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
+void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
+void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
+void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
+void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
+void err_noop() { out("250 ok\r\n"); }
+void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
+void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
 
-stralloc helohost = {0};
-stralloc mailfrom = {0};
-stralloc rcptto = {0};
-int seenmail = 0;
 
-stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+stralloc greeting = {0};
+
+void smtp_greet(code) char *code;
+{
+  substdio_puts(&ssout,code);
+  substdio_put(&ssout,greeting.s,greeting.len);
+}
+void smtp_help()
+{
+  out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n");
+}
+void smtp_quit()
+{
+  smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
+}
 
 char *remoteip;
 char *remotehost;
@@ -72,378 +82,340 @@ char *remoteinfo;
 char *local;
 char *relayclient;
 
-void dohelo(arg) char *arg;
-{
- if (!stralloc_copys(&helohost,arg)) outofmem(); 
- if (!stralloc_0(&helohost)) outofmem(); 
-}
+stralloc helohost = {0};
+char *fakehelo; /* pointer into helohost, or 0 */
 
-void getenvs()
-{
- remoteip = env_get("TCPREMOTEIP");
- if (!remoteip) remoteip = "unknown";
- local = env_get("TCPLOCALHOST");
- if (!local) local = env_get("TCPLOCALIP");
- if (!local) local = "unknown";
- remotehost = env_get("TCPREMOTEHOST");
- if (!remotehost) remotehost = "unknown";
- remoteinfo = env_get("TCPREMOTEINFO");
- relayclient = env_get("RELAYCLIENT");
- dohelo(remotehost);
+void dohelo(arg) char *arg; {
+  if (!stralloc_copys(&helohost,arg)) die_nomem(); 
+  if (!stralloc_0(&helohost)) die_nomem(); 
+  fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
 }
 
-void straynewline()
-{
- out("451 \
-Put ,E=\\r\\n at the end of Mether, Mtcp, or Msmtp in sendmail.cf \
-if you are using Solaris 2.5 (fixed in 2.5.1). \
-I cannot accept messages with stray newlines. \
-Many SMTP servers will time out waiting for \\r\\n.\\r\\n.\
-\r\n");
- die();
-}
+int liphostok = 0;
+stralloc liphost = {0};
+int bmfok = 0;
+stralloc bmf = {0};
+struct constmap mapbmf;
 
-void blast(ssfrom,hops)
-substdio *ssfrom;
-int *hops;
+void setup()
 {
- char ch;
- int state;
- int flaginheader;
- int pos; /* number of bytes since most recent \n, if fih */
- int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
- int flagmaybey; /* 1 if this line might match \r\n, if fih */
- int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
-
- state = 1;
- *hops = 0;
- flaginheader = 1;
- pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
- for (;;)
-  {
-   if (substdio_get(ssfrom,&ch,1) <= 0) die();
-   if (flaginheader)
-    {
-     if (pos < 9)
-      {
-       if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;
-       if (flagmaybez) if (pos == 8) ++*hops;
-       if (pos < 8)
-         if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;
-       if (flagmaybex) if (pos == 7) ++*hops;
-       if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
-       if (flagmaybey) if (pos == 1) flaginheader = 0;
-      }
-     ++pos;
-     if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
-    }
-   switch(state)
-    {
-     case 0:
-       if (ch == '\n') straynewline();
-       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;
-       break;
-     case 2: /* \r\n + . */
-       if (ch == '\n') straynewline();
-       if (ch == '\r') { state = 3; continue; }
-       state = 0;
-       break;
-     case 3: /* \r\n + .\r */
-       if (ch == '\n') return;
-       qmail_put(&qqt,".\r",2);
-       if (ch == '\r') { state = 4; continue; }
-       state = 0;
-       break;
-     case 4: /* + \r */
-       if (ch == '\n') { state = 1; break; }
-       if (ch != '\r') { qmail_put(&qqt,"\r",1); state = 0; }
-    }
-   qmail_put(&qqt,&ch,1);
-  }
+  char *x;
+  unsigned long u;
+  if (control_init() == -1) die_control();
+  if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)
+    die_control();
+  liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);
+  if (liphostok == -1) die_control();
+  if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
+  if (timeout <= 0) timeout = 1;
+
+  if (rcpthosts_init() == -1) die_control();
+
+  bmfok = control_readfile(&bmf,"control/badmailfrom",0);
+  if (bmfok == -1) die_control();
+  if (bmfok)
+    if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+  if (control_readint(&databytes,"control/databytes") == -1) die_control();
+  x = env_get("DATABYTES");
+  if (x) { scan_ulong(x,&u); databytes = u; }
+  if (!(databytes + 1)) --databytes;
+  remoteip = env_get("TCPREMOTEIP");
+  if (!remoteip) remoteip = "unknown";
+  local = env_get("TCPLOCALHOST");
+  if (!local) local = env_get("TCPLOCALIP");
+  if (!local) local = "unknown";
+  remotehost = env_get("TCPREMOTEHOST");
+  if (!remotehost) remotehost = "unknown";
+  remoteinfo = env_get("TCPREMOTEINFO");
+  relayclient = env_get("RELAYCLIENT");
+  dohelo(remotehost);
 }
 
+
+stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+
 int addrparse(arg)
 char *arg;
 {
- int i;
- char ch;
- struct ip_address ip;
- int flagesc;
- int flagquoted;
-
- arg += str_chr(arg,'<');
- if (*arg != '<') return 0;
- ++arg;
-
- /* strip source route */
- if (*arg == '@') while (*arg) if (*arg++ == ':') break;
-
- if (!*arg) return 0;
- if (!stralloc_copys(&addr,"")) outofmem();
- flagesc = 0;
- flagquoted = 0;
- for (i = 0;ch = arg[i];++i) /* copy arg to addr, stripping quotes */
-  {
-   if (flagesc)
-    { if (!stralloc_append(&addr,&ch)) outofmem(); flagesc = 0; }
-   else
-    {
-     if (!flagquoted && (ch == '>')) break;
-     switch(ch)
-      {
-       case '\\': flagesc = 1; break;
-       case '"': flagquoted = !flagquoted; break;
-       default: if (!stralloc_append(&addr,&ch)) outofmem();
+  int i;
+  char ch;
+  char terminator;
+  struct ip_address ip;
+  int flagesc;
+  int flagquoted;
+  terminator = '>';
+  i = str_chr(arg,'<');
+  if (arg[i])
+    arg += i + 1;
+  else { /* partner should go read rfc 821 */
+    terminator = ' ';
+    arg += str_chr(arg,':');
+    if (*arg == ':') ++arg;
+    while (*arg == ' ') ++arg;
+  }
+
+  /* strip source route */
+  if (*arg == '@') while (*arg) if (*arg++ == ':') break;
+
+  if (!stralloc_copys(&addr,"")) die_nomem();
+  flagesc = 0;
+  flagquoted = 0;
+  for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */
+    if (flagesc) {
+      if (!stralloc_append(&addr,&ch)) die_nomem();
+      flagesc = 0;
+    }
+    else {
+      if (!flagquoted && (ch == terminator)) break;
+      switch(ch) {
+        case '\\': flagesc = 1; break;
+        case '"': flagquoted = !flagquoted; break;
+        default: if (!stralloc_append(&addr,&ch)) die_nomem();
       }
     }
   }
- if (!ch) return 0;
- if (!stralloc_append(&addr,"")) outofmem();
- ++i;
- while (arg[i])
-  {
-   if (!case_diffs(arg + i," BODY=8BITMIME")) i += 14;
-   else if (!case_diffs(arg + i," BODY=7BIT")) i += 10;
-   else return 0;
-  }
-
- if (liphostok)
-  {
-   i = byte_rchr(addr.s,addr.len,'@');
-   if (i < addr.len) /* if not, partner should go read rfc 821 */
-     if (addr.s[i + 1] == '[')
-       if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])
-         if (ipme_is(&ip))
-          {
-           addr.len = i + 1;
-           if (!stralloc_cat(&addr,&liphost)) outofmem();
-           if (!stralloc_0(&addr)) outofmem();
+  /* could check for termination failure here, but why bother? */
+  if (!stralloc_append(&addr,"")) die_nomem();
+
+  if (liphostok) {
+    i = byte_rchr(addr.s,addr.len,'@');
+    if (i < addr.len) /* if not, partner should go read rfc 821 */
+      if (addr.s[i + 1] == '[')
+        if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])
+          if (ipme_is(&ip)) {
+            addr.len = i + 1;
+            if (!stralloc_cat(&addr,&liphost)) die_nomem();
+            if (!stralloc_0(&addr)) die_nomem();
           }
   }
 
- return 1;
+  if (addr.len > 900) return 0;
+  return 1;
 }
 
-int addrallowed()
+int bmfcheck()
 {
- int j;
- if (!rhok) return 1;
- j = byte_rchr(addr.s,addr.len,'@');
- if (j >= addr.len) return 1; /* can be taken care of by envnoathost */
- if (constmap(&maprcpthosts,addr.s + j + 1,addr.len - j - 2)) return 1;
- for (;j < addr.len;++j)
-   if (addr.s[j] == '.')
-     if (constmap(&maprcpthosts,addr.s + j,addr.len - j - 1)) return 1;
- return 0;
+  int j;
+  if (!bmfok) return 0;
+  if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
+  j = byte_rchr(addr.s,addr.len,'@');
+  if (j < addr.len)
+    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+  return 0;
 }
 
-void bmfcheck()
+int addrallowed()
 {
- int j;
- flagbarf = 0;
- if (!bmfok) return;
- if (constmap(&mapbmf,addr.s,addr.len - 1)) { flagbarf = 1; return; }
- j = byte_rchr(addr.s,addr.len,'@');
- if (j < addr.len)
-   if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) flagbarf = 1;
+  int r;
+  r = rcpthosts(addr.s,str_len(addr.s));
+  if (r == -1) die_control();
+  return r;
 }
 
-void smtp_greet(code) char *code; {
- if (substdio_puts(&ssout,code) == -1) die();
- if (substdio_put(&ssout,greeting.s,greeting.len) == -1) die(); }
-void smtp_quit() { smtp_greet("221 "); out("\r\n"); die(); }
-void smtp_help() { out("214-qmail home page: http://pobox.com/~djb/qmail.html\r\n214 send comments to qmail@pobox.com\r\n"); }
-void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
-void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
-void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
-void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
-void err_seenmail() { out("503 one MAIL per message (#5.5.1)\r\n"); }
-void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }
-void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }
-void err_noop() { out("250 ok\r\n"); }
-void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }
-void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }
-void smtp_helo(arg) char *arg; {
- smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
- seenmail = 0;
- dohelo(arg ? arg : ""); }
-void smtp_rset() {
- seenmail = 0;
- out("250 flushed\r\n"); }
-void smtp_mail(arg) char *arg; {
if (seenmail) { err_seenmail(); return; }
- if (!arg) { err_syntax(); return; }
- if (!addrparse(arg)) { err_syntax(); return; }
bmfcheck();
seenmail = 1; out("250 ok\r\n");
if (!stralloc_copys(&rcptto,"")) outofmem();
if (!stralloc_copys(&mailfrom,addr.s)) outofmem();
- if (!stralloc_0(&mailfrom)) outofmem(); }
+
+int seenmail = 0;
+int flagbarf; /* defined if seenmail */
+stralloc mailfrom = {0};
+stralloc rcptto = {0};
+
+void smtp_helo(arg) char *arg;
+{
+  smtp_greet("250 "); out("\r\n");
+  seenmail = 0; dohelo(arg);
+}
+void smtp_ehlo(arg) char *arg;
+{
+  smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
+  seenmail = 0; dohelo(arg);
+}
+void smtp_rset()
+{
+  seenmail = 0;
+  out("250 flushed\r\n");
+}
+void smtp_mail(arg) char *arg;
+{
 if (!addrparse(arg)) { err_syntax(); return; }
+  flagbarf = bmfcheck();
+  seenmail = 1;
 if (!stralloc_copys(&rcptto,"")) die_nomem();
 if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
 if (!stralloc_0(&mailfrom)) die_nomem();
 out("250 ok\r\n");
+}
 void smtp_rcpt(arg) char *arg; {
- if (!seenmail) { err_wantmail(); return; }
- if (!arg) { err_syntax(); return; }
- if (!addrparse(arg)) { err_syntax(); return; }
- if (flagbarf) { err_bmf(); return; }
- if (relayclient)
-  {
-   --addr.len;
-   if (!stralloc_cats(&addr,relayclient)) outofmem();
-   if (!stralloc_0(&addr)) outofmem();
+  if (!seenmail) { err_wantmail(); return; }
+  if (!addrparse(arg)) { err_syntax(); return; }
+  if (flagbarf) { err_bmf(); return; }
+  if (relayclient) {
+    --addr.len;
+    if (!stralloc_cats(&addr,relayclient)) die_nomem();
+    if (!stralloc_0(&addr)) die_nomem();
   }
- else
-   if (!addrallowed()) { err_nogateway(); return; }
- out("250 ok\r\n");
- if (!stralloc_cats(&rcptto,"T")) outofmem();
- if (!stralloc_cats(&rcptto,addr.s)) outofmem();
- if (!stralloc_0(&rcptto)) outofmem(); }
+  else
+    if (!addrallowed()) { err_nogateway(); return; }
+  if (!stralloc_cats(&rcptto,"T")) die_nomem();
+  if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
+  if (!stralloc_0(&rcptto)) die_nomem();
+  out("250 ok\r\n");
+}
 
-char accept_buf[FMT_ULONG];
-void acceptmessage(qp) unsigned long qp;
+
+int saferead(fd,buf,len) int fd; char *buf; int len;
 {
- datetime_sec when;
- when = now();
- out("250 ok ");
- accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
- out(accept_buf);
- out(" qp ");
- accept_buf[fmt_ulong(accept_buf,qp)] = 0;
- out(accept_buf);
- out("\r\n");
+  int r;
+  flush();
+  r = timeoutread(timeout,fd,buf,len);
+  if (r == -1) if (errno == error_timeout) die_alarm();
+  if (r <= 0) die_read();
+  return r;
 }
 
-void smtp_data() {
- int hops; int r; unsigned long qp;
- if (!seenmail) { err_wantmail(); return; }
- if (!rcptto.len) { err_wantrcpt(); return; }
- seenmail = 0;
- if (qmail_open(&qqt) == -1) { err_qqt(); return; }
- qp = qmail_qp(&qqt);
- out("354 go ahead\r\n");
-
- received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,case_diffs(remotehost,helohost.s) ? helohost.s : 0);
- blast(&ssin,&hops);
- hops = (hops >= MAXHOPS);
- if (hops) qmail_fail(&qqt);
- qmail_from(&qqt,mailfrom.s);
- qmail_put(&qqt,rcptto.s,rcptto.len);
-
- r = qmail_close(&qqt);
- if (!r) { acceptmessage(qp); return; }
- if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; }
- switch(r)
-  {
-   case QMAIL_TOOLONG: out("554 address too long (#5.1.3)\r\n"); return;
-   case QMAIL_SYS: out("451 qq system error (#4.3.0)\r\n"); return;
-   case QMAIL_READ: out("451 qq read error (#4.3.0)\r\n"); return;
-   case QMAIL_WRITE: out("451 qq write error or disk full (#4.3.0)\r\n"); return;
-   case QMAIL_NOMEM: out("451 qq out of memory (#4.3.0)\r\n"); return;
-   case QMAIL_EXECSOFT: out("451 could not exec qq (#4.3.0)\r\n"); return;
-   case QMAIL_TIMEOUT: out("451 qq timeout (#4.3.0)\r\n"); return;
-   case QMAIL_WAITPID: out("451 qq waitpid surprise (#4.3.0)\r\n"); return;
-   case QMAIL_CRASHED: out("451 qq crashed (#4.3.0)\r\n"); return;
-   case QMAIL_USAGE: out("451 qq usage surprise (#4.3.0)\r\n"); return;
-   default: out("451 qq internal bug (#4.3.0)\r\n"); return;
-  }
+char ssinbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof ssinbuf);
+
+struct qmail qqt;
+unsigned int bytestooverflow = 0;
+
+void put(ch)
+char *ch;
+{
+  if (bytestooverflow)
+    if (!--bytestooverflow)
+      qmail_fail(&qqt);
+  qmail_put(&qqt,ch,1);
 }
 
-static struct { void (*fun)(); char *text; int flagflush; } smtpcmd[] = {
-  { smtp_rcpt, "rcpt", 0 }
-, { smtp_mail, "mail", 0 }
-, { smtp_data, "data", 1 }
-, { smtp_quit, "quit", 1 }
-, { smtp_helo, "helo", 1 }
-, { smtp_helo, "ehlo", 1 }
-, { smtp_rset, "rset", 0 }
-, { smtp_help, "help", 1 }
-, { err_noop, "noop", 1 }
-, { err_vrfy, "vrfy", 1 }
-, { 0, 0, 0 }
-};
-
-void doit(cmd)
-char *cmd;
+void blast(hops)
+int *hops;
 {
- int i;
- int j;
- char ch;
-
- for (i = 0;smtpcmd[i].fun;++i)
-  {
-   for (j = 0;ch = smtpcmd[i].text[j];++j)
-     if ((cmd[j] != ch) && (cmd[j] != ch - 32))
-       break;
-   if (!ch)
-     if (!cmd[j] || (cmd[j] == ' '))
-      {
-       while (cmd[j] == ' ') ++j;
-       if (!cmd[j])
-         smtpcmd[i].fun((char *) 0);
-       else
-         smtpcmd[i].fun(cmd + j);
-       if (smtpcmd[i].flagflush) flush();
-       return;
+  char ch;
+  int state;
+  int flaginheader;
+  int pos; /* number of bytes since most recent \n, if fih */
+  int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
+  int flagmaybey; /* 1 if this line might match \r\n, if fih */
+  int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
+  state = 1;
+  *hops = 0;
+  flaginheader = 1;
+  pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
+  for (;;) {
+    substdio_get(&ssin,&ch,1);
+    if (flaginheader) {
+      if (pos < 9) {
+        if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;
+        if (flagmaybez) if (pos == 8) ++*hops;
+        if (pos < 8)
+          if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;
+        if (flagmaybex) if (pos == 7) ++*hops;
+        if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
+        if (flagmaybey) if (pos == 1) flaginheader = 0;
       }
+      ++pos;
+      if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
+    }
+    switch(state) {
+      case 0:
+        if (ch == '\n') straynewline();
+        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;
+        break;
+      case 2: /* \r\n + . */
+        if (ch == '\n') straynewline();
+        if (ch == '\r') { state = 3; continue; }
+        state = 0;
+        break;
+      case 3: /* \r\n + .\r */
+        if (ch == '\n') return;
+        put(".");
+        put("\r");
+        if (ch == '\r') { state = 4; continue; }
+        state = 0;
+        break;
+      case 4: /* + \r */
+        if (ch == '\n') { state = 1; break; }
+        if (ch != '\r') { put("\r"); state = 0; }
+    }
+    put(&ch);
   }
- err_unimpl();
- flush();
 }
 
-void getcontrols()
+char accept_buf[FMT_ULONG];
+void acceptmessage(qp) unsigned long qp;
 {
- if (control_init() == -1) die();
- if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1) die();
- switch(control_rldef(&liphost,"control/localiphost",1,(char *) 0))
-  { case -1: die(); case 1: liphostok = 1; }
- if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die();
- if (timeout <= 0) timeout = 1;
- switch(control_readfile(&rcpthosts,"control/rcpthosts",0))
-  {
-   case -1: die();
-   case 1:
-     rhok = 1;
-     if (!constmap_init(&maprcpthosts,rcpthosts.s,rcpthosts.len,0)) die();
-  }
- switch(control_readfile(&bmf,"control/badmailfrom",0))
-  {
-   case -1: die();
-   case 1:
-     bmfok = 1;
-     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die();
-  }
+  datetime_sec when;
+  when = now();
+  out("250 ok ");
+  accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
+  out(accept_buf);
+  out(" qp ");
+  accept_buf[fmt_ulong(accept_buf,qp)] = 0;
+  out(accept_buf);
+  out("\r\n");
+}
+
+void smtp_data() {
+  int hops;
+  unsigned long qp;
+  char *qqx;
+  if (!seenmail) { err_wantmail(); return; }
+  if (!rcptto.len) { err_wantrcpt(); return; }
+  seenmail = 0;
+  if (databytes) bytestooverflow = databytes + 1;
+  if (qmail_open(&qqt) == -1) { err_qqt(); return; }
+  qp = qmail_qp(&qqt);
+  out("354 go ahead\r\n");
+  received(&qqt,"SMTP",local,remoteip,remotehost,remoteinfo,fakehelo);
+  blast(&hops);
+  hops = (hops >= MAXHOPS);
+  if (hops) qmail_fail(&qqt);
+  qmail_from(&qqt,mailfrom.s);
+  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 ");
+  out(qqx + 1);
+  out("\r\n");
 }
 
+struct commands smtpcommands[] = {
+  { "rcpt", smtp_rcpt, 0 }
+, { "mail", smtp_mail, 0 }
+, { "data", smtp_data, flush }
+, { "quit", smtp_quit, flush }
+, { "helo", smtp_helo, flush }
+, { "ehlo", smtp_ehlo, flush }
+, { "rset", smtp_rset, 0 }
+, { "help", smtp_help, flush }
+, { "noop", err_noop, flush }
+, { "vrfy", err_vrfy, flush }
+, { 0, err_unimpl, flush }
+} ;
+
 void main()
 {
- static stralloc cmd = {0};
- int match;
-
- sig_alarmcatch(sigalrm);
- sig_pipeignore();
-
- if (chdir(auto_qmail) == -1) die();
- getcontrols();
- getenvs();
-
- if (ipme_init() != 1) die();
-
- smtp_greet("220 ");
- out(" ESMTP\r\n");
-
- for (;;)
-  {
-   /* XXX: recipient can contain quoted lf. aargh. */
-   if (getln(&ssin,&cmd,&match,'\n') == -1) die();
-   if (!match) die();
-   if (cmd.len == 0) die();
-   if (cmd.s[--cmd.len] != '\n') die();
-   if ((cmd.len > 0) && (cmd.s[cmd.len - 1] == '\r')) --cmd.len;
-   cmd.s[cmd.len++] = 0;
-   doit(cmd.s);
-  }
+  sig_pipeignore();
+  if (chdir(auto_qmail) == -1) die_control();
+  setup();
+  if (ipme_init() != 1) die_ipme();
+  smtp_greet("220 ");
+  out(" ESMTP\r\n");
+  if (commands(&ssin,&smtpcommands) == 0) die_read();
+  die_nomem();
 }
index 95db54f..29876ec 100644 (file)
@@ -4,7 +4,7 @@ qmail-start \- turn on mail delivery
 .SH SYNOPSIS
 .B qmail-start
 [
-.I aliasempty
+.I defaultdelivery
 [
 .I logger arg ...
 ]
@@ -16,7 +16,8 @@ invokes
 .BR qmail-lspawn ,
 .BR qmail-rspawn ,
 and
-.BR qmail-clean .
+.BR qmail-clean ,
+under the proper uids and gids.
 These four daemons cooperate to deliver messages from the queue.
 
 .B qmail-start
@@ -33,7 +34,7 @@ Other than this,
 does not print anything, even on failure.
 
 If
-.I aliasempty
+.I defaultdelivery
 is supplied,
 .B qmail-start
 passes it to
@@ -67,8 +68,10 @@ manually:
    (all on one line)
 .EE
 
+Resource limits, controlling ttys, et al. are also passed from
 .B qmail-start
-sets the uid and gid of each daemon properly.
+to
+.BR qmail-local .
 
 Note that
 .B qmail-send
diff --git a/qmail-tcpok.8 b/qmail-tcpok.8
new file mode 100644 (file)
index 0000000..ed2efcf
--- /dev/null
@@ -0,0 +1,24 @@
+.TH qmail-tcpok 8
+.SH NAME
+qmail-tcpok \- clear TCP timeout table
+.SH SYNOPSIS
+.B qmail-tcpok
+.SH DESCRIPTION
+.B qmail-tcpok
+erases
+.BR qmail-remote 's
+current list of timeouts,
+so that
+.B qmail-remote
+does not make any assumptions about failing addresses. 
+
+.B qmail-tcpok
+must be run either as 
+.B root
+or with user id
+.B qmailr
+and group id
+.BR qmail .
+.SH "SEE ALSO"
+qmail-remote(8),
+qmail-tcpto(8)
diff --git a/qmail-tcpok.c b/qmail-tcpok.c
new file mode 100644 (file)
index 0000000..a9b9652
--- /dev/null
@@ -0,0 +1,35 @@
+#include "strerr.h"
+#include "substdio.h"
+#include "lock.h"
+#include "open.h"
+#include "readwrite.h"
+#include "auto_qmail.h"
+#include "exit.h"
+
+#define FATAL "qmail-tcpok: fatal: "
+
+char buf[1024]; /* XXX: must match size in tcpto_clean.c, tcpto.c */
+substdio ss;
+
+void main()
+{
+  int fd;
+  int i;
+
+  if (chdir(auto_qmail) == -1)
+    strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
+  if (chdir("queue/lock") == -1)
+    strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,"/queue/lock: ");
+
+  fd = open_write("tcpto");
+  if (fd == -1)
+    strerr_die4sys(111,FATAL,"unable to write ",auto_qmail,"/queue/lock/tcpto: ");
+  if (lock_ex(fd) == -1)
+    strerr_die4sys(111,FATAL,"unable to lock ",auto_qmail,"/queue/lock/tcpto: ");
+
+  substdio_fdbuf(&ss,write,fd,buf,sizeof buf);
+  for (i = 0;i < sizeof buf;++i) substdio_put(&ss,"",1);
+  if (substdio_flush(&ss) == -1)
+    strerr_die4sys(111,FATAL,"unable to clear ",auto_qmail,"/queue/lock/tcpto: ");
+  _exit(0);
+}
index f305181..cb4ddd6 100644 (file)
@@ -26,4 +26,5 @@ and group id
 .BR qmail .
 .SH "SEE ALSO"
 qmail-qread(8),
-qmail-remote(8)
+qmail-remote(8),
+qmail-tcpok(8)
diff --git a/qmail-upgrade.9 b/qmail-upgrade.9
deleted file mode 100644 (file)
index 82ae6de..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-.TH qmail-upgrade 7
-.SH "NAME"
-qmail-upgrade \- user-visible differences between qmail and sendmail
-.SH "INTRODUCTION"
-You will notice some differences
-when the system switches from
-.B sendmail
-to
-.BR qmail .
-.TP 5
-1.
-.B qmail-local
-sends incoming mail to
-.B ~\fIyou\fB/Mailbox
-by default,
-not
-.BR /usr/spool/mail/\fIyou\fB .
-Your system administrator has changed your
-.B MAIL
-environment variable so that your mail reader looks for
-.BR ~\fIyou\fB/Mailbox .
-.B \fR(\fB/usr/spool/mail
-is a massive security problem.)
-.TP 5
-2.
-.B qmail-local
-pays no attention to
-.BR .forward .
-It has a much better mechanism,
-.BR .qmail ,
-so that you can handle not only forwarding
-but even your own mailing lists.
-See below for more details.
-.TP 5
-3.
-.B qmail-local
-pays no attention to
-.BR /etc/aliases .
-Your system administrator
-can use the
-.B .qmail
-mechanism instead.
-See below.
-.TP 5
-4.
-.B qmail
-does not support the
-.B \e\fIyou\fB
-mechanism
-for ignoring aliases.
-The
-.B .qmail
-mechanism is much more flexible;
-see below.
-.TP 5
-5.
-.B qmail-inject
-has a completely different philosophy from
-.B sendmail
-on interpreting non-fully-qualified host names.
-It uses fixed rules, not DNS.
-Some examples at UIC:
-
-.EX
-     russet -> russet.math.uic.edu
-.br
-     newton -> newton.math.uic.edu
-.br
-     ut.ee  -> ut.ee  (a host in Estonia)
-.br
-     ut.ee+ -> ut.ee.uic.edu
-.br
-     uicvm+ -> uicvm.uic.edu
-.EE
-
-Here the
-.I default domain name
-(for hosts without dots)
-is
-.B math.uic.edu\fP,
-and the
-.I plus domain name
-is
-.B uic.edu\fP.
-.TP 5
-6.
-Unlike
-.BR sendmail ,
-.B qmail-inject
-doesn't replace host names with canonical names.
-Example:
-.B qmail-inject
-won't change
-.B postmaster@ftp.cs.berkeley.edu
-in your header to
-.BR postmaster@kohler.cs.berkeley.edu .
-.TP 5
-7.
-.B qmail-local
-adds a new field,
-.BR Delivered-To ,
-before every delivery.
-It uses the contents of
-.B Delivered-To
-to prevent mail forwarding loops.
-.TP 5
-8.
-If you send a message with only
-.B Bcc
-recipients,
-.B qmail-inject
-will add
-.B Cc: recipient list not shown:;\fR,
-rather than
-.BR sendmail 's
-privacy-invading
-.B Apparently-To
-header field.
-.SH "QMAIL MAILING LISTS"
-.B sendmail
-deals with aliases, forwarding, and mailing lists
-at the very heart of the mail system.
-
-.B qmail
-takes a radically different approach.
-It gives you the power to set up your own mailing lists without
-pestering your system administrator.
-
-Under
-.BR qmail ,
-you are in charge of all addresses of the form
-.B \fIyou\fBBREAK\fIanything\fR.
-The delivery of
-.B \fIyou\fBBREAK\fIanything
-is controlled by
-.B ~\fIyou\fB/.qmail-\fIanything\fR,
-a file in your home directory.
-
-For example, if you want to set up a
-bug-of-the-month-club mailing list,
-you can put a list of addresses into
-.BR ~\fIyou\fB/.qmail-botmc .
-Any mail to
-.B \fIyou\fBBREAKbotmc
-will be forwarded to all of those addresses.
-Mail directly to
-.B \fIyou\fB
-is controlled by
-.BR ~\fIyou\fB/.qmail .
-You can even set up a catch-all,
-.BR ~\fIyou\fB/.qmail-default ,
-to handle unknown
-.B \fIyou\fBBREAK
-addresses.
-
-Your
-.B .qmail
-files, like your old
-.BR .forward ,
-may list files,
-forwarding addresses,
-or other programs to run.
-(But beware that the syntax is a bit different;
-see
-.B dot-qmail(5)
-for more details.)
-.B qmail-local
-automatically
-detects forwarding loops the instant they occur,
-even if they happen indirectly through other hosts.
-
-As a helpful special case, if a
-.B .qmail
-file is empty, it refers to
-.BR ~\fIyou\fB/Mailbox .
-For example, if you touch
-.BR ~\fIyou\fB/.qmail-direct ,
-mail for
-.B \fIyou\fBBREAKdirect
-will act like
-.B \e\fIyou\fB
-did under
-.BR sendmail .
-
-Addresses that don't contain a username are handled by the
-.B alias
-user.
-For example, your system administrator has set up
-.B ~alias/.qmail-postmaster
-to handle mail for
-.BR Postmaster .
-(Note to administrators:
-.B ~alias
-doesn't apply to addresses that start with a user name,
-with certain exceptions.)
-.SH "SEE ALSO"
-addresses(5),
-dot-qmail(5),
-envelopes(5),
-qmail-header(8),
-qmail-inject(8)
diff --git a/qmail.7 b/qmail.7
index 3be2093..a59e8d0 100644 (file)
--- a/qmail.7
+++ b/qmail.7
@@ -12,10 +12,10 @@ Available commands for the
 .B .qmail
 file include
 .BR qbiff (1),
-.BR qlist (1),
 .BR qreceipt (1),
 .BR forward (1),
-and (for advanced users)
+.BR bouncesaying (1),
+and
 .BR condredirect (1).
 Other helpful commands include
 .BR maildirmake (1),
@@ -51,13 +51,12 @@ and
 .BR forgeries (7).
 
 Miscellaneous documentation includes
-.BR qmail-upgrade (7),
-.BR qmail-limits (7),
+.BR qmail-limits (7)
 and
 .BR qmail-pop3d (8).
 
 This documentation describes version
-1.01
+1.03
 of
 .BR qmail .
 See
diff --git a/qmail.c b/qmail.c
index 7484331..0fe0dfa 100644 (file)
--- a/qmail.c
+++ b/qmail.c
@@ -28,7 +28,7 @@ struct qmail *qq;
       close(pie[1]);
       if (fd_move(0,pim[0]) == -1) _exit(120);
       if (fd_move(1,pie[0]) == -1) _exit(120);
-      if (chdir(auto_qmail) == -1) _exit(120);
+      if (chdir(auto_qmail) == -1) _exit(61);
       execv(*binqqargs,binqqargs);
       _exit(120);
   }
@@ -77,27 +77,49 @@ void qmail_to(qq,s) struct qmail *qq; char *s;
   qmail_put(qq,"",1);
 }
 
-int qmail_close(qq)
+char *qmail_close(qq)
 struct qmail *qq;
 {
   int wstat;
+  int exitcode;
 
   qmail_put(qq,"",1);
   if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
   close(qq->fde);
 
-  if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID;
-  if (wait_crashed(wstat)) return QMAIL_CRASHED;
-  switch(wait_exitcode(wstat)) {
-    case 0: if (qq->flagerr) return QMAIL_BUG; return 0;
-    case 112: return QMAIL_USAGE;
-    case 115: return QMAIL_TOOLONG;
-    case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS;
-    case 121: return QMAIL_READ;
-    case 122: return QMAIL_WRITE;
-    case 123: return QMAIL_NOMEM;
-    case 124: return QMAIL_TIMEOUT;
-    case 120: return QMAIL_EXECSOFT;
-    default: /* 101 or 102 */ return QMAIL_BUG;
+  if (wait_pid(&wstat,qq->pid) != qq->pid)
+    return "Zqq waitpid surprise (#4.3.0)";
+  if (wait_crashed(wstat))
+    return "Zqq crashed (#4.3.0)";
+  exitcode = wait_exitcode(wstat);
+
+  switch(exitcode) {
+    case 115: /* compatibility */
+    case 11: return "Denvelope address too long for qq (#5.1.3)";
+    case 31: return "Dmail server permanently rejected message (#5.3.0)";
+    case 51: return "Zqq out of memory (#4.3.0)";
+    case 52: return "Zqq timeout (#4.3.0)";
+    case 53: return "Zqq write error or disk full (#4.3.0)";
+    case 0: if (!qq->flagerr) return ""; /* fall through */
+    case 54: return "Zqq read error (#4.3.0)";
+    case 55: return "Zqq unable to read configuration (#4.3.0)";
+    case 56: return "Zqq trouble making network connection (#4.3.0)";
+    case 61: return "Zqq trouble in home directory (#4.3.0)";
+    case 63:
+    case 64:
+    case 65:
+    case 66:
+    case 62: return "Zqq trouble creating files in queue (#4.3.0)";
+    case 71: return "Zmail server temporarily rejected message (#4.3.0)";
+    case 72: return "Zconnection to mail server timed out (#4.4.1)";
+    case 73: return "Zconnection to mail server rejected (#4.4.1)";
+    case 74: return "Zcommunication with mail server failed (#4.4.2)";
+    case 91: /* fall through */
+    case 81: return "Zqq internal bug (#4.3.0)";
+    case 120: return "Zunable to exec qq (#4.3.0)";
+    default:
+      if ((exitcode >= 11) && (exitcode <= 40))
+       return "Dqq permanent problem (#5.3.0)";
+      return "Zqq temporary problem (#4.3.0)";
   }
 }
diff --git a/qmail.h b/qmail.h
index 7864ea1..7fa13e2 100644 (file)
--- a/qmail.h
+++ b/qmail.h
@@ -18,19 +18,7 @@ extern void qmail_puts();
 extern void qmail_from();
 extern void qmail_to();
 extern void qmail_fail();
-extern int qmail_close();
+extern char *qmail_close();
 extern unsigned long qmail_qp();
 
-#define QMAIL_WAITPID -2
-#define QMAIL_CRASHED -3
-#define QMAIL_USAGE -4
-#define QMAIL_BUG -5
-#define QMAIL_SYS -6
-#define QMAIL_READ -7
-#define QMAIL_WRITE -8
-#define QMAIL_NOMEM -9
-#define QMAIL_EXECSOFT -11
-#define QMAIL_TIMEOUT -13
-#define QMAIL_TOOLONG -14
-
 #endif
index 9b51196..49b9807 100644 (file)
@@ -60,6 +60,8 @@ stralloc quoted = {0};
 
 void finishheader()
 {
+ char *qqx;
+
  if (!flagreceipt) die_noreceipt();
  if (str_equal(returnpath,"")) die_noreceipt();
  if (str_equal(returnpath,"#@[]")) die_noreceipt();
@@ -88,13 +90,11 @@ following address: ");
 
  qmail_from(&qqt,"");
  qmail_to(&qqt,returnpath);
+ qqx = qmail_close(&qqt);
 
- switch(qmail_close(&qqt))
-  {
-   case 0: break;
-   case QMAIL_TOOLONG: die_qqperm();
-   default: die_qqtemp();
-  }
+ if (*qqx)
+   if (*qqx == 'D') die_qqperm();
+   else die_qqtemp();
 }
 
 stralloc hfbuf = {0};
diff --git a/quote.c b/quote.c
index 9f97d93..659cfcd 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -45,7 +45,7 @@ unsigned int n;
 {
  unsigned char uch;
  int i;
- if (!n) return 0;
+ if (!n) return 1;
  for (i = 0;i < n;++i)
   {
    uch = s[i];
@@ -73,6 +73,7 @@ stralloc *sa;
 char *s;
 {
  int j;
+ if (!*s) return stralloc_copys(sa,s);
  j = str_rchr(s,'@');
  if (!stralloc_copys(&foo,s)) return 0;
  if (!s[j]) return quote(sa,&foo);
diff --git a/rcpthosts.c b/rcpthosts.c
new file mode 100644 (file)
index 0000000..1bc3018
--- /dev/null
@@ -0,0 +1,60 @@
+#include "cdb.h"
+#include "byte.h"
+#include "open.h"
+#include "error.h"
+#include "control.h"
+#include "constmap.h"
+#include "stralloc.h"
+#include "rcpthosts.h"
+
+static int flagrh = 0;
+static stralloc rh = {0};
+static struct constmap maprh;
+static int fdmrh;
+
+int rcpthosts_init()
+{
+  flagrh = control_readfile(&rh,"control/rcpthosts",0);
+  if (flagrh != 1) return flagrh;
+  if (!constmap_init(&maprh,rh.s,rh.len,0)) return flagrh = -1;
+  fdmrh = open_read("control/morercpthosts.cdb");
+  if (fdmrh == -1) if (errno != error_noent) return flagrh = -1;
+  return 0;
+}
+
+static stralloc host = {0};
+
+int rcpthosts(buf,len)
+char *buf;
+int len;
+{
+  int j;
+
+  if (flagrh != 1) return 1;
+
+  j = byte_rchr(buf,len,'@');
+  if (j >= len) return 1; /* presumably envnoathost is acceptable */
+
+  ++j; buf += j; len -= j;
+
+  if (!stralloc_copyb(&host,buf,len)) return -1;
+  buf = host.s;
+  case_lowerb(buf,len);
+
+  for (j = 0;j < len;++j)
+    if (!j || (buf[j] == '.'))
+      if (constmap(&maprh,buf + j,len - j)) return 1;
+
+  if (fdmrh != -1) {
+    uint32 dlen;
+    int r;
+
+    for (j = 0;j < len;++j)
+      if (!j || (buf[j] == '.')) {
+       r = cdb_seek(fdmrh,buf + j,len - j,&dlen);
+       if (r) return r;
+      }
+  }
+
+  return 0;
+}
diff --git a/rcpthosts.h b/rcpthosts.h
new file mode 100644 (file)
index 0000000..5e7e6cc
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef RCPTHOSTS_H
+#define RCPTHOSTS_H
+
+extern int rcpthosts_init();
+extern int rcpthosts();
+
+#endif
index 195eef6..c7abd70 100644 (file)
 #include "remoteinfo.h"
 
 static char line[999];
+static int t;
+
+static int mywrite(fd,buf,len) int fd; char *buf; int len;
+{
+  return timeoutwrite(t,fd,buf,len);
+}
+static int myread(fd,buf,len) int fd; char *buf; int len;
+{
+  return timeoutread(t,fd,buf,len);
+}
 
 char *remoteinfo_get(ipr,rp,ipl,lp,timeout)
 struct ip_address *ipr;
@@ -28,6 +38,8 @@ int timeout;
   unsigned int len;
   int numcolons;
   char ch;
+
+  t = timeout;
  
   s = socket(AF_INET,SOCK_STREAM,0);
   if (s == -1) return 0;
@@ -46,10 +58,10 @@ int timeout;
   len += fmt_ulong(line + len,lp);
   len += fmt_str(line + len,"\r\n");
  
-  substdio_fdbuf(&ss,timeoutwrite,TIMEOUTWRITE(timeout,s),buf,sizeof(buf));
+  substdio_fdbuf(&ss,mywrite,s,buf,sizeof buf);
   if (substdio_putflush(&ss,line,len) == -1) { close(s); return 0; }
  
-  substdio_fdbuf(&ss,timeoutread,TIMEOUTREAD(timeout,s),buf,sizeof(buf));
+  substdio_fdbuf(&ss,myread,s,buf,sizeof buf);
   x = line;
   numcolons = 0;
   for (;;) {
diff --git a/scan_nbblong.c b/scan_nbblong.c
deleted file mode 100644 (file)
index 5078053..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "scan.h"
-
-unsigned int scan_nbblong(s,n,base,bext,u)
-char *s; unsigned int n; unsigned int base; unsigned int bext; unsigned long *u;
-/* Note that n == 0 means scan forever. Hopefully this is a good choice. */
-{
-  unsigned int pos; unsigned long result; unsigned long c;
-  pos = 0; result = 0;
-  while (((c = (unsigned long) (unsigned char) (s[pos] - '0')) < base)
-       ||(((c = (unsigned long) (unsigned char) (s[pos] - 'a')) < bext)
-        &&(c = c + base))
-       ||(((c = (unsigned long) (unsigned char) (s[pos] - 'A')) < bext)
-        &&(c = c + base))
-        ) /* this gets the job done */
-    { result = result * (base + bext) + c; ++pos; if (pos == n) break; }
-  *u = result; return pos;
-}
-
-unsigned int scan_nbbint(s,n,base,bext,u)
-char *s; unsigned int n; unsigned int base; unsigned int bext; unsigned int *u;
-{
-  unsigned int pos; unsigned long result;
-  pos = scan_nbblong(s,n,base,bext,&result);
-  *u = result; return pos;
-}
-
-unsigned int scan_nbbshort(s,n,base,bext,u)
-char *s; unsigned int n; unsigned int base; unsigned int bext; unsigned short *u;
-{
-  unsigned int pos; unsigned long result;
-  pos = scan_nbblong(s,n,base,bext,&result);
-  *u = result; return pos;
-}
index f4205e1..46d0e4b 100644 (file)
@@ -9,8 +9,40 @@
 
 void nomem()
 {
- substdio_putsflush(subfderr,"sendmail: fatal: out of memory\n");
- _exit(111);
+  substdio_putsflush(subfderr,"sendmail: fatal: out of memory\n");
+  _exit(111);
+}
+
+void die_usage()
+{
+  substdio_putsflush(subfderr,"sendmail: usage: sendmail [ -t ] [ -fsender ] [ -Fname ] [ -bp ] [ -bs ] [ arg ... ]\n");
+  _exit(100);
+}
+
+char *smtpdarg[] = { "bin/qmail-smtpd", 0 };
+void smtpd()
+{
+  if (!env_get("PROTO")) {
+    if (!env_put("RELAYCLIENT=")) nomem();
+    if (!env_put("DATABYTES=0")) nomem();
+    if (!env_put("PROTO=TCP")) nomem();
+    if (!env_put("TCPLOCALIP=127.0.0.1")) nomem();
+    if (!env_put("TCPLOCALHOST=localhost")) nomem();
+    if (!env_put("TCPREMOTEIP=127.0.0.1")) nomem();
+    if (!env_put("TCPREMOTEHOST=localhost")) nomem();
+    if (!env_put("TCPREMOTEINFO=sendmail-bs")) nomem();
+  }
+  execv(*smtpdarg,smtpdarg);
+  substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-smtpd\n");
+  _exit(111);
+}
+
+char *qreadarg[] = { "bin/qmail-qread", 0 };
+void mailq()
+{
+  execv(*qreadarg,qreadarg);
+  substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-qread\n");
+  _exit(111);
 }
 
 int flagh;
@@ -20,79 +52,78 @@ void main(argc,argv)
 int argc;
 char **argv;
 {
- int opt;
- char **qiargv;
- char **arg;
- int i;
-
- if (chdir(auto_qmail) == -1)
-  {
-   substdio_putsflush(subfderr,"sendmail: fatal: unable to switch to qmail home directory\n");
-   _exit(111);
+  int opt;
+  char **qiargv;
+  char **arg;
+  int i;
+  if (chdir(auto_qmail) == -1) {
+    substdio_putsflush(subfderr,"sendmail: fatal: unable to switch to qmail home directory\n");
+    _exit(111);
   }
 
- flagh = 0;
- sender = 0;
- while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJx")) != opteof)
-   switch(opt)
-    {
-     case 'B': break;
-     case 't': flagh = 1; break;
-     case 'f': sender = optarg; break;
-     case 'F': if (!env_put2("MAILNAME",optarg)) nomem(); break;
-     case 'p': break; /* could generate a Received line from optarg */
-     case 'v': break;
-     case 'i': break; /* what an absurd concept */
-     case 'x': break; /* SVR4 stupidity */
-     case 'm': break; /* twisted-paper-path blindness, incompetent design */
-     case 'e': break; /* qmail has only one error mode */
-     case 'o':
-       switch(optarg[0])
-       {
-        case 'd': break; /* qmail has only one delivery mode */
-        case 'e': break; /* see 'e' above */
-        case 'i': break; /* see 'i' above */
-        case 'm': break; /* see 'm' above */
+  flagh = 0;
+  sender = 0;
+  while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJxb:")) != opteof)
+    switch(opt) {
+      case 'B': break;
+      case 't': flagh = 1; break;
+      case 'f': sender = optarg; break;
+      case 'F': if (!env_put2("MAILNAME",optarg)) nomem(); break;
+      case 'p': break; /* could generate a Received line from optarg */
+      case 'v': break;
+      case 'i': break; /* what an absurd concept */
+      case 'x': break; /* SVR4 stupidity */
+      case 'm': break; /* twisted-paper-path blindness, incompetent design */
+      case 'e': break; /* qmail has only one error mode */
+      case 'o':
+        switch(optarg[0]) {
+         case 'd': break; /* qmail has only one delivery mode */
+         case 'e': break; /* see 'e' above */
+         case 'i': break; /* see 'i' above */
+         case 'm': break; /* see 'm' above */
+       }
+        break;
+      case 'E': case 'J': /* Sony NEWS-OS */
+        while (argv[optind][optpos]) ++optpos; /* skip optional argument */
+        break;
+      case 'b':
+       switch(optarg[0]) {
+         case 'm': break;
+         case 'p': mailq();
+         case 's': smtpd();
+         default: die_usage();
        }
-       break;
-     case 'E': case 'J': /* Sony NEWS-OS */
-       while (argv[optind][optpos]) ++optpos; /* skip optional argument */
-       break;
-     default:
-       _exit(100);
+       break;
+      default:
+       die_usage();
     }
- argc -= optind;
- argv += optind;
-
- if (str_equal(optprogname,"mailq"))
-  {
-   substdio_putsflush(subfderr,"sendmail: fatal: please use qmail-qread instead\n");
-   _exit(100);
-  }
+  argc -= optind;
+  argv += optind;
+  if (str_equal(optprogname,"mailq"))
+    mailq();
 
- if (str_equal(optprogname,"newaliases"))
-  {
-   substdio_putsflush(subfderr,"sendmail: fatal: please use the qmsmac newaliases instead\n");
-   _exit(100);
+  if (str_equal(optprogname,"newaliases")) {
+    substdio_putsflush(subfderr,"sendmail: fatal: please use fastforward/newaliases instead\n");
+    _exit(100);
   }
 
- qiargv = (char **) alloc((argc + 10) * sizeof(char *));
- if (!qiargv) nomem();
-
- arg = qiargv;
- *arg++ = "bin/qmail-inject";
- *arg++ = (flagh ? "-H" : "-a");
- if (sender)
-  {
-   *arg++ = "-f";
-   *arg++ = sender;
+  qiargv = (char **) alloc((argc + 10) * sizeof(char *));
+  if (!qiargv) nomem();
+  arg = qiargv;
+  *arg++ = "bin/qmail-inject";
+  *arg++ = (flagh ? "-H" : "-a");
+  if (sender) {
+    *arg++ = "-f";
+    *arg++ = sender;
   }
- *arg++ = "--";
- for (i = 0;i < argc;++i) *arg++ = argv[i];
- *arg = 0;
-
- execv(*qiargv,qiargv);
+  *arg++ = "--";
+  for (i = 0;i < argc;++i) *arg++ = argv[i];
+  *arg = 0;
  
- substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-inject\n");
- _exit(111);
+  execv(*qiargv,qiargv);
+  substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-inject\n");
+  _exit(111);
 }
index 27be0ea..2fcef15 100644 (file)
@@ -1,6 +1,7 @@
 #include "stralloc.h"
 #include "readwrite.h"
 #include "slurpclose.h"
+#include "error.h"
 
 int slurpclose(fd,sa,bufsize)
 int fd;
@@ -11,6 +12,7 @@ int bufsize;
   for (;;) {
     if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
     r = read(fd,sa->s + sa->len,bufsize);
+    if (r == -1) if (errno == error_intr) continue;
     if (r <= 0) { close(fd); return r; }
     sa->len += r;
   }
index 7a0de6e..c3f7f7d 100644 (file)
@@ -36,6 +36,12 @@ extern void substdio_seek();
 #define substdio_PEEK(s) ( (s)->x + (s)->n )
 #define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) )
 
+#define substdio_BPUTC(s,c) \
+  ( ((s)->n != (s)->p) \
+    ? ( (s)->x[(s)->p++] = (c), 0 ) \
+    : substdio_bput((s),&(c),1) \
+  )
+
 extern int substdio_copy();
 
 #endif
index 4cebf54..c75e29c 100644 (file)
@@ -3,23 +3,20 @@
 #include "error.h"
 #include "readwrite.h"
 
-int timeoutread(fdt,buf,len) int fdt; char *buf; int len;
+int timeoutread(t,fd,buf,len) int t; int fd; char *buf; int len;
 {
   fd_set rfds;
   struct timeval tv;
-  int fd;
 
-  tv.tv_sec = (fdt >> 10);
+  tv.tv_sec = t;
   tv.tv_usec = 0;
 
-  fd = (fdt & 1023);
   FD_ZERO(&rfds);
   FD_SET(fd,&rfds);
 
   if (select(fd + 1,&rfds,(fd_set *) 0,(fd_set *) 0,&tv) == -1) return -1;
   if (FD_ISSET(fd,&rfds)) return read(fd,buf,len);
 
-  shutdown(fd,0);
   errno = error_timeout;
   return -1;
 }
index c1d19a0..20d3bfc 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef TIMEOUTREAD_H
 #define TIMEOUTREAD_H
 
-#define TIMEOUTREAD(s,fd) (((s) << 10) | (fd))
-
 extern int timeoutread();
 
 #endif
index 8a09c8a..516d283 100644 (file)
@@ -3,23 +3,20 @@
 #include "error.h"
 #include "readwrite.h"
 
-int timeoutwrite(fdt,buf,len) int fdt; char *buf; int len;
+int timeoutwrite(t,fd,buf,len) int t; int fd; char *buf; int len;
 {
   fd_set wfds;
   struct timeval tv;
-  int fd;
 
-  tv.tv_sec = (fdt >> 10);
+  tv.tv_sec = t;
   tv.tv_usec = 0;
 
-  fd = (fdt & 1023);
   FD_ZERO(&wfds);
   FD_SET(fd,&wfds);
 
   if (select(fd + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1;
   if (FD_ISSET(fd,&wfds)) return write(fd,buf,len);
 
-  shutdown(fd,1);
   errno = error_timeout;
   return -1;
 }
index c93aa18..4725861 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef TIMEOUTWRITE_H
 #define TIMEOUTWRITE_H
 
-#define TIMEOUTWRITE(s,fd) (((s) << 10) | (fd))
-
 extern int timeoutwrite();
 
 #endif
index 7760159..48a4388 100644 (file)
@@ -306,6 +306,7 @@ stralloc *buf;
      default:
        do
        {
+        if (sa->s[i] == '\\') if (++i >= salen) break;
         ++numchars;
         if (++i >= salen)
           break;
@@ -384,6 +385,7 @@ stralloc *buf;
        t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
        do
        {
+        if (sa->s[i] == '\\') if (++i >= salen) break;
         *cbuf++ = sa->s[i]; ++t->slen;
         if (++i >= salen)
           break;
index 8dde830..d7a7e84 100644 (file)
@@ -1,13 +1,39 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include "error.h"
+#include "haswaitp.h"
+
+#ifdef HASWAITPID
 
-/* restriction: you must not care about any other child. */
 int wait_pid(wstat,pid) int *wstat; int pid;
 {
   int r;
+
   do
+    r = waitpid(pid,wstat,0);
+  while ((r == -1) && (errno == error_intr));
+  return r;
+}
+
+#else
+
+/* XXX untested */
+/* XXX breaks down with more than two children */
+static int oldpid = 0;
+static int oldwstat; /* defined if(oldpid) */
+
+int wait_pid(wstat,pid) int *wstat; int pid;
+{
+  int r;
+
+  if (pid == oldpid) { *wstat = oldwstat; oldpid = 0; return pid; }
+
+  do {
     r = wait(wstat);
-  while ((r != pid) && ((r != -1) || (errno == error_intr)));
+    if ((r != pid) && (r != -1)) { oldwstat = *wstat; oldpid = r; continue; }
+  }
+  while ((r == -1) && (errno == error_intr));
   return r;
 }
+
+#endif