nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit d15ee51c9ddb9d233ad5ebc28fddf1de8378657d
parent af9625ddf9464e85fd781e8ad889201ce340d9fc
Author: D. J. Bernstein <djb@cr.yp.to>
Date:   Thu,  7 May 1998 00:00:00 +0200

qmail 1.02

Diffstat:
MBLURB2 | 6+++---
MBLURB3 | 15+++++++++------
MBLURB4 | 4++--
MCHANGES | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MFAQ | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
MFILES | 55++++++++++++++++++++++++++++++++++++++-----------------
MINSTALL | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
MINSTALL.alias | 8++++----
MINSTALL.boot | 5++---
MINSTALL.ctl | 19++++++++++++++-----
MINSTALL.ids | 15++++++++++++++-
AINSTALL.maildir | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MINSTALL.mbox | 124+++++++++++++++++++------------------------------------------------------------
DINSTALL.qsmhook | 53-----------------------------------------------------
AINSTALL.vsm | 50++++++++++++++++++++++++++++++++++++++++++++++++++
MINTERNALS | 3++-
MMakefile | 1280+++++++++++++++++++++++++++++++++++++------------------------------------------
APIC.local2alias | 37+++++++++++++++++++++++++++++++++++++
APIC.local2ext | 41+++++++++++++++++++++++++++++++++++++++++
APIC.local2local | 40++++++++++++++++++++++++++++++++++++++++
APIC.local2rem | 38++++++++++++++++++++++++++++++++++++++
APIC.local2virt | 44++++++++++++++++++++++++++++++++++++++++++++
APIC.nullclient | 38++++++++++++++++++++++++++++++++++++++
APIC.relaybad | 8++++++++
APIC.relaygood | 33+++++++++++++++++++++++++++++++++
APIC.rem2local | 36++++++++++++++++++++++++++++++++++++
MREADME | 358+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
DRFCHCSC | 37-------------------------------------
DRFCLOOPS | 338-------------------------------------------------------------------------------
DRFCMXPS | 122-------------------------------------------------------------------------------
DRFCNETSTR | 88-------------------------------------------------------------------------------
DRFCNRUDT | 89-------------------------------------------------------------------------------
DRFCQMTP | 229-------------------------------------------------------------------------------
DRFCQSBMF | 155-------------------------------------------------------------------------------
DRFCVERP | 88-------------------------------------------------------------------------------
MSECURITY | 18+++++++++---------
ASENDMAIL | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MTARGETS | 165+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
MTHANKS | 488+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
MTHOUGHTS | 155+++++++++++++++++++++++++++++++++++--------------------------------------------
MTODO | 29+++++++++++++++++++++++------
MUPGRADE | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
MVERSION | 2+-
Abinm1+df.sh | 11+++++++++++
Abinm1.sh | 10++++++++++
Abinm2+df.sh | 11+++++++++++
Abinm2.sh | 10++++++++++
Abinm3+df.sh | 11+++++++++++
Abinm3.sh | 10++++++++++
Acommands.c | 40++++++++++++++++++++++++++++++++++++++++
Acommands.h | 12++++++++++++
Mcondredirect.1 | 7+++++++
Mcondredirect.c | 114+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mconf-qmail | 7+++++++
Aconfig-fast.sh | 30++++++++++++++++++++++++++++++
Rqmail-config.sh -> config.sh | 0
Mconstmap.c | 161+++++++++++++++++++++++++++++++++++++------------------------------------------
Mconstmap.h | 6++----
Mcontrol.c | 3++-
Mdot-qmail.9 | 10+++++-----
Mforward.c | 76+++++++++++++++++++++++++++++++++++++++-------------------------------------
Mhfield.c | 1+
Mhfield.h | 3++-
Ahome+df.sh | 9+++++++++
Ahome.sh | 7+++++++
Mmaildir.5 | 2+-
Mmaildirmake.c | 30++++++++++++++++--------------
Mndelay.c | 6+++++-
Mndelay_off.c | 6+++++-
Mpredate.c | 39+++++++++++++++------------------------
Mpreline.c | 121++++++++++++++++++++++++++++++++++++++++---------------------------------------
Aproc+df.sh | 9+++++++++
Aproc.sh | 7+++++++
Dqlist.1 | 112-------------------------------------------------------------------------------
Dqlist.c | 333-------------------------------------------------------------------------------
Dqlist2.sh | 1-
Mqmail-command.8 | 44+++++++++++++++++++++++++++++++++++---------
Mqmail-control.9 | 6+++++-
Mqmail-getpw.9 | 7++++++-
Mqmail-getpw.c | 2++
Mqmail-header.5 | 4++--
Mqmail-hier.c | 56++++++++++++++++++++++++++++++++++++++++++++++++--------
Mqmail-inject.8 | 15+++++++++++++++
Mqmail-inject.c | 196+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mqmail-local.8 | 4++--
Mqmail-local.c | 274+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mqmail-log.5 | 37++++++++++++++-----------------------
Mqmail-lspawn.8 | 4++--
Aqmail-newmrh.9 | 41+++++++++++++++++++++++++++++++++++++++++
Aqmail-newmrh.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mqmail-pop3d.8 | 2+-
Mqmail-pop3d.c | 500++++++++++++++++++++++++++++++++-----------------------------------------------
Mqmail-popup.c | 254++++++++++++++++++++++++++++++++++---------------------------------------------
Mqmail-pw2u.9 | 12+++++++++---
Mqmail-pw2u.c | 14+++++++++-----
Aqmail-qmqpc.8 | 35+++++++++++++++++++++++++++++++++++
Aqmail-qmqpc.c | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aqmail-qmqpd.8 | 31+++++++++++++++++++++++++++++++
Aqmail-qmqpd.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mqmail-qmtpd.8 | 7+++++--
Mqmail-qmtpd.c | 439++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mqmail-qstat.sh | 8++++++--
Mqmail-queue.8 | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mqmail-queue.c | 40++++++++++++++++++++--------------------
Mqmail-remote.8 | 3+--
Mqmail-remote.c | 613++++++++++++++++++++++++++++++++++++-------------------------------------------
Mqmail-send.9 | 40+++++++++++-----------------------------
Mqmail-send.c | 104+++++++++++++++++++++++++-------------------------------------------------------
Mqmail-showctl.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mqmail-smtpd.8 | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mqmail-smtpd.c | 699++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mqmail-start.9 | 11+++++++----
Aqmail-tcpok.8 | 24++++++++++++++++++++++++
Aqmail-tcpok.c | 35+++++++++++++++++++++++++++++++++++
Mqmail-tcpto.8 | 3++-
Dqmail-upgrade.9 | 201-------------------------------------------------------------------------------
Mqmail.7 | 6++----
Mqmail.c | 52+++++++++++++++++++++++++++++++++++++---------------
Mqmail.h | 14+-------------
Mqreceipt.c | 12++++++------
Mquote.c | 3++-
Arcpthosts.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arcpthosts.h | 7+++++++
Mremoteinfo.c | 16++++++++++++++--
Dscan_nbblong.c | 33---------------------------------
Msendmail.c | 167+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mslurpclose.c | 2++
Msubstdio.h | 6++++++
Mtimeoutread.c | 7++-----
Mtimeoutread.h | 2--
Mtimeoutwrite.c | 7++-----
Mtimeoutwrite.h | 2--
Mtoken822.c | 2++
Mwait_pid.c | 30++++++++++++++++++++++++++++--
134 files changed, 5589 insertions(+), 5483 deletions(-)

diff --git 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 @@ -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 diff --git 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 @@ -1,3 +1,220 @@ +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 @@ -21,6 +21,10 @@ 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? @@ -31,7 +35,7 @@ 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 +45,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? @@ -102,11 +108,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 +126,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 +141,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 +154,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 +173,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 +200,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 +you rather than the original sender. - | qlist2 sos my.host.name - -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? @@ -237,6 +247,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 @@ -284,17 +336,20 @@ replacing 7770 and 2108 with the qmaild uid and nofiles gid. See question 5.1 for more details. -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 @@ -315,8 +370,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,21 +390,21 @@ 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? @@ -358,7 +412,7 @@ before /var/qmail/bin/qmail-smtpd in your tcpserver line. Answer: Three steps. First, put | [ "@$HOST" = "@fixme" ] || ( echo Permission denied; exit 100 ) - | qmail-inject -f "$SENDER" -- "$EXT2" + | qmail-inject -f "$SENDER" -- "$DEFAULT" into ~alias/.qmail-fixup-default. Second, put @@ -371,12 +425,12 @@ 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. @@ -395,8 +449,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 +485,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 +585,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 @@ -9,23 +9,26 @@ INSTALL.alias INSTALL.boot INSTALL.ctl INSTALL.ids +INSTALL.maildir INSTALL.mbox -INSTALL.qsmhook +INSTALL.vsm 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 @@ -58,7 +61,6 @@ mailsubj.1 mbox.5 preline.1 qbiff.1 -qlist.1 qmail-clean.8 qmail-command.8 qmail-control.9 @@ -69,10 +71,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 +88,28 @@ 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 +120,7 @@ qmail-send.c qmail-showctl.c qmail-smtpd.c qmail-start.c +qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c @@ -122,7 +132,6 @@ hostname.c ipmeprint.c tcp-env.c sendmail.c -qlist.c qreceipt.c qsmhook.c qbiff.c @@ -137,13 +146,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 +181,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 @@ -348,7 +368,6 @@ fmt_ulong.c scan.h scan_ulong.c scan_8long.c -scan_nbblong.c slurpclose.h slurpclose.c quote.h @@ -399,3 +418,5 @@ maildir.5 maildir.h maildir.c tcp-environ.5 +constmap.h +constmap.c diff --git a/INSTALL b/INSTALL @@ -16,80 +16,100 @@ Installation steps that 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: + + 3. Compile the programs and create the qmail directory tree: # make setup - 6. Run instcheck to make sure it doesn't print any warnings: + + 4. 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: + + 5. Read INSTALL.ctl and FAQ. Minimal survival command: + # ./config + + 6. 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. + + 7. Read INSTALL.mbox and INSTALL.vsm. + + 8. Read INSTALL.maildir. + + 9. Read SENDMAIL. This is what your users will want to know about the + switch from sendmail to qmail. + +10. Copy /var/qmail/boot/home (or proc) to /var/qmail/rc. 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. + # /var/qmail/rc & + 12. Look for a - qmail: running + qmail: status: local 0/10 remote 0/20 line in syslog. qmail-send always prints either ``cannot start'' or - ``running''. (The big number is a splogger timestamp.) + ``status''. (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. + as qmailq. You will also see splogger, running as qmaill. + 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: + 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.) + 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: 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 ~/Mailbox. + You will now have a bounce message in your 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: 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. + 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. + Look for the message in the alias mailbox, normally ~alias/Mailbox. + 18. Double-bounce test: Send a message with a completely bad envelope. % /var/qmail/bin/qmail-inject -f nonexistent To: unknownuser @@ -98,7 +118,8 @@ Pre-upgrade tests: 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. + bounce in the alias mailbox. + 19. Group membership test: % cat > ~me/.qmail-groups |groups >> MYGROUPS; exit 0 @@ -112,28 +133,35 @@ 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 # ln -s /var/qmail/bin/sendmail /usr/lib/sendmail + 23. 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 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. @@ -166,16 +194,20 @@ Post-upgrade tests (can be done immediately after step 24): 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. + PoStMaStEr@domain. Look for the message in the alias mailbox. That's it! To report success: % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ - | mail djb-qst@koobera.math.uic.edu + | mail djb-qst@cr.yp.to Replace First M. Last with your name. If you have questions about qmail, -contact qmail@pobox.com. +join the qmail mailing list; see http://pobox.com/~djb/qmail.html. diff --git a/INSTALL.alias b/INSTALL.alias @@ -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 @@ -10,7 +10,6 @@ Find sendmail in your boot scripts. It's usually in either /etc/rc or -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 &' + csh -cf '/var/qmail/rc &' -That's it. (Make sure you include the ./ and the &.) +That's it. (Make sure you include the &.) diff --git a/INSTALL.ctl b/INSTALL.ctl @@ -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, diff --git a/INSTALL.ids b/INSTALL.ids @@ -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 @@ -0,0 +1,64 @@ +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. + +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. + + +2. Sun's Network F_ail_u_re 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. diff --git a/INSTALL.mbox b/INSTALL.mbox @@ -3,110 +3,46 @@ 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). +qmail-local delivers mail by default into ~user/Mailbox (in mbox format, +using flock), rather than /var/spool/mail/user. -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. +For an explanation of the problems with /var/spool/mail, and a list of +options if you want to continue delivering to /var/spool/mail, see +INSTALL.vsm. -If you desperately don't want to change anything, see INSTALL.qsmhook. +This file explains how to handle the change to ~user/Mailbox. The basic +procedure 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_ail_u_re 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. +An alternative to symbolic links is hlfsd. Consult the documentation for +hlfsd if it is included in your operating system. -1. Throw away /usr/spool/mail! +If /var/spool/mail is large, you can gain extra speed by configuring +your mail software to look at ~user/Mailbox directly: -/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: + * Most MUAs: Put ``setenv MAIL $HOME/Mailbox'' in your system-wide + .cshrc and ``MAIL=$HOME/Mailbox; export MAIL'' in your system-wide + .profile. - 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. + * 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.) - 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. + * pine: Put ``inbox-path=Mailbox'' in your system-wide pine.conf. + (For pine versions more recent than 3.91, see also FAQ 6.2.) - 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. + * procmail: Change SYSTEM_MBOX in config.h and recompile. - D. Announce the change. + * qpopper 2.2: Change /.mail to /Mailbox in pop_dropcopy.c and + recompile with -DHOMEDIRMAIL in CFLAGS. 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. - - -3. Sun's Network F_ail_u_re 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. +/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 @@ -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 @@ -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. diff --git 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 diff --git 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,70 @@ 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 + 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 +209,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 +233,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,21 +250,20 @@ 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: \ @@ -238,7 +275,7 @@ 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 +283,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 +292,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 +307,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 +366,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 +389,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 +401,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 +417,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 +429,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 +441,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 +454,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 +484,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 +492,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,15 +500,15 @@ 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 fd.a: \ @@ -479,15 +516,15 @@ 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 +533,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 +568,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 +605,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,24 +668,35 @@ 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 +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 install: \ @@ -663,10 +706,8 @@ open.a error.a str.a fs.a stralloc.a alloc.a open.a error.a str.a fs.a 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 stralloc.h gen_alloc.h getln.h \ +readwrite.h exit.h open.h error.h strerr.h byte.h fifo.h ./compile install.c instcheck: \ @@ -676,28 +717,22 @@ error.a str.a fs.a alloc.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 substdio.h stralloc.h gen_alloc.h getln.h \ +readwrite.h exit.h error.h strerr.h byte.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 +742,21 @@ 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 maildirmake maildir2mbox maildirwatch \ +qail elq pinq qmail-hier 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 +768,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 +784,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 +802,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 +833,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,21 +876,20 @@ 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-command.0 tcp-environ.0 maildir.0 mbox.0 addresses.0 \ -envelopes.0 forgeries.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 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 mbox.0: \ 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 +897,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 +920,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 +949,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 +1017,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 +1033,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,12 +1073,9 @@ 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: \ @@ -1116,40 +1089,31 @@ auto_uids.o 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 subfd.h substdio.h substdio.h auto_split.h \ +auto_uids.h fmt.h ./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 +1131,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 +1169,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 +1219,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 +1283,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 +1357,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 +1390,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 +1411,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 +1432,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 +1461,54 @@ 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 +substdio.a error.a str.a fs.a auto_qmail.o auto_uids.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 + alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ + auto_uids.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_qmail.h auto_uids.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 +1528,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 +1557,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 +1587,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 +1604,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 +1617,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 +1665,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,10 +1693,8 @@ 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: \ @@ -1753,55 +1702,59 @@ it man conf-qmail ./qmail-hier | ./install `head -1 conf-qmail` 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 \ -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 \ -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 \ -case_diffb.c case_diffs.c case_lowerb.c case_lowers.c case_starts.c \ -cdb.3 cdb.h cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h \ -cdbmake_add.c cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 \ -coe.h coe.c fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c fifo_make.3 \ -fifo.h fifo.c trymkffo.c fork.h1 fork.h2 tryvfork.c now.3 now.h now.c \ -open.h open_append.c open_excl.c open_read.c open_trunc.c \ -open_write.c seek.h seek_cur.c seek_end.c seek_set.c seek_trunc.c \ -conf-qmail auto_qmail.h qmail.h qmail.c gen_alloc.h gen_allocdefs.h \ -stralloc.3 stralloc.h stralloc_eady.c stralloc_pend.c stralloc_copy.c \ +INSTALL.boot INSTALL.ctl INSTALL.ids INSTALL.maildir INSTALL.mbox \ +INSTALL.vsm 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 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 \ +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-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 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 \ +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 \ +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 install.c instcheck.c \ +alloc.3 alloc.h alloc.c alloc_re.c case.3 case.h case_diffb.c \ +case_diffs.c case_lowerb.c case_lowers.c case_starts.c cdb.3 cdb.h \ +cdb_hash.c cdb_seek.c cdb_unpack.c cdbmake.h cdbmake_add.c \ +cdbmake_hash.c cdbmake_pack.c cdbmss.h cdbmss.c coe.3 coe.h coe.c \ +fd.h fd_copy.3 fd_copy.c fd_move.3 fd_move.c fifo_make.3 fifo.h \ +fifo.c trymkffo.c fork.h1 fork.h2 tryvfork.c now.3 now.h now.c open.h \ +open_append.c open_excl.c open_read.c open_trunc.c open_write.c \ +seek.h seek_cur.c seek_end.c seek_set.c seek_trunc.c conf-qmail \ +auto_qmail.h qmail.h qmail.c gen_alloc.h gen_allocdefs.h stralloc.3 \ +stralloc.h stralloc_eady.c stralloc_pend.c stralloc_copy.c \ stralloc_opyb.c stralloc_opys.c stralloc_cat.c stralloc_catb.c \ stralloc_cats.c stralloc_arts.c strerr.h strerr_sys.c strerr_die.c \ substdio.h substdio.c substdi.c substdo.c substdio_copy.c subfd.h \ @@ -1819,14 +1772,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 +1791,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 +1843,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 +1872,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 +1909,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 +1951,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 +1994,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 +2030,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 +2039,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 +2085,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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -1,6 +1,6 @@ -qmail 1.01 -19970413 -Copyright 1997 +qmail 1.02 +19980430 +Copyright 1998 D. J. Bernstein, qmail@pobox.com qmail is a secure, reliable, efficient, simple message transfer agent. @@ -9,191 +9,261 @@ 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. +1.01, 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/RFCHCSC b/RFCHCSC @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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. diff --git 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 @@ -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 @@ -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 @@ -280,10 +291,6 @@ condredirect maildirmake.o maildirmake maildir2mbox.o -maildir.o -strerr_sys.o -strerr_die.o -strerr.a maildir2mbox maildirwatch.o maildirwatch @@ -296,6 +303,16 @@ install.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,24 +323,30 @@ 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 @@ -333,13 +356,13 @@ 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 +374,5 @@ addresses.0 envelopes.0 forgeries.0 man +setup +check diff --git a/THANKS b/THANKS @@ -2,216 +2,334 @@ 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 +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 +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 diff --git 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 @@ -1,9 +1,26 @@ -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 +test qmail-qmqpc +test qmail-qmqpd + +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 lib822 in qmail-inject +use lib822 in qreceipt +use lib822 in qbiff +use lib822 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 @@ -3,12 +3,20 @@ 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 +Here's how to upgrade from qmail 1.01 to qmail 1.02. 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: 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: recipientmap is gone. The virtualdomains mechanism has been +expanded to support virtual users. + +WARNING: qmail-start is now normally started from /var/qmail/rc. If you +have changed your qmail-start line, you will have to change +/var/qmail/rc accordingly in step 8. Before starting, compare conf* to your old conf*, and make any necessary @@ -17,27 +25,37 @@ changes. Do not copy your old conf*; the baseline has changed. 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/*/* + 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 - 7. Run instcheck to make sure it doesn't print any warnings: + + 6. 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. + + 7. 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.) + + 8. Compare /var/qmail/rc to the qmail-start boot line in your boot + scripts. Edit /var/qmail/rc if necessary. Replace the qmail-start + boot line in your boot scripts with + csh -cf '/var/qmail/rc &' + + 9. Reenable deliveries: + # csh -cf '/var/qmail/rc &' + 10. 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.) @@ -46,48 +64,61 @@ How to install: How to test (steps 11-17 can be done before step 10): 11. Look for a - qmail: running + qmail: status: local 0/10 remote 0/20 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: + 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.) + 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: 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 ~/Mailbox. + You will now have a bounce message in your 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: 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. + 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. + Look for the message in the alias mailbox. + 16. Double-bounce test: Send a message with a completely bad envelope. % /var/qmail/bin/qmail-inject -f nonexistent To: unknownuser @@ -96,7 +127,8 @@ How to test (steps 11-17 can be done before step 10): 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. + bounce in the alias mailbox. + 17. Group membership test: % cat > ~me/.qmail-groups |groups >> MYGROUPS; exit 0 @@ -104,6 +136,7 @@ How to test (steps 11-17 can be done before step 10): % 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... @@ -130,16 +163,20 @@ How to test (steps 11-17 can be done before step 10): 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. + PoStMaStEr@domain. Look for the message in the alias mailbox. That's it! To report success: % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ - | mail djb-qst@koobera.math.uic.edu + | mail djb-qst@cr.yp.to Replace First M. Last with your name. If you have questions about qmail, -contact qmail@pobox.com. +join the qmail mailing list; see http://pobox.com/~djb/qmail.html. diff --git a/VERSION b/VERSION @@ -1 +1 @@ -qmail 1.01 +qmail 1.02 diff --git a/binm1+df.sh b/binm1+df.sh @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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/commands.c b/commands.c @@ -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 @@ -0,0 +1,12 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +struct commands { + char *text; + void (*fun)(); + void (*flush)(); +} ; + +extern int commands(); + +#endif diff --git a/condredirect.1 b/condredirect.1 @@ -48,6 +48,13 @@ 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" dot-qmail(5), qmail-command(8), diff --git a/condredirect.c b/condredirect.c @@ -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); } diff --git a/conf-qmail b/conf-qmail @@ -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 @@ -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!' diff --git a/qmail-config.sh b/config.sh diff --git a/constmap.c b/constmap.c @@ -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); } diff --git a/constmap.h b/constmap.h @@ -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(); diff --git 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/dot-qmail.9 b/dot-qmail.9 @@ -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/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); } diff --git 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 }; diff --git 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/home+df.sh b/home+df.sh @@ -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 @@ -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/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 . diff --git a/maildirmake.c b/maildirmake.c @@ -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); } diff --git 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); } diff --git a/ndelay_off.c b/ndelay_off.c @@ -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); } diff --git 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)); } diff --git 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" @@ -10,78 +10,81 @@ #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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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"} diff --git a/qmail-command.8 b/qmail-command.8 @@ -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), diff --git a/qmail-control.9 b/qmail-control.9 @@ -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), diff --git a/qmail-getpw.9 b/qmail-getpw.9 @@ -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 diff --git a/qmail-getpw.c b/qmail-getpw.c @@ -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) { diff --git a/qmail-header.5 b/qmail-header.5 @@ -239,7 +239,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 +250,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 @@ -78,8 +78,42 @@ void main() dir(auto_uido,"755","/man/man5"); dir(auto_uido,"755","/man/man7"); dir(auto_uido,"755","/man/man8"); + dir(auto_uido,"755","/doc"); + dir(auto_uido,"755","/boot"); - dir(auto_uida,"755","/alias"); + copy(auto_uido,"755","/boot/","home"); + copy(auto_uido,"755","/boot/","home+df"); + copy(auto_uido,"755","/boot/","proc"); + copy(auto_uido,"755","/boot/","proc+df"); + copy(auto_uido,"755","/boot/","binm1"); + copy(auto_uido,"755","/boot/","binm1+df"); + copy(auto_uido,"755","/boot/","binm2"); + copy(auto_uido,"755","/boot/","binm2+df"); + copy(auto_uido,"755","/boot/","binm3"); + copy(auto_uido,"755","/boot/","binm3+df"); + + copy(auto_uido,"644","/doc/","FAQ"); + copy(auto_uido,"644","/doc/","UPGRADE"); + copy(auto_uido,"644","/doc/","SENDMAIL"); + copy(auto_uido,"644","/doc/","INSTALL"); + copy(auto_uido,"644","/doc/","INSTALL.alias"); + copy(auto_uido,"644","/doc/","INSTALL.boot"); + copy(auto_uido,"644","/doc/","INSTALL.ctl"); + copy(auto_uido,"644","/doc/","INSTALL.ids"); + copy(auto_uido,"644","/doc/","INSTALL.maildir"); + copy(auto_uido,"644","/doc/","INSTALL.mbox"); + copy(auto_uido,"644","/doc/","INSTALL.vsm"); + copy(auto_uido,"644","/doc/","PIC.local2alias"); + copy(auto_uido,"644","/doc/","PIC.local2ext"); + copy(auto_uido,"644","/doc/","PIC.local2local"); + copy(auto_uido,"644","/doc/","PIC.local2rem"); + copy(auto_uido,"644","/doc/","PIC.local2virt"); + copy(auto_uido,"644","/doc/","PIC.nullclient"); + copy(auto_uido,"644","/doc/","PIC.relaybad"); + copy(auto_uido,"644","/doc/","PIC.relaygood"); + copy(auto_uido,"644","/doc/","PIC.rem2local"); + + dir(auto_uida,"2755","/alias"); dir(auto_uidq,"750","/queue"); dir(auto_uidq,"700","/queue/pid"); dir(auto_uidq,"700","/queue/intd"); @@ -115,6 +149,7 @@ void main() copy(auto_uido,"711","/bin/","qmail-send"); copy(auto_uido,"711","/bin/","splogger"); copy(auto_uido,"700","/bin/","qmail-newu"); + copy(auto_uido,"700","/bin/","qmail-newmrh"); copy(auto_uido,"711","/bin/","qmail-pw2u"); copy(auto_uido,"755","/bin/","qmail-inject"); copy(auto_uido,"755","/bin/","predate"); @@ -124,14 +159,15 @@ void main() 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-tcpok"); copy(auto_uido,"755","/bin/","qmail-pop3d"); - copy(auto_uido,"700","/bin/","qmail-popup"); + copy(auto_uido,"711","/bin/","qmail-popup"); + copy(auto_uido,"755","/bin/","qmail-qmqpc"); + copy(auto_uido,"755","/bin/","qmail-qmqpd"); 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"); @@ -170,8 +206,6 @@ void main() 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"); @@ -187,8 +221,6 @@ void main() 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"); @@ -222,6 +254,8 @@ void main() 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-newmrh.8"); + copy(auto_uido,"644","/man/cat8/","qmail-newmrh.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"); @@ -230,12 +264,18 @@ void main() 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-tcpok.8"); + copy(auto_uido,"644","/man/cat8/","qmail-tcpok.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-qmqpc.8"); + copy(auto_uido,"644","/man/cat8/","qmail-qmqpc.0"); + copy(auto_uido,"644","/man/man8/","qmail-qmqpd.8"); + copy(auto_uido,"644","/man/cat8/","qmail-qmqpd.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"); diff --git a/qmail-inject.8 b/qmail-inject.8 @@ -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 diff --git a/qmail-inject.c b/qmail-inject.c @@ -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(); diff --git a/qmail-local.8 b/qmail-local.8 @@ -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 diff --git a/qmail-local.c b/qmail-local.c @@ -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" @@ -28,40 +29,17 @@ #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; diff --git a/qmail-log.5 b/qmail-log.5 @@ -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" diff --git a/qmail-lspawn.8 b/qmail-lspawn.8 @@ -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 @@ -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 @@ -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); +} diff --git a/qmail-pop3d.8 b/qmail-pop3d.8 @@ -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 diff --git a/qmail-pop3d.c b/qmail-pop3d.c @@ -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(); } diff --git a/qmail-popup.c b/qmail-popup.c @@ -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(); } diff --git a/qmail-pw2u.9 b/qmail-pw2u.9 @@ -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), diff --git a/qmail-pw2u.c b/qmail-pw2u.c @@ -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 @@ -0,0 +1,35 @@ +.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 . + +.B qmail-qmqpc +is currently experimental; +use it at your own risk. +It will be fully supported in the next release of +.BR qmail . +.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 @@ -0,0 +1,161 @@ +/* EXPERIMENTAL! Use at your own risk. */ + +#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 @@ -0,0 +1,31 @@ +.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. + +.B qmail-qmqpd +is currently experimental; +use it at your own risk. +It will be fully supported in the next release of +.BR qmail . +.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 @@ -0,0 +1,178 @@ +/* EXPERIMENTAL! Use at your own risk. */ + +#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)"; + + fmt_ulong(strnum,str_len(result)); + + substdio_puts(&ssout,strnum); + substdio_puts(&ssout,":"); + substdio_puts(&ssout,result); + substdio_puts(&ssout,","); + substdio_flush(&ssout); + _exit(0); +} diff --git a/qmail-qmtpd.8 b/qmail-qmtpd.8 @@ -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" diff --git a/qmail-qmtpd.c b/qmail-qmtpd.c @@ -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 */ } } diff --git a/qmail-qstat.sh b/qmail-qstat.sh @@ -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` diff --git a/qmail-queue.8 b/qmail-queue.8 @@ -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) diff --git a/qmail-queue.c b/qmail-queue.c @@ -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); diff --git a/qmail-remote.8 b/qmail-remote.8 @@ -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) diff --git a/qmail-remote.c b/qmail-remote.c @@ -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(); } diff --git a/qmail-send.9 b/qmail-send.9 @@ -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: diff --git a/qmail-send.c b/qmail-send.c @@ -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); } diff --git a/qmail-showctl.c b/qmail-showctl.c @@ -1,3 +1,5 @@ +#include <sys/types.h> +#include <sys/stat.h> #include "substdio.h" #include "subfd.h" #include "exit.h" @@ -8,6 +10,7 @@ #include "stralloc.h" #include "direntry.h" #include "auto_qmail.h" +#include "auto_uids.h" stralloc me = {0}; int meok; @@ -93,7 +96,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 +113,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 +125,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,11 +136,35 @@ 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,auto_qmail); substdio_puts(subfdout,"/control.\n"); + substdio_puts(subfdout,"The uids and gids are "); + 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,", "); + 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 "); substdio_puts(subfdout,auto_qmail); @@ -170,6 +197,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 +210,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 +250,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 +261,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; diff --git a/qmail-smtpd.8 b/qmail-smtpd.8 @@ -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) diff --git a/qmail-smtpd.c b/qmail-smtpd.c @@ -1,6 +1,5 @@ #include "sig.h" #include "readwrite.h" -#include "getln.h" #include "stralloc.h" #include "substdio.h" #include "alloc.h" @@ -14,57 +13,68 @@ #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,333 @@ 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]) { /* partner should go read rfc 821 */ + terminator = ' '; + i = str_chr(arg,':'); + if (!arg[i]) return 0; + } + arg += i + 1; + + /* 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 + 1,addr.len - 2); + 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\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_helo, 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(); } diff --git a/qmail-start.9 b/qmail-start.9 @@ -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 @@ -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 @@ -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); +} diff --git a/qmail-tcpto.8 b/qmail-tcpto.8 @@ -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 @@ -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 @@ -12,7 +12,6 @@ Available commands for the .B .qmail file include .BR qbiff (1), -.BR qlist (1), .BR qreceipt (1), .BR forward (1), and (for advanced users) @@ -51,13 +50,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.02 of .BR qmail . See diff --git 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 @@ -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 diff --git a/qreceipt.c b/qreceipt.c @@ -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 @@ -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 @@ -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 @@ -0,0 +1,7 @@ +#ifndef RCPTHOSTS_H +#define RCPTHOSTS_H + +extern int rcpthosts_init(); +extern int rcpthosts(); + +#endif diff --git a/remoteinfo.c b/remoteinfo.c @@ -12,6 +12,16 @@ #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 @@ -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; -} diff --git a/sendmail.c b/sendmail.c @@ -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); } diff --git a/slurpclose.c b/slurpclose.c @@ -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; } diff --git a/substdio.h b/substdio.h @@ -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 diff --git a/timeoutread.c b/timeoutread.c @@ -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; } diff --git a/timeoutread.h b/timeoutread.h @@ -1,8 +1,6 @@ #ifndef TIMEOUTREAD_H #define TIMEOUTREAD_H -#define TIMEOUTREAD(s,fd) (((s) << 10) | (fd)) - extern int timeoutread(); #endif diff --git a/timeoutwrite.c b/timeoutwrite.c @@ -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; } diff --git a/timeoutwrite.h b/timeoutwrite.h @@ -1,8 +1,6 @@ #ifndef TIMEOUTWRITE_H #define TIMEOUTWRITE_H -#define TIMEOUTWRITE(s,fd) (((s) << 10) | (fd)) - extern int timeoutwrite(); #endif diff --git a/token822.c b/token822.c @@ -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; diff --git a/wait_pid.c b/wait_pid.c @@ -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