Import ezmlm-idx 0.40 idx idx/0.40
authorMark Wooding <mdw@metalzone.distorted.org.uk>
Tue, 14 Feb 2006 14:25:57 +0000 (14:25 +0000)
committerMark Wooding <mdw@metalzone.distorted.org.uk>
Tue, 14 Feb 2006 14:25:57 +0000 (14:25 +0000)
179 files changed:
BIN
CHANGES.idx [new file with mode: 0644]
DOWNGRADE.idx [new file with mode: 0644]
FAQ.idx [new file with mode: 0644]
FILES.idx [new file with mode: 0644]
INSTALL.idx [new file with mode: 0644]
LICENCE.TXT [new file with mode: 0644]
MAN
Makefile
README.idx [new file with mode: 0644]
TARGETS [new file with mode: 0644]
UPGRADE.idx [new file with mode: 0644]
VERSION
author.c [new file with mode: 0644]
auto_cron.h [new file with mode: 0644]
case_diffs.c [new file with mode: 0644]
case_starts.c [new file with mode: 0644]
checktag.c [new symlink]
concatHDR.c [new file with mode: 0644]
conf-cron [new file with mode: 0644]
conf-sqlcc [new symlink]
conf-sqlld [new symlink]
constmap.c
constmap.h
copy.c [new file with mode: 0644]
copy.h [new file with mode: 0644]
date2yyyymm.c [new file with mode: 0644]
dateline.c [new file with mode: 0644]
decodeB.c [new file with mode: 0644]
decodeHDR.c [new file with mode: 0644]
decodeQ.c [new file with mode: 0644]
encodeB.c [new file with mode: 0644]
encodeQ.c [new file with mode: 0644]
env.c [new file with mode: 0644]
error.c
error.h
errtxt.h [new file with mode: 0644]
ezcgi.css [new file with mode: 0644]
ezcgirc [new file with mode: 0644]
ezmlm-accept.1 [new file with mode: 0644]
ezmlm-accept.sh [new file with mode: 0644]
ezmlm-archive.1 [new file with mode: 0644]
ezmlm-archive.c [new file with mode: 0644]
ezmlm-cgi.1 [new file with mode: 0644]
ezmlm-cgi.c [new file with mode: 0644]
ezmlm-check.1 [new file with mode: 0644]
ezmlm-check.sh [new file with mode: 0644]
ezmlm-clean.1 [new file with mode: 0644]
ezmlm-clean.c [new file with mode: 0644]
ezmlm-cron.1 [new file with mode: 0644]
ezmlm-cron.c [new file with mode: 0644]
ezmlm-gate.1 [new file with mode: 0644]
ezmlm-gate.c [new file with mode: 0644]
ezmlm-get.1 [new file with mode: 0644]
ezmlm-get.c [new file with mode: 0644]
ezmlm-glconf.1 [new file with mode: 0644]
ezmlm-glconf.sh [new file with mode: 0644]
ezmlm-idx.1 [new file with mode: 0644]
ezmlm-idx.c [new file with mode: 0644]
ezmlm-issubn.1 [new file with mode: 0644]
ezmlm-issubn.c [new file with mode: 0644]
ezmlm-limit.1 [new file with mode: 0644]
ezmlm-limit.c [new file with mode: 0644]
ezmlm-list.1
ezmlm-list.c
ezmlm-make.1
ezmlm-make.c
ezmlm-manage.1
ezmlm-manage.c
ezmlm-mktab [new symlink]
ezmlm-mktab.1 [new file with mode: 0644]
ezmlm-moderate.1 [new file with mode: 0644]
ezmlm-moderate.c [new file with mode: 0644]
ezmlm-receipt.1 [new file with mode: 0644]
ezmlm-receipt.c [new file with mode: 0644]
ezmlm-reject.1
ezmlm-reject.c
ezmlm-request.1 [new file with mode: 0644]
ezmlm-request.c [new file with mode: 0644]
ezmlm-return.1
ezmlm-return.c
ezmlm-send.1
ezmlm-send.c
ezmlm-split.1 [new file with mode: 0644]
ezmlm-split.c [new file with mode: 0644]
ezmlm-store.1 [new file with mode: 0644]
ezmlm-store.c [new file with mode: 0644]
ezmlm-sub.1
ezmlm-sub.c
ezmlm-test.1 [new file with mode: 0644]
ezmlm-test.sh [new file with mode: 0644]
ezmlm-tstdig.1 [new file with mode: 0644]
ezmlm-tstdig.c [new file with mode: 0644]
ezmlm-unsub.1
ezmlm-unsub.c
ezmlm-warn.1
ezmlm-warn.c
ezmlm-weed.1
ezmlm-weed.c
ezmlm.5
ezmlmglrc [new file with mode: 0644]
ezmlmglrc.5 [new file with mode: 0644]
ezmlmrc.5 [new file with mode: 0644]
ezmlmrc.ch_GB [new file with mode: 0644]
ezmlmrc.cs [new file with mode: 0644]
ezmlmrc.da [new file with mode: 0644]
ezmlmrc.de [new file with mode: 0644]
ezmlmrc.en_US [new file with mode: 0644]
ezmlmrc.es [new file with mode: 0644]
ezmlmrc.fr [new file with mode: 0644]
ezmlmrc.id [new file with mode: 0644]
ezmlmrc.it [new file with mode: 0644]
ezmlmrc.jp [new file with mode: 0644]
ezmlmrc.pl [new file with mode: 0644]
ezmlmrc.pt [new file with mode: 0644]
ezmlmrc.pt_BR [new file with mode: 0644]
ezmlmrc.ru [new file with mode: 0644]
ezmlmrc.sv [new file with mode: 0644]
ezmlmsubrc [new file with mode: 0644]
ezmlmsubrc.5 [new file with mode: 0644]
idx.h [new file with mode: 0644]
idx.patch [new file with mode: 0644]
idxthread.c [new file with mode: 0644]
idxthread.h [new file with mode: 0644]
issub.c [changed from file to symlink]
log.c
logmsg.c [new symlink]
makehash.c [new file with mode: 0644]
makehash.h [new file with mode: 0644]
mime.h [new file with mode: 0644]
opensql.c [new symlink]
putsubs.c [new symlink]
qmail-qmqpc.tar.gz [new file with mode: 0644]
qmail-verh.tar.gz [new file with mode: 0644]
qmail.c
qmail.h
searchlog.c [new symlink]
sub_mysql/README [new file with mode: 0644]
sub_mysql/checktag.c [new file with mode: 0644]
sub_mysql/conf-sqlcc [new file with mode: 0644]
sub_mysql/conf-sqlld [new file with mode: 0644]
sub_mysql/ezmlm-mktab [new file with mode: 0755]
sub_mysql/issub.c [new file with mode: 0644]
sub_mysql/logmsg.c [new file with mode: 0644]
sub_mysql/opensql.c [new file with mode: 0644]
sub_mysql/putsubs.c [new file with mode: 0644]
sub_mysql/searchlog.c [new file with mode: 0644]
sub_mysql/subscribe.c [new file with mode: 0644]
sub_mysql/tagmsg.c [new file with mode: 0644]
sub_mysql/to40x [new file with mode: 0755]
sub_pgsql/README [new file with mode: 0644]
sub_pgsql/checktag.c [new file with mode: 0644]
sub_pgsql/conf-sqlcc [new file with mode: 0644]
sub_pgsql/conf-sqlld [new file with mode: 0644]
sub_pgsql/ezmlm-mktab [new file with mode: 0755]
sub_pgsql/issub.c [new file with mode: 0644]
sub_pgsql/logmsg.c [new file with mode: 0644]
sub_pgsql/opensql.c [new file with mode: 0644]
sub_pgsql/putsubs.c [new file with mode: 0644]
sub_pgsql/searchlog.c [new file with mode: 0644]
sub_pgsql/subscribe.c [new file with mode: 0644]
sub_pgsql/tagmsg.c [new file with mode: 0644]
sub_std/README [new file with mode: 0644]
sub_std/checktag.c [new file with mode: 0644]
sub_std/conf-sqlcc [new file with mode: 0644]
sub_std/conf-sqlld [new file with mode: 0644]
sub_std/ezmlm-mktab [new file with mode: 0755]
sub_std/issub.c [new file with mode: 0644]
sub_std/logmsg.c [new file with mode: 0644]
sub_std/opensql.c [new file with mode: 0644]
sub_std/putsubs.c [new file with mode: 0644]
sub_std/searchlog.c [new file with mode: 0644]
sub_std/subscribe.c [new file with mode: 0644]
sub_std/tagmsg.c [new file with mode: 0644]
subscribe.c [changed from file to symlink]
subscribe.h
tagmsg.c [new symlink]
unfoldHDR.c [new file with mode: 0644]
yyyymm.h [new file with mode: 0644]

diff --git a/BIN b/BIN
index 76f0320..1c9db2b 100644 (file)
--- a/BIN
+++ b/BIN
@@ -1,11 +1,31 @@
 d:::755:::
 d:::755:::
+c:::755:/:ezmlm-accept:
+c:::755:/:ezmlm-archive:
+c:::755:/:ezmlm-issubn:
+c:::755:/:ezmlm-glconf:
 c:::755:/:ezmlm-make:
 c:::755:/:ezmlm-make:
+c:::755:/:ezmlm-mktab:
 c:::755:/:ezmlm-manage:
 c:::755:/:ezmlm-send:
 c:::755:/:ezmlm-manage:
 c:::755:/:ezmlm-send:
+c:::755:/:ezmlm-request:
 c:::755:/:ezmlm-reject:
 c:::755:/:ezmlm-return:
 c:::755:/:ezmlm-warn:
 c:::755:/:ezmlm-weed:
 c:::755:/:ezmlm-list:
 c:::755:/:ezmlm-reject:
 c:::755:/:ezmlm-return:
 c:::755:/:ezmlm-warn:
 c:::755:/:ezmlm-weed:
 c:::755:/:ezmlm-list:
+c:::755:/:ezmlm-clean:
+c:::755:/:ezmlm-cron:
+c:::755:/:ezmlm-limit:
+c:::755:/:ezmlm-store:
+c:::755:/:ezmlm-split:
+c:::755:/:ezmlm-moderate:
 c:::755:/:ezmlm-sub:
 c:::755:/:ezmlm-unsub:
 c:::755:/:ezmlm-sub:
 c:::755:/:ezmlm-unsub:
+c:::644:/:ezmlmrc:
+c:::644:/:ezmlmglrc:
+c:::644:/:ezmlmsubrc:
+c:::755:/:ezmlm-idx:
+c:::755:/:ezmlm-check:
+c:::755:/:ezmlm-gate:
+c:::755:/:ezmlm-tstdig:
+c:::755:/:ezmlm-get:
diff --git a/CHANGES.idx b/CHANGES.idx
new file mode 100644 (file)
index 0000000..49a4f8a
--- /dev/null
@@ -0,0 +1,842 @@
+$Id: CHANGES.idx,v 1.66 1999/12/24 04:33:03 lindberg Exp $
+$Name: ezmlm-idx-040 $
+
+BUGS:  -ezmlm-idx does not implement a full rfc822 parser. Comments can be
+        inserted to defeat the MIME parsing mechanism, such as:
+        Content-Type: (comment) test/plain
+        This type of comment, while legal, does not occur in normal messages.
+        Guiding info past ezmlm-idx MIME parsing is easier done by enclosing
+        a message within a message. The mechanism isn't intended as a
+        "secure" way of preventing e.g. "application/ms-tnef" from being
+        disseminated.
+        If you think this is a problem, E-mail lindberg@id.wustl.edu.
+        Mimeremove/reject work only at the outer MIME layer.
+       -ezmlm-request requires addresses to be user@host. While rfc822
+        compliant, addresses like ``"the man" @ host'' are not accepted.
+       -ezmlm-cgi doesn't deal optimally with holes in the archive.
+       -ezmlm-cgi seems not to work with Chinese. The problem has been to
+        find someone willing/able to participate in debugging.
+
+TODO:
+-ezmlm-cgi to run directly under tcpserver.
+
+Acknowledgements, some are missing. Please write lindberg@id.wustl.edu
+if you're missing.
+
+Some ezmlmrc are not updated and won't work right:
+cn_GB,cs,pl,ru,da,pt_BR,pt
+
+If you fix them, please send them to lindberg@id.wustl.edu for inclusion
+in the next version.
+
+ezmlm-idx-0.40, 19991220
+========================
+-Fixed bug in sub_mysql/issub.c that caused return of undef pointer for
+ non-subs. Security problem for sender checks, but not for moderation. Of
+ course only mysql version affected.
+-Updated ezmlmrc translations. Thanks all who worked on this.
+-added ezmlmrc.es. Thanks Vicent Mas/Francesc Alted/Sonia Lorente/Cyndy DePoy.
+-added ezmlmrc.cn_GB. Thanks HG.
+-ezmlm-weed: Groupwise garbage filter added. Thanks, SA.
+-mysql: include files now don't have a dir. This is so that one can have
+ them in e.g. /usr/include. conf-sqlcc adjusted.
+-Removed utils/. Not updated - add when done.
+-Full PostgresSQL support. Thanks, MS.
+-Corrected ordering of searchlog output for MySQL version to match default.
+ Thanks, MS.
+-ezmlm-moderate/store: Fork /bin/sh ... instead of sh for people with unset
+ PATH. Thanks, TM.
+-ezmlm-manage: rfc2369 headers added where possible also to admin
+ messages. Main finesse is that the WELCOME message has a custom
+ List-Unsubscribe header. -U/-S logic deconvoluted. -nN added.
+-ezmlm-store: -B to send only header of message to moderate, rather than
+ the entire message. Used for send-only list with very large posts.
+-ezmlm-reject: -b to reject messages with body or subject starting with
+ ``subscribe'' or ``unsubscribe''.
+-support for List-ID (draft). Added to all list messages if DIR/listid is
+ present. The first line of that file is added after "List-ID: ".
+-ezmlmrc: Added List-Subscribe header. Rewrite some texts, move some info
+ from bottom to help. Add ezmlm-archive (-i), add some switches to make
+ announcement lists easier.
+-ezmlm-make: Modifed to make -I default since -i now controls ezmlm-archive
+ with all lists configured with ezmlm-get. Also, ezmlm-make will not overwrite
+ files tagged with #E in ezmlmrc when in edit mode (-+ or -e). This preserves
+ manual customization. The behavior can be overridden with -++ or -ee to
+ reset the list texts (old behavior). Added version check for ezmlmrc Tx, SA.
+-ezmlm-archive and ezmlm-cgi added: Very easy to set up WWW access to list
+ archive. Support for various charsets incl iso-2022-*. For Russian,
+ one would need to do substitutions when making entries in archive/n/index.
+ This is not supported yet, so summary view entries may be incorrect if
+ the messages use Russian text in a charset different from the one the list
+ uses. Probably doesn't work for Chinese - lack of willing/able testers.
+-qmail-qmqp support via idx.h and DIR/qmqpservers. If your bandwidth is
+ limited, look at this (see ezmlm-send(1)/ezmlm-get(1)/ezmlm(5)). If you
+ have large lists, sublist them locally and specify different QMQP servers
+ for each sublist via DIR/qmqpservers. Added qmail-qmqpc.tar.gz patch to
+ allow specifying QMQP server on command line. With this, DIR/qmqpservers can
+ be used to specify different servers for different lists for busy servers.
+-ezmlm-gate: added -q file. Each line in "file" is processed as per
+ dot-qmail(5). 111 => temp_err, 99 => post, 100 => moderate, 0 => check sub.
+ Any other exit code will result in a bounce.
+ NOTE: This changes the behavior of ezmlm-gate used with only one DIR
+ argument (not used in any std listsetup for previous versions). Before,
+ this tested for subscriber status, now messages will
+ be moderated. This use is not set up by any ezmlm-make option and should
+ be _extremely_ rate. To obtain the old behavior, simply specify the
+ list directory twice.
+-Made conf-sqlcc and conf-sqlld to support both phases of the build. Adjusted
+ mysql includes to not assume they're in a "mysql" subdir.
+
+ezmlm-idx-0.324, 19990905 (PostgresSQL)
+=======================================
+-Minor typo in ezmlmrc.fr fixed.
+-Added [partial] PostgresSQL interface by Magnus Stalaker. See INSTALL.idx.
+-Added ezmlm-store Cc: docs mistakenly missed in 0.323.
+-Fixed problem with "it/itall" target (Thanks MW).
+
+
+ezmlm-idx-0.323, 19990815 (bug fix)
+===================================
+-ezmlm-store: Cc: list-accept-subscribe remote admin conf added to mod
+ requests. For lists using ezmlm-gate, this allows adding poster as allowed
+ alias. Thanks RVI for suggesting.
+-Added qmail-verh.tar.gz (0.03). This is the 0.02 qmail patch and a patch
+ to change ezmlmrc to take advantage of it. See docs inside.
+-conf-sqlcc/conf-sqlld instead of conf-sql to allow include file additions
+ (conf-cc) and libraries (conf-ld) for RDBMS interfaces.
+-Added ezmlmrc.id and ezmlmrc.it. Thanks APN and RDC.
+-ezmlm-manage: Mime boundary was missing for subscribe notifications for
+ moderated lists using QP/base64 encoding. Thanks TF.
+-ezmlm-get: Logic to prevent digest triggering from list-@host.
+-ezmlm-get: Digest parts have file names list_msgnum.txt instead of
+ list.msgnum to work around a MS Outlook bug. Thanks, MH.
+-ezmlm-request: Support for multipart MIME when used as a majordomo emulator.
+ Thanks, Johannes Ehrfeldt for reporting the bug.
+-ezmlm-send: trailer was added to mutipart/non-alternative. Problems with
+ multipart/signed. Now, trailer for multipart is added only to mixed,
+ digest, and parallel. Thanks BPF.
+-ezmlm-reject.1: typo.
+-ezmlm-test.sh multiple minor changes to work on more platforms. Still, if
+ it doesn't work, the problem is most likely here, and not in ezmlm(idx)
+ itself. Thanks RM DM and others.
+-ezmlm-moderate: added missing newline at beginning of MIME reject message.
+ Thanks, XXX.
+-idx.h fixed ALT_XX alternative command names which erroneously started '-'.
+ Looks bad, but was of no consequence.
+
+
+ezmlm-idx-0.322, 19990505 (bug fix)
+===================================
+-ezmlmrc.*: Added x-confirm-reading-to and x-pmrqc. Thanks JK.
+-ezmlmrc.ru: Added Russian version contributed by RVI. Thanks.
+-ezmlmrc: Czech version of ezmlmrc is ezmlmrc.cz. Should be ezmlmrc.cs. Fixed.
+-searchlog.c: Made the MySQL version also match in address field to make
+ the records returned the same as for std version.
+-ezmlm-store: -allow-subscribe confirm address in Cc: header to make it easier
+ for the moderator to add the poster to the allow database. (Thanks, RVI.)
+-ezmlm-manage: -query from remote admin for subscriber failed due to use of
+ static storage within issub(). Fixed.
+-ezmlm-manage: Made remote admin unsub failure return error. For sub it's
+ important to be silent for multi-moderator setups, but since unsub is never
+ moderated, it's ok to return negative feedback, since it may be needed by
+ remote admins. As a consequence it was trivial to add -Q[Q] not quiet to
+ provide [un]subscribe feedback to the owner.
+-ezmlm-send/reject: "boundary" in Content-type can be delimited by ';'.
+ Without, some messages could be erroneously rejected when using mimeremove.
+ New error text added to errtxt.h.
+
+
+ezmlm-idx-0.321, 19990322 (bug fix)
+===================================
+-added ezmlm-limit to limit list traffic. As this is a bug fix release,
+ ezmlm-limit should be considered experimental and is not built/installed
+ by default. (Thanks, TM for suggesting.)
+-subscribe.c: in some cases a ``T'' was incorrectly added before the address
+ in the DIR/Log subscription log. Corrected (Thanks, PH.).
+-ezmlm-test: reordered some tests to avoid timing problems on some
+ platforms. Tested hostname output since it may return a non-FQDN host name.
+ Added tests for most of the fixed bugs.
+-ezmlm-tstdig: improved DEFAULT logic. Failed with existing incorrect inlocal
+ in virtual domains.
+-ezmlm-manage bug: deny access control fixed.
+-ezmlm-request/ezmlm-tstdig: qmail>=1.02 doesn't set DEFAULT when there is
+ nothing matching. Unable to detect qmail version here. Changed logic to
+ always be correct with qmail>=1.02 and virtually always for earlier versions.
+ Missing inlocal is taken as meaning qmail>=1.02.
+-ezmlm-request: mdomo emulator: Corrected address listed for WHICH.
+-ezmlm-request: Silent exit on bounces (NULL sender). Fake SENDER spam to the
+ majordomo address otherwise causes double bounces to postmaster who has
+ better things to do.
+-ezmlmrc: corrected missing ezmlm-return in bouncer for normal (^6W) lists.
+ (Thanks Matt McGlynn.)
+-opensql.c: psql needs to be destroyed for ezmlm-reqest WHICH which may open
+ connections to several servers.
+-searchlog.c: made inbuf/ssin static. Was incorrect and generated linker
+ warning on some systems, but had no functional consequences. Thanks, SOH.
+-ezmlm-test: converted "export ENVIRON=value" to "ENVIRON=value; export ENVIRON"
+ to work with Solaris sh. Also, moved final ezmlm-warn section to the end
+ to avoid timing issue on some systems. "ps" test for qmail made non-fatal,
+ as differing options on different ps make it more likely that ps use is
+ the problem than that qmail is not running. (Thanks, SOH.)
+
+
+ezmlm-idx-0.32, 19990222
+========================
+-updated ezmlm-test. It tests most functions, and for important new features
+ or bugs discovered we'll add new tests in future. Thanks ME for patient
+ testing, suggestions, and "de-bashing".
+-added a rfc2369 headers for list-help, list-post, and list-unsubscribe.
+ It takes little space, and may promote support in MUAs.
+-ezmlm-get: list-get.9999999_x now always returns at least HISTGET messages
+ (default 30) provided that "9999999" is larger that the latest message number.
+ This allows embedding of an address for new subscribers to get at least what
+ has transpired since the latest digest and usually 30 messages before that,
+ to quickly see what's going on.
+-ezmlm-get: list-get for non-digested lists now returns the latest HISTGET
+ (default 30) messages instead of the latest message. To get the latest message,
+ mail list-get-9999999, where "9999999" is larger than the latest message
+ number.
+-Added ezmlm-manage/get -B switch to suppress text/bottom + request addition to
+ ezmlm-manage messages (except of course -help).
+-ezmlm-send uses copy() for trailer and headeradd. <#h#>, <#l#>, and <#n#>
+ in these texts are substituted with outhost, outlocal, and message number,
+ respectively. Now you can add ``To receive this thread, mail
+ <#l#>-get.<#n#>@<#h#>'' to the trailer. Removed dir/sequence feature, since
+ this can now be done with headeradd. copy() modified to suppress blank
+ lines when copying headers. extern decl in copy.h fixed. A consequence
+ is that headeradd isn't added to the archive copy which is good. <#n#>
+ for ezmlm-get is the latest message processed, except for the digest, where
+ it is the first message in the digest (which is also the digest msg #).
+-Added ezmlm-split (previously separate). Modified to use the same split
+ mechanisms as the SQL routines. -D switch to support easier reorganisation,
+ with extensive docs in man page. Interconversion between ezmlm-split and SQL
+ use is now relatively easy.
+-Reorganized files. The subscriber db sources are now in sub_std/ for the
+ standard ezmlm db, sub_mysql/ for the mysql version. Normally, there are
+ symlinks to the std version. ``make mysql'' changes the symlinks to sub_mysql
+ and ``make std'' can be used to set them back.
+-Replaced ezmlm-glmake with ``ezmlm-make -Cezmlmglrc''. See ezmlmglrc.5.
+-Added status.pl for status monitoring of ``list trees'' via httpd. In utils/.
+-Added feedback logging support with ezmlm-receipt and ezmlm-make -w. ezmlm-send
+ and ezmlm-get for the SQL version log info to the db.
+-Added support for setting up a minimal (SQL-enabled) sublist:
+ ezmlm-make -Cezmlmsubrc. See ezmlmsubrc.5.
+-Added ezmlm-make -w to remove ezmlm-warn invocation and if used with -6 to
+ configure ezmlm-receipt in place of ezmlm-return. Used for main list in
+ SQL-enabled list clusters for feedback and bounce logging.
+-Added MySQL support. ezmlm-make -6. This is a _major_ change and makes it
+ trivial to do sublisting and dynamically redistribute load. see ezmlm.5.
+-Modified ezmlm-return to add -dD switches. Previous design decision to have
+ ezmlm-return autodetect digest vs normal bounces cause problems when
+ sublisting a digest list. -dD force non-digest vs digest function and we'll
+ set uyp new lists with that, but keep autodetection for compatibility with
+ existing lists. ezmlmrc files modified appropriately. German version
+ updated and improved by Frank Tegtmeyer. Thanks!
+-Modified ezmlm-warn/return bounce handling. DIR/bounce now has a ``h''
+ subdir, further subdivided a-p for storage of h... files, where the first
+ character of the hash is used for the subdir, and a ``d'' subdir, containing
+ subdirs, each holding bounce (d... files) for a 10,000 s interval. This way,
+ only ``ripe'' bounce files are processed by ezmlm-warn. Also, ``lastd'' to
+ prevent unnecessary reparsing of bounces and ``lasth'' to keep track for
+ ``h'' subdir cleaning of remaining files older than 3x time out.
+-Modified all programs to use DEFAULT if available. With qmail>=1.02, this
+ allows one to ignore inhost/inlocal so that special adjustment for virtual
+ domain lists is no longer required. Works the old way with qmail<1.02.
+-DIR/extra and DIR/blacklist for extra allowed SENDERs and SENDER blacklisting
+ have been renamed DIR/allow and DIR/deny. This is used sparingly and the old
+ nomenclature was confusing. ``mkdir DIR/allow; mv DIR/extra/* DIR/allow''
+ and the corresponding move for DIR/deny will take care of it.
+-Extended the remote admin -log command. Now, -log.xxx will return only
+ Log lines matching 'xxx'. '.' matches '.' and '_' matches any character.
+-The ``From:'' line of subscribers confirmation message will be logged to
+ ``Log''. This allows the administrator to use the Log to by name locate the
+ subscription address of a user.
+
+
+ezmlm-idx-0.316, 19990815 (bug fixes only)
+==========================================
+-Migrated back fixes for 0.322 -> 0.323 that are applicable to 0.31x:
+-ezmlm-get: Made filename extension constant for digest parts to work around
+ Outlook bug.
+-ezmlm-manage: Mime boundary added for mod-sub-ok message when QP/base64 is
+ used.
+-ezmlm-manage.1: Typo.
+-ezmlm-moderate: Missing newline for non-MIME reject message.
+-ezmlm-request: Support by global interface of multipart/alternative messages.
+-ezmlm-send: Trailer only for some types of multipart messages.
+-ezmlm-reject.1: Typo.
+
+
+ezmlm-idx-0.315, 19990505 (bug fixes only)
+==========================================
+-Bug fixes fed back from up to 0.322.
+-ezmlm-send/reject: "boundary" in Content-type can be delimited by ';'.
+ Without, some messages could be erroneously rejected when using mimeremove.
+ New error text added to errtxt.h.
+-ezmlm-manage: -query from remote admin for subscriber failed due to use of
+ static storage within issub(). Fixed.
+-ezmlm-manage bug: deny access control fixed.
+
+
+ezmlm-idx-0.314, 19990216 (bug fixes only)
+==========================================
+-Added ezmlm-test, a script that tests [most] ezmlm + idx program functions.
+-added ezmlmrc.cz (Thanks, Jan Kasprzak).
+-ezmlm-make -e failed if DIR/config didn't exist. Fixed. (Thanks, SOH.)
+-ezmlm-make man page bug for virtual domain (Thanks, XX).
+-ezmlm-get segfaulted when run from the command line with LOCAL undefined.
+ Fixed. (Thanks, ME.)
+
+ezmlm-idx-0.313, 19981121 (bug fixes almost only)
+=================================================
+-ezmlm-get returns 0 for success in editor and command line use, rather than
+ 99. No impact on current lists, but makes more sense.
+-ezmlm-warn tests >= for timeout rather than >. No impact other than easier
+ use with future test script.
+-ezmlm-manage -get function was broken - fixed. Needed for backwards compat
+ with ezmlm-0.53. (Thanks, KS.)
+-Reorganized INSTALL.idx, UPGRADE.idx, README.idx and introduced FILES.idx
+ to simplify. Made corrections to FAQ.idx, but no additions.
+-ezmlm-send no longer adds trailer to multipart/mixed messages. Also, multipart
+ messages consisting of only "mimeremove" parts will be bounced. (Thanks, BE.)
+ The trailer is suppressed for base64-encoded messages. In both cases,
+ trailer addition might corrupt the message. Default charset is added if none
+ specified (was left empty).
+-The US version of ezmlmrc is now ``ezmlmrc.en_US'' and ``make'' by default
+ copies it to ezmlmrc. Added support to Makefile and docs to copy in other
+ versions via e.g. ``make jp''. Target ezmlmrc is there to not overwrite with
+ ezmlmrc.en_US on ``make setup''.
+-Changed ezmlmrc so that headeradd/headerremove/sub-ok/mod-sub are not rewritten
+ when editing lists. (Thanks, GS.)
+-In ezmlm-idx and ezmlm-send, made dirs without trailing slash (mkdir with
+ it bombs on Ultrix). (Thanks, BW.)
+-added check for NULL sender is zapnosub() in ezmlm-get. Fixed NULL pointer
+ use when the command is -dig- and no digest code was given on the command
+ line.
+-added 'x' to FORMATS in idx.h. (Thanks, MMcL.)
+-ezmlm-reject changed to honor subject continuation lines. Eudora likes to
+ break right after "Subject:" which caused rejection for empty subject.
+ (Thanks, SOH.) Same for To:. Also deals with quoted content types. Error
+ message now always states the offending MIME type.
+-Added "(null)", "(none)", and "(no subject)" to rejected subjects. What are
+ these MUA authors thinking??
+-ezmlm-reject bug fixed to reject commands in subjects. (Thanks, JH.)
+-ezmlm-request bug fixed to allow correct processing of complete command
+ addresses in the subject, even for virtual domains. (Thanks, EC.)
+-ezmlmrc.de corrected (Thanks, FT).
+-Made local check in ezmlm-tstdig case-insensitive (Thanks, Rick Myers).
+-Fixed ezmlm-glconf to work with 'sh', not only 'bash' (missing ';' before '}')
+ (Thanks, MS).
+-ezmlm-manage: text/bottom added also when moderated subscription is
+ completed (Thanks, SOH). Added -log command to ezmlm-manage. Allows remote
+ admins to retrieve Log if -l switch is set. Added -log into to mod-help via
+ ezmlmrc.
+-Made character defines sun4 cc compliant in decode{Q|B}.c and unfoldHDR.c.
+-Added support for "Sv:" and "Rv:" reply indicators (Nordic, Spanish).
+-Improved/expanded ezmlm-check.
+-Added -+ switch to ezmlm-make. Makes letter switches sticky (not -cC).
+ <#F#> is all letter switches, not only the ones set. (Thanks, SOH). Also,
+ added virtual domain info to ezmlm-make.1.
+
+ezmlm-idx-0.312, 19980805 (bug fixes only and support scripts added)
+====================================================================
+-Fixed declaration of char16table[] in decodeQ.c to get clean mips64 compile
+ (Thanks, MF).
+-Fixed ezmlm-request so that <#l#> and <#h#> are substituted correctly.
+-Added ezmlm-glmake to create a global list setup. Left ezdomo.tar.gz since that
+ is what's documented in the FAQ.
+-Fixed inconsistencies/errors in the ezdomo.tar.gz example files (Thanks, PN).
+-Changed ezmlm-return.c to understand qmail preVERP error messages even if
+ qmail is patched to use MIME error messages.
+-Added ezmlm-glconf and man page to the package. The program creates a config
+ file for the "majordomo-style" interface from a user's existing lists.
+-Updated ezmlmrc and translations to not overwrite text/faq|info when editing
+ the list and add a note on -faq/-info to text/bottom and on -list/-edit
+ to text/mod-help. Thanks to the "usual suspects" for the translations!
+-Corrected small bug in ezmlmrc.de and ezmlmrc.da.
+-Corrected small bug in ezmlm-check -s switch handling (Thanks, DS).
+-Fixed bug in unfoldHDR.c affecting handling of subject prefixes without
+ message number (Thanks, LL).
+
+ezmlm-idx-0.311, 19980701 (bug fix only)
+========================================
+-Restored the mistakenly amputated ezmlmrc (English only, others were ok).
+-Fixed ezmlm-gate to tolerate unset $SENDER (Thanks, AP).
+
+ezmlm-idx-0.31, 19980630
+========================
+-Added ezmlm-manage -m switch for moderated unsubscription, pre request.
+ (Thanks, FT).
+-made cookie for accept/reject the same: ezmlm-moderate/ezmlm-store.
+-ezmlmrc.da (Thanks, TF). Other ezmlmrc updated (Thanks: see README.idx).
+-copy.c modified to allow NUL, multiple tags per line, and <#h#> => outhost.
+ (Thanks, TM).
+-ezmlm-manage sends replies to "-help" from "list-return-@". This will break
+ all autoresponder loops for admin messages after 1 round. Otherwise,
+ ezmlm-warn and a broken responder can start an endless manage<->responder
+ exchange. (Thanks, MM.)
+-Simplified tosubs(). Slightly less efficient with qmail, but avoids a lot
+ of problems.
+-Added umask(022) to ezmlm-unsub.c and ezmlm-sub.c, in case they 
+ are the ones to create dir/lock.
+-ezmlm-moderate and ezmlm-gate changed to pass on switches for exec'd
+ programs. ezmlm-moderate sets sender for ezmlm-send so that -C switch
+ works also for moderated lists.
+-ezmlm-accept now autoconfigured with ezmlm bin path and installed.
+-ezmlm-manage allows remote access to the ``extra'' db (-allow-subscribe)
+ with same restrictions as for the main list. Access to the ``blacklist''
+ db for remote admins only (-deny-subscribe).
+-ezmlmrc changed to skip ezmlm-reject in editor of sublists.
+-ezmlm-reject now rejects messages that do not contain the list
+ address in To:/Cc: (Thanks, DJB). ezmlmrc modified, since it requires
+ the ezmlm-reject line to have the list dir on the command line. Not full
+ rfc822 parser (see BUGS in ezmlm-reject.1!).
+-made missing file in copy.c a permanent error. This way, it's discovered
+ sooner, as the list owner may not have access to maillog.
+-docs updates, including adding terminal '/' to directories to make them
+ clearly distinct from files.
+-Safer storage of return-path by ezmlm-store.
+-ezmlm-send now adds a "Return-Path:" header to the archive copy. This way,
+ listowners without maillog access can get all the info (together with
+ "received:" and "delivered-to: lines).
+-ezmlm-send -R switch to remove "Received:" headers that cause bounces to users
+ (due to too low sendmail hopcount) that can subscribe and are reached by
+ probes just fine. "received:" headers still go to the archive (Thanks, TM).
+-Fixed minor bug in "reply-indicator" trimming (unfoldHDR.c).
+-Make default behavior of -get command to send the messages that have arrived
+ since the last digest (up to MAXGET) if there has ever been a digest (only
+ last message otherwise).
+-"prefix" number substitution changed to LAST '#'. Support for rfc2047 encoded
+ prefix. With iso-2022-* this will work only if characters after '#' are
+ ascii only, due to the removal of redundant ESC sequences from subjects before
+ comparison, and the need for any line to end in ascii. Improved robustness
+ of unfoldHDR.c (could be crashed with some illegal encoded words).
+-Make reject messages come From: list-owner@listhost in ezmlm-moderate. A
+ "Reply-To: address" is added if "-t address" is on the command
+  line (Thanks, YG).
+-ezmlm-get digesting now orders headers only for rfc1153 (mandated), otherwise
+ displays them as they come. The default headers included are the same, but
+ this can be overridden with dir/digheaders containing a list of the headers
+ to include.
+-ezmlm-request takes the first line starting with a letter and interprets it
+ as a command, if the subject is empty or does not start with a letter.
+ Only one line is interpreted.
+-ezmlm-request if used with "-f config" interprets "config" as a config file
+ of lists and list info. When used with this switch, it ignores the subject and
+ expects a command on the first body line. This is to service e.g. the
+ majordomo@host address. See man page.
+-ezmlm-request understands a number of command synonyms to make it easier for
+ users familiar to other MLMs. These are just translated into regular ezmlm
+ commands for use with the list.
+-ezmlm-manage services -faq, -info, and -query commands (see man page). Stubs
+for faq/info added to ezmlmrc and to edit-list via ezmlmrc.
+-ezmlm-check fixes for grep not understanding '-q' and a ezmlm-check -S switch
+ to avoid subscriber listing (Thanks, TEE).
+
+ezmlm-idx-0.302, 19980617 (bug fixes only)
+==========================================
+-Removed args from copy_insertsubject() call in ezmlm-send.c
+-made ezmlm-make enforce absolute "dot".
+-Fixed MIME newline bug in ezmlm-moderate/store/clean. (Thanks, JS).
+-Fixed missing arg in postmsg() call from previous fix (Thanks, MF).
+
+ezmlm-idx-0.301, 19980508 (bug fixes only)
+==========================================
+-Digest format is multipart/digest again. The new format MIXED/'x' is
+ identical, except that it is multipart/mixed. The former works well for
+ most MUA. The latter is better for Pine when ezmlm texts are content-
+ transfer-encoded.
+-RFC1153 format ignores content-transfer-encoding. This works fine with
+ us-ascii. For non-us-ascii it works if the mail path is 8-bit clean. RFC1153
+ is really a us-ascii format, since the messages are dependent on the
+ encoding of the main message. This way is as good as it can get.
+-Added many content-types to mimeremove in ezmlmrc (Thanks, SP).
+-Removed most of the -x stuff in ezmlmrc. Now, -x only adds MIME content-type
+ stripping (extensive) and limits message body size to 2-40000 bytes. If you
+ want "Reply-To:" munging, edit ezmlmrc. The "mailto:" stuff was bad, and 
+ the references to list-owner@host for intractable problems are now standard.
+-Changed ezmlmrc extensions to iso 639: SV - Swedish.
+-Added ezmlmrc files for DE, PL (Thanks, FT, SP).
+-Fixed ezmlm-get: -index reply lacked MIME end boundary (Thanks, KI).
+-Fixed bug in ezmlm-get: outformat error when using digest trigger messages
+ in dir/editor. (Thanks YG).
+-Fixed bug in ezmlm-clean: cp_setlocal wasn't called.
+-Improved ezmlmrc files so that digest links and dirs are not created for
+ on-digested lists. Decreases number of .qmail files.
+-Fixed bug in ezmlm-get: Headers from trigger message are no longer copied
+ to digest (but are still copied to -index/-get/-thread reply). (Thanks STH.)
+-Fixed ezmlm-0.53 bug in ezmlm-return. The "d..." file was the same for all
+ addresses of a pre-VERP bounce, resulting in only the first one being
+ processed correctly (sent to DJB).
+-Changed ezmlm-get to include dir/headeradd headers for digest. (Thanks PH.)
+-Changed ezmlm-get to send digest "To: list@list" from "list-digest@host".
+ This way, the list address is one of the "reply-to-all" addresses, just
+ as for list messages. (Thanks PH.)
+-Corrected ezmlmrc: in some places "d" was used for "n" switch resuling in
+ missing dir/text files for editing if editing was enabled and digest
+ were not. (Thanks JS.)
+-Corrected ezmlmrc/se/jp to add terminal ';' to list in ezmlm-issubn
+ lines. Caused trouble with strict /bin/sh as on FreeBSD. (Thanks STH.)
+-Corrected ezmlm-make man page to show that "digestcode" is optional.
+
+
+ezmlm-idx-0.30, 19980325
+========================
+-Fixed bug in continuation line handling for digest. In some circumstances,
+ continuations ended up with the wrong header. (Thanks SA).
+-Changed digest format to multipart/mixed as pine has trouble with an
+ encoded text/plain part first in multipart/digest (although this is
+ rfc2046-ok). (Thanks SA).
+-Updated FAQ, *.idx, and man pages for new functionality.
+-Changed subdb.a folding qputsubs.c into putsubs.c and passing a pointer
+ to the write function. Better and necessary to allow QP/base64 output by
+ the ezmlm-manage -list command.
+-Added ezmlm-warn -t switch to modify bounce time-out as well as moved the
+ compile-time default to idx.h (Thanks Mark Delany).
+-Added note on "make clean" to INSTALL/UPGRADE.idx (Thanks Peter Hunter).
+-Added support for message numbers in the prefix. This violates mail standards,
+ but is very popular in Japan. (Thanks KI for inspiring this.) ezmlm-idx-0.30
+ does prefix differently, so that it modifies the subject as little as possible
+ for compliance with IETF recs and rfcs. ezmlm-idx-0.23 when prefix was used,
+ used a processed and unfolded subject, which was less correct, and could cause
+ problems with very long subjects.
+-Changed MAXEDIT to 10k. This should accomodate all reasonable dir/text files.
+ A limit _is_ required (see FAQ: SECURITY).
+-Made any _user-generated_ commands case-insensitive throughout (ezmlm-get,
+ -manage, -request). Note: ezmlm-generated ones, such as "list-accept" are
+ still case-sensitive. (Thanks GS for reminding me.)
+-Separated ezmlm-make switches for SENDER checks. -u for posts, -g for archive.
+ Also changed names of other switches. -n for text file editing, -d for
+ digest list. ezmlm-manage edit is now -eE, but the old -dD is still accepted.
+-Modified most programs to service requests for both list and digest list,
+ depending on LOCAL. For ezmlm-warn a command line -d switch is used to
+ process digest bounces. Created copy.h/c as a general routine that
+ does encoding and on-the-fly substitution of <#l#> to the name of the list
+ being serviced. ezmlmrc modified to set up list appropriately and create
+ a digest list for switch -d. The very rudimentary digest list is always
+ called 'list-digest' for the list 'list' and lives as a subscriber and a
+ bounce dir in dir/digest. log.c modified to take the dir as an argument.
+ copy.c introduced. Can deal with encoding and substitution for <#l#>,
+ <#B#>, <#R#>.
+-Made dir/extra standard. All subscriber restriction (ezmlm-make -u) is
+ to accept addresses that are subscribers of either list or in dir/extra.
+-Added REMOVE as a forbidden subject in ezmlm-reject.
+-Added support for rejection based on message and message part MIME
+ Content-type. ezmlm-send can from composite MIME messages filter out
+ body parts based on content-type. Trailers are added as MIME parts
+ to composite MIME messages and in the Content-transfer-encoding of the
+ message for single body messages.
+-min and max message size restrictions moved from ezmlm-send/store to
+ ezmlm-reject.
+-Added support for optional base64 and quoted-printable encoding of trailer
+ and all outgoing ezmlm messages. The same encodings are accepted as input
+ for moderator comments and edited text files.
+-Added hash for threading due to inconsistent/incorrect handling of LWSP
+ by iso-2022-jp MUAs. Now threading works for rfc2047 encoded subjects.
+-Added support for rfc2047 encoded From: lines and continuation for From:
+ lines.
+-Moved relevant parts of idxsub.c into ezmlm-send and ezmlm-idx.
+-Added MIME en/decoding routines to support rfc2047 encoded subject lines.
+ Also, added code to remove redundant ESC sequences when unfolding headers
+ in iso-2022-jp* and iso-2022-cn* and iso-2022-kr. Only iso-2022-jp has been
+ tested.
+-Added ezmlm-idx -d switch to use date from 'Date:' header instead of the
+ qmail received line. For old archives processed through ezmlm-send to
+ re-archive. Remove (GMT), (PST), and DOW, and make 2-digit years xx where
+ xx >= 70 19xx and others 20xx.
+
+
+ezmlm-idx-0.231, 19980302
+=========================
+-ezmlm-check.sh elsif -> elif.
+-Allowed ezmlm-make -a switch (was missing; Thanks MF).
+-Removed subject truncation for index: for prefixed lists it is used and
+rfc2047-encoded subjects are often longer.
+-Fixed idxsub.c bug (subject continuation lines skipped by ezmlm-idx if
+ 'Subject:' is after 'From:'). (Thanks, SOH.)
+
+
+ezmlm-idx-0.23, 19980120
+========================
+-ezmlm-check fixed to remove bash-specific pattern matching. (Thanks, VV).
+-ezmlm-both now makes completely functional list & digest list with digest
+ creation from dir/editor. If address is given, it becomes the owner, remote
+ admin, and a subscriber of both lists. By default, the remote admin is allowed
+ to get a subscriber list.
+-updated ezmlmrc.fr.
+-ezmlm commands now have alternates defined via idx.h, allowing aliases, rather
+ than replacement of command names in non-English domain.
+-Modified ezmlm-tstdig to run easily from within dir/editor and dir/manager.
+ Had to add dir/tstdig timestamp when run from dir/editor, to prevent triggering
+ a new digest while one is being made. Now no new request is issued within one
+ hour after the last one.
+ Changed ezmlmrc to make this default for digested lists.
+-New switches for ezmlm-make.
+-Added ezmlm-get -f and -t switches for easier use on the command line and
+ in dir/editor. Made it "context-sensitive" by testing LOCAL.
+-Via ezmlmrc added -q switch for processing commands to list-request,
+ a -3 hrs switch to configure ezmlm-tstdig in dir/manager, and some cleanup
+ in texts.
+-Modified ezmlm-make to fall back to system ezmlmrc files (with warning)
+ if the -c switch is used by no custom ezmlmrc file is found. This makes
+ it possible for a GUI to rely more on ezmlm-make.
+-Added ezmlm-request to redirect 'Subject:' line requests.
+-Added ezmlm-cron, a very restrictive crond interface enabling users
+ without direct cron access to generate digest trigger messages. Suitable
+ to be run from scripts for non-shell users as well. See ezmlm-cron.1.
+-modified ezmlmrc to set up sublists (-0 sublist@subhost), directories in
+ dir/modpost|modsub|remote with -789, and SENDER restriction on posts and
+ archive retrieval (-6 digest_dir). Doc'd in ezmlm-make.1.
+-modified ezmlm-make to allow </file#^5/> meaning -5 not defined/empty.
+-ezmlm-issubn -n[egate] switch to make 'blacklisting' of SENDERs easier.
+-ezmlm-get TOC loop starts at first message with the given subject, rather
+ than first message in range.
+-Added time and author to the subject index. The TOC now has author info.
+ Changes made so that the programs run fine with old or mixed old/new subject
+ index files.
+-removed == n == from rfc1153 digest messages.
+-Allowed for -dig.code[range]-targetlocal=targethost in ezmlm-get. Makes
+ it easier to trigger digests since SENDER "faking" is no longer required.
+-ezmlmrc changed to add 'Precedence: bulk' to dir/headeradd. For "vacation".
+-Added ezmlm-manage -edit and -edit.file actions. If the -d switch is
+ used, they allow remote admins to edit dir/text files.
+-Modified ezmlm-send to use the main list message number if the message
+ sender has the correct format and if the list is a non-archived sublist.
+-Added tosubs.c, putsubs.c, qputsubs.c for subscriber address output,
+ modified issub.c and subscribe.c, and put all into subdb.a. subscribe.h
+ modified to become the general header file for subscriber database interface.
+ issub() returns (char *)matching_address for compatibility with later packages.
+ Modified all programs interfacing with subscriber databases to use these
+ routines. In all a consistent interface. Using ezmlm with a different
+ subscriber database manager requires changes to these routines only.
+-Modified ezmlm-make and ezmlmrc to store all config info in dir/config, and
+ also read it from there if ezmlm-make is invoked in edit mode with the 
+ 'dir' argument only.
+-Fixed ezmlm-manage to make all output MIME using dir/charset (Thanks, SK).
+
+
+ezmlm-idx-0.221, 19980101
+=========================
+-Fixed ezmlm-send bug causing problems with undefined SENDER.
+ (Thanks, Sadhu, TR).
+-Fixed ezmlm-make lock file name bug (Thanks, SOH).
+
+
+ezmlm-idx-0.22, 19971210
+========================
+-Added 'make clean' and TARGETS. (Thanks, TF).
+-man page and FAQ updates. Some of FAQ info moved into a 'USAGE' section
+ of the man pages.
+-Bug fixed: caused ezmlm-make to ignore the -c switch.
+-Added -34567890 switches to ezmlm-make. They take a command line argument
+ and substitute it for <#3#>, <#4#>, etc, in ezmlmrc.
+-Added code to ezmlm-gate to enable it to pass switches to both ezmlm-send
+ and ezmlm-store (which have and need to keep non-overlapping switches).
+-Added multi-moddir capability to ezmlm-gate, which now becomes the
+ standard tool for SENDER-restricting posts. ezmlm-store does this the
+ slightly more involved but much more secure way.
+-Added -C no copy to sender switch to ezmlm-send. Useful for small lists.
+-Added -d digdir switch to ezmlm-get. When specified, SENDER is accepted
+ for -get/thread/index only if a subscriber of the main list or the list
+ based in digdir.
+-ezmlm-manage sends help in reply to a specific list-help request, even if
+ the list is not public.
+-Added ezmlm-send -cC switches controlling post to self (Thanks TF, JS).
+-Modified ezmlmrc to add a few switches: -t (trailer), -f (prefix),
+ -l (subscriber list to remote admins, if any).
+-Added ezmlm-tstdig which tests if a specified number of messages, message
+ body bytes, or time have passed since the last digest creation. Added
+ support for this in ezmlm-send and ezmlm-get.
+-Added ezmlm-issub, and ezmlm-issubn (tests if SENDER is in any of a number
+ of subscriber databases). Thanks Mark Delany for the original ezmlm-issub.
+-Modified issub.c and subscribe.c to make subscriber database storage
+ and comparisons case-insensitive (backwards compatible).
+-Removed ezmlm-warn from ezmlmrc setup of DIR/bouncer. This helps big
+ lists with lots of bounces.
+-Added locking of list dir to ezmlm-make when used in -e [edit] mode.
+-Bug: ezmlm-send would make all subjects 'Re: something' even if they were
+ not replies for non-indexed lists with a subject prefix. Thanks, Ximenes
+ Zalteca (ximenes@mythic.net) for reporting this.
+
+
+ezmlm-idx-0.21, 19971115
+========================
+-Slightly improved ezmlm-both (now works even for non-remote admin setups).
+ It's still very pedestrian.
+-Added a few rfc1893 error codes.
+-Added -rR option to ezmlm-clean to control sender notification of time-out.
+-Bug: in ezmlm-idx missing message->continue (was break). Caused abort if
+ archive messages are missing (uncommon, but possible if user decides to
+ delete a few). (Tanks MF).
+-More strict on Re[...]: in idxsub: '...' has to be digits and ']' is
+ required. ':' is optional for broken MUAs. Swedish 'Ang:' accommodated.
+-Added 'Content-Disposition:' header to digest messages from ezmlm-get per
+ rfc2183 (Thanks, SK). Removed Content-Type: message/rfc822 txt, since it
+ is the default.
+-Updated man pages and FAQ for new features.
+-ezmlm-send no longer requires DIR/num. If it's not there, it's assumed to
+ be zero and created. This helps ezmlm-make -e.
+-Added ezmlm-make '-e' 'edit' switch. Modified ezmlmrc accordingly.
+-Added ezmlm-check script to help diagnose ezmlm list setup errors. Need to
+ add checks for DIR/text messages.
+-ezmlm-store now pipes the message to ezmlm-send if DIR/modpost is not present.
+ Removing DIR/modpost will make a message moderated list non-moderated.
+-Added ezmlm-gate which pipes to ezmlm-send/ezmlm-mode depending on membership
+ in an address database. This is now a installed C program.
+-ezmlm-get no longer requires index to be executable. Also, improved handling
+ of missing index files in indexed archive (no FATAL error, except for master
+ subject in 'thread' and that should be fixable ...). Added new format specifier
+ 'n' for 'not threaded'. Affects -get and -dig.
+-Bug: Fixed ezmlm-idx to create index via temp file (indexn) and chmod to 700.
+ (Thanks Toshinori Maeno).
+-Removed charset from multipart/digest header (Thanks SK).
+-Bug: Added <#D#> to ezmlm-warn line under </owner/> in ezmlmrc.
+
+
+ezmlm-idx-0.20, 19971030
+========================
+-Requests to ezmlm-moderate to accept/reject already processed messages
+ returns an error ONLY if the requested action is different from the actual
+ fate of the message. Keeps moderators happier in multi-moderator lists,
+ without info loss, with less traffic.
+-A moderator's (un)subscribe CONFIRM reply results in target notification,
+ only if the target's status changed. Multiple moderators confirming no
+ longer yields multiple messages to target.
+-ezmlm-manage copy() takes 2 arguments, the file name and a fall-back file
+ name in case the first file does not exist. CONFIRM requests to moderators
+ use text/mod-(un)sub-confirm (fall back: text/(un)sub-confirm). ezmlmrc
+ changed to set these up.
+-Added MIME header to ezmlm-get -index response (to get DIR/charset effect).
+-Updated docs and FAQ.idx.
+-Pre-release compile testing on several platforms. (Thanks YG, ARB, MF, SK).
+-Added DIR/msgsize. If it exists and is not 0, ezmlm-send and ezmlm-store will
+ bounce posts in excess of 'msgsize' bytes body size.
+-Fixed ezmlm-clean to that when multiple messages time out, the message-id:s
+ are different.
+-ezmlm-clean and ezmlm-moderate now by default return the post as a
+ MIME attachment. Use '-M' for old format.
+-Rewrote ezmlm-make to work from the ezmlmrc template file for better
+ and easier customization. Changed moderator rejection comment tag to '%%%'
+ from '###' to support '#' as a comment character in ezmlmrc. '###' still
+ works.
+-Added DIR/sequence for optional message number header, and DIR/charset for
+ character set. Thanks, SK. Default Compiled is now US-ASCII, as per rfc2046.
+-Added TEST.idx, SECURITY.idx.
+-ezmlm-get allows remote admins archive access even for non-public lists. The
+ ezmlm-get -pP switches override DIR/public effects.
+-ezmlm-manage still does moderator-initiated (un)sub when DIR/public is absent.
+-Fixed bug: Updated MIME to rfc2046. With this the ezmlm-get 'm' format is no
+ longer rfc1153-like. 'r' still gives rfc1153. Moderation attachments are now
+ message/rfc822. Hopefully, the pine attachment viewer will catch up.
+ Thanks, YG [and Mutt developers] for teaching me the errors of my ways. Also,
+ see ezmlm-get.1(BUGS).
+-ezmlm-manage gives moderator help and does list if target is moderator,
+ rather than sender. Allows moderator to access from secondary account (to
+ which mail sent to the primary account is forwarded).
+-ezmlm-store checks DIR/modpost for leading '/' and if found assumes that the
+ first line is the base directory for message moderators.
+-ezmlm-manage checks DIR/modsub and DIR/remote contents for a leading '/'.
+ If found, it is assumed to be the base-dir for moderators. NB: if both
+ DIR/modsub and DIR/remote have entries, only DIR/modsub is used, i.e. it
+ is not possible to have different dbs for remote admin and (un)sub mods.
+-Modified ezmlm-manage to add separate moderator confirm commands (tc/vc)
+ to allow also subscription moderator via forwarded mail. This is essentially
+ a total rewrite of ezmlm-manage. Also, the -S and -U switches were added to
+ allow optional omission of the user confirm phase for (un)subscribe.
+ USE OF THESE SWITCHES DRASTICALLY DECREASES SECURITY, except for
+ moderated lists. Since there have been many request for this (and it
+ seems reasonable in some circumstances) these options have been added.
+ Make sure you understand the consequences if you use them.
+-Fixed bug: Added exit code to ezmlm-moderate. Thanks BG.
+-Added include for sys/types.h to ezmlm-clean.c and ezmlm-store.c, changed
+ ulong/uint to unsigned long/int, removed void from empty parameter lists for
+ two functions, all to compile on BSDI 2.1 and Sun. Thanks, ARB and TE.
+-Combined ezmlm-mod with ezmlm-idx and fused mod.h into idx.h.
+
+ezmlm-idx-0.12, 19970910
+========================
+-Cleanups to allow compile on SGI.  Thanks MF.
+
+ezmlm-idx-0.11, 19970907
+========================
+-Fixed bug: ezmlm-idx failed to check for error return from issub.c.
+-Fixed bug: ezmlm-idx would crash on empty subjects.
+-Moved out command names and lengths to idx.h making changing to other
+ languages easier. Please use this only for totally local lists.
+-Added -cC switches to ezmlm-get to disable all but -dig. Useful for secret
+ lists that are archived and digested.
+-Fixed bug: -dig would give "nothing to digest" with only 1 new message. Now
+ it sends that message out (previously, this message would have been in the
+ next digest as soon as more messages had arrived).
+-Added DIR/prefix. If it exists, it is prefixed to outgoing subjects. Not
+ added to archive/index. ezmlm-idx deals with it. 'Re: ' is prefixed for
+ replies, since we use reply-parsed subject in ezmlm-send. A lot of pain for
+ little gain, but for some reason this seems to be a 'must'.
+-Changed idxsub routines to return 1 if reply indicators were fund, 0 else.
+-Changed idxthread routines from int to void (don't return anything).
+-Split out errtxt.h from idx.h in anticipation of ezmlm-mod.
+-changed ezmlm-send to honor 'mailing-list' in headerremove.
+-fixed ezmlm-make to deal with non-archived and non-indexed lists and to
+ point out that -index works in sets of 100.
+-ezmlm-get error msg on non-sub -thread request fixed.
+-Added DIR/text/trailer. If it exists, it is added to all messages, as
+ suggested by Fred B. Ringel. It is not copied to the archive.
+-ezmlm-make changed to adapt text/bottom to archived/indexed status of list.
+-Fixed usage text for ezmlm-send.
+-'Reply-To:' header from messages is included in standard MIME digests
+ (after reading Dan's comments on Reply-To munging). rfc1153 doesn't allow it.
+-Changed ezmlm-get.c default to NOT restrict get/index/thread to subscribers.
+-Fixed ezmlm-get.1 to correctly reflect effect of -s/-S switches.
+-Fixed FAQ and added more info.
+
+ezmlm-idx-0.10, 19970801
+========================
+-Added several items to FAQ.
+-Made digestcode case-insensitive.
+-Fixed format bugs causing trouble with PINE (Thanks Fred B. Ringel).
+-Improved handling of missing index file in indexed archives.
+-Added info on -get and -index restrictions to text/bottom.
+-Added FAQ.idx (a little silly at the moment ;-).
+-Added CHANGES.idx.
+ Updated README.idx, UPDATE.idx, ezmlm.5 and other man pages.
+-Added text/digest to allow standard info to be added to the list. A place
+ holder is put in by ezmlm-manage, since the exact info depends on the
+ digest list.
+-Moved all error messages into defines in idx.h to support alternative
+ languages.
+-folded subject indexing into ezmlm-send.
+-ezmlm-get.c: Added -s (default) restricting -get, -index, -thread to
+ subscribers. -S on the command line removes this restriction.
+-Added support for the horrid German 'Aw:' and 'Aw[..]:' replies.
+-All linear white space is converted to a single ' ' in subject indexing.
+ Existing archives should be re-indexed using the new ezmlm-idx. Probably rarely
+ needed, but it's more correct.
+-Added support for subject continuation lines (rfc822). Probably very rarely
+ needed.
+-Limited '-thread' to +/- 2000 messages (defines in ezmlm-get.c) from the
+ "master message" to limit resource use on large archives.
+-Changed limit for '-get' to 50 messages, '-index' to 20 sets (2000 subjects).
+-Added digestcode support to ezmlm-make as a 5th argument. Default=blank.
+-Added arguments to digest option. If one is given, digesting starts with that
+ message and dignum/digissue are used/updated. If both are given, dignum and
+ digissue are not updated and the issue number is the number of the first
+ message in the archive.
+-Added digest support. Enabled by specifying a 'digestcode'last on the
+ ezmlm-get command line.
+-Removed the now redundant -fF (filter) and -qQ (quote) options.
+-Changed message format for returned messages allowing rfc1153, MIME
+ multipart/digest, or MIME multipart/digest ordering and retaining only headers
+ as per rfc1153, with the addition of 'Content-Type:' to better support
+ alternative character sets. The latter format is the default.
+-Fixed bug in -thread: search for messages was set to start at the beginning
+ of the index containing the "master message", rather than at the beginning of
+ the archive.
+-Fixed bug: A few stralloc* were incorrectly stdio* in sindex.c.
+
+ezmlm-idx-0.02, 19970702
+========================
+-Adapted to changes in ezmlm-0.52 => ezmlm-0.53.
+
+ezmlm-idx-0.01, 19970615
+========================
diff --git a/DOWNGRADE.idx b/DOWNGRADE.idx
new file mode 100644 (file)
index 0000000..59a1114
--- /dev/null
@@ -0,0 +1,36 @@
+$Id: DOWNGRADE.idx,v 1.3 1997/12/30 21:30:56 lindberg Exp $
+$Name: ezmlm-idx-040 $
+
+MODIFYING ezmlm-idx lists to work with "virgin" ezmlm-0.53
+
+With ezmlm-idx-0.22, the routines issub.c and subscribe.c are modified to
+store subscriber addresses using a hash based on the lower case address,
+rather than a case sensitive hash. This was done to avoid the many problems
+with subscribers using mixed case addresses (User@host and user@host) without
+realizing that these are different.
+
+These changes have no impact on lower case-only addresses. For mixed case
+addresses, the case in the local part is retained. If not found, a second
+lookup is done with a hash based on the mixed case address. This results in
+backwards compatibility with ezmlm-0.53 subscriber list.
+
+In the unlikely event that you use ezmlm-idx and then decide to go back to
+ezmlm-0.53 alone, mixed case addresses stored in the new location
+(case-insensitive hash) will not be found by the old ezmlm-0.53 programs.
+To place them in the ezmlm-0.53 position, do the following with your lists
+after installing the "virgin" ezmlm-0.53 binaries and backing up everything
+under DIR/subscribers:
+
+       % ezmlm-list DIR >tmp.tmp
+       % rm -rf DIR/subscribers/*
+       % xargs ezmlm-sub DIR <tmp.tmp
+
+This just recreates the subscriber database with the old style hash.
+
+This procedure can also be used to recover corrupted subscriber databases,
+by editing tmp.tmp before resubscribing.
+
+You can also identify the addresses that would be affected by:
+
+       % ezmlm-list | grep -G '[A-Z]'
+
diff --git a/FAQ.idx b/FAQ.idx
new file mode 100644 (file)
index 0000000..38a46eb
--- /dev/null
+++ b/FAQ.idx
@@ -0,0 +1,6072 @@
+  EZFAQ 0.40 - ezmlm-idx and ezmlm FAQ
+  Fred Lindberg, lindberg@id.wustl.edu & Fred B. Ringel,
+  fredr@rivertown.net
+  22-NOV-1999
+
+  This document is a collection of frequently asked questions about
+  ezmlm-idx. Where applicable, ezmlm itself is also covered. This FAQ
+  presumes familiarity with Unix, and with the basic concepts of E-mail
+  and mailing lists.  This FAQ is updated for ezmlm-0.53 and ezmlm-
+  idx-0.40.
+  ______________________________________________________________________
+
+  Table of Contents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  1. General Information
+
+     1.1 Acknowledgements
+     1.2 What is this document?
+     1.3 Terminology
+     1.4 What is the difference between ezmlm and ezmlm-idx?
+     1.5 Where can I get all of the ezmlm-related programs?
+     1.6 Where can I find documentation for ezmlm and patches?
+     1.7 Where do I send comments on this document?
+     1.8 How to experiment with new versions of ezmlm-idx.
+
+  2. Quick start
+
+  3. Overview of mailing list management and mailing list managers
+
+  4. Overview of ezmlm function
+
+     4.1 The basic setup.
+     4.2 Inventions in ezmlm.
+     4.3 The qmail delivery mechanism.
+     4.4 What the different programs do.
+     4.5 What the different files in the list directory do.
+     4.6 The paper path for posts.
+     4.7 The ezmlm path for moderation messages.
+     4.8 The ezmlm path for administrative messages.
+     4.9 The ezmlm path for bounces.
+     4.10 Messages to list-owner and list-digest-owner.
+     4.11 Structure of subscriber databases.
+     4.12 Local case in E-mail addresses.
+     4.13 Testing SENDER to allow posts only from list subscribers.
+     4.14 How cookies work.
+     4.15 How moderator E-mail addresses are stored.
+     4.16 How subscription moderation works.
+     4.17 How remote administration works.
+     4.18 How message moderation works.
+     4.19 How QMQP support works
+     4.20 How messages are stored in the archive.
+     4.21 How the message index works.
+     4.22 How threading works.
+     4.23 How digests work.
+     4.24 How WWW archive access works.
+     4.25 How ezmlm-tstdig works.
+     4.26 How sublists work.
+     4.27 How sublisting can be made transparent to the user.
+     4.28 How to service commands in the subject line.
+     4.29 How to support alternative command names.
+     4.30 How to add your own commands.
+     4.31 How remote administrators can retrieve a subscriber list
+     4.32 How remote administrators can determine the number of subscribers
+     4.33 How remote admins can see if an address is a subscriber or not
+     4.34 How remote administrators can search the subscription log
+     4.35 How text file editing works.
+     4.36 How subject line prefixes work.
+     4.37 How bounces are handled.
+     4.38 How the info and faq commands work.
+     4.39 How the global ezmlm list address works.
+     4.40 How ezmlm-cron works.
+     4.41 How ezmlm-make works.
+     4.42 What names can I use for my lists?
+     4.43 Lists in virtual domains
+     4.44 How do I make customization simple for me/my users?
+
+  5. ezmlm support for SQL databases.
+
+     5.1 Why use an SQL database with ezmlm?
+     5.2 Why not to use an SQL database with ezmlm.
+     5.3 Tables used for (My)SQL support.
+        5.3.1 Address tables.
+        5.3.2 Subscriber log tables.
+        5.3.3 Message logging tables.
+     5.4 How to set up a simple list with SQL support.
+        5.4.1 Helper programs for SQL-enabled lists.
+     5.5 Manually manipulating the subscribers of a SQL-enabled list.
+     5.6 Converting to and from and SQL database.
+     5.7 Optimizing MySQL for ezmlm.
+        5.7.1 Address SELECTs, additions, removals.
+     5.8 Maintenance of the MySQL database.
+
+  6. Possible error conditions in ezmlm lists.
+
+     6.1 What do I do if ezmlm doesn't work?
+     6.2 How do I report ezmlm bugs?
+     6.3 Where do I send suggestions for ezmlm-idx improvements?
+     6.4 Using ezmlm-test to check the ezmlm(-idx) programs.
+     6.5 Using ezmlm-check to find setup errors.
+     6.6 Posts are rejected: Sorry, no mailbox here by that name (#5.1.1).
+     6.7 Post are not sent to subscribers.
+     6.8 ezmlm-make fails: usage: ezmlm-make ...
+     6.9 ezmlm-make fails: Unable to create ...
+     6.10 ezmlm-make fails: ... ezmlmrc does not exist
+     6.11 Index/get/thread requests fail quietly or with errors from ezmlm-manage.
+     6.12 Digest triggering requests fail.
+     6.13 Remote administration (un)subscribe confirm requests go to the user, not the moderator.
+     6.14 (Un)subscribers does not receive a (un)subscribe acknowledgement
+     6.15 Messages posted to a moderated list are sent out without moderation.
+     6.16 Messages posted to a moderated list do not result in moderation requests.
+     6.17 Moderation request replies do not result in the appropriate action.
+     6.18 Moderator comments with moderation request replies are not added to the post/sent to the poster.
+     6.19 Some headers are missing from messages in the digest.
+     6.20 Some Received: headers are missing from messages.
+     6.21 My Mutt users cannot thread their digest messages.
+     6.22 Posts fail: Message already has Mailing-List (#5.7.2).
+     6.23 The last line of a
+     6.24 No CONFIRM requests are sent to moderators.
+     6.25 Deliveries fail ``temporary qmail-queue error''
+     6.26 How to deal with corrupted subscriber lists
+     6.27 Vacation program replies are treated as bounces by ezmlm.
+     6.28 Digests do not come at regular hours.
+     6.29 Preventing loops from misconfigured subscriber addresses.
+     6.30 A user can subscribe and receives warning and probe messages, but no messages from the list.
+
+  7. Customizing ezmlm-make operation via ezmlmrc
+
+     7.1 Using ezmlm-make to edit existing lists.
+     7.2 What is ezmlmrc?
+     7.3 Changing defaults for
+     7.4 Changing default moderator directories.
+     7.5 Adapting ezmlm-make for virtual domains.
+     7.6 Setting up ezmlm-make for special situations.
+
+  8. Restricting message posting to the list.
+
+     8.1 Requiring the list address in To:/Cc: headers.
+     8.2 Rejecting messages sent from other mailing lists.
+     8.3 Restricting posts based on the Subject line.
+     8.4 Restricting the size of posts.
+     8.5 Restricting posts based on MIME content-type.
+     8.6 Restricting posts to list subscribers.
+     8.7 Restricting posts to an arbitrary set of E-mail addresses (higher security option).
+     8.8 Completely restricting posts.
+     8.9 A general solution to restricting posts based on SENDER.
+
+  9. Customizing outgoing messages.
+
+     9.1 Adding a trailer to outgoing messages.
+     9.2 Adding a subject prefix to outgoing messages.
+     9.3 Adding a header to outgoing messages.
+     9.4 Adding a message number header.
+     9.5 Removing headers from outgoing messages.
+     9.6 Removing MIME parts from messages.
+     9.7 Limiting ``Received:'' headers in outgoing messages.
+     9.8 Setting ``Reply-To: list@host''.
+     9.9 Configuring the list so posts are not copied to the original sender.
+     9.10 Customizing ezmlm notification messages.
+     9.11 Specifying character set and content-transfer-encoding for outgoing ezmlm messages.
+
+  10. Customizing archive retrieval.
+
+     10.1 Specifying the format for retrieved messages.
+     10.2 Specifying the default format for digests and archive retrieval.
+     10.3 Limiting the number of messages per -get/-index request.
+
+  11. Restricting archive retrieval.
+
+     11.1 Restricting archive access to subscribers.
+     11.2 Restricting available archive retrieval commands.
+     11.3 Restricting archive retrieval to moderators.
+     11.4 Allowing archive retrieval from a non-public list.
+
+  12. Customizing digests.
+
+     12.1 Setting up a digest list.
+     12.2 Generating daily digests.
+     12.3 Generating the first digest.
+     12.4 Adding standard administrative information to digests.
+     12.5 Controlling the digest format.
+     12.6 Customizing bounce handling.
+
+  13. Remote administration.
+
+     13.1 How can I remotely add moderators, subscriber aliases, etc?
+     13.2 Moderating posts from a secondary account.
+     13.3 Moderating subscription from a secondary account.
+     13.4 Automatically approving posts or subscriptions.
+     13.5 Allowing remote administrators to get a subscriber list.
+     13.6 Allowing remote administrators to retrieve or search a subscription log.
+     13.7 Allowing users to get a subscriber list.
+     13.8 Changing the timeout for messages in the moderation queue.
+     13.9 Finding out how many messages are waiting for moderation.
+     13.10 Using the same moderators for multiple lists.
+     13.11 Using different moderators for message and subscription moderation.
+     13.12 Setting up moderated lists with the list owner as the ``super moderator'' able to add/remove moderators remotely.
+     13.13 Customizing ezmlm administrative messages.
+     13.14 Manually approving a message awaiting moderation.
+     13.15 Manually rejecting a message awaiting moderation.
+
+  14. Sublists.
+
+     14.1 Sublists of ezmlm lists.
+     14.2 Sublists of non-ezmlm lists.
+     14.3 How to set up a cluster of list and sublists with standard databases.
+
+  15. Migration to Ezmlm from other Mailing List Managers.
+
+     15.1 Basic Concepts.
+     15.2 Setting up ezmlm to respond to host-centric commands.
+     15.3 Commands of other mailinglist managers recognized by ezmlm.
+        15.3.1 Listproc/Listserv.
+        15.3.2 Majordomo.
+        15.3.3 Smartlist.
+
+  16. Optimizing list performance.
+
+     16.1 Crond-generated digests for better performance.
+     16.2 Optimizing execution of ezmlm-warn(1).
+     16.3 Decreasing ezmlm-warn time out to increase performance.
+     16.4 Use ezmlm without ezmlm-idx for maximum performance.
+     16.5 Not archiving to maximize performance.
+     16.6 Sublists to maximize performance.
+
+  17. Miscellaneous.
+
+     17.1 How do I quickly change the properties of my list?
+     17.2 Open archived list with daily digests.
+     17.3 Variations in moderation
+     17.4 Lists that allow remote admin, but not user initiated subscription or archive retrieval.
+     17.5 Lists that allow remote admin, user archive retrieval, but not user-initiated subscription.
+     17.6 Lists that restrict archive retrieval to subscribers.
+     17.7 Lists that do not allow archive retrieval at all.
+     17.8 Lists that do not allow archive retrieval and do not allow digest triggering per mail.
+     17.9 Lists that allow archive retrieval only to moderators, but allow user-initiated subscription.
+     17.10 Lists that do not require user confirmation for (un)subscription.
+     17.11 Announcement lists for a small set of trusted posters
+     17.12 Announcement lists allowing moderated posts from anyone.
+     17.13 Announcement lists with less security and more convenience.
+
+  18. Ezmlm-idx compile time options.
+
+     18.1 Location of binaries.
+     18.2 Location of man pages.
+     18.3 Base directory of qmail-installation.
+     18.4 Short header texts, etc.
+     18.5 Arbitrary limits.
+     18.6 Command names.
+     18.7 Error messages.
+     18.8 Paths and other odd configuration items.
+
+  19. Multiple language support.
+
+     19.1 Command names.
+     19.2 Text files.
+     19.3 Multi-byte character code support.
+
+  20. Subscriber notification of moderation events.
+
+     20.1 General opinions.
+     20.2 Users should know that the list is subscription moderated.
+     20.3 Subscribers should know that posts are moderated.
+     20.4 Senders of posts should be notified of rejections.
+
+  21. Ezmlm-idx security.
+
+     21.1 General assumptions.
+     21.2 SENDER manipulation.
+     21.3 ezmlm cookies.
+     21.4 Lists without remote admin/subscription moderation.
+     21.5 Message moderation.
+     21.6 Subscription moderation.
+     21.7 Remote administration.
+     21.8 Remote editing of ezmlm text files.
+     21.9 Digest generation and archive retrieval.
+     21.10 Convenience for security: the ezmlm-manage ``-S'' and ``-U'' switches.
+     21.11 Denial of service.
+     21.12 Moderator anonymity.
+     21.13 Confidentiality of subscriber E-mail addresses.
+     21.14 Help message for moderators.
+     21.15 Sublists.
+     21.16 SQL databases.
+     21.17 Reporting security problems.
+
+
+  ______________________________________________________________________
+
+  1\b1.\b.  G\bGe\ben\bne\ber\bra\bal\bl I\bIn\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn
+
+
+  1\b1.\b.1\b1.\b.  A\bAc\bck\bkn\bno\bow\bwl\ble\bed\bdg\bge\bem\bme\ben\bnt\bts\bs
+
+  Many ezmlm users have contributed to improvements in ezmlm-idx. These
+  are listed in the R\bRE\bEA\bAD\bDM\bME\bE.\b.i\bid\bdx\bx file in the ezmlm-idx distribution.
+  Others have through questions and suggestions inspired parts in this
+  FAQ, or pointed out errors or omissions. Thanks! Direct contributions
+  are attributed to the respective authors in the text. Thanks again!
+
+
+  1\b1.\b.2\b2.\b.  W\bWh\bha\bat\bt i\bis\bs t\bth\bhi\bis\bs d\bdo\boc\bcu\bum\bme\ben\bnt\bt?\b?
+
+  This FAQ contains answers to many questions that arise while
+  installing ezmlm, ezmlm-idx, and while setting up and managing ezmlm
+  mailing lists. See ``'' for a brief summary of what is ezmlm and what
+  is ezmlm-idx.
+
+  Many aspects of ezmlm are covered in several places in this FAQ. The
+  early sections explain how ezmlm works. Later sections discuss how to
+  deal with possible errors/problems. Subsequent sections discuss
+  details of customization and list setup in a _\bH_\bO_\bW_\bT_\bO form. Finally,
+  there are sections on information philosophy for moderated lists and
+  on security aspects on ezmlm lists.
+
+  This is an evolving document.  If you find any errors, or wish to
+  comment, please do so to the authors.  This FAQ is currently aimed at
+  system administrators and knowledgeable users, and heavily weighted
+  towards questions specific to the ezmlm-idx add-on.
+
+  If you have problems with the ezmlm-idx package, please start by
+  reading the ``man'' pages which come with each program, then this
+  document and other ezmlm documentation which is identified here. If
+  you have exhausted these resources, try the ezmlm and qmail mailing
+  lists and their respective mailing list archives. If you have solved a
+  problem not in the documentation, write it up as a proposed section of
+  a FAQ and send it to the authors. This way, it can be added to the
+  next version of this FAQ.
+
+
+  1\b1.\b.3\b3.\b.  T\bTe\ber\brm\bmi\bin\bno\bol\blo\bog\bgy\by
+
+  This document uses a number of terms. Here are the meanings ascribed
+  to them by the authors.
+
+     D\bDI\bIR\bR
+        The base directory of the list.
+
+
+     S\bSE\bEN\bND\bDE\bER\bR
+        The envelope sender of the message, as passed to ezmlm by qmail
+        via the $SENDER environment variable.
+
+
+     L\bLO\bOC\bCA\bAL\bL
+        The local part of the envelope recipient. For list-get-1@host,
+        it is usually _\bl_\bi_\bs_\bt_\b-_\bg_\be_\bt_\b-_\b1. If host is a virtual domain,
+        controlled by _\bu_\bs_\be_\br_\b-_\bs_\bu_\bb, then local would be _\bu_\bs_\be_\br_\b-_\bs_\bu_\bb_\b-_\bl_\bi_\bs_\bt_\b-_\bg_\be_\bt_\b-_\b1.
+
+
+     m\bmo\bod\bdd\bdi\bir\br
+        Base directory for moderators.  Moderator E-mail addresses are
+        stored in a hashed database in m\bmo\bod\bdd\bdi\bir\br/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/. By default,
+        ``moddir'' is D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/.
+
+        To add or remove moderators:
+
+
+          % ezmlm-sub DIR/moddir moderator@host.domain
+          % ezmlm-unsub DIR/moddir moderator@host.domain
+
+
+
+
+
+     d\bdo\bot\btd\bdi\bir\br
+
+        The second argument of ezmlm-make is the main .qmail file for
+        the list. dotdir is the directory in which this ``dot file''
+        resides, i.e. the directory part of the ``dot'' argument. This
+        is usually the home directory of the user controlling the list
+        (but NOT necessarily of the one creating the list). Thus, _\bd_\bo_\bt_\bd_\bi_\br
+        is ~\b~a\bal\bli\bia\bas\bs/\b/ if ``root'' creates a list:
+
+
+           # ezmlm-make ~alias/list ~alias/.qmail-list ...
+
+
+
+
+     _\bd_\bo_\bt_\bd_\bi_\br is where the .\b.e\bez\bzm\bml\blm\bmr\brc\bc file is expected when the ezmlm-
+     make(1) ``-c'' switch is used (see ``Customizing ezmlm-make opera-
+     tion'').
+
+
+     e\bez\bzm\bml\blm\bm b\bbi\bin\bna\bar\bry\by d\bdi\bir\bre\bec\bct\bto\bor\bry\by
+        The directory where the ezmlm-binaries are normally stored, as
+        defined at compile time in c\bco\bon\bnf\bf-\b-b\bbi\bin\bn.  This is compiled into the
+        programs and does not change just because you have moved the
+        program.
+
+
+     e\bez\bzm\bml\blm\bm-\b-g\bge\bet\bt(\b(1\b1)\b)
+        This is a reference to the ezmlm-get.1 man page.  Access it with
+        one of the following:
+
+
+          % man ezmlm-get
+          % man 1 ezmlm-get
+
+
+
+
+     or if you have not yet installed ezmlm-idx (replace ``xxx'' with
+     the version number):
+
+
+          % cd ezmlm-idx-0.xxx
+          % man ./ezmlm-get.1
+
+
+
+     b\bba\bas\bse\bed\bdi\bir\br
+        The list directory when referencing the list subscriber address
+        database.  For E-mail addresses stored in a set of files within
+        D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/, the ``basedir'' is ``DIR''.
+
+
+     a\bad\bdd\bdr\bre\bes\bss\bs d\bda\bat\bta\bab\bba\bas\bse\be
+        A collection of E-mail addresses stored in a set of files within
+        the ``subscribers'' subdirectory of the basedir,
+        D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/.
+
+
+     m\bme\bes\bss\bsa\bag\bge\be m\bmo\bod\bde\ber\bra\bat\bto\bor\br
+        An address to which moderation requests for posts to the list
+        are sent. The moderation requests are formatted with
+        ``From:''-``reject'' and a ``To:''-``accept'' default headers
+        for moderator replies. A reply to the ``reject'' address leads
+        to the rejection of the post. A reply to the ``accept'' address
+        leads to the acceptance of the post. Any E-mail address can be a
+        moderator E-mail address. Any number of moderator E-mail
+        addresses can be used. If a post is sent from a moderator E-mail
+        address, the moderation request is sent to that E-mail address
+        only. If a post is sent from an E-mail address that is not a
+        moderator, a moderation request is sent to all moderators.
+
+        The first reply to the moderation request determines the fate of
+        the message. Further requests for the action already taken are
+        silently ignored, while a request for the contrary action
+        results in an error message stating the actual fate of the
+        message. Thus, if you want to ``accept'' the message and it has
+        already been accepted, you receive no reply, but if you attempt
+        to ``reject'' it, you will receive an error message stating that
+        the message already has been accepted.
+
+        Most lists are not message moderated. If they are, the owner is
+        usually a ``message moderator'', sometimes together with a few
+        other trusted users.
+
+        For an announcement list, it is common to make all the
+        ``official announcers'' ``message moderators''. This way, they
+        can post securely and ``accept'' their own posts, while posts
+        from other users will be sent to this set of ``official
+        announcers'' for approval.
+
+
+     s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\bra\bat\bto\bor\br
+        An E-mail address where subscription moderation requests are
+        sent. A subscription moderation request is sent after a user has
+        confirmed her intention to subscribe. The subscription
+        moderation request is sent to all moderators. As soon as a reply
+        to this message is received, the user is subscribed and
+        notified. Any E-mail address can be a subscription moderator and
+        any number of subscription moderators can be used.
+
+        Unsubscribe requests are never moderated (except when the ezmlm-
+        manage(1) ``-U'' flag is used and the sender attempts to remove
+        an address other than the one s/he is sending from). It is hard
+        to imagine a legitimate mailing list that would want to prevent
+        unsubscriptions.
+
+
+     r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\br
+        When a remote administrator subscribes or unsubscribes a list
+        member, the ``confirm'' request is sent back to the remote
+        administrator, rather than to the subscriber's E-mail address.
+        This allows the remote administrator to (un)subscribe any list
+        member without the cooperation of the subscriber at that
+        address. Any E-mail address can be a remote administrator and
+        any number of E-mail addresses can be remote administrators.
+
+        The set of E-mail addresses that are ``remote administrators''
+        and ``subscription moderators'' are always the same. This set of
+        E-mail addresses can be ``remote administrators'',
+        ``subscription moderators'' or both.
+
+        For most lists, the owner would be the ``remote administrator'',
+        if s/he wishes to moderate messages, the owner would be the
+        ``message moderator'' and if s/he wishes to moderate
+        subscriptions the owner would also be the ``subscription
+        moderator''.
+
+        The list's ``message moderator(s)'' can be the same, but can
+        also be set up to be completely different.
+
+
+     C\bCh\bha\ban\bng\bgi\bin\bng\bg l\bli\bis\bst\bt `\b``\b`o\bow\bwn\bne\ber\brs\bsh\bhi\bip\bp'\b''\b'
+        Within this FAQ there are references to the need to check or
+        change the list ``ownership.'' This is not a reference to the
+        individual user who is the ``list-owner'', but a reference to
+        the ownership of the files by your operating system which make
+        up the list and reside in D\bDI\bIR\bR/\b/.
+
+        To change the ownership of D\bDI\bIR\bR/\b/ and everything within:
+
+
+          % chown -R user DIR
+          % chgrp -R group DIR
+
+
+
+
+     Depending on your system/shell, it may be possible to combine these
+     commands into either:
+
+
+          % chown -R user.group DIR
+          % chown -R user:group DIR
+
+
+
+
+
+  1\b1.\b.4\b4.\b.  W\bWh\bha\bat\bt i\bis\bs t\bth\bhe\be d\bdi\bif\bff\bfe\ber\bre\ben\bnc\bce\be b\bbe\bet\btw\bwe\bee\ben\bn e\bez\bzm\bml\blm\bm a\ban\bnd\bd e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx?\b?
+
+  ezmlm-0.53 is a qmail-based mailing list manager written by Dan J.
+  Bernstein.  It has all the basic functionality of a mailing list
+  manager, such as subscriber address management including automated
+  bounce handling as well as message distribution and archiving.
+
+  ezmlm-idx is an add-on to ezmlm. It adds multi-message threaded
+  message retrieval from the archive, digests, message and subscription
+  moderation, and a number of remote administration function. It
+  modifies the configuration program ezmlm-make(1) so that it uses a
+  text file template rather than compiled-in texts in list creation. In
+  this manner, ezmlm-idx allows easy setup of lists in different
+  languages and customization of default list setup. ezmlm-idx also adds
+  MIME handling, and other support to streamline use with languages
+  other than English. As an ezmlm add-on, ezmlm-idx does not work
+  without ezmlm and tries to be compatible with ezmlm as much as
+  possible.  ezmlm-idx also modifies the ezmlm subscriber database to be
+  case insensitive to avoid many unsubscribe problems.
+
+  New in ezmlm-idx-0.40 are better support for announcement lists,
+  support for QMQP to offload message distribution onto external hosts,
+  simplified optional SQL database use (MySQL or PostgreSQL), more
+  flexibility in determining which messages should be moderated, a WWW
+  interface to the list archives, and many small improvements.
+
+  ezmlm-idx-0.32 adds improved handling of very large lists with
+  optimized bounce handling, ezmlm-split(1) for forwarding (un)subscribe
+  requests to sublists to allow sublisting transparent to the
+  subscriber, and SQL support to allow sublisting with improved message
+  authentication and monitoring of list function, as well as dynamic
+  addition/removal/reconfiguration of sublists. Also, subscriber
+  ``From:'' lines are logged with support for finding a subscription
+  address from a name. The qmail DEFAULT variable is used, if present.
+  Together, these additions eliminate the most common problems making
+  ezmlm use and administration even easier.
+
+  This document is a FAQ for ezmlm-idx. However, many of the basic items
+  that are discussed also apply to ezmlm per se. Referring to the two
+  paragraphs above, it should be relatively easy to figure out which
+  features require ezmlm-idx.
+
+
+  1\b1.\b.5\b5.\b.  W\bWh\bhe\ber\bre\be c\bca\ban\bn I\bI g\bge\bet\bt a\bal\bll\bl o\bof\bf t\bth\bhe\be e\bez\bzm\bml\blm\bm-\b-r\bre\bel\bla\bat\bte\bed\bd p\bpr\bro\bog\bgr\bra\bam\bms\bs?\b?
+
+  We have now registered ezmlm.org to make access to ezmlm-idx and
+  related programs/documentation easier. www.ezmlm.org is currently an
+  alias for Fred B. Ringel's www.rivertown.net/~ezmlm/ and ftp.ezmlm.org
+  an alias for Fred Lindberg's ftp.id.wustl.edu.
+
+
+     D\bDa\ban\bn J\bJ.\b. B\bBe\ber\brn\bns\bst\bte\bei\bin\bn'\b's\bs e\bez\bzm\bml\blm\bm-\b-0\b0.\b.5\b53\b3
+
+     +\bo  <ftp://cr.yp.to/pub/software/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.ezmlm.org/pub/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.ntnu.no/pub/unix/mail/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.pipex.net/mirrors/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.jp.qmail.org/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.rifkin.technion.ac.il/pub/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <ftp://ftp.mira.net.au/unix/mail/qmail/ezmlm-0.53.tar.gz>
+
+     +\bo  <http://www.qmail.org/>
+
+     T\bTh\bhe\be l\bla\bat\bte\bes\bst\bt v\bve\ber\brs\bsi\bio\bon\bn o\bof\bf e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx
+        ezmlm-idx releases are numbered ``ezmlm-idx-0.xy[z]''.  Versions
+        with the same ``x'' are backwards compatible. A change in ``x''
+        signifies major changes, some of which _\bm_\ba_\by require list changes
+        (see UPGRADE.idx). However, backwards compatibility with
+        ezmlm-0.53 list will be maintained. Thus, this is an issue only
+        if you are already using an older version of ezmlm-idx.
+
+        Addition of ``z'' are bug fixes only. Thus, ezmlm-idx-0.301 is
+        ezmlm-idx-0.30 with known bugs fixed (but no other significant
+        changes).  When available, patches are named
+        ``filename-0.xy[z].diff'', where ``0.xy[z]'' corresponds to the
+        release to which they apply.  When a number of bugs (or a
+        significant bug) are found a bug-fix release is made
+        incorporating all the patches for the previous version.
+
+        To get the latest features, look for the highest number (``e.g.
+        ezmlm-idx-0.40''). Any bugs in versions with new features are
+        expected to be limited to the new features.
+
+        To get the most solid version, get the highest 3-digit number,
+        i.e. a bug fix. If you already run a version in that series and
+        a new bug fix is released, see CHANGES.idx to determine if it is
+        worthwhile to upgrade. Most bugs so far have been relevant only
+        when using lists in very unusual ways or with rarely used
+        options.
+
+
+     +\bo  <ftp://ftp.ezmlm.org/pub/patches/>
+
+     +\bo  <ftp://gd.tuwien.ac.at/infosys/mail/qmail/ezmlm-patches/> ftp
+        mirror in Austria.
+
+     +\bo  <http://gd.tuwien.ac.at/infosys/mail/qmail/ezmlm-patches/> http
+        access to the same mirror.
+
+     +\bo  <ftp://ftp.win.or.jp/pub/network/mail/qmail/ezmlm-idx/> ftp
+        mirror in Japan.
+
+     e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) f\bfi\bil\ble\bes\bs f\bfo\bor\br d\bdi\bif\bff\bfe\ber\bre\ben\bnt\bt l\bla\ban\bng\bgu\bua\bag\bge\bes\bs
+        The latest versions at the time of release of a package are
+        included in that package. Thus, this directory will have a file
+        labeled with the current ezmlm-idx version number only if it has
+        been updated later than the package.  ezmlmrc(5) files are
+        updated and new ones are added all the time, also with bug fix
+        releases. Therefore, always look at the latest package. Please
+        note that ezmlmrc may change significantly between versions.
+        Thus, do not expect the ezmlm-idx-0.324 ezmlmrc.es to work with
+        ezmlm-idx-0.40.
+
+        ezmlmrc(5) files contain some release-specific configurations.
+        Do not use a later file (other than from bug fix releases) with
+        an earlier version of the programs. It is usually OK to use a
+        version from an earlier package (see UPGRADE.idx), but some new
+        functionality may nor be available.
+
+        To contribute an ezmlmrc(5) file in a new language, start with
+        the en_US version from the latest package, and send the gzipped
+        file to lindberg@id.wustl.edu. Please leave comments intact and
+        in English and do not change the order of items in the file.
+        This will facilitate maintenance.
+
+
+     +\bo  <ftp://ftp.ezmlm.org/pub/patches/ezmlmrc/>
+
+     +\bo  <ftp://gd.tuwien.ac.at/infosys/mail/qmail/ezmlm-
+        patches/ezmlmrc/>
+
+     +\bo  <http://gd.tuwien.ac.at/infosys/mail/qmail/ezmlm-
+        patches/ezmlmrc/>
+
+     +\bo  <ftp://ftp.win.or.jp/pub/network/mail/qmail/ezmlm-idx/ezmlmrc/>
+
+     e\bez\bzm\bml\blm\bm-\b-i\bis\bss\bsu\bub\bb-\b-0\b0.\b.0\b05\b5
+
+     +\bo  <ftp://ftp.ezmlm.org/pub/patches/ezmlm-issub-0.05.tar.gz>.  Use
+        ezmlm-issub only if you do not use ezmlm-idx. The same
+        functionality is available in ezmlm-idx and the packages are not
+        compatible.
+
+     +\bo  Also via mirrors mentioned above.
+
+
+     R\bRP\bPM\bMs\bs a\ban\bnd\bd S\bSR\bRP\bPM\bMS\bS o\bof\bf q\bqm\bma\bai\bil\bl,\b, e\bez\bzm\bml\blm\bm a\ban\bnd\bd e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx
+
+     +\bo  <ftp://ftp.ezmlm.org/pub/patches/>
+
+     +\bo  <ftp://summersoft.fay.ar.us/pub/qmail/>
+
+
+  1\b1.\b.6\b6.\b.  W\bWh\bhe\ber\bre\be c\bca\ban\bn I\bI f\bfi\bin\bnd\bd d\bdo\boc\bcu\bum\bme\ben\bnt\bta\bat\bti\bio\bon\bn f\bfo\bor\br e\bez\bzm\bml\blm\bm a\ban\bnd\bd p\bpa\bat\btc\bch\bhe\bes\bs?\b?
+
+
+     m\bma\ban\bn p\bpa\bag\bge\bes\bs
+        All ezmlm component programs come with their own man pages.
+        Thus, for info on _\be_\bz_\bm_\bl_\bm_\b-_\bs_\be_\bn_\bd, type:
+
+
+
+          % man ezmlm-send
+
+
+
+
+     or if you have unpacked ezmlm, but not made it or installed it:
+
+
+
+          % cd ezmlm-0.53
+          % man ./ezmlm-send.1
+
+
+
+
+
+     e\bez\bzm\bml\blm\bm(\b(5\b5)\b)
+        General info on ezmlm and list directories is in e\bez\bzm\bml\blm\bm.\b.5\b5:
+
+
+
+          % man ezmlm
+
+
+
+
+     or
+
+
+
+          % cd ezmlm-0.53
+          % man ./ezmlm.5
+
+
+
+
+     _\bN_\bO_\bT_\bE_\b: Installation of the ezmlm-idx package updates some existing
+     man pages to reflect changes made by the patch (e.g.  ezmlm-
+     send(1), ezmlm(5)).
+
+
+     T\bTe\bex\bxt\bt f\bfi\bil\ble\bes\bs i\bin\bn t\bth\bhe\be d\bdi\bis\bst\btr\bri\bib\bbu\but\bti\bio\bon\bn
+        ezmlm comes with a R\bRE\bEA\bAD\bDM\bME\bE file with general instructions, an
+        I\bIN\bNS\bST\bTA\bAL\bLL\bL file with installation instructions, an U\bUP\bPG\bGR\bRA\bAD\bDE\bE file for
+        upgrading from a previous version and a C\bCH\bHA\bAN\bNG\bGE\bES\bS file with
+        information on changes from previous versions. ezmlm-idx comes
+        with similar files suffixed with ``.\b.i\bid\bdx\bx''. Most other patches or
+        add-ons contain similar files and man pages and should contain
+        identifying suffixes (.iss for ezmlm-issub, for example).  For a
+        discussion of the authors' understanding of ezmlm security, see
+        ``Ezmlm-idx security''.
+
+
+     `\b``\b`E\bEz\bzm\bma\ban\bn'\b''\b',\b, a\ban\bn e\bez\bzm\bml\blm\bm/\b/i\bid\bdx\bx m\bma\ban\bnu\bua\bal\bl
+        The ezmlm manual is a brief manual that is meant for list
+        subscribers, list moderators and remote administrators, and as
+        an introduction for list owners. It is useful even if you do not
+        use ezmlm-idx. Features requiring ezmlm-idx are marked as such.
+        The manual is available as a set of html files, as a text file,
+        and in a ``letter'' and ``A4'' postscript version:
+
+     +\bo  ezman for download <ftp://ftp.ezmlm.org/pub/patches/ezman/>
+
+     +\bo  An on-line html version <http://www.ezmlm.org/ezman>
+
+
+     T\bTh\bhi\bis\bs F\bFA\bAQ\bQ
+        This FAQ is built from a sgml source. It is available in the
+        following formats:
+
+     +\bo  A text file <ftp://ftp.ezmlm.org/pub/patches/ezfaq.txt.gz>
+
+     +\bo  An on-line html version <http://www.ezmlm.org/>
+
+     +\bo  Html for download
+        <ftp://ftp.ezmlm.org/pub/patches/ezfaq.html.tar.gz>
+
+     +\bo  A postscript (letter) version
+        <ftp://ftp.ezmlm.org/pub/patches/ezfaq.ps.gz>
+
+     +\bo  A postscript (A4) version
+        <ftp://ftp.ezmlm.org/pub/patches/ezfaq.ps4.gz>
+
+     +\bo  Via mirrors mentioned for the ezmlm-idx package.
+
+     +\bo  An up-to-date text version,F\bFA\bAQ\bQ.\b.i\bid\bdx\bx, included with the ezmlm-idx
+        package.
+
+
+     W\bWW\bWW\bW r\bre\bes\bso\bou\bur\brc\bce\bes\bs
+
+        A\bAn\bn o\bon\bn-\b-l\bli\bin\bne\be v\bve\ber\brs\bsi\bio\bon\bn o\bof\bf t\bth\bhi\bis\bs F\bFA\bAQ\bQ
+           <http://www.ezmlm.org/>The main site with an up-to-date
+           mirror list.  <http://www.de.ezmlm.org/>German mirror.
+           <http://www.pl.ezmlm.org/www.ezmlm.org/>Polish mirror.
+           <http://www.jp.ezmlm.org/>Japanese mirror.
+           <http://www.pt.ezmlm.org/>Portuguese mirror.
+           <http://www.at.ezmlm.org/>Austrian mirror.
+           <http://www.ca.ezmlm.org/ezmlm/>Canadian mirror.
+
+        G\bGe\ben\bne\ber\bra\bal\bl q\bqm\bma\bai\bil\bl a\ban\bnd\bd e\bez\bzm\bml\blm\bm i\bin\bnf\bfo\bo
+
+        +\bo  Dan J. Bernstein's qmail page
+           <http://www.pobox.com/~djb/qmail.html>
+
+        +\bo  Dan J. Bernstein's ezmlm page
+           <http://www.pobox.com/~djb/ezmlm.html>
+
+        +\bo  Russell Nelson's qmail page <http://www.qmail.org>
+
+        +\bo  Mirrors of www.qmail.org <http://www.ISO.qmail.org>.
+           Substitute your two-letter country abbreviation for ``ISO''.
+
+        T\bTh\bhe\be q\bqm\bma\bai\bil\bl m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bt a\bar\brc\bch\bhi\biv\bve\be
+
+
+        +\bo  <http://www.ornl.gov/cts/archives/mailing-lists/qmail/>
+
+        T\bTh\bhe\be e\bez\bzm\bml\blm\bm m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bt a\bar\brc\bch\bhi\biv\bve\be
+
+        +\bo  <http://sunsite.auc.dk/mhonarc-archives/ezmlm/>
+           <http://www.ezmlm.org/archive/> This archive of the ezmlm
+           list is searchable from 11/97-present. ezmlm-cgi(1) is used
+           to allow direct access to the sublist archive.
+
+     M\bMa\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bts\bs
+        Please read other documentation and mailing list archives before
+        posting questions to the lists. It's also useful to ``lurk'' on
+        the list for a few days, (i.e. to subscribe and read without
+        posting) before asking your questions on the list.
+
+        To subscribe, send mail to the E-mail addresses listed:
+
+     +\bo  Dan Bernstein's ezmlm list: ezmlm-subscribe@list.cr.yp.to
+
+     +\bo  A digest version of the ezmlm list fredr-ezmlm-digest-
+        subscribe@rivertown.net
+
+     +\bo  Dan Bernstein's qmail list: qmail-subscribe@list.cr.yp.to
+
+     +\bo  The Japanese ezmlm list: ezmlm-subscribe@jp.qmail.org
+
+     +\bo  The Japanese qmail list: qmail-subscribe@jp.qmail.org
+
+     +\bo  A ezmlm/idx digest list of djb-qmail: qmail-digest-
+        subscribe@id.wustl.edu
+
+     +\bo  A ezmlm/idx sublist of djb-qmail (you can test ezmlm-idx
+        commands): qmail-index@id.wustl.edu
+
+
+  1\b1.\b.7\b7.\b.  W\bWh\bhe\ber\bre\be d\bdo\bo I\bI s\bse\ben\bnd\bd c\bco\bom\bmm\bme\ben\bnt\bts\bs o\bon\bn t\bth\bhi\bis\bs d\bdo\boc\bcu\bum\bme\ben\bnt\bt?\b?
+
+  To the authors via E-mail:
+
+  +\bo  Fred Lindberg, lindberg@id.wustl.edu
+
+  +\bo  Fred B. Ringel, fredr@rivertown.net
+
+
+  1\b1.\b.8\b8.\b.  H\bHo\bow\bw t\bto\bo e\bex\bxp\bpe\ber\bri\bim\bme\ben\bnt\bt w\bwi\bit\bth\bh n\bne\bew\bw v\bve\ber\brs\bsi\bio\bon\bns\bs o\bof\bf e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx.\b.
+
+  ezmlm-idx>=0.23 writes D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg in a standard format.  If ezmlm-
+  make(1) is invoked with the ``-e'' or ``-+'' switch and the ``DIR''
+  argument only, ezmlm-make(1) will read other arguments from this file.
+  The difference between the switches is that with ``-e'' the options
+  used are the ones specified on the command line, whereas with ``-+''
+  they are the ones currently active for the list, as overridden by any
+  command line options.  Thus, with just:
+
+
+               % ezmlm-make -+ DIR
+
+
+
+
+  you can rebuild the list, without affecting any archives, list state
+  variables, etc. You will _\bl_\bo_\bs_\be _\bm_\ba_\bn_\bu_\ba_\bl _\bc_\bu_\bs_\bt_\bo_\bm_\bi_\bz_\ba_\bt_\bi_\bo_\bn_\bs _\bt_\bo _\bs_\bo_\bm_\be _\bo_\bf _\by_\bo_\bu_\br
+  _\bf_\bi_\bl_\be_\bs. However, text files and D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd are protected against
+  being overwritten, so that your manual customizations of these files
+  are retained. To override this protection, simply specify the used
+  edit switch twice, e.g. ``-ee'' and ``-++'', respectively. This is a
+  feature introduced in ezmlm-idx-0.40.
+
+  To test a new version of ezmlm-idx or to run several version, make the
+  new version as per I\bIN\bNS\bST\bTA\bAL\bLL\bL.\b.i\bid\bdx\bx (if you haven't used ezmlm-idx before)
+  or U\bUP\bPG\bGR\bRA\bAD\bDE\bE.\b.i\bid\bdx\bx (if you've got a previous version of ezmlm-idx
+  installed), setting c\bco\bon\bnf\bf-\b-b\bbi\bin\bn to a new directory. You can use either
+  the current directory or any other directory. If not using the current
+  dir, you also have to:
+
+
+               % make setup
+
+
+
+
+  If you now edit the list using the new ezmlm-make program, the list
+  will automatically be configured to use the new binaries. To change
+  back to the ``default'' installation, just edit the list again, this
+  time with the old ezmlm-make(1).
+
+  If your system has an /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc file, you may need to temporarily
+  place the e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) file for the ezmlm version you want to test in
+  d\bdo\bot\btd\bdi\bir\br of the list and use the ezmlm-make(1) ``-c'' switch (see
+  ``Terminology: dotdir'').
+
+  ezmlm-idx>=0.314 comes with ezmlm-test(1), a program that tests most
+  functions of ezmlm+idx and can  be used before installation.
+
+
+  2\b2.\b.  Q\bQu\bui\bic\bck\bk s\bst\bta\bar\brt\bt
+
+
+  1. Create a use ``eztest'' for testing. If you use another name, add
+     the switch ``-u another_name'' to the ezmlm-test(1) line below.
+     (The space between the switch and the argument is required.)
+
+  2. Unpack the ezmlm-0.53 distribution.
+
+  3. Unpack the ezmlm-idx distribution.
+
+  4. Move the ezmlm-idx files to the ezmlm-0.53 directory.
+
+  5. Edit c\bco\bon\bnf\bf-\b-b\bbi\bin\bn and c\bco\bon\bnf\bf-\b-m\bma\ban\bn to reflect the target directories.
+
+  6. build and install:
+
+
+               % cd ezmlm-0.53
+               % patch < idx.patch
+               % make; make man
+               % su
+               # su eztest
+               % ./ezmlm-test
+               % exit
+               # make setup
+               # exit
+
+
+
+
+  7. Make a list and digest list
+
+
+
+
+
+          % ezmlm-make -rdugm -5 me@host ~/list ~/.qmail-list me-list host
+          % ezmlm-sub ~/list me@host
+          % ezmlm-sub ~/list/digest me@host
+          % ezmlm-sub ~/list/mod me@host
+
+
+
+
+  where ``me'' is your user name and ``host'' the host your list is on.
+
+  Now, you are the owner, remote administrator, and subscriber of both
+  list@host and the accompanying digest list list-digest@host. Only
+  subscribers are allowed to access the archive and to post. To post to
+  the list, mail to list@host. For a user to subscribe, s/he should mail
+  to list-subscribe@host and for help to list-help@host.
+
+  When a non-subscriber posts, you will be asked to approve, reject, or
+  ignore the request. If you want to subscriber joe@joehost.dom, mail
+  list-subscribe-joe=joehost.dom@host.
+
+  Digests are generated about every two days, when 30 messages have
+  arrived since the last digest, or when more than 64 kbytes of message
+  body has arrived. To manage the digest list, use the same commands as
+  the main list, but replace ``list'' with ``list-digest''.
+
+  The sender restriction on posting used in this setup works, but is not
+  secure. For more info, read the man pages (start with ezmlm(5) and
+  ezmlm-make(1)), this FAQ (F\bFA\bAQ\bQ.\b.i\bid\bdx\bx in the distribution),
+  R\bRE\bEA\bAD\bDM\bME\bE/\b/R\bRE\bEA\bAD\bDM\bME\bE.\b.i\bid\bdx\bx, I\bIN\bNS\bST\bTA\bAL\bLL\bL/\b/I\bIN\bNS\bST\bTA\bAL\bLL\bL.\b.i\bid\bdx\bx, and U\bUP\bPG\bGR\bRA\bAD\bDE\bE.\b.i\bid\bdx\bx.
+
+
+  3\b3.\b.  O\bOv\bve\ber\brv\bvi\bie\bew\bw o\bof\bf m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bt m\bma\ban\bna\bag\bge\bem\bme\ben\bnt\bt a\ban\bnd\bd m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bt m\bma\ban\bna\bag\bge\ber\brs\bs
+
+  (To be written. Until then, please consult the
+  <http://www.ezmlm.org/ezman/> manual for ezmlm and ezmlm-idx related
+  material.)
+
+
+  4\b4.\b.  O\bOv\bve\ber\brv\bvi\bie\bew\bw o\bof\bf e\bez\bzm\bml\blm\bm f\bfu\bun\bnc\bct\bti\bio\bon\bn
+
+
+  4\b4.\b.1\b1.\b.  T\bTh\bhe\be b\bba\bas\bsi\bic\bc s\bse\bet\btu\bup\bp.\b.
+
+  In designing ezmlm, _\bD_\ba_\bn _\bJ_\b. _\bB_\be_\br_\bn_\bs_\bt_\be_\bi_\bn has used the unix philosophy of
+  small component programs with limited and well defined functions.
+  Requests for specific functions can then be met by the addition of new
+  programs.
+
+  Thanks to the program execution mechanism Dan built into qmail, it is
+  easy to execute several small programs per delivery in a defined
+  sequence. It is also very easy to add shell scripts for further
+  customization.
+
+
+  4\b4.\b.2\b2.\b.  I\bIn\bnv\bve\ben\bnt\bti\bio\bon\bns\bs i\bin\bn e\bez\bzm\bml\blm\bm.\b.
+
+  Dan J. Bernstein has written ezmlm in C. It is written for speed and
+  reliability even in the face of power loss and NFS.  These features
+  are augmented to a large extent by the ruggedness of the qmail (also
+  by Dan) delivery mechanism (see qmail-command(8)).
+
+  ezmlm uses some routines and techniques that still are not frequently
+  seen in many mailing list managers. For example, subscriber E-mail
+  addresses are stored in a hash so that searches require reading only,
+  at most, 2% of the E-mail addresses.  ezmlm has a optional message
+  archive, where messages are stored 100 per directory, again to allow
+  more efficient storage and retrieval. Important files are written
+  under a new name and, only when safely written, moved in place, to
+  assure that crashes do not leave the list in an undefined state.
+
+  In addition, ezmlm has a number of new inventions. One of these is
+  bounce detection, which generates an automatic warning containing
+  information identifying the messages which have bounced, followed by a
+  probe message to the E-mail addresses for which mail has bounced.  If
+  the probe bounces, the address is unsubscribed. Thus, the system won't
+  remove E-mail addresses due to temporary bounces: it takes 12 days
+  after the first bounce before a warning is sent, and another 12 days
+  of bounces after the warning bounce before the probe message is set.
+
+  Another Dan J. Bernstein invention is the use of cryptographic cookies
+  based on a timestamp, address, and action. These are used to assure
+  that the user sending a request to subscribe or unsubscribe really
+  controls the target address.  It is also used to prevent forgery of
+  warning or probe messages to make it exceedingly difficult to subvert
+  the bounce detection mechanism to unsubscribe another user.
+
+
+  4\b4.\b.3\b3.\b.  T\bTh\bhe\be q\bqm\bma\bai\bil\bl d\bde\bel\bli\biv\bve\ber\bry\by m\bme\bec\bch\bha\ban\bni\bis\bsm\bm.\b.
+
+  See qmail(7), qmail-local(8), qmail-command(8), envelopes(5), and dot-
+  qmail(5).  Briefly, qmail having resolved the delivery address
+  delivers it via the .\b.q\bqm\bma\bai\bil\bl file that most completely matches the
+  address. This file may be a link to another file, as is the case in
+  ezmlm lists. qmail then delivers the message according to successive
+  lines in this file forwarding it to an address, storing it, or piping
+  it to a program. In the latter case, the program is expected to exit 0
+  leading delivery to proceed to the next line in the .\b.q\bqm\bma\bai\bil\bl file, or 99
+  leading to success without delivery to succeeding lines. An exit code
+  of 100 is a permanent error leading to an error message to the SENDER.
+  An exit code of 111 is used for temporary errors, leading to re-
+  delivery until successful or until the queue lifetime of the message
+  has been exceeded.
+
+  Delivery granularity is the .\b.q\bqm\bma\bai\bil\bl file and re-deliveries start at the
+  top. Thus, if the message fails temporarily at a later line, the
+  delivery according to an earlier line will be repeated. Similarly,
+  qmail may have made deliveries successfully according to most of the
+  .\b.q\bqm\bma\bai\bil\bl file and then fail permanently. The SENDER is informed that the
+  delivery failed, but not about at which point.
+
+  ezmlm takes advantage of these basic mechanisms to build a fast,
+  efficient, and very configurable mailing list manager from a set of
+  small independent programs.
+
+
+  4\b4.\b.4\b4.\b.  W\bWh\bha\bat\bt t\bth\bhe\be d\bdi\bif\bff\bfe\ber\bre\ben\bnt\bt p\bpr\bro\bog\bgr\bra\bam\bms\bs d\bdo\bo.\b.
+
+  See ezmlm(5) and the man pages for the different programs (listed in
+  ezmlm(5)).
+
+
+  4\b4.\b.5\b5.\b.  W\bWh\bha\bat\bt t\bth\bhe\be d\bdi\bif\bff\bfe\ber\bre\ben\bnt\bt f\bfi\bil\ble\bes\bs i\bin\bn t\bth\bhe\be l\bli\bis\bst\bt d\bdi\bir\bre\bec\bct\bto\bor\bry\by d\bdo\bo.\b.
+
+  See ezmlm(5).
+
+
+  4\b4.\b.6\b6.\b.  T\bTh\bhe\be p\bpa\bap\bpe\ber\br p\bpa\bat\bth\bh f\bfo\bor\br p\bpo\bos\bst\bts\bs.\b.
+
+  Messages to the list are delivered to a .\b.q\bqm\bma\bai\bil\bl file, usually ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-
+  l\bli\bis\bst\btn\bna\bam\bme\be which is linked to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br.  Here, the message is first
+  delivered to ezmlm-reject(1) which can reject messages based on
+  subject line contents, MIME content-type, and message body length. It
+  also by default rejects all messages that do not have the list address
+  in the ``To:'' or ``Cc:'' header. This eliminates most bulk spam. If
+  the list is set up for restrictions based on envelope SENDER, the next
+  delivery is to one or more instances of ezmlm-issubn(1).  If the
+  messages passed this check, it is usually delivered to ezmlm-send(1)
+  for distribution.  If the list is message moderated, it is instead
+  delivered to ezmlm-store(1) which queues the message and sends out a
+  moderation request.  ezmlm-gate(1) is used by some other setups. It
+  will for message moderated lists invoke ezmlm-send(1) directly if the
+  message is from a specific set of SENDERs, and in other cases ezmlm-
+  store(1) to send the message out for moderation.
+
+  You can specify a separate .\b.q\bqm\bma\bai\bil\bl-like file for ezmlm-gate(1).  The
+  lines will be executed and the return codes determine if the message
+  is rejected, sent to the list, or sent to the moderator. See man page
+  for details.
+
+  If the list is configured for digests, D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br also contains an
+  ezmlm-tstdig(1) line followed by an ezmlm-get(1) line. If ezmlm-
+  tstdig(1) determines that the criteria are met for digest generation,
+  it exits with an exit code of 0, causing the ezmlm-get(1) line to be
+  executed leading to a digest mailing. Otherwise, ezmlm-tstdig(1) exits
+  99, resulting in the remainder of the D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br file to be ignored
+  too long. The digest is not related to the message being delivered,
+  but the delivery is used to trigger execution of the relevant
+  programs.
+
+
+  In addition, D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br contains a number of house-keeping functions.
+  These are invocations of ezmlm-warn(1) to send out bounce warnings and
+  and (if the list is moderated) ezmlm-clean(1) to clean the moderation
+  queue of messages that have been ignored. Again, these functions are
+  not related to the specific message delivered, but the delivery itself
+  is used as a convenient ``trigger'' for processing.
+
+
+  4\b4.\b.7\b7.\b.  T\bTh\bhe\be e\bez\bzm\bml\blm\bm p\bpa\bat\bth\bh f\bfo\bor\br m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Replies to moderation requests are channeled to D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br. This
+  file contains an invocation of ezmlm-moderate(1) which invokes ezmlm-
+  send(1) for accepted messages and sends out a rejection notice for
+  rejected messages.  It also sends error messages if the message is not
+  found or already accepted/rejected _\bc_\bo_\bn_\bt_\br_\ba_\br_\by to the moderation message.
+  Thus, if you accept a message already accepted, no error message is
+  sent. ezmlm-clean(1) is also invoked from D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br for house
+  keeping.
+
+
+  4\b4.\b.8\b8.\b.  T\bTh\bhe\be e\bez\bzm\bml\blm\bm p\bpa\bat\bth\bh f\bfo\bor\br a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\biv\bve\be m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Administrative requests for both list and digest lists are captured by
+  ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\btn\bna\bam\bme\be-\b-d\bde\bef\bfa\bau\bul\blt\bt linked to D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br.  Here they are
+  delivered first to ezmlm-get(1) which processed archive retrieval
+  requests, exiting 99 after successful completion which causes the rest
+  of the delivery lines to be ignored. If the request is not for ezmlm-
+  get(1) it rapidly exits 0. This leads to invocation of ezmlm-manage(1)
+  which handles subscriber database functions, help messages, and (if
+  configured) editing of D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ files. Again, ezmlm-warn(1) lines are
+  included for bounce directory processing.
+
+  If configured, an ezmlm-request(1) line is present. This program
+  constructs valid ezmlm requests from command in the subject lines of
+  messages sent to listname-request@host and exits 99. These requests
+  are mailed and will then return to be processed by one of the other
+  programs.
+
+  4\b4.\b.9\b9.\b.  T\bTh\bhe\be e\bez\bzm\bml\blm\bm p\bpa\bat\bth\bh f\bfo\bor\br b\bbo\bou\bun\bnc\bce\bes\bs.\b.
+
+  Bounces to the list are handled by D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\ber\br. For the digest list
+  this is D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/b\bbo\bou\bun\bnc\bce\ber\br. The two were combined in previous
+  versions, which is still supported. As this leads to problems with
+  list names ending in ``digest'', the functions are separate with lists
+  set up or edited with ezmlm-idx>=0.32. The bounce is first delivery is
+  to ezmlm-weed(1) which removes delivery delay notification and other
+  junk. The second to ezmlm-return(1) which analyzes valid bounces
+  storing the information in D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\be/\b/ for the list and
+  D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/b\bbo\bou\bun\bnc\bce\be/\b/ for the digest.  This is the information that
+  ezmlm-warn(1) (invoked from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br) uses and
+  processes for automatic bounce handling.  ezmlm-return(1) will also
+  unsubscribe a subscriber from whom a probe message has bounced.
+
+
+  4\b4.\b.1\b10\b0.\b.  M\bMe\bes\bss\bsa\bag\bge\bes\bs t\bto\bo l\bli\bis\bst\bt-\b-o\bow\bwn\bne\ber\br a\ban\bnd\bd l\bli\bis\bst\bt-\b-d\bdi\big\bge\bes\bst\bt-\b-o\bow\bwn\bne\ber\br.\b.
+
+  These are processed by D\bDI\bIR\bR/\b/o\bow\bwn\bne\ber\br and delivered to D\bDI\bIR\bR/\b/m\bma\bai\bil\blb\bbo\box\bx by
+  default. It is better to put the real owner address in this location.
+  This can be done manually, via editing of e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b), or via the
+  ezmlm-make(1) -5 switch. Again, some house-keeping functions are also
+  executed.
+
+
+  4\b4.\b.1\b11\b1.\b.  S\bSt\btr\bru\buc\bct\btu\bur\bre\be o\bof\bf s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br d\bda\bat\bta\bab\bba\bas\bse\bes\bs.\b.
+
+  ezmlm subscriber E-mail addresses are stored within D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/
+  as a hashed set of 53 files. The hash calculated from the address
+  determines which of the 53 files and address is stored in. Thus, to
+  find out if an address is a subscriber, ezmlm has to read at most
+  about 2% of the E-mail addresses.  The hash function insures that E-
+  mail addresses are reasonably evenly distributed among the 53 files.
+
+  Addresses in the files in D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/ are stored as strings
+  starting with ``T'', followed by the address, followed by a zero byte.
+  This is the same format as taken by qmail-queue(8) on file descriptor
+  1.  Thus, subscriber lists can be directly copied to qmail without any
+  further processing.
+
+  With ezmlm-idx>=0.32 you can use an SQL server for the subscriber
+  databases.  Please see the SQL section (``ezmlm support for SQL
+  datbases'').
+
+
+  4\b4.\b.1\b12\b2.\b.  L\bLo\boc\bca\bal\bl c\bca\bas\bse\be i\bin\bn E\bE-\b-m\bma\bai\bil\bl a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs.\b.
+
+  rfc822 states that the host part of an address is case insensitive,
+  but that case of the local part should be respected and the
+  interpretation of it is the prerogative of the machine where the
+  mailbox exists.  Thus, ezmlm preserves the case of the local part, but
+  converts the host part to lower case. ezmlm proper also bases the hash
+  on the case of the local part, so that USER@host and user@host are not
+  (usually) stored in the same file.
+
+  Locally, deliveries are most often case insensitive, i.e. mail to
+  USER@host and user@host are delivered to the same mail box. A
+  consequence of this is that many users use E-mail addresses with
+  different case interchangeably.  The problem is that when USER@host is
+  subscribed, ezmlm will not find that address in response to an
+  unsubscribe request from user@host. This is even more problematic when
+  E-mail addresses have been added by hand to e.g. moderator lists.
+
+  ezmlm-idx>=0.22 changes address storage to make comparisons case
+  insensitive and store E-mail addresses based on the hash of the all
+  lower case address. Case is maintained for the local part. Thus, if
+  USER@host is subscribed, mail is set to USER@host, but user@host is
+  recognized as a subscriber and an unsubscribe request from user@host
+  will remove USER@host from the subscriber list.
+
+  To maintain backwards compatibility with old subscriber lists, a
+  second lookup is made for partially upper case E-mail addresses in
+  some cases. This will find USER@host subscribed with a case sensitive
+  hash as well.
+
+  If may be useful to move all old mixed case E-mail addresses to the
+  ``new'' positions.  Without this, USER@host subscribed with the old
+  system will be able to unsubscribe as USER@host, but not as user@host.
+  After the repositioning, s/he will be successfully able to use any
+  case in an unsubscribe request, e.g. UsEr@host. To do this:
+
+
+
+       % ezmlm-list DIR | grep -G '[A-Z]' > tmp.tmp
+       % xargs ezmlm-sub DIR < tmp.tmp
+
+
+
+
+  This works, because subscribing an address, even if it already exists,
+  will assure that it is stored with a case insensitive hash. On some
+  systems, the grep ``-G'' switch need/should not be used.
+
+
+  4\b4.\b.1\b13\b3.\b.  T\bTe\bes\bst\bti\bin\bng\bg S\bSE\bEN\bND\bDE\bER\bR t\bto\bo a\bal\bll\blo\bow\bw p\bpo\bos\bst\bts\bs o\bon\bnl\bly\by f\bfr\bro\bom\bm l\bli\bis\bst\bt s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.
+
+  This mode of operation is automatically set up if you specify the
+  ezmlm-make(1) ``-u'' switch. Since there may be some addresses that
+  should be allowed to post, but are not subscribers of list or list-
+  digest, ezmlm-make(1) sets up an additional address database in
+  D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/.  Use ezmlm-sub(1), ezmlm-unsub(1), and ezmlm-list(1) to
+  manipulate these addresses. If the list is configured for remote
+  administration (see ``How remote administration works''), you can
+  add/remove addresses from the D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/ database by mailing list-
+  allow-subscribe@listhost and list-allow-unsubscribe@listhost,
+  respectively. Other commands that access subscriber databases work in
+  the same manner.
+
+  To similarly restrict archive access, use the ezmlm-make(1) ``-g''
+  switch.
+
+  Since SENDER is under the control of a potential attacker, it is not
+  secure to use tests of SENDER for anything important. However, when
+  replies are always sent to SENDER (such as for archive access), a
+  check of SENDER can prevent the sending of information to E-mail
+  addresses not in the database.
+
+  To test sender, use the program ezmlm-issubn(1). It will return 0
+  (true for the shell, success for qmail deliveries) if SENDER is in at
+  least one of a set of subscriber databases. If not, it will return 99
+  (false for the shell: success, but skip remainder of .\b.q\bqm\bma\bai\bil\bl file for
+  qmail deliveries). The basedirs of the subscriber lists (i.e. the
+  directories in which the ``subscriber'' dirs are located) are given as
+  arguments.  ezmlm-issubn(1) can take any number of arguments.
+
+  Thus, to permit an action if SENDER is a subscriber to the list in any
+  of D\bDI\bIR\bR/\b/, D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/, or D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/ and exit silently, put the
+  following into the relevant .\b.q\bqm\bma\bai\bil\bl file:
+
+
+
+
+  |/usr/local/bin/ezmlm/ezmlm-issubn DIR DIR/digest DIR/allow [...]
+  |/path/action_program
+
+
+
+
+  Restricting your list to posts from your subscribers is as easy as
+  that. If your ezmlm binaries are in a different directory, you may
+  have to modify the ezmlm-issubn(1) path.
+
+  ezmlm-issubn(1) has a ``-n'' switch which ``negates/reverses'' the
+  exit code.  To do an action if SENDER is _\bN_\bO_\bT a subscriber of any of
+  the lists:
+
+
+
+       |/usr/local/bin/ezmlm/ezmlm-issubn -n DIR/deny [dir2 ...]
+       |/path/other_program
+
+
+
+
+  To automatically configure the list with a blacklist address database
+  in D\bDI\bIR\bR/\b/d\bde\ben\bny\by, use the ezmlm-make(1) ``-k'' switch. If the list is
+  configured for remote administration (see ``How remote administration
+  works'') and if you are a remote administrator, you can manipulate the
+  ``deny'' database remotely by sending mail to list-deny-subscribe-
+  user=userhost@listhost, etc.
+
+
+  4\b4.\b.1\b14\b4.\b.  H\bHo\bow\bw c\bco\boo\bok\bki\bie\bes\bs w\bwo\bor\brk\bk.\b.
+
+  Each ezmlm list has it's own ``key'' created by ezmlm-make at setup
+  time.  This key is stored in D\bDI\bIR\bR/\b/k\bke\bey\by, and you can improve it by adding
+  garbage of your own to it. However, changing the key will make all
+  outstanding cookies invalid, so this should be done when the list is
+  established.
+
+  When ezmlm receives an action request, such as ``subscribe'', it
+  constructs a cookie as a function of:
+
+  +\bo  the request,
+
+  +\bo  the time,
+
+  +\bo  and the target address.
+
+     The cookie and these items are then assembled into a address that
+     is sent out as the ``Reply-To:'' address in the confirmation
+     request sent to the subscriber. When the subscriber replies, ezmlm
+     first checks if the timestamp is more than 1,000,000 seconds old
+     (approx 11.6 days) and rejects the request if it is. Next, ezmlm
+     recalculates the cookie from the items.  If the cookies match, the
+     request is valid and will be completed. Depending on the
+     circumstances, ezmlm generates an error message or a new cookie
+     based on the current time and sends the target a new confirmation
+     request.
+
+  Dan has based these cookies on cryptographic functions that make it
+  very unlikely that a change in any part of the cookie or the items
+  will result in a valid combination. Thus, it is virtually impossible
+  to forge a request even for someone who has a number of valid requests
+  to analyze. Since the algorithm ezmlm uses is available, the security
+  rests on the key (and the correctness of the algorithm). Anyone who
+  knows the key for your lists can easily construct valid requests.
+
+  As ezmlm-make(1) doesn't use a truly random process to generate the
+  key, it is theoretically possible that someone with sufficient
+  knowledge about your system can guess your key. In practice, this is
+  very unlikely, and the safety of the system is orders of magnitude
+  higher than that of other mechanisms that you may rely on in your list
+  management and mail transport (exclusive of strong encryption, such as
+  _\bP_\bG_\bP).
+
+
+  4\b4.\b.1\b15\b5.\b.  H\bHo\bow\bw m\bmo\bod\bde\ber\bra\bat\bto\bor\br E\bE-\b-m\bma\bai\bil\bl a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs a\bar\bre\be s\bst\bto\bor\bre\bed\bd.\b.
+
+  Moderator E-mail addresses are stored just like ezmlm subscriber
+  addresses, in a set of up to 53 files within the s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs
+  subdirectory of the list's b\bba\bas\bse\bed\bdi\bir\br/\b/.  For subscribers, the b\bba\bas\bse\bed\bdi\bir\br/\b/ is
+  the list directory itself, i.e. D\bDI\bIR\bR/\b/.  For moderators, the default is
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/, which can be overridden by placing a b\bba\bas\bse\bed\bdi\bir\br name (starting
+  with a ``/'') in D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb, D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be, or D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt for
+  subscription moderation, remote administration, and message
+  moderation, respectively. This permits the use of one moderator
+  database for multiple lists. _\bN_\bo_\bt_\be_\b: _\bS_\bu_\bb_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bm_\bo_\bd_\be_\br_\ba_\bt_\bo_\br_\bs _\ba_\bn_\bd _\br_\be_\bm_\bo_\bt_\be
+  _\ba_\bd_\bm_\bi_\bn_\bi_\bs_\bt_\br_\ba_\bt_\bo_\br_\bs _\ba_\br_\be _\ba_\bl_\bw_\ba_\by_\bs _\bt_\bh_\be _\bs_\ba_\bm_\be _\ba_\bd_\bd_\br_\be_\bs_\bs_\be_\bs_\b. _\bI_\bf _\bb_\bo_\bt_\bh D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb and
+  D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be contain paths, only the D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb path is used.
+
+
+  4\b4.\b.1\b16\b6.\b.  H\bHo\bow\bw s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn w\bwo\bor\brk\bks\bs.\b.
+
+  Subscription moderation is a simple extension of the ezmlm subscribe
+  mechanism. Once the user has confirmed the subscribe request, a new
+  request is constructed with a _\bd_\bi_\bf_\bf_\be_\br_\be_\bn_\bt _\ba_\bc_\bt_\bi_\bo_\bn _\bc_\bo_\bd_\be. This is sent out
+  to the moderator(s). When a moderator replies with a valid request and
+  cookie combination, the user is subscribed. The user is then also
+  welcomed to the list. Other moderators won't know that the request has
+  already been approved. If other moderators reply to the request, no
+  notification of the duplicate action is sent to the subscriber of the
+  duplicate action. Ezmlm knows that this is a repeat request since the
+  target address is already a subscriber.
+
+  The moderators are not informed about the result, unless there was an
+  error (subscribing a target that is already a subscriber is not
+  considered an error). This cuts down the number of messages a
+  moderator receives. Any list moderator knows (or _\bs_\bh_\bo_\bu_\bl_\bd know) the
+  qmail/ezmlm/unix paradigm: _\bi_\bf _\by_\bo_\bu_\b'_\br_\be _\bn_\bo_\bt _\bt_\bo_\bl_\bd _\bo_\bt_\bh_\be_\br_\bw_\bi_\bs_\be_\b, _\by_\bo_\bu_\br _\bc_\bo_\bm_\bm_\ba_\bn_\bd
+  _\bw_\ba_\bs _\bc_\ba_\br_\br_\bi_\be_\bd _\bo_\bu_\bt _\bs_\bu_\bc_\bc_\be_\bs_\bs_\bf_\bu_\bl_\bl_\by.  This may be counterintuitive to those
+  used to some other operating systems, but in our experience it doesn't
+  take long to get used to the reliability and efficiency of
+  U*ix/qmail/ezmlm.
+
+  Subscription moderation is enabled by creating D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb and adding
+  the subscription moderator to D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/:
+
+
+       % ezmlm-sub DIR/mod moderator@host
+
+
+
+
+  To use an alternative basedir for subscription moderators, place that
+  directory name with a leading ``/'' in D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb.
+
+
+  4\b4.\b.1\b17\b7.\b.  H\bHo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\bio\bon\bn w\bwo\bor\brk\bks\bs.\b.
+
+  The term ``remote administration'' is used to denote the ability of a
+  list administrator by E-mail to add or remove any E-mail address from
+  the subscriber list without the cooperation of the user. Normally,
+  when user@userhost sends a message to list-subscribe-
+  other=otherhost@listhost to subscribe other@otherhost, the
+  confirmation request goes to other@otherhost. However, if remote
+  administration is enabled and user@userhost is a moderator, a
+  confirmation request (with a different action code) is sent back to
+  user@userhost instead. The reply from the administrator is suppressed
+  in the welcome message sent to the new subscriber (other@otherhost).
+  This protects the identity of the remote administrator.
+
+  Remote administration is enabled by creating D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be and adding the
+  remote administrator E-mail address(es) to D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/:
+
+
+       % ezmlm-sub DIR/mod remoteadm@host
+
+
+
+
+  To use an alternative basedir for remote administrators, place that
+  directory name with a leading ``/'' in D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb.  Remote administra-
+  tors and subscription moderators databases always consist of the same
+  E-mail addresses.  If both are enabled and one of D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb and
+  D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be contains an alternative basedir name, this basedir is used
+  for both functions.  If both D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb and D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be contain direc-
+  tory names, the one in D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb is used for both functions.
+
+  Remote administrators can add and remove addresses to the digest list,
+  the ``allow'' list (user aliases for lists using SENDER restrictions
+  on posting and archive access), and if used the ``deny'' list
+  containing addresses that are denied posting rights to the list. The
+  latter is easy to circumvent and intended to block errant mail robots,
+  rather than human users.
+
+
+  4\b4.\b.1\b18\b8.\b.  H\bHo\bow\bw m\bme\bes\bss\bsa\bag\bge\be m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn w\bwo\bor\brk\bks\bs.\b.
+
+  ezmlm-store(1), invoked in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br, receives messages for message
+  moderated lists. If D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt does not exist, ezmlm-store(1) just
+  calls ezmlm-send(1) and the message is posted to the list as if it
+  were not moderated.  If D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt exists, ezmlm-store(1) places the
+  message in D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/.  It also sends a moderation request to
+  all the moderators. Included with this request is a copy of the
+  message.  The ``From:'' and ``Reply-To:'' E-mail addresses contain
+  codes for ``reject'' and ``accept'', together with a unique message
+  name (derived from the message timestamp and process id) and a cookie
+  based on these items.  When a moderator replies, ezmlm-moderate(1) is
+  invoked via D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br.  ezmlm-moderate(1) validates the request,
+  and if the request is valid and the message is found in
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/, it carries out the requested action.
+
+  If the request is ``reject'' the post is returned to SENDER with an
+  explanation and an optional moderator comment. If the request is
+  ``accept'' the message is posted to the list via ezmlm-send(1). As the
+  request is processed, a stub for the message is created in
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/r\bre\bej\bje\bec\bct\bte\bed\bd/\b/ or D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/a\bac\bcc\bce\bep\bpt\bte\bed\bd/\b/ for ``reject'' and ``accept''
+  requests, respectively.
+
+  If a valid reply is received but the message is no longer in
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/, ezmlm-moderate(1) looks for the corresponding stub
+  in D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/r\bre\bej\bje\bec\bct\bte\bed\bd/\b/ and D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/a\bac\bcc\bce\bep\bpt\bte\bed\bd/\b/.  If the stub is found and
+  the fate of the message was the one dictated by the new request, no
+  further action is taken. If, however, no stub is found or the request
+  and the actual message fate do not match, a notification is sent to
+  the moderator. This scheme was chosen to impart a maximum of
+  information with a minimum of messages. Also, it is the least
+  demoralizing setup for multiple moderator lists, where it is important
+  not to notify subsequent moderators that their work was in vain since
+  the action of the first responding moderator has already resulted in
+  processing of the message.
+
+  If a message is not ``rejected'' or ``accepted'' it remains in
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/ until it times out. Cleanup of both messages and
+  stubs is accomplished by ezmlm-clean(1) which is invoked through both
+  D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br for message moderated lists. ezmlm-
+  clean(1) looks at the timestamp used to generate the message/stub
+  name. If it is older than 120 hours (configurable in a range of 24-240
+  hours, by placing the value in D\bDI\bIR\bR/\b/m\bmo\bod\bdt\bti\bim\bme\be) it is removed.  Unless
+  suppressed with the ezmlm-clean(1) ``-R'' switch, the SENDER of the
+  message is notified.
+
+  By default, the E-mail addresses of message moderators are stored as a
+  subscriber list with a basedir of D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/.  This can be changed to
+  any other b\bba\bas\bse\bed\bdi\bir\br by placing the name of that directory with a leading
+  ``/'' in D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt.  Although the default basedirs for message
+  moderation and subscription moderation/remote administration are the
+  same, both the functions and actors are entirely independent.
+
+
+  4\b4.\b.1\b19\b9.\b.  H\bHo\bow\bw Q\bQM\bMQ\bQP\bP s\bsu\bup\bpp\bpo\bor\brt\bt w\bwo\bor\brk\bks\bs
+
+  qmail processes messages on a first-come-first-served basis. This
+  means that when it receives a post to 100,000 subscribers, it will try
+  all the recipients before processing the next message. Often, it is
+  desirable to offload this work to an external host so that the main
+  list host remains responsive to e.g. ``subscribe'' and archive access
+  commands, as well as to other mail is it is not a dedicated mail host.
+
+  ezmlm-idx allows the main distribution work to be offloaded to an
+  external server via the QMQP protocol. Configure qmail-qmqpc(1) on the
+  list host, and qmail-qmqpd(1) on the mail host (see qmail docs for
+  details), then create the file D\bDI\bIR\bR/\b/q\bqm\bmq\bqp\bps\bse\ber\brv\bve\ber\brs\bs/\b/0\b0. The list housed in
+  D\bDI\bIR\bR will now use the QMQP server for posts, by the local qmail for
+  other messages. If you apply the qmail-qmqpc.tar.gz patch (included in
+  the ezmlm-idx distribution), you can specify the QMQP server IP
+  addresses, one per line, in D\bDI\bIR\bR/\b/q\bqm\bmq\bqp\bps\bse\ber\brv\bve\ber\brs\bs/\b/0\b0, just as you normally
+  would in /\b/v\bva\bar\br/\b/q\bqm\bma\bai\bil\bl/\b/c\bco\bon\bnt\btr\bro\bol\bl/\b/q\bqm\bmq\bqp\bps\bse\ber\brv\bve\ber\brs\bs.  If the first server cannot
+  be contacted, the installation will try the second, and so on. The
+  advantage of controlling the servers locally is that you can specify
+  different servers for different lists. A good idea is to set up also
+  the list host as a QMQP server and use that as the last IP address.
+  This way, the list host will be used if the main QMQP server cannot be
+  contacted. Of course, ezmlm does not loose messages, but rather lets
+  qmail redeliver the post if no QMQP server is available.
+
+
+  4\b4.\b.2\b20\b0.\b.  H\bHo\bow\bw m\bme\bes\bss\bsa\bag\bge\bes\bs a\bar\bre\be s\bst\bto\bor\bre\bed\bd i\bin\bn t\bth\bhe\be a\bar\brc\bch\bhi\biv\bve\be.\b.
+
+  The structure of the ezmlm list archive is described in the ezmlm(5)
+  manual page.  Basically, the message is stored in D\bDI\bIR\bR/\b/a\bar\brc\bch\bhi\biv\bve\be/\b/n\bn/\b/m\bm,
+  where ``n'' is the message number divided by 100 and ``m'' the
+  remainder (2 digits). The first message is stored in D\bDI\bIR\bR/\b/a\bar\brc\bch\bhi\biv\bve\be/\b/0\b0/\b/0\b01\b1.
+
+
+  4\b4.\b.2\b21\b1.\b.  H\bHo\bow\bw t\bth\bhe\be m\bme\bes\bss\bsa\bag\bge\be i\bin\bnd\bde\bex\bx w\bwo\bor\brk\bks\bs.\b.
+
+  The ezmlm-idx(1) adds the option (default) of a message index to
+  ezmlm.  The ``From:'' line, the subject, the author's E-mail address
+  and name and the time of receipt are logged for each message as it is
+  received. The subject is ``normalized'' by concatenating split lines
+  and removing reply-indicators such as ``Re:''. A hash of the
+  normalized subject with all white space removed is also stored.  The
+  hash for any message within a thread is almost always the same and is
+  used together with the order of receipt to connect a set of messages
+  into a ``thread''. A hash is needed due to the inconsistent handling
+  by MUAs of white space in rfc2047-encoded subject headers.
+
+  The message index is stored as D\bDI\bIR\bR/\b/a\bar\brc\bch\bhi\biv\bve\be/\b/n\bn/\b/i\bin\bnd\bde\bex\bx, where ``n'' is the
+  message number mod 100.  Thus, the directory D\bDI\bIR\bR/\b/a\bar\brc\bch\bhi\biv\bve\be/\b/5\b52\b2/\b/ stores
+  messages 5200 through 5299 and the file ``index'' which contains the
+  index for those messages.
+
+  The message index can be retrieved with the -index command (see ezmlm-
+  get(1)). You can also retrieve a range of messages, a specific thread,
+  or generate a message digest (see ezmlm-get(1)). Each of these
+  commands can be disabled or restricted as desired by the list owner.
+
+  The ezmlm-idx(1) can be used at any time to either reconstruct an
+  existing index or create one an index for an existing message archive.
+  without one.
+
+
+  4\b4.\b.2\b22\b2.\b.  H\bHo\bow\bw t\bth\bhr\bre\bea\bad\bdi\bin\bng\bg w\bwo\bor\brk\bks\bs.\b.
+
+  A ezmlm thread is just a message number-ordered set of messages with
+  identical ``normalized'' subject entries. This is a very reliable
+  method for threading messages. It does not rely on any variably
+  present ``In-Reply-To:'' or ``References:'' headers. If the subject
+  changes, the continuation becomes a separate thread very close to the
+  original thread in a digest. ezmlm uses this mechanism to return
+  message sets threaded and with a thread and author index, unless
+  specifically told not to do so with the ``n'' format specifier.
+  Naturally, lists set up without a message index (using the ezmlm-make
+  ``-I'' switch) do not maintain thread information.
+
+
+  4\b4.\b.2\b23\b3.\b.  H\bHo\bow\bw d\bdi\big\bge\bes\bst\bts\bs w\bwo\bor\brk\bk.\b.
+
+  A ``digest'' is just an ordered collection of messages from a list,
+  usually sent out regularly depending on the time and traffic volume
+  since the last digest. Digest subscribers thus can read messages as
+  ``threads'' once daily, rather than receiving a constant trickle of
+  messages.
+
+  As a major change in ezmlm-idx-0.30, the digest is no longer a totally
+  separate ezmlm-list, but a part of the main list. This has security
+  advantages, makes setup and administration easier, saves space, and
+  allows a consistent way for subscribers of both ``list'' and ``list-
+  digest'' to retrieve missed messages from a single archive.
+
+  The digest of the list ``list'' is always called ``list-digest''. To
+  set up a list with a digest, simply use the ezmlm-make(1) ``-d''
+  switch. You subscribe to and unsubscribe from a digest the same way as
+  for the main list, except that the request is sent to e.g. list-
+  digest-subscribe@host rather than to list-subscribe@host.
+
+  Any option such as remote admin or subscription moderation that is
+  active for the list applies also to the digest list. Any restrictions
+  in posts or archive retrieval set up for the list, automatically
+  accept both subscribers of the main list and of the digest list.
+
+  The changes in ezmlm-idx>=0.30 allow all programs to service both list
+  and list-digest functions.  All digest-specific files are stored in
+  D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/.  Digest list subscriber addresses in
+  D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/ and digest list bounce information in
+  D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/b\bbo\bou\bun\bnc\bce\be/\b/. Text files are shared between list and digest. To
+  get the local part of the list or list-digest name in a context
+  sensitive manner, use ``<#l#>'' (lower case ``L'') in the text file.
+
+
+  In order to generate digest, the list needs to be archived and indexed
+  (both default).  You can retrieve sets of messages from the message
+  archive. Such sets are always returned to the SENDER of the request.
+  ``Digests'' are a special form of such a set/request. First, there are
+  no restrictions on the number of messages that can be in a digest
+  (which is balanced by the requirement for a ``digest code'' that needs
+  to be specified in order to create a digest based on a mailed
+  request).  Second, special files (D\bDI\bIR\bR/\b/d\bdi\big\bgi\bis\bss\bsu\bue\be and D\bDI\bIR\bR/\b/d\bdi\big\bgn\bnu\bum\bm) keep
+  track of the digest issue and the message number, amount, and time
+  when the last digest was created.  Thus, the system is adapted to make
+  it easy to create the regular collections of messages commonly
+  referred to as ``digests''.
+
+  Digest can be generated in several different ways:
+
+     C\bCo\bom\bmm\bma\ban\bnd\bd l\bli\bin\bne\be
+        ezmlm-get can be invoked on the command line, or via a script
+        from e.g.  crond(8):
+
+
+                  % ezmlm-get DIR
+
+
+
+
+     If for some reason the digest should be disseminated via a separate
+     list, the digest can be redirected to a ``target address'' with the
+     ezmlm-get(1) ``-t'' switch. This may be useful if a non-standard
+     digest list name is required. In this case, the list disseminating
+     the digest must be set up as a sublist of the main list (see ``How
+     sublists work'').
+
+
+     f\bfr\bro\bom\bm D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br
+        This is the default and does not require and additional setup.
+        It works well with most lists. The only possible advantage is
+        for very low traffic lists and for lists where it is important
+        that a digest be sent out at a specific time (as D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br
+        digests are triggered only when messages are received).
+
+        In D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br, ezmlm-get(1) needs to be combined with ezmlm-
+        tstdig(1) so that digests are generated only if certain criteria
+        are met (in this case, more than 30 messages, 64 kbytes of
+        message body or 48 hours since the latest digest). Add these
+        lines after the ezmlm-send line in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br:
+
+
+                  |/usr/local/bin/ezmlm/ezmlm-tstdig -t48 -m30 -k64 DIR || exit 99
+                  |/usr/local/bin/ezmlm/ezmlm-get diglist@host DIR || exit 0
+
+
+
+
+     To set this up automatically when you create the list:
+
+
+                  % ezmlm-make -d DIR dot local host [code]
+
+
+
+
+     Again, the ezmlm-get(1) ``-t'' switch can be used for non-standard
+     arrangements to redirect the digest.  The ezmlm-make(1) ``-4''
+     switch can be used to specify alternative ezmlm-tstdig(1) parame-
+     ters.
+
+     f\bfr\bro\bom\bm D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br
+        This is useful only if you want digests at specific times, and
+        you do not have access to crond(8) on the list host.  ezmlm-
+        get(1) is in it's normal place in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br before ezmlm-
+        manage(1), but a digest code is specified in the ezmlm-get(1)
+        command line. To trigger digests requires a regular trigger
+        messages generated from e.g. crond(8) (see below), but this can
+        be done from _any_ host, not only the list host.  ezmlm-make(1)
+        sets up ezmlm-get(1) this way if a digest ``code'' is given as
+        the 5th ezmlm-make(1) command line argument. However, you need
+        to set up the trigger messages separately (see below):
+
+
+                  % ezmlm-make DIR dot local host code
+
+
+
+
+     To also test for message volume with this setup, generate trigger
+     messages with the granularity you'd like, and add a ezmlm-tstdig(1)
+     line to D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. E.g., use a trigger message every 3 hours and
+     the following ezmlm-tstdig(1) line before ezmlm-get(1):
+
+
+                  |/usr/local/bin/ezmlm/ezmlm-tstdig -t24 -m30 -k64 DIR || exit 99
+
+
+
+
+     In general, a cron-triggered digest is preferred for very large
+     lists and for lists with very low traffic.  Again, the ezmlm-get(1)
+     ``-t'' switch can be used for non-standard arrangements to redirect
+     the digest.  For most lists, the digesting from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br works
+     very well, and does not require any extra setup work.
+
+     C\bCo\bom\bmb\bbi\bin\bna\bat\bti\bio\bon\bn s\bse\bet\btu\bup\bps\bs
+        The default setup in the ezmlmrc(5) file included in the
+        distribution is the D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br triggered setup described above.
+        If you in addition use ezmlm-cron(1) or crond(8) directly to
+        generate trigger messages to list-dig.code@host, you can get
+        regular digests (via the trigger messages and D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br), with
+        extra digest sent when traffic is unusually high (via the ezmlm-
+        tstdig/ezmlm-get limits set in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br).  This works best
+        when the time argument on the ezmlm-tstdig(1) command line is
+        the same as the trigger message interval, and the other ezmlm-
+        tstdig(1) parameters are set so that they are only rarely
+        exceeded within the normal digest interval.
+
+
+  4\b4.\b.2\b24\b4.\b.  H\bHo\bow\bw W\bWW\bWW\bW a\bar\brc\bch\bhi\biv\bve\be a\bac\bcc\bce\bes\bss\bs w\bwo\bor\brk\bks\bs.\b.
+
+  If the list is set up with ezmlm-make -i, ezmlm-archive(1) will be
+  invoked from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br. This program creates indices for threads,
+  subjects, and authors under D\bDI\bIR\bR/\b/a\bar\brc\bch\bhi\biv\bve\be from the i\bin\bnd\bde\bex\bx files.  ezmlm-
+  cgi(1) is set up per user or globally (see man page) and told about
+  different lists via the /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bm/\b/e\bez\bzc\bcg\bgi\bir\brc\bc file. ezmlm-cgi(1) presents
+  and used the index created by ezmlm-archive(1) and converts these and
+  the messages to html on-the-fly. To be as efficient as possible,
+  ezmlm-cgi(1) outputs only basic html. However, style sheets are
+  supported and can be used to customize formatting without modification
+  of ezmlm-cgi(1).  Extra buttons can be added via the config file. See
+  man page for details.
+
+
+
+
+  4\b4.\b.2\b25\b5.\b.  H\bHo\bow\bw e\bez\bzm\bml\blm\bm-\b-t\bts\bst\btd\bdi\big\bg w\bwo\bor\brk\bks\bs.\b.
+
+  ezmlm-tstdig(1) looks at D\bDI\bIR\bR/\b/n\bnu\bum\bm and D\bDI\bIR\bR/\b/d\bdi\big\bgn\bnu\bum\bm to determine how many
+  messages and how much traffic (in terms of bytes of message body) has
+  arrived to the list since the latest digest. It also determines how
+  much time has passed since the last digest was generated. If any of
+  the criteria specified by command line switches exists, ezmlm-
+  tstdig(1) exits 0, causing the invocation of the next line in the
+  .qmail file. If not, ezmlm-tstdig(1) exits 99 causing qmail to skip
+  the rest of the .qmail file. ezmlm-tstdig(1) looks at LOCAL to
+  determine if it is invoked in the command line, in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br, or in
+  D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. In the latter two cases, ezmlm-tstdig(1) verifies that
+  the list local address is correct. If invoked in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br, ezmlm-
+  tstdig(1) exits 0 for all action requests except list-dig, so that is
+  does not interfere with the normal functions of ezmlm-get(1) and
+  ezmlm-manage(1). ezmlm-tstdig(1) uses D\bDI\bIR\bR/\b/t\bts\bst\btd\bdi\big\bg as a flag to avoid
+  problems caused by starting the program when another copy is already
+  running.
+
+  ezmlm-make(1) automatically configures ezmlm-tstdig(1) with the
+  parameters ``-t48 -m30 -k64'', which can be overridden with the ``-3''
+  switch.
+
+
+  4\b4.\b.2\b26\b6.\b.  H\bHo\bow\bw s\bsu\bub\bbl\bli\bis\bst\bts\bs w\bwo\bor\brk\bk.\b.
+
+  ezmlm uses the concept of sublists.  Sublists are regular ezmlm lists,
+  except that they only accept messages from their parent list, which is
+  placed in the file D\bDI\bIR\bR/\b/s\bsu\bub\bbl\bli\bis\bst\bt.
+
+  sublists are used to split the load of a large mailing list among
+  several hosts. All you need to do to set up a local sublist of e.g.
+  the qmail@list.cr.yp.to list is to create a ezmlm list, and put
+  ``qmail@list.cr.yp.to'' into D\bDI\bIR\bR/\b/s\bsu\bub\bbl\bli\bis\bst\bt of you list, and subscribe
+  the sublist to the main qmail list. Now anyone can subscribe to your
+  local list which handles its own bounces, subscribe requests, etc.
+  The load on the main list is only the single message to your local
+  list.
+
+  Sublists will not add their own mailing list header and they will not
+  add a subject prefix. Normally, sublists will use their own message
+  number, rather than that used by the main list.  With ezmlm-idx>=0.23,
+  sublists that are not archived and not indexed, will instead use the
+  main list message number. This way, bounce messages from the sublist
+  can refer the subscriber to the main list archive. This is not done
+  for indexed/archived sublists for security reasons (an attacker could
+  overwrite messages in the sublist archive).
+
+  With ezmlm-idx>=0.31, there is support for using ezmlm as a sublist of
+  a mailing list run by another mailing list manager. To set this up,
+  set up a normal ezmlm sublist, then edit D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br so that the _\be_\bz_\bm_\bl_\bm_\b-
+  _\bs_\be_\bn_\bd line contains the command line option ``-\b-h\bh _\bX_\b-_\bL_\bi_\bs_\bt_\bp_\br_\bo_\bc_\be_\bs_\bs_\bo_\br_\b-
+  _\bV_\be_\br_\bs_\bi_\bo_\bn_\b:'' (before D\bDI\bIR\bR). As the header text, you need to use a header
+  that the main list manager adds to messages. Now your sublist will
+  accept only messages from the main list requiring that they come from
+  that list _\ba_\bn_\bd contain the header specified.
+
+  ezmlm-idx>=0.313 also has added protection against the malicious
+  subscription of the ezmlm list to mailing lists run by other list
+  managers. If the ezmlm-reject(1) line in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br has ``-h'' and
+  ``D\bDI\bIR\bR'' on it, ezmlm-reject(1) will read D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bej\bje\bec\bct\bt and reject
+  messages that have any header specified in that file. See the ezmlm-
+  reject(1) man page for suitable headers.
+
+
+
+  4\b4.\b.2\b27\b7.\b.  H\bHo\bow\bw s\bsu\bub\bbl\bli\bis\bst\bti\bin\bng\bg c\bca\ban\bn b\bbe\be m\bma\bad\bde\be t\btr\bra\ban\bns\bsp\bpa\bar\bre\ben\bnt\bt t\bto\bo t\bth\bhe\be u\bus\bse\ber\br.\b.
+
+  Often you create a local sublist of a list that you do not control.
+  Local users know to subscribe to your local list. However,
+  occasionally, you want to run your own list as a main list and a
+  series of sublists per geographic site, or split onto several hosts if
+  the list is too large to be handled by a single computer. You may also
+  want to split the load of a ``well known'' list host that is getting
+  overwhelmed with traffic. ezmlm supports sublists, but here the fact
+  that the user has to interact with the correct sublist is a problem.
+  What if the user doesn't remember which sublist s/he is subscribed to?
+  What if you change the name of a sublist host or move a sublist to a
+  different host?
+
+  ezmlm-idx&-0.32 adds ezmlm-split(1), which allows sublisting
+  transparent to the user. This program is invoked before ezmlm-
+  manage(1) in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. If it detects a subscribe or unsubscribe
+  command, it will forward the command to the appropriate sublist based
+  on a ``split file'' D\bDI\bIR\bR/\b/s\bsp\bpl\bli\bit\bt. This file contains entries, one per
+  line, of the format:
+
+
+               domain:lo:hi:sublistname@sublisthost
+               edu:::othersub@otherhost
+               :1:26:third@thirdhost
+
+
+
+
+  For each address, a hash in the range 0-52 is calculated. The
+  ``domain'' is the last two parts of the host name, reversed. Thus, for
+  id.wustl.edu it would be ``edu.wustl''. The domain is considered to
+  match if the characters in the split file match. It is advisable to
+  use only the last part of the domain for compatibility with the SQL
+  version version  (see section ``ezmlm support for SQL datbases'').
+
+  Thus, any address *@*.domain with a hash between ``lo'' and ``hi''
+  inclusive would match the first line and be forwarded to
+  sublistname@sublisthost.  *@*.edu (independent of hash) would match
+  the second line and be forwarded to othersub@otherhost. Of remaining
+  requests, a request for any target address with a hash between 1 and
+  26 would be forwarded to the sublist third@thirdhost. Remaining
+  requests would be passed on to the local list.
+
+  The domain is useful for ``geographic'' splitting, and the hash for
+  load splitting (within a domain). The user interacts only with the
+  main list, and does not need to know from which sublist s/he is
+  serviced.
+
+  ezmlm-idx sublists use the message number of the main list message if
+  they are not indexed. This allows sublists to in bounce messages refer
+  the subscriber to the main list archive. Use ezmlm-make(1) in
+  conjunction with ezmlmsubrc(5) to set up the sublists. See man pages
+  for further details.
+
+  Since the addresses are stored locally, the system is very fast and
+  robust, but it is difficult to add new sublists. ezmlm-split(1) -D
+  supports parsing addresses on stdin and splitting them to stdout (see
+  man page). Thus, if you divide the domain of some sublist(s) onto a
+  net set of sublists, you can use ezmlm-list(1) to collect the
+  addresses, ezmlm-split -D with the new split file to split them, then
+  after clearing the local subscriber databases use ezmlm-sub(1) to add
+  the correct addresses to each new sublist.  The section on SQL support
+  describes an alternative way of managing sublists (see section ``ezmlm
+  support for SQL datbases'').
+
+  4\b4.\b.2\b28\b8.\b.  H\bHo\bow\bw t\bto\bo s\bse\ber\brv\bvi\bic\bce\be c\bco\bom\bmm\bma\ban\bnd\bds\bs i\bin\bn t\bth\bhe\be s\bsu\bub\bbj\bje\bec\bct\bt l\bli\bin\bne\be.\b.
+
+  Rfc2142 (standards track) says that for each mailing list list@host,
+  there MUST be an administrative address list-request@host. This is not
+  the default for ezmlm, but can be added with ezmlm-make(1) ``-q'',
+  which adds a ezmlm-request(1) line before the ezmlm-manage(1) line in
+  D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. This address is used to manage commands in the
+  ``Subject:'' line, by translating them into appropriate ezmlm command
+  messages.
+
+  When migrating from other mailing list managers which use this method
+  to issue list commands, configuring ezmlm to respond to such commands
+  may be useful. In addition, some software manufacturers sell MUAs and
+  mail gateways that are unable to correctly transport rfc822-compliant
+  Internet mail with certain characters in the local part of the
+  address.
+
+  ezmlm-request(1) services the list-request@host address per rfc2142
+  (standards track). It is usually invoked in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br before ezmlm-
+  get(1) and ezmlm-manage(1). It ignores all requests that are not for
+  the list-request address. For requests to the list-request@host
+  address, ezmlm-request(1) parses the ``Subject:'' line. If a ezmlm
+  command address starting with the contents of D\bDI\bIR\bR/\b/o\bou\but\btl\blo\boc\bca\bal\bl (e.g. list-
+  get45) is on the command line, ezmlm-request(1) generates the
+  corresponding full ezmlm request message. If the subject does not
+  start with the contents of D\bDI\bIR\bR/\b/o\bou\but\btl\blo\boc\bca\bal\bl, ezmlm-request(1) prefixes the
+  line with the contents of D\bDI\bIR\bR/\b/o\bou\but\btl\blo\boc\bca\bal\bl, thereby building a complete
+  ezmlm command. If a host name is specified, it must match the contents
+  of D\bDI\bIR\bR/\b/o\bou\but\bth\bho\bos\bst\bt, i.e. ezmlm-request(1) in this function will only
+  generate command messages for the local list.
+
+  Thus, a subject of ``subscribe'' to list-request@host will be auto-
+  magically rewritten as a message to list-subscribe-
+  userlocal=userhost@host.  Similarly, any ezmlm command or ``Reply-
+  To:'' address can be pasted into the subject field and sent to list-
+  request@host.  ezmlm-request(1) does not validate the command name,
+  but invalid commands result in a ``help'' message in reply via ezmlm-
+  manage(1). This allows ezmlm-request(1) to also service custom
+  commands, like list-faq@host that you may have created for your list.
+
+  If the ``Subject:'' is empty or does not start with a letter, ezmlm-
+  request(1) will attempt to interpret the first message body line that
+  starts with a letter in the first position.
+
+  When ezmlm-request(1) has successfully processed a ''request''
+  command, it exits 99 to skip the rest of D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br.
+
+  To set up a list to include ezmlm-request processing, use the ezmlm-
+  make(1) ``-q'' switch. The default is to not do this.
+
+
+  4\b4.\b.2\b29\b9.\b.  H\bHo\bow\bw t\bto\bo s\bsu\bup\bpp\bpo\bor\brt\bt a\bal\blt\bte\ber\brn\bna\bat\bti\biv\bve\be c\bco\bom\bmm\bma\ban\bnd\bd n\bna\bam\bme\bes\bs.\b.
+
+  ezmlm-idx>=0.23 allows alternate names for all user commands. This can
+  be used to e.g. make a message to list-remove@host to result in an
+  ``unsubscribe'' action. This may help migration from other mailing
+  list managers and in non-English environments. The use of aliases
+  allows ezmlm to respond to new command names, while always responding
+  correctly to the standard commands. If ezmlm-request(1) is used it
+  will automatically be able to deal with any commands you set up for
+  the list, within ezmlm or as separate programs.  See ``Multiple
+  language support'' on how to set up command aliases.
+
+
+
+
+  4\b4.\b.3\b30\b0.\b.  H\bHo\bow\bw t\bto\bo a\bad\bdd\bd y\byo\bou\bur\br o\bow\bwn\bn c\bco\bom\bmm\bma\ban\bnd\bds\bs.\b.
+
+  The qmail/ezmlm mechanism makes it very easy to add your own commands.
+  You can add them to D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br, but this requires great care in terms
+  of ordering and exit codes. Easier is to set them up separately with a
+  .\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt-\b-c\bco\bom\bmm\bma\ban\bnd\bd file.
+
+  Let's assume you want to allow anyone to determine how many
+  subscribers are subscribed to your list with the command list-
+  count@host.  Just create a program to do the work:
+
+
+               #!/bin/sh
+               DTLINE='Delivered-To: list-count@host processor'
+               grep "$DTLINE" > /dev/null &&
+                       { echo "This message is looping"; exit 100; }
+               {
+                 echo "$DTLINE"
+                 cat <<EOF
+                 From: list-help@host
+                 To: $SENDER
+                 Subject: list@host subscriber count
+
+                 Current number of subscribers:
+                 EOF
+                 ezmlm-list ~/DIR | wc -l
+               } | /var/qmail/qmail-inject -f list-return- "$SENDER"
+               exit 0
+
+
+
+
+  Then, create D\bDI\bIR\bR/\b/c\bco\bou\bun\bnt\bt containing ``|/path/program'' and then do ``ln
+  -sf DIR/count ~/.qmail-list-count''. Now, the command will pass the
+  message to ``program''. The first thing ``program'' looks for is its
+  delivered-to line to detect looping. If not found, it goes on to print
+  this header, followed by some minimal text and the subscriber number.
+  This can of course be made prettier with ezmlm-list error checking,
+  and maybe in perl, but shows how easy it is to extend ezmlm. All
+  thanks to the DJB/qmail delivery mechanism.
+
+
+  4\b4.\b.3\b31\b1.\b.  H\bHo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\brs\bs c\bca\ban\bn r\bre\bet\btr\bri\bie\bev\bve\be a\ba s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br l\bli\bis\bst\bt
+
+  A user with shell access can always manipulate subscriber lists with
+  ezmlm-sub(1), ezmlm-unsub(1), and ezmlm-list(1) for the lists s/he
+  owns.
+
+  Sometimes a remote administrator requires a list of subscriber E-mail
+  addresses. At the same time, the list should be kept out of the hands
+  of spammers and all unauthorized entities. By default, ezmlm does not
+  allow remote subscriber list retrieval.  You can enable the ``-list''
+  command for remote retrieval of a subscriber list by using the ezmlm-
+  make(1) ``-l'' switch or by adding the ``-l'' switch to the ezmlm-
+  manage(1) line in DIR/manager. With this switch, ezmlm will permit
+  retrieval of a subscriber list, but only to remote administrators.
+  Subscribers cannot get the list membership, and any outsider would
+  have to be able to read a remote administrator's mail to get the list.
+  _\bN_\bo_\bt_\be_\b: _\bT_\bh_\bi_\bs _\bo_\bp_\bt_\bi_\bo_\bn _\bi_\bs _\bn_\bo_\bt _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\ba_\bl _\bu_\bn_\bl_\be_\bs_\bs _\bt_\bh_\be _\bl_\bi_\bs_\bt _\bi_\bs _\bc_\bo_\bn_\bf_\bi_\bg_\bu_\br_\be_\bd _\bf_\bo_\br
+  _\br_\be_\bm_\bo_\bt_\be _\ba_\bd_\bm_\bi_\bn_\bi_\bs_\bt_\br_\ba_\bt_\bi_\bo_\bn_\b, _\bi_\b._\be_\b. _\bt_\bh_\be _\be_\bz_\bm_\bl_\bm_\b-_\bm_\ba_\bk_\be_\b(_\b1_\b) _\b`_\b`_\b-_\br_\bl_\b'_\b' _\bs_\bw_\bi_\bt_\bc_\bh_\be_\bs _\bn_\be_\be_\bd _\bt_\bo
+  _\bb_\bo_\bt_\bh _\bb_\be _\bu_\bs_\be_\bd_\b.
+
+  The list returned is unsorted for efficiency reasons. You can easily
+  sort it or use your mail reader to find a specific entry. The number
+  of subscribers is shown at the bottom of the list. To get the number
+  of subscribers from the command line, use:
+               % ezmlm-list DIR | wc -l
+
+
+
+
+
+  4\b4.\b.3\b32\b2.\b.  H\bHo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\brs\bs c\bca\ban\bn d\bde\bet\bte\ber\brm\bmi\bin\bne\be t\bth\bhe\be n\bnu\bum\bmb\bbe\ber\br o\bof\bf s\bsu\bub\bb-\b-
+  s\bsc\bcr\bri\bib\bbe\ber\brs\bs
+
+  For the list aaa@example.com, send a message to aaa-listn@example.com.
+  This is preferable to the ``-list'' command for very large lists.
+
+
+  4\b4.\b.3\b33\b3.\b.  H\bHo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bns\bs c\bca\ban\bn s\bse\bee\be i\bif\bf a\ban\bn a\bad\bdd\bdr\bre\bes\bss\bs i\bis\bs a\ba s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br o\bor\br n\bno\bot\bt
+
+  For the list aaa@example.com, and subscriber user@host.cn send a
+  message to aaa-query=host.cn@example.com. Users can do this as well,
+  but in that case the reply is sent to the target address
+  (user@host.cn) and not to the SENDER to protect the subscriber
+  addresses.
+
+
+  4\b4.\b.3\b34\b4.\b.  H\bHo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\brs\bs c\bca\ban\bn s\bse\bea\bar\brc\bch\bh t\bth\bhe\be s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn l\blo\bog\bg
+
+  The same conditions that enable remote administrators to retrieve a
+  subscriber list (see ``'') also enable the remote admin to retrieve
+  the subscription log, i.e. the log of changes made to the subscriber
+  list. The command is list-log@host. The entries are of the form ``date
+  timestamp dir event address comment''. ``dir'' is ``+'' for addition
+  of an address, ``-'' for removal, ``event'' is empty for normal
+  (un)subscribe ``manual'' for changes made with ezmlm-(un)sub, and
+  ``probe'' for removals via bounce handling. ``address'' is the
+  subscription address, and ``comment'' is empty or the subscribers
+  ``From:'' line. The log can be used to look at recent
+  additions/removals and to try to track down a subscriber address from
+  e.g. the name on the ``From:'' line. The log is written on a best-
+  effort basis. In contrast to the subscriber database, entries in the
+  log may be lost at a system crash.
+
+  The remote administrator can do a case-insensitive search through the
+  log with the command list-log.xxx@host, where ``xxx'' is any sequence
+  of letters/numbers that must occur on a line in order for that line to
+  be included in the reply. A ``_'' is a wild card and should be used
+  for special characters as well. Thus, to search for any entry with a
+  host name of host* mail list-log._host and to find entries for ``Keith
+  John...'' etc, use list-log.keith_john.
+
+  For SQL-enabled lists, this command searches the ``list_slog'' table.
+
+
+  4\b4.\b.3\b35\b5.\b.  H\bHo\bow\bw t\bte\bex\bxt\bt f\bfi\bil\ble\be e\bed\bdi\bit\bti\bin\bng\bg w\bwo\bor\brk\bks\bs.\b.
+
+  If a list is set up with the ezmlm-make(1) ``-n'' switch, or if the
+  ``-e'' switch is added to the ezmlm-manage(1) line in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br,
+  ezmlm allows remote administrators to edit the text files that make up
+  most of the ezmlm responses.  Of course, this will work only if remote
+  administration is enabled for the list. Replies are sent only if the
+  target address is a remote administrator.  Thus, ezmlm does not rely
+  on SENDER (easily forged) but on the notion that only the recipient
+  receives the message.  This is a reasonable assumption for remote
+  administrators that receive mail on the local system.
+
+  With this switch, ezmlm replies to the -edit command with a list of
+  the files in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/.  Only files where editing seems reasonable are
+  included in the list. The remote administrator can edit any file in
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ by sending e-mail containing the new text to -edit.file
+  where ``file'' is the name of the file replaced (edited). The file
+  must exist and the name consist of only lower case letters and '-'.
+  Any '-' (hyphen) must be substituted by a '_' (underscore). For remote
+  administrator convenience, the substitution has been made in the list
+  of files sent in reply to the -edit command.
+
+  In reply to this command, ezmlm sends a message with the file and
+  editing instructions. A ``cookie'' based on the date, file name, and
+  contents of the file is added to the ``Reply-To:'' address. The cookie
+  becomes invalid as soon as the file has been changed, or after 27
+  hours, whichever is shorter.  Also, the cookie cannot be used to edit
+  any other file, even if the other file has exactly the same contents.
+  If you sent an edit request, and decide not to edit the file, you can
+  simply delete the message.
+
+  To apply standard changes to all your text files it is easier to edit
+  ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc. To reset the list's text files back to their default
+  contents (as specified by e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b)), use the ezmlm-make(1) ``-ee''
+  switch together with any other switches used to set up the list, or
+  the ``-++'' switch and any switches that you whish to change from the
+  current configuration.
+
+
+  4\b4.\b.3\b36\b6.\b.  H\bHo\bow\bw s\bsu\bub\bbj\bje\bec\bct\bt l\bli\bin\bne\be p\bpr\bre\bef\bfi\bix\bxe\bes\bs w\bwo\bor\brk\bk.\b.
+
+  First of all, it is against a number of RFCs to modify the
+  ``Subject:'' header of messages. However, it is frequently requested
+  by users who have seen it on other list managers. Second, it is many
+  times worse to have a prefix that changes from message to message,
+  such as a prefix with the message number.  However, a number of lists,
+  especially in Japan, use this feature and in its absence these lists
+  might be unable to take advantage of ezmlm. Thus, while we recommend
+  against using a prefix, ezmlm-idx supports it.
+
+  To add a subject prefix, just put the text into D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx. The only
+  format that makes any sense is ``list:'' or ``(list)'' or such.
+
+  The message number prefix is activated by putting e.g. ``(list-#)''
+  into D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx. ``#'' is replaced by the message number. ezmlm
+  refuses to make more drastic changes in the subject of a message. As a
+  consequence, the message number prefix is added only when the subject
+  does not already contain a prefix. Thus, replies will have the message
+  number of the original message. Doing anything else and still
+  supporting rfc2047-encoded subjects in the archive threading (much
+  more important) would require decoding the subject, removing/editing
+  the prefix, and re-encoding the subject. This is far too invasive.
+
+  The entire thread can always be retrieved by sending a message to
+  list-thread-x where ``x'' is the message number in the prefix of any
+  message in the thread.
+
+
+  4\b4.\b.3\b37\b7.\b.  H\bHo\bow\bw b\bbo\bou\bun\bnc\bce\bes\bs a\bar\bre\be h\bha\ban\bnd\bdl\ble\bed\bd.\b.
+
+  Ezmlm messages are sent with an envelope sender (``Return-Path'') that
+  directs bounces to D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\ber\br and also via ``VERP'' contain
+  information about the intended recipient. Thus, programs run from
+  D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\ber\br know the subscriber for whom the message bounced. ezmlm-
+  weed(1) is used to weed out delivery delay notification and other
+  junk.  For others ezmlm-return(1) decides if the address is a
+  subscriber.  If so, it saves the first bounce message and a list of
+  bounced-message numbers. ezmlm-warn(1) executed from e.g. D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br
+  goes through these bounce files. If it finds any that are older than
+  1,000,000 seconds (about 11.6 days) it sends a warning message to the
+  subscriber. If this warning message bounces, ezmlm-return(1) sets up a
+  "warning flag" for the subscriber. If ezmlm-warn(1) finds a warning
+  flag older than 11.6 days, it sends a "probe" to the subscriber.  If
+  ezmlm-return(1) receives a bounced probe, the subscriber is
+  automatically unsubscribed.
+
+  The ezmlm-warn(1) ``-t'' switch can be used to change the time-out (in
+  days).  The ezmlm-warn(1) ``-d'' switch causes processing of ``list-
+  digest'' bounces rather than ``list'' bounces. ezmlm-weed(1) and
+  ezmlm-return(1) can handle bounces for either list.
+
+  ezmlm-warn(1) also removes any files in the bounce directory that are
+  older than 3 times the bounce time-out.
+
+  ezmlm-warn(1) is normally run from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br. This can take quite a
+  lot of resources, if there are a large number of bouncing addresses
+  (>>1000) on a busy list, since by default all bounces are stored in a
+  single directory and ezmlm-warn(1) examines all of them with each
+  invocation.  ezmlm-idx->=0.32 changes bounce handling to improve
+  performance for large lists. Bounces are stored in subdirectories of
+  D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\be/\b/d\bd/\b/, one per 10,000 seconds. The corresponding address
+  hashes are stored in 16 subdirectories of D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\be/\b/h\bh/\b/. Instead of
+  looking at all bounces, ezmlm-warn(1) processes only the bounces in
+  D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\be/\b/d\bd/\b/ subdirectories that are ``due''. In addition, ezmlm-
+  warn(1) uses D\bDI\bIR\bR/\b/b\bbo\bou\bun\bnc\bce\be/\b/l\bla\bas\bst\btd\bd as a simple lockout, to assure that it
+  will do work only at most once every 5.5 hours. (Times are scaled to
+  the ezmlm-warn(1) ``-t'' argument if used.)  Together, these changes
+  assure that bounce handling will scale well in the default
+  configuration, even for very large lists.
+
+
+  4\b4.\b.3\b38\b8.\b.  H\bHo\bow\bw t\bth\bhe\be i\bin\bnf\bfo\bo a\ban\bnd\bd f\bfa\baq\bq c\bco\bom\bmm\bma\ban\bnd\bds\bs w\bwo\bor\brk\bk.\b.
+
+  The _\b-_\bi_\bn_\bf_\bo and _\b-_\bf_\ba_\bq commands simply reply with the contents of the
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/i\bin\bnf\bfo\bo and D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/f\bfa\baq\bq files. Edit these files directly or
+  remotely (see ``How to remotely edit dir/text files'').  The
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/i\bin\bnf\bfo\bo file should start with a single line that is meaningful
+  as is and describes the list. This will be used in later versions to
+  allow automatic assembly of the global ``list-of-lists'' (see ``How to
+  set up a global list address like majordomo@host or listserv@host'').
+
+
+  4\b4.\b.3\b39\b9.\b.  H\bHo\bow\bw t\bth\bhe\be g\bgl\blo\bob\bba\bal\bl e\bez\bzm\bml\blm\bm l\bli\bis\bst\bt a\bad\bdd\bdr\bre\bes\bss\bs w\bwo\bor\brk\bks\bs.\b.
+
+  Sometimes, it is desirable to have a host- or user-wide address that
+  can list available mailing lists.
+
+  ezmlm-request(1) can be used to set up a global address, such as
+  ezmlm@host which allows the user to see and interact with a number of
+  different mailing lists. This is especially useful when your users are
+  used to other mailing list managers, such as ``majordomo'' or
+  ``listproc''. ezmlm-request(1) is set up to answer requests to the
+  address (see ``How to set up a global list address like majordomo@host
+  or listserv@host'').  There, it interprets the first line of the
+  message body as a command. It will reply directly to ``lists'' and
+  ``which'' commands. All other commands will be used to construct
+  messages to the respective lists. Where other mailing list managers
+  use synonyms of ezmlm commands, ezmlm-request(1) recognizes these and
+  translates them to the corresponding ezmlm commands.  ezmlm-request(1)
+  will build commands also of unrecognized commands. Thus, if you create
+  new commands for a list, ezmlm-request(1) will automatically support
+  them.
+
+  If the user does not specify the complete list address, ezmlm-
+  request(1) will attempt to complete the name. See the ezmlm-reject(1)
+  man page for more info.
+
+
+  4\b4.\b.4\b40\b0.\b.  H\bHo\bow\bw e\bez\bzm\bml\blm\bm-\b-c\bcr\bro\bon\bn w\bwo\bor\brk\bks\bs.\b.
+
+  If you are a user and have crond(8) access, if you do not need to get
+  digests at specific times, or if you are a system administrator
+  setting up lists, there is no reason for you to use ezmlm-cron(1). If
+  you are a system administrator not allowing users crond(8) access or a
+  user that needs digests at specific times, but without crond(8)
+  access, read on.
+
+  ezmlm-cron(1) is a very restrictive interface to crond(8).  ezmlm-
+  cron(1) can be used to create digest trigger messages. If a list is
+  set up with a digest code (see ezmlm-make(1) and ezmlm-get(1)) ezmlm
+  will generate a digest from the list joe-sos@host sent to to
+  subscribers of joe-sos-digest@dighost when receiving a message to joe-
+  sos-dig-code@host where ``code'' is the digest code. ezmlm-cron(1) can
+  be used to generate such messages at regular intervals.  The file
+  e\bez\bzc\bcr\bro\bon\bnr\brc\bc is set up by the sysadmin and controls what trigger messages
+  specific users may set up via ezmlm-cron(1).
+
+  Usually, the ezcronrc of that use will have an entry like
+  ``user:user-:host:10'' allowing ``user'' to create trigger messages
+  for up to 10 lists with names starting with ``user-'' and on the host
+  ``host''.
+
+  To list the ezcronrc line controlling your use of ezmlm-cron(1):
+
+
+               % ezmlm-cron -c
+
+
+
+
+  To list all entries that you've created:
+
+
+               % ezmlm-cron -l
+
+
+
+
+  To add an entry to trigger digests from list@host every morning at
+  0230:
+
+
+               % ezmlm-cron -t 02:30 -i24 list@host code
+
+
+
+
+  A new entry for the same list overwrites an old entry.
+
+  To delete the entry above:
+
+
+               % ezmlm-cron -d list@host
+
+
+
+
+  or use ezmlm-cron to trigger messages at a different time:
+
+
+               % ezmlm-cron -t 16:16 -i24 list@host code
+
+
+
+  4\b4.\b.4\b41\b1.\b.  H\bHo\bow\bw e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be w\bwo\bor\brk\bks\bs.\b.
+
+  ezmlm lists allow almost infinite customization. The component build,
+  together with the qmail delivery mechanism makes it possible to create
+  any variant of list function imaginable. However, this complexity
+  makes it somewhat daunting to the average user wanting to set up a
+  mailing list. ezmlm-make(1) allows automated list setup, while
+  permitting a large amount of configurability.
+
+  At first glance, ezmlm-make(1) has many complicated options. However,
+  these can be applied iteratively through the ezmlm-make(1) edit
+  mechanism. Also, they are intended to be relatively complete so that
+  execution of ezmlm-make(1) by e.g. a GUI can be used to safely set up
+  and edit any list.
+
+  ezmlm-make(1) reads its command line arguments and switches, then
+  creates the list directory. If the ``-e'' edit or ``-+'' sticky edit
+  switches are not specified, ezmlm-make(1) will fail if the directory
+  already exists. The directory argument must be an absolute path
+  starting with a slash. The dot-qmail file argument, if specified, must
+  also be absolute.
+
+  ezmlm-make(1) next reads ezmlmrc(5) located in the /\b/e\bet\btc\bc/\b/ directory
+  with a default install. If not found, the file in the ezmlm binary
+  directory will be used. The second ezmlm-make command line argument
+  specify the root name of the .qmail files. If the ezmlm-make(1) ``-c''
+  switch is used, ezmlm-make(1) will look in that directory for a
+  .\b.e\bez\bzm\bml\blm\bmr\brc\bc file and use it instead. If this file does not exist, ezmlm-
+  make(1) will print a warning and use the previously discussed
+  ezmlmrc(5) files in the same order.  You can also use ``-C
+  _\be_\bz_\bm_\bl_\bm_\br_\bc_\b._\ba_\bl_\bt'' to use _\be_\bz_\bm_\bl_\bm_\br_\bc_\b._\ba_\bl_\bt as the ezmlmrc(5) file. Again, ezmlm-
+  make(1) will fall back to the others with a warning, if the specified
+  ezmlmrc(5) file is not found.
+
+  When not run in ``-e edit'' or ``-+'' sticky edit modes, ezmlm-make(1)
+  first creates the list directory.  It also as the last step of its
+  action creates D\bDI\bIR\bR/\b/k\bke\bey\by containing the key used for cookie generation.
+
+  The ezmlmrc(5) file consists of a number of file names relative to the
+  list directory, followed by conditional flags (see ezmlm-make(1) and
+  ezmlmrc(5) for details). If all the conditional flags (controlled by
+  the corresponding command line switches) are true, the lines that
+  follow are entered into the named file. There are also tags to erase
+  files.  Tags in the format <#X#> (where ``X'' is any number, except
+  ``1'' and ``2'') are replaced by the corresponding ezmlm-make(1)
+  switch argument. The ezmlm-make(1) command line arguments and the
+  ezmlm binary path can be similarly substituted into the text. Thus,
+  ezmlmrc(5) controls (within reason) the entire operation of ezmlm-
+  make(1). ezmlmrc(5) is also set up so that no messages or file
+  containing list state information are lost. Therefore, ezmlm-make(1)
+  can be used to safely edit existing lists. The only caveat is that the
+  list state is undefined while editing is in progress. Thus, it is
+  advisable to prevent mail delivery by setting the ``sticky'' bit on
+  the user's home directory while editing lists.
+
+  ezmlm-make(1) will create the file D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg. This files saves all
+  the flags that were set at the last execution of ezmlm-make, as well
+  as all the switch and command line arguments. When editing a list,
+  only ``DIR'' and the non-default letter switches need to be specified.
+  Other command line arguments and the ``digit switch'' arguments are
+  read from D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg.  To remove a digit switch, simply use it with
+  two single quotes as the argument.
+
+  You can also easily determine how a list was set up by looking at
+  D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg.
+
+  _\bN_\bo_\bt_\be_\b: D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ files will be created but not overwritten when using
+  the ``-e'' or ``-+'' edit switches. This is to preserve manual
+  customizations. To overwrite these and reset the files to the content
+  specified by e\bez\bzm\bml\blm\bmr\brc\bc, use ``-ee'' or ``-++''.
+
+  _\bN_\bo_\bt_\be_\b: As of ezmlm-idx-0.40 the ezmlm-make(1) ``-c'' and ``-C file''
+  switches are sticky when using ``-+'' or ``-++'', so you do not need
+  to specify them. This feature is disabled if ezmlm-make(1) is run as
+  root.
+
+
+  4\b4.\b.4\b42\b2.\b.  W\bWh\bha\bat\bt n\bna\bam\bme\bes\bs c\bca\ban\bn I\bI u\bus\bse\be f\bfo\bor\br m\bmy\by l\bli\bis\bst\bts\bs?\b?
+
+  Rather than restrict you to a single E-mail address (user@host), qmail
+  in the default setup gives you control over an infinite number of
+  addresses user-*@host. Of course, you (normally) have no way of
+  controlling elsewhere@host since that could lead to overlap between
+  users' ``e-mail address space''. As a consequence, all you mailing
+  lists have to be named user-xx@host where ``user'' is your user name
+  and ``xx'' is anything. You cannot create e.g. mylist@host, only user-
+  mylist@host. To create the list user-list@host do:
+
+
+               % ezmlm-make ~/list ~/.qmail-list user-list host
+
+
+
+
+  Notice that ``user'' is n\bno\bot\bt part of the .\b.q\bqm\bma\bai\bil\bl file name.
+
+  There are two way to create lists with names not starting with your
+  user name: First, qmail can be set up so that you control a virtual
+  domain (see below).  Second, the system administrator can set up lists
+  with arbitrary names within the ~\b~a\bal\bli\bia\bas\bs/\b/ directory.
+
+
+  4\b4.\b.4\b43\b3.\b.  L\bLi\bis\bst\bts\bs i\bin\bn v\bvi\bir\brt\btu\bua\bal\bl d\bdo\bom\bma\bai\bin\bns\bs
+
+  If you use qmail>=1.02 and ezmlm-idx>=0.32, lists under virtual
+  domains work just like other lists and require no adjustments. You can
+  choose any local name for the list and the ezmlm-make(1) argument
+  ``local'' is that name; ``host'' is the name of the virtual domain.
+
+
+  4\b4.\b.4\b44\b4.\b.  H\bHo\bow\bw d\bdo\bo I\bI m\bma\bak\bke\be c\bcu\bus\bst\bto\bom\bmi\biz\bza\bat\bti\bio\bon\bn s\bsi\bim\bmp\bpl\ble\be f\bfo\bor\br m\bme\be/\b/m\bmy\by u\bus\bse\ber\brs\bs?\b?
+
+  All non-default switches, ezmlm-issubn(1) setups, etc, can be made
+  standard for new lists by customizing the ezmlm-make(1) configuration
+  file named ``e\bez\bzm\bml\blm\bmr\brc\bc''.  A default e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) is installed in the
+  ezmlm binary directory. If installed, a system-wide customized ezmlmrc
+  file in /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc (or symlinked from there) overrides this.
+  Installing a ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc file in a user d\bdo\bot\btd\bdi\bir\br and using the ezmlm-
+  make(1) ``-c'' switch allows further per user customization (see
+  ``Customizing ezmlm-make operation'').
+
+
+  5\b5.\b.  e\bez\bzm\bml\blm\bm s\bsu\bup\bpp\bpo\bor\brt\bt f\bfo\bor\br S\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\bes\bs.\b.
+
+
+  5\b5.\b.1\b1.\b.  W\bWh\bhy\by u\bus\bse\be a\ban\bn S\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\be w\bwi\bit\bth\bh e\bez\bzm\bml\blm\bm?\b?
+
+  The main advantages are that you are using an address database system
+  that can easily be accessed from any number of other programs via
+  ODBC, perl, java, PHP, ... You can easily hook up ezmlm with your
+  customer database, etc.  ezmlm programs compiled with SQL support (and
+  when available also those compiled with support for other SQL servers)
+  are entirely backwards compatible. You can mix SQL dbs with normal
+  ezmlm dbs, and convert lists between them.
+
+
+  5\b5.\b.2\b2.\b.  W\bWh\bhy\by n\bno\bot\bt t\bto\bo u\bus\bse\be a\ban\bn S\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\be w\bwi\bit\bth\bh e\bez\bzm\bml\blm\bm.\b.
+
+  The main disadvantages of the SQL version are that you need to be
+  familiar with the SQL server, the binaries are quite a bit larger, and
+  you are trusting your addresses to a large database program, rather
+  than a small and easily audited set of ezmlm programs. Also, the SQL
+  server becomes a single point of failure.
+
+  Ezmlm with SQL support continues to rely on qmail stability. If
+  connection fails, ezmlm aborts with a temporary error causing
+  redelivery at a later time point.
+
+
+  5\b5.\b.3\b3.\b.  T\bTa\bab\bbl\ble\bes\bs u\bus\bse\bed\bd f\bfo\bor\br (\b(M\bMy\by)\b)S\bSQ\bQL\bL s\bsu\bup\bpp\bpo\bor\brt\bt.\b.
+
+  The basic philosophy is that the database can be on any host (if you
+  use SENDER restrictions, connectivity to the main host is more
+  important than to the sublists), and you choose the database and
+  ``table root'' names. The default database is ``ezmlm'' and the
+  default table root is ``list''. Each list has a separate table root.
+  Any number of lists can share a database.
+
+  The main list address table is named with the table root only, others
+  have that name with various suffixes. In the following ``list'' is
+  used as the table root.
+
+
+  5\b5.\b.3\b3.\b.1\b1.\b.  A\bAd\bdd\bdr\bre\bes\bss\bs t\bta\bab\bbl\ble\bes\bs.\b.
+
+
+     l\bli\bis\bst\bt
+        List subscriber addresses.
+
+     l\bli\bis\bst\bt_\b_d\bdi\big\bge\bes\bst\bt
+        Digest list subscriber addresses.
+
+     l\bli\bis\bst\bt_\b_a\bal\bll\blo\bow\bw
+        List subscriber alias addresses. Used only if SENDER
+        restrictions are used for the list. This is configured in the
+        default SQL list setup, but a local (ezmlm-style non-SQL)
+        database could also be used.
+
+     l\bli\bis\bst\bt_\b_d\bde\ben\bny\by
+        List deny addresses. This table is created, but the default
+        configuration, if it uses the ``deny'' addresses at all, will do
+        so with a local database.
+
+     l\bli\bis\bst\bt_\b_m\bmo\bod\bd
+        Moderator addresses. Created for completeness, but not used in
+        the default configuration. If moderators are used, the addresses
+        are stored in a local database.
+
+
+  5\b5.\b.3\b3.\b.2\b2.\b.  S\bSu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br l\blo\bog\bg t\bta\bab\bbl\ble\bes\bs.\b.
+
+  For each of the above tables, there is a ``*_slog'' table that
+  contains one row per transaction against the corresponding address
+  table. The entries contain a time stamp, the subscription address; a
+  direction indicator (``-'' for removals, ``+'' for additions); a type
+  indicator (blank for ezmlm-manage, ``m'' for ``manual'', ``p'' for
+  ``probe, i.e. bounce handling; and the subscriber ``From:'' line
+  contents (only additions and only when made by ezmlm-manage or by
+  ``ezmlm-sub(1) -n'').
+
+
+  5\b5.\b.3\b3.\b.3\b3.\b.  M\bMe\bes\bss\bsa\bag\bge\be l\blo\bog\bgg\bgi\bin\bng\bg t\bta\bab\bbl\ble\bes\bs.\b.
+
+  For both the list and the digest list, there are a pair of tables that
+  log messages:
+
+
+     l\bli\bis\bst\bt_\b_c\bco\boo\bok\bki\bie\be
+        The main list stores the message number and a pseudo-random
+        cookie in this table when it processes the message. The cookie
+        is derived from the secret D\bDI\bIR\bR/\b/k\bke\bey\by, the message sender and the
+        message number. Thus, it is non-repeating and virtually
+        impossible to guess beforehand. Sublists will check that the
+        cookie sent with the message is the same as the one received
+        with the message.
+
+        The digest list is created similarly, except that it is ezmlm-
+        get(1) that originates the message and creates the cookie.  This
+        is done in ``list_digest_cookie''.
+
+
+     l\bli\bis\bst\bt_\b_m\bml\blo\bog\bg
+        Both the main list and the sublists make entries in this table.
+        Each entry consists of a time stamp, a message number, a list
+        number, and a code. The code is 0 for message arrival, 1 for
+        ``finished processing'', 2 for ``receipt received'' and -1 for
+        bounce. The lists will refuse to process messages that do not
+        have the correct cookie, or if the message already has an entry
+        with a code of greater than 0. To inject a message at the
+        sublist, an attacker would have to inject a message with the
+        correct code before the list has processed the ``real'' message,
+        or subvert the SQL server. In practice, this is very hard to do,
+        unless the attacker has broken security at the database server
+        or a sublist. This authentication mechanism is intended to make
+        it safe to sublist moderated lists. It also blocks any message
+        duplication between main list and sublist from being propagated
+        to the subscribers.
+
+        The codes 2 for ``receipt received'' and -1 for bounce are
+        entered by ezmlm-receipt(1) at the main list. This program is
+        configured instead of ezmlm-return(1) if the main list was set
+        up with ``ezmlm-make -w6''.  ezmlm-receipt(1) checks the cookie
+        of messages addresses to mainlocal-return-receipt@mainhost and
+        if correct enters the ``receipt received'' code. This address is
+        normally in the subscriber database with a hash of 98, so that
+        each list sends a message to the address _\ba_\bf_\bt_\be_\br all subscriber
+        addresses.
+
+        Bounces of sublist messages should not lead to removal of the
+        sublist from the database. ezmlm-receipt(1) will instead log the
+        bounce to the ``list_mlog'' table. It will also store up to 50
+        bounces in the bounce directory. This helps error detection and
+        diagnosis. After the first 50 bounces, no more bounces are
+        stored, until you manually remove the old ones. This is to
+        prevent filling up your hard disk in case a configuration error
+        causes a deluge of bounces.
+
+        The digest list is treated in the same manner. Here, the tables
+        is ``list_digest_mlog'' and the feedback address is mainlocal-
+        digest-return-receipt@mainhost.
+
+
+
+
+  5\b5.\b.4\b4.\b.  H\bHo\bow\bw t\bto\bo s\bse\bet\bt u\bup\bp a\ba s\bsi\bim\bmp\bpl\ble\be l\bli\bis\bst\bt w\bwi\bit\bth\bh S\bSQ\bQL\bL s\bsu\bup\bpp\bpo\bor\brt\bt.\b.
+
+  To use SQL database support, you have to compile the programs with SQL
+  support. Currently, only MySQL support is available. See I\bIN\bNS\bST\bTA\bAL\bLL\bL.\b.i\bid\bdx\bx
+  in the package on how to do this.
+
+  The programs with SQL support will work exactly like the normal
+  programs for standard lists. However, if the file s\bsq\bql\bl exists in the
+  basedir, it turns on the SQL mode and it is expected to contain SQL
+  server connect info in the format
+
+       ``host:port:user:password:database:table''
+
+
+  Here, ``Host'' is the SQL database server host, ``port'' can be left
+  blank to use the default port, ``user'' and  ``password'' are connec-
+  tion credentials for a user you need to define and grant access to the
+  database. ``Table'' is the name of the address table (``list'' in the
+  examples above and ``list_digest'' for the corresponding digest list).
+  For list clusters, ``:sublist'' is suffixed to this info and it is the
+  name/address of the sublist.
+
+  For each address database, you also need to create the address table
+  as well as the ``*_slog'' subscription log table. In addition, you
+  should create a ``*_cookie'' and ``*_mlog'' table for message logging.
+  This is all it takes to start using an SQL database.
+
+
+  5\b5.\b.4\b4.\b.1\b1.\b.  H\bHe\bel\blp\bpe\ber\br p\bpr\bro\bog\bgr\bra\bam\bms\bs f\bfo\bor\br S\bSQ\bQL\bL-\b-e\ben\bna\bab\bbl\ble\bed\bd l\bli\bis\bst\bts\bs.\b.
+
+  Two programs are supplied in the distribution to make it easier to
+  create the database user and tables. Also, ezmlm-make(1) has support
+  for setting up SQL-enabled lists.
+
+
+     C\bCr\bre\bea\bat\bti\bin\bng\bg t\bth\bhe\be t\bta\bab\bbl\ble\bes\bs
+        ezmlm-mktab(1) will create the necessary tables:
+
+
+                  % ezmlm-mktab -d table
+
+
+
+
+     Pipe this into the SQL client with the appropriate administrator
+     credentials needed to create tables (see MySQL documentation, e.g.
+     <http://www.tcx.se/>).
+
+     For most lists, the only addresses that are stored in the SQL
+     database are the subscribers of list and digest, and the ``allow''
+     aliases. It is NOT normally advisable to store moderator addresses
+     there, since they are needed only at the main list and secrecy is
+     more important. ``Deny'' addresses are few and again only needed at
+     the main list. ``Allow'' are put in the SQL database when using the
+     default ezmlmrc file only to make all relevant addresses
+     manipulatable via the SQL server. The other tables are created, in
+     case they are  wanted (the cost for having them as empty table is
+     zero). The basedir/sql file is the decision point. If it exists, an
+     SQL table is used; if not a local ezmlm db is used.
+
+
+     C\bCr\bre\bea\bat\bti\bin\bng\bg a\ba u\bus\bse\ber\br e\ben\bnt\btr\bry\by
+        Create a user that has full access to the database from the list
+        host. How to do this depends on the RDBMS.
+
+
+     C\bCr\bre\bea\bat\bti\bin\bng\bg t\bth\bhe\be l\bli\bis\bst\bt
+        ezmlm-make(1) supports SQL-enabled lists with the ``-6'' switch:
+
+
+                  % ezmlm-make other_switches -6 'host:port:user:pw:db:table' \
+                          dir dot local host
+
+
+
+
+     Will create an SQL-enabled list that uses the SQL server for the
+     main list subscribers, digest list subscribers (if configured) and
+     ``allow'' poster alias addresses (if configured).
+
+
+  5\b5.\b.5\b5.\b.  M\bMa\ban\bnu\bua\bal\bll\bly\by m\bma\ban\bni\bip\bpu\bul\bla\bat\bti\bin\bng\bg t\bth\bhe\be s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs o\bof\bf a\ba S\bSQ\bQL\bL-\b-e\ben\bna\bab\bbl\ble\bed\bd l\bli\bis\bst\bt.\b.
+
+  ezmlm-sub(1), ezmlm-unsub(1), and ezmlm-list(1) work as you would
+  expect also with a SQL-enabled list. ezmlm-list(1) may be minimally
+  slower (depending on network speed) if the SQL server is not local.
+  ezmlm-sub(1) and ezmlm-unsub(1) will be faster, but this is noticeable
+  only with very large subscriber lists and addition/removal of large
+  numbers of addresses (more than several thousands).
+
+
+  5\b5.\b.6\b6.\b.  C\bCo\bon\bnv\bve\ber\brt\bti\bin\bng\bg t\bto\bo a\ban\bnd\bd f\bfr\bro\bom\bm a\ban\bnd\bd S\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\be.\b.
+
+  Just like other programs, ezmlm-list(1), ezmlm-sub(1), and ezmlm-
+  unsub(1) will work with normal address databases in the absence of
+  D\bDI\bIR\bR/\b/s\bsq\bql\bl.  However, they also have a ``-M'' switch to force this
+  behavior even in the presence of D\bDI\bIR\bR/\b/s\bsq\bql\bl. This is used to convert an
+  address database from the standard type to the SQL type:
+
+
+               % ezmlm-list -M dir | xargs ezmlm-sub dir
+
+
+
+
+  or from the SQL version to the standard type:
+
+
+               % ezmlm-list dir | xargs ezmlm-sub -M dir
+
+
+
+
+  To synchronize the two, remove one and then update it with ezmlm-
+  sub(1) from the other. Alternatively, sort the ezmlm-list(1) output
+  for both, use diff and sed/awk to get separate files of the differ-
+  ences, and use ezmlm-sub(1) and ezmlm-unsub(1) to apply the differ-
+  ences to the appropriate database.
+
+  This type of conversion can serve as a convenient means to convert a
+  list from one type to another, to back up databases, and to move
+  subscriber addresses from a standard list to a SQL table for other
+  purposes, or from a SQL database to a standard mailing list (you may
+  need to use addresses from a SQL table, without wanting your lists to
+  be dependent on an SQL server for day to day operation).
+
+  _\bN_\bo_\bt_\be_\b: This inter-conversion requires the D\bDI\bIR\bR/\b/s\bsq\bql\bl file. If you do not
+  run the list against an SQL server, you need to disable deliveries
+  before you temporarily create this file. Otherwise, the list will run
+  against the SQL database during the time D\bDI\bIR\bR/\b/s\bsq\bql\bl exists.
+
+
+  5\b5.\b.7\b7.\b.  O\bOp\bpt\bti\bim\bmi\biz\bzi\bin\bng\bg M\bMy\byS\bSQ\bQL\bL f\bfo\bor\br e\bez\bzm\bml\blm\bm.\b.
+
+
+  5\b5.\b.7\b7.\b.1\b1.\b.  A\bAd\bdd\bdr\bre\bes\bss\bs S\bSE\bEL\bLE\bEC\bCT\bTs\bs,\b, a\bad\bdd\bdi\bit\bti\bio\bon\bns\bs,\b, r\bre\bem\bmo\bov\bva\bal\bls\bs.\b.
+
+  ezmlm-idx-0.40 simplifies the SQL support and queries over ezmlm-
+  idx-0.32 at the cost of dropping distributed sublist support. We have
+  figured out a simpler way to support the latter, which hopefully will
+  be incorporated into ezmlm in the future (written under contract).
+
+  With the simplification, the queries are very straight forward, and
+  tuning is indicated only under extreme circumstances (very many very
+  large and busy lists or constant addition/removal of many addresses).
+
+
+  5\b5.\b.8\b8.\b.  M\bMa\bai\bin\bnt\bte\ben\bna\ban\bnc\bce\be o\bof\bf t\bth\bhe\be M\bMy\byS\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\be.\b.
+
+  Weekly to monthly error checks on MySQL tables is recommended. Best is
+  to use:
+
+
+               # isamchk -s -O readbuffer=2M */*.ISM
+
+
+
+
+  Other options allow automatic correction of errors, but are dangerous
+  if tables are accessed while isamchk is running.
+
+  Other isamchk options allow recovery of space after frequent
+  insert/delete of addresses (can also be done with ``OPTIMIZE TABLE''),
+  key optimization, etc.  See the MySQL documentation (
+  <http://www.tcx.se>) for more info.
+
+
+  6\b6.\b.  P\bPo\bos\bss\bsi\bib\bbl\ble\be e\ber\brr\bro\bor\br c\bco\bon\bnd\bdi\bit\bti\bio\bon\bns\bs i\bin\bn e\bez\bzm\bml\blm\bm l\bli\bis\bst\bts\bs.\b.
+
+
+  6\b6.\b.1\b1.\b.  W\bWh\bha\bat\bt d\bdo\bo I\bI d\bdo\bo i\bif\bf e\bez\bzm\bml\blm\bm d\bdo\boe\bes\bsn\bn'\b't\bt w\bwo\bor\brk\bk?\b?
+
+  Try to determine where the problem occurs and how to reproduce it:
+
+  +\bo  Do messages to ezmlm return an error message to the sender or not?
+
+  +\bo  What is/are the error message(s)?
+
+  +\bo  What does ezmlm log into the mail log?
+
+  +\bo  Are you using a setup with virtual domains, and qmail<1.02 or
+     ezmlm-idx<0.31? If so, have you adjusted D\bDI\bIR\bR/\b/i\bin\bnl\blo\boc\bca\bal\bl (see
+     ``Adapting ezmlm-make for virtual domains'')?
+
+  +\bo  Are posts sent out to the subscribers?
+
+  +\bo  Are there subscribers?
+
+
+       %  ezmlm-list DIR
+
+
+
+
+  +\bo  Are there moderators?
+
+
+
+  % ezmlm-list moddir
+
+
+
+
+  where ``moddir'' is the contents of D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be (for remote admin
+  lists), of D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb (for subscription moderated lists) or D\bDI\bIR\bR/\b/m\bmo\bod\bd-\b-
+  p\bpo\bos\bst\bt (for message moderation), if and only if the contents start with
+  a forward slash. The default in all cases is D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/. If both
+  D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb and D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be contain directory names, the one in D\bDI\bIR\bR/\b/m\bmo\bod\bd-\b-
+  s\bsu\bub\bb is used for both subscription moderation and remote admin.
+
+  +\bo  Are the ownerships of all files correct, i.e. read/writable for the
+     owner?
+
+
+       % chown -R user DIR
+
+
+
+
+  For lists under alias:
+
+
+       % chown -R alias DIR
+
+
+
+
+  If you use custom moderator databases, those directories and all their
+  contents must also be readable for the user under which the list oper-
+  ates (i.e. the user qmail changes to during the delivery).
+
+  +\bo  Read the qmail log and capture relevant parts.
+
+  +\bo  Did you customize the package at all? If so, try the default
+     settings which are known to work.
+
+  +\bo  Did you customize e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b)? Try to use the default copy (skip the
+     -c switch).
+
+  +\bo  Did your customization of .\b.e\bez\bzm\bml\blm\bmr\brc\bc fail to have an effect?
+     Remember to use the -c switch. The .\b.e\bez\bzm\bml\blm\bmr\brc\bc file used is the one in
+     ``dotdir'', i.e. the directory where the .\b.q\bqm\bma\bai\bil\bl files go, usually,
+     but NOT necessarily, the one in your home directory.
+
+  +\bo  Make sure you followed the instructions in man pages and other
+     documentation. Most of the problems are due to not closely
+     following the instructions. Try again with a new test list.
+
+  +\bo  Make sure to take notes of how the list was created (which flags
+     you used, etc.).
+
+  +\bo  use ezmlm-check(1) (see ``Using ezmlm-check to find setup
+     errors'').  and compare the variables identified by ezmlm-check to
+     D\bDI\bIR\bR/\b/i\bin\bnl\blo\boc\bca\bal\bl, etc. If you don't get a reply from ezmlm-check, then
+     message was not delivered properly. Check your qmail setup.
+
+  +\bo  Try to find your problem or a question/item close to it in the FAQ.
+
+  +\bo  If this didn't resolve the problem, post to the ezmlm mailing list,
+     describing how you set up the list, your general setup (especially
+     the relevant control files for a virtual domain), what works and
+     what doesn't and what results from different actions (log entries,
+     error messages).
+
+  If you have solved a problem that you believe might be more general,
+  please send a description of the problem and its solution to the
+  authors, ideally as a FAQ item.
+
+
+  6\b6.\b.2\b2.\b.  H\bHo\bow\bw d\bdo\bo I\bI r\bre\bep\bpo\bor\brt\bt e\bez\bzm\bml\blm\bm b\bbu\bug\bgs\bs?\b?
+
+  If you have found a bug in the ezmlm-idx additions, please send a bug
+  report by E-mail to lindberg@id.wustl.edu. Describe the error, your
+  setup, and your system in sufficient detail so that it can be
+  reproduced by third parties. Include relevant sections of mail log,
+  and information about any error messages returned. If you ran into a
+  problem and resolved it on your own, include a fix as a context diff
+  against the distribution.
+
+  If you have found a bug in ezmlm proper (unlikely), please send a
+  similar bug report to djb@cr.yp.to or djb-ezmlm@cr.yp.to. If you're
+  unsure where the bug is, you can start with lindberg@id.wustl.edu.  If
+  you have problems and questions, please refer to the documentation,
+  then to mailing list archives, then E-mail the ezmlm mailing list or
+  the authors.
+
+
+  6\b6.\b.3\b3.\b.  W\bWh\bhe\ber\bre\be d\bdo\bo I\bI s\bse\ben\bnd\bd s\bsu\bug\bgg\bge\bes\bst\bti\bio\bon\bns\bs f\bfo\bor\br e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx i\bim\bmp\bpr\bro\bov\bve\bem\bme\ben\bnt\bts\bs?\b?
+
+  E-mail to lindberg@id.wustl.edu, ideally with a context diff.  For
+  ezmlm proper, ezmlm@list.cr.yp.to may be better.
+
+
+  6\b6.\b.4\b4.\b.  U\bUs\bsi\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-t\bte\bes\bst\bt t\bto\bo c\bch\bhe\bec\bck\bk t\bth\bhe\be e\bez\bzm\bml\blm\bm(\b(-\b-i\bid\bdx\bx)\b) p\bpr\bro\bog\bgr\bra\bam\bms\bs.\b.
+
+  ezmlm-test(1) tests the different ezmlm(-idx) programs. It is useful
+  to test your installation. If this program succeeds, it is not likely
+  that you have problems due to platform-specific ezmlm(-idx) bugs. If
+  ezmlm-test(1) fails, this is the place to start. The program is good
+  at finding problems but not that easy to use to determine the cause.
+  Start by finding the place where it fails, recreate the conditions
+  (add ``exit 0'' just before the point of failure and set the
+  environment variables as set by the script), then try to run the
+  command manually. ~\b~/\b/_\b__\b_T\bTS\bST\bTD\bDI\bIR\bR_\b__\b_e\ber\brr\br may contain a relevant error
+  message.  For further help, E-mail lindberg@id.wustl.edu.
+
+
+  6\b6.\b.5\b5.\b.  U\bUs\bsi\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-c\bch\bhe\bec\bck\bk t\bto\bo f\bfi\bin\bnd\bd s\bse\bet\btu\bup\bp e\ber\brr\bro\bor\brs\bs.\b.
+
+  ezmlm-check(1) is included in the ezmlm-idx distribution. ezmlm-
+  check(1) is an evolving shell script which when put into a .\b.q\bqm\bma\bai\bil\bl file
+  of a mailing list will return information about the environment
+  variables passed by qmail to ezmlm as well as the list setup. It also
+  attempts to check for common error conditions, such as HOST and
+  D\bDI\bIR\bR/\b/i\bin\bnh\bho\bos\bst\bt mismatch, missing files, etc. To use ezmlm-check(1), place
+  a line:
+
+
+       |/usr/local/bin/ezmlm/ezmlm-check 'DIR'
+
+
+
+
+  where ``DIR'' is the list directory, as the first line in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br
+  (for mail to list), D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br (for mail to list-subscribe, list-
+  help, etc), D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br (for mail to list-accept, list-reject).
+  ezmlm-check(1) will send its output to SENDER. The rest of the .\b.q\bqm\bma\bai\bil\bl
+  file will be ignored.  If you use a non-standard ezmlm binary direc-
+  tory, change the ezmlm-check(1) path accordingly.
+
+  ezmlm-check(1) in combination with mail logs and ezmlm error messages
+  should make it easy to diagnose setup problems. When done, don't
+  forget to remove the ezmlm-check(1) line. It is not security-proofed
+  against SENDER manipulation and with it in place, the list won't work.
+
+  ezmlm-check(1) does not check all aspects of list generation, but
+  catches all common errors when lists are created with ezmlm-make(1),
+  an many other errors as well. The ezmlm-check(1) reply is also very
+  valuable for support via E-mail.
+
+
+  6\b6.\b.6\b6.\b.  P\bPo\bos\bst\bts\bs a\bar\bre\be r\bre\bej\bje\bec\bct\bte\bed\bd:\b: S\bSo\bor\brr\bry\by,\b, n\bno\bo m\bma\bai\bil\blb\bbo\box\bx h\bhe\ber\bre\be b\bby\by t\bth\bha\bat\bt n\bna\bam\bme\be
+  (\b(#\b#5\b5.\b.1\b1.\b.1\b1)\b).\b.
+
+  qmail tried to deliver the mail, but there is no mailbox with that
+  name.  ezmlm-make(1) was used with incorrect arguments, often in
+  conjunction with a virtual domain setup. If the list is in a virtual
+  domain, the ``host'' argument for ezmlm-make(1) should be the virtual
+  domain, not the real host name.  See ``What names can I use for my
+  mailing lists?''  and ``Lists in virtual domains'' for more info.
+
+  Other possibilities are that your qmail setup is incorrect.  For a
+  virtual domain controlled by user ``virt'', create ~\b~v\bvi\bir\brt\bt/\b/.\b.q\bqm\bma\bai\bil\bl-\b-t\bte\bes\bst\bt
+  containing ``|/bin/echo "It worked"; exit 100''. Now send mail to
+  test@virtual.dom. If delivery works, you should get an error message
+  ``It worked'' back. If you get anything else, you need to adjust your
+  qmail setup. Similarly, for a normal user, create ~\b~u\bus\bse\ber\br/\b/.\b.q\bqm\bma\bai\bil\bl-\b-t\bte\bes\bst\bt
+  and mail user-test@host to test that you control extension addresses.
+  If this fails, contact your system administrator or adjust your qmail
+  setup.
+
+  If these tests worked, but your list still does not, you most likely
+  supplied an incorrect ``dot'' argument for ezmlm-manage(1). It should
+  be ~\b~v\bvi\bir\brt\bt/\b/.\b.q\bqm\bma\bai\bil\bl-\b-t\bte\bes\bst\bt for the list test@virtual.dom and ~\b~u\bus\bse\ber\br/\b/.\b.q\bqm\bma\bai\bil\bl-\b-
+  t\bte\bes\bst\bt for the list user-test@host.
+
+
+  6\b6.\b.7\b7.\b.  P\bPo\bos\bst\bt a\bar\bre\be n\bno\bot\bt s\bse\ben\bnt\bt t\bto\bo s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.
+
+
+     N\bNo\bon\bn-\b-m\bmo\bod\bde\ber\bra\bat\bte\bed\bd l\bli\bis\bst\bts\bs
+
+        1. Read the qmail log. Is your message delivered to the list?
+           You can also:
+
+
+
+             % cat DIR/num
+
+
+
+
+        2. Send a message to the list.
+
+        3. See if it was received/processed:
+
+
+
+             % cat DIR/num
+
+
+
+
+        If the number was incremented, the message went to the list, and
+        was successfully sent out in the opinion of ezmlm-send(1)
+        (ezmlm-send(1) doesn't mind if there are no subscribers, so
+        check that there really are both moderators and subscribers.
+        These are added with ezmlm-sub(1). You can not just put
+        addresses into a text file!).
+
+
+     M\bMe\bes\bss\bsa\bag\bge\be m\bmo\bod\bde\ber\bra\bat\bte\bed\bd l\bli\bis\bst\bts\bs
+
+        1. Check number of queued messages awaiting moderation:
+
+
+
+             % ls -l DIR/mod/pending
+
+
+
+
+        2. Send a message to the list.
+
+        3. Check if another message was added to the queue:
+
+
+
+             % ls -l DIR/mod/pending
+
+
+
+
+        A new file should have appeared. If this file has the owner exe-
+        cute bit set, it was successfully processed by ezmlm-store(1).
+        If this is true, but no moderation request was sent, then con-
+        tinue with ``Messages posted to the list do not result in moder-
+        ation requests''. If there is no new file, the message did not
+        reach ezmlm-store(1), or ezmlm-store(1) failed early. In both
+        cases, the mail log should tell you more.
+
+        If the message is there, but the owner execute bit is not set,
+        ezmlm-store(1) failed.  Check the mail log. Possible reasons
+        include a failure to find the ezmlm-send(1) binary or D\bDI\bIR\bR/\b/m\bms\bsg\bg-\b-
+        s\bsi\biz\bze\be is specified and the message body size is outside of the
+        allowed range (again, this is accompanied by an error message
+        and mail log entry).
+
+
+     G\bGe\ben\bne\ber\bra\bal\bl
+
+        1. If the message was not received/processed, there should be an
+           error message in the mail log.
+
+        2. Fix temporary and permanent errors with the help of qmail and
+           ezmlm documentation.
+
+        3. If there is no log entry at all, then the mail went to
+           another host. Check your qmail setup.
+
+        4. If mail was delivered to the list, but not forwarded to the
+           subscribers (check the qmail log - there should be an entry
+           for a new delivery to the list), t\bth\bhe\be m\bmo\bos\bst\bt c\bco\bom\bmm\bmo\bon\bn e\ber\brr\bro\bor\br i\bis\bs
+           t\bth\bha\bat\bt t\bth\bhe\ber\bre\be a\bar\bre\be n\bno\bo s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.  In this case, ezmlm-send(1)
+           sends a message from list-help@host, and logs success, but no
+           recipients are logged. To qmail, it is perfectly acceptable
+           to send a message without recipients, so no error message is
+           logged.
+
+        5. Check subscribers:
+
+
+                % ezmlm-list DIR
+
+
+
+
+        6. Assure that ownerships are correct on the list directories:
+
+
+                     % chown -R user DIR
+
+
+
+
+        For lists owned by the ``alias'' user (in ~alias):
+
+
+                     % chown -R alias DIR
+
+
+
+
+        7. Most other problems should be easily corrected with the help
+           of the qmail log.
+
+
+  6\b6.\b.8\b8.\b.  e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be f\bfa\bai\bil\bls\bs:\b: u\bus\bsa\bag\bge\be:\b: e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be .\b..\b..\b.
+
+  The command line you specified is incomplete. Usually, a command line
+  argument has been omitted or a switch was placed after the other
+  arguments rather than before.
+
+  The same error is issued when you attempt to invoke ezmlm-make(1) with
+  only the ``DIR'' argument without using the ``-e'' or ``-+'' switch.
+  Other command line arguments can be omitted only when editing lists
+  created or previously edited with ezmlm-make from ezmlm-idx>=0.23.
+
+  Some special situations use ezmlm-make(1) as a general script
+  processor, e.g.  the setting up of sublists with ezmlmsubrc(5) and of
+  a global interface with ezmlmglrc(5). Here, there is no ``memory'' so
+  all arguments have to be specified, even when using the ``-e'' or
+  ``-+'' switches.
+
+
+  6\b6.\b.9\b9.\b.  e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be f\bfa\bai\bil\bls\bs:\b: U\bUn\bna\bab\bbl\ble\be t\bto\bo c\bcr\bre\bea\bat\bte\be .\b..\b..\b.
+
+  This error occurs when ezmlm-make is used to set up a list, and it
+  tries to create a directory or a .\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt link that already exists.
+  Usually, this occurs because the list already exists. If you are
+  creating a new list, first erase remnants of any old test lists by
+  deleting the list directory and the link files: _\bN_\bO_\bT_\bE_\b: _\bD_\bO _\bN_\bO_\bT _\bU_\bS_\bE _\bT_\bH_\bE_\bS_\bE
+  _\bC_\bO_\bM_\bM_\bA_\bN_\bD_\bS _\bW_\bI_\bT_\bH_\bO_\bU_\bT _\bU_\bN_\bD_\bE_\bR_\bS_\bT_\bA_\bN_\bD_\bI_\bN_\bG _\bT_\bH_\bE_\bM_\b.  You may erase more than you
+  intended!
+
+
+
+       % rm -rf DIR
+       % rm -rf ~/.qmail-list ~/.qmail-list-*
+
+
+
+
+  If you want to save some files (such as in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/), make backup
+  copies first, run ezmlm-make, then copy the backups to D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/. Of
+  course, it is usually easier to create a custom .\b.e\bez\bzm\bml\blm\bmr\brc\bc, and than use
+  that for all your lists.
+
+  To use ezmlm-make(1) to modify an existing list, without changing the
+  subscriber or moderator lists or the message archive, use the ezmlm-
+  make ``-e'' switch. With this, you need to re-specify all desired
+  switches. If instead you use ``-+'' you need to specify only switches
+  that are changed/new.  NOTE: any customization that you've made to
+  program files like D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br will be overwritten. For instance, if
+  you manually added checks to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br or added a pointer to a custom
+  moderator database in e.g.  D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb these changes will be lost.  To
+  retain such changes (especially ones that are common for several of
+  your lists), place them in a local ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc file instead. You can
+  either make such changes the default for your lists, or you can
+  configure ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc so that they are added only if a specific ezmlm-
+  make switch is used.  (see ``Customizing ezmlm-make operation'').
+
+
+  6\b6.\b.1\b10\b0.\b.  e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be f\bfa\bai\bil\bls\bs:\b: .\b..\b..\b. e\bez\bzm\bml\blm\bmr\brc\bc d\bdo\boe\bes\bs n\bno\bot\bt e\bex\bxi\bis\bst\bt
+
+  There is no readable ezmlmrc(5) file in /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bm nor in the ezmlm
+  binary directory. If you have .\b.e\bez\bzm\bml\blm\bmr\brc\bc in ``dotdir'' (see
+  ``Terminology: dotdir'') use the ezmlm-make(1) ``-c'' switch (see
+  ``Customizing ezmlm-make operation'').  _\bN_\bo_\bt_\be_\b: The default location for
+  a global edited e\bez\bzm\bml\blm\bmr\brc\bc file is /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bm/\b/e\bez\bzm\bml\blm\bmr\brc\bc as of ezmlm-
+  idx-0.40.
+
+
+  6\b6.\b.1\b11\b1.\b.  I\bIn\bnd\bde\bex\bx/\b/g\bge\bet\bt/\b/t\bth\bhr\bre\bea\bad\bd r\bre\beq\bqu\bue\bes\bst\bts\bs f\bfa\bai\bil\bl q\bqu\bui\bie\bet\btl\bly\by o\bor\br w\bwi\bit\bth\bh e\ber\brr\bro\bor\brs\bs f\bfr\bro\bom\bm
+  e\bez\bzm\bml\blm\bm-\b-m\bma\ban\bna\bag\bge\be.\b.
+
+  Make sure this is an indexed list and has an ``ezmlm-get'' line first
+  in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. If not, your commands are fed directly to ezmlm-
+  manage(1). If they contain ``-'', ezmlm-manage interprets the rest as
+  an address to which it sends the error message.  Usually, this results
+  in a "trash address" mail log entry and a bounce, which is why you
+  don't see any error message. The same happens if you send non-existing
+  commands followed by ``-'' and arguments. Thus, list-gugu-54@host
+  results in an ezmlm-manage error, resulting in help text being sent to
+  54@localhost ... When testing, try using syntax with a ``.'', not a
+  ``-'', after the action command, e.g. list-get.54_60@host. This will
+  assure that error messages get back to you.
+
+
+  6\b6.\b.1\b12\b2.\b.  D\bDi\big\bge\bes\bst\bt t\btr\bri\big\bgg\bge\ber\bri\bin\bng\bg r\bre\beq\bqu\bue\bes\bst\bts\bs f\bfa\bai\bil\bl.\b.
+
+  (Digest triggering by mail is a relic from older versions. Use the
+  standard setup with ezmlm-tstdig(1) as by ezmlm-make(1) ``-d'', or run
+  ezmlm-get(1) directly from the command line via crond(8).)
+
+  If you get an error message, it tells you why the request failed. If
+  you do not, see the previous item. Try using syntax without ``-''
+  after the ``dig'' command. Also, requests that would result in an
+  empty digest are silently ignored, but the reason why no digest was
+  created is logged to the mail log. This is done so that cron scripts
+  generating daily digest will just fail silently, rather than
+  generating an error, for what isn't really one.
+
+
+  6\b6.\b.1\b13\b3.\b.  R\bRe\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\bio\bon\bn (\b(u\bun\bn)\b)s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\be c\bco\bon\bnf\bfi\bir\brm\bm r\bre\beq\bqu\bue\bes\bst\bts\bs g\bgo\bo t\bto\bo t\bth\bhe\be
+  u\bus\bse\ber\br,\b, n\bno\bot\bt t\bth\bhe\be m\bmo\bod\bde\ber\bra\bat\bto\bor\br.\b.
+
+  Either the list is not set up for remote administration (i.e.
+  D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be does not exist), or the moderator is sending the request
+  from an address that is not in the moderator database (e.g. from
+  Fred@host.dom, when fred@host.dom is in the moderator db, but
+  Fred@host.dom is not). ezmlm-manage(1) has no way of knowing that the
+  SENDER is a moderator and treats the request as coming from a regular
+  user, i.e. it sends a confirmation request to the target address.
+  Correct the SENDER address, the address in the moderator db, or create
+  D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be. If you are using a non-default moderator db location, make
+  sure that the moddir name is in D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be (for remote admin only) or
+  D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb (if there is subscription moderation as well). In both
+  cases, the contents will be ignored unless they start with a ``/''.
+
+
+  6\b6.\b.1\b14\b4.\b.  (\b(U\bUn\bn)\b)s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs d\bdo\boe\bes\bs n\bno\bot\bt r\bre\bec\bce\bei\biv\bve\be a\ba (\b(u\bun\bn)\b)s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\be a\bac\bck\bkn\bno\bow\bwl\ble\bed\bdg\bge\be-\b-
+  m\bme\ben\bnt\bt
+
+  With normal ezmlm lists, a subscriber confirming a subscription or a
+  non-subscriber confirming a unsubscribe request results in a message
+  to the target address. This message is suppressed when the list is set
+  up for subscription and/or remote administration, so that
+  confirmations from multiple moderators do not result in multiple
+  messages to the target address. The target address is always notified
+  if the subscriber status of the address changes (from non-subscriber
+  to subscriber or vice versa).
+
+
+  6\b6.\b.1\b15\b5.\b.  M\bMe\bes\bss\bsa\bag\bge\bes\bs p\bpo\bos\bst\bte\bed\bd t\bto\bo a\ba m\bmo\bod\bde\ber\bra\bat\bte\bed\bd l\bli\bis\bst\bt a\bar\bre\be s\bse\ben\bnt\bt o\bou\but\bt w\bwi\bit\bth\bho\bou\but\bt m\bmo\bod\bde\ber\br-\b-
+  a\bat\bti\bio\bon\bn.\b.
+
+  The list is not set up as a moderated list. Check D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br.  If
+  should contain a ezmlm-store(1) line after the ezmlm-reject line if it
+  is a moderated list. No ezmlm-send(1) line should be in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br.
+  If there is, the list is not moderated. Also, D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt must exist.
+  If it does not, ezmlm-store(1) will post the messages directly (via
+  ezmlm-send(1)) without sending them out for moderation first. This
+  makes it easy to temporarily remove message moderation by simply
+  removing D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt, but may be confusing if the user is unaware of
+  this ezmlm-store(1) feature.
+
+
+  6\b6.\b.1\b16\b6.\b.  M\bMe\bes\bss\bsa\bag\bge\bes\bs p\bpo\bos\bst\bte\bed\bd t\bto\bo a\ba m\bmo\bod\bde\ber\bra\bat\bte\bed\bd l\bli\bis\bst\bt d\bdo\bo n\bno\bot\bt r\bre\bes\bsu\bul\blt\bt i\bin\bn m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn
+  r\bre\beq\bqu\bue\bes\bst\bts\bs.\b.
+
+
+  +\bo  Check that ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt is a link to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br.
+
+  +\bo  Check that D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br contains ezmlm-store(1) and not ezmlm-
+     send(1).  If this is not the case, the list is not message
+     moderated.
+
+  +\bo  Check for the presence of D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt. If this file is missing, the
+     list is not moderated, even if D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br is set up with ezmlm-
+     store(1).
+
+  +\bo  Check qmail logs for error conditions during post delivery and
+     correct these. If the messages are delivered correctly, verify that
+     ezmlm-store(1) generated the moderation requests to the moderators.
+
+  +\bo  Check to see that there are indeed moderators:
+
+
+
+       % ezmlm-list moddir
+
+
+
+
+  where ``moddir'' is the contents of D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt if they start with a
+  ``/'', otherwise those of D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be (same ``/'' requirement), and
+  D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ by default.
+
+
+  +\bo  Check file ownerships.
+
+     Another common problem is directory ownerships, especially for
+     lists under ~alias. To correct this error, issue the following
+     command while in the ~alias directory (User the user/group of the
+     list owner; for ~alias lists user=alias, group=qmail):
+
+
+       % chown -R user DIR
+
+
+
+
+
+  6\b6.\b.1\b17\b7.\b.  M\bMo\bod\bde\ber\bra\bat\bti\bio\bon\bn r\bre\beq\bqu\bue\bes\bst\bt r\bre\bep\bpl\bli\bie\bes\bs d\bdo\bo n\bno\bot\bt r\bre\bes\bsu\bul\blt\bt i\bin\bn t\bth\bhe\be a\bap\bpp\bpr\bro\bop\bpr\bri\bia\bat\bte\be
+  a\bac\bct\bti\bio\bon\bn.\b.
+
+
+  +\bo  Check that the address in the moderation request is correct.
+
+  +\bo  Check that the ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt-\b-a\bac\bcc\bce\bep\bpt\bt-\b-d\bde\bef\bfa\bau\bul\blt\bt and ~\b~.\b./\b/q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt-\b-
+     r\bre\bej\bje\bec\bct\bt-\b-d\bde\bef\bfa\bau\bul\blt\bt links exists and point to D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br.
+
+  +\bo  Check that D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br invokes ezmlm-moderate(1), and that there
+     is a copy of ezmlm-send(1) in the ezmlm binary directory.
+
+  +\bo  Check the qmail log to see that the replies were delivered to this
+     address.
+
+  +\bo  Check directory ownerships. For lists under alias:
+
+
+
+       % chown -R alias DIR
+
+
+
+
+  _\bN_\bO_\bT_\bE_\b: This needs to be done every time you add/remove moderators as
+  ``root''. For user-controlled lists (i.e. you are ``user'' when run-
+  ning e.g. ezmlm-sub(1)) this is not a problem.
+
+  If setting up lists for _\ba_\bl_\bi_\ba_\bs, you can avoid many problems by setting
+  them up as ``alias'', i.e. use ``su alias'' not ``su''.
+
+  If setting up lists for a user controlling a virtual domain, you can
+  avoid many problems by assuming that uid (``su user'') before making
+  any changes.
+
+  +\bo  Check the qmail logs: After the delivery of the moderation request,
+     ezmlm-send(1) should run to send messages to all the list
+     subscribers.
+
+  +\bo  Make sure there are list subscribers:
+
+
+
+       % ezmlm-list DIR
+
+
+
+
+  Most error conditions, incorrect request cookies, etc, should result
+  in informative error messages in the mail log.
+
+
+  6\b6.\b.1\b18\b8.\b.  M\bMo\bod\bde\ber\bra\bat\bto\bor\br c\bco\bom\bmm\bme\ben\bnt\bts\bs w\bwi\bit\bth\bh m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn r\bre\beq\bqu\bue\bes\bst\bt r\bre\bep\bpl\bli\bie\bes\bs a\bar\bre\be n\bno\bot\bt
+  a\bad\bdd\bde\bed\bd t\bto\bo t\bth\bhe\be p\bpo\bos\bst\bt/\b/s\bse\ben\bnt\bt t\bto\bo t\bth\bhe\be p\bpo\bos\bst\bte\ber\br.\b.
+
+  Moderator comments are where the moderator chooses to ``reject'' the
+  message and inform the person posting which his/her message was
+  inappropriate.  However, if a moderator wants to comment on a\bac\bcc\bce\bep\bpt\bte\bed\bd
+  posts, the moderator may only do so via a follow-up post to the list.
+  This is to avoid anonymously tagged-on text to posts. If a moderator
+  has something to say to the list, they should (and can only) do so in
+  regular posts. If you want to edit posts before sending them to the
+  list, set up a moderated list with you as the only moderator. Into
+  D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br before the ezmlm-store(1) line, put a condredirect(1) line
+  that redirects all messages with a SENDER other than you to your
+  address. You can edit the contents ands repost, the message will pass
+  condredirect(1), and hit ezmlm-store(1). You will be asked to confirm
+  (needed to assure that nobody else can post directly) and when you do,
+  the messages is posted.
+
+  Moderator comments for ``reject(ed)'' posts need to be enclosed
+  between two lines (yes, the end marker is required), having ``%%%''
+  starting on one of the first 5 positions of the line. If there are
+  characters before the marker, these will be removed from any comment
+  line that starts with the same characters (e.g. the characters before
+  ``comment2'' in the example below will be removed):
+
+
+  %%%
+  comment
+  %%%
+
+
+  or:
+
+
+  > %%%
+  comment
+  > comment2
+  > %%%
+
+
+  but not:
+
+  %%
+  COMMENT
+  %%
+
+
+  and not:
+
+  %%% this is my comment %%%
+
+
+  or
+
+  ezmlm said>%%%
+  comment
+  ezmlm said>%%%
+
+
+
+
+  6\b6.\b.1\b19\b9.\b.  S\bSo\bom\bme\be h\bhe\bea\bad\bde\ber\brs\bs a\bar\bre\be m\bmi\bis\bss\bsi\bin\bng\bg f\bfr\bro\bom\bm m\bme\bes\bss\bsa\bag\bge\bes\bs i\bin\bn t\bth\bhe\be d\bdi\big\bge\bes\bst\bt.\b.
+
+  By default, only a subset of message headers are sent out in any
+  digest and archive retrieval requests. First, headers in
+  D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bem\bmo\bov\bve\be are stripped. Most non-essential headers are excluded
+  when the default archive retrieval format (``m'') is used.  Use the
+  ``v'' or ``n'' format (see ezmlm-get(1)) to get all message headers
+  that are in the archive.
+
+
+  6\b6.\b.2\b20\b0.\b.  S\bSo\bom\bme\be R\bRe\bec\bce\bei\biv\bve\bed\bd:\b: h\bhe\bea\bad\bde\ber\brs\bs a\bar\bre\be m\bmi\bis\bss\bsi\bin\bng\bg f\bfr\bro\bom\bm m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  ezmlm-idx>=0.313 removes all but the latest ``Received:'' header from
+  messages sent to the list. This is done since messages, especially
+  sent via sublists, may have so many ``Received:'' headers that MTAs
+  with primitive ``loop detection'' erroneously reject them. The
+  subscriber can subscribe, since those messages have fewer such
+  headers, and will receive warning and probe messages, but never see
+  any posts.
+
+  To see all headers of a message for diagnostic purposes, mail
+  mainlist-getv.num@mainhost, where ``num'' is the message number.  All
+  ``Received:'' headers are stored in the archive copy of the message.
+
+  To disable ``Received:'' header pruning, use the ezmlm-send(1) ``-r''
+  switch.
+
+
+  6\b6.\b.2\b21\b1.\b.  M\bMy\by M\bMu\but\btt\bt u\bus\bse\ber\brs\bs c\bca\ban\bnn\bno\bot\bt t\bth\bhr\bre\bea\bad\bd t\bth\bhe\bei\bir\br d\bdi\big\bge\bes\bst\bt m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  The digest by default removed non-essential headers like ``In-Reply-
+  To:'' from messages. Modern MUAs, like _\bM_\bu_\bt_\bt can split out messages
+  from a digest and then thread them based on such headers. To include
+  these and all other headers in the digest messages, use the ``v'' or
+  ``n'' format as described on the ezmlm-get(1) man page. Normally, the
+  threading done by ezmlm is sufficient and the default format preferred
+  to reduce message and digest size, often by 25% or more.
+
+
+  6\b6.\b.2\b22\b2.\b.  P\bPo\bos\bst\bts\bs f\bfa\bai\bil\bl:\b: M\bMe\bes\bss\bsa\bag\bge\be a\bal\blr\bre\bea\bad\bdy\by h\bha\bas\bs M\bMa\bai\bil\bli\bin\bng\bg-\b-L\bLi\bis\bst\bt (\b(#\b#5\b5.\b.7\b7.\b.2\b2)\b).\b.
+
+  The list you are trying to post to is used as a sublist (a list fed
+  with messages from another (ezmlm) list), but not properly set up as a
+  sublist. Put  the name of the parent list (``origlist@orighost'')
+  which exactly matches the SENDER of the original (or parent) list into
+  D\bDI\bIR\bR/\b/s\bsu\bub\bbl\bli\bis\bst\bt.  Check the ownership of D\bDI\bIR\bR/\b/s\bsu\bub\bbl\bli\bis\bst\bt, to make sure that
+  the user controlling the list can read it.
+
+  Alternatively, use the ezmlm-make(1) ``-0 origlist@orighost'' switch
+  (see ``Customizing ezmlm-make operation'').
+
+
+  6\b6.\b.2\b23\b3.\b.  T\bTh\bhe\be l\bla\bas\bst\bt l\bli\bin\bne\be o\bof\bf a\ba D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/  f\bfi\bil\ble\be i\bis\bs i\big\bgn\bno\bor\bre\bed\bd.\b.
+
+  Only complete lines ending with ``newline'' are copied. The last line
+  in the D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ file most likely lacks a terminal ``newline''.
+
+
+  6\b6.\b.2\b24\b4.\b.  N\bNo\bo C\bCO\bON\bNF\bFI\bIR\bRM\bM r\bre\beq\bqu\bue\bes\bst\bts\bs a\bar\bre\be s\bse\ben\bnt\bt t\bto\bo m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs.\b.
+
+  Assuming that the user initiated the subscribe request, got a
+  ``confirm'' request, and replied correctly, there are two possible
+  causes for the problem: Either the list is not subscription moderated
+  (in this case the user is subscribed and received a note saying so) or
+  the list is subscription moderated but no moderators have been added
+  (ezmlm-manage(1) sends out the request and doesn't mind that there are
+  no recipients).
+
+  Check that the list is subscription moderated:
+
+
+  % cat DIR/modsub
+
+
+
+
+  If this fails the list is not subscription moderated. If it succeeds
+  with a directory name with a leading ``/'', this is your ``moddir''.
+  If not:
+
+
+
+       % cat DIR/remote
+
+
+
+
+  If this succeeds with a directory name with a leading ``/'', this is
+  your moddir, otherwise the moddir is ``D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/''.
+
+  Check for moderators:
+
+
+
+       % ezmlm-list moddir
+
+
+
+
+  If there are none, this is your problem. If there are some, check the
+  mail log to see what happened when the CONFIRM requests was supposed
+  to have gone out. Assure correct ownerships for the moderator db:
+
+
+
+       % chown -R user moddir
+
+
+
+
+  For ~alias:
+
+
+
+        # chown -R alias moddir
+
+
+
+
+  Another possible problem is that you are trying to use the remote
+  admin feature to subscribe a user, but you get no CONFIRM request.
+  Usually, this is due to your SENDER address not being in the moderator
+  database.  The CONFIRM request went to the target address instead,
+  since as far as ezmlm is concerned, you are a regular user.
+
+
+  6\b6.\b.2\b25\b5.\b.  D\bDe\bel\bli\biv\bve\ber\bri\bie\bes\bs f\bfa\bai\bil\bl `\b``\b`t\bte\bem\bmp\bpo\bor\bra\bar\bry\by q\bqm\bma\bai\bil\bl-\b-q\bqu\bue\beu\bue\be e\ber\brr\bro\bor\br'\b''\b'
+
+  Usually, this is due to a corrupted qmail queue (should affect all
+  mail) or a corrupted ezmlm subscriber database (See ``How to deal with
+  corrupted subscriber lists'').  ezmlm-idx>=0.40 has more informative
+  qmail error messages.
+
+
+
+
+
+  6\b6.\b.2\b26\b6.\b.  H\bHo\bow\bw t\bto\bo d\bde\bea\bal\bl w\bwi\bit\bth\bh c\bco\bor\brr\bru\bup\bpt\bte\bed\bd s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br l\bli\bis\bst\bts\bs
+
+  Dan has made ezmlm very robust, but a subscriber list can still become
+  corrupted due to e.g. disk errors. Usually, this will lead to a
+  ``temporary qmail-queue error'' because an address does not conform to
+  the standard format. Occasionally, two E-mail addresses are fused,
+  e.g.  ``addr1@hostTaddr2@host''.  To diagnose and fix this type of
+  error, disable deliveries (easiest is to ``chmod 0 DIR/lock''), back
+  up the contents of D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/, then:
+
+
+
+       % ezmlm-list DIR > tmp.tmp
+
+               ( edit tmp.tmp to fix any problems )
+
+       % rm -rf DIR/subscribers/*
+       % ezmlm-sub DIR < tmp.tmp
+
+
+
+
+  This will list all E-mail addresses, allow you to edit them, then re-
+  subscribe them.  Don't forget to re-enable deliveries.
+
+
+  6\b6.\b.2\b27\b7.\b.  V\bVa\bac\bca\bat\bti\bio\bon\bn p\bpr\bro\bog\bgr\bra\bam\bm r\bre\bep\bpl\bli\bie\bes\bs a\bar\bre\be t\btr\bre\bea\bat\bte\bed\bd a\bas\bs b\bbo\bou\bun\bnc\bce\bes\bs b\bby\by e\bez\bzm\bml\blm\bm.\b.
+
+  Standard vacation programs do not reply to messages that contain a
+  ``Precedence: bulk'' header. ezmlm-idx>=0.23 sets up lists with this
+  header in D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd. For older lists, use ``ezmlm-make -+'' or
+  ``ezmlm-make -e'' to update them, or just add a ``Precedence: bulk''
+  line to D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd.
+
+
+  6\b6.\b.2\b28\b8.\b.  D\bDi\big\bge\bes\bst\bts\bs d\bdo\bo n\bno\bot\bt c\bco\bom\bme\be a\bat\bt r\bre\beg\bgu\bul\bla\bar\br h\bho\bou\bur\brs\bs.\b.
+
+  In the default setup, ezmlm-tstdig(1) determines if a new digest is
+  due every time a message arrives to the list. Thus, even though ezmlm-
+  tstdig is set to produce digests 48 hours after the previous digest,
+  the digest will not be generated until a message arrives. If you'd
+  like digests at a specific time each day, use crond(8) and crontab(1)
+  to daily run:
+
+
+               % ezmlm-get DIR
+
+
+
+
+
+  6\b6.\b.2\b29\b9.\b.  P\bPr\bre\bev\bve\ben\bnt\bti\bin\bng\bg l\blo\boo\bop\bps\bs f\bfr\bro\bom\bm m\bmi\bis\bsc\bco\bon\bnf\bfi\big\bgu\bur\bre\bed\bd s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs.\b.
+
+  Occasionally, a subscriber address is misconfigured and automatically
+  sends a message back to the list. Sometimes, the subscriber's setup
+  has removed headers that ezmlm uses for loop detection or the
+  generated messages has nothing in common with the send-out. To block
+  such mail at the list, include the ezmlm-make(1) ``-k'' (kill) switch
+  and add the offending address to D\bDI\bIR\bR/\b/d\bde\ben\bny\by/\b/ with
+
+
+               % ezmlm-sub DIR/deny badadr@badhost
+
+
+
+
+  ezmlm-unsub(1) and ezmlm-list(1) can be used similarly to remove or
+  list the addresses. If your list is configured for remote administra-
+  tion (see ``How remote administration works''), and you are a remote
+  administrator, you can add the address by sending mail to list-deny-
+  badadr=badhost@listhost. Other subscriber database commands work as
+  well for list-deny.
+
+  In other instances, a configuration error somewhere close to the
+  subscriber creates a local mail loop throwing off messages to you.
+  They are often bounces that are sent to the list address or to ``list-
+  help'' due to configuration errors. Rather than accepting these, or
+  the often resulting double bounces to ``postmaster'', just add a
+  ``|/path/ezmlm-weed'' line first to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br or D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. This
+  discards the bounce messages generated by the looping systems. ezmlm-
+  weed(1) is also useful in other settings where excessive numbers of
+  error messages are sent to the wrong address.
+
+
+  6\b6.\b.3\b30\b0.\b.  A\bA u\bus\bse\ber\br c\bca\ban\bn s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\be a\ban\bnd\bd r\bre\bec\bce\bei\biv\bve\bes\bs w\bwa\bar\brn\bni\bin\bng\bg a\ban\bnd\bd p\bpr\bro\bob\bbe\be m\bme\bes\bss\bsa\bag\bge\bes\bs,\b,
+  b\bbu\but\bt n\bno\bo m\bme\bes\bss\bsa\bag\bge\bes\bs f\bfr\bro\bom\bm t\bth\bhe\be l\bli\bis\bst\bt.\b.
+
+  ezmlm lists (ezmlm-idx>=0.31) remove ``Received:'' headers from
+  incoming messages by default. This can be prevented with the ezmlm-
+  send(1) ``-r'' switch.  When the headers are propagated, especially
+  sublist message may have many (15-20 or more), ``Received:'' headers.
+  If there is a poorly configured sendmail host with a ``hopcount'' set
+  too low, it will bounce these messages, incorrectly believing that the
+  many ``Received:'' headers are due to a mail loop.  The reason that
+  administrative from the list do not bounce is that they have fewer
+  ``Received:'' headers, since they originate from the sublist.
+
+  The message with all headers including the removed ``Received:''
+  headers can be retrieved from the list archive with the _\b-_\bg_\be_\bt_\bv command.
+  The top incoming ``Received:'' header is added by qmail at the receipt
+  to the list (or last sublist) host. This header is not removed, to
+  allow the recipient to determine when the message reached the list.
+
+
+  7\b7.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be o\bop\bpe\ber\bra\bat\bti\bio\bon\bn v\bvi\bia\ba e\bez\bzm\bml\blm\bmr\brc\bc
+
+
+  7\b7.\b.1\b1.\b.  U\bUs\bsi\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be t\bto\bo e\bed\bdi\bit\bt e\bex\bxi\bis\bst\bti\bin\bng\bg l\bli\bis\bst\bts\bs.\b.
+
+  With ezmlm-make(1) (from ezmlm-idx >=0.21) you can use the ``-e''
+  switch to edit existing lists.  Invoke the ezmlm-make(1) command just
+  as you would to create the list anew, but change the switches to
+  reflect the desired change, and add the ``-e'' switch. ezmlm-make will
+  accept preexisting directories and overwrite or remove files to change
+  the setup.  The message counter (D\bDI\bIR\bR/\b/n\bnu\bum\bm), digest counters (D\bDI\bIR\bR/\b/d\bdi\big\bgn\bnu\bum\bm
+  and D\bDI\bIR\bR/\b/d\bdi\big\bgi\bis\bss\bsu\bue\be), the key (D\bDI\bIR\bR/\b/k\bke\bey\by) and the message archive will not
+  be affected.
+
+  If the list has been created or previously edited with ezmlm-make(1)
+  from ezmlm-idx>=0.23, the list remembers (via D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg) the
+  arguments and the switches. All you have to do is to use the ezmlm-
+  make(1) ``-+'' switch and specify options you wish to change, or use
+  the ``-e'' switch and specify all non-default options you'd like to
+  use.
+
+  _\bN_\bO_\bT_\bE_\b: ezmlm-make(1) ``-e'' and ``-+'' will OVERWRITE any manual
+  customizations you have made to the program files, but not text files
+  and D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd, D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bem\bmo\bov\bve\be, etc. To reset all such files
+  (such as when changing list name), use ``-ee'' or ``-++''.
+
+  To make general customizations, please change e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) (see ``What
+  is ezmlmrc?''  or read on) instead and use the ``-c'' switch as well.
+  DO NOT use this option to change production lists without testing it
+  on other lists first.  Also, for some changes, removing or adding a
+  flag is sufficient (see ``How do I quickly change properties of my
+  list'').
+
+
+  7\b7.\b.2\b2.\b.  W\bWh\bha\bat\bt i\bis\bs e\bez\bzm\bml\blm\bmr\brc\bc?\b?
+
+  ezmlm-make(1) has a number of default switches that through e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b)
+  have defined functions. These allow creation of many standard lists.
+
+  In addition, ezmlm-make(1) operation is fully customizable via
+  modification of the template file, ezmlmrc(5) or .ezmlmrc. A default
+  ezmlmrc(5) is installed in the ezmlm binary directory.  The system
+  administrator can install a system-wide default e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) file in
+  /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc (or symlinked from there) which overrides the file in the
+  ezmlm binary directory. If the ezmlm-make(1) ``-c'' (custom) switch is
+  used, ezmlm-make(1) will look for .\b.e\bez\bzm\bml\blm\bmr\brc\bc in the ``dotdir'', i.e. the
+  directory in which the .\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt links are placed. This is usually a
+  set directory for a given user/virtual domain (usually, the home
+  directory for the user controlling the lists).
+
+  e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) controls everything except creation of the list directory
+  itself and the key used for cookie generation. The syntax of
+  e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) is documented in ezmlm-make(1), the ezmlmrc(5) man page,
+  and in the ezmlmrc(5) file installed in the ezmlm binary directory.
+  ezmlm-make limits its effects to within the list ``dot'' and ``DIR''
+  directories. In the ``dotdir'', only links to within ``DIR'' can be
+  created.
+
+
+  7\b7.\b.3\b3.\b.  C\bCh\bha\ban\bng\bgi\bin\bng\bg d\bde\bef\bfa\bau\bul\blt\bts\bs f\bfo\bor\br D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/  f\bfi\bil\ble\bes\bs.\b.
+
+  Copy the ezmlmrc(5) file from the ezmlm bin directory to .\b.e\bez\bzm\bml\blm\bmr\brc\bc in
+  your .\b.q\bqm\bma\bai\bil\bl file base directory (usually your home directory):
+
+
+       % cp /usr/local/bin/ezmlm/ezmlmrc ~/.ezmlmrc
+
+
+
+
+  The base e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) file lives in the ezmlm binary directory, which
+  may differ from ``/\b/u\bus\bsr\br/\b/l\blo\boc\bca\bal\bl/\b/b\bbi\bin\bn/\b/e\bez\bzm\bml\blm\bm/\b/e\bez\bzm\bml\blm\bmr\brc\bc'' if you do not have a
+  default setup.  If your system administrator has placed a ezmlmrc(5)
+  file into the /\b/e\bet\btc\bc directory, start with that one instead, as it is
+  likely to already contain some useful local customization and
+  comments.
+
+  Now edit ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc. Find the tag corresponding to the text file you
+  want to change, e.g. ``</text/mod-request/>'', and modify it
+  appropriately. Some tags have conditional flags, so that succeeding
+  text is copied only if specific switches are on/off. Thus, text
+  succeeding ``</text/file#rms/>'' is copied into D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/f\bfi\bil\ble\be if and
+  only if the ezmlm-make(1) ``-rms'' switches are all used. For more
+  info, see documentation in e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) and the ezmlm-make(1) man page.
+  To invoke a custom .\b.e\bez\bzm\bml\blm\bmr\brc\bc file, use the ezmlm-make(1) ``-c''
+  (custom) switch.
+
+
+  7\b7.\b.4\b4.\b.  C\bCh\bha\ban\bng\bgi\bin\bng\bg d\bde\bef\bfa\bau\bul\blt\bt m\bmo\bod\bde\ber\bra\bat\bto\bor\br d\bdi\bir\bre\bec\bct\bto\bor\bri\bie\bes\bs.\b.
+
+  See above. Edit the .\b.e\bez\bzm\bml\blm\bmr\brc\bc file to add a directory name to e.g.
+  ``</modsub/#s>''. Also, you need to create that directory, and the
+  subscribers subdirectory under it. NOTE: D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ is still required as
+  the base directory for the message moderation queue.
+  7\b7.\b.5\b5.\b.  A\bAd\bda\bap\bpt\bti\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be f\bfo\bor\br v\bvi\bir\brt\btu\bua\bal\bl d\bdo\bom\bma\bai\bin\bns\bs.\b.
+
+  This is not necessary if you use qmail>=1.02 and ezmlm-idx>=0.32.
+
+  The problem with virtual domains is that ezmlm-make(1) by default puts
+  the list name in D\bDI\bIR\bR/\b/i\bin\bnl\blo\boc\bca\bal\bl. However, if the domain host1.dom.com is
+  controlled by the user ``virt'', then the local part of the address
+  for the list list@host.dom.com will be ``virt-list'', not ``list''.
+  This is easily accommodated by putting a .\b.e\bez\bzm\bml\blm\bmr\brc\bc file in ~\b~v\bvi\bir\brt\bt/\b/.  In
+  the ``</inlocal/>'' section of this file, enter ``virt-<#L#>'' instead
+  of ``<#L#>''.  Now, all lists created under ~\b~v\bvi\bir\brt\bt will be
+  automatically set up correctly.
+
+  Similarly, if host1.dom.com is controlled by virt-dom1 and
+  host2.dom.com by ``virt-dom2'', inlocal for list list@host1.dom.com
+  should be ``virt-dom1-list'' and for list@host2.dom.com should be
+  ``virt-dom2-list''. To accommodate this, put ``virt-<#1#>-<#L#>'' in
+  ``</inlocal/>''.
+
+  Running:
+
+
+       % ezmlm-make -c ~virt/LIST ~virt/.qmail-dom1-list \
+                  list host1.dom.com
+
+
+
+
+  will produce a L\bLI\bIS\bST\bT/\b/i\bin\bnl\blo\boc\bca\bal\bl of virt-dom1-list by substituting the
+  first part between two ``-'' (dom1) for ``<#1#>''. Two levels of
+  dashes are accommodated, i.e. ``<#2#>'' will be replaced by the second
+  part between two ``-'' (in this case empty (_\bS_\bi_\bc_\b!)).  For more info,
+  see ezmlm-make(1) and comments in e\bez\bzm\bml\blm\bmr\brc\bc.
+
+
+  7\b7.\b.6\b6.\b.  S\bSe\bet\btt\bti\bin\bng\bg u\bup\bp e\bez\bzm\bml\blm\bm-\b-m\bma\bak\bke\be f\bfo\bor\br s\bsp\bpe\bec\bci\bia\bal\bl s\bsi\bit\btu\bua\bat\bti\bio\bon\bns\bs.\b.
+
+  Ezmlm-make is very flexible. There are only three sets of special
+  command line switches: ``-vV'' for version info, ``-cC'' controlling
+  the use of a custom file .\b.e\bez\bzm\bml\blm\bmr\brc\bc in the ``dot'' directory, and
+  ``-eE'' for edit mode (i.e. reconfiguration of existing list setups).
+  All other switches are soft, i.e. controlled through e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b).  Many
+  switches, have special meanings via e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) and are documented in
+  the man page. Any other switches can be used for customization (_\bN_\bO_\bT_\bE_\b:
+  _\bw_\be _\bm_\ba_\by _\bu_\bs_\be _\bs_\bw_\bi_\bt_\bc_\bh_\be_\bs _\bo_\bt_\bh_\be_\br _\bt_\bh_\ba_\bn _\b`_\b`_\b-_\bx_\by_\bz_\b'_\b' _\bf_\bo_\br _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc _\bp_\bu_\br_\bp_\bo_\bs_\be_\bs _\bi_\bn
+  _\bf_\bu_\bt_\bu_\br_\be _\bv_\be_\br_\bs_\bi_\bo_\bn_\bs_\b.)  The ``-xyz'' switches will always be available for
+  your use, with the ``-x'' switch being configured for some
+  demo/special features in the distributed e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b).  You can use them
+  for anything you like. They are by default off=false. The complement
+  of these switches is ``-XYZ'' (by default on=true). You can use these
+  to cause specific changes in the list setup if a given switch is used.
+  For an example, see the ``-x'' switch as used and documented in the
+  default e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) file.  The switches ``-aip'' are set by default to
+  be backwards compatible with ezmlm-0.53. Other switches are ``off'' by
+  default.
+
+  Switches ``-a-z'' and ``-A-Z'' take no arguments.  Switches ``-0'' and
+  and ``-3-9'' take arguments.  When the ezmlm-make(1) ``-+'' switch is
+  used, the current settings for all these switches are read from the
+  list's D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg (if available).
+
+
+  8\b8.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\be p\bpo\bos\bst\bti\bin\bng\bg t\bto\bo t\bth\bhe\be l\bli\bis\bst\bt.\b.
+
+
+
+  8\b8.\b.1\b1.\b.  R\bRe\beq\bqu\bui\bir\bri\bin\bng\bg t\bth\bhe\be l\bli\bis\bst\bt a\bad\bdd\bdr\bre\bes\bss\bs i\bin\bn T\bTo\bo:\b:/\b/C\bCc\bc:\b: h\bhe\bea\bad\bde\ber\brs\bs.\b.
+
+  SPAM or junk mail is usually sent by mailing a single message to a
+  large number of (unwilling) recipients. As such, it usually does not
+  contain the E-mail address of all recipients (remember, junk mailers
+  pay for these address lists). By rejecting messages that do not have
+  the list address in the To: or Cc: header(s) a large fraction of spam
+  to the list can be filtered out.
+
+  This filter function is activated by default, but will work only if
+  you specify the list directory on the ezmlm-reject(1) command line. To
+  disable this restriction, remove the ``DIR'' argument from the ezmlm-
+  reject(1) command line, or add the ``-T'' switch.
+
+  By default, this error is logged, and an error message is sent to the
+  sender.  Since virtually all the failures will be SPAM and virtually
+  all spam has a faked SENDER, most of these error messages will go to
+  the postmaster.  Thus, you may want to use the ezmlm-reject ``-q''
+  switch (quiet) to suppress the sender notification.
+
+
+  8\b8.\b.2\b2.\b.  R\bRe\bej\bje\bec\bct\bti\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs s\bse\ben\bnt\bt f\bfr\bro\bom\bm o\bot\bth\bhe\ber\br m\bma\bai\bil\bli\bin\bng\bg l\bli\bis\bst\bts\bs.\b.
+
+  ezmlm automatically detects are rejects messages that are sent from
+  other ezmlm mailing lists. Some other mailing list managers do not use
+  a rigorous mechanisms to verify subscribers. Thus, it is possible to
+  subscribe an ezmlm list address to such a mailing list. You can easily
+  block such a list by adding the address to the ``deny'' if you use the
+  ezmlm-make(1) ``-k'' option. However, you can also configure ezmlm-
+  reject(1) to reject messages based on specific headers placed into
+  D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bej\bje\bec\bct\bt. A set of headers which will catch mailing list
+  managers known to us are listed in the ezmlm-reject(1) man page. To
+  activate this option, you must specify the ``-h'' switch and D\bDI\bIR\bR on
+  the ezmlm-reject(1) line in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br. Naturally, you can make this
+  the default by editing ezmlmrc(5) (See ``Customizing ezmlm-make
+  operation'').
+
+
+  8\b8.\b.3\b3.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs b\bba\bas\bse\bed\bd o\bon\bn t\bth\bhe\be S\bSu\bub\bbj\bje\bec\bct\bt l\bli\bin\bne\be.\b.
+
+  ezmlm-reject(1) is by default configured to reject posts with empty
+  subject (``-s'' switch) or with a subject that consists of only an
+  administrative command word (``-c'' switch), such as ``subscribe''. To
+  remove these restrictions, use the ezmlm-reject(1) ``-S'' and ``-C''
+  switch, respectively. You can also into D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br before the ezmlm-
+  send(1) line add:
+
+
+               | grep -i 'subject:' | grep -if DIR/bad_words >/dev/null && \
+                       {echo "bad words found"; exit 100; }
+
+
+
+
+  to reject messages that have a line matching ``Subject:'' followed by
+  any bad word listed in D\bDI\bIR\bR/\b/b\bba\bad\bd_\b_w\bwo\bor\brd\bds\bs.
+
+
+  8\b8.\b.4\b4.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg t\bth\bhe\be s\bsi\biz\bze\be o\bof\bf p\bpo\bos\bst\bts\bs.\b.
+
+  If the ``DIR'' argument is specified on the ezmlm-reject(1) line in
+  D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and D\bDI\bIR\bR/\b/m\bms\bsg\bgs\bsi\biz\bze\be exists and contains a number (in bytes)
+  greater than ``0'', then any posts with a body larger than the number
+  specified is rejected. The maximum message size can optionally be
+  followed by ``:'' and a minimum message body size in bytes.  For
+  moderated lists, messages that are too large are rejected and not sent
+  to the moderators. This feature can be used to prevent the posting an
+  entire digest to the list by setting D\bDI\bIR\bR/\b/m\bms\bsg\bgs\bsi\biz\bze\be slightly below the
+  message size set in your ezmlm-tstdig(1) innovation (if any). A
+  minimum size can catch a few administrative request sent to the main
+  list, but is otherwise not that useful. To always configure your lists
+  with a message size restriction, add to e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b):
+
+
+               </msgsize/>
+               max:min
+
+
+
+
+  The ezmlm-make(1) ``-x'' switch adds this with 40000:2.
+
+
+  8\b8.\b.5\b5.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs b\bba\bas\bse\bed\bd o\bon\bn M\bMI\bIM\bME\bE c\bco\bon\bnt\bte\ben\bnt\bt-\b-t\bty\byp\bpe\be.\b.
+
+  ezmlm-reject(1) will look for D\bDI\bIR\bR/\b/m\bms\bsg\bgs\bsi\biz\bze\be, D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bej\bje\bec\bct\bt, and
+  D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bem\bmo\bov\bve\be if the ``DIR'' argument is specified (``DIR'' can be
+  left out to conserve resources on lists that do not use these
+  features). _\bN_\bo_\bt_\be_\b: _\bT_\bh_\be _\b`_\b`_\bD_\bI_\bR_\b'_\b' _\ba_\br_\bg_\bu_\bm_\be_\bn_\bt _\bi_\bs _\ba_\bl_\bs_\bo _\br_\be_\bq_\bu_\bi_\br_\be_\bd _\bf_\bo_\br _\bt_\bh_\be _\bt_\bh_\be
+  _\bT_\bo_\b:_\b/_\bC_\bc_\b: _\bl_\bi_\bs_\bt _\ba_\bd_\bd_\br_\be_\bs_\bs _\br_\be_\bs_\bt_\br_\bi_\bc_\bt_\bi_\bo_\bn _\b(_\bs_\be_\be _\b`_\b`_\bR_\be_\bq_\bu_\bi_\br_\bi_\bn_\bg _\bt_\bh_\be _\bl_\bi_\bs_\bt _\ba_\bd_\bd_\br_\be_\bs_\bs _\bi_\bn
+  _\bT_\bo_\b:_\b/_\bC_\bc_\b: _\bh_\be_\ba_\bd_\be_\br_\bs_\b'_\b'_\b)_\b.  If the message contains MIME parts that are of a
+  content-type listed in D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bej\bje\bec\bct\bt they are rejected. If the
+  message is a simple MIME message of a content-type listed in either
+  D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bej\bje\bec\bct\bt or D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bem\bmo\bov\bve\be it is also rejected.
+
+  There is currently no ezmlm-make(1) switch for D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bej\bje\bec\bct\bt, but it
+  can easily be configured by editing e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b). The ezmlm-make ``-x''
+  switch configures D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bem\bmo\bov\bve\be (see ``mimeremove'') for a list of
+  content-types).  Messages consisting solely of these content-types
+  (rare) will be rejected, and the corresponding MIME parts of composite
+  messages will be removed.
+
+
+  8\b8.\b.6\b6.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs t\bto\bo l\bli\bis\bst\bt s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.
+
+  Use message moderation. As an alternative, implement a check against
+  SENDER by using ezmlm-issubn(1). The latter is easily defeated by
+  faking SENDER. Also, it prevents posts from legitimate subscribers
+  that are subscribed under a different address than the one they send
+  from.  Nevertheless, it may be useful in some situations. Add:
+
+
+
+       |/usr/local/bin/ezmlm/ezmlm-issubn 'DIR' 'DIR/digest' 'DIR/allow' ||
+          { echo "Sorry, you are not allowed to post to this list.";
+            exit 100; }
+
+
+
+
+  _\bA_\bL_\bL _\bO_\bN _\bO_\bN_\bE _\bL_\bI_\bN_\bE to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br before the ezmlm-send(1) line. ``DIR''
+  is the main list directory. If your ezmlm binaries live in a different
+  directory, change the ezmlm-issubn(1) path accordingly. If you would
+  like denied posts to be dropped silently rather than bounced, change
+  the exit code to 99.
+
+  See ``Customizing ezmlm-make operation'' if you want your lists to
+  have some of these features by default or set by specific ezmlm-
+  make(1) switches. The ezmlm-make(1) ``-u'' switch by default sets up
+  restrictions this way.
+
+
+  If you do not want to allow digest subscribers to post, remove
+  D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/ from the ezmlm-issubn command line. To allow posts from an
+  address that is not a subscriber, simply add it to the addresses in
+  D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/:
+
+
+               % ezmlm-sub DIR/allow address@host
+
+
+
+
+  The ``allow'' database can be manipulated remotely by sending mail to
+  list-allow-subscribe@listhost, list-allow-unsubscribe@listhost, etc.
+  If configured for the list, the ``-list'' command for remote adminis-
+  trators will work for the ``allow'' database as well.
+
+  Please note that this setup is not secure, as it is easy to modify the
+  envelope SENDER. For more secure options, see ``Restricting posts to
+  an arbitrary set of E-mail addresses (higher security option)''.
+
+
+
+  8\b8.\b.7\b7.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs t\bto\bo a\ban\bn a\bar\brb\bbi\bit\btr\bra\bar\bry\by s\bse\bet\bt o\bof\bf E\bE-\b-m\bma\bai\bil\bl a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs
+  (\b(h\bhi\big\bgh\bhe\ber\br s\bse\bec\bcu\bur\bri\bit\bty\by o\bop\bpt\bti\bio\bon\bn)\b).\b.
+
+  The easiest way to achieve this is to simply set up a message
+  moderated list, and add all the e-mail addresses to the moderator db.
+  Use a custom location, if you want a different set of moderators for
+  subscription moderation/remote admin. If a "moderator" posts, only
+  s/he will get a confirmation request. If anybody else posts, the post
+  will be sent to all moderators.
+
+
+  To directly bounce posts from SENDERs not in the database, use the
+  ezmlm-store ``-P'' (not public) switch. This is more secure than a
+  simple ezmlm-issubn(1) construct, since faking SENDER to a moderator
+  address will result in a confirmation request to that moderator (which
+  s/he will reject/ignore), rather than a direct post. The draw-back is
+  that each post has to be confirmed, but with the speed of ezmlm the
+  request will arrive immediately after the post is made, so the
+  overhead should is The best choice depends on your particular needs in
+  the trade-off between security and convenience.
+
+  ``ezmlm-make -om'' will set up such a moderated list with ``ezmlm-
+  store -P''.  This is the most useful setup for an announcement list.
+
+
+  Setting a list up in this way with only the owner's address gives you
+  a pretty safe owner-only list.
+
+
+  8\b8.\b.8\b8.\b.  C\bCo\bom\bmp\bpl\ble\bet\bte\bel\bly\by r\bre\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs.\b.
+
+  To completely prevent posting (for instance a message-of-the-day
+  list), set up a normal list, and just remove ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt and
+  D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br altogether. Make posts from the shell, or from shell
+  scripts or crond, by simply piping a (complete) message to ezmlm-
+  send(1):
+
+
+
+       % /usr/local/bin/ezmlm/ezmlm-send DIR < message
+
+
+
+
+  _\bN_\bO_\bT_\bE: This can be done by any user with write access to files within
+  the list directory, so make sure your file modes are set correctly.
+  The ezmlm-send(1) path may need to be changed to match your ezmlm
+  binary directory. It's also a good idea to not allow others to read
+  your list directory and D\bDI\bIR\bR/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/ and other address lists.
+
+
+  8\b8.\b.9\b9.\b.  A\bA g\bge\ben\bne\ber\bra\bal\bl s\bso\bol\blu\but\bti\bio\bon\bn t\bto\bo r\bre\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg p\bpo\bos\bst\bts\bs b\bba\bas\bse\bed\bd o\bon\bn S\bSE\bEN\bND\bDE\bER\bR.\b.
+
+  As discussed above, the security afforded by SENDER checks is minimal,
+  but nevertheless sufficient to keep out most spam and garbage.
+  However, some subscribers post from e-mail addresses other than their
+  subscription address, and users tend to become unfriendly when their
+  posts are denied even though they are subscribers. This is a general
+  solution to this problem which has minimal overhead for the list owner
+  and is essentially completely transparent to the subscriber.
+
+  Set up the list with ezmlm-gate(1) in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br in place of the
+  ezmlm-send(1) line.  To the ezmlm-gate(1) command line add the list
+  directory twice, then a digest directory D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/ (if it exists),
+  then D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/.  Create D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt. Add the list owner as a message
+  moderator.
+
+  With this setup, any message from a SENDER that is a subscriber of the
+  main list, the digest list or added to D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/, will be posted
+  directly, others will be sent to the list owner for approval. If the
+  list wants to automatically approve posts from that address in future
+  (e.g. it is an alias for a subscriber) s/he just adds it to the
+  database in D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/.  If the owner wants to approve this post, but
+  not necessarily future posts from that address, s/he just accepts the
+  message. To reject the message with a comment is equally easy. If the
+  owner wished to have the option to silently ignore posts (and not have
+  the SENDER notified that the post timed out), just add the ezmlm-
+  clean(1) ``-R'' switch in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br.
+
+  In this way, the normal subscriber is always happy and the ``behind
+  the scenes'' work of the owner is minimalized.
+
+  ezmlm-make creates lists with this setup if you specify the ``-u''
+  switch in addition to the ``-m'' switch:
+
+
+
+               % ezmlm-make -mu ~/list ~/.qmail-list joe-list host
+
+
+
+
+  If you omit the ``-m'' switch, the setup will reject posts from non-
+  subscribers that are not in the ``allow'' database.  ezmlm-both(1)
+  uses a set of similar ezmlm-make(1) invocations to create a list with
+  digest, optionally making you a remote admin, list owner, and
+  subscriber to both lists.
+
+
+  9\b9.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+
+  9\b9.\b.1\b1.\b.  A\bAd\bdd\bdi\bin\bng\bg a\ba t\btr\bra\bai\bil\ble\ber\br t\bto\bo o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Put the text in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/t\btr\bra\bai\bil\ble\ber\br. The text is NOT copied to the
+  archived version of the message. This works also for sublists.  Tags
+  ``<#h#>'', ``<#l#>'', and ``<#n#>'' are replaced by the list host,
+  local name, and current message number, respectively.
+
+
+  9\b9.\b.2\b2.\b.  A\bAd\bdd\bdi\bin\bng\bg a\ba s\bsu\bub\bbj\bje\bec\bct\bt p\bpr\bre\bef\bfi\bix\bx t\bto\bo o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Put the exact text in D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx. You can include the message number
+  assigned to the post in the list archive by adding the ``#'' character
+  in the text in D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx (example: put ``lsqb;listname-#rsqb;'' in
+  D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx).  ezmlm does not modify the subject other than by
+  prefixing it with the prefix.  ezmlm knows about rfc2047 encoded
+  subject and can detect a prefix within an encoded word. However, ezmlm
+  will not modify the subject itself. It will add a prefix only of none
+  has been added before. A consequence of this is that a message will
+  have the message number prefix of the first message in the thread
+  rather than a prefix with the number of the message itself. The entire
+  thread can always be retrieved with a message to list-thread-x@host,
+  where ``x'' is the number in the prefix.
+
+  We recommend against using the prefix feature and strongly against the
+  message number prefix. If you use it, make sure you understand the
+  drawbacks, of message modification and subjects that change between
+  message and reply.  ezmlm can deal with this, but other programs may
+  not be able to.
+
+  Sublists ignore D\bDI\bIR\bR/\b/p\bpr\bre\bef\bfi\bix\bx.
+
+  If you add a prefix, especially if you previously added it by other
+  means (procmail, etc.), use ezmlm-idx to re-index the archive. Due to
+  the way ezmlm-get(1) does threading from the subject, it works best if
+  you use exactly the same prefix as you did before.
+
+
+  9\b9.\b.3\b3.\b.  A\bAd\bdd\bdi\bin\bng\bg a\ba h\bhe\bea\bad\bde\ber\br t\bto\bo o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Put the exact header text as a line in D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd.  Thus, if you'd
+  like a ``Precedence: bulk'' header added to outgoing messages, put a
+  line ``Precedence: bulk'' into D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd. This particular header
+  is already added via the default ezmlmrc(5). Any modifications you
+  wish to be active for all future lists should be made via modification
+  of ezmlmrc(5) (see ``Customizing ezmlm-make operation'').  As of
+  ezmlm-idx-0.32, the following tags can be used in D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd, and
+  will be substituted: <#n#> for the current message number, <#l#> for
+  the local part of the list (this will be the digest list for digests),
+  <#h#> for the host part of the list name. These substitutions are done
+  at the time of message delivery, in contrast to the ``capital letter''
+  tags substituted by ezmlm-make(1) when the list is set up.
+
+
+  9\b9.\b.4\b4.\b.  A\bAd\bdd\bdi\bin\bng\bg a\ba m\bme\bes\bss\bsa\bag\bge\be n\bnu\bum\bmb\bbe\ber\br h\bhe\bea\bad\bde\ber\br.\b.
+
+  Don't! A sequence header may be useful for users whose systems don't
+  pass on the ``Return-to:'' header to the MUA.
+
+  Use D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd with a header of the type ``X-Sequence: <#n#>''.
+
+  Bounced messages are identified by their local message numbers, i.e.
+  when ezmlm sends you a message about which messages bounced, it refers
+  to the message number of the sublist. To be consistent with these
+  numbers, and a local sublist archive, use D\bDI\bIR\bR/\b/s\bse\beq\bqu\bue\ben\bnc\bce\be on the sublist,
+  not the main list. To get consistent message numbering in digests,
+  digest have the message number of the first message in the digest.
+
+  ezmlm-idx tries to make message numbering problems with sublists a
+  little easier: sublists use the incoming message number, but only when
+  the sublist is not archived and not indexed. This restriction is
+  necessary for security reasons. Otherwise, an attacker could wreak
+  havoc in the local message archive by sending messages with faked
+  message numbers in the SENDER.
+
+  9\b9.\b.5\b5.\b.  R\bRe\bem\bmo\bov\bvi\bin\bng\bg h\bhe\bea\bad\bde\ber\brs\bs f\bfr\bro\bom\bm o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Put the header up to, but excluding the ``:'' in D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bem\bmo\bov\bve\be.
+
+
+  9\b9.\b.6\b6.\b.  R\bRe\bem\bmo\bov\bvi\bin\bng\bg M\bMI\bIM\bME\bE p\bpa\bar\brt\bts\bs f\bfr\bro\bom\bm m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  ezmlm-idx>=0.30 can strip parts from composite mime messages based on
+  content type. Just put the appropriate content-types such as
+  ``text/ms-word'' or ``text/html'' into D\bDI\bIR\bR/\b/m\bmi\bim\bme\ber\bre\bem\bmo\bov\bve\be. This is
+  automatically configured when using the ezmlm-make(1) ``-x'' switch.
+
+
+  9\b9.\b.7\b7.\b.  L\bLi\bim\bmi\bit\bti\bin\bng\bg `\b``\b`R\bRe\bec\bce\bei\biv\bve\bed\bd:\b:'\b''\b' h\bhe\bea\bad\bde\ber\brs\bs i\bin\bn o\bou\but\btg\bgo\boi\bin\bng\bg m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Sendmail still is being used on the majority of mail hubs. Sendmail
+  has very primitive loop detection, bouncing messages based on
+  excessive ``hopcount''.  The ``hopcount'' is determined by counting
+  ``Received:'' headers. ezmlm by default propagates ``Received:''
+  headers to facilitate message tracking. Thus, messages, especially
+  from a sublist, can have a number of ``Received:'' headers that
+  exceeds the ``hopcount'' set on poorly configured sendmail hosts.
+  Subscription confirmation requests, warning, and probe messages have
+  fewer ``Received:'' headers. Thus, a user may be able to receive
+  these, but not (some of the) list messages. Of course, the best is to
+  correct the configuration on the bouncing host, but this is often
+  under the control of neither list owner nor user.
+
+  To compensate for this problem, ezmlm-send(1) of ezmlm-idx->=0.313 by
+  default removes all ``Received:'' headers except the top one.  They
+  are still written to the archive, an can be retrieved from there using
+  the ``-getv'' command.  To cause ezmlm-send(1) to pass on all the
+  ``Received:'' headers, use the ezmlm-send(1) ``-r'' switch.
+
+
+  9\b9.\b.8\b8.\b.  S\bSe\bet\btt\bti\bin\bng\bg `\b``\b`R\bRe\bep\bpl\bly\by-\b-T\bTo\bo:\b: l\bli\bis\bst\bt@\b@h\bho\bos\bst\bt'\b''\b'.\b.
+
+  This is not recommended, since it leads to dissemination via the list
+  of messages returned from bad auto-responders and MTAs. Also, it may
+  lead to public replies to the list where personal replies were
+  intended. In addition, the original ``Reply-To:'' header is lost. If
+  you do want to add a reply-to list header, put ``reply-to'' into
+  D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\brr\bre\bem\bmo\bov\bve\be, and ``Reply-To: list@host.dom'' into D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\bra\bad\bdd\bd.
+
+
+  9\b9.\b.9\b9.\b.  C\bCo\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg t\bth\bhe\be l\bli\bis\bst\bt s\bso\bo p\bpo\bos\bst\bts\bs a\bar\bre\be n\bno\bot\bt c\bco\bop\bpi\bie\bed\bd t\bto\bo t\bth\bhe\be o\bor\bri\big\bgi\bin\bna\bal\bl
+  s\bse\ben\bnd\bde\ber\br.\b.
+
+  For most mailing lists, you want all subscribers, including the sender
+  of a particular message, to get all messages. This way, the sender
+  sees that the message reached the list. For small lists, such as a
+  project group, it may be annoying for the members to receive their own
+  posts.
+
+  ezmlm-send(1) can be configured to exclude the sender from the
+  recipient E-mail addresses if configured with the ``-C'' switch. To
+  add this switch, edit the ezmlm-send(1) line of D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br.
+
+
+  9\b9.\b.1\b10\b0.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg e\bez\bzm\bml\blm\bm n\bno\bot\bti\bif\bfi\bic\bca\bat\bti\bio\bon\bn m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Most of ezmlm's more commonly used messages are stored in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/.
+  These messages can be edited manually for a list once it is set up, or
+  on a global basis via modification of e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b).  The messages may
+  also be edited via E-mail by remote administrators (remote admin must
+  also be enabled - ezmlm-make switch ``-r'') after the list is
+  established by creating the list using the ezmlm-make(1) ``-n'' (new
+  text files) (see ``How text file editing works'' and see ``Customizing
+  ezmlm-make operation'').
+
+  The most useful messages are D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/s\bsu\bub\bb-\b-o\bok\bk (and for subscription
+  moderated lists D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/m\bmo\bod\bd-\b-s\bsu\bub\bb) for new subscriber information (such
+  as the traditional ``welcome'' message, or a list charter or list
+  posting rules/guidelines); D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/u\bun\bns\bsu\bub\bb-\b-n\bno\bop\bp is useful for messages
+  to frustrated users unsuccessful in their unsubscribe attempts;
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/h\bhe\bel\blp\bp for general help information in reply to list-help@host
+  or unrecognized commands, D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/b\bbo\bot\btt\bto\bom\bm for inclusion at the bottom
+  of virtually all ezmlm messages; D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/m\bmo\bod\bd-\b-h\bhe\bel\blp\bp for moderator
+  information; D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/t\btr\bra\bai\bil\ble\ber\br for a (few) line(s) at the bottom of
+  each post; D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/d\bdi\big\bge\bes\bst\bt for information in the ``Administrivia''
+  section of digests.
+
+
+  9\b9.\b.1\b11\b1.\b.  S\bSp\bpe\bec\bci\bif\bfy\byi\bin\bng\bg c\bch\bha\bar\bra\bac\bct\bte\ber\br s\bse\bet\bt a\ban\bnd\bd c\bco\bon\bnt\bte\ben\bnt\bt-\b-t\btr\bra\ban\bns\bsf\bfe\ber\br-\b-e\ben\bnc\bco\bod\bdi\bin\bng\bg f\bfo\bor\br o\bou\but\bt-\b-
+  g\bgo\boi\bin\bng\bg e\bez\bzm\bml\blm\bm m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  All ezmlm replies, except errors handled directly by qmail, can be
+  sent in any character set and optionally with quoted-printable or
+  base64 content-transfer-encoding. D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ files are always 8-bit
+  files, but even though qmail has no problems with 8-bit mail, other
+  MTAs and MUAs do.  Problems due to this can be avoided by assuring
+  that outgoing ezmlm messages are 7bit by using the appropriate
+  content-transfer-encoding.
+
+  To specify a character set, put the name in D\bDI\bIR\bR/\b/c\bch\bha\bar\brs\bse\bet\bt (default: us-
+  ascii). To specify quoted-printable or base64 content-transfer-
+  encoding, add ``:Q'' or ``:B'' after the character set name in
+  D\bDI\bIR\bR/\b/c\bch\bha\bar\brs\bse\bet\bt.
+
+
+  1\b10\b0.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl.\b.
+
+
+  1\b10\b0.\b.1\b1.\b.  S\bSp\bpe\bec\bci\bif\bfy\byi\bin\bng\bg t\bth\bhe\be f\bfo\bor\brm\bma\bat\bt f\bfo\bor\br r\bre\bet\btr\bri\bie\bev\bve\bed\bd m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Add a format (f) specifier after the archive retrieval command:
+
+
+
+       list-getf@host
+
+
+
+
+  where ``f'' is ``r'' for rfc1153 format, ``m'' (mime; default) for
+  MIME multipart/digest with subset of ordered headers, and ``v'' (vir-
+  gin) MIME multipart/digest, i.e. with all headers retained from the
+  archive, and ``n'' (native) the same as ``v'' except that no threading
+  is performed and messages are returned in numerical order.  Under some
+  circumstances, it may be preferable to have a digest in ``multi-
+  part/mixed''.  The ``x'' (mixed) format is identical to ``m'' except
+  for this header.
+
+  For ezmlm-cron(1), just suffix the format code to the digest code.
+
+
+  1\b10\b0.\b.2\b2.\b.  S\bSp\bpe\bec\bci\bif\bfy\byi\bin\bng\bg t\bth\bhe\be d\bde\bef\bfa\bau\bul\blt\bt f\bfo\bor\brm\bma\bat\bt f\bfo\bor\br d\bdi\big\bge\bes\bst\bts\bs a\ban\bnd\bd a\bar\brc\bch\bhi\biv\bve\be
+  r\bre\bet\btr\bri\bie\bev\bva\bal\bl.\b.
+
+  The ezmlm-get(1) ``-f'' switch can be used to change the default
+  format (MIME with removal of less relevant headers) to other formats.
+  The format specifiers are the same as for individual archive
+  retrievals (see ``Specifying the format for retrieved messages'').
+
+
+  1\b10\b0.\b.3\b3.\b.  L\bLi\bim\bmi\bit\bti\bin\bng\bg t\bth\bhe\be n\bnu\bum\bmb\bbe\ber\br o\bof\bf m\bme\bes\bss\bsa\bag\bge\bes\bs p\bpe\ber\br -\b-g\bge\bet\bt/\b/-\b-i\bin\bnd\bde\bex\bx r\bre\beq\bqu\bue\bes\bst\bt.\b.
+
+  By default, a single -get request returns a maximum of 100 messages,
+  and a single -index request 2000 subjects entries (20 files of 100
+  subjects entries each). This can be changed by editing MAXGET, and
+  MAXINDEX in i\bid\bdx\bx.\b.h\bh and recompiling. Remember to edit t\bte\bex\bxt\bt/\b/b\bbo\bot\btt\bto\bom\bm,
+  t\bte\bex\bxt\bt/\b/b\bbo\bou\bun\bnc\bce\be, and e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) to reflect these changes so that your
+  users won't get confused.
+
+
+  1\b11\b1.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl.\b.
+
+
+  1\b11\b1.\b.1\b1.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg a\bar\brc\bch\bhi\biv\bve\be a\bac\bcc\bce\bes\bss\bs t\bto\bo s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.
+
+  If you use ezmlm-get(1), archive retrieval can be restricted by using
+  the ezmlm-make(1) ``-g'' (guard archive) switch. This in turn sets
+  ezmlm-get(1) up with its ``-s'' switch, allowing access only to
+  addresses that are subscribers of the list, or of the digest list, or
+  that are present in an extra address database stored in D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/.
+  Addresses can be added remotely by mailing list-allow-
+  useralias=userhost@listhost. Other commands, such as ``subscribe''
+  work as expected. As you can see, the different programs have many
+  options and ezmlm-make(1) organizes most of them into the most useful
+  sets to make it easier. Don't hesitate to look at the ezmlmrc(5) man
+  page and man pages for individual commands. There are many useful
+  options to more finely tune your lists to your taste. Via modification
+  of ezmlmrc(5) you can make your favorite options the default!
+
+  Since ezmlm-get always sends the reply to SENDER, this assures that
+  only subscribers can get archive excerpts. Since SENDER is easily
+  faked, anyone can still request archive info (and drain system
+  resources), but replies go only to subscriber E-mail addresses.  The
+  D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/ database can be used to manually add addresses that should
+  be given archive access, but are not subscribers. This may be an
+  address of a subscriber who posts from an address other than his or
+  her subscription address.
+
+
+  1\b11\b1.\b.2\b2.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg a\bav\bva\bai\bil\bla\bab\bbl\ble\be a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl c\bco\bom\bmm\bma\ban\bnd\bds\bs.\b.
+
+  If you want to disable all archive retrieval except digest creation,
+  simply add the ``-C'' command line switch to the ezmlm-get(1) line in
+  D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. If you don't want digest creation via trigger messages
+  and D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br, but use other means to created digests, you can
+  remove the ezmlm-get(1) line from D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br.
+
+
+  1\b11\b1.\b.3\b3.\b.  R\bRe\bes\bst\btr\bri\bic\bct\bti\bin\bng\bg a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl t\bto\bo m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs.\b.
+
+  If D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc does not exist, ezmlm-manage(1) and ezmlm-get(1) modify
+  their behavior. They disallow user requests, but for remote
+  administration lists, honor moderator requests.  Thus, for a remote
+  admin list without D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc, only subscription moderators or remote
+  administrators can receive archive retrievals and only remote
+  administrators can subscribe and unsubscribe user addresses.
+
+  If you'd like this restriction of archive retrieval with maintained
+  user-initiated ezmlm-manage(1) subscription functions, use the ezmlm-
+  get(1) ``-P'' (not public) switch, and retain D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc. Also, look
+  at the ezmlm-make ``-b'' switch.
+
+
+  1\b11\b1.\b.4\b4.\b.  A\bAl\bll\blo\bow\bwi\bin\bng\bg a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl f\bfr\bro\bom\bm a\ba n\bno\bon\bn-\b-p\bpu\bub\bbl\bli\bic\bc l\bli\bis\bst\bt.\b.
+
+  A non-public list lacks D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc. ezmlm-manage(1) will reject user
+  requests for (un) subscription and for archive retrieval. The
+  restriction on archive retrieval can be removed with the ezmlm-get(1)
+  ``-p'' (public) switch.
+
+
+  1\b12\b2.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg d\bdi\big\bge\bes\bst\bts\bs.\b.
+
+
+  1\b12\b2.\b.1\b1.\b.  S\bSe\bet\btt\bti\bin\bng\bg u\bup\bp a\ba d\bdi\big\bge\bes\bst\bt l\bli\bis\bst\bt.\b.
+
+  Digests are integrated with normal ezmlm lists if you use ezmlm-
+  idx>=0.30.  Just add the ezmlm-make(1) ``-d'' switch to your list
+  setup. To add digests to an existing list created with ezmlm-idx>=0.23
+  use:
+
+
+               % ezmlm-make -+d DIR
+
+
+
+
+  For ezmlm-0.53 or older lists, you just need to re-specify also other
+  switches and the other ezmlm-make(1) arguments.
+
+
+  1\b12\b2.\b.2\b2.\b.  G\bGe\ben\bne\ber\bra\bat\bti\bin\bng\bg d\bda\bai\bil\bly\by d\bdi\big\bge\bes\bst\bts\bs.\b.
+
+  The easiest way to generate trigger messages is to use crond(8) and
+  execute ezmlm-get(1) daily. To do this, create the list with:
+
+
+               ezmlm-make -d dir dot local host
+
+
+
+
+  and add a line to your crontab file:
+
+
+               30 04 * * * ezmlm-get dir
+
+
+
+
+  and execute crontab(1). This will generate a digest each day at 04:30
+  am. In addition, a digest will be generated at any time when the lat-
+  est post makes it more than 30 messages or more than 64 kbytes of mes-
+  sage body since the latest digest. If you do not want these extra
+  digests, edit D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and remove the ezmlm-tstdig(1) and ezmlm-
+  get(1) lines.
+
+  If you do not need the digests to go out at a particular time, use the
+  standard setup, but edit D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br to put ``-t 24'' on the ezmlm-
+  tstdig(1) line instead of the default ``-t 48'' for 48 hours. This is
+  even easier.  You can modify all parameters by editing e\bez\bzm\bml\blm\bmr\brc\bc or by
+  using the ezmlm-make(1) ``-4'' argument when creating/editing the
+  list. This is described in the ezmlm-make(1) man page, and the options
+  etc, are described in the ezmlm-tstdig(1) man page.
+
+
+
+
+
+  1\b12\b2.\b.3\b3.\b.  G\bGe\ben\bne\ber\bra\bat\bti\bin\bng\bg t\bth\bhe\be f\bfi\bir\brs\bst\bt d\bdi\big\bge\bes\bst\bt.\b.
+
+  If you want the first digest to start with issue 1 and the first
+  message in your archive, no special action is required.
+
+  If you want the first digest to start at message 123 and you have
+  shell access, put '122' into D\bDI\bIR\bR/\b/d\bdi\big\bgn\bnu\bum\bm.
+
+  If you want the next digest to start at message 456, you can always
+  edit D\bDI\bIR\bR/\b/d\bdi\big\bgn\bnu\bum\bm to contain '455'. If you want the next digest to be
+  named issue 678, put '677' into D\bDI\bIR\bR/\b/d\bdi\big\bgi\bis\bss\bsu\bue\be.
+
+
+  1\b12\b2.\b.4\b4.\b.  A\bAd\bdd\bdi\bin\bng\bg s\bst\bta\ban\bnd\bda\bar\brd\bd a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\biv\bve\be i\bin\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn t\bto\bo d\bdi\big\bge\bes\bst\bts\bs.\b.
+
+  The text in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/d\bdi\big\bge\bes\bst\bt is copied into  the ``Administrivia''
+  section of the digest.  This information can be customized on a
+  system-wide basis by editing /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc, on a user-wide basis by
+  editing ~\b~/\b/.\b.e\bez\bzm\bml\blm\bmr\brc\bc, or for the list by directly editing the
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/d\bdi\big\bge\bes\bst\bt file, or by a remote administrator by editing the file
+  via e-mail, if the list has been set up using the ezmlm-make(1)
+  ``-nr'' switches (see ``How text file editing works'').
+
+
+  1\b12\b2.\b.5\b5.\b.  C\bCo\bon\bnt\btr\bro\bol\bll\bli\bin\bng\bg t\bth\bhe\be d\bdi\big\bge\bes\bst\bt f\bfo\bor\brm\bma\bat\bt.\b.
+
+  You can control the default format that ezmlm-get(1) uses for its
+  output by using the ``-f x'' switch. For individual digests triggered
+  by mail or other archive access, add a format specifier after the
+  digestcode:
+
+
+
+       list-dig.codef@host
+
+
+
+
+  For example:
+
+
+
+       joe-sos-dig.gagax@id.com
+
+
+
+
+  where ``x'' is ``r'' for rfc1153 format, ``m'' (default) for MIME mul-
+  tipart/digest with a subset of headers, ``v'' for virgin MIME multi-
+  part/digest, i.e. with all headers retained from the archive, ``n''
+  produces format similar to ``v'', without threading and with messages
+  in numerical order. The ``x'' format is identical to the default ``m''
+  format, but the digest content-type is ``multipart/alternative''
+  rather than ``multipart/digest''. This helps with a pine bug if you
+  are using quoted-printable/base64 encoding of ezmlm messages.
+
+  With digests triggered directly from crond(8), just use the ``-f''
+  format specifier:
+
+
+               ezmlm-get -fx DIR
+
+
+
+
+  The same switch can also be used for standard digest triggering from
+  D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br. Just add the ``-fx'' switch to the ezmlm-get(1) command
+  line there. Edit ~\b~/\b/e\bez\bzm\bml\blm\bmr\brc\bc to assure that such customizations will be
+  used for future list creations/edits.
+
+
+  1\b12\b2.\b.6\b6.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg b\bbo\bou\bun\bnc\bce\be h\bha\ban\bnd\bdl\bli\bin\bng\bg.\b.
+
+  The time out for bounce messages is normally 11.6 days. This means
+  that a bad address will take longer that 3 weeks to be removed.
+  Usually, this delay is desirable. After all, it is much worse to
+  remove a subscriber just because the address had temporary problems
+  that to send a few extra messages and receive a few extra bounces.
+
+  However, for large lists, bounce handling can consume a considerable
+  amount of resources. To decrease the load, remove all ezmlm-warn(1)
+  lines from the D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br, and D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br files. Instead, execute:
+
+
+       /path/ezmlm-warn DIR
+       /path/ezmlm-warn -d DIR
+
+
+
+
+  daily during off-peak hours via a cron script. The second line can be
+  omitted if you are not using the digest capability of the list.
+
+  This should not be necessary for ezmlm-idx>=0.32. That version adds
+  much more efficient bounce handling, making this type of modification
+  usable only for extremely large lists with many bad addresses (unusual
+  for ezmlm lists) and for hosts that are working near the limit of
+  their capacity (where shifting some qmail load to off-peak hours is
+  worth the effort).
+
+  In addition, you may want to reduce the time out for bounces from 11.6
+  to a lower number of days, e.g. 5. To do so, add ``-t 5'' to the
+  ezmlm-warn(1) command line.
+
+  If you start with a list from a list manager that does not have bounce
+  handling, chances are that you have many bad addresses in your list.
+  You can always execute:
+
+
+       /path/ezmlm-warn -t0 DIR
+       /path/ezmlm-warn -d -t0 DIR
+
+
+
+
+  to move bounce handling one step forward per execution. Users whose
+  mail has bounced will be sent a warning. Users for whom the warning
+  message has bounced will be sent a probe.
+
+
+  1\b13\b3.\b.  R\bRe\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\bio\bon\bn.\b.
+
+
+  1\b13\b3.\b.1\b1.\b.  H\bHo\bow\bw c\bca\ban\bn I\bI r\bre\bem\bmo\bot\bte\bel\bly\by a\bad\bdd\bd m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs,\b, s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br a\bal\bli\bia\bas\bse\bes\bs,\b, e\bet\btc\bc?\b?
+
+  On any list, the D\bDI\bIR\bR/\b/a\bal\bll\blo\bow\bw/\b/ database can be manipulated remotely via
+  mail to list-allow-subscribe@listhost, etc. The rules for
+  adding/removing/listing addresses to this database are the same as for
+  the main list. Thus, if a user on an open list wants to be able to
+  post from alias@al.host.com s/he can send a message to list-allow-
+  subscribe-alias=al.host.com@listhost and reply to the confirmation
+  request. Now, s/he can post from this address even on a subscriber-
+  only list and even though the address is not a real subscriber.
+
+  It can be confusing to some users that you use ``subscribe'' here, but
+  you don't get any messages. If you explain to them that this is just
+  another collection of addresses they will understand. You can also
+  send the initial message on their behalf. If you are a remote admin,
+  you can even complete the transaction adding the alias without
+  subscriber participation.
+
+  Addresses can also be unsubscribed from the ``allow'' database.
+  However, there is usually no good reason to do so.
+
+  If configured, the D\bDI\bIR\bR/\b/d\bde\ben\bny\by/\b/ database can be manipulated, but only by
+  remote administrators, by mail to e.g.  list-deny-
+  baduser=badhost@listhost. Normal users cannot access this database.
+
+  To remotely administrate the D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ databases (i.e., without shell
+  access), you need to set up a non-public, remotely administered list
+  which ``resides'' within the D\bDI\bIR\bR/\b/m\bmo\bod\bd. _\bP_\bl_\be_\ba_\bs_\be _\bc_\ba_\br_\be_\bf_\bu_\bl_\bl_\by _\bc_\bo_\bn_\bs_\bi_\bd_\be_\br _\bt_\bh_\be
+  _\bi_\bm_\bp_\bl_\bi_\bc_\ba_\bt_\bi_\bo_\bn_\bs _\bo_\bf _\bm_\ba_\bk_\bi_\bn_\bg _\bi_\bt _\bp_\bo_\bs_\bs_\bi_\bb_\bl_\be _\bt_\bo _\br_\be_\bm_\bo_\bt_\be_\bl_\by _\ba_\bd_\bd_\b, _\br_\be_\bm_\bo_\bv_\be_\b, _\ba_\bn_\bd _\bl_\bi_\bs_\bt
+  _\bm_\bo_\bd_\be_\br_\ba_\bt_\bo_\br_\bs_\b. _\bI_\bn _\bm_\ba_\bn_\by _\bc_\bi_\br_\bc_\bu_\bm_\bs_\bt_\ba_\bn_\bc_\be_\bs_\b, _\bt_\bh_\bi_\bs _\bi_\bs _\bd_\ba_\bn_\bg_\be_\br_\bo_\bu_\bs_\b.
+
+  After setting up your list with the specific functionality you need,
+  use the following command for D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/:
+
+
+               % ezmlm-make -ePrIAl ~/list/mod ~/.qmail-list-mod joe-list-mod host
+
+
+
+
+  The '-l' flag is not necessary, but makes it easier to administrate
+  your moderator database by permitting the ``supermoderator'' to see
+  who is on the list.
+
+  The new list does not have a key. Using the key from the main list is
+  inadvisable. Instead, create a dummy list, copy the key from this list
+  to your ``moderator'' list:
+
+
+               % cp ~/DUMMY/key ~/DIR/mod/key
+
+
+
+
+  Erase the dummy list. Also, posts to this list should not be allowed.
+  Erase the ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\bt-\b-m\bmo\bod\bd and ~\b~/\b/D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/e\bed\bdi\bit\bto\bor\br.  Then add the remote
+  administrator of the ``moderator'' list:
+
+
+               % ezmlm-sub ~/list/mod/mod supermod@superhost
+
+
+
+
+  The ``supermoderator'' can now remotely administrate the moderators of
+  the main list.
+
+
+  1\b13\b3.\b.2\b2.\b.  M\bMo\bod\bde\ber\bra\bat\bti\bin\bng\bg p\bpo\bos\bst\bts\bs f\bfr\bro\bom\bm a\ba s\bse\bec\bco\bon\bnd\bda\bar\bry\by a\bac\bcc\bco\bou\bun\bnt\bt.\b.
+
+  Request for moderation of posts can be forwarded to any address and
+  acted on from that address. By default, all post moderation requests
+  have subjects starting with ``MODERATE for'' followed by the list
+  name.
+
+  1\b13\b3.\b.3\b3.\b.  M\bMo\bod\bde\ber\bra\bat\bti\bin\bng\bg s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn f\bfr\bro\bom\bm a\ba s\bse\bec\bco\bon\bnd\bda\bar\bry\by a\bac\bcc\bco\bou\bun\bnt\bt.\b.
+
+  Requests for moderator approval of user subscribe requests can be
+  forwarded to any address and acted on from that address.  All
+  subscription moderation requests have subjects starting with
+  ``CONFIRM'' (or ``CONFIRM subscribe to listname'', since ``CONFIRM
+  unsubscribe from listname'' is sent to the moderator only in reply to
+  a moderator-initiated request on a list with remote admin).
+
+  Remote administration (initiation by the moderator of (un)subscribe
+  requests on behalf of a user) CANNOT be initiated from an account that
+  is not listed in the moderator database. If such attempts are made,
+  these will be treated as regular requests, resulting in a confirm
+  request to the user (which includes a copy of the initial request,
+  revealing the moderator's address to the user). The user reply to a
+  confirm request will on a non-moderated list result in the addition of
+  the user address to the subscriber list, and in a moderated list a
+  CONFIRM request to all the moderators. Replies to unsubscribe confirm
+  requests always result in the removal of the address, without
+  moderator intervention (except in some cases when the ezmlm-manage -U
+  switch is used (see below)).  With this caveat, moderation and remote
+  administration can be done from a secondary address.
+
+  For the subscription moderator to temporarily use a different address,
+  s/he needs to forward all ``CONFIRM'' messages to the new address. For
+  a permanent move, it is better to remove the old moderator address and
+  add the new SENDER address to allow moderator-initiated (un)subscribes
+  without user intervention from the new address (of course, the list
+  has to be configured for remote administration with D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be).
+
+
+  1\b13\b3.\b.4\b4.\b.  A\bAu\but\bto\bom\bma\bat\bti\bic\bca\bal\bll\bly\by a\bap\bpp\bpr\bro\bov\bvi\bin\bng\bg p\bpo\bos\bst\bts\bs o\bor\br s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bns\bs.\b.
+
+  Sometimes, it may be desirable for the moderator to automatically
+  approve all moderation requests. This may be appropriate for a single
+  moderator of a ``civilized'' list when away for the week.
+
+  Set up your client to auto-reply to the ``Reply-To:'' address for all
+  messages with subjects ``CONFIRM subscribe to listname'' or ``MODERATE
+  for listname''. Beware that this can be used by malicious people to
+  trick your account to send mail anywhere.  In practice, this should
+  not be a problem.  If you are worried, forward the messages to a
+  (trusted) friend and ask him/her to appropriately reply to the
+  requests.
+
+
+  1\b13\b3.\b.5\b5.\b.  A\bAl\bll\blo\bow\bwi\bin\bng\bg r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\brs\bs t\bto\bo g\bge\bet\bt a\ba s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br l\bli\bis\bst\bt.\b.
+
+  Access to the subscriber list is sensitive. Thus, this option is
+  disabled by default. The ezmlm-manage(1) ``-l'' command line switch
+  enables this option, but will send a subscriber list only to a
+  moderator's address. This allows a moderator to also initiate a
+  subscriber list retrieval from a secondary account (i.e.  one to which
+  the moderator's mail is delivered, but for which SENDER is not a
+  moderator). The latter option does not decrease security, as it is
+  trivial to fake SENDER (see ``Ezmlm-idx security'' for a discussion of
+  ezmlm-idx security aspects).
+
+  For maximum subscriber list security, do not enable this feature. To
+  enable this feature by default, just modify e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) (see
+  ``Customizing ezmlm-make operation'').
+
+
+
+
+
+  1\b13\b3.\b.6\b6.\b.  A\bAl\bll\blo\bow\bwi\bin\bng\bg r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bto\bor\brs\bs t\bto\bo r\bre\bet\btr\bri\bie\bev\bve\be o\bor\br s\bse\bea\bar\brc\bch\bh a\ba s\bsu\bub\bb-\b-
+  s\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn l\blo\bog\bg.\b.
+
+  This is restricted and works as the subscriber list, since it contains
+  information of equal sensitivity. To receive the entire log, mail
+  list-log@listhost.  See ``Howto get a subscription log'' for more
+  details on the reply format.  As of ezmlm-idx-0.32, the subscription
+  log also contains the From: line contents from the user's subscribe
+  confirmation. This usually contains the user's name and can be helpful
+  if the user cannot recall or determine the subscription address. To
+  make life easier for the remote admin, ezmlm-idx-0.32 also supports
+  searching the log, using exact matches for alphanumerics and ``_'' as
+  a wild card character. Thus, to find records matching ``Keith John*'',
+  the remote admin can mail list-log.Keith_John.  See ``Howto get a
+  subscription log'' for more information.
+
+
+  1\b13\b3.\b.7\b7.\b.  A\bAl\bll\blo\bow\bwi\bin\bng\bg u\bus\bse\ber\brs\bs t\bto\bo g\bge\bet\bt a\ba s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br l\bli\bis\bst\bt.\b.
+
+  If you want any user to be able to get a subscriber list, you can set
+  up a separate link to D\bDI\bIR\bR/\b/l\bli\bis\bst\bt and then put in a script using ezmlm-
+  list (See ``adding your own commands'' for more info.)  . The authors
+  strongly urge against this, since a common method for spammers to get
+  valid E-mail addresses from mailing lists is to exploit unrestricted
+  -list commands.  A subscriber with questions about who is on the list
+  should contact the list-owner@host. A subscriber wishing to confirm
+  that they are still on the list can just send a message to list-
+  subscribe@listhost, and reply to the confirm request. The following
+  message will be a ``ezmlm response'' if the user was already a
+  subscriber, and a ``WELCOME to listname'' if s/he was not.
+
+
+  1\b13\b3.\b.8\b8.\b.  C\bCh\bha\ban\bng\bgi\bin\bng\bg t\bth\bhe\be t\bti\bim\bme\beo\bou\but\bt f\bfo\bor\br m\bme\bes\bss\bsa\bag\bge\bes\bs i\bin\bn t\bth\bhe\be m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn q\bqu\bue\beu\bue\be.\b.
+
+  Put the time, in hours, into D\bDI\bIR\bR/\b/m\bmo\bod\bdt\bti\bim\bme\be. This value may not exceed
+  the range of 24-120 h set at compile time by the defines in i\bid\bdx\bx.\b.h\bh.
+
+
+  1\b13\b3.\b.9\b9.\b.  F\bFi\bin\bnd\bdi\bin\bng\bg o\bou\but\bt h\bho\bow\bw m\bma\ban\bny\by m\bme\bes\bss\bsa\bag\bge\bes\bs a\bar\bre\be w\bwa\bai\bit\bti\bin\bng\bg f\bfo\bor\br m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+
+
+       % ls -l DIR/mod/pending
+
+
+
+
+  and count lines with the owner execute bit set (rwx------).  Others
+  are remnants from failed ezmlm-store runs (ignore - ezmlm-clean(1)
+  will remove them).
+
+  There is currently no way to see this remotely, although you could
+  easily install a script mailing the 'ls' output in response to a
+  message to e.g. l\bli\bis\bst\bt-\b-c\bch\bhk\bkq\bqu\bue\beu\bue\be@\b@h\bho\bos\bst\bt.  (See ezmlm-check(1) and ``adding
+  your own commands'' for examples.)
+
+
+  1\b13\b3.\b.1\b10\b0.\b.  U\bUs\bsi\bin\bng\bg t\bth\bhe\be s\bsa\bam\bme\be m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs f\bfo\bor\br m\bmu\bul\blt\bti\bip\bpl\ble\be l\bli\bis\bst\bts\bs.\b.
+
+  Set up a moderator dir:
+
+
+
+
+
+
+  % mkdir /path/moddir /path/moddir/subscribers
+  % touch /path/moddir/lock
+  % chown -R user /path/moddir
+
+
+
+
+  For alias:
+
+
+
+        # chown -R alias /path/moddir
+
+
+
+
+  For example:
+
+
+
+       % mkdir ~joe/mods ~joe/mods/subscribers
+       % touch ~joe/mods/lock
+
+
+
+
+  Then for the lists, put /\b/p\bpa\bat\bth\bh/\b/m\bmo\bod\bdd\bdi\bir\br into D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb (for moderation
+  of subscribes), D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be (for remote admin if D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb does not
+  exist), and D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt (for moderation of messages).
+
+  For example:
+
+
+
+       % echo "/home/joe/mods" > ~joe/DIR/modsub
+
+
+
+
+  _\bN_\bO_\bT_\bE_\b: The path must start with a '/'.
+
+
+  1\b13\b3.\b.1\b11\b1.\b.  U\bUs\bsi\bin\bng\bg d\bdi\bif\bff\bfe\ber\bre\ben\bnt\bt m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs f\bfo\bor\br m\bme\bes\bss\bsa\bag\bge\be a\ban\bnd\bd s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\br-\b-
+  a\bat\bti\bio\bon\bn.\b.
+
+  Proceed as in the previous point, but set up two different moddirs.
+  Naturally, one of these can be D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ (preferably the one for posts,
+  to keep it cleaner). Then modify the appropriate files (D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt
+  and D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb) to contain absolute paths to the correct moddir.
+
+
+  1\b13\b3.\b.1\b12\b2.\b.  t\bth\bhe\be `\b``\b`s\bsu\bup\bpe\ber\br m\bmo\bod\bde\ber\bra\bat\bto\bor\br'\b''\b' a\bab\bbl\ble\be t\bto\bo a\bad\bdd\bd/\b/r\bre\bem\bmo\bov\bve\be m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs
+  r\bre\bem\bmo\bot\bte\bel\bly\by.\b.  S\bSe\bet\btt\bti\bin\bng\bg u\bup\bp m\bmo\bod\bde\ber\bra\bat\bte\bed\bd l\bli\bis\bst\bts\bs w\bwi\bit\bth\bh t\bth\bhe\be l\bli\bis\bst\bt o\bow\bwn\bne\ber\br a\bas\bs
+
+  This is done by crating a list that has D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ as it's main list
+  directory, then adding the ``super moderator'' to D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/m\bmo\bod\bd/\b/ (see
+  ``remotely adding moderators'').
+
+  If this is a common setup for you, you can write a simple script
+  creating both lists (plus a digest list, if desired) with one simple
+  action (see ezmlm-both(1) for an example).
+
+
+
+
+
+  1\b13\b3.\b.1\b13\b3.\b.  C\bCu\bus\bst\bto\bom\bmi\biz\bzi\bin\bng\bg e\bez\bzm\bml\blm\bm a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\biv\bve\be m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  Subject lines, and other ezmlm output for moderation are controlled by
+  defines in i\bid\bdx\bx.\b.h\bh and by files in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt. To customize these, change
+  i\bid\bdx\bx.\b.h\bh and recompile or for D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt files, edit e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) (see
+  ``Customizing ezmlm-make operation'').
+
+  You can also configure the list to allow remote administrators to edit
+  files in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ via E-mail (see ``How text file editing works'').
+
+
+  1\b13\b3.\b.1\b14\b4.\b.  M\bMa\ban\bnu\bua\bal\bll\bly\by a\bap\bpp\bpr\bro\bov\bvi\bin\bng\bg a\ba m\bme\bes\bss\bsa\bag\bge\be a\baw\bwa\bai\bit\bti\bin\bng\bg m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+  All you have to do is to pipe the corresponding message to ``ezmlm-
+  send DIR''. Messages awaiting moderation are kept in D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/.
+  To find a particular file, grep the contents.  Thus, to find a file
+  from user@host.dom, try:
+
+
+
+       % grep 'user@host\.dom' DIR/mod/pending/*
+
+
+
+
+  (Depending on your setup, you may not have to escape the period.)
+  Check the files for the owner execute (``x'') bit. It is set on all
+  messages queued successfully. Ignore other files!
+
+  To then accept the message (change the ezmlm-send(1) path if you've
+  installed in a non-default directory):
+
+
+
+       % cat DIR/mod/pending/filename \
+       % /usr/local/bin/ezmlm/ezmlm-send DIR
+
+
+
+
+  Alternatively, use ezmlm-accept(1).  It checks the 'x' bit, ezmlm-
+  send(1) return codes, removes the file, etc.
+
+  For example:
+
+
+
+       % ezmlm-accept ~joe/SOS ~joe/SOS/pending/*
+
+
+
+
+  will accept all messages in the queue of the list in ~\b~j\bjo\boe\be/\b/S\bSO\bOS\bS/\b/.
+
+
+  1\b13\b3.\b.1\b15\b5.\b.  M\bMa\ban\bnu\bua\bal\bll\bly\by r\bre\bej\bje\bec\bct\bti\bin\bng\bg a\ba m\bme\bes\bss\bsa\bag\bge\be a\baw\bwa\bai\bit\bti\bin\bng\bg m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+  Simply deleting the file from D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/p\bpe\ben\bnd\bdi\bin\bng\bg/\b/ will do it. If you want
+  to notify the sender, just send him/her an E-mail.  There is an easy
+  way to get ezmlm-idx programs to do it for you: just wait and let
+  ezmlm-clean(1) take care of it for you, once the message has timed out
+  (number of hours settable within 24-240 in D\bDI\bIR\bR/\b/m\bmo\bod\bdt\bti\bim\bme\be; default 120).
+
+
+
+
+  1\b14\b4.\b.  S\bSu\bub\bbl\bli\bis\bst\bts\bs.\b.
+
+  A sublist is a list that receives its input from another mailing list,
+  rather than from users directly. The sublist is just a regular
+  subscriber of the main list. A sublist in e.g. Tasmania is very useful
+  since only one message is sent from the main list and then the
+  sublists servers all subscribers in Tasmania. Bounces and all
+  administration is handled locally. The local sublist can have a
+  digest, even though the main list may not.  (See ``How sublists work''
+  for more info on how sublists work).
+
+
+  1\b14\b4.\b.1\b1.\b.  S\bSu\bub\bbl\bli\bis\bst\bts\bs o\bof\bf e\bez\bzm\bml\blm\bm l\bli\bis\bst\bts\bs.\b.
+
+  To set up a sublist to an ezmlm list, just use the ezmlm-make ``-5
+  mainlist@mainhost'' switch. This will configure your list as a sublist
+  to the mainlist@mainhost mailing list.
+
+
+  1\b14\b4.\b.2\b2.\b.  S\bSu\bub\bbl\bli\bis\bst\bts\bs o\bof\bf n\bno\bon\bn-\b-e\bez\bzm\bml\blm\bm l\bli\bis\bst\bts\bs.\b.
+
+  To set up a sublist to an ezmlm list, just use the ezmlm-make ``-5
+  mainlist@mainhost'' switch. This will configure your list as a sublist
+  to the mainlist@mainhost mailing list. Since the main list may not use
+  the ``Mailing-List'' header, you must identify another header that the
+  main list adds to all messages. See the ezmlm-reject(1) man page for
+  examples. Next, edit D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br of your sublist and add a ``-h
+  _\bL_\bi_\bs_\bt_\bp_\br_\bo_\bc_\be_\bs_\bs_\bo_\br_\b-_\bV_\be_\br_\bs_\bi_\bo_\bn_\b:'' option to the ezmlm-send(1) line, but
+  replacing ``_\bL_\bi_\bs_\bt_\bp_\br_\bo_\bc_\be_\bs_\bs_\bo_\br_\b-_\bV_\be_\br_\bs_\bi_\bo_\bn_\b:'' with your mainlist header.
+
+  Now your list will accept only messages from mainlist@mainhost and
+  with the header specified.
+
+
+  1\b14\b4.\b.3\b3.\b.  H\bHo\bow\bw t\bto\bo s\bse\bet\bt u\bup\bp a\ba c\bcl\blu\bus\bst\bte\ber\br o\bof\bf l\bli\bis\bst\bt a\ban\bnd\bd s\bsu\bub\bbl\bli\bis\bst\bts\bs w\bwi\bit\bth\bh s\bst\bta\ban\bnd\bda\bar\brd\bd
+  d\bda\bat\bta\bab\bba\bas\bse\bes\bs.\b.
+
+  ezmlm-0.53 allows sublists. The difference between a sublist and a
+  main list is that the sublist requires that the SENDER of the message
+  is the main list and that the message has a ``Mailing-List:'' header.
+  Sublist messages have their own subscriber database and subscription
+  mechanism, and use their own message number. This is very convenient
+  if you want to create a private sublist.  Since the subscribers have
+  to interact with the appropriate sublist, it is difficult to
+  administrate if you want to use it to distribute the load of a very
+  large list, since users will have to address administrative requests
+  such as unsubscribe to the correct sublist. Also, bounce messages
+  refer to the sublist archive with sublist message numbers.
+
+  ezmlm-idx modifies this in several ways: First, the message number of
+  the incoming message is used also for the outgoing message so that
+  subscribers see the same message number no matter which sublist they
+  get it from. For security reasons, this is enabled only if the sublist
+  is NOT ARCHIVED. With this feature, bounce messages can refer the user
+  to the main list archive instead, obviating multiple archives.
+
+  Second, ezmlm-split(1) can be used to forward administrative requests
+  sent to the main list, to the appropriate sublist. Thus, subscribers
+  interact only with the main list, and do not need to know which
+  sublist that servers them. With bounce and administrative messages
+  referring them to the main list, subscribers will usually be unaware
+  of the sublisting.
+
+  To set this up:
+
+
+  +\bo
+
+     c\bcr\bre\bea\bat\bte\be t\bth\bhe\be m\bma\bai\bin\bn l\bli\bis\bst\bt
+
+
+                  ezmlm-make dir dot local host
+
+
+
+
+  +\bo
+
+     a\bad\bdd\bd a\ban\bn e\bez\bzm\bml\blm\bm-\b-s\bsp\bpl\bli\bit\bt(\b(1\b1)\b) i\bin\bnv\bvo\boc\bca\bat\bti\bio\bon\bn
+        Before the ezmlm-manage(1) line in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br add:
+
+
+                  |/path/ezmlm-split dir
+
+
+
+
+  +\bo
+
+     d\bde\bec\bci\bid\bde\be h\bho\bow\bw t\bto\bo s\bsp\bpl\bli\bit\bt t\bth\bhe\be l\blo\boa\bad\bd
+        The main list sends to sublists and to any addresses not covered
+        by the split table. You can split the load by domain
+        (``geographically''), and any domain (including '') can be
+        subdivided by ``hash'' by using different parts of the 0-52
+        range. Of course, you can also use hash alone.  The request will
+        go to the first row that matches, so although overlaps are not
+        advisable (in case you later want to add sublists of switch to
+        an SQL server-based system (see ``'')), they have no negative
+        effects. The domain for ezmlm-split can be the last TWO parts,
+        i.e. ``edu.wustl'' to handle all *.wustl.edu subscribers.  This
+        is useful, but remember that the SQL version supports only one
+        level.
+
+        An example:
+
+
+             domain:hash_lo:hash_hi:sublistname
+             edu:0:52:sub1@here.edu
+             com:0:26:sub2@there.net
+             com:27:52:sub3@some.com
+             :0:13:sub4@what.org
+             :14:39:sub5@what.org
+
+
+
+
+     As you can see, the entire ``edu'' domain is handled by
+     sub1@here.edu.  The ``com'' domain is about evenly split between
+     sub2@there.net and sub3@some.com.  Everything else is split so that
+     approximately 1/4 goes to sub4@what.org, 1/2 to sub5@what.org and
+     the rest falls through, i.e. is handled by the main list.
+
+     Why are there 2 sublists on the same host? This is in preparation
+     of adding a host. It easy to just move the entire sub5@what.org
+     list to a new host.  All we have to do it to set up the new list,
+     copy over the subscribers, and change the name in the split table
+     entry.
+
+     To split the split the sub5@what.org load onto 2 lists requires a
+     little more work. First, create a dummy split table in a directory
+     ``temp'':
+
+        :14:26:new1@new.net
+        :27:39:new1@other.net
+
+
+
+
+     Next, split the subscribers of sub5@what.org into these 2 groups,
+     as detailed in the ezmlm-split(1) man page. Create the two new
+     lists, add the respective subscribers, and replace the
+     sub5@what.org line with the two lines above.
+
+     To add a totally new domain, e.g. jp:0:52:sub6@niko.jp requires
+     collection or subscribers from all lists that currently handle
+     these subscribers, (the ones with blank domain in the example), re-
+     splitting them, and adjusting the subscribers. Easiest here is to
+     just unsubscribe the sub6@niko.jp subscribers to be from the other
+     list with ezmlm-sub(1).  Since that program will silently ignore
+     any addresses that are not on the respective list, it will work
+     fine.
+
+  +\bo
+
+     C\bCr\bre\bea\bat\bte\be t\bth\bhe\be s\bsu\bub\bbl\bli\bis\bst\bts\bs
+        Use ezmlmsubrc which sets up a minimal non-archived sublist with
+        bounce texts pointing to the main list:
+
+
+
+                  % ezmlm-make -Cezmlmsubrc -3mainlocal -4mainhost \
+                          DIR dot sub1local sub1host
+
+
+
+
+  +\bo
+
+     s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\be t\bth\bhe\be r\bre\bes\bsp\bpe\bec\bct\bti\biv\bve\be s\bsu\bub\bbl\bli\bis\bst\bts\bs t\bto\bo t\bth\bhe\be m\bma\bai\bin\bn l\bli\bis\bst\bt
+        If you forget, the sublist will not get any messages to
+        distribute. Add these addresses with ezmlm-sub(1) as subscribers
+        to the main list.
+
+  A strong point of this system is that it is relatively simple and that
+  only a fraction of the addresses are available to any given sublist.
+  Thus, compromised security at a sublist threatens only the addresses
+  and functions handled by that sublist.
+
+  As you can see, this works quite well, but it's not trivial to change
+  the setup.  If you modify it while the list is running, some
+  subscribers may get duplicate messages or miss messages. Therefore,
+  you should disable deliveries to the main list before the final step
+  of the changes (removal of subscribers from old lists and adding new
+  lists as subscribers to the main list). For most lists, this should
+  work flawlessly, and some minimal planning and extra lines in
+  ``split'' can markedly facilitate future expansion.
+
+  Another weak point is the authentication of messages between list and
+  sublist.  The requirements the sublist places on the message can be
+  easily faked. This allows injection of messages at the sublist level
+  as a way to circumvent moderation or other access control.
+
+  An associated disadvantage is that not even the main list has access
+  to all the addresses. Thus, SENDER checks for archive access
+  (relatively secure) and posts (relatively insecure) cannot directly be
+  used. Also, sublist cooperation is required to determine the number of
+  subscribers, or to access subscriber addresses for a purpose other
+  than distribution of list messages.
+  1\b15\b5.\b.  M\bMi\big\bgr\bra\bat\bti\bio\bon\bn t\bto\bo E\bEz\bzm\bml\blm\bm f\bfr\bro\bom\bm o\bot\bth\bhe\ber\br M\bMa\bai\bil\bli\bin\bng\bg L\bLi\bis\bst\bt M\bMa\ban\bna\bag\bge\ber\brs\bs.\b.
+
+  This section describes differences and similarities between ezmlm and
+  other mailing list managers. It also details functions of ezmlm-idx
+  that allow you to configure ezmlm to respond to commands utilized by
+  such other mailing list managers so the command syntax will be
+  familiar to such users.  Contributions to complete this sections are
+  welcome.
+
+
+  1\b15\b5.\b.1\b1.\b.  B\bBa\bas\bsi\bic\bc C\bCo\bon\bnc\bce\bep\bpt\bts\bs.\b.
+
+  Ezmlm is different from other mailing list managers in that it is
+  _\bl_\bi_\bs_\bt_\b-_\bc_\be_\bn_\bt_\br_\bi_\bc rather than _\bh_\bo_\bs_\bt_\b-_\bc_\be_\bn_\bt_\br_\bi_\bc. With a _\bl_\bi_\bs_\bt_\b-_\bc_\be_\bn_\bt_\br_\bi_\bc interface,
+  you address the list directly with administrative commands. With
+  ezmlm, the command is embedded in the list address thus becoming part
+  of it (i.e., the ``command address''.)  With smartlist, again you
+  address the list, but send all administrative commands to the list-
+  request address. Ezmlm lists can support this if you use the ezmlm-
+  make(1) ``-q'' switch to configure ezmlm-request(1) in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br.
+
+  Other mailing list managers are _\bh_\bo_\bs_\bt_\b-_\bc_\be_\bn_\bt_\br_\bi_\bc, i.e.  administrative
+  commands for any list on that particular host are addressed to a
+  central address such as majordomo@host, listserv@host, or
+  listproc@host. Then the user is required to place the command in
+  either the subject header or more commonly in the body text of the
+  message. The listname has to be included with the command. [_\bN_\bo_\bt_\be_\b: The
+  above concept is not universally applicable to all host-centric
+  mailing lists.  While intended to to used in a host-centric manner,
+  many such mailing list managers also support listname-request@host
+  addressing. See the applicable list manger documentation for details.
+  Coverage of this aspect of other mailing list manager functionality is
+  beyond the scope of this FAQ.]  To make the migration to ezmlm easier,
+  support for a _\bh_\bo_\bs_\bt_\b-_\bc_\be_\bn_\bt_\br_\bi_\bc style mailing list manger is available.
+  This is based on the use of ezmlm-request(1) with the ``-f
+  c\bco\bon\bnf\bfi\big\bg_\b_f\bfi\bil\ble\be'' switch.
+
+
+  1\b15\b5.\b.2\b2.\b.  S\bSe\bet\btt\bti\bin\bng\bg u\bup\bp e\bez\bzm\bml\blm\bm t\bto\bo r\bre\bes\bsp\bpo\bon\bnd\bd t\bto\bo h\bho\bos\bst\bt-\b-c\bce\ben\bnt\btr\bri\bic\bc c\bco\bom\bmm\bma\ban\bnd\bds\bs.\b.
+
+  ezmlm-request(1) can be used a a ``majordomo/listserv-emulator''. You
+  can create the necessary accessory files manually. However, ezmlm-
+  idx>=0.32 contains ezmlmglrc(5) which makes is very easy for you:
+
+
+               % su
+               # su alias
+               # ezmlm-make -C/usr/local/bin/ezmlmglrc dir dot local host
+
+
+
+
+  where ``local'' may be e.g. ``majordomo''. Even easier is to set it up
+  under a virtual domain ``host'' controlled by a user ``user''. Just
+  put ``user'' in place of ``alias'' in the example.
+
+  If you use a character set other than US-ASCII, put it's name,
+  optionally followed by ``:'' and the desired content-transfer-encoding
+  character (``Q'' for quoted-printable and ``B'' for base64) into
+  e\bez\bzd\bdo\bom\bmo\bo/\b/c\bch\bha\bar\brs\bse\bet\bt.
+
+  All that remains is to set up D\bDI\bIR\bR/\b/e\bez\bzd\bdo\bom\bmo\bo.\b.c\bcf\bf with information on the
+  lists (local and/or remote) that you want to make accessible via this
+  interface. Another script, ezmlm-glconf(1) can help you with this for
+  your local lists. To configure for all your lists:
+
+          ezmlm-glmake ~/ > ~/dir/ezdomo.cf
+
+
+
+
+  See man page for details. Alternatively, do it manually:
+
+  The D\bDI\bIR\bR/\b/e\bez\bzd\bdo\bom\bmo\bo.\b.c\bcf\bf contains a list of mailing lists which the
+  ``majordomo'' (in this case) can provide information about in the
+  following syntax:
+
+
+         list@host:listdir:description
+
+
+
+
+  To show a list in ``lists'', but not include it in a ``which'' search,
+  simply omit the ``listdir'' for that line:
+
+
+         list@host::description
+
+
+
+
+  For the ``which'' command to work, the D\bDI\bIR\bR/\b/, which contains the
+  subscriber database, must be readable by the user under which mail is
+  delivered. This means that ``which'' is usually limited to lists owned
+  by the user or virtual domain under which the ``ezdomo'' interface is
+  set up.
+
+
+  1\b15\b5.\b.3\b3.\b.  C\bCo\bom\bmm\bma\ban\bnd\bds\bs o\bof\bf o\bot\bth\bhe\ber\br m\bma\bai\bil\bli\bin\bng\bgl\bli\bis\bst\bt m\bma\ban\bna\bag\bge\ber\brs\bs r\bre\bec\bco\bog\bgn\bni\biz\bze\bed\bd b\bby\by e\bez\bzm\bml\blm\bm.\b.
+
+
+  1\b15\b5.\b.3\b3.\b.1\b1.\b.  L\bLi\bis\bst\btp\bpr\bro\boc\bc/\b/L\bLi\bis\bst\bts\bse\ber\brv\bv.\b.
+
+  When set up as above, substituting ``listproc'' or ``listserv'' for
+  ``majordomo'' as appropriate, ezmlm will recognize and respond to the
+  following commands placed in the body of the e-mail with the syntax
+  below.  N\bNo\bot\bte\be:\b: e\bez\bzm\bml\blm\bm w\bwi\bil\bll\bl o\bon\bnl\bly\by r\bre\bes\bsp\bpo\bon\bnd\bd t\bto\bo o\bon\bne\be c\bco\bom\bmm\bma\ban\bnd\bd p\bpe\ber\br m\bme\bes\bss\bsa\bag\bge\be.\b.
+
+  s\bsy\byn\bnt\bta\bax\bx:\b: c\bco\bom\bmm\bma\ban\bnd\bd l\bli\bis\bst\btn\bna\bam\bme\be [\b[s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br@\b@h\bho\bos\bst\bt]\b]
+
+
+     S\bSu\bup\bpp\bpo\bor\brt\bte\bed\bd c\bco\bom\bmm\bma\ban\bnd\bds\bs
+        subscribe, sub, unsubscribe, unsub, list, help, review.
+
+     A\bAd\bdd\bdi\bit\bti\bio\bon\bna\bal\bl s\bsu\bup\bpp\bpo\bor\brt\bte\bed\bd c\bco\bom\bmm\bma\ban\bnd\bds\bs
+        All ezmlm commands, such as ``thread'', ``index'' and ``get'' as
+        well as the list owner's commands.
+
+  This interfaced makes information available via command messages to
+  the appropriate mailing list.  Thus, ``list'' and ``review'' will send
+  a subscriber list only to remote administrators and only if
+  specifically allowed by the list owner.
+
+
+  1\b15\b5.\b.3\b3.\b.2\b2.\b.  M\bMa\baj\bjo\bor\brd\bdo\bom\bmo\bo.\b.
+
+  s\bsy\byn\bnt\bta\bax\bx:\b: c\bco\bom\bmm\bma\ban\bnd\bd l\bli\bis\bst\btn\bna\bam\bme\be [\b[s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br@\b@h\bho\bos\bst\bt]\b]
+
+
+     S\bSu\bup\bpp\bpo\bor\brt\bte\bed\bd c\bco\bom\bmm\bma\ban\bnd\bds\bs
+        lists, subscribe, unsubscribe, help, which, who.
+     A\bAd\bdd\bdi\bit\bti\bio\bon\bna\bal\bl s\bsu\bup\bpp\bpo\bor\brt\bte\bed\bd c\bco\bom\bmm\bma\ban\bnd\bds\bs
+        All ezmlm user and ezmlm owner commands.
+
+  This interfaced makes information available via command messages to
+  the appropriate mailing list.  Thus, ``who'' will send a subscriber
+  list only to remote administrators and only if specifically allowed by
+  the list owner.
+
+
+  1\b15\b5.\b.3\b3.\b.3\b3.\b.  S\bSm\bma\bar\brt\btl\bli\bis\bst\bt.\b.
+
+  Unlike ``listproc/listserv'' or ``majordomo'', ``smart-list'' does not
+  provide ``host-centric'' services. Rather, commands are addressed to
+  listname-request@host and the command placed on the ``Subject:'' line:
+
+
+         To: listname-request@host
+         Subject: command [subscriber@host]
+
+
+
+
+  The body of the message is normally ignored.  If the subject is empty,
+  the first body line that starts with a letter is interpreted.
+
+
+     S\bSu\bup\bpp\bpo\bor\brt\bte\bed\bd c\bco\bom\bmm\bma\ban\bnd\bds\bs
+        subscribe, unsubscribe.
+
+     A\bAd\bdd\bdi\bit\bti\bio\bon\bna\bal\bl S\bSu\bup\bpp\bpo\bor\brt\bte\bed\bd C\bCo\bom\bmm\bma\ban\bnd\bds\bs
+        All ezmlm user and ezmlm owner commands.
+
+
+  1\b16\b6.\b.  O\bOp\bpt\bti\bim\bmi\biz\bzi\bin\bng\bg l\bli\bis\bst\bt p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  Ezmlm-idx is designed to make it as easy as possible to set up mailing
+  lists.  The default setup works well for small and medium-sized lists.
+  For large lists, the lists can be made more efficient with a few
+  simple changes.
+
+
+  1\b16\b6.\b.1\b1.\b.  C\bCr\bro\bon\bnd\bd-\b-g\bge\ben\bne\ber\bra\bat\bte\bed\bd d\bdi\big\bge\bes\bst\bts\bs f\bfo\bor\br b\bbe\bet\btt\bte\ber\br p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  With the default setup, ezmlm-tstdig(1) in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br tests if a
+  digest should be sent out. On lists with a lot of traffic this is
+  inefficient.  Also, you may want digests to be delivered as a specific
+  time. To do this, use crond(8) to execute ezmlm-get(1) directly, as
+  described elsewhere.
+
+
+  1\b16\b6.\b.2\b2.\b.  O\bOp\bpt\bti\bim\bmi\biz\bzi\bin\bng\bg e\bex\bxe\bec\bcu\but\bti\bio\bon\bn o\bof\bf e\bez\bzm\bml\blm\bm-\b-w\bwa\bar\brn\bn(\b(1\b1)\b).\b.
+
+  ezmlm-idx>=0.32 comes with much improved bounce handling. Modification
+  as described below should be considered only when you expect thousands
+  of bouncing addresses (virtually never). The description remains, for
+  users of ezmlm-0.53 or earlier versions of ezmlm-idx. For users of
+  ezmlm-0.53 alone, we recommend a patch (
+  <ftp://ftp.id.wustl.edu/pub/patches/ezmlm-return.diff> which fixes a
+  bug in ezmlm-0.53 bounce handling. The patch is superseded by ezmlm-
+  idx.
+
+  To redistribute the load of bounce warning and probe addresses to off-
+  peak hours, you may want to set up the list without ezmlm-warn(1) by
+  using the ezmlm-make ``-w'' switch, and instead execute ``ezmlm-warn
+  DIR'' via crond(8). You also need to run ``ezmlm-warn -d DIR'' for
+  digest bounces if your list is configured with digests. Normal ezmlm
+  list with ezmlm-idx>=0.32 will have an insignificant bounce load,
+  except if you bulk add addresses, e.g. from a MLM without bounce
+  handling. In the latter case, the load will be higher for the first
+  2-4 weeks, then decrease drastically. If you feel you need to run
+  ezmlm-warn(1) from crond(8), you should seriously consider sublisting
+  your lists.
+
+  _\bN_\bo_\bt_\be_\b: the ezmlm-make(1) ``-w'' switch has a special meaning if used at
+  the same time as enabling SQL-support (``-6''; see man pages).
+
+
+  1\b16\b6.\b.3\b3.\b.  D\bDe\bec\bcr\bre\bea\bas\bsi\bin\bng\bg e\bez\bzm\bml\blm\bm-\b-w\bwa\bar\brn\bn t\bti\bim\bme\be o\bou\but\bt t\bto\bo i\bin\bnc\bcr\bre\bea\bas\bse\be p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  With ezmlm-idx, you may alter the ezmlm-warn(1) timeout to a number of
+  seconds with the ``-t seconds'' switch.  The default is 1,000,000
+  seconds or about 11.6 days. This is the time from the first bounce
+  until ezmlm-warn(1) sends a warning message and the time from the
+  warning message bounce until ezmlm-warn(1) sends a probe (which if
+  bounced leads to removal of the address from the subscriber list).  If
+  you have a digest list, remember to execute ezmlm-warn(1) with the
+  ``-d'' switch as well.
+
+  Decreasing the default to e.g. 5 days will cut in half the average
+  number of files in the bounce directory and the number of messages
+  sent at each crond(8)-directed invocation of ezmlm-warn(1). The trade-
+  off is that worst case, a subscriber may be unsubscribed if his/her
+  mail path is defective for more than twice the timeout. Removing a
+  subscriber after 10 days seems reasonable on a busy list. Do this by
+  adding the ``-t'' switch to all the ezmlm-warn(1) invocations. This
+  timeout should be larger than the interval between ezmlm-warn(1)
+  invocation.
+
+  To be aggressive, use ``ezmlm-warn -t0''. This will minimize the time
+  your lists spends servicing bounces, but will for some errors lead to
+  subscribers to be also lead to subscribers being removed if messages
+  to them bounce for two consecutive ezmlm-warn(1) runs. This is useful
+  to rapidly clean up a low quality address collection.
+
+
+  1\b16\b6.\b.4\b4.\b.  U\bUs\bse\be e\bez\bzm\bml\blm\bm w\bwi\bit\bth\bho\bou\but\bt e\bez\bzm\bml\blm\bm-\b-i\bid\bdx\bx f\bfo\bor\br m\bma\bax\bxi\bim\bmu\bum\bm p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  ezmlm-idx adds a number of functions to ezmlm. It indexes the archive,
+  and adds an index entry for each message, it can remove MIME parts, it
+  can add a subject prefix and message trailer, decode rfc2047-encoded
+  subjects, etc.  Although designed to impact minimally on performance,
+  these options when used take time. Even when they are not used, time
+  is spent looking for e.g. the prefix. However, the performance penalty
+  is small, as the absolutely dominating cost of a mailing list is the
+  work qmail does to deliver the messages to subscribers.
+
+  In bench marking, we have not found a significant difference in
+  performance between ezmlm-0.53 and ezmlm-0.53+ezmlm-idx-0.32 when
+  ezmlm-idx features are not used. Thus, a non-indexed list with ezmlm-
+  idx-0.32 performs the same as the corresponding ezmlm-0.53 list.
+  Adding an index adds the overhead of another safe write (the index
+  file). Use of other features adds very marginally to execution time.
+  For virtually all lists, the ezmlm execution time is negligible
+  compared to the resources needed by qmail to disseminate the message
+  to the subscribers.
+
+
+  1\b16\b6.\b.5\b5.\b.  N\bNo\bot\bt a\bar\brc\bch\bhi\biv\bvi\bin\bng\bg t\bto\bo m\bma\bax\bxi\bim\bmi\biz\bze\be p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  An archived list needs to write the message to the archive. If you
+  don't need an archive, don't archive. However, the archive is very
+  useful to allow users to catch up on messages that they didn't receive
+  due to delivery problems.
+
+
+  1\b16\b6.\b.6\b6.\b.  S\bSu\bub\bbl\bli\bis\bst\bts\bs t\bto\bo m\bma\bax\bxi\bim\bmi\biz\bze\be p\bpe\ber\brf\bfo\bor\brm\bma\ban\bnc\bce\be.\b.
+
+  Consider splitting your list into sublists, ideally geographically.
+  The main list deals only with a subset of subscribers (or only the
+  sublists), and each sublist deals with a subset of subscribers,
+  bounces, etc. This is the most rational way to scale ezmlm to large
+  lists (see ``How sublists work'' for more info on how sublists work
+  and ``Sublists'' on how to set up sublists).
+
+
+  1\b17\b7.\b.  M\bMi\bis\bsc\bce\bel\bll\bla\ban\bne\beo\bou\bus\bs.\b.
+
+
+  1\b17\b7.\b.1\b1.\b.  H\bHo\bow\bw d\bdo\bo I\bI q\bqu\bui\bic\bck\bkl\bly\by c\bch\bha\ban\bng\bge\be t\bth\bhe\be p\bpr\bro\bop\bpe\ber\brt\bti\bie\bes\bs o\bof\bf m\bmy\by l\bli\bis\bst\bt?\b?
+
+
+
+               ezmlm-make -+ [changed_switches] dir
+
+
+
+
+  ezmlm-make(1) stores configuration info in D\bDI\bIR\bR/\b/c\bco\bon\bnf\bfi\big\bg and uses that
+  info as the default when you use the ``-+'' switch. If the list was
+  created with a very old version or ezmlm-0.53 ezmlm-make(1) you have
+  to restate all arguments the first time you edit the list.
+
+  The ``-e'' switch works the same, without stickiness for switches.
+
+  A message arriving during reconfiguration may be handled incorrectly.
+  The prudent user will set the sticky bit on the home directory to
+  prevent delivery, then clear it after the list has been changed.
+
+
+  1\b17\b7.\b.2\b2.\b.  O\bOp\bpe\ben\bn a\bar\brc\bch\bhi\biv\bve\bed\bd l\bli\bis\bst\bt w\bwi\bit\bth\bh d\bda\bai\bil\bly\by d\bdi\big\bge\bes\bst\bts\bs.\b.
+
+  This is the default setup. The main list generates digests in response
+  to a mailed request or when a message arrives and the amount of
+  messages since the last digest exceeds set limits (see ezmlm-
+  tstdig(1)).  Alternatively, ezmlm-get(1) can be invoked from the
+  command line. In both cases, the generated digest message is
+  disseminated to the subscribers stored in D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs/\b/,
+  i.e. the subscriber database with the base directory D\bDI\bIR\bR/\b/d\bdi\big\bge\bes\bst\bt/\b/.
+
+  +\bo  See ``setting up a digest list'' on how to set up the lists.
+
+
+  1\b17\b7.\b.3\b3.\b.  V\bVa\bar\bri\bia\bat\bti\bio\bon\bns\bs i\bin\bn m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn
+
+  You can set up lists with combinations of message moderation,
+  subscription moderation, and remote administration, easiest by
+  combining ezmlm-make(1) ``-m'' ,``-s'', and ``-r'' switches. You can
+  use a non-default moderator db, by specifying a directory starting
+  with a slash in D\bDI\bIR\bR/\b/m\bmo\bod\bds\bsu\bub\bb or D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be (for remote admin and
+  subscription moderation - always the same db for both functions) or in
+  D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt for message moderation. You can point several lists to the
+  same moderator db, thus using the same moderators for several lists.
+  _\bN_\bO_\bT_\bE_\b: The user controlling the list must have read/write access to the
+  files (specifically, must be able to write the lock file).
+
+  Some of these setups are not trivial. However, you can make them
+  trivial by modifying ezmlmrc(5) so that ezmlm-make(1) can set up the
+  desired lists by default or when the user uses e.g. the ``-y'' or
+  ``-z'' switches (see ``Customizing ezmlm-make operation'').
+
+
+  1\b17\b7.\b.4\b4.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt a\bal\bll\blo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bn,\b, b\bbu\but\bt n\bno\bot\bt u\bus\bse\ber\br i\bin\bni\bit\bti\bia\bat\bte\bed\bd s\bsu\bub\bbs\bsc\bcr\bri\bip\bp-\b-
+  t\bti\bio\bon\bn o\bor\br a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl.\b.
+
+  Create a regular remote admin list, but remove D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc.  This
+  allows moderators to (un)subscribe users and have archive access, but
+  rejects all user requests. Posts work as usual.  Naturally, this can
+  be combined with message moderation or ezmlm-issub SENDER checks (see
+  ``Restricting message posting to the list'').
+
+
+  1\b17\b7.\b.5\b5.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt a\bal\bll\blo\bow\bw r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bn,\b, u\bus\bse\ber\br a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl,\b, b\bbu\but\bt n\bno\bot\bt
+  u\bus\bse\ber\br-\b-i\bin\bni\bit\bti\bia\bat\bte\bed\bd s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn.\b.
+
+  Create a regular remote admin list, remove D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc, and add the
+  ``-p'' [public] switch to the ezmlm-get(1) command line in
+  D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. This overrides the normal D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc effect on ezmlm-
+  get(1) and archive retrieval, allowing full archive access to anyone,
+  but rejecting user -help and subscription commands.  It is assumed
+  that the users know archive retrieval commands without help. If you
+  want to provide specific help, just link ~\b~/\b/.\b.q\bqm\bma\bai\bil\bl-\b-l\bli\bis\bst\btn\bna\bam\bme\be-\b-h\bhe\bel\blp\bp to
+  D\bDI\bIR\bR/\b/h\bhe\bel\blp\bp, and invoke a script that copies help info from there. See
+  ezmlm-check(1) for an example.
+
+
+  1\b17\b7.\b.6\b6.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt r\bre\bes\bst\btr\bri\bic\bct\bt a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl t\bto\bo s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs.\b.
+
+  Use a standard list, but add the ezmlm-get(1) ``-s'' command line
+  switch in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. Only subscribers can receive archive excerpts.
+  Digests work as usual. This can be set up using the ezmlm-make(1)
+  ``-g'' switch.
+
+
+  1\b17\b7.\b.7\b7.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt d\bdo\bo n\bno\bot\bt a\bal\bll\blo\bow\bw a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl a\bat\bt a\bal\bll\bl.\b.
+
+  Use a standard list, but add the ``-C'' switch to both the ezmlm-
+  get(1) and ezmlm-manage(1) command lines in D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. No archive
+  retrieval commands will be honored. Digest can be created as usual
+  (See ``Restricting archive retrieval'').
+
+
+  1\b17\b7.\b.8\b8.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt d\bdo\bo n\bno\bot\bt a\bal\bll\blo\bow\bw a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl a\ban\bnd\bd d\bdo\bo n\bno\bot\bt a\bal\bll\blo\bow\bw
+  d\bdi\big\bge\bes\bst\bt t\btr\bri\big\bgg\bge\ber\bri\bin\bng\bg p\bpe\ber\br m\bma\bai\bil\bl.\b.
+
+  For maximal archive security, set up a normal indexed and archived
+  list, then remove the ezmlm-get(1) line from D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br and add the
+  ``-C'' switch to the ezmlm-manage(1) command line. You can still
+  create digests by direct invocation of ezmlm-get(1) from a script or
+  crontab entry.
+
+
+  1\b17\b7.\b.9\b9.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt a\bal\bll\blo\bow\bw a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl o\bon\bnl\bly\by t\bto\bo m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs,\b, b\bbu\but\bt
+  a\bal\bll\blo\bow\bw u\bus\bse\ber\br-\b-i\bin\bni\bit\bti\bia\bat\bte\bed\bd s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn.\b.
+
+  Create a normal remote admin (+ subscription moderated) list, and add
+  the ``-P'' (not public) switch to the ezmlm-get(1) command line in
+  D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br. Subscription will not be affected, but ezmlm-get(1) will
+  send archive excerpts only to moderators.  Digests are unaffected.
+
+
+  1\b17\b7.\b.1\b10\b0.\b.  L\bLi\bis\bst\bts\bs t\bth\bha\bat\bt d\bdo\bo n\bno\bot\bt r\bre\beq\bqu\bui\bir\bre\be u\bus\bse\ber\br c\bco\bon\bnf\bfi\bir\brm\bma\bat\bti\bio\bon\bn f\bfo\bor\br (\b(u\bun\bn)\b)s\bsu\bub\bbs\bsc\bcr\bri\bip\bp-\b-
+  t\bti\bio\bon\bn.\b.
+
+
+  The need for a user handshake can be eliminated by the ezmlm-manage(1)
+  ``-S'' (subscribe) and/or ``-U'' (unsubscribe) switches. Alone, this
+  is very insecure. However, there may be some use for it in local lists
+  with subscription moderation, or alone for notifications where ease of
+  use is more important than preventing users from (un)subscribing
+  others. If the list has subscription moderation or remote
+  administration, any user subscribe or unsubscribe request is forwarded
+  to the moderators if the SENDER and target address do not match, even
+  if the ``-U/-S'' switches are specified. This is put in place to make
+  a ``-U/-S'' list similar to other list managers, not for security
+  (it's not secure, since a malicious outsider can easily fake the
+  SENDER address). Unsubscribe confirmations are sent also to the target
+  in this case, to avoid situations where the user needs moderator
+  ``permission'' to get off the list.
+
+
+  1\b17\b7.\b.1\b11\b1.\b.  A\bAn\bnn\bno\bou\bun\bnc\bce\bem\bme\ben\bnt\bt l\bli\bis\bst\bts\bs f\bfo\bor\br a\ba s\bsm\bma\bal\bll\bl s\bse\bet\bt o\bof\bf t\btr\bru\bus\bst\bte\bed\bd p\bpo\bos\bst\bte\ber\brs\bs
+
+  Set up the list with ezmlm-make ``-om'' and add the ``trusted E-mail
+  addresses'' to D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ with
+
+
+       % ezmlm-sub DIR/mod address@host
+
+
+
+
+  A post from a ``trusted address'' is sent back to that address for
+  approval, assuring that the user at that address really sent the post.
+  Posts from other e-mail addresses are rejected.
+
+
+  1\b17\b7.\b.1\b12\b2.\b.  A\bAn\bnn\bno\bou\bun\bnc\bce\bem\bme\ben\bnt\bt l\bli\bis\bst\bts\bs a\bal\bll\blo\bow\bwi\bin\bng\bg m\bmo\bod\bde\ber\bra\bat\bte\bed\bd p\bpo\bos\bst\bts\bs f\bfr\bro\bom\bm a\ban\bny\byo\bon\bne\be.\b.
+
+  This is useful in many circumstances. A list announcing new programs
+  for a system, where both the main developers and other users may have
+  contributed programs.
+
+  Set up the list with ezmlm-make ``-m'' and the main developers as
+  moderators. When any of these posts, that user alone is asked to
+  confirm. Posts from other E-mail addresses are sent to all
+  moderators/developers.  To use a different set of E-mail addresses as
+  ``trusted e-mail addresses'' and moderators for other posts, use the
+  ezmlm-store(1) ``-S'' switch and make a separate address database for
+  the ``trusted E-mail addresses''.  Put the name of the basedir for the
+  ``trusted e-mail addresses'' database in D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt (needs leading
+  ``/''), and add the post moderator(s) to D\bDI\bIR\bR/\b/m\bmo\bod\bd/\b/ using ezmlm-sub(1)
+  as shown above.
+
+
+  1\b17\b7.\b.1\b13\b3.\b.  A\bAn\bnn\bno\bou\bun\bnc\bce\bem\bme\ben\bnt\bt l\bli\bis\bst\bts\bs w\bwi\bit\bth\bh l\ble\bes\bss\bs s\bse\bec\bcu\bur\bri\bit\bty\by a\ban\bnd\bd m\bmo\bor\bre\be c\bco\bon\bnv\bve\ben\bni\bie\ben\bnc\bce\be.\b.
+
+  A general solution for SENDER checking is to configure list with
+  ezmlm-gate(1).  ezmlm-gate(1) takes as arguments any number of
+  basedirs for subscriber lists. Posts from SENDERs that are found are
+  posted. For others ezmlm-store(1) is invoked. If D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt exists,
+  ezmlm-store(1) will send out other messages for moderation.  To bounce
+  such messages, create D\bDI\bIR\bR/\b/m\bmo\bod\bdp\bpo\bos\bst\bt, and use the ezmlm-gate(1) ``-P''
+  switch (will be passed on to ezmlm-store(1) to bounce any posts not
+  from a moderator).
+
+  By default, ezmlm-gate(1) accepts messages from subscribers. However,
+  this is overridden if any ``basedirs'' are put on the ezmlm-gate(1)
+  command line. Common would be to create a address list and put its
+  ``basedir'' on the ezmlm-gate(1) command line. Trusted E-mail
+  addresses can then be added with:
+       % ezmlm-sub basedir trusted@host
+
+
+
+
+  As this relies on SENDER checks it is less secure than the ezmlm-store
+  based confirmation-requiring setup.
+
+
+  1\b18\b8.\b.  E\bEz\bzm\bml\blm\bm-\b-i\bid\bdx\bx c\bco\bom\bmp\bpi\bil\ble\be t\bti\bim\bme\be o\bop\bpt\bti\bio\bon\bns\bs.\b.
+
+
+  1\b18\b8.\b.1\b1.\b.  L\bLo\boc\bca\bat\bti\bio\bon\bn o\bof\bf b\bbi\bin\bna\bar\bri\bie\bes\bs.\b.
+
+  This is configured via c\bco\bon\bnf\bf-\b-b\bbi\bin\bn as for other ezmlm programs.  The
+  default is /\b/u\bus\bsr\br/\b/l\blo\boc\bca\bal\bl/\b/b\bbi\bin\bn/\b/e\bez\bzm\bml\blm\bm.
+
+
+  1\b18\b8.\b.2\b2.\b.  L\bLo\boc\bca\bat\bti\bio\bon\bn o\bof\bf m\bma\ban\bn p\bpa\bag\bge\bes\bs.\b.
+
+  This is configured via c\bco\bon\bnf\bf-\b-m\bma\ban\bn as for other ezmlm programs.  The
+  default is /\b/u\bus\bsr\br/\b/l\blo\boc\bca\bal\bl/\b/m\bma\ban\bn.
+
+
+  1\b18\b8.\b.3\b3.\b.  B\bBa\bas\bse\be d\bdi\bir\bre\bec\bct\bto\bor\bry\by o\bof\bf q\bqm\bma\bai\bil\bl-\b-i\bin\bns\bst\bta\bal\bll\bla\bat\bti\bio\bon\bn.\b.
+
+  This is configured via c\bco\bon\bnf\bf-\b-q\bqm\bma\bai\bil\bl as for other ezmlm programs.  The
+  default is /\b/v\bva\bar\br/\b/q\bqm\bma\bai\bil\bl.
+
+
+  1\b18\b8.\b.4\b4.\b.  S\bSh\bho\bor\brt\bt h\bhe\bea\bad\bde\ber\br t\bte\bex\bxt\bts\bs,\b, e\bet\btc\bc.\b.
+
+  Ezmlm-idx text (short lines, such as ``Administrivia'' for digests),
+  command names, etc, are defined in i\bid\bdx\bx.\b.h\bh, used at compile time. You
+  can change them by changing the defines in this file.
+
+
+  1\b18\b8.\b.5\b5.\b.  A\bAr\brb\bbi\bit\btr\bra\bar\bry\by l\bli\bim\bmi\bit\bts\bs.\b.
+
+  i\bid\bdx\bx.\b.h\bh contains defines for some ezmlm-idx arbitrary limits, such as
+  the maximum number of messages per ``-get'' request. They can be
+  changed here.
+
+
+  1\b18\b8.\b.6\b6.\b.  C\bCo\bom\bmm\bma\ban\bnd\bd n\bna\bam\bme\bes\bs.\b.
+
+  There is support for one alias per user command for
+  internationalization.  (See ``Multiple language support''.)
+
+
+  1\b18\b8.\b.7\b7.\b.  E\bEr\brr\bro\bor\br m\bme\bes\bss\bsa\bag\bge\bes\bs.\b.
+
+  All ezmlm-idx error messages are defines in e\ber\brr\brt\btx\bxt\bt.\b.h\bh, used at compile
+  time. These can be changed for special situations, but we would advise
+  against doing so. If you do for some reason produce such a translated
+  file, we would appreciate if you sent a copy to the authors. NOTE:
+  These do not affect error messages from programs that are not part of
+  the ezmlm-idx package, nor of some subroutines used by ezmlm-idx
+  programs (getconf_line.c comes to mind).
+
+  Hopefully, the error messages for all parts will be synchronized in
+  later versions of ezmlm, and possibly handled from a run-time
+  changeable separate file (maybe as a .cdb database).
+
+
+
+  1\b18\b8.\b.8\b8.\b.  P\bPa\bat\bth\bhs\bs a\ban\bnd\bd o\bot\bth\bhe\ber\br o\bod\bdd\bd c\bco\bon\bnf\bfi\big\bgu\bur\bra\bat\bti\bio\bon\bn i\bit\bte\bem\bms\bs.\b.
+
+  idx.h also has defines for /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc, default formats for
+  moderation enclosures, default character set, default digest format,
+  etc. Since most of these items are easily changed at run time, there
+  is usually no need to change the compiled-in defaults. If you do need
+  to, this is where they are.
+
+
+  1\b19\b9.\b.  M\bMu\bul\blt\bti\bip\bpl\ble\be l\bla\ban\bng\bgu\bua\bag\bge\be s\bsu\bup\bpp\bpo\bor\brt\bt.\b.
+
+
+  1\b19\b9.\b.1\b1.\b.  C\bCo\bom\bmm\bma\ban\bnd\bd n\bna\bam\bme\bes\bs.\b.
+
+  ezmlm commands can have aliases for use in translations for non-
+  English use.  Due to the use of commands in mail e-mail addresses, the
+  character set is limited by rfc822 to us-ascii. To enable the command
+  aliases, remove the comment marks around the INTL_CMDS define in
+  idx.h. Also, remove the comments from the define corresponding to one
+  language (currently, only LANG_FR - French) available.
+
+  The INTL_CMDS define results in the compilation of all ezmlm programs
+  with support for alias commands for those commands listed in the INTL
+  section (all that are used directly by users). All aliases MUST be
+  defined, but should be the normal English commands. The language-
+  specific sections un-define and redefine the commands for which
+  alternative names should be used. This allows use of e.g.
+  ``inscription'' as an alias in addition to the standard ``subscribe''.
+
+
+  1\b19\b9.\b.2\b2.\b.  T\bTe\bex\bxt\bt f\bfi\bil\ble\bes\bs.\b.
+
+  Most ezmlm responses are made from text files in D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/. These are
+  created from the template file ``ezmlmrc''. Thanks to Frank Denis, and
+  Masashi Fujita, Wanderlei Antonio Cavassin, Sergiusz Pawlowicz, Frank
+  Tegtmeyer, Torben Fjerdingstad, Jan Kasprzak, and Sebastian Andersson,
+  French, Japanese, Portuguese (var. Brazil), Polish, German, Danish,
+  Czech, and Swedish versions are available. Just:
+
+
+               % make jp
+
+
+
+
+  before
+
+
+               # make setup
+
+
+
+
+  or just copy e\bez\bzm\bml\blm\bmr\brc\bc.\b.j\bjp\bp to /\b/e\bet\btc\bc/\b/e\bez\bzm\bml\blm\bmr\brc\bc, where it will override the
+  copy installed in the ezmlm binary directory. For rpm packages, the
+  en_US version is installed, but the other versions are available in
+  the /\b/u\bus\bsr\br/\b/d\bdo\boc\bc/\b/ hierarchy.
+
+  If you have made an e\bez\bzm\bml\blm\bmr\brc\bc(\b(5\b5)\b) version for another language, please
+  make it public domain and E-mail it as an attachment to
+  lindberg@id.wustl.edu. It will then be put into the e\bez\bzm\bml\blm\bmr\brc\bc directory
+  of the distribution site. Please take advantage of the ``Content-
+  transfer-encoding'' capability of ezmlm-idx>=0.30, if needed, as this
+  avoids problems when messages are sent via non-8-bit MUAs.
+
+
+  Other ezmlm responses, such as words in subject lines, are defines in
+  i\bid\bdx\bx.\b.h\bh and can be changed there. Error messages should ideally not be
+  altered. However, it may make sense to change a few of them which are
+  used as messages to e.g. remote administrators. The defines for all
+  error messages are in e\ber\brr\brt\btx\bxt\bt.\b.h\bh.
+
+
+  1\b19\b9.\b.3\b3.\b.  M\bMu\bul\blt\bti\bi-\b-b\bby\byt\bte\be c\bch\bha\bar\bra\bac\bct\bte\ber\br c\bco\bod\bde\be s\bsu\bup\bpp\bpo\bor\brt\bt.\b.
+
+  ezmlm, as far as we know, places no restrictions on character sets.
+  The configurable default character set allows you to use other
+  character sets for out going ezmlm messages. ezmlm-make does not _\bp_\be_\br
+  _\bs_\be support other character sets. However, any single-byte character
+  set is supported, as long as the us-ascii character sequence ``</''
+  does not occur anywhere as the first characters of the line, and the
+  character sequence ``<#x#>'' (where ``x'' is any number, or A, B, C,
+  D, F, H, L, R, T) does not occur anywhere is text (if it does, it
+  risks being substituted). Also, any occurrence or ``<#A#>'' and
+  ``<#R#>'' that is the first on any text line will be substituted by
+  ezmlm-manage and ezmlm-store. Any occurrence of ``!A'' and ``!R'' as
+  the first characters on a line will be substituted by ezmlm-manage and
+  ezmlm-store.
+
+  For multi-byte character codes, the same restrictions apply.  Thus,
+  ``</'' at the start of a line will confuse ezmlm-make, and any
+  ``<#x#>'' sequence within the text risks substitution. In practice,
+  both of these should be very rare and easily avoidable when setting up
+  an ezmlmrc(5).
+
+
+  2\b20\b0.\b.  S\bSu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br n\bno\bot\bti\bif\bfi\bic\bca\bat\bti\bio\bon\bn o\bof\bf m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn e\bev\bve\ben\bnt\bts\bs.\b.
+
+
+  2\b20\b0.\b.1\b1.\b.  G\bGe\ben\bne\ber\bra\bal\bl o\bop\bpi\bin\bni\bio\bon\bns\bs.\b.
+
+  This is a collection of the authors opinions and an explanation of
+  ezmlm-idx moderation design, which you may or may not agree with.
+
+
+  2\b20\b0.\b.2\b2.\b.  U\bUs\bse\ber\brs\bs s\bsh\bho\bou\bul\bld\bd k\bkn\bno\bow\bw t\bth\bha\bat\bt t\bth\bhe\be l\bli\bis\bst\bt i\bis\bs s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\bra\bat\bte\bed\bd.\b.
+
+  List subscribers should be informed that subscriptions to the list are
+  controlled by a moderator.  ezmlm-idx in its default setup handles
+  this notification during and after the subscribe handshake. Most of
+  this can be disabled by manipulation of the D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/ files.
+
+
+  2\b20\b0.\b.3\b3.\b.  S\bSu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\brs\bs s\bsh\bho\bou\bul\bld\bd k\bkn\bno\bow\bw t\bth\bha\bat\bt p\bpo\bos\bst\bts\bs a\bar\bre\be m\bmo\bod\bde\ber\bra\bat\bte\bed\bd.\b.
+
+  List subscribers should be informed that posts to the list are
+  moderated. ezmlm-idx does this by adding the ``Delivered-To: moderator
+  for ...'' header, but IOHO, the list owner should make the fact of
+  list moderation plain in introductory messages, or other means, to the
+  list subscribers.
+
+
+  2\b20\b0.\b.4\b4.\b.  S\bSe\ben\bnd\bde\ber\brs\bs o\bof\bf p\bpo\bos\bst\bts\bs s\bsh\bho\bou\bul\bld\bd b\bbe\be n\bno\bot\bti\bif\bfi\bie\bed\bd o\bof\bf r\bre\bej\bje\bec\bct\bti\bio\bon\bns\bs.\b.
+
+  With normal use of ezmlm-idx, the sender of a rejected post is
+  notified that the post has been rejected and if the moderators chooses
+  to comment, the sender receives this comment, usually describing why
+  the post was rejected.  This ezmlm behavior cannot be disabled at run
+  time.
+
+  If post are neither accepted or rejected, they time out. ezmlm-
+  clean(1) notifies the sender when this happens. This behavior can be
+  disabled with the ezmlm-clean(1) ``-R'' (not return) switch, which has
+  to be placed on the command line of all invocations of ezmlm-clean(1)
+  (normally in D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br and D\bDI\bIR\bR/\b/m\bmo\bod\bde\ber\bra\bat\bto\bor\br).  If you for some reason do
+  not wish to inform the sender of your editorial decision, you can use
+  this switch and let undesirable posts time out, rather than actively
+  rejecting them. IOHO, it is better to be "above board" and use the
+  normal notification mechanisms, together with active rejection and
+  informative rejection comments.
+
+  The ezmlm-make(1) ``-u'' switch uses moderation in a slightly
+  different way. Here, posts are restricted to subscribers, but posts
+  from non-subscribers are sent to the moderator(s) rather that being
+  ignored. This to help the subscriber that posts from an alias of the
+  subscribed address, or the occasional non-subscriber. In this case it
+  is perfectly acceptable to just ignore non-accepted posts. Thus, using
+  the ezmlm-make(1) ``-u'' switch configures the ezmlm-clean(1)
+  invocations with the ``-R'' switch.
+
+
+  2\b21\b1.\b.  E\bEz\bzm\bml\blm\bm-\b-i\bid\bdx\bx s\bse\bec\bcu\bur\bri\bit\bty\by.\b.
+
+
+  2\b21\b1.\b.1\b1.\b.  G\bGe\ben\bne\ber\bra\bal\bl a\bas\bss\bsu\bum\bmp\bpt\bti\bio\bon\bns\bs.\b.
+
+  This document discusses security aspects of ezmlm-idx addition to the
+  ezmlm-0.53 mailing list manager. This is the authors' understanding of
+  security aspects of ezmlm-idx functions and not to be taken as a
+  warranty. If you find any errors in this document or the ezmlm-idx
+  package in general, please inform the authors.
+
+  In general, ezmlm with or without the ezmlm-idx package is more secure
+  and less resource hungry than most other mailing list managers. Better
+  security than afforded by ezmlm +/- ezmlm-idx would require encryption
+  or PGP/digital signatures. Such an addition would make it difficult,
+  if not impossible, to run the mailing list from a standard MUA. The
+  ezmlm-idx package adds a number of functions and options, which under
+  some conditions may decrease security. The purpose of this document is
+  to discuss security aspects of using/enabling these different
+  functions.
+
+
+  2\b21\b1.\b.2\b2.\b.  S\bSE\bEN\bND\bDE\bER\bR m\bma\ban\bni\bip\bpu\bul\bla\bat\bti\bio\bon\bn.\b.
+
+  We assume that the cost of manipulating/falsifying the SENDER address
+  of a message is zero. Thus, any mechanism relying on SENDER alone is
+  insecure. However, such a mechanism may help in case of simple mailer
+  or user errors. We also assume that the "cookies" used by ezmlm are
+  secure, i.e.  that it is very hard for someone to generate a valid
+  cookie for a given address. SENDER is used to identify a moderator for
+  remote administration of subscriptions. The result of the action or
+  the confirmation request are sent back to that moderator address.
+  Thus, providing a false SENDER is useless, unless the attacker can
+  also read that moderator's mail.
+
+
+  2\b21\b1.\b.3\b3.\b.  e\bez\bzm\bml\blm\bm c\bco\boo\bok\bki\bie\bes\bs.\b.
+
+  Since ezmlm doesn't rely on the SENDER, the security lies entirely
+  within the action-time-cookie-address combination.  Anyone obtaining a
+  valid "combination" can do whatever the combination is meant to do,
+  but nothing else. Also, the cookie times out 1000000 seconds
+  (approximately 11.6 days) after it was issued. Since the
+  "combinations" are specific for a particular action and address, they
+  can only be reused for that particular purpose, and within 11.6 days.
+  Ezmlm (un)subscriptions for a given address are usually pointless to
+  repeat. Message moderation "combinations" are useless after they've
+  been used, since the message is no longer in the moderation queue.
+
+
+  2\b21\b1.\b.4\b4.\b.  L\bLi\bis\bst\bts\bs w\bwi\bit\bth\bho\bou\but\bt r\bre\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bn/\b/s\bsu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+  Maliciously (un)subscribing an address with ezmlm-0.53 requires that
+  the attacker is able to read mail sent to the subscription address.
+
+  With the ezmlm-idx add-on, a non-moderated list works exactly the same
+  way. Ezmlm-idx introduces the moderator for moderated and remote admin
+  lists. For any moderator functions, an attacker needs to be able to
+  read mail sent to a moderator's address. If s/he can do this, the
+  attacker can affect anything the moderator is allowed to do (since
+  falsifying SENDER is trivial). To minimize risks, give moderators only
+  the power they need, do not use more moderators than necessary, and
+  use moderators whose mail is hard to intercept (on the same
+  machine/same internal/secure network or by encryption via e.g. ssh).
+
+
+  2\b21\b1.\b.5\b5.\b.  M\bMe\bes\bss\bsa\bag\bge\be m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+  A basic message moderated list keeps ezmlm subscriber security, but
+  interpolates the moderator(s) between the address of the list and the
+  list itself. An attacker able to read moderator mail can accept/reject
+  a post, if s/he can do it before a regular moderator has taken action.
+  The potential for abuse can be minimized by using few and local
+  moderators. Mail logs are needed to trace which moderator address was
+  misused.
+
+
+  2\b21\b1.\b.6\b6.\b.  S\bSu\bub\bbs\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn m\bmo\bod\bde\ber\bra\bat\bti\bio\bon\bn.\b.
+
+  A basic subscription moderated list retains ezmlm subscriber security,
+  but adds a moderator handshake. An attacker would need to be able to
+  both read mail to the subscriber address and to at least one
+  moderator.
+
+
+  2\b21\b1.\b.7\b7.\b.  R\bRe\bem\bmo\bot\bte\be a\bad\bdm\bmi\bin\bni\bis\bst\btr\bra\bat\bti\bio\bon\bn.\b.
+
+  A remote admin (-r) list adds the ability of the moderator to
+  (un)subscribe any address. The price of this is that an attacker able
+  to read moderator mail can (un)subscribe any address. The moderator
+  handshake message will be delivered to the abused moderator address,
+  which will alert that moderator and reveal the compromise. Another
+  basic assumption is that action-date-cookie-address combinations are
+  only sent to the target address or a moderator and that moderator
+  action "combinations" are never sent to non-moderators.
+
+
+  2\b21\b1.\b.8\b8.\b.  R\bRe\bem\bmo\bot\bte\be e\bed\bdi\bit\bti\bin\bng\bg o\bof\bf e\bez\bzm\bml\blm\bm t\bte\bex\bxt\bt f\bfi\bil\ble\bes\bs.\b.
+
+  ezmlm-manage(1) can allow remote administrators to edit files in
+  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt.  First, this option is disabled by default. Second, the
+  ``-edit'' command is accepted only when the target (the recipient) is
+  a remote administrator.  Third, only existing files within D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt
+  are editable.  It is not possible to create files.
+
+  ezmlm replies to a valid request with an informative message and the
+  contents of the file. In addition, the ``Reply-To:'' address contains
+  a cookie based on the file name and contents, as well as the current
+  time.  Anyone possessing this cookie can save a new version of the
+  text file. As with other ezmlm security, the security of this process
+  depends on only the remote administrator receiving remote
+  administrator mail. If this is not sufficiently secure for you, do not
+  enable this option. As always, an increase in accessibility results
+  results in a decrease in security.
+
+  Cookies for editing expire in approximately 27 hours. Also, as soon as
+  a file is changed, the cookie is invalidated since the file contents
+  change.  This also means that an outstanding edit request cannot be
+  completed if the files has been updated in the interim.
+
+  A potential attacker obtaining a valid cookie has a window of
+  opportunity while you edit the file, or for at most 27 hours. S/he can
+  overwrite and existing text file with potentially offensive material.
+  Usually, this can be achieved more easily by posting to the list. S/he
+  can also potentially fill your disk with a large amount of data (up to
+  two times 10240 bytes (limited by MAXEDIT in i\bid\bdx\bx.\b.h\bh)) and could put
+  part of this data onto messages leaving the list. Again, this is much
+  more easily achieved by e.g. sending the equivalently sized message to
+  your list.
+
+
+  2\b21\b1.\b.9\b9.\b.  D\bDi\big\bge\bes\bst\bt g\bge\ben\bne\ber\bra\bat\bti\bio\bon\bn a\ban\bnd\bd a\bar\brc\bch\bhi\biv\bve\be r\bre\bet\btr\bri\bie\bev\bva\bal\bl.\b.
+
+  The archive retrieval functions added by ezmlm-idx are digests
+  (protected by a "code") and other functions. Anyone who knows the
+  digest code (through reading mail logs, reading D\bDI\bIR\bR/\b/m\bma\ban\bna\bag\bge\ber\br of the
+  list, or reading any scripts used to send digest triggering messages)
+  can trigger a digest. Protect these locations accordingly!  For
+  default lists with digests triggered from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br via ezmlm-
+  tstdig(1) and ezmlm-get(1), you do not need the digest code and can
+  thus disable the possibility to trigger digest by mail.  For other
+  functions, the output is sent to SENDER and can be restricted to
+  subscribers (the ``-s'' switch). ezmlm-get(1) functions (apart from
+  digest) can be entirely disabled with the i``-C'' switch, or
+  restricted to moderators with the ``-P'' switch or by removing
+  D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc. Other sections of this document discuss several other
+  options. All switches are documented in the man pages.
+
+  The moderator support functions added by the ezmlm-idx package
+  (extended help and subscriber list) are sent only to a moderator
+  address, i.e. an attacker again needs to be able to read moderator
+  mail to read the output. The help info (D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/m\bmo\bod\bd-\b-h\bhe\bel\blp\bp) should not
+  contain secrets. The ``-list'' function is normally disabled, but can
+  be enabled with the ezmlm-manage -l switch to aid the remote
+  administrator(s).
+
+
+  2\b21\b1.\b.1\b10\b0.\b.  C\bCo\bon\bnv\bve\ben\bni\bie\ben\bnc\bce\be f\bfo\bor\br s\bse\bec\bcu\bur\bri\bit\bty\by:\b: t\bth\bhe\be e\bez\bzm\bml\blm\bm-\b-m\bma\ban\bna\bag\bge\be `\b``\b`-\b-S\bS'\b''\b' a\ban\bnd\bd `\b``\b`-\b-U\bU'\b''\b'
+  s\bsw\bwi\bit\btc\bch\bhe\bes\bs.\b.
+
+  ezmlm-manage(1) functions can be made more convenient, at the expense
+  of security. There have been many requests for these options, so they
+  have been added, although we recommend against using them:
+
+  The ezmlm-manage(1) ``-S'' switch eliminates the subscriber handshake
+  from subscribe requests. Thus, it is no longer necessary for the
+  subscriber to confirm the subscription. This is not secure, but may be
+  convenient for some moderated lists.  Use only with extreme caution.
+  The ezmlm-manage(1) ``-U'' switch similarly eliminates subscriber
+  confirmation from unsubscribe requests. Again, this is insecure and
+  useful only under special circumstances. If the list has any
+  moderators (remote or modsub), requests to (un)subscribe an address
+  other than sender are still routed to a moderator. This is similar to
+  how some other lists work. Naturally, this is insecure because it
+  relies on SENDER.  Unsubscribe requests are always non-moderated,
+  since, IOHO, it seems un-ethical to force a subscriber to remain on a
+  list. Where an unsubscribe confirm request is sent out it is (also)
+  sent to the target, except when the request was initiated by a
+  moderator on a list with remote administration (D\bDI\bIR\bR/\b/r\bre\bem\bmo\bot\bte\be exists).
+  The (un)subscription target is always informed about completed
+  (un)subscribe request, whether initiated by that address, another
+  address, or by a moderator. Thus, attempts of a user or moderator to
+  subscribe an address will be brought to the attention of the user
+  receiving mail at that address.
+
+
+  2\b21\b1.\b.1\b11\b1.\b.  D\bDe\ben\bni\bia\bal\bl o\bof\bf s\bse\ber\brv\bvi\bic\bce\be.\b.
+
+  ezmlm-get(1) archive retrieval functions can be used to deplete system
+  resources. However, this can also be done by posting messages to
+  lists, mail bombing, etc. If you are worried about this, you can use a
+  combination of ezmlm-manage/ezmlm-get ``-C'', ``-s'', and ``-P''
+  switches, removal of D\bDI\bIR\bR/\b/p\bpu\bub\bbl\bli\bic\bc, and removal of the mail-triggered
+  digest function (by removing the digest code from the ezmlm-get(1)
+  command line) to decrease availability of these functions (see man
+  pages). Digest can also be triggered by direct execution of ezmlm-get
+  from within a script from D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br as in the default setup with the
+  ezmlm-make(1) ``-d'' switch.
+
+
+  2\b21\b1.\b.1\b12\b2.\b.  M\bMo\bod\bde\ber\bra\bat\bto\bor\br a\ban\bno\bon\bny\bym\bmi\bit\bty\by.\b.
+
+  Anyone getting messages from the list can see the ``Delivered-To:
+  Moderator for ...'' header and realize that the list is moderated.  In
+  the authors opinion, this is fair and appropriate. If this bothers
+  you, edit the source of e\bez\bzm\bml\blm\bm-\b-s\bst\bto\bor\bre\be.\b.c\bc.
+
+  While the fact that the list is moderated will be disclosed by the
+  headers, the moderator(s)' identity will not be disclosed by the
+  header. Moderators are anonymous to anyone who cannot directly read
+  the mail log, the moderator list, or monitor your outgoing and
+  incoming mail. Anyone intercepting the acting moderators' mail or able
+  to read the mail log can determine who took a particular action.
+
+  Moderator E-mail addresses are not (to our knowledge) disclosed by any
+  ezmlm mechanism. Thus, the poster does not know who rejected/accepted
+  the message. Other moderators can find out that the message was
+  accepted (by seeing it on the list or by themselves committing to a
+  reject/accept reply) or rejected (by being informed by the poster or
+  by themselves committing to a reject/accept reply). If no moderator
+  takes any action for a given time (120 h - configurable to anything
+  24-240 h via D\bDI\bIR\bR/\b/m\bmo\bod\bdt\bti\bim\bme\be - and the parameters are likewise
+  configurable at compile time via i\bid\bdx\bx.\b.h\bh) the message times out, an act
+  for which no particular moderator can be held accountable.
+
+  Subscription requests are acted upon only if a moderator completes the
+  transaction by approving the requests. Requests can not be directly
+  disapproved, but the associated cookie becomes invalid after
+  approximately 11.6 days. Neither the subscriber nor the other
+  moderators know which moderator accepted the subscription request.
+  Requests to unsubscribe from the list are never moderated or otherwise
+  controlled, except by requiring confirmation from the subscriber
+  (normal unsubscribe) or the moderator that initiated the request
+  (remote administration). If several moderators approve the same
+  subscribe request, the user gets multiple notifications.
+
+  The triggering message (the moderation approval or the moderator's
+  completion of the subscription request) are not returned or logged.
+  This protects moderator anonymity, but makes it harder to track down
+  the offender in case of abuse. Only a good mail log will help. IOHO,
+  abuse of these mechanisms requires considerably more effort that it is
+  worth to (un)subscribe someone to a list.  Also, IOHO, moderator
+  anonymity is more important. If this increased difficulty in tracking
+  down abusive behavior bothers you, don't use the remote administration
+  and moderated subscription features.
+  2\b21\b1.\b.1\b13\b3.\b.  C\bCo\bon\bnf\bfi\bid\bde\ben\bnt\bti\bia\bal\bli\bit\bty\by o\bof\bf s\bsu\bub\bbs\bsc\bcr\bri\bib\bbe\ber\br E\bE-\b-m\bma\bai\bil\bl a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs.\b.
+
+  The optional ``-list'' command enabled by the ``-l'' ezmlm-manage(1)
+  command line switch returns a subscriber list to the moderator. Again,
+  anyone who can intercept a moderators' mail can fake SENDER and use
+  this command to obtain a subscriber list. The use of local moderators
+  minimize the risk. If the risk of subscriber disclosure is not worth
+  this convenience, do not enable this feature.
+
+
+  2\b21\b1.\b.1\b14\b4.\b.  H\bHe\bel\blp\bp m\bme\bes\bss\bsa\bag\bge\be f\bfo\bor\br m\bmo\bod\bde\ber\bra\bat\bto\bor\brs\bs.\b.
+
+  ezmlm-manage sends D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/m\bmo\bod\bd-\b-h\bhe\bel\blp\bp, rather than D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/h\bhe\bel\blp\bp in
+  reply to messages to list-help@host if the target address is a
+  moderator.  D\bDI\bIR\bR/\b/t\bte\bex\bxt\bt/\b/m\bmo\bod\bd-\b-h\bhe\bel\blp\bp should not contain secrets or other
+  confidential information.
+
+
+  2\b21\b1.\b.1\b15\b5.\b.  S\bSu\bub\bbl\bli\bis\bst\bts\bs.\b.
+
+  ezmlm sublists require that the message envelope sender is the main
+  list, and that the message has a ``Mailing-List:'' header. Both are
+  easy to fake, allowing an attacker to inject messages at the sublist
+  level. Other than the possible ramifications of only a subset of
+  subscribers seeing the message, this is of no concern for open lists.
+  For a ``subscriber-only'' list based on SENDER checks, it is no harder
+  to set SENDER to the address of a subscriber than to fake the headers
+  required by the sublist. However, for a moderated list the mainlist to
+  sublist communication becomes the weakest link. Sublists using a SQL
+  database also use better authentication in this step (see ``SQL-
+  enabled ezmlm lists'').
+
+  A sublist user can unsubscribe a normal ezmlm sublist from the main
+  list. To guard against this, you need to prevent propagation of
+  unsubscribe confirm requests by the sublist. Easiest is to add a line
+  to D\bDI\bIR\bR/\b/e\bed\bdi\bit\bto\bor\br before the ezmlm-send(1) line:
+
+
+               |grep -i '^Subject: CONFIRM' >/dev/null 2>&1 && exit 99; exit 0
+
+
+
+
+  Another option would be to take advantage of the fact that D\bDI\bIR\bR/\b/h\bhe\bea\bad\bde\ber\br-\b-
+  a\bad\bdd\bd headers at the main list are added to normal messages, but not to
+  administrative messages. Thus, one could discard messages that lack
+  the default ``Precedence: bulk'' header:
+
+
+               |grep -i '^Precedence: bulk' >/dev/null 2>&1 || exit 99; exit 0
+
+
+
+
+  For lists with SQL-support, users cannot unsubscribe sublists (see
+  ``SQL-enabled ezmlm lists'').
+
+  Break-in at a sublist host for normal ezmlm lists leads to
+  loss/compromise of the addresses handled by the sublist. For MySQL-
+  enabled lists, the sublist access credentials give DELETE and SELECT
+  access to all addresses serviced by the list. Thus, a successful
+  sublist attacker can completely disable the list. The MySQL log (if
+  used) will reveal from which host the attack was done. Although the
+  potential damage to a SQL-enabled list is greater, the results are of
+  the same order of magnitude. The risk in minimized by keeping control
+  over all sublist hosts. A successful sublist attacker cannot normally
+  add addresses, since the sublist users by default are set up without
+  INSERT privileges to the address database.
+
+
+  2\b21\b1.\b.1\b16\b6.\b.  S\bSQ\bQL\bL d\bda\bat\bta\bab\bba\bas\bse\bes\bs.\b.
+
+  For SQL-enabled lists, the database contains all list information.
+  Subversion of your database server allows an attacker to add/remove
+  addresses at will.  This is also true for normal ezmlm lists. In
+  addition, modification of the ``*_name'', ``*_cookie'', and ``*_mlog''
+  tables can cause the list to misbehave in a manner that doesn't
+  immediately suggest a security breach.  Keep your ezmlm list and
+  database servers secure.
+
+
+  2\b21\b1.\b.1\b17\b7.\b.  R\bRe\bep\bpo\bor\brt\bti\bin\bng\bg s\bse\bec\bcu\bur\bri\bit\bty\by p\bpr\bro\bob\bbl\ble\bem\bms\bs.\b.
+
+  Please send private E-mail about any security problems with the ezmlm-
+  idx additions to Fred Lindberg, lindberg@id.wustl.edu.  For ezmlm,
+  please send them via private E-mail to Dan J. Bernstein, the author of
+  ezmlm proper.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FILES.idx b/FILES.idx
new file mode 100644 (file)
index 0000000..3c2095d
--- /dev/null
+++ b/FILES.idx
@@ -0,0 +1,165 @@
+CHANGES.idx
+DOWNGRADE.idx
+FAQ.idx
+FILES.idx
+INSTALL.idx
+LICENCE.TXT
+README.idx
+TARGETS
+UPGRADE.idx
+author.c
+auto_cron.h
+case_diffs.c
+case_starts.c
+checktag.c
+concatHDR.c
+conf-cron
+conf-sqlcc
+conf-sqlld
+copy.c
+copy.h
+date2yyyymm.c
+dateline.c
+decodeB.c
+decodeHDR.c
+decodeQ.c
+encodeB.c
+encodeQ.c
+env.c
+errtxt.h
+ezcgi.css
+ezcgirc
+ezmlm-accept.1
+ezmlm-accept.sh
+ezmlm-archive.1
+ezmlm-archive.c
+ezmlm-cgi.1
+ezmlm-cgi.c
+ezmlm-check.1
+ezmlm-check.sh
+ezmlm-clean.1
+ezmlm-clean.c
+ezmlm-cron.1
+ezmlm-cron.c
+ezmlm-gate.1
+ezmlm-gate.c
+ezmlm-get.1
+ezmlm-get.c
+ezmlm-glconf.1
+ezmlm-glconf.sh
+ezmlm-idx.1
+ezmlm-idx.c
+ezmlm-issubn.1
+ezmlm-issubn.c
+ezmlm-limit.1
+ezmlm-limit.c
+ezmlm-list.c
+ezmlm-make.1
+ezmlm-make.c
+ezmlm-manage.1
+ezmlm-manage.c
+ezmlm-mktab
+ezmlm-mktab.1
+ezmlm-moderate.1
+ezmlm-moderate.c
+ezmlm-receipt.1
+ezmlm-receipt.c
+ezmlm-reject.1
+ezmlm-reject.c
+ezmlm-request.1
+ezmlm-request.c
+ezmlm-return.c
+ezmlm-send.c
+ezmlm-split.1
+ezmlm-split.c
+ezmlm-store.1
+ezmlm-store.c
+ezmlm-sub.c
+ezmlm-test.1
+ezmlm-test.sh
+ezmlm-tstdig.1
+ezmlm-tstdig.c
+ezmlm-unsub.c
+ezmlm-warn.c
+ezmlmglrc
+ezmlmglrc.5
+ezmlmrc.5
+ezmlmrc.cs
+ezmlmrc.da
+ezmlmrc.de
+ezmlmrc.en_US
+ezmlmrc.es
+ezmlmrc.fr
+ezmlmrc.id
+ezmlmrc.it
+ezmlmrc.jp
+ezmlmrc.pl
+ezmlmrc.pt_BR
+ezmlmrc.ru
+ezmlmrc.sv
+ezmlmsubrc
+ezmlmsubrc.5
+idx.h
+idx.patch
+idxthread.c
+idxthread.h
+issub.c
+logmsg.c
+makehash.c
+makehash.h
+mime.h
+opensql.c
+putsubs.c
+qmail-qmqpc.tar.gz
+qmail-verh.tar.gz
+qmail.c
+qmail.h
+searchlog.c
+subscribe.c
+subscribe.h
+tagmsg.c
+unfoldHDR.c
+yyyymm.h
+
+sub_mysql:
+README
+checktag.c
+conf-sqlcc
+conf-sqlld
+ezmlm-mktab
+issub.c
+logmsg.c
+opensql.c
+putsubs.c
+searchlog.c
+subscribe.c
+tagmsg.c
+to40x
+
+sub_pgsql:
+README
+checktag.c
+conf-sqlcc
+conf-sqlld
+ezmlm-mktab
+issub.c
+logmsg.c
+opensql.c
+putsubs.c
+searchlog.c
+subscribe.c
+tagmsg.c
+
+sub_std:
+README
+checktag.c
+conf-sqlcc
+conf-sqlld
+ezmlm-mktab
+issub.c
+logmsg.c
+opensql.c
+putsubs.c
+searchlog.c
+subscribe.c
+tagmsg.c
diff --git a/INSTALL.idx b/INSTALL.idx
new file mode 100644 (file)
index 0000000..6a7d899
--- /dev/null
@@ -0,0 +1,274 @@
+$Id: INSTALL.idx,v 1.49 1999/12/24 20:12:57 lindberg Exp $
+$Name: ezmlm-idx-040 $
+
+Like any other piece of software (and information generally), ezmlm-idx
+comes with NO WARRANTY.
+
+This file is for installing ezmlm-idx for the first time on a system
+that may have ezmlm-0.53. If you're already using ezmlm-idx, see
+UPGRADE.idx instead.
+
+Things you have to decide before starting:
+
+   Common for ezmlm-0.53:
+   Put the desired ezmlm bin path into conf-bin. Default "/usr/local/bin/ezmlm",
+   but for e.g. rpm packages it's "/usr/bin". Adjust conf-man accordingly.
+   For installations (e.g. Debian) where qmail is not in "/var/qmail", adjust
+   conf-qmail.
+
+   NOTE: If you follow the test instructions in INSTALL of ezmlm-0.53 after
+   adding ezmlm-idx, step 6 will fail. Before this step, edit
+   ~/testlist/editor and remove the ezmlm-reject line.
+
+HOW TO BUILD, TEST, AND INSTALL:
+
+ 1. Expand the ezmlm-0.53.tar.gz archive. expand the ezmlm-idx-0.xx.tar.gz
+   archive:
+       % zcat ezmlm-0.53.tar.gz | tar -xvf
+       % zcat ezmlm-idx-0.xx.tar.gz | tar -xvf
+
+ 2. Copy the contents of the archive to your ezmlm-0.53 directory.
+       % mv ezmlm-idx-0.xx/* ezmlm-0.53/
+
+ 3. Patch the ezmlm-0.53 source:
+       % cd ezmlm-0.53
+       % patch < idx.patch
+
+    If you patch utility failes with this, get GNU patch.
+    [ezmlm-issubn, an enhanced version of ezmlm-issub is part of this package.
+    The patch for the ezmlm-return bug is also part of this package.]
+
+ 4. If your 'crontab' binary does not live in '/usr/bin' edit 'conf-cron'
+    now to reflect the correct path.
+
+ 5. RDBM Support.
+
+    MySQL:
+    If you want to compile ezmlm with MySQL support (http://www.tcx.se),
+    edit sub_mysql/conf-sqlcc (include files) and mysql/conf-sqlld (libraries)
+    to reflect your MySQL installation (see MySQL documentation). The files
+    are preset for RedHat Linux-i386. On some systems, the ``-lnsl'' should
+    be removed from conf-sqlld. The package has been tested with MySQL 3.22.
+
+    (Programs compiled with MySQL support will work like
+    their non-MySQL counterparts for lists that are not specifically
+    set up to take advantage of MySQL support.) Do:
+       % make mysql
+
+    PostgresSQL:
+    If you want to compile ezmlm with PostgreSQL support 
+    (http://www.postgreSQL.org), edit sub_pgsql/conf-sqlcc (include files) 
+    and pgsql/conf-sqlld (libraries) to reflect your PostgreSQL installation 
+    (see PostgreSQL documentation). Do:
+       % make pgsql
+
+    Others:
+    If you're familiar with C programming for the particular RDBMS, it will
+    take you no more than a few hours to adapt the files in sub_mysql (see
+    docs there). Create a new sub_????, tar and gzip it and send it to
+    lindberg#@id.wustl.edu for inclusion into the package.
+
+ 6. Compile the programs and man pages:
+       % make clean
+       % make; make man
+
+ 7. To use a language other than US English as the default for list texts:
+       % make ISO
+
+    where ``iso'' is the ISO language designation. Currently supported
+    are: cz, da, de, en_US, fr, jp, pl, pt_BR, sv. NOTE: A normal ``make'' sets
+    up the en_US version (as before). ezmlmrc files for your language
+    may be available via ftp://id.wustl.edu/pub/patches/ezmlmrc. If not,
+    please feel free to contribute one (translate ezmlmrc.en_US, but leave
+    comments intact for "diff").
+
+ 8. Test the programs:
+       a. Create a user ``eztest'' or edit ezmlm-test to use another user name.
+          This user should be able to execute the new binaries and also needs
+          to have read access to ezmlm-test (chmod 755 ezmlm-test).
+       b. Change to that user.
+       c. From the build directory, execute ezmlm-test:
+               % ./ezmlm-test
+
+       ezmlm-test will set up a test list, execute the various programs, and
+       test most functions of most programs. It works only if your qmail
+       installation works and allows sending mail to the local user. If you
+       use another user name, add ``-u other_user_name''. NOTE that the
+       arguments must be separated by a space from the switches.
+
+       Occasionally, ezmlm-test fails. This is usually due to problems with
+       ezmlm-test on your particular platform/installation and not due to
+       problems in ezmlm-idx. Please report problems with ezmlm-test, and if
+       you can, patches for correcting it.
+
+
+ 9. To test the SQL functions, set up a mysql database ``ezmlm'' accessible
+    to a user at this host (see MySQL/PostgreSQL docs; the ezmlm-mktab script
+    creates the necessary tables (see man page) but you must first create a
+    database and a user with sufficient access.
+
+    The following command creates a database for use with ezmlm-test.
+    NOTE that ezmlm-mktab and ezmlm-test options must be separated from the
+    switch, whereas the passwd argument for mysql -p must immediately
+    follow the switch.
+       % ./ezmlm-mktab -d list | mysql -hhost -uuser -ppasswd -f ezmlm
+
+    or for PostgresSQL:
+       % ./ezmlm-mktab -d list | pgsql [...] ezmlm
+
+    Now, as the ``eztest'' user, execute:
+       % ./ezmlm-test -l user -p passwd -h host
+
+    This will test the SQL part of the binaries. ``host'' defaults to
+    ``localhost'' and ``user'' defaults to ``ezmlm''. There is no default
+    for passwd and indeed ezmlm-test uses this switch to know to work
+    with SQL support. To execute under a user other than ``eztest'',
+    add a ``-u testuser'' switch. Note that -p has to be specified even if
+    the database has no password. In this case, use -p ''.
+
+10. If you for some reason want to rebuild binaries without MySQL support, do:
+       % make std
+       % make
+
+11. Copy binaries and man pages to the correct locations.
+       # make setup
+       (or copy manually).
+    If you'd like to retest the installation, change uid to the test user
+    ``eztest'' and change to the ezmlm binary directory. Now run ezmlm-test
+    as before.
+
+
+12. Your lists will run as before. To enable ezmlm-idx features like
+    threaded archive access, digest, etc, use:
+
+       % ezmlm-make -e [switches] DIR dot local host
+
+    where ``DIR dot local host'' are the arguments used to create the list,
+    and ``switches'' are desired options (see ezmlm-make man page). Future
+    adjustments can be made with:
+
+       % ezmlm-make -+ [switches] DIR
+
+    where ``switches'' are desired _changes_ from the previous configuration.
+
+------ OPTIONAL ------
+
+13. If you want qmail to add a subscriber-adapted List-Unsubscribe header to
+    outgoing messages, apply the enclosed qmail-verh-0.03.tar.gz patch to
+    qmail-1.03 and follow the documentation in that archive. This is a
+    failsafe way in which to unsubscribe, even if subscriber or list have
+    changed address.
+
+14. If you want to use large lists with custom QMQP servers, apply the
+    qmail-qmqp.tar.gz patch per instructions in the archive. You need this
+    only if you want per-[sub]list control over the QMQP servers used.
+15. (This can be done later if you decide to use ezmlm-cron(1). It is not
+    needed for normal lists and mainly for ``legacy installations''.)
+    The ezmlm-cron(1) program can be run SUID/SGID a special user with crond
+    access. This allows your users to use ezmlm-cron to generate digest
+    trigger messages, without being able to directly use crond. To enable
+    this feature create a special user, e.g. "ezmlm". Then:
+
+       # chown ezmlm /usr/local/bin/ezmlm-cron
+        # chmod 4555 /usr/local/bin/ezmlm-cron
+
+    and create ~ezmlm/ezcronrc as described in the ezmlm-cron(1) man
+    page. You may need to modify the path in the commands above if
+    you have installed ezmlm in a non-default location. ezmlm-cron refuses
+    to run SUID root.
+
+    This user can read its crontab file which may contain digest codes from
+    other users. Thus, this should be a reserved user name, not one of an 
+    ordinary user.
+
+
+16. If you would like to make your archived lists available via the World
+    Wide Web, you must install the ezmlm-cgi program which comes with
+    ezmlm-idx versions starting with ezmlm-idx-0.40. When ezmlm-idx is compiled
+    with the 'make' command, ezmlm-cgi is compiled also, however, it is not
+    installed. Installation of the program allows one to view the archives by
+    date, thread and author.  See, ezmlm-cgi.1 for more details.
+
+17. ezmlm-cgi must be installed where all other common gateway interface
+    ("CGI") programs are installed on your system. For most Un*x based system,
+    this will be in a directory titled 'cgi-bin' which is also, generally
+    speaking, in the root directory for your web server. For example, for apache
+    installations where /usr/local/apache is the root directory for the web
+    server, the directory /usr/local/apache/cgi-bin is where globally availably
+    CGI programs are located. You must copy the ezmlm-cgi program to this
+    location:
+
+       % cp /ezmlm-0.53/ezmlm-cgi /usr/local/apache/cgi-bin
+
+18. ezmlm-cgi should be installed SUID root. Examine the source code to make
+    yourself comfortable that the program is safe. After copying the program to
+    the 'cgi-bin' directory, change the ownerships and permissions as follows:
+
+       % chown root.root ezmlm-cgi
+       % chmod 4755 ezmlm-cgi
+
+    If you are using ezmlm-cgi for a single user, you can install it SUID that
+    user and place the config file (see below) as .ezcgirc in the same directory
+    as the program. If the list archive is readable to the httpd user, you do
+    not have to install it SUID at all (see man page for details).
+
+19. ezmlm-cgi uses a configuration files called 'ezcgirc' which must reside
+    in the /etc/ezmlm directory. First create the directory:
+
+       % mkdir /etc/ezmlm
+
+    Then use your favorite text editor to create the ezcgirc file. 
+
+    The file parameters are set forth on the first line. Comments are
+    allowed if preceded by the '#' in position 1. Lists are input by number
+    which is an arbitrary identifier with the exception of list '0' which is the
+    default list shown on the web page. As an example, the following utilizes a
+    list 'test@example.com' which is owned by the 'alias' user with a UID of
+    7827. The list resides in the directory '/var/qmail/alias/test' and its home
+    page is at 'http://www.example.com/test'. With the foregoing setup, the
+    ezcgirc file's contents are as follows:
+
+# Format for ezcgirc file
+#listno;uid;listdir;listaddr;buttonbar;charset;style;bannerprog
+0;7827;/var/qmail/alias/test;test@example.com;[Home]=http://www.example.com/test
+
+    Note there are no entries for 'charset', 'style' and 'bannerprog' Where
+    no entries are made, the default variables are assumed. The above
+    configuration assumes that the character set 'iso-8859-1' and that no
+    style sheet is used. Since formatting is largely controlled by the
+    style sheet, the output doesn't look exciting on a GUI browser. Start with
+    ezcgi.css in the distribution, and modify to taste. See www.ezmlm.org
+    for URLs to archives using different style sheets/banners.
+
+20. Finally, before accessing the list via the web, you must archive any
+    existing list and add an entry to listdir/editor to archive future posts.
+    You must also run ezmlm-idx (first see man pages for both programs):
+       
+       % ezmlm-idx DIR
+       % ezmlm-archive -c DIR
+
+21. For any existing lists which you would like to archive,
+    add the following line after the call to ezmlm-send in listdir/editor:
+
+       | /usr/local/ezmlm/ezmlm-archive listdir/DIR || exit 0
+
+    This is automatically done when running:
+
+       % ezmlm-make -+i DIR
+
+22. To display your web based archive, open your browser as follows:
+
+       %lynx http://localhost/cgi-bin/ezmlm-cgi
+
+ ------------- End Optional items -----------   
+
+23. That's it! To report success (helps to track platform-specific problems):
+
+       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \
+         | mail cfl-src@id.wustl.edu
+
+Replace First M. Last with your name.
+
+Send bugs reports, ideally with patch, to 'lindberg@id.wustl.edu'.
+
diff --git a/LICENCE.TXT b/LICENCE.TXT
new file mode 100644 (file)
index 0000000..ee0775e
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/MAN b/MAN
index df7b2a7..06f2e71 100644 (file)
--- a/MAN
+++ b/MAN
@@ -1,27 +1,67 @@
 d:::755:::
 d:::755:/man1::
 d:::755:/man5::
 d:::755:::
 d:::755:/man1::
 d:::755:/man5::
+c:::644:/man1/:ezmlm-accept.1:
+c:::644:/man1/:ezmlm-archive.1:
+c:::644:/man1/:ezmlm-issubn.1:
 c:::644:/man5/:ezmlm.5:
 c:::644:/man5/:ezmlm.5:
+c:::644:/man5/:ezmlmrc.5:
+c:::644:/man5/:ezmlmglrc.5:
+c:::644:/man5/:ezmlmsubrc.5:
 c:::644:/man1/:ezmlm-list.1:
 c:::644:/man1/:ezmlm-list.1:
+c:::644:/man1/:ezmlm-glconf.1:
 c:::644:/man1/:ezmlm-make.1:
 c:::644:/man1/:ezmlm-make.1:
+c:::644:/man1/:ezmlm-mktab.1:
 c:::644:/man1/:ezmlm-manage.1:
 c:::644:/man1/:ezmlm-manage.1:
+c:::644:/man1/:ezmlm-moderate.1:
 c:::644:/man1/:ezmlm-reject.1:
 c:::644:/man1/:ezmlm-reject.1:
+c:::644:/man1/:ezmlm-request.1:
 c:::644:/man1/:ezmlm-return.1:
 c:::644:/man1/:ezmlm-send.1:
 c:::644:/man1/:ezmlm-return.1:
 c:::644:/man1/:ezmlm-send.1:
+c:::644:/man1/:ezmlm-split.1:
+c:::644:/man1/:ezmlm-store.1:
 c:::644:/man1/:ezmlm-sub.1:
 c:::644:/man1/:ezmlm-unsub.1:
 c:::644:/man1/:ezmlm-warn.1:
 c:::644:/man1/:ezmlm-weed.1:
 c:::644:/man1/:ezmlm-sub.1:
 c:::644:/man1/:ezmlm-unsub.1:
 c:::644:/man1/:ezmlm-warn.1:
 c:::644:/man1/:ezmlm-weed.1:
+c:::644:/man1/:ezmlm-idx.1:
+c:::644:/man1/:ezmlm-gate.1:
+c:::644:/man1/:ezmlm-tstdig.1:
+c:::644:/man1/:ezmlm-get.1:
+c:::644:/man1/:ezmlm-check.1:
+c:::644:/man1/:ezmlm-clean.1:
+c:::644:/man1/:ezmlm-limit.1:
+c:::644:/man1/:ezmlm-cron.1:
 d:::755:/cat1::
 d:::755:/cat5::
 c:::644:/cat5/:ezmlm.0:
 d:::755:/cat1::
 d:::755:/cat5::
 c:::644:/cat5/:ezmlm.0:
+c:::644:/cat5/:ezmlmrc.0:
+c:::644:/cat5/:ezmlmglrc.0:
+c:::644:/cat5/:ezmlmsubrc.0:
 c:::644:/cat1/:ezmlm-list.0:
 c:::644:/cat1/:ezmlm-list.0:
+c:::644:/cat1/:ezmlm-glconf.0:
 c:::644:/cat1/:ezmlm-make.0:
 c:::644:/cat1/:ezmlm-make.0:
+c:::644:/cat1/:ezmlm-mktab.0:
 c:::644:/cat1/:ezmlm-manage.0:
 c:::644:/cat1/:ezmlm-manage.0:
+c:::644:/cat1/:ezmlm-moderate.0:
+c:::644:/cat1/:ezmlm-request.0:
 c:::644:/cat1/:ezmlm-reject.0:
 c:::644:/cat1/:ezmlm-return.0:
 c:::644:/cat1/:ezmlm-send.0:
 c:::644:/cat1/:ezmlm-reject.0:
 c:::644:/cat1/:ezmlm-return.0:
 c:::644:/cat1/:ezmlm-send.0:
+c:::644:/cat1/:ezmlm-store.0:
+c:::644:/cat1/:ezmlm-split.0:
 c:::644:/cat1/:ezmlm-sub.0:
 c:::644:/cat1/:ezmlm-unsub.0:
 c:::644:/cat1/:ezmlm-warn.0:
 c:::644:/cat1/:ezmlm-weed.0:
 c:::644:/cat1/:ezmlm-sub.0:
 c:::644:/cat1/:ezmlm-unsub.0:
 c:::644:/cat1/:ezmlm-warn.0:
 c:::644:/cat1/:ezmlm-weed.0:
+c:::644:/cat1/:ezmlm-idx.0:
+c:::644:/cat1/:ezmlm-gate.0:
+c:::644:/cat1/:ezmlm-tstdig.0:
+c:::644:/cat1/:ezmlm-get.0:
+c:::644:/cat1/:ezmlm-check.0:
+c:::644:/cat1/:ezmlm-clean.0:
+c:::644:/cat1/:ezmlm-limit.0:
+c:::644:/cat1/:ezmlm-cron.0:
+c:::644:/cat1/:ezmlm-accept.0:
+c:::644:/cat1/:ezmlm-archive.0:
+c:::644:/cat1/:ezmlm-issubn.0:
index 111a542..e3c7ab3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,14 @@
+#$Id: Makefile,v 1.117 1999/12/23 02:42:12 lindberg Exp $
+#$Name: ezmlm-idx-040 $
 SHELL=/bin/sh
 SHELL=/bin/sh
-
+SQLCC=`head -1 conf-sqlcc`
+SQLLD=`head -1 conf-sqlld`
 default: it
 
 default: it
 
+clean: \
+TARGETS
+       rm -f `cat TARGETS`
+
 alloc.0: \
 alloc.3
        nroff -man alloc.3 > alloc.0
 alloc.0: \
 alloc.3
        nroff -man alloc.3 > alloc.0
@@ -18,6 +25,10 @@ alloc_re.o: \
 compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c
        ./compile alloc_re.c
 
 compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c
        ./compile alloc_re.c
 
+author.o: \
+compile author.c mime.h
+       ./compile author.c
+
 auto-ccld.sh: \
 conf-cc conf-ld warn-auto.sh
        ( cat warn-auto.sh; \
 auto-ccld.sh: \
 conf-cc conf-ld warn-auto.sh
        ( cat warn-auto.sh; \
@@ -34,6 +45,14 @@ compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \
 exit.h auto-str.c
        ./compile auto-str.c
 
 exit.h auto-str.c
        ./compile auto-str.c
 
+auto_cron.c: \
+auto-str conf-cron
+       ./auto-str auto_cron `head -1 conf-cron` > auto_cron.c
+
+auto_cron.o: \
+compile auto_cron.c
+       ./compile auto_cron.c
+
 auto_bin.c: \
 auto-str conf-bin
        ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c
 auto_bin.c: \
 auto-str conf-bin
        ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c
@@ -79,13 +98,18 @@ case.3
        nroff -man case.3 > case.0
 
 case.a: \
        nroff -man case.3 > case.0
 
 case.a: \
-makelib case_diffb.o case_lowerb.o case_startb.o
-       ./makelib case.a case_diffb.o case_lowerb.o case_startb.o
+makelib case_diffb.o case_diffs.o case_starts.o case_lowerb.o case_startb.o
+       ./makelib case.a case_diffb.o case_lowerb.o case_startb.o \
+       case_diffs.o case_starts.o
 
 case_diffb.o: \
 compile case_diffb.c case.h case_diffb.c
        ./compile case_diffb.c
 
 
 case_diffb.o: \
 compile case_diffb.c case.h case_diffb.c
        ./compile case_diffb.c
 
+case_diffs.o: \
+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_lowerb.o: \
 compile case_lowerb.c case.h case_lowerb.c
        ./compile case_lowerb.c
@@ -94,6 +118,15 @@ case_startb.o: \
 compile case_startb.c case.h case_startb.c
        ./compile case_startb.c
 
 compile case_startb.c case.h case_startb.c
        ./compile case_startb.c
 
+checktag.o: \
+compile checktag.c stralloc.h scan.h fmt.h strerr.h cookie.h \
+       errtxt.h subscribe.h conf-sqlcc
+       ./compile checktag.c ${SQLCC}
+
+case_starts.o: \
+compile case_starts.c case.h
+       ./compile case_starts.c
+
 compile: \
 make-compile warn-auto.sh systype
        ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
 compile: \
 make-compile warn-auto.sh systype
        ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
@@ -110,6 +143,19 @@ compile cookie.c cookie.h cookie.c str.h cookie.c uint32.h cookie.c \
 surfpcs.h uint32.h surfpcs.h cookie.c
        ./compile cookie.c
 
 surfpcs.h uint32.h surfpcs.h cookie.c
        ./compile cookie.c
 
+copy.o: \
+compile copy.c copy.h stralloc.h substdio.h str.h readwrite.h open.h qmail.h \
+strerr.h getln.h case.h errtxt.h mime.h error.h quote.h
+       ./compile copy.c
+
+date2yyyymm.o:\
+compile date2yyyymm.c yyyymm.h
+       ./compile date2yyyymm.c
+
+dateline.o:\
+compile dateline.c yyyymm.h stralloc.h fmt.h
+       ./compile dateline.c
+
 date822fmt.o: \
 compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \
 date822fmt.h date822fmt.c
 date822fmt.o: \
 compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \
 date822fmt.h date822fmt.c
@@ -133,13 +179,46 @@ compile trydrent.c direntry.h1 direntry.h2
        && cat direntry.h2 || cat direntry.h1 ) > direntry.h
        rm -f trydrent.o
 
        && cat direntry.h2 || cat direntry.h1 ) > direntry.h
        rm -f trydrent.o
 
+concatHDR.o: \
+compile concatHDR.c mime.h stralloc.h strerr.h byte.h errtxt.h
+       ./compile concatHDR.c
+
+decodeB.o: \
+compile decodeB.c mime.h uint32.h stralloc.h strerr.h errtxt.h
+       ./compile decodeB.c
+
+decodeHDR.o: \
+compile decodeHDR.c mime.h stralloc.h strerr.h error.h case.h byte.h \
+uint32.h errtxt.h
+       ./compile decodeHDR.c
+
+decodeQ.o: \
+compile decodeQ.c mime.h stralloc.h strerr.h errtxt.h
+       ./compile decodeQ.c
+
+encodeB.o: \
+compile encodeB.c mime.h uint32.h stralloc.h strerr.h errtxt.h
+       ./compile encodeB.c
+
+encodeQ.o: \
+compile encodeQ.c mime.h stralloc.h strerr.h errtxt.h
+       ./compile encodeQ.c
+
+unfoldHDR.o: \
+compile unfoldHDR.c mime.h stralloc.h strerr.h errtxt.h
+       ./compile unfoldHDR.c
+
 env.0: \
 env.3
        nroff -man env.3 > env.0
 
 env.a: \
 env.0: \
 env.3
        nroff -man env.3 > env.0
 
 env.a: \
-makelib envread.o
-       ./makelib env.a envread.o
+makelib env.o envread.o
+       ./makelib env.a env.o envread.o
+
+env.o: \
+compile env.c env.h str.h
+       ./compile env.c
 
 envread.o: \
 compile envread.c env.h envread.c str.h envread.c
 
 envread.o: \
 compile envread.c env.h envread.c str.h envread.c
@@ -169,28 +248,281 @@ error_temp.0: \
 error_temp.3
        nroff -man error_temp.3 > error_temp.0
 
 error_temp.3
        nroff -man error_temp.3 > error_temp.0
 
+ezmlm-accept: \
+ezmlm-accept.sh warn-auto.sh conf-bin
+       (cat warn-auto.sh; \
+       echo EZPATH=\'`head -1 conf-bin`\'; \
+       cat ezmlm-accept.sh ) > ezmlm-accept
+
+ezmlm-accept.0: \
+ezmlm-accept.1
+       nroff -man ezmlm-accept.1 > ezmlm-accept.0
+
+ezmlm-archive: \
+load ezmlm-archive.o getconf.o slurpclose.o slurp.o getln.a sig.a \
+strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
+lock.a fd.a getopt.a idxthread.o yyyymm.a
+       ./load ezmlm-archive getconf.o slurpclose.o slurp.o getln.a sig.a \
+       idxthread.o yyyymm.a strerr.a substdio.a stralloc.a alloc.a \
+       error.a str.a fs.a open.a lock.a fd.a getopt.a
+
+ezmlm-archive.0: \
+ezmlm-archive.1
+       nroff -man ezmlm-archive.1 > ezmlm-archive.0
+
+ezmlm-archive.o: \
+compile ezmlm-archive.c alloc.h error.h stralloc.h gen_alloc.h str.h \
+sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h \
+makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h sgetopt.h subgetopt.h
+       ./compile ezmlm-archive.c
+
+ezmlm-cgi: \
+load ezmlm-cgi.o getconf.o slurpclose.o slurp.o constmap.o getln.a sig.a \
+mime.a strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
+lock.a fd.a getopt.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a
+       ./load ezmlm-cgi getconf.o slurpclose.o slurp.o constmap.o getln.a \
+       mime.a sig.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a \
+       strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
+       lock.a fd.a getopt.a
+
+ezmlm-cgi.0: \
+ezmlm-cgi.1
+       nroff -man ezmlm-cgi.1 > ezmlm-cgi.0
+
+ezmlm-cgi.o: \
+compile ezmlm-cgi.c alloc.h error.h stralloc.h gen_alloc.h str.h \
+sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h env.h \
+makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h mime.h \
+constmap.h sgetopt.h subgetopt.h datetime.h now.h fork.h wait.h
+       ./compile ezmlm-cgi.c
+
+ezmlm-check: \
+ezmlm-check.sh warn-auto.sh conf-bin
+       (cat warn-auto.sh; \
+       echo EZPATH=\'`head -1 conf-bin`\'; \
+       echo QMPATH=\'`head -1 conf-qmail`\'; \
+       cat ezmlm-check.sh ) > ezmlm-check
+
+ezmlm-check.0: \
+ezmlm-check.1
+       nroff -man ezmlm-check.1 > ezmlm-check.0
+
+ezmlm-clean: \
+load ezmlm-clean.o auto_qmail.o getconf.o copy.o mime.a \
+now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
+getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a surf.a \
+error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a cookie.o getopt.a
+       ./load ezmlm-clean auto_qmail.o getconf.o copy.o mime.a \
+       now.o datetime.o date822fmt.o slurpclose.o \
+       slurp.o qmail.o quote.o getln.a env.a sig.a strerr.a \
+       substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
+       open.a seek.a wait.a lock.a fd.a cookie.o getopt.a surf.a
+
+ezmlm-clean.0: \
+ezmlm-clean.1
+       nroff -man ezmlm-clean.1 > ezmlm-clean.0
+
+ezmlm-clean.o: \
+compile ezmlm-clean.c error.h stralloc.h gen_alloc.h str.h \
+env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h copy.h mime.h \
+qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h cookie.h \
+date822fmt.h direntry.h fmt.h strerr.h errtxt.h idx.h sgetopt.h subgetopt.h
+       ./compile ezmlm-clean.c
+
+ezmlm-cron: \
+load ezmlm-cron.o strerr.a stralloc.a alloc.a error.a open.a auto_qmail.o \
+getopt.a getln.a str.a substdio.a sig.a fs.a open.a fd.a lock.a wait.a \
+case.a auto_cron.o
+       ./load ezmlm-cron getopt.a getln.a strerr.a substdio.a \
+       stralloc.a alloc.a sig.a fs.a open.a fd.a lock.a error.a \
+       wait.a case.a str.a auto_qmail.o auto_cron.o
+
+ezmlm-cron.0: \
+ezmlm-cron.1
+       nroff -man ezmlm-cron.1 > ezmlm-cron.0
+
+ezmlm-cron.o: \
+compile ezmlm-cron.c strerr.h substdio.h stralloc.h error.h str.h \
+fork.h readwrite.h wait.h errtxt.h idx.h sgetopt.h auto_qmail.h \
+fmt.h auto_cron.h
+       ./compile ezmlm-cron.c
+
+ezmlm-gate: \
+load ezmlm-gate.o subdb.a auto_bin.o getopt.a getln.a env.a sig.a strerr.a \
+stralloc.a alloc.a error.a str.a case.a wait.a substdio.a open.a lock.a \
+fs.a getconf.o slurpclose.o slurp.o seek.a conf-sqlld
+       ./load ezmlm-gate subdb.a getconf.o slurpclose.o slurp.o \
+       getopt.a getln.a auto_bin.o env.a sig.a fs.a \
+       strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a wait.a \
+       open.a lock.a seek.a ${SQLLD}
+
+ezmlm-gate.0: \
+ezmlm-gate.1
+       nroff -man ezmlm-gate.1 > ezmlm-gate.0
+
+ezmlm-gate.o: \
+compile ezmlm-gate.c idx.h errtxt.h subscribe.h auto_bin.h \
+sgetopt.h subgetopt.h substdio.h getconf.h \
+env.h sig.h strerr.h stralloc.h alloc.h error.h str.h case.h \
+fork.h wait.h exit.h getln.h open.h
+       ./compile ezmlm-gate.c
+
+ezmlm-get: \
+load ezmlm-get.o idxthread.o subdb.a auto_qmail.o getopt.a now.o getconf.o \
+datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o makehash.o \
+cookie.o surf.a yyyymm.a \
+constmap.o getln.a env.a sig.a strerr.a substdio.a mime.a stralloc.a alloc.a \
+error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a copy.o conf-sqlld
+       ./load ezmlm-get idxthread.o subdb.a auto_qmail.o getopt.a getconf.o \
+       now.o datetime.o date822fmt.o cookie.o makehash.o slurpclose.o slurp.o \
+       yyyymm.a \
+       constmap.o substdio.a copy.o mime.a strerr.a stralloc.a alloc.a \
+       qmail.o quote.o surf.a getln.a env.a sig.a \
+       error.a str.a fs.a case.a \
+       open.a seek.a wait.a lock.a fd.a ${SQLLD}
+
+ezmlm-get.o: \
+compile ezmlm-get.c idx.h errtxt.h error.h getconf.h stralloc.h gen_alloc.h \
+str.h cookie.h env.h sig.h slurp.h strerr.h byte.h getln.h case.h qmail.h \
+substdio.h readwrite.h seek.h quote.h sgetopt.h subgetopt.h datetime.h now.h \
+date822fmt.h fmt.h strerr.h copy.h errtxt.h idx.h idxthread.h mime.h \
+constmap.h makehash.h
+       ./compile ezmlm-get.c
+
+ezmlm-get.0: \
+ezmlm-get.1
+       nroff -man ezmlm-get.1 > ezmlm-get.0
+
+ezmlm-greturn: \
+load ezmlm-greturn.o quote.o getconf.o subdb.a log.o \
+slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \
+strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \
+case.a open.a conf-sqlld
+       ./load ezmlm-greturn quote.o getconf.o subdb.a \
+       log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \
+       env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \
+       error.a str.a fs.a case.a open.a ${SQLLD}
+
+ezmlm-greturn.0: \
+ezmlm-greturn.1
+       nroff -man ezmlm-greturn.1 > ezmlm-greturn.0
+
+ezmlm-greturn.o: \
+compile ezmlm-greturn.c stralloc.h gen_alloc.h stralloc.h str.h env.h sig.h \
+slurp.h getconf.h strerr.h byte.h case.h getln.h substdio.h error.h \
+quote.h readwrite.h fmt.h datetime.h now.h cookie.h \
+strerr.h subscribe.h
+       ./compile ezmlm-greturn.c
+
+ezmlm-gwarn: \
+load ezmlm-gwarn.o auto_qmail.o getconf.o mime.a cookie.o subdb.a now.o \
+slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \
+case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \
+open.a lock.a str.a fs.a fd.a wait.a copy.o getopt.a conf-sqlld
+       ./load ezmlm-gwarn auto_qmail.o getconf.o mime.a \
+       cookie.o subdb.a getopt.a \
+       now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \
+       qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \
+       stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \
+       wait.a copy.o ${SQLLD}
+
+ezmlm-gwarn.0: \
+ezmlm-gwarn.1
+       nroff -man ezmlm-gwarn.1 > ezmlm-gwarn.0
+
+ezmlm-gwarn.o: \
+compile ezmlm-gwarn.c direntry.h readwrite.h getln.h \
+substdio.h stralloc.h gen_alloc.h slurp.h getconf.h byte.h error.h str.h \
+sig.h now.h datetime.h  date822fmt.h fmt.h cookie.h qmail.h substdio.h \
+qmail.h copy.h mime.h idx.h errtxt.h sgetopt.h subgetopt.h
+       ./compile ezmlm-gwarn.c
+
+ezmlm-idx: \
+load ezmlm-idx.o slurp.o slurpclose.o mime.a wait.a getopt.a \
+getln.a strerr.a sig.h sig.a open.a lock.a substdio.a stralloc.a \
+alloc.a error.a str.a fd.a case.a fs.a getconf.o makehash.o surf.o mime.a
+       ./load ezmlm-idx \
+       mime.a slurp.o slurpclose.o wait.a getln.a strerr.a sig.a open.a \
+       lock.a mime.a substdio.a stralloc.a alloc.a error.a str.a fd.a \
+       getopt.a case.a fs.a getconf.o makehash.o surf.o
+
+ezmlm-idx.o: \
+compile ezmlm-idx.c stralloc.h getconf.h \
+substdio.h subfd.h strerr.h error.h sgetopt.h \
+lock.h sig.h slurp.h open.h getln.h case.h \
+str.h fmt.h readwrite.h exit.h idx.h mime.h errtxt.h uint32.h
+       ./compile ezmlm-idx.c
+
+ezmlm-idx.0: \
+ezmlm-idx.1
+       nroff -man ezmlm-idx.1 > ezmlm-idx.0
+
+ezmlm-glconf: \
+ezmlm-glconf.sh warn-auto.sh conf-bin
+       (cat warn-auto.sh; \
+       echo EZPATH=\'`head -1 conf-bin`\'; \
+       cat ezmlm-glconf.sh ) > ezmlm-glconf
+
+ezmlm-glconf.0: \
+ezmlm-glconf.1
+       nroff -man ezmlm-glconf.1 > ezmlm-glconf.0
+
+ezmlm-issubn: \
+load ezmlm-issubn.o subdb.a getconf.o slurpclose.o slurp.o \
+env.a fs.a strerr.a getln.a getopt.a conf-sqlld \
+substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
+       ./load ezmlm-issubn subdb.a getconf.o slurpclose.o slurp.o \
+       getopt.a env.a fs.a strerr.a \
+       getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
+       open.a lock.a ${SQLLD}
+
+ezmlm-issubn.0: \
+ezmlm-issubn.1
+       nroff -man ezmlm-issubn.1 > ezmlm-issubn.0
+
+ezmlm-issubn.o: \
+compile ezmlm-issubn.c strerr.h subscribe.h env.h errtxt.h sgetopt.h idx.h
+       ./compile ezmlm-issubn.c
+
+ezmlm-limit: \
+load ezmlm-limit.o getconf.o slurpclose.o slurp.o substdio.a stralloc.a \
+alloc.a error.a str.a case.a open.a lock.a getopt.a fs.a sig.a now.o
+       ./load ezmlm-limit getconf.o slurpclose.o slurp.o getopt.a \
+       strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a \
+       open.a lock.a fs.a sig.a now.o
+
+ezmlm-limit.0: \
+ezmlm-limit.1
+       nroff -man ezmlm-limit.1 > ezmlm-limit.0
+
+ezmlm-limit.o: \
+compile ezmlm-limit.c stralloc.h strerr.h substdio.h readwrite.h sig.h lock.h \
+getconf.h fmt.h now.h sgetopt.h error.h errtxt.h idx.h datetime.h
+       ./compile ezmlm-limit.c
+
 ezmlm-list: \
 ezmlm-list: \
-load ezmlm-list.o strerr.a getln.a substdio.a stralloc.a alloc.a \
-error.a open.a str.a
-       ./load ezmlm-list strerr.a getln.a substdio.a stralloc.a \
-       alloc.a error.a open.a str.a 
+load ezmlm-list.o subdb.a fs.a getconf.o slurpclose.o slurp.o \
+strerr.a getln.a substdio.a stralloc.a alloc.a \
+error.a open.a str.a case.a getopt.a conf-sqlld
+       ./load ezmlm-list subdb.a fs.a getconf.o slurpclose.o slurp.o \
+       strerr.a getln.a getopt.a substdio.a stralloc.a \
+       alloc.a error.a open.a str.a case.a ${SQLLD}
 
 ezmlm-list.0: \
 ezmlm-list.1
        nroff -man ezmlm-list.1 > ezmlm-list.0
 
 ezmlm-list.o: \
 
 ezmlm-list.0: \
 ezmlm-list.1
        nroff -man ezmlm-list.1 > ezmlm-list.0
 
 ezmlm-list.o: \
-compile ezmlm-list.c stralloc.h gen_alloc.h stralloc.h ezmlm-list.c \
-substdio.h ezmlm-list.c getln.h ezmlm-list.c strerr.h ezmlm-list.c \
-error.h ezmlm-list.c readwrite.h ezmlm-list.c exit.h ezmlm-list.c \
-open.h ezmlm-list.c
+compile ezmlm-list.c stralloc.h gen_alloc.h substdio.h getln.h strerr.h \
+error.h readwrite.h exit.h open.h errtxt.h subscribe.h exit.h sgetopt.h \
+idx.h fmt.h
        ./compile ezmlm-list.c
 
 ezmlm-make: \
        ./compile ezmlm-list.c
 
 ezmlm-make: \
-load ezmlm-make.o auto_bin.o open.a getopt.a substdio.a strerr.a \
-stralloc.a alloc.a error.a str.a
-       ./load ezmlm-make auto_bin.o open.a getopt.a substdio.a \
-       strerr.a stralloc.a alloc.a error.a str.a 
+load ezmlm-make.o auto_bin.o open.a getln.a getopt.a substdio.a strerr.a \
+stralloc.a alloc.a error.a lock.a str.a
+       ./load ezmlm-make auto_bin.o open.a getln.a getopt.a substdio.a \
+       strerr.a stralloc.a alloc.a error.a lock.a str.a
 
 ezmlm-make.0: \
 ezmlm-make.1
 
 ezmlm-make.0: \
 ezmlm-make.1
@@ -202,19 +534,20 @@ sgetopt.h ezmlm-make.c stralloc.h gen_alloc.h stralloc.h ezmlm-make.c \
 strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \
 open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \
 auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \
 strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \
 open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \
 auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \
-ezmlm-make.c
+errtxt.h idx.h getln.h lock.h
        ./compile ezmlm-make.c
 
 ezmlm-manage: \
        ./compile ezmlm-make.c
 
 ezmlm-manage: \
-load ezmlm-manage.o auto_qmail.o getconf.o subscribe.o log.o cookie.o \
+load ezmlm-manage.o auto_qmail.o getconf.o subdb.a log.o cookie.o \
 now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
 surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
 now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
 surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
-error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a
-       ./load ezmlm-manage auto_qmail.o getconf.o subscribe.o \
-       log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
+error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a \
+mime.a copy.o conf-sqlld
+       ./load ezmlm-manage subdb.a auto_qmail.o getconf.o copy.o \
+       mime.a log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
        slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
        substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
        slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
        substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
-       open.a seek.a wait.a lock.a fd.a 
+       open.a seek.a wait.a lock.a fd.a getopt.a ${SQLLD}
 
 ezmlm-manage.0: \
 ezmlm-manage.1
 
 ezmlm-manage.0: \
 ezmlm-manage.1
@@ -231,35 +564,84 @@ ezmlm-manage.c readwrite.h ezmlm-manage.c seek.h ezmlm-manage.c \
 quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \
 datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \
 ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \
 quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \
 datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \
 ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \
-ezmlm-manage.c cookie.h ezmlm-manage.c
+sgetopt.h subgetopt.h cookie.h idx.h errtxt.h copy.h
        ./compile ezmlm-manage.c
 
        ./compile ezmlm-manage.c
 
+ezmlm-mktab.0: \
+ezmlm-mktab.1
+       nroff -man ezmlm-mktab.1 > ezmlm-mktab.0
+
+ezmlm-moderate: \
+load ezmlm-moderate.o auto_qmail.o getconf.o auto_bin.o copy.o mime.a \
+cookie.o now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
+surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
+error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a
+       ./load ezmlm-moderate auto_qmail.o getconf.o copy.o mime.a \
+       cookie.o now.o datetime.o date822fmt.o slurpclose.o \
+       slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
+       substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
+       auto_bin.o open.a seek.a wait.a lock.a fd.a getopt.a
+
+ezmlm-moderate.0: \
+ezmlm-moderate.1
+       nroff -man ezmlm-moderate.1 > ezmlm-moderate.0
+
+ezmlm-moderate.o: \
+compile ezmlm-moderate.c error.h stralloc.h gen_alloc.h str.h \
+env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h \
+qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h \
+date822fmt.h fmt.h strerr.h cookie.h errtxt.h idx.h copy.h mime.h \
+subgetopt.h sgetopt.h auto_bin.h fork.h wait.h
+       ./compile ezmlm-moderate.c
+
+ezmlm-request: \
+load ezmlm-request.o subdb.a getconf.o constmap.o getln.a auto_qmail.o qmail.o \
+strerr.a slurpclose.o slurp.o getopt.a env.a open.a fd.a sig.a case.a \
+substdio.a error.a stralloc.a alloc.a str.a case.a fs.a wait.a seek.a \
+date822fmt.o now.o datetime.o quote.o copy.o mime.a conf-sqlld
+       ./load ezmlm-request subdb.a getconf.o constmap.o getln.a auto_qmail.o \
+       qmail.o date822fmt.o datetime.o now.o quote.o \
+       slurpclose.o slurp.o env.a open.a sig.a wait.a getopt.a \
+       strerr.a substdio.a error.a copy.o stralloc.a alloc.a substdio.a \
+       str.a case.a fs.a fd.a sig.a wait.a seek.a mime.a ${SQLLD}
+
+ezmlm-request.0:
+       nroff -man ezmlm-request.1 > ezmlm-request.0
+
+ezmlm-request.o: \
+compile ezmlm-request.c stralloc.h subfd.h strerr.h error.h qmail.h env.h \
+sig.h open.h getln.h case.h str.h readwrite.h exit.h substdio.h quote.h \
+getconf.h constmap.h fmt.h byte.h errtxt.h idx.h datetime.h date822fmt.h \
+subscribe.h now.h copy.h
+       ./compile ezmlm-request.c
+
 ezmlm-reject: \
 ezmlm-reject: \
-load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a \
-alloc.a str.a getopt.a case.a
-       ./load ezmlm-reject getln.a strerr.a substdio.a error.a \
-       stralloc.a alloc.a str.a getopt.a case.a 
+load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a open.a \
+qmail.o env.a seek.a fd.a wait.a auto_qmail.o \
+alloc.a getconf.o slurp.o slurpclose.o str.a getopt.a case.a constmap.o fs.a
+       ./load ezmlm-reject qmail.o getln.a strerr.a substdio.a error.a fs.a \
+       env.a constmap.o getconf.o slurp.o slurpclose.o stralloc.a alloc.a \
+       seek.a str.a getopt.a case.a open.a fd.a wait.a auto_qmail.o
 
 ezmlm-reject.0: \
 ezmlm-reject.1
        nroff -man ezmlm-reject.1 > ezmlm-reject.0
 
 ezmlm-reject.o: \
 
 ezmlm-reject.0: \
 ezmlm-reject.1
        nroff -man ezmlm-reject.1 > ezmlm-reject.0
 
 ezmlm-reject.o: \
-compile ezmlm-reject.c strerr.h ezmlm-reject.c substdio.h \
-ezmlm-reject.c readwrite.h ezmlm-reject.c stralloc.h gen_alloc.h \
-stralloc.h ezmlm-reject.c getln.h ezmlm-reject.c sgetopt.h \
-subgetopt.h sgetopt.h ezmlm-reject.c
+compile ezmlm-reject.c strerr.h substdio.h readwrite.h stralloc.h gen_alloc.h \
+stralloc.h getln.h sgetopt.h subgetopt.h constmap.h getconf.h errtxt.h \
+scan.h fmt.h idx.h qmail.h env.h seek.h
        ./compile ezmlm-reject.c
 
 ezmlm-return: \
        ./compile ezmlm-reject.c
 
 ezmlm-return: \
-load ezmlm-return.o quote.o getconf.o issub.o subscribe.o log.o \
+load ezmlm-return.o quote.o getconf.o subdb.a log.o \
 slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \
 strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \
 slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \
 strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \
-case.a open.a
-       ./load ezmlm-return quote.o getconf.o issub.o subscribe.o \
+case.a open.a conf-sqlld
+       ./load ezmlm-return quote.o getconf.o subdb.a \
        log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \
        env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \
        log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \
        env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \
-       error.a str.a fs.a case.a open.a 
+       error.a str.a fs.a case.a open.a ${SQLLD}
 
 ezmlm-return.0: \
 ezmlm-return.1
 
 ezmlm-return.0: \
 ezmlm-return.1
@@ -270,43 +652,134 @@ compile ezmlm-return.c stralloc.h gen_alloc.h stralloc.h \
 ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \
 ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \
 strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \
 ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \
 ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \
 strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \
-getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h \
+getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h direntry.h \
 ezmlm-return.c quote.h ezmlm-return.c readwrite.h ezmlm-return.c \
 fmt.h ezmlm-return.c now.h datetime.h now.h ezmlm-return.c cookie.h \
 ezmlm-return.c subscribe.h strerr.h strerr.h subscribe.h \
 ezmlm-return.c quote.h ezmlm-return.c readwrite.h ezmlm-return.c \
 fmt.h ezmlm-return.c now.h datetime.h now.h ezmlm-return.c cookie.h \
 ezmlm-return.c subscribe.h strerr.h strerr.h subscribe.h \
-ezmlm-return.c issub.h strerr.h strerr.h issub.h ezmlm-return.c
+strerr.h strerr.h
        ./compile ezmlm-return.c
 
 ezmlm-send: \
 load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
        ./compile ezmlm-return.c
 
 ezmlm-send: \
 load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
-slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a \
-substdio.a stralloc.a alloc.a error.a str.a fd.a case.a fs.a
-       ./load ezmlm-send auto_qmail.o getconf.o qmail.o \
-       constmap.o slurp.o slurpclose.o wait.a getln.a strerr.a \
-       sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a \
-       error.a str.a fd.a case.a fs.a 
+slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
+substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a \
+getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
+       ./load ezmlm-send subdb.a cookie.o surf.a auto_qmail.o getconf.o \
+       getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
+       wait.a getln.a strerr.a \
+       sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
+       fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
 
 ezmlm-send.0: \
 ezmlm-send.1
        nroff -man ezmlm-send.1 > ezmlm-send.0
 
 ezmlm-send.o: \
 
 ezmlm-send.0: \
 ezmlm-send.1
        nroff -man ezmlm-send.1 > ezmlm-send.0
 
 ezmlm-send.o: \
-compile ezmlm-send.c stralloc.h gen_alloc.h stralloc.h ezmlm-send.c \
-subfd.h substdio.h subfd.h ezmlm-send.c strerr.h ezmlm-send.c error.h \
-ezmlm-send.c qmail.h substdio.h substdio.h qmail.h ezmlm-send.c env.h \
-ezmlm-send.c lock.h ezmlm-send.c sig.h ezmlm-send.c open.h \
-ezmlm-send.c getln.h ezmlm-send.c case.h ezmlm-send.c scan.h \
-ezmlm-send.c str.h ezmlm-send.c fmt.h ezmlm-send.c readwrite.h \
-ezmlm-send.c exit.h ezmlm-send.c substdio.h substdio.h ezmlm-send.c \
-getconf.h ezmlm-send.c constmap.h ezmlm-send.c
+compile ezmlm-send.c stralloc.h gen_alloc.h copy.h \
+subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
+lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
+exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
+uint32.h
        ./compile ezmlm-send.c
 
        ./compile ezmlm-send.c
 
+ezmlm-master: \
+load ezmlm-master.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
+slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
+substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a\
+getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
+       ./load ezmlm-master subdb.a cookie.o surf.a auto_qmail.o getconf.o \
+       getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
+       wait.a getln.a strerr.a \
+       sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
+       fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
+
+ezmlm-master.0: \
+ezmlm-master.1
+       nroff -man ezmlm-master.1 > ezmlm-master.0
+
+ezmlm-master.o: \
+compile ezmlm-master.c stralloc.h gen_alloc.h copy.h \
+subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
+lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
+exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
+uint32.h
+       ./compile ezmlm-master.c
+
+ezmlm-slave: \
+load ezmlm-slave.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
+slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
+substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a \
+getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
+       ./load ezmlm-slave subdb.a cookie.o surf.a auto_qmail.o getconf.o \
+       getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
+       wait.a getln.a strerr.a \
+       sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
+       fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
+
+ezmlm-slave.0: \
+ezmlm-slave.1
+       nroff -man ezmlm-slave.1 > ezmlm-slave.0
+
+ezmlm-slave.o: \
+compile ezmlm-slave.c stralloc.h gen_alloc.h copy.h \
+subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
+lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
+exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
+uint32.h
+       ./compile ezmlm-slave.c
+
+ezmlm-split: \
+load ezmlm-split.o auto_qmail.o getconf.o \
+slurpclose.o slurp.o qmail.o quote.o wait.a \
+getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
+error.a str.a fs.a case.a open.a fd.a
+       ./load ezmlm-split auto_qmail.o getconf.o slurpclose.o \
+       slurp.o qmail.o quote.o getln.a env.a sig.a strerr.a \
+       substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
+       open.a fd.a wait.a
+
+ezmlm-split.0: \
+ezmlm-split.1
+       nroff -man ezmlm-split.1 > ezmlm-split.0
+
+ezmlm-split.o: \
+compile ezmlm-split.c error.h stralloc.h gen_alloc.h str.h \
+env.h sig.h getconf.h strerr.h byte.h getln.h case.h \
+qmail.h substdio.h  readwrite.h quote.h \
+fmt.h errtxt.h idx.h uint32.h
+       ./compile ezmlm-split.c
+
+ezmlm-store: \
+load ezmlm-store.o auto_qmail.o getconf.o subdb.a log.o auto_bin.o mime.a \
+cookie.o now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
+surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a conf-sqlld \
+error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a copy.o
+       ./load ezmlm-store auto_qmail.o getconf.o subdb.a copy.o mime.a \
+       log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
+       slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
+       substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
+       open.a seek.a wait.a lock.a fd.a getopt.a auto_bin.o ${SQLLD}
+
+ezmlm-store.0: \
+ezmlm-store.1
+       nroff -man ezmlm-store.1 > ezmlm-store.0
+
+ezmlm-store.o: \
+compile ezmlm-store.c error.h stralloc.h gen_alloc.h str.h \
+sgetopt.h subgetopt.h fork.h wait.h auto_bin.h lock.h mime.h \
+env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h \
+qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h \
+date822fmt.h fmt.h subscribe.h strerr.h cookie.h errtxt.h idx.h copy.h
+       ./compile ezmlm-store.c
+
 ezmlm-sub: \
 ezmlm-sub: \
-load ezmlm-sub.o subscribe.o log.o now.o fs.a strerr.a getln.a \
+load ezmlm-sub.o subdb.a getconf.o slurpclose.o slurp.o \
+log.o now.o fs.a strerr.a getln.a getopt.a fs.a conf-sqlld \
 substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
 substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
-       ./load ezmlm-sub subscribe.o log.o now.o fs.a strerr.a \
+       ./load ezmlm-sub subdb.a getconf.o slurpclose.o slurp.o \
+       log.o now.o fs.a strerr.a getopt.a fs.a \
        getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
        getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
-       open.a lock.a 
+       open.a lock.a ${SQLLD}
 
 ezmlm-sub.0: \
 ezmlm-sub.1
 
 ezmlm-sub.0: \
 ezmlm-sub.1
@@ -314,57 +787,86 @@ ezmlm-sub.1
 
 ezmlm-sub.o: \
 compile ezmlm-sub.c strerr.h ezmlm-sub.c subscribe.h strerr.h \
 
 ezmlm-sub.o: \
 compile ezmlm-sub.c strerr.h ezmlm-sub.c subscribe.h strerr.h \
-strerr.h subscribe.h ezmlm-sub.c log.h ezmlm-sub.c
+getln.h substdio.h stralloc.h readwrite.h \
+strerr.h subscribe.h log.h errtxt.h sgetopt.h scan.h idx.h
        ./compile ezmlm-sub.c
 
        ./compile ezmlm-sub.c
 
+ezmlm-test: \
+ezmlm-test.sh warn-auto.sh conf-bin
+       (cat warn-auto.sh; \
+       echo QMPATH=\'`head -1 conf-qmail`\'; \
+       cat ezmlm-test.sh ) > ezmlm-test; \
+       chmod 755 ezmlm-test
+
+ezmlm-test.0: \
+ezmlm-test.1
+       nroff -man ezmlm-test.1 > ezmlm-test.0
+
+ezmlm-tstdig: \
+load ezmlm-tstdig.o getopt.a getconf.o now.o fs.a strerr.a getln.a \
+lock.a \
+substdio.a stralloc.a alloc.a error.a str.a case.a sig.a \
+open.a slurpclose.o slurp.o env.a
+       ./load ezmlm-tstdig getopt.a getconf.o env.a now.o fs.a strerr.a \
+       lock.a getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
+       sig.a slurpclose.o slurp.o open.a 
+
+ezmlm-tstdig.0: \
+ezmlm-tstdig.1
+       nroff -man ezmlm-tstdig.1 > ezmlm-tstdig.0
+
+ezmlm-tstdig.o: \
+compile ezmlm-tstdig.c strerr.h sgetopt.h getconf.h \
+sig.h now.h errtxt.h stralloc.h sig.h env.h fmt.h substdio.h readwrite.h \
+now.h idx.h
+       ./compile ezmlm-tstdig.c
+
 ezmlm-unsub: \
 ezmlm-unsub: \
-load ezmlm-unsub.o subscribe.o log.o now.o fs.a strerr.a getln.a \
+load ezmlm-unsub.o subdb.a getconf.o slurpclose.o slurp.o \
+log.o now.o fs.a strerr.a getln.a getopt.a fs.a conf-sqlld \
 substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
 substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
-       ./load ezmlm-unsub subscribe.o log.o now.o fs.a strerr.a \
+       ./load ezmlm-unsub subdb.a getopt.a getconf.o slurpclose.o slurp.o \
+       log.o now.o fs.a strerr.a fs.a \
        getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
        getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
-       open.a lock.a 
+       open.a lock.a ${SQLLD}
 
 ezmlm-unsub.0: \
 ezmlm-unsub.1
        nroff -man ezmlm-unsub.1 > ezmlm-unsub.0
 
 ezmlm-unsub.o: \
 
 ezmlm-unsub.0: \
 ezmlm-unsub.1
        nroff -man ezmlm-unsub.1 > ezmlm-unsub.0
 
 ezmlm-unsub.o: \
-compile ezmlm-unsub.c strerr.h ezmlm-unsub.c subscribe.h strerr.h \
-strerr.h subscribe.h ezmlm-unsub.c log.h ezmlm-unsub.c
+compile ezmlm-unsub.c strerr.h subscribe.h \
+log.h errtxt.h sgetopt.h scan.h idx.h readwrite.h stralloc.h substdio.h 
        ./compile ezmlm-unsub.c
 
 ezmlm-warn: \
        ./compile ezmlm-unsub.c
 
 ezmlm-warn: \
-load ezmlm-warn.o auto_qmail.o getconf.o cookie.o issub.o now.o \
+load ezmlm-warn.o auto_qmail.o getconf.o mime.a cookie.o subdb.a now.o \
 slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \
 case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \
 slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \
 case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \
-open.a lock.a str.a fs.a fd.a wait.a
-       ./load ezmlm-warn auto_qmail.o getconf.o cookie.o issub.o \
+open.a lock.a str.a fs.a fd.a wait.a copy.o getopt.a conf-sqlld
+       ./load ezmlm-warn auto_qmail.o getconf.o mime.a \
+       cookie.o subdb.a getopt.a \
        now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \
        qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \
        stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \
        now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \
        qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \
        stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \
-       wait.a 
+       wait.a copy.o ${SQLLD}
 
 ezmlm-warn.0: \
 ezmlm-warn.1
        nroff -man ezmlm-warn.1 > ezmlm-warn.0
 
 ezmlm-warn.o: \
 
 ezmlm-warn.0: \
 ezmlm-warn.1
        nroff -man ezmlm-warn.1 > ezmlm-warn.0
 
 ezmlm-warn.o: \
-compile ezmlm-warn.c ezmlm-warn.c ezmlm-warn.c direntry.h direntry.h \
-direntry.h ezmlm-warn.c readwrite.h ezmlm-warn.c getln.h ezmlm-warn.c \
-substdio.h ezmlm-warn.c stralloc.h gen_alloc.h stralloc.h \
-ezmlm-warn.c slurp.h ezmlm-warn.c getconf.h ezmlm-warn.c byte.h \
-ezmlm-warn.c error.h ezmlm-warn.c str.h ezmlm-warn.c strerr.h \
-ezmlm-warn.c sig.h ezmlm-warn.c now.h datetime.h now.h ezmlm-warn.c \
-datetime.h datetime.h ezmlm-warn.c date822fmt.h ezmlm-warn.c fmt.h \
-ezmlm-warn.c cookie.h ezmlm-warn.c qmail.h substdio.h substdio.h \
-qmail.h ezmlm-warn.c
+compile ezmlm-warn.c direntry.h readwrite.h getln.h \
+substdio.h stralloc.h gen_alloc.h slurp.h getconf.h byte.h error.h str.h \
+sig.h now.h datetime.h  date822fmt.h fmt.h cookie.h qmail.h substdio.h \
+qmail.h copy.h mime.h idx.h errtxt.h sgetopt.h subgetopt.h
        ./compile ezmlm-warn.c
 
 ezmlm-weed: \
        ./compile ezmlm-warn.c
 
 ezmlm-weed: \
-load ezmlm-weed.o getln.a strerr.a substdio.a error.a stralloc.a \
+load ezmlm-weed.o getln.a strerr.a substdio.a error.a case.a stralloc.a \
 alloc.a str.a
        ./load ezmlm-weed getln.a strerr.a substdio.a error.a \
 alloc.a str.a
        ./load ezmlm-weed getln.a strerr.a substdio.a error.a \
-       stralloc.a alloc.a str.a 
+       case.a stralloc.a alloc.a str.a 
 
 ezmlm-weed.0: \
 ezmlm-weed.1
 
 ezmlm-weed.0: \
 ezmlm-weed.1
@@ -380,6 +882,18 @@ ezmlm.0: \
 ezmlm.5
        nroff -man ezmlm.5 > ezmlm.0
 
 ezmlm.5
        nroff -man ezmlm.5 > ezmlm.0
 
+ezmlmglrc.0: \
+ezmlmglrc.5
+       nroff -man ezmlmglrc.5 > ezmlmglrc.0
+
+ezmlmrc.0: \
+ezmlmrc.5
+       nroff -man ezmlmrc.5 > ezmlmrc.0
+
+ezmlmsubrc.0: \
+ezmlmsubrc.5
+       nroff -man ezmlmsubrc.5 > ezmlmsubrc.0
+
 fd.a: \
 makelib fd_copy.o fd_move.o
        ./makelib fd.a fd_copy.o fd_move.o
 fd.a: \
 makelib fd_copy.o fd_move.o
        ./makelib fd.a fd_copy.o fd_move.o
@@ -496,16 +1010,23 @@ install.c open.h install.c error.h install.c strerr.h install.c \
 byte.h install.c
        ./compile install.c
 
 byte.h install.c
        ./compile install.c
 
+idxthread.o: \
+compile idxthread.c idxthread.h alloc.h error.h stralloc.h str.h lock.h idx.h \
+substdio.h fmt.h readwrite.h idx.h errtxt.h substdio.h byte.h yyyymm.h
+       ./compile idxthread.c
+
 issub.o: \
 issub.o: \
-compile issub.c stralloc.h gen_alloc.h stralloc.h issub.c getln.h \
-issub.c readwrite.h issub.c substdio.h issub.c open.h issub.c byte.h \
-issub.c case.h issub.c lock.h issub.c error.h issub.c issub.h \
-strerr.h issub.h issub.c uint32.h issub.c
-       ./compile issub.c
+compile issub.c stralloc.h gen_alloc.h getln.h readwrite.h substdio.h \
+open.h byte.h case.h lock.h error.h subscribe.h strerr.h uint32.h fmt.h \
+conf-sqlcc
+       ./compile issub.c ${SQLCC}
 
 it: \
 
 it: \
+ezmlm-idx ezmlm-accept ezmlm-archive ezmlm-check ezmlm-gate ezmlm-get \
+ezmlm-clean ezmlm-glconf ezmlm-moderate ezmlm-store ezmlm-tstdig \
 ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject ezmlm-return \
 ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject ezmlm-return \
-ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub
+ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub ezmlm-cgi ezmlm-limit \
+ezmlm-issubn ezmlm-cron ezmlm-request ezmlm-test ezmlm-split ezmlmrc
 
 load: \
 make-load warn-auto.sh systype
 
 load: \
 make-load warn-auto.sh systype
@@ -527,6 +1048,10 @@ gen_alloc.h stralloc.h log.c log.h log.c now.h datetime.h now.h log.c \
 fmt.h log.c open.h log.c
        ./compile log.c
 
 fmt.h log.c open.h log.c
        ./compile log.c
 
+logmsg.o: \
+compile logmsg.c stralloc.h fmt.h conf-sqlcc
+       ./compile logmsg.c ${SQLCC}
+
 make-compile: \
 make-compile.sh auto-ccld.sh
        cat auto-ccld.sh make-compile.sh > make-compile
 make-compile: \
 make-compile.sh auto-ccld.sh
        cat auto-ccld.sh make-compile.sh > make-compile
@@ -542,6 +1067,10 @@ make-makelib.sh auto-ccld.sh
        cat auto-ccld.sh make-makelib.sh > make-makelib
        chmod 755 make-makelib
 
        cat auto-ccld.sh make-makelib.sh > make-makelib
        chmod 755 make-makelib
 
+makehash.o: \
+makehash.c makehash.h surf.h uint32.h stralloc.h
+       ./compile makehash.c
+
 makelib: \
 make-makelib warn-auto.sh systype
        ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \
 makelib: \
 make-makelib warn-auto.sh systype
        ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \
@@ -549,12 +1078,23 @@ make-makelib warn-auto.sh systype
        chmod 755 makelib
 
 man: \
        chmod 755 makelib
 
 man: \
-ezmlm.0 ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \
+ezmlm.0 ezmlm-gate.0 ezmlm-idx.0 ezmlm-get.0 ezmlm-check.0 ezmlm-tstdig.0 \
+ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 ezmlm-accept.0 \
 ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 ezmlm-list.0 ezmlm-sub.0 \
 ezmlm-unsub.0 alloc.0 case.0 datetime.0 direntry.0 env.0 error.0 \
 error_str.0 error_temp.0 ezmlm.0 fd_copy.0 fd_move.0 getln.0 getln2.0 \
 ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 ezmlm-list.0 ezmlm-sub.0 \
 ezmlm-unsub.0 alloc.0 case.0 datetime.0 direntry.0 env.0 error.0 \
 error_str.0 error_temp.0 ezmlm.0 fd_copy.0 fd_move.0 getln.0 getln2.0 \
+ezmlm-issubn.0 ezmlm-cron.0 ezmlm-glconf.0 ezmlmglrc.0 ezmlm-test.0 \
+ezmlmsubrc.0 ezmlm-mktab.0 ezmlm-split.0 ezmlm-archive.0 ezmlm-cgi.0 \
 getopt.0 now.0 sgetopt.0 stralloc.0 subfd.0 subgetopt.0 substdio.0 \
 getopt.0 now.0 sgetopt.0 stralloc.0 subfd.0 subgetopt.0 substdio.0 \
-substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0
+substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0 \
+ezmlm-clean.0 ezmlm-moderate.0 ezmlm-store.0 ezmlm-request.0 ezmlmrc.0 \
+ezmlm-limit.0
+
+mime.a: \
+makelib concatHDR.o decodeHDR.o unfoldHDR.o \
+decodeQ.o encodeQ.o decodeB.o encodeB.o author.o
+       ./makelib mime.a concatHDR.o decodeHDR.o decodeQ.o encodeQ.o \
+       decodeB.o encodeB.o unfoldHDR.o author.o
 
 now.0: \
 now.3
 
 now.0: \
 now.3
@@ -582,6 +1122,16 @@ open_trunc.o: \
 compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c
        ./compile open_trunc.c
 
 compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c
        ./compile open_trunc.c
 
+opensql.o: \
+compile opensql.c error.h strerr.h errtxt.h \
+       str.h case.h stralloc.h subscribe.h conf-sqlcc
+       ./compile opensql.c ${SQLCC}
+
+putsubs.o: \
+compile putsubs.c error.h substdio.h strerr.h readwrite.h \
+str.h open.h case.h errtxt.h stralloc.h subscribe.h qmail.h fmt.h conf-sqlcc
+       ./compile putsubs.c ${SQLCC}
+
 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 \
 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 \
@@ -601,6 +1151,12 @@ scan_ulong.o: \
 compile scan_ulong.c scan.h scan_ulong.c
        ./compile scan_ulong.c
 
 compile scan_ulong.c scan.h scan_ulong.c
        ./compile scan_ulong.c
 
+searchlog.o: \
+compile searchlog.c case.h stralloc.h scan.h open.h datetime.h errtxt.h str.h \
+       datetime.h date822fmt.h substdio.h readwrite.h strerr.h error.h \
+       subscribe.h conf-sqlcc
+       ./compile searchlog.c ${SQLCC}
+
 seek.a: \
 makelib seek_set.o
        ./makelib seek.a seek_set.o
 seek.a: \
 makelib seek_set.o
        ./makelib seek.a seek_set.o
@@ -800,6 +1356,12 @@ strerr_sys.o: \
 compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c
        ./compile strerr_sys.c
 
 compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c
        ./compile strerr_sys.c
 
+subdb.a: \
+makelib checktag.o issub.o logmsg.o subscribe.o opensql.o putsubs.o \
+       tagmsg.o searchlog.o
+       ./makelib subdb.a checktag.o issub.o logmsg.o subscribe.o \
+       opensql.o putsubs.o tagmsg.o searchlog.o
+
 subfd.0: \
 subfd.3
        nroff -man subfd.3 > subfd.0
 subfd.0: \
 subfd.3
        nroff -man subfd.3 > subfd.0
@@ -818,12 +1380,10 @@ compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c
        ./compile subgetopt.c
 
 subscribe.o: \
        ./compile subgetopt.c
 
 subscribe.o: \
-compile subscribe.c stralloc.h gen_alloc.h stralloc.h subscribe.c \
-getln.h subscribe.c readwrite.h subscribe.c substdio.h subscribe.c \
-strerr.h subscribe.c open.h subscribe.c byte.h subscribe.c case.h \
-subscribe.c lock.h subscribe.c error.h subscribe.c uint32.h \
-subscribe.c subscribe.h strerr.h strerr.h subscribe.h subscribe.c
-       ./compile subscribe.c
+compile subscribe.c stralloc.h gen_alloc.h stralloc.h \
+getln.h readwrite.h substdio.h strerr.h open.h byte.h case.h \
+lock.h error.h uint32.h subscribe.h idx.h fmt.h conf-sqlcc
+       ./compile subscribe.c ${SQLCC}
 
 substdi.o: \
 compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \
 
 substdi.o: \
 compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \
@@ -889,6 +1449,10 @@ systype: \
 find-systype trycpp.c
        ./find-systype > systype
 
 find-systype trycpp.c
        ./find-systype > systype
 
+tagmsg.o: \
+compile tagmsg.c stralloc.h slurp.h scan.h fmt.h strerr.h cookie.h conf-sqlcc
+       ./compile tagmsg.c ${SQLCC}
+
 uint32.h: \
 tryulong32.c compile load uint32.h1 uint32.h2
        ( ( ./compile tryulong32.c && ./load tryulong32 && \
 uint32.h: \
 tryulong32.c compile load uint32.h1 uint32.h2
        ( ( ./compile tryulong32.c && ./load tryulong32 && \
@@ -907,3 +1471,124 @@ makelib wait_pid.o
 wait_pid.o: \
 compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c
        ./compile wait_pid.c
 wait_pid.o: \
 compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c
        ./compile wait_pid.c
+
+yyyymm.a: \
+makelib date2yyyymm.o dateline.o
+       ./makelib yyyymm.a date2yyyymm.o dateline.o
+
+ch: \
+ezmlmrc.ch
+       cp -f ezmlmrc.ch_GB ezmlmrc
+
+ch_GB: \
+ezmlmrc.ch_GB
+       cp -f ezmlmrc.ch_GB ezmlmrc
+
+cs: \
+ezmlmrc.cs
+       cp -f ezmlmrc.cs ezmlmrc
+
+da: \
+ezmlmrc.da
+       cp -f ezmlmrc.da ezmlmrc
+
+de: \
+ezmlmrc.de
+       cp -f ezmlmrc.de ezmlmrc
+
+en_US: \
+ezmlmrc.en_US
+       cp -f ezmlmrc.en_US ezmlmrc
+
+en: \
+ezmlmrc.en_US
+       cp -f ezmlmrc.en_US ezmlmrc
+
+es: \
+ezmlmrc.es
+       cp -f ezmlmrc.es ezmlmrc
+
+us: \
+ezmlmrc.en_US
+       cp -f ezmlmrc.en_US ezmlmrc
+
+ezmlmrc: \
+ezmlmrc.en_US
+       cp -f ezmlmrc.en_US ezmlmrc
+
+fr: \
+ezmlmrc.fr
+       cp -f ezmlmrc.fr ezmlmrc
+
+id: \
+ezmlmrc.id
+       cp -f ezmlmrc.id ezmlmrc
+
+ita: \
+ezmlmrc.it
+       cp -f ezmlmrc.it ezmlmrc
+
+jp: \
+ezmlmrc.jp
+       cp -f ezmlmrc.jp ezmlmrc
+
+pl: \
+ezmlmrc.pl
+       cp -f ezmlmrc.pl ezmlmrc
+
+pt: \
+ezmlmrc.pt
+       cp -f ezmlmrc.pt ezmlmrc
+
+pt_BR: \
+ezmlmrc.pt_BR
+       cp -f ezmlmrc.pt_BR ezmlmrc
+
+ru: \
+ezmlmrc.ru
+       cp -f ezmlmrc.ru ezmlmrc
+
+sv: \
+ezmlmrc.sv
+       cp -f ezmlmrc.sv ezmlmrc
+
+mysql:
+       ln -sf sub_mysql/ezmlm-mktab ezmlm-mktab
+       ln -sf sub_mysql/checktag.c checktag.c; rm -f checktag.o
+       ln -sf sub_mysql/issub.c issub.c; rm -f issub.o
+       ln -sf sub_mysql/logmsg.c logmsg.c; rm -f logmsg.o
+       ln -sf sub_mysql/subscribe.c subscribe.c; rm -f subscribe.o
+       ln -sf sub_mysql/opensql.c opensql.c; rm -f opensql.o
+       ln -sf sub_mysql/putsubs.c putsubs.c; rm -f putsubs.o
+       ln -sf sub_mysql/tagmsg.c tagmsg.c; rm -f tagmsg.o
+       ln -sf sub_mysql/searchlog.c searchlog.c; rm -f searchlog.o
+       ln -sf sub_mysql/conf-sqlld conf-sqlld; touch conf-sqlld
+       ln -sf sub_mysql/conf-sqlcc conf-sqlcc; touch conf-sqlcc
+
+pgsql:
+       ln -sf sub_pgsql/ezmlm-mktab ezmlm-mktab
+       ln -sf sub_pgsql/checktag.c checktag.c; rm -f checktag.o
+       ln -sf sub_pgsql/issub.c issub.c; rm -f issub.o
+       ln -sf sub_pgsql/logmsg.c logmsg.c; rm -f logmsg.o
+       ln -sf sub_pgsql/subscribe.c subscribe.c; rm -f subscribe.o
+       ln -sf sub_pgsql/opensql.c opensql.c; rm -f opensql.o
+       ln -sf sub_pgsql/putsubs.c putsubs.c; rm -f putsubs.o
+       ln -sf sub_pgsql/tagmsg.c tagmsg.c; rm -f tagmsg.o
+       ln -sf sub_pgsql/searchlog.c searchlog.c; rm -f searchlog.o
+       ln -sf sub_pgsql/conf-sqlld conf-sqlld; touch conf-sqlld
+       ln -sf sub_pgsql/conf-sqlcc conf-sqlcc; touch conf-sqlcc
+
+std:
+       ln -sf sub_std/ezmlm-mktab ezmlm-mktab
+       ln -sf sub_std/checktag.c checktag.c; rm -f checktag.o
+       ln -sf sub_std/issub.c issub.c; rm -f issub.o
+       ln -sf sub_std/logmsg.c logmsg.c; rm -f logmsg.o
+       ln -sf sub_std/subscribe.c subscribe.c; rm -f subscribe.o
+       ln -sf sub_std/opensql.c opensql.c; rm -f opensql.o
+       ln -sf sub_std/putsubs.c putsubs.c; rm -f putsubs.o
+       ln -sf sub_std/tagmsg.c tagmsg.c; rm -f tagmsg.o
+       ln -sf sub_std/searchlog.c searchlog.c; rm -f searchlog.o
+       ln -sf sub_std/conf-sqlld conf-sqlld; touch conf-sqlld
+       ln -sf sub_std/conf-sqlcc conf-sqlcc; touch conf-sqlcc
+
+
diff --git a/README.idx b/README.idx
new file mode 100644 (file)
index 0000000..7ffd895
--- /dev/null
@@ -0,0 +1,337 @@
+$Id: README.idx,v 1.70 1999/12/24 04:20:45 lindberg Exp $
+$Name: ezmlm-idx-040 $
+
+(c) 1997, 1998, 1999 Fred Lindberg, lindberg@id.wustl.edu (code+docs+faq)
+                     Fred B. Ringel, fredr@rivertown.net (faq)
+
+This software is distributed under the GNU General Public Licence as
+published by the Free Software Foundation.  See the file LICENCE.TXT for
+the conditions under which this software is made available.
+
+Like any other piece of software (and information generally), ezmlm-idx
+comes with NO WARRANTY.
+
+This is an addition and patch to ezmlm-0.53 [(c) Dan J. Bernstein].
+Ezmlm-idx uses Dan's libraries and heavily relies on ezmlm-0.53 code.
+ezmlm-idx does not function without ezmlm-0.53.
+
+ezmlm-0.53 provides basic message distribution, subscriber address handling,
+message archiving (single quoted message retrieval only), and bounce
+handling. ezmlm-idx adds multi-message threaded archive retrieval, digests,
+remote administration, message and subscription moderation, subscriber-only
+restrictions, message trailer, subject prefix, subscriber name storage,
+customizable setup, multi-language and MIME support and more. In addition,
+improved bounce handling, case-insensitive subscriber address storage,
+and support for distributed lists (main + sublist transparent to the
+subscriber). Ezmlm-idx can now be compiled with MySQL or Postgres support.
+
+See INSTALL.idx for installation instructions.
+See UPGRADE.idx to upgrade from a previous version of ezmlm-idx.
+See CHANGES.idx to see what's new in this version.
+See FILES.idx for a list of files in this package.
+See FAQ.idx for more info on ezmlm(-idx) functions and setup (see below on
+           how to get the latest version).
+See ezman-0.xx* for a user's/administrator's manual to ezmlm/idx. Available
+           on line at http://www.ezmlm.org/ and for download at
+           ftp://ftp.ezmlm.org/pub/patches/ezman/ and mirrors.
+
+NOTE: Some ezmlmrc translations may not be up-to-date. ezmlm-make will
+complain and the results may not match the documentation. Changes required
+are small. If you correct a translation, please submit it for inclusion
+in the next ezmlm-idx version.
+
+*.rpm will put ezmlm-cgi in the bin directory. To use it, you must manually
+move it to a cgi-bin directory, set ownership and SUID (if needed), and
+set up /ezmlm/ezcgirc.
+
+See http://pobox.com/~djb/ezmlm.html for the latest information about
+ezmlm.
+
+See ftp://ftp.id.wustl.edu/pub/patches for the latest version of ezmlm-idx and
+downloadable versions of the FAQ.
+
+See http://www.ezmlm.org/ for ezmlm FAQ and docs on line.
+
+Mail ``ezmlm-subscribe@list.cr.yp.to'' to join the ezmlm mailing
+list (averages 3 messages per day). This list is run by Dan J. Bernstein
+using ezmlm-0.53.
+
+Send general comments and questions to:
+lindberg@id.wustl.edu or fredr@rivertown.net.
+
+Send bug reports and patches to:
+lindberg@id.wustl.edu.
+
+Below, acknowledgements and a list of systems where ezmlm-idx has been reported
+to work.
+
+ACKNOWLEDGEMENTS
+- Fred B. Ringel, first and foremost, for a great collaboration, ideas, testing,
+  docs clarification. This makes it so much more fun.
+- Dan J. Bernstein for qmail, ezmlm, and great libraries.
+- Toshinori Maeno (TM; tmaeno@hpcl.titech.ac.jp) for finding an ezmlm-idx-0.20
+  bug, and MIME suggestions, suggestions about hopcount and received headers,
+  return-path header in archive, sublist loop detection, ezmlm-limit suggestion,
+  many other suggestions and explanations, help to get ezmlm-cgi Japanese
+  support to work, as well as pre-release testing.
+- Frank Tegtmeyer for inciting digests and format info/suggestions, and for
+  ezmlmrc.de.
+- Magnus Stålåker (MAS; stalaker@umc.se) for the PostgresSQL interface.
+- Mark Delany for the original ezmlm-issub and for suggesting reordering
+  unlink() and doit() in ezmlm-warn.
+- Raul Miller and Chris Garrigues for format info/suggestions.
+- Thomas Erskine (TEE; tom@crc.doc.ca) for fix to clean sunos-4.1.3 compiles
+  and pre-release compilation on many platforms, fixes for bash-isms in
+  ezmlm-check, and testing.
+- Shuhei Kobayashi (SK; shuhei-k@jaist.ac.jp) for MIME corrections/suggestions,
+  X-sequence suggestions, ezmlm-check/make corrections, and pre-release testing.
+- Yusuf Goolamabbas (YG; yusufg@krdl.org.sg) and the Mutt developers for
+  pointing out outdated MIME, ezmlmrc improvements, outformat bug, suggestion
+  about ezmlm-moderate -r switch, and pre-release testing.
+- Brian Gentry (BG; gentry@usaccess-inc.com) for reporting the
+  ezmlm-moderate-0.12 exit code bug.
+- Anand R. Buddhev (ARB; arb@iconnect.co.ke) for fix to clean BSDI 2.1 compiles
+  and pre-release testing.
+- Masashi Fujita (MF; objectx@polyphony.scei.co.jp) for fix to clean SGI
+  compiles, lint advice, MIME suggestions, pre-release testing, a patch for
+  the ezmlm-make-0.21 -c bug, ezmlmrc.jp, and finding postmsg bug in 0.301.
+- Matthew D. Stock (MDS; stock@perdix.acsu.buffalo.edu) for pre-release testing.
+- Ximenes Zalteca for finding an ezmlm-send-0.21 bug.
+- Jukka Suomela (JS; jukka@narnia.tky.hut.fi) for inciting the ezmlm-send -cC
+  switch.
+- John White (johnjohn@triceratops.com) for questions leading to ezmlm-tstdig,
+  and for testing the example script.
+- Torben Fjerdingstad (TF; unitfj@tfj.uni-c.dk) for testing case-insensitive
+  issub.c and subscribe.c, for TARGETS, for suggesting a no-copy-to-SENDER
+  option, for ezmlmrc.da, for reporting missing MIME end for base64/QP
+  moderated [un]sub confirms, and for pre-release testing.
+- Shinya O'Hira (SOH; Shinya_Oohira@justsystem.co.jp) for reporting the
+  ezmlm-make-0.22 lock file name bug and for testing the fix. Also for many
+  helpful suggestions and hard work testing rfc2047 subject support.
+- Sadhu(sadhu@aloha.net) & Tracy Reed (TR; treed@ultraviolet.org) for reporting
+  the ezmlm-send-0.22 undefined SENDER bug, and testing the fix.
+- Scott Balantyne (SDB; sdb@ssr.com) for inciting the modifications for digest
+  out of dir/editor.
+- Frank Denis (j@industrie.capgemini.fr) for ezmlmrc.fr.
+- Marc Evans (marc@destek.net) for reporting the ezmlm-make-0.221 64-bit bug
+  and pre-release testing, and inciting, improving, and testing ezmlm-test.
+- Vince Vielhaber (VV; vev@michvhf.com) for reporting ezmlm-check problems with
+  non-bash and testing fixes.
+- Andrew Pam (AP; xanni@xanadu.net) for suggesting the ezmlm-idx -d switch and
+  reporting the ezmlm-gate failure on NULL $SENDER bug.
+- Glen Stewart (GS; glen_stewart@associate.com) for reminding me about command
+  case insensitivity and ezmlmrc typo fixes.
+- Kenji Ikeda (KI; noroi@nt.is.dnp.co.jp) for a patch to ezmlm-idx-0.23 to get
+  message numbers in subjects. I've added code to ezmlm-idx-0.30 implementing
+  this is a similar manner. Sen Nagata (sen_ml@eccosys.com) for suggesting this
+  earlier. Bugfix for missing MIME boundary in -index reply.
+- Sebastian Andersson (SA; sa@hogia.net) for ezmlmrc.sv, MIME suggestions,
+  ezmlm-weed patch, ezmlmrc version check suggestion and pre-release testing.
+- Giorgos Stathakopoulos (GS; stathako@cti.gr) for pre-release testing.
+- David Summers (DS; david@summersoft.fay.ar.us) for pre-release testing,
+  reporting a ezmlm-check bug and SPEC files for rpm:s.
+- Steinar Haug (STH; sthaug@nethelp.no) for pointing out missing ';' in
+  ezmlmrc (caused problems with /bin/sh on FreeBSD), and the trigger message
+  received lines in the digest header.
+- Peter Hunter (PH) for suggesting dir/headeradd and list address in digest
+  headers and for reporting a "cosmetic" bug in subscription logging.
+- Jim Simmons (JS) for finding the n/d switch misnaming in ezmlmrc for text file
+  editing.
+- Sergiusz Pawlowicz (SP; ser@arch.pwr.wroc.pl) for ezmlmrc.pl, and many entries
+  for mimeremove.
+- Wanderlei Antonio Cavassin (WAC; cavassin@connectiva.com.br) for
+  ezmlmrc.pt_BR.
+- Jim Simmons (     ) for finding a missing-newline-mime bug in
+  ezmlm-moderate/store/clean.
+- Monte Mitzelfelt (MM; monte@gonefishing.org) for suggesting alternative
+  From: for ezmlm-manage help messages to break responder loops.
+- Louis Larry (LL; luois@kediri.webindonesia.com) for reporting a 0.311 prefix
+  handling bug.
+- Sigi Remsmurr (SR; service@isk.de), Bill Nugent (whn@topelo.lopi.com), James
+  Smallacombe (JS; up@3am) for ezmlmrc corrections/suggestions.
+- Matthew Saunders (MS; matts@easynet.net) for ezmlm-glconf.sh corrections and
+  reporting crashability of ezmlm-get by abnormal use (fixed).
+- Petr Novotny (PN; Petr.Novotny@antek.cz) for ezdomo.tar.gz corrections.
+- Evan Champion (EC; evanc@synapse.net) for ezmlm-request bug report.
+- Jeff Hill (JH; jhill@hronline.com) for ezmlm-reject bug report.
+- Bruno Wolff (BW; bruno@cerberus.umn.edu) for Ultrix fixes.
+- Butch Evans (BE; butch@###.com) for reporting trailer problems with
+  multipart/alternative messages and testing fix.
+- Kragen Sitaker (KS; kragen@pobox.com) for reporting ezmlm-manage -get bug.
+- Lars B. Rasmusson (LBR; lbr@mjolner.dk) for prerelease testing with sun cc.
+- Mike McLeish (MMcL; Mike.Mcleish@chatsoft.com) for reporting problems
+  using the 'x' format and testing the fix.
+- Jan Kasprzak (JK; kas@informatics.muni.cz) for ezmlmrc.cs and headerremove
+  suggestions.
+- Matt McGlynn for reporting 0.32 ezmlmrc -return omission.
+- Roman V Isaev (RVI; rm@techno.ru) for ezmlmrc.ru as well as suggestions
+  on -allow automation.
+- Aria Prima Novianto (APN; aria@isnet.org) for ezmlmrc.id.
+- Roberto De Carlo (RDC; rodeca@flashnet.it) for ezmlmrc.it.
+- Vicent Mas, Francesc Alted, Sonia Lorente, and Cyndy DePoy for ezmlmrc.es.
+- HaiFeng Guo (HFG; haifeng@ms.lawton.com.cn) for ezmlmrc.cn_GB.
+- Benjamin Pflugman (BPF; philemon@spin.de) for reporting multipart/signed
+  problems and testing fix.
+- Rik Myers (RM; rik@sumthin.nu), Daniel Mattos (DM; daniel@tiii.com) and others
+  for helping make ezmlm-test less platform-sensitive.
+- Michael Hirohama (MH; michael@sooth.com) for reporting Outlook problems and
+  testing a work-around.
+- Mate Wierdl (MW; mw@wierdlpc.msci.memphis.edu) for SPEC file kit and
+  suggestions on ezmlm-test, "it", etc, and pre-release testing.
+- Numerous users for suggestions/corrections for the documentation.
+- I'm sure I've forgotten others who have contributed ideas, questions,
+  comments. Thanks!
+
+EZMLM-IDX HAS BEEN REPORTED TO WORK ON (With ezmlm-0.53):
+0.12: linux-2.0.18-:i386-:-:i486-:- (Thanks Dileep Agrawal)
+0.12: linux-2.0.23-:i386-:-:i486-:- (Thanks TV)
+0.12: linux-2.0.31-:i386-:-:i486-:- (Thanks Nathan D. Faber)
+0.20: linux-2.0.23-:i386-:-:i486:-:-
+0.20: linux-2.0.31-:i386-:-:pentium:-:- (Thanks FBR)
+0.20: linux-2.0.23-:i386-:-:pentium:-:- (Thanks YG)
+0.20: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.20: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB)
+0.20: sunos-4.1.4-2-:sparc-:sun4:sun4m- (Thanks SK)
+0.20: freebsd-2.2.2-release-:i386-:-:pentium.pro-:- (Thanks MDS)
+0.21: linux-2.0.23-:i386-:-:i486-:-
+0.21: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.21: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE)
+0.21: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB)
+0.21: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH)
+0.22: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.22: linux-2.0.23-:i386-:-:i486-:-
+0.22: linux-2.0.31-:i386-:-:ppro-:- (Thanks YG)
+0.22: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR)
+0.22: linux-2.0.32-:i386-:-:pentium-:- (Thanks TF)
+0.22: freebsd-2.2.1-release-:i386-:-:-:- (Thanks TM)
+0.22: freebsd-2.2.5-stable-:i386-:-:pentium.pro-:- (Thanks MDS)
+0.22: osf1-v4.0-386-:-:-:alpha-:- (Thanks TEE)
+0.22: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE)
+0.22: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4u-:sun4u- (Thanks YG)
+0.22: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (Thanks TEE)
+0.22: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH)
+0.23: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.23: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB)
+0.23: freebsd-2.2.1-release-:i386-:-:-:- (Thanks TM)
+0.23: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.23: linux-2.0.30-:i386-:-:i486-:-
+0.23: linux-2.0.32-:i386-:-:i486-:- (Thanks BCL; Bruce C. Law)
+0.23: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR)
+0.23: osf1-v4.0-386-:-:-:alpha-:- (Thanks TEE)
+0.23: osf1-v4.0-564-:-:-:alpha-:- (Thanks ME)
+0.23: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE)
+0.23: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (Thanks TEE)
+0.23: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH)
+0.30: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.30: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB)
+0.30: freebsd-2.2.5-release-:i386-:-:-:- (Thanks TM)
+0.30: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.30: linux-2.0.30-:i386-:-:i486-:-
+0.30: linux-2.0.31-:i386-:-:ppro:-:- (Thanks YG)
+0.30: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR)
+0.30: osf1-v4.0-564-:-:-:alpha-:- (Thanks ME)
+0.30: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH)
+0.301: freebsd-2.2.5-release-:i386-:-:pentium.pro-:- (Thanks Matthew S. Soffen)
+0.301: linux-2.0.30-:-:-:sparc-:- (Thanks Bill Himmelstoss)
+0.301: linux-2.0.30-:i386-:-:i486-:-
+0.301: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR)
+0.301: linux-2.0.33-:i386-:-:i486-:- (Thanks BCL)
+0.301: linux-2.0.32-:i386-:-:ppro-:-
+0.302: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.302: linux-2.0.31-:i386-:-:ppro:-:- (Thanks YG)
+0.302: linux-2.0.32-:i386-:-:i486-:-
+0.302: linux-2.0.34-:i386-:-:pentium-:- (Thanks FBR)
+0.31: freebsd-2.2.6-release-:i386-:-:-:- (Thanks TM)
+0.31: linux-2.0.32-:i386-:-:ppro-:-
+0.31: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.311: linux-2.0.31-:i386-:-:ppro-:- (Thanks YG)
+0.311: linux-2.0.32-:i386-:-:ppro-:-
+0.311: linux-2.0.33-:i386-:-:i486-:- (Thanks BCL)
+0.311: linux-2.0.35-:i386-:-:i486-:- (Thanks PN)
+0.312: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.312: freebsd-3.0-current-:i386-:-:pentium/p54c-:- (Thanks MS)
+0.312: irix-5.3-08031224-:-:-:ip12-:- (Thanks Rob Stone)
+0.312: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.312: irix64-6.4-02121744-:-:-:ip30-:- (Thanks MF)
+0.312: linux-2.0.32-:i386-:-:ppro-:-
+0.312: linux-2.1.115-:i386-:-:pentium-:- (Thanks Uwe Ohse)
+0.312: sunos-5.6-generic_105181-06-:sparc-:sun4-:sun4u-:sun4u- (Thanks GS)
+0.312: sunos-5.6-generic_105182-08-:i386-:i86pc-:i86pc-:i86pc- (Thanks LBR)
+0.313: aix-4-2-:-:-:00720704c00-:- (Thanks TF)
+0.313: freebsd-2.2.6-release-:i386-:-:-:- (Thanks TM)
+0.313: freebsd-2.2.6-release-:i386-:-:pentium-:- (Thanks Dave Walton)
+0.313: freebsd-3.0-release-:i386-:-:pentium.ii.(qtr-micr)-:- (Tx Erik Gault)
+0.313: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.313: irix64-6.4-02121744-:-:-:ip30-:- (Thanks MF)
+0.313: linux-2.0.32-:i386-:-:ppro-:-
+0.313: linux-2.0.35-:i386-:-:pentium-:- (Thanks crt@ice.degan.si)
+0.313: linux-2.0.36-:i386-:-:pentium-:- (Thanks FBR)
+0.313: linux-2.2.0-pre4-:i386-:-:i486-:- (Thanks Chris Van Meter)
+0.313: sunos-5.6-generic_105181-04-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH)
+0.313: sunos-5.6-generic_105181-08-:sparc-:sun4-:sun4u-:sun4u- (Thanks LBR)
+0.313: ultrix-4.3-0-:-:-:risc-:- (Thanks BW)
+0.314: amigaos-3.1-40.60-:-:-:m68k-:- (Thanks Kirk Strauser)
+0.314: freebsd-2.2.8-stable-:i386-:-:pentium.ii-:-
+0.314: linux-2.0.32-:i386-:-:ppro-:-
+0.32: bsd.os-4.0-:i386-:-:-:- (Thanks ME)
+0.32: freebsd-2.2.7-stable-:i386-:-:pentium.pro-:- (Thanks Chris Johnson)
+0.32: freebsd-3.0-release-:i386-:-:pentium.ii.(qtr-micr)-:- (Thanks MS)
+0.32: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF)
+0.32: linux-2.0.34-:i386-:-:i486-:- (Thanks Benjamin T. Brillat)
+0.32: linux-2.0.34-:i386-:-:ppro-:- (Thanks Troy N. Poppe)
+0.32: linux-2.0.36-:i386-:-:pentium-:- (Thanks Peter J. Hunter)
+0.32: linux-2.0.36-:i386-:-:ppro-:- (Thanks FT)
+0.32: linux-2.2.0-pre4-:i386-:-:pentium-:- (Thanks FBR)
+0.32: linux-2.2.1-:i386-:-:pentium-:- (Thanks FBR)
+0.32: netbsd-1.3i-:i386-:-:intel.pentium.(p54c).(586-class)-:- (Thanks GC Wing)
+0.321: bsd.os-4.0-:i386-:-:pentium.ii-:- (Thanks RV Isaev)
+0.321: freebsd-3.1-release-:i386-:-:pentium.ii-:- (Thanks AR Buddhdev)
+0.321: freebsd-3.1-release-:i386-:-:pentium.ii/xeon/celeron-:- (Tx A Iijima)
+0.321: freebsd-3.1-stable-:i386-:-:pentium.ii/xeon/celeron-:- (Tx B Fuerst)
+0.321: linux-2.0.34-:i386-:-:pentium-:- (Thanks root@issaries.com.au)
+0.321: linux-2.0.36-:i386-:-:pentium-:- (Thanks MC Yoon)
+0.321: linux-2.0.36-:i386-:-:i486-:- (Thanks K Ralph)
+0.321: linux-2.0.36-:i386-:-:ppro-:- (Thanks JD Mitchell)
+0.321: linux-2.2.2-:i386-:-:pentium-:- (Thanks R Siemer)
+0.321: linux-2.2.4-:i386-:-:pentium-:- (Thanks JM Charette)
+0.321: linux-2.2.5-:i386-:-:ppro-:- (Thanks SM Moret)
+0.321: sunos-5.6-generic_105181-10-:sparc-:sun4-:sun4u-:sun4u- (Tx JA Marshall)
+0.322: aix-4-2-:-:-:000720704c00-:- (Thanks TF)
+0.322: linux-2.0.35-:i386-:-:i486-:- (Thanks Robert Siemer)
+0.322: linux-2.0.36-:i386-:-:i486-:- (Thanks Ryan C. Hughes)
+0.322: linux-2.0.36-:i386-:-:pentium-:- (Thanks Kengo Nakajima)
+0.322: linux-2.2.10-:i386-:-:pentium-:- (Thanks Peter Green)
+0.322: linux-2.0.36-:i386-:-:ppro-:- (Thanks Jeff Hill)
+0.322: linux-2.2.5-15-:i386-:-:pentium-:- (Thanks Raj H.)
+0.322: linux-2.2.5-15-:i386-:-:ppro-:- (Thanks peter@mail.gradwell.com)
+0.322: linux-2.2.5-:i386-:-:ppro-:- (Thanks Achim Gosse)
+0.322: linux-2.2.9-:i386-:-:pentium-:- (Thanks FBR)
+0.322: netbsd-1.4-:sparc-:-:mb86900/1a.or.l64801.@.25.mhz,.wtl3170/2.fpu-:- (Tx R Nurges)
+0.322: sunos-5.6-generic_105181-05-:sparc-:sun4-:sun4u-:sun4u- (Tx Ralf Weber)
+0.322: sunos-5.6-generic_105181-13-:sparc-:sun4-:sun4u-:sun4u- (Tx MN Boyiazis)
+0.322: sunos-5.7-generic-:sparc-:sun4-:sun4u-:sun4u- (Tx Paul Theodoropoulos)
+0.322: sunos-5.7-generic_106541-02-:sparc-:sun4-:sun4u-:sun4u- (Tx Bo Fussing)
+0.323: linux-2.0.36-:i386-:-:pentium-:- (TX RVI)
+0.323: linux-2.2.3-:i386-:-:pentium-:- (TX Ludovico Magocavallo)
+0.323: linux-2.2.7-:i386-:-:ppro-:- (TX Achim Gosse)
+0.324: bsd.os-4.0.1-:i386-:-:-:- (Tx Peeter Pirn)
+0.324: freebsd-3.3-stable-:i386-:-:pentium/p54c-:- (Tx J B Bell)
+0.324: freebsd-4.0-19990816-current-:i386-:-:pentium.ii/xeon/celeron-:- (Tx MS)
+0.324: irix-6.5-04151556-:-:-:ip22-:- (Tx Claudio Nieder)
+0.324: linux-2.0.36-:i386-:-:pentium-:- (Tx Michael P. McMillan)
+0.324: linux-2.0.38-:i386-:-:pentium-:- (Tx Anton V. Bobykin)
+0.324: linux-2.2.1-:-:-:armv4l-:- (Tx Jim Zajkowski)
+0.324: linux-2.2.12-20-:i386-:-:ppro-:- (Tx Michael D. Mooney)
+0.324: linux-2.2.12-:i386-:-:p2-:- (TX Oden Eriksson)
+0.324: linux-2.2.13-:i386-:-:pentium-:- (Tx Tibor Szentmarjay)
+0.324: linux-2.2.5-22-:alpha-:-:alpha-:- (Tx Steve J. Borho)
+0.324: linux-2.2.5-22-:i386-:-:ppro-:- (Tx Yann M. Aubert)
+0.324: linux-2.2.7-:i386-:-:ppro-:- (Tx Brad W. Baker)
+0.324: openbsd-2.5-generic#172-:openbsd.sparc-:-:sparc-:- (Tx Grant L Miller)
+0.324: openbsd-2.5-generic#243-:openbsd.i386-:-:i386-:- (Tx Grant L Miller)
+0.324: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (Tx D Andrew Reynhout)
+0.40: freebsd-3.3-release-:i386-:-:prentium.iii-:- (Tx MAS)
+0.40: linux-2.2.11-:i386-:-:pentium-:- (Tx FBR)
+0.40: linux-2.2.5-22-:i386-:-:ppro-:- [RH6.0]
+0.40: linux-2.2.13-:i386-:-:ppro-:- [Debian] (Tx MAS)
+  
diff --git a/TARGETS b/TARGETS
new file mode 100644 (file)
index 0000000..6ae1653
--- /dev/null
+++ b/TARGETS
@@ -0,0 +1,191 @@
+alloc.a
+alloc.o
+alloc_re.o
+author.o
+auto-ccld.sh
+auto-str
+auto-str.o
+auto_bin.c
+auto_bin.o
+auto_cron.c
+auto_cron.o
+auto_qmail.c
+auto_qmail.o
+byte_chr.o
+byte_copy.o
+byte_cr.o
+byte_diff.o
+byte_rchr.o
+byte_zero.o
+case.a
+case_diffb.o
+case_diffs.o
+case_lowerb.o
+case_startb.o
+case_starts.o
+checktag.o
+compile
+concatHDR.o
+constmap.o
+cookie.o
+copy.o
+date2yyyymm.o
+date822fmt.o
+dateline.o
+datetime.o
+decodeB.o
+decodeHDR.o
+decodeQ.o
+direntry.h
+encodeB.o
+encodeQ.o
+env.a
+env.o
+envread.o
+error.a
+error.o
+error_str.o
+ezmlm-accept
+ezmlm-archive
+ezmlm-archive.o
+ezmlm-cgi
+ezmlm-cgi.o
+ezmlm-check
+ezmlm-clean
+ezmlm-clean.o
+ezmlm-cron
+ezmlm-cron.o
+ezmlm-gate
+ezmlm-gate.o
+ezmlm-get
+ezmlm-get.o
+ezmlm-glconf
+ezmlm-idx
+ezmlm-idx.o
+ezmlm-issubn
+ezmlm-issubn.o
+ezmlm-limit
+ezmlm-limit.o
+ezmlm-list
+ezmlm-list.o
+ezmlm-make
+ezmlm-make.o
+ezmlm-manage
+ezmlm-manage.o
+ezmlm-moderate
+ezmlm-moderate.o
+ezmlm-reject
+ezmlm-reject.o
+ezmlm-request
+ezmlm-request.o
+ezmlm-return
+ezmlm-return.o
+ezmlm-send
+ezmlm-send.o
+ezmlm-split
+ezmlm-split.o
+ezmlm-store
+ezmlm-store.o
+ezmlm-sub
+ezmlm-sub.o
+ezmlm-test
+ezmlm-tstdig
+ezmlm-tstdig.o
+ezmlm-unsub
+ezmlm-unsub.o
+ezmlm-warn
+ezmlm-warn.o
+ezmlm-weed
+ezmlm-weed.o
+ezmlmrc
+fd.a
+fd_copy.o
+fd_move.o
+find-systype
+fmt_str.o
+fmt_uint.o
+fmt_uint0.o
+fmt_ulong.o
+fork.h
+fs.a
+getconf.o
+getln.a
+getln.o
+getln2.o
+getopt.a
+hasflock.h
+hassgact.h
+idxthread.o
+issub.o
+load
+lock.a
+lock_ex.o
+log.o
+logmsg.o
+make-compile
+make-load
+make-makelib
+makehash.o
+makelib
+mime.a
+now.o
+open.a
+open_append.o
+open_read.o
+open_trunc.o
+opensql.o
+putsubs.o
+qmail.o
+quote.o
+scan_8long.o
+scan_ulong.o
+searchlog.o
+seek.a
+seek_set.o
+sgetopt.o
+sig.a
+sig_catch.o
+sig_pipe.o
+slurp.o
+slurpclose.o
+str.a
+str_chr.o
+str_cpy.o
+str_diff.o
+str_diffn.o
+str_len.o
+str_rchr.o
+str_start.o
+stralloc.a
+stralloc_arts.o
+stralloc_cat.o
+stralloc_catb.o
+stralloc_cats.o
+stralloc_copy.o
+stralloc_eady.o
+stralloc_opyb.o
+stralloc_opys.o
+stralloc_pend.o
+strerr.a
+strerr.o
+strerr_die.o
+strerr_sys.o
+subdb.a
+subfderr.o
+subgetopt.o
+subscribe.o
+substdi.o
+substdio.a
+substdio.o
+substdio_copy.o
+substdo.o
+surf.a
+surf.o
+surfpcs.o
+systype
+tagmsg.o
+uint32.h
+unfoldHDR.o
+wait.a
+wait_pid.o
+yyyymm.a
diff --git a/UPGRADE.idx b/UPGRADE.idx
new file mode 100644 (file)
index 0000000..3e18bc2
--- /dev/null
@@ -0,0 +1,190 @@
+$Id: UPGRADE.idx,v 1.39 1999/12/19 16:47:30 lindberg Exp $
+$Name: ezmlm-idx-040 $
+
+Like any other piece of software (and information generally), ezmlm-idx
+comes with NO WARRANTY.
+
+This file is for upgrading from earlier version of ezmlm-idx/mod. If you use
+ezmlm-0.53 but have not installed a previous version of ezmlm-idx,
+see INSTALL.idx. For details on what's new in this version, see CHANGES.idx.
+
+1. Proceed as per INSTALL.idx.
+   NOTE: If you follow the test instructions in INSTALL of ezmlm-0.53 after
+   adding ezmlm-idx, step 6 will fail. Before this step, edit
+   ~/testlist/editor and remove the ezmlm-reject line. 
+
+
+Steps required for upgrading from ezmlm-idx-0.31x/32x
+-----------------------------------------------------
+In the unlikely event that you have lists that have been manually configured
+to use ezmlm-gate (sender check/moderation combination) using only a single
+directory, add the same directory to the command line a second time. If you
+do not do this, all messages will be moderated, i.e. no major problem. No
+other changes are required, but you may want to use some of the new features
+(see CHANGES.idx).
+
+See below to migrate customized ezmlmrc files.
+
+Run ezmlm-idx on your lists. The index file format has changed. The old
+format will still work, but only the new format can be used with WWW archive
+access.
+
+To enable WWW archive access for your list(s) see the "Optional" section in
+INSTALL.idx.
+
+If you used MySQL support, you need to update the tables. A few new fields
+have been added for performance moitoring and billing. sub_mysql/to40x will
+generate the necessary SQL. For each list, do:
+
+sh sub_mysql/to40x list | mysql ...
+
+where ``list'' is the tableroot for the list.
+
+Additional steps for upgrading from ezmlm-idx-0.30x
+---------------------------------------------------
+
+If your old lists use SENDER restriction on posts with aliases (DIR/extra)
+and blacklisted addresses (DIR/blacklist) you need to change the name of
+these directories to DIR/allow and DIR/deny, respectively, and rebuild the list
+(see below). Without this change the list will still function normally, but
+addresses cannot be added/removed from these addresses remotely (e.g. via
+list-allow-subscribe). Other than this, your lists will function without
+modifications if you are upgrading from ezmlm-idx>=0.30.
+
+See below for changing the names of the extra databases.
+
+
+Additional steps for upgrading from ezmlm-idx<0.30
+--------------------------------------------------
+1.  Reindex the subject index for existing lists:
+
+       % ezmlm-idx DIR
+
+    for each list directory 'DIR'.
+
+2.  For existing digest lists, assuming the list "joe-sos" and the digest list
+    "joe-sos-digest".
+
+    a. Remove links to the digest list:
+
+       % rm -f ~joe/.qmail-sos-digest*
+
+    b. edit the main list to include a digest list:
+
+       % ezmlm-make -edxxx ~joe/SOS ~joe/.qmail joe-sos id.com gaga
+
+       where 'xxx' are switches used in creating the original list. For lists
+       created with ezmlm-idx-0.23 or later, the arguments after the list
+       directory may be omitted.
+
+    c. Move the digest subscriber info:
+
+       % mv ~joe/SOS-digest/subscribers/* ~joe/SOS/digest/subscribers
+
+    The digest list bounce info will be lost, as the key used for the new
+    digest is the same as for the list, and different for that from the old
+    digest. At worst, this will make the info for a digest user on missed
+    digests incomplete. It may also slightly delay the removal
+    of a permanently bouncing subscriber addresses.
+
+
+Additional steps for upgrading from ezmlm-idx<0.23x
+---------------------------------------------------
+For subscription-moderated lists created with ezmlm-idx<0.23:
+
+1.  If you have subscription moderated lists created with ezmlm-idx<0.23,
+    they likely lack dir/text/mod-sub-confirm and dir/text/mod-unsub-confirm.
+    Ezmlm-idx-0.23 substituted dir/text/(un)sub-confirm if the above files were
+    missing, but ezmlm-idx>=0.30 will not work without these files. Again,
+    ezmlm-make -e is the easiest way to update the list. Alternatively,
+    just copy dir/text/(un)sub-confirm to dir/text/mod-(un)sub-confirm.
+
+------------------------------------------------------------------------------
+That's it! To report success (this helps to track platform-specific problems):
+
+       % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \
+         | mail cfl-src@id.wustl.edu
+
+Replace First M. Last with your name.
+
+Send bugs reports, ideally with patch, to 'lindberg@id.wustl.edu'.
+
+
+------------------------------------------------------------------------------
+
+
+ Additional information
+------------------------
+
+Migrating customized ezmlmrc files
+==================================
+
+ezmlmrc is upgraded from ezmlm-idx-0.31x/32x, but the changes are not required
+for using the list.
+
+The changes from ezmlm-0.30x are minimal, but fix a couple of bugs, see
+CHANGES.idx). If you have custom ezmlmrc files and wish to update them,
+do the following:
+
+    First create a diff between the old ezmlmrc distribution and the
+    custom ezmlmrc file:
+
+       % cp /usr/local/bin/ezmlm/ezmlmrc ~/ezmlmrc.orig
+       % cp ~/.ezmlmrc ~/ezmlmrc
+       % diff -c ~/ezmlmrc.orig ~/ezmlmrc ~/ezmlmrc.diff
+
+    Next, apply the changes to the new ezmlmrc:
+
+       % cp .../ezmlm-idx-0.33/ezmlmrc ~/ezmlmrc
+       % patch ~/ezmlmrc < ~/ezmlmrc.diff
+
+    Next check for rejected parts (you need to apply them manually):
+
+       % cat ~/ezmlmrc.rej
+
+Any existing list can be edited with 'ezmlm-make -e dir dot local host [code]'
+with the appropriate switches to take advantage of new ezmlm functions. If
+you make ezmlmrc files in other languages, please make them public domain and
+mail them to lindberg@id.wustl.edu for inclusion in future versions of
+ezmlm-idx.
+
+Adjusting the name of the extra databases (from ezmlm-idx<0.30):
+===============================================================
+
+       % mv DIR/extra DIR/allow
+       % mv DIR/blacklist DIR/deny
+       % ezmlm-make -+ DIR
+
+Additional steps required when upgrading from ezmlm-idx<0.30:
+
+1.  Reindex the subject index for existing lists:
+
+       % ezmlm-idx DIR
+
+    for each list directory 'DIR'.
+
+2.  For existing digest lists, assuming the list "joe-sos" and the digest list
+    "joe-sos-digest".
+
+    a. Remove links to the digest list:
+
+       % rm -f ~joe/.qmail-sos-digest*
+
+    b. edit the main list to include a digest list:
+
+       % ezmlm-make -edxxx ~joe/SOS ~joe/.qmail joe-sos id.com gaga
+
+       where 'xxx' are switches used in creating the original list. For lists
+       created with ezmlm-idx-0.23 or later, the arguments after the list
+       directory may be omitted.
+
+    c. Move the digest subscriber info:
+
+       % mv ~joe/SOS-digest/subscribers/* ~joe/SOS/digest/subscribers
+
+    The digest list bounce info will be lost, as the key used for the new
+    digest is the same as for the list, and different for that from the old
+    digest. At worst, this will make the info for a digest user on missed
+    digests incomplete. It may also slightly delay the removal
+    of a permanently bouncing subscriber addresses.
+
diff --git a/VERSION b/VERSION
index 6049539..a01a1fd 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
 ezmlm 0.53
 ezmlm 0.53
+$Name: ezmlm-idx-040 $
diff --git a/author.c b/author.c
new file mode 100644 (file)
index 0000000..c5bf0dc
--- /dev/null
+++ b/author.c
@@ -0,0 +1,103 @@
+/*$Id: author.c,v 1.3 1999/09/29 03:11:44 lindberg Exp $*/
+/*$Name:*/
+
+unsigned int author_name(char **sout,char *s,unsigned int l)
+/* s is a string that contains a from: line argument\n. We parse */
+/* s as follows: If there is an unquoted '<' we eliminate everything after */
+/* it else if there is a unquoted ';' we eliminate everything after it.    */
+/* Then, we eliminate LWSP and '"' from the beginning and end. Note that   */
+/* this is not strict rfc822, but all we need is a display handle that     */
+/* doesn't show the address. If in the remaining text there is a '@' we put*/
+/* in a '.' instead. Also, there are some non-rfc822 from lines out there  */
+/* and we still want to maximize the chance of getting a handle, even if it*/
+/* costs a little extra work.*/
+{
+  int squote = 0;
+  int dquote = 0;
+  int level = 0;
+  int flagdone;
+  unsigned int len;
+  char ch;
+  char *cpfirst,*cp;
+  char *cpcomlast = 0;
+  char *cpquotlast = 0;
+  char *cpquot = 0;
+  char *cpcom = 0;
+  char *cplt = 0;
+
+  if (!s || !l) {      /* Yuck - pass the buck */
+    *sout = s;
+    return 0;
+  }
+  cp = s; len = l;
+
+  while (len--) {
+    ch = *(cp++);
+    if (squote) {
+      squote = 0;
+      continue;
+    }
+    if (ch == '\\') {
+      squote = 1;
+      continue;
+    }
+    if (ch == '"') {           /* "name" <address@host> */
+      if (dquote) {
+       cpquotlast = cp - 2;
+        break;
+      } else {
+       cpquot = cp;
+        dquote = 1;
+      }
+      continue;
+    } else if (dquote) continue;
+    if (ch == '(') {
+       if (!level) cpcom = cp;
+       level++;
+    } else if (ch == ')') {
+       level--;
+       if (!level)
+         cpcomlast = cp - 2;   /* address@host (name) */
+    } else if (!level) {
+      if (ch == '<') {         /* name <address@host> */
+       cplt = cp - 2;
+       break;
+      } else if (ch == ';') break;     /* address@host ;garbage */
+    }
+  }
+  if (cplt) {                  /* non-comment '<' */
+    cp = cplt;
+    cpfirst = s;
+  } else if (cpquot && cpquotlast >= cpquot) {
+    cpfirst = cpquot;
+    cp = cpquotlast;
+  } else if (cpcom && cpcomlast >= cpcom) {
+    cpfirst = cpcom;
+    cp = cpcomlast;
+  } else {
+    cp = s + l - 1;
+    cpfirst = s;
+  }
+  flagdone = 0;
+  for (;;) {           /* e.g. LWSP <user@host> */
+    while (cpfirst <= cp &&
+       (*cpfirst == ' ' || *cpfirst == '\t' || *cpfirst == '<')) cpfirst++;
+    while (cp >= cpfirst &&
+       (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '>')) cp--;
+    if (cp >= cpfirst || flagdone)
+      break;
+    cp = s + l - 1;
+    cpfirst = s;
+    flagdone = 1;
+  }
+
+  *sout = cpfirst;
+  len = cp - cpfirst + 1;
+  while (cpfirst <= cp) {
+    if (*cpfirst == '@')
+      *cpfirst = '.';
+    cpfirst++;
+  }
+  return len;
+}
+
diff --git a/auto_cron.h b/auto_cron.h
new file mode 100644 (file)
index 0000000..bdd9387
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef AUTO_CRON_H
+#define AUTO_CRON_H
+
+extern char auto_cron[];
+
+#endif
diff --git a/case_diffs.c b/case_diffs.c
new file mode 100644 (file)
index 0000000..212c645
--- /dev/null
@@ -0,0 +1,19 @@
+#include "case.h"
+
+int case_diffs(s,t)
+register char *s;
+register char *t;
+{
+  register unsigned char x;
+  register unsigned char y;
+
+  for (;;) {
+    x = *s++ - 'A';
+    if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
+    y = *t++ - 'A';
+    if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+    if (x != y) break;
+    if (!x) break;
+  }
+  return ((int)(unsigned int) x) - ((int)(unsigned int) y);
+}
diff --git a/case_starts.c b/case_starts.c
new file mode 100644 (file)
index 0000000..2278a0a
--- /dev/null
@@ -0,0 +1,18 @@
+#include "case.h"
+
+int case_starts(s,t)
+register char *s;
+register char *t;
+{
+  register unsigned char x;
+  register unsigned char y;
+
+  for (;;) {
+    x = *s++ - 'A';
+    if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
+    y = *t++ - 'A';
+    if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+    if (!y) return 1;
+    if (x != y) return 0;
+  }
+}
diff --git a/checktag.c b/checktag.c
new file mode 120000 (symlink)
index 0000000..fe4e410
--- /dev/null
@@ -0,0 +1 @@
+sub_std/checktag.c
\ No newline at end of file
diff --git a/concatHDR.c b/concatHDR.c
new file mode 100644 (file)
index 0000000..604892c
--- /dev/null
@@ -0,0 +1,45 @@
+/*$Id: */
+/*$Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "strerr.h"
+#include "case.h"
+#include "byte.h"
+#include "mime.h"
+#include "errtxt.h"
+
+void concatHDR(indata,n,outdata,fatal)
+char *indata;
+unsigned int n;
+stralloc *outdata;
+char *fatal;
+/* takes a concatenated string of line and continuation line, trims leading */
+/* and trailing LWSP and collapses line breaks and surrounding LWSP to ' '. */
+/* indata has to end in \n or \0 or this routine will write beyond indata!  */
+/* if indata ends with \0, this will be changed to \n. */
+
+{
+  register char *cp,*cpout;
+  char *cplast;
+  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(outdata,n)) die_nomem(fatal);
+  cpout = outdata->s;
+  if (n == 0) return;
+  cplast = indata + n - 1;
+  cp = cplast;
+  while (*cplast == '\0' || *cplast == '\n') --cplast;
+  if (cp == cplast) die_nomem(fatal);          /* just in case */
+  *(++cplast) = '\n';                          /* have terminal '\n' */
+  cp = indata;
+  while (cp <= cplast) {
+    while (*cp == ' ' || *cp == '\t') ++cp;    /* LWSP before */
+    while (*cp != '\n') *(cpout++) = *(cp++);  /* text */
+    ++cp;                                      /* skip \n */ 
+    --cpout;                                   /* last char */
+    while (*cpout == ' ' || *cpout == '\t') --cpout;   /* LWSP after */
+    *(++cpout) = ' ';                          /* replace with single ' ' */
+    ++cpout;                                   /* point to free byte */
+  }
+  outdata->len = cpout - outdata->s;
+}
+
diff --git a/conf-cron b/conf-cron
new file mode 100644 (file)
index 0000000..612a7e3
--- /dev/null
+++ b/conf-cron
@@ -0,0 +1,3 @@
+/usr/bin
+
+This is the directory housing the crontab binary
diff --git a/conf-sqlcc b/conf-sqlcc
new file mode 120000 (symlink)
index 0000000..6d13424
--- /dev/null
@@ -0,0 +1 @@
+sub_std/conf-sqlcc
\ No newline at end of file
diff --git a/conf-sqlld b/conf-sqlld
new file mode 120000 (symlink)
index 0000000..7432a47
--- /dev/null
@@ -0,0 +1 @@
+sub_std/conf-sqlld
\ No newline at end of file
index 722e3b8..8c742c2 100644 (file)
@@ -18,6 +18,39 @@ int len;
   return h;
 }
 
   return h;
 }
 
+/* Returns index of string in constmap. 1 = first string, 2 = second ... */
+/* 0 not found. Use for commands */ 
+int constmap_index(cm,s,len)
+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 pos + 1;
+    pos = cm->next[pos];
+  }
+  return 0;
+}
+
+/* returns pointer to sz of string with index "idx". 1 = first, 2 = second...*/
+char *constmap_get(cm,idx)
+struct constmap *cm;
+int idx;
+
+{
+  if (idx <= 0 || idx > cm->num)
+    return 0;
+  else
+    return cm->input[idx-1];
+}
+
 char *constmap(cm,s,len)
 struct constmap *cm;
 char *s;
 char *constmap(cm,s,len)
 struct constmap *cm;
 char *s;
@@ -38,6 +71,9 @@ int len;
 }
 
 int constmap_init(cm,s,len,flagcolon)
 }
 
 int constmap_init(cm,s,len,flagcolon)
+/* if flagcolon is true, we process only the stuff before the colon on */
+/* each line. Otherwise, it's the entire line. Still, the entire line */
+/* is stored! */
 struct constmap *cm;
 char *s;
 int len;
 struct constmap *cm;
 char *s;
 int len;
index 3f29179..66be99f 100644 (file)
@@ -16,5 +16,6 @@ struct constmap {
 extern int constmap_init();
 extern void constmap_free();
 extern char *constmap();
 extern int constmap_init();
 extern void constmap_free();
 extern char *constmap();
-
+extern char *constmap_get();
+extern int constmap_index();
 #endif
 #endif
diff --git a/copy.c b/copy.c
new file mode 100644 (file)
index 0000000..24f0034
--- /dev/null
+++ b/copy.c
@@ -0,0 +1,211 @@
+/*$Id: copy.c,v 1.10 1999/08/07 19:28:16 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+/* Copies a file relative the current directory and substitutes    */
+/* !A at the beginning of a line for the target,                   */
+/* !R at the beginning of a line for the confirm reply address,    */
+/* The following substitutions are also made. If not set, ?????    */
+/* will be printed:  <#l#> outlocal                                */
+/* will be printed:  <#h#> outhost                                 */
+/* will be printed:  <#n#> outmsgnum                               */
+/* Other tags are killed, e.g. removed. A missing file is a        */
+/* permanent error so owner finds out ASAP. May not have access to */
+/* maillog. Content transfer encoding is done for 'B' and 'Q'. For */
+/* 'H' no content transfer encoding is done, but blank lines are   */
+/* suppressed. Behavior for other codes is undefined. This includes*/
+/* lower case 'q'/'b'! If code is 'H' substitution of target and   */
+/* verptarget is prevented as it may create illegal headers.       */
+
+#include "stralloc.h"
+#include "substdio.h"
+#include "strerr.h"
+#include "str.h"
+#include "getln.h"
+#include "case.h"
+#include "readwrite.h"
+#include "qmail.h"
+#include "errtxt.h"
+#include "error.h"
+#include "quote.h"
+#include "copy.h"
+#include "mime.h"
+                       /* for public setup functions only */
+#define FATAL "copy: fatal: "
+
+static stralloc line = {0};
+static stralloc outline = {0};
+static stralloc qline = {0};
+static stralloc outlocal = {0};
+static stralloc outhost = {0};
+static substdio sstext;
+static char textbuf[256];
+static char *target = "?????";
+static char *verptarget = "?????";
+static char *confirm = "?????";
+static char *szmsgnum = "?????";
+
+void set_cpoutlocal(ln)
+stralloc *ln;
+{      /* must be quoted for safety. Note that substitutions that use */
+       /* outlocal within an atom may create illegal addresses */
+  if (!quote(&outlocal,ln))
+        strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
+void set_cpouthost(ln)
+stralloc *ln;
+{
+  if (!stralloc_copy(&outhost,ln))
+        strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
+void set_cptarget(tg)
+char *tg;
+{
+  target = tg;
+}
+
+void set_cpverptarget(tg)
+char *tg;
+{
+  verptarget = tg;
+}
+
+void set_cpconfirm(cf)
+char *cf;
+{
+  confirm = cf;
+}
+
+void set_cpnum(cf)
+char *cf;
+{
+  szmsgnum = cf;
+}
+
+static struct qmail *qq;
+
+static void codeput(l,n,code,fatal)
+char *l;
+unsigned int n;
+char code;
+char *fatal;
+
+{
+  if (!code || code == 'H')
+    qmail_put(qq,l,n);
+  else {
+    if (code == 'Q')
+      encodeQ(l,n,&qline,fatal);
+    else
+      encodeB(l,n,&qline,0,fatal);
+    qmail_put(qq,qline.s,qline.len);
+  }
+}
+
+static void codeputs(l,code,fatal)
+char *l;
+char code;
+char *fatal;
+{
+  codeput(l,str_len(l),code,fatal);
+}
+
+void copy(qqp,fn,q,fatal)
+struct qmail *qqp;
+char *fn;              /* text file name */
+char q;                        /* = '\0' for regular output, 'B' for base64, */
+                       /* 'Q' for quoted printable,'H' for header    */
+char *fatal;           /* FATAL error string */
+
+{
+  int fd;
+  int match, done;
+  unsigned int pos,nextpos;
+
+  qq = qqp;
+  if ((fd = open_read(fn)) == -1)
+    if (errno != error_noent)
+      strerr_die4sys(111,fatal,ERR_OPEN,fn,": ");
+    else
+      strerr_die4sys(100,fatal,ERR_OPEN,fn,": ");
+  substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+  for (;;) {
+    if (getln(&sstext,&line,&match,'\n') == -1)
+      strerr_die4sys(111,fatal,ERR_READ,fn,": ");
+    if (match) {       /* suppress blank line for 'H'eader mode */
+      if (line.len == 1 && q == 'H') continue;
+      if (line.s[0] == '!') {
+       if (line.s[1] == 'R') {
+         codeput("   ",3,q,fatal);
+         codeputs(confirm,q,fatal);
+         codeput("\n",1,q,fatal);
+         continue;
+       }
+       if (line.s[1] == 'A') {
+         codeput("   ",3,q,fatal);
+         codeputs(target,q,fatal);
+         codeput("\n",1,q,fatal);
+         continue;
+       }
+      }
+               /* Find tags <#x#>. Replace with for x=R confirm, for x=A */
+               /* target, x=l outlocal, x=h outhost. For others, just    */
+               /* skip tag. If outlocal/outhost are not set, the tags are*/
+               /* skipped. If confirm/taget are not set, the tags are    */
+               /* replaced by "???????" */
+      pos = 0;
+      nextpos = 0;
+      done = 0;
+      outline.len = 0;                 /* zap outline */
+      while ((pos += byte_chr(line.s+pos,line.len-pos,'<')) != line.len) {
+        if (pos + 4 < line.len &&
+            line.s[pos+1] == '#' &&
+            line.s[pos+3] == '#' &&
+            line.s[pos+4] == '>') {    /* tag. Copy first part of line */
+          done = 1;                            /* did something */
+          if (!stralloc_catb(&outline,line.s+nextpos,pos-nextpos))
+                        die_nomem(fatal);
+          switch(line.s[pos+2]) {
+            case 'A':
+             if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE);
+              if (!stralloc_cats(&outline,target)) die_nomem(fatal);
+              break;
+            case 'R':
+              if (!stralloc_cats(&outline,confirm)) die_nomem(fatal);
+              break;
+            case 'l':
+              if (!stralloc_cat(&outline,&outlocal)) die_nomem(fatal);
+              break;
+            case 'h':
+              if (!stralloc_cat(&outline,&outhost)) die_nomem(fatal);
+              break;
+            case 't':
+             if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE);
+              if (!stralloc_cats(&outline,verptarget)) die_nomem(fatal);
+              break;
+            case 'n':
+              if (!stralloc_cats(&outline,szmsgnum)) die_nomem(fatal);
+              break;
+            default:
+              break;                   /* unknown tags killed */
+          }
+          pos += 5;
+          nextpos = pos;
+        } else
+          ++pos;                               /* try next position */
+      }
+      if (!done)
+        codeput(line.s,line.len,q,fatal);
+      else {
+        if (!stralloc_catb(&outline,line.s+nextpos,line.len-nextpos))
+               die_nomem(fatal);               /* remainder */
+        codeput(outline.s,outline.len,q,fatal);
+      }
+
+    } else
+      break;
+  }
+  close(fd);
+}
+
diff --git a/copy.h b/copy.h
new file mode 100644 (file)
index 0000000..3a642eb
--- /dev/null
+++ b/copy.h
@@ -0,0 +1,11 @@
+#ifndef COPY_H
+#define COPY_H
+
+/* copy (qq,fn,fatal) */
+extern void copy();
+extern void set_cpoutlocal();
+extern void set_cpouthost();
+extern void set_cptarget();
+extern void set_cpconfirm();
+extern void set_cpnum();
+#endif
diff --git a/date2yyyymm.c b/date2yyyymm.c
new file mode 100644 (file)
index 0000000..dd6ea87
--- /dev/null
@@ -0,0 +1,71 @@
+
+/*$Id: date2yyyymm.c,v 1.1 1999/10/09 16:45:43 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "yyyymm.h"
+
+unsigned int date2yyyymm(s)
+char *s;
+/* expects a qmail date string s and returns yyyymm */
+/* if there are problems, it returns 0. If there is no terminating char */
+/* we may segfault if the syntax is bad. Assure that the ';' is there   */
+/* or add '\0' */
+{
+  unsigned int mo;
+  unsigned int year;   /* must hold yyyymm - ok to year 65K */
+  char ch,ch1,ch2;
+
+/* jan feb mar apr may jun jul aug sep oct nov dec */
+/* - strictly qmail datefmt dependent*/
+  for (;;s++) {
+    ch = *s;
+    if (ch != ' ' && (ch < '0' || ch > '9')) break;
+  }
+  mo = 0;
+  if (!(ch = *(s++))) return 0;
+  if (ch >= 'a')  ch -= ('a' - 'A');   /* toupper */
+  if (!(ch1 = *(s++))) return 0;       /* rfc822 hrds are case-insens */
+  if (ch1 >= 'a')  ch1 -= ('a' - 'A');
+  if (!(ch2 = *(s++))) return 0;
+  if (ch2 >= 'a')  ch2 -= ('a' - 'A');
+
+  switch (ch) {
+    case 'J':
+       if (ch1 == 'A' && ch2 == 'N') { mo = 1; break; }
+       if (ch1 == 'U') {
+         if (ch2 == 'N') mo = 6;
+         else if (ch2 == 'L') mo = 7;
+       }
+       break;
+    case 'F': if (ch1 == 'E' && ch2 == 'B') mo = 2; break;
+    case 'A':
+       if (ch1 == 'P' && ch2 == 'R') mo = 4;
+       else if (ch1 == 'U' && ch2 == 'G') mo = 8;
+       break;
+    case 'M':
+       if (ch1 != 'A') break;
+       if (ch2 == 'R') mo = 3;
+       else if (ch2 == 'Y') mo = 5;
+       break;
+    case 'S': if (ch1 == 'E' && ch2 == 'P') mo = 9; break;
+    case 'O': if (ch1 == 'C' && ch2 == 'T') mo = 10; break;
+    case 'N': if (ch1 == 'O' && ch2 == 'V') mo = 11; break;
+    case 'D': if (ch1 == 'E' && ch2 == 'C') mo = 12; break;
+    default:
+       break;
+  }
+  if (!mo || *(s++) != ' ')
+    return 0L;         /* mo true means s[0-2] valid */
+  year = 0L;
+  for (;;) {
+    register unsigned char chy;
+    chy = (unsigned char) *(s++);
+    if (chy < '0' || chy > '9') {
+      if (year) break;
+      else return 0;
+    }
+    year = year * 10 + (chy - '0');
+  }
+  return year * 100 + mo;
+}
+
+
diff --git a/dateline.c b/dateline.c
new file mode 100644 (file)
index 0000000..77a11bd
--- /dev/null
@@ -0,0 +1,41 @@
+/*$Id: dateline.c,v 1.2 1999/10/09 17:44:37 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "fmt.h"
+#include "yyyymm.h"
+#include "stralloc.h"
+
+static char strnum[FMT_ULONG];
+
+int dateline(dt,d)
+stralloc *dt; unsigned long d;
+/* converts yyyymm from unsigned long d to text dt */
+{
+  char *mo;
+  switch (d % 100) {
+    case 1: mo = "January"; break;
+    case 2: mo = "February"; break;
+    case 3: mo = "March"; break;
+    case 4: mo = "April"; break;
+    case 5: mo = "May"; break;
+    case 6: mo = "June"; break;
+    case 7: mo = "July"; break;
+    case 8: mo = "August"; break;
+    case 9: mo = "September"; break;
+    case 10: mo = "October"; break;
+    case 11: mo = "November"; break;
+    case 12: mo = "December"; break;
+    case 0: mo = "????"; break;
+    default: cgierr("I don't know any month > 12",
+               "","");
+  }
+  if (!stralloc_copys(dt,mo)) return -1;
+  if (!stralloc_cats(dt," ")) return -1;
+  if ((d/100)) {
+    if (!stralloc_catb(dt,strnum,fmt_ulong(strnum,d/100))) return -1;
+  } else
+    if (!stralloc_cats(dt,"????")) return 0;
+  return 1;
+}
+
+
diff --git a/decodeB.c b/decodeB.c
new file mode 100644 (file)
index 0000000..78406bc
--- /dev/null
+++ b/decodeB.c
@@ -0,0 +1,71 @@
+#include "stralloc.h"
+#include "strerr.h"
+#include "uint32.h"
+#include "errtxt.h"
+
+       /* Characters and translation as per rfc2047. */
+static char char64table[128] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+#define char64enc(c)  (((c) & 0x80) ? -1 : char64table[(c)])
+
+static void die_nomem(fatal)
+  char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+void decodeB(cpfrom,n,outdata,fatal)
+char *cpfrom;
+unsigned int n;
+stralloc *outdata;
+char *fatal;
+/* does B decoding of the string pointed to by cpfrom up to the character */
+/* before the one pointed to by cpnext, and appends the results to mimeline*/
+{
+  uint32 hold32;
+  char holdch[4] = "???";
+  int i,j;
+  char c;      /* needs to be signed */
+  char *cp, *cpnext;
+
+  cp = cpfrom;
+  cpnext = cp + n;
+  i = 0;
+  hold32 = 0L;
+  if (!stralloc_readyplus(outdata,n)) die_nomem(fatal);
+  for (;;) {
+    if (i == 4) {
+      for (j = 2; j >= 0; --j) {
+        holdch[j] = hold32 & 0xff;
+        hold32 = hold32 >> 8;
+      }
+      if (!stralloc_cats(outdata,holdch)) die_nomem(fatal);
+      if (cp >= cpnext)
+        break;
+      hold32 = 0L;
+      i = 0;
+    }
+    if (cp >= cpnext) {        /* pad */
+      c = 0;
+    } else {
+      c = char64enc(*cp);
+      ++cp;
+    }
+    if (c < 0)         /* ignore illegal characters */
+      continue;
+    else {
+      hold32 = (hold32 << 6) | (c & 0x7f);
+      ++i;
+    }
+  }
+}
+
diff --git a/decodeHDR.c b/decodeHDR.c
new file mode 100644 (file)
index 0000000..4693d3d
--- /dev/null
@@ -0,0 +1,92 @@
+/*$Id: decodeHDR.c,v 1.2 1998/02/28 19:03:02 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "strerr.h"
+#include "error.h"
+#include "case.h"
+#include "byte.h"
+#include "uint32.h"
+#include "mime.h"
+#include "errtxt.h"
+
+static void die_nomem(fatal)
+  char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+void decodeHDR(indata,n,outdata,charset,fatal)
+char *indata;
+unsigned int n;
+stralloc *outdata;
+char *charset;
+char *fatal;
+
+/* decodes indata depending on charset. May put '\n' and '\0' into out */
+/* data and can take them as indata. */
+{
+  unsigned int pos;
+  char *cp,*cpnext,*cpstart,*cpenc,*cptxt,*cpend,*cpafter;
+
+  cpnext = indata;
+  cpafter = cpnext + n;
+  cpstart = cpnext;
+  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(outdata,n)) die_nomem(fatal);
+  for (;;) {
+    cpstart = cpstart + byte_chr(cpstart,cpafter-cpstart,'=');
+    if (cpstart == cpafter)
+      break;
+    ++cpstart;
+    if (*cpstart != '?')
+      continue;
+    ++cpstart;
+    cpenc = cpstart + byte_chr(cpstart,cpafter-cpstart,'?');
+    if (cpenc == cpafter)
+      continue;
+    cpenc++;
+    cptxt = cpenc + byte_chr(cpenc,cpafter-cpenc,'?');
+    if (cptxt == cpafter)
+      continue;
+    cptxt++;
+    cpend = cptxt + byte_chr(cptxt,cpafter-cptxt,'?');
+    if (cpend == cpafter || *(cpend + 1) != '=')
+      continue;
+       /* We'll decode anything. On lists with many charsets, this may */
+       /* result in unreadable subjects, but that's the case even if   */
+       /* no decoding is done. This way, the subject will be optimal   */
+       /* for threading, but charset info is lost. We aim to correctly */
+       /* decode us-ascii and all iso-8859/2022 charsets. Exacly how   */
+       /* these will be displayed depends on dir/charset.              */
+    cp = cpnext;
+                       /* scrap lwsp between coded strings */
+    while (*cp == ' ' || *cp == '\t')
+      cp++;
+    if (cp != cpstart - 2)
+      if (!stralloc_catb(outdata,cpnext, cpstart - cpnext - 2))
+               die_nomem(fatal);
+   cpnext = cp + 1;
+   cpstart = cpnext;
+          switch (*cpenc) {
+            case 'b':
+            case 'B':
+              pos = outdata->len;
+              decodeB(cptxt,cpend-cptxt,outdata,2,fatal);
+              cpnext = cpend + 2;
+              cpstart = cpnext;
+              break;
+            case 'q':
+            case 'Q':
+              decodeQ(cptxt,cpend-cptxt,outdata,fatal);
+              cpnext = cpend + 2;
+              cpstart = cpnext;
+              break;
+            default:           /* shouldn't happen, but let's be reasonable */
+              cpstart = cpend + 2;
+              break;
+          }
+  }
+  if (!stralloc_catb(outdata,cpnext,indata-cpnext+n)) die_nomem(fatal);
+}
+
diff --git a/decodeQ.c b/decodeQ.c
new file mode 100644 (file)
index 0000000..7e5d388
--- /dev/null
+++ b/decodeQ.c
@@ -0,0 +1,77 @@
+/*$Id: decodeQ.c,v 1.3 1998/10/29 21:48:24 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "mime.h"
+
+/* takes a string pointed to by cpfrom and adds the next 'n' bytes to        */
+/* outdata, replacing any Quoted-Printable codes with the real characters.   */
+/* NUL and LF in the input are allowed, but anything that decodes to these   */
+/* values is ignored. */
+
+static char char16table[128] = {
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
+    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
+};
+
+#define char16enc(c)  (((c) & 0x80) ? -1 : char16table[(c)])
+
+static void die_nomem(fatal)
+  char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+void decodeQ(cpfrom,n,outdata,fatal)
+char *cpfrom;
+unsigned int n;
+stralloc *outdata;
+char *fatal;
+/* does Q decoding of the string pointed to by cpfrom up to the character */
+/* before the one pointed to by cpnext, and appends the results to mimeline*/
+{
+  char *cp,*cpnext,*cpmore;
+  char holdch[2];
+  char ch1,ch2;                /* need to be signed */
+
+  cpmore = cpfrom;
+  cp = cpfrom;
+  cpnext = cp + n;
+  if (!stralloc_readyplus(outdata,n)) die_nomem(fatal);
+
+  while (cp < cpnext) {
+    if (*cp == '_') *cp = ' ';         /* '_' -> space */
+    else if (*cp == '=') {             /* "=F8" -> '\xF8' */
+                                       /* copy stuff before */
+      if (!stralloc_catb(outdata,cpmore,cp-cpmore)) die_nomem(fatal);
+      cpmore = cp;
+      ++cp;
+      if (*cp == '\n') {               /* skip soft line break */
+        ++cp;
+        cpmore = cp;
+        continue;
+      }
+      ch1 = char16enc(*cp);
+      if (++cp >= cpnext)
+        break;
+      ch2 = char16enc(*cp);
+      if (ch1 >= 0 && ch2 >= 0) {      /* ignore illegals */
+        holdch[0] = (ch1 << 4 | ch2) & 0xff;
+        if (!stralloc_catb(outdata,holdch,1)) die_nomem(fatal);
+        cpmore += 3;
+      }
+    }
+    ++cp;
+  }                                    /* copy stuff after */
+  if (!stralloc_catb(outdata,cpmore,cpnext-cpmore)) die_nomem(fatal);
+}      
+
+
diff --git a/encodeB.c b/encodeB.c
new file mode 100644 (file)
index 0000000..1672de9
--- /dev/null
+++ b/encodeB.c
@@ -0,0 +1,99 @@
+/* $Id: encodeB.c,v 1.3 1998/03/21 18:30:27 lindberg Exp $*/
+/* $Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "uint32.h"
+#include "mime.h"
+#include "strerr.h"
+#include "errtxt.h"
+
+static void die_nomem(fatal)
+  char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static unsigned char base64char[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned int pos = 0;
+static unsigned int i = 0;
+static uint32 hold32;
+static unsigned char *cpout;
+
+static void addone(ch)
+unsigned char ch;
+{
+ if (!(pos++))
+    hold32 = (uint32) ch;
+  else
+    hold32 = (hold32 << 8) | ch;
+  if (pos == 3) {
+    *cpout++ = base64char[(hold32 >> 18) & 0x3f];
+    *cpout++ = base64char[(hold32 >> 12) & 0x3f];
+    *cpout++ = base64char[(hold32 >>  6) & 0x3f];
+    *cpout++ = base64char[hold32 & 0x3f];
+    if (++i == 18) {
+      *cpout++ = '\n';
+      i = 0;
+    }
+    pos = 0;
+  }
+}
+
+static void dorest()
+{
+  switch (pos) {
+    case 2:
+      hold32 = hold32 << 2;
+      *cpout++ = base64char[(hold32 >> 12) & 0x3f];
+      *cpout++ = base64char[(hold32 >> 06) & 0x3f];
+      *cpout++ = base64char[hold32 & 0x3f];
+      *cpout++ = '=';
+      break;
+    case 1:
+      hold32 = hold32 << 4;
+      *cpout++ = base64char[(hold32 >> 06) & 0x3f];
+      *cpout++ = base64char[hold32 & 0x3f];
+      *cpout++ = '=';
+      *cpout++ = '=';
+      break;
+    default:
+      break;
+  }
+  *cpout++ = '\n';
+}   
+
+void encodeB(indata,n,outdata,control,fatal)
+unsigned char *indata;
+unsigned int n;
+stralloc *outdata;
+int control;   /* 1 = init, 2 = flush */
+char *fatal;
+       /* converts any character with the high order bit set to */
+       /* base64. In: n chars of indata, out: stralloc outdata  */
+       /* as '=' is not allowed within the block, we cannot flush after */
+       /* each line, so we carry over data from call to call. The last  */
+       /* call to encodeB should have control = 2 to do the flushing.   */
+       /* control = 0 resets, and the routine starts out reset. */
+{
+  register unsigned char ch;
+
+  if (control == 1) {
+    pos = 0;
+    i = 0;
+  }
+  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(outdata,n*8/3 + n/72 + 5)) die_nomem(fatal);
+  cpout = (unsigned char *) outdata->s;
+  while (n--) {
+    ch = *indata++;
+    if (ch == '\n')
+      addone('\r');
+    addone(ch);
+  }
+  if (control == 2)
+    dorest();
+  outdata->len = (unsigned int) (cpout - (unsigned char *) outdata->s);
+}
+
diff --git a/encodeQ.c b/encodeQ.c
new file mode 100644 (file)
index 0000000..080b875
--- /dev/null
+++ b/encodeQ.c
@@ -0,0 +1,58 @@
+/* $Id: encodeQ.c,v 1.2 1998/02/28 19:03:02 lindberg Exp $*/
+/* $Name: ezmlm-idx-040 $*/
+
+#include "errtxt.h"
+#include "mime.h"
+#include "stralloc.h"
+#include "strerr.h"
+
+static void die_nomem(fatal)
+  char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static char *hexchar = "0123456789ABCDEF";
+
+void encodeQ(indata,n,outdata,fatal)
+char *indata;
+unsigned int n;
+stralloc *outdata;
+char *fatal;
+
+       /* converts any character with the high order bit set to */
+       /* quoted printable. In: n chars of indata, out: stralloc outdata*/
+
+{
+  register char *cpout;
+  register char ch;
+  unsigned int i;
+  char *cpin;
+
+  cpin = indata;
+  i = 0;
+       /* max 3 outchars per inchar  & 2 char newline per 72 chars */
+  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(outdata,n * 3 + n/36)) die_nomem(fatal); /* worst case */
+  cpout = outdata->s;
+  while (n--) {
+    ch = *cpin++;
+    if (ch != ' ' && ch != '\n' && ch != '\t' &&
+          (ch > 126 || ch < 33 || ch == 61)) {
+      *(cpout++) = '=';
+      *(cpout++) = hexchar[(ch >> 4) & 0xf];
+      *(cpout++) = hexchar[ch & 0xf];
+      i += 3;
+    } else {
+      if (ch == '\n')
+        i = 0;
+      *(cpout++) = ch;
+    }
+    if (i >= 72) {
+      *(cpout++) = '=';
+      *(cpout++) = '\n';
+      i = 0;
+    }
+  }
+  outdata->len = (unsigned int) (cpout - outdata->s);
+}
diff --git a/env.c b/env.c
new file mode 100644 (file)
index 0000000..05d527b
--- /dev/null
+++ b/env.c
@@ -0,0 +1,113 @@
+/* env.c, envread.c, env.h: environ library
+Daniel J. Bernstein, djb@silverton.berkeley.edu.
+Depends on str.h, alloc.h.
+Requires environ.
+19960113: rewrite. warning: interface is different.
+No known patent problems.
+*/
+
+#include "str.h"
+#include "alloc.h"
+#include "env.h"
+
+int env_isinit = 0; /* if env_isinit: */
+static int ea; /* environ is a pointer to ea+1 char*'s. */
+static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */
+
+static void env_goodbye(i) int i;
+{
+ alloc_free(environ[i]);
+ environ[i] = environ[--en];
+ environ[en] = 0;
+}
+
+static char *null = 0;
+
+void env_clear()
+{
+ if (env_isinit) while (en) env_goodbye(0);
+ else environ = &null;
+}
+
+static void env_unsetlen(s,len) char *s; int len;
+{
+ int i;
+ for (i = en - 1;i >= 0;--i)
+   if (!str_diffn(s,environ[i],len))
+     if (environ[i][len] == '=')
+       env_goodbye(i);
+}
+
+int env_unset(s) char *s;
+{
+ if (!env_isinit) if (!env_init()) return 0;
+ env_unsetlen(s,str_len(s));
+ return 1;
+}
+
+static int env_add(s) char *s;
+{
+ char *t;
+ t = env_findeq(s);
+ if (t) env_unsetlen(s,t - s);
+ if (en == ea)
+  {
+   ea += 30;
+   if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *)))
+    { ea = en; return 0; }
+  }
+ environ[en++] = s;
+ environ[en] = 0;
+ return 1;
+}
+
+int env_put(s) char *s;
+{
+ char *u;
+ if (!env_isinit) if (!env_init()) return 0;
+ u = alloc(str_len(s) + 1);
+ if (!u) return 0;
+ str_copy(u,s);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_put2(s,t) char *s; char *t;
+{
+ char *u;
+ int slen;
+ if (!env_isinit) if (!env_init()) return 0;
+ slen = str_len(s);
+ u = alloc(slen + str_len(t) + 2);
+ if (!u) return 0;
+ str_copy(u,s);
+ u[slen] = '=';
+ str_copy(u + slen + 1,t);
+ if (!env_add(u)) { alloc_free(u); return 0; }
+ return 1;
+}
+
+int env_init()
+{
+ char **newenviron;
+ int i;
+ for (en = 0;environ[en];++en) ;
+ ea = en + 10;
+ newenviron = (char **) alloc((ea + 1) * sizeof(char *));
+ if (!newenviron) return 0;
+ for (en = 0;environ[en];++en)
+  {
+   newenviron[en] = alloc(str_len(environ[en]) + 1);
+   if (!newenviron[en])
+    {
+     for (i = 0;i < en;++i) alloc_free(newenviron[i]);
+     alloc_free(newenviron);
+     return 0;
+    }
+   str_copy(newenviron[en],environ[en]);
+  }
+ newenviron[en] = 0;
+ environ = newenviron;
+ env_isinit = 1;
+ return 1;
+}
diff --git a/error.c b/error.c
index d51304f..f9b617d 100644 (file)
--- a/error.c
+++ b/error.c
@@ -17,7 +17,7 @@ ENOMEM;
 -2;
 #endif
 
 -2;
 #endif
 
-int error_noent = 
+int error_noent =
 #ifdef ENOENT
 ENOENT;
 #else
 #ifdef ENOENT
 ENOENT;
 #else
@@ -93,3 +93,10 @@ EACCES;
 #else
 -13;
 #endif
 #else
 -13;
 #endif
+
+int error_notdir =
+#ifdef ENOTDIR
+ENOTDIR;
+#else
+-14;
+#endif
diff --git a/error.h b/error.h
index 01bd3dc..42fdc81 100644 (file)
--- a/error.h
+++ b/error.h
@@ -16,6 +16,7 @@ extern int error_again;
 extern int error_pipe;
 extern int error_perm;
 extern int error_acces;
 extern int error_pipe;
 extern int error_perm;
 extern int error_acces;
+extern int error_notdir;
 
 extern char *error_str();
 extern int error_temp();
 
 extern char *error_str();
 extern int error_temp();
diff --git a/errtxt.h b/errtxt.h
new file mode 100644 (file)
index 0000000..ae82bf9
--- /dev/null
+++ b/errtxt.h
@@ -0,0 +1,156 @@
+/*$Id: errtxt.h,v 1.46 1999/11/29 04:54:01 lindberg Exp $*/
+/*Name: $*/
+
+#ifndef ERRTXT_H
+#define ERRTXT_H
+
+/* Error messages. If you translate these, I would urge you to keep the */
+/* English version as well. I'm happy to include any bilingual versions */
+/* of this file with future versions of ezmlm-idx.                      */
+
+#define ERR_NOMEM "out of memory"
+#define ERR_NOCMD "command not available"
+#define ERR_CLOSE "unable to close "
+#define ERR_WRITE "unable to write "
+#define ERR_READ "unable to read "
+#define ERR_READ_KEY "unable to read key"
+#define ERR_FLUSH "unable to flush "
+#define ERR_SEEK "unalble to seek "
+#define ERR_SYNC "unable to sync "
+#define ERR_CHMOD "unable to chmod "
+#define ERR_STAT "unable to stat "
+#define ERR_DELETE "unable to delete "
+#define ERR_READ_INPUT "unable to read input: "
+#define ERR_SEEK_INPUT "unable to seek input: "
+#define ERR_CREATE "unable to create "
+#define ERR_MOVE "unable to move "
+#define ERR_OPEN "unable to open "
+#define ERR_OBTAIN "unable to obtain "
+#define ERR_OPEN_LOCK "unable to open lock: "
+#define ERR_OBTAIN_LOCK "unable to obtain lock: "
+#define ERR_NOLOCAL "LOCAL not set"
+#define ERR_NODTLINE "DTLINE not set"
+#define ERR_NOSENDER "SENDER not set"
+#define ERR_NOHOST "HOST not set"
+#define ERR_NOEXIST " does not exist"
+#define ERR_NOEXIST_KEY " key does not exist"
+#define ERR_SWITCH "unable to switch to "
+#define ERR_BOUNCE "I do not reply to bounce messages (#5.7.2)"
+#define ERR_ANONYMOUS "I do not reply to senders without host names (#5.7.2)"
+#define ERR_NOT_PUBLIC "Sorry, I've been told to reject all requests (#5.7.2)"
+#define ERR_NOT_ARCHIVED "Sorry, this list is not archived (#5.1.1)"
+#define ERR_NOT_INDEXED "Sorry, this list is not indexed (#5.1.1)"
+#define ERR_NOT_AVAILABLE "Command not available (#5.1.1)"
+#define ERR_NOT_ALLOWED "Command allowed only to moderators (#5.7.1)"
+#define ERR_BAD_ADDRESS "I don't accept messages at this address (inlocal and/or inhost don't match) (#5.1.1)"
+#define ERR_BAD_RETURN_ADDRESS "Invalid bounce or receipt address format (#5.1.1)"
+#define ERR_BAD_REQUEST "Illegal request format (#5.7.1)"
+#define ERR_QMAIL_QUEUE "unable to run qmail-queue: "
+#define ERR_TMP_QMAIL_QUEUE "temporary qmail-queue error: "
+#define ERR_NOT_PARENT "this message is not from my parent list (#5.7.2)"
+#define ERR_SUBLIST "sublist messages must have a Mailing-List header (#5.7.2)"
+#define ERR_MAILING_LIST "message already has a Mailing-List header (maybe I should be a sublist) (#5.7.2)"
+#define ERR_LOOPING "this message is looping: it already has my Delivered-To line (#5.4.6)"
+#define ERR_SUBSCRIBER_CAN "only subscribers can "
+#define ERR_571 " (#5.7.1)"
+#define ERR_EMPTY_DIGEST "nothing to digest"
+#define ERR_EMPTY_LIST "no messages in archive"
+#define ERR_NOINDEX "Sorry, I can't find the index for this message"
+#define ERR_BAD_INDEX "Old format or corrupted index. Run ezmlm-idx! (#5.3.0)"
+#define ERR_BAD_DIGCODE "incorrect digest code (#5.7.1)"
+#define ERR_UNEXPECTED "program logic error (#5.3.0)"
+#define ERR_BAD_ALL "Sorry, after removing unacceptable MIME parts from your message I was left with nothing (#5.7.0)"
+#define ERR_MIME_QUOTE "MIME boundary lacks end quote"
+#define ERR_SUBST_UNSAFE "Sorry, substitution of target addresses into headers with <#A#> or <#T#> is unsafe and not permitted."
+
+/* ezmlm-request unique */
+#define ERR_REQ_LISTNAME "This command requires a mailing list name (#5.1.1)"
+#define ERR_REQ_LOCAL "the local part of the command string does not match this list (#5.1.1)"
+
+/* ezmlm-reject unique */
+#define ERR_MAX_SIZE "Sorry, I don't accept messages larger than "
+#define ERR_MIN_SIZE "Sorry, I don't accept messages shorter than "
+#define ERR_SIZE_CODE " (#5.2.3)"
+#define ERR_NO_ADDRESS "List address must be in To: or Cc: (#5.7.0)"
+#define ERR_NO_SUBJECT "Sorry, I don't accept message with empty Subject (#5.7.0)"
+#define ERR_SUBCOMMAND "Sorry, I don't accept commands in the subject line. Please send a message to the -help address shown in the the ``Mailing-List:'' header for command info (#5.7.0)"
+#define ERR_BODYCOMMAND "Sorry, as the message starts with ``[un]subscribe'' it looks like an adminstrative request. Please send a message to the -help address shown in the ``Mailing-List:'' header for [un]subscribe info (#5.7.0)"
+#define ERR_BAD_TYPE "Sorry, I don't accept messages of MIME Content-Type '"
+#define ERR_BAD_PART "Sorry, a message part has an unacceptable MIME Content-Type: "
+#define ERR_JUNK "Precedence: junk - message ignored"
+
+/* ezmlm-manage unique */
+#define ERR_SUB_NOP "target is already a subscriber"
+#define ERR_UNSUB_NOP "target is not a subscriber"
+#define ERR_BAD_NAME "only letters and underscore allowed in file name (#5.6.0)"
+#define ERR_NO_MARK "missing start-of-text or end-of-text mark (#5.6.0)"
+#define ERR_EDSIZE "Maximum edit file size exceeded (#5.6.0)"
+#define ERR_BAD_CHAR "NUL or other illegal character in input (#5.6.0)"
+#define ERR_EXTRA_SUB "Processed SENDER check addition request for: "
+#define ERR_EXTRA_UNSUB "Processed SENDER check removal request for: "
+
+
+/* ezmlm-moderation functions unique */
+#define ERR_MOD_TIMEOUT "I'm sorry, I no longer have this message"
+#define ERR_MOD_ACCEPTED "I'm sorry, I've already accepted this message"
+#define ERR_MOD_REJECTED "I'm sorry, I've already rejected this message"
+#define ERR_MOD_COOKIE "Illegal or outdated moderator request (#5.7.1)"
+#define ERR_FORK "unable to fork: "
+#define ERR_EXECUTE "unable to execute "
+#define ERR_CHILD_CRASHED "child crashed"
+#define ERR_CHILD_FATAL "fatal error from child"
+#define ERR_CHILD_TEMP "temporary error from child"
+#define ERR_CHILD_UNKNOWN "unknown error from child"
+#define ERR_UNIQUE "unable to create unique message file name"
+#define ERR_NO_POST "I'm sorry, you are not allowed to post messages to this list (#5.7.2)"
+
+/* ezmlm-make unique */
+#define ERR_VERSION "ezmlmrc version mismatch. Behavior may not match docs."
+#define ERR_ENDTAG "tag lacks /> end marker: "
+#define ERR_LINKDIR "linktag lacks /dir: "
+#define ERR_FILENAME "continuation tag without defined file name: "
+#define ERR_PERIOD "periods not allowed in tags: "
+#define ERR_SLASH "dir and dot must start with slash"
+#define ERR_NEWLINE "newlines not allowed in dir"
+#define ERR_QUOTE "quotes not allowed in dir"
+#define ERR_SYNTAX " syntax error: "
+
+/* ezmlm-limit unique */
+#define ERR_EXCESS_MOD "excess traffic: moderating"
+#define ERR_EXCESS_DEFER "excess traffic: deferring"
+
+/* ezmlm-cron unique */
+#define ERR_SAME_HOST "list and digest must be on same host"
+#define ERR_DOW "single comma-separated digits only for day-of-week"
+#define ERR_NOT_CLEAN "Bad character in address components"
+#define ERR_SUID "Sorry, I won't run as root"
+#define ERR_UID "user id not found"
+#define ERR_EUID "effective user id not found"
+#define ERR_BADUSER "user not allowed"
+#define ERR_BADHOST "list host not allowed"
+#define ERR_BADLOCAL "list local not allowed"
+#define ERR_LISTNO "max number of list entries exceeded"
+#define ERR_NO_MATCH "no matching entry found"
+#define ERR_SETUID "unable to set uid: "
+#define ERR_CFHOST "bounce-host required on first line of "
+#define ERR_EXCLUSIVE "action-controlling switches are mutually exclusive"
+#define ERR_CRONTAB "crontab update failed. Contact you sysadmin with the above error information"
+
+/* ezmlm-gate */
+#define ERR_REJECT "Sorry, I've been told to reject this message (#5.7.0)"
+
+/* issub/subscribe ... */
+#define ERR_ADDR_AT "address does not contain @"
+#define ERR_ADDR_LONG "address is too long"
+#define ERR_ADDR_NL "address contains newline"
+
+/* sql */
+#define ERR_COOKIE "message does not have valid authentication token"
+#define ERR_NOT_ACTIVE "this sublist is not active"
+#define ERR_PARSE "unable to parse "
+#define ERR_DONE "message already successfully processed by this list"
+#define ERR_MAX_BOUNCE "max bounces exceeded: bounce will not be saved"
+#define ERR_NO_TABLE "no table specified in database connect data"
+
+#endif
+
diff --git a/ezcgi.css b/ezcgi.css
new file mode 100644 (file)
index 0000000..f4c4f87
--- /dev/null
+++ b/ezcgi.css
@@ -0,0 +1,24 @@
+BODY { background-color: #ffffe0; margin-left: 5%; margin-right: 5% }
+
+  a:link { color: black }
+  a:active { color: black }
+
+  H1 { color: red; font-size: 200% ; text-align: center}
+  H2 { color: green; font-size: 150%; text-align: left }
+
+  HR { border: medium; color: #00426B }
+
+  DIV.idx { margin-left: 5%; margin-right: 5% }
+  a.alk { color: green; font-style: italic }
+
+  LI.subjbody { margin-left: 15% }
+  LI.authbody { margin-left: 10% }
+
+  DIV.rfc822hdr { text-align: left; font-size: 100% }
+    EM.rfc822hdr { font-weight: bold; font-family: arial, sans-serif }
+      SPAN.subject { font-weight: bold; font-size: 150% }
+       a.relk { color: red }
+
+DIV.copyright { font-size: 50%; text-align: right }
+
+
diff --git a/ezcgirc b/ezcgirc
new file mode 100644 (file)
index 0000000..13e101f
--- /dev/null
+++ b/ezcgirc
@@ -0,0 +1,15 @@
+# listno;[-]UID;DIR;[-]listaddr;button[,button ...];style;banner
+
+# Default list. "alias" UID=7771. One extra button pointing to my home page ;-)
+0;7771;/var/qmail/alias/QMAIL;qmail@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg
+
+# the real qmail archive. Because of '-' before the list name, the from
+# address is not shown, only the associated "handle". More buttons here.
+1;7771;/var/qmail/alias/QMAIL;-qmail@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg,[qmail.org]=http://www.qmail.org,[djb]=http://www.pobox.com/~djb/qmail.html
+
+# This is another alias list. The '-' before the 7771 suppresses the chroot(),
+# which is needed since banner program "./niles" uses /bin/sh, cat, etc. The
+# style sheet is specified as well. Blank lines are ok, but all chars on config
+# lines are significant.
+2;-7771;/var/qmail/alias/SAMBA;samba@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg;iso-8859-1;/ezcgi.css;./niles
+
diff --git a/ezmlm-accept.1 b/ezmlm-accept.1
new file mode 100644 (file)
index 0000000..bbb86f3
--- /dev/null
@@ -0,0 +1,30 @@
+.TH ezmlm-accept 1
+.SH NAME
+ezmlm-accept \- accept messages in moderation queue
+.SH SYNOPSIS
+.B ezmlm-accept
+.I dir
+.I file
+[
+.I file1 ...
+]
+.SH DESCRIPTION
+.B ezmlm-accept
+copies
+.IR file ,
+.IR file1 ,\ ...
+to
+.B ezmlm-send
+.IR dir .
+.B ezmlm-accept
+removes each file that was successfully processed by
+.BR ezmlm-send .
+
+This can be used to manually ``accept'' messages in a
+.I ezmlm
+moderation queue.
+.SH "SEE ALSO"
+ezmlm(5),
+ezmlm-moderate(1),
+ezmlm-send(1),
+ezmlm-store(1)
diff --git a/ezmlm-accept.sh b/ezmlm-accept.sh
new file mode 100644 (file)
index 0000000..b723259
--- /dev/null
@@ -0,0 +1,30 @@
+# [should have a bin/sh line and EZPATH added above by make]
+#
+# script to accept files in DIR/mod/pending. Use as:
+# ezmlm-accept DIR file1 [file2 ...]
+# where ``DIR'' is the list directory and ``file1'' is a file to be
+# accepted. ``ezmlm-accept DIR DIR/mod/pending/*'' will accept all
+# pending files. Files that are successfully sent to the list are
+# deled. See man page for details.
+
+EZSEND="${EZPATH}/ezmlm-send"
+FATAL='ezmlm-accept: fatal:'
+if [ ! -x "$EZSEND" ]; then
+  echo "$FATAL please edit script to the correct ezmlm-send path"
+  exit 100;
+fi
+
+DIR="$1"
+
+if [ -z "$1" ] || [ -z "$2" ]; then
+  echo "$FATAL usage: ezmlm-accept DIR file1 [file2 ...]"
+  exit 100;
+fi
+
+while [ -n "$2" ]; do
+  if [ -x "$2" ]; then
+    $EZSEND $DIR < "$2" && rm -f "$2"
+  fi
+  shift
+done
+exit 0;
diff --git a/ezmlm-archive.1 b/ezmlm-archive.1
new file mode 100644 (file)
index 0000000..ca764f8
--- /dev/null
@@ -0,0 +1,178 @@
+.TH ezmlm-archive 1
+.SH NAME
+ezmlm-archive \- create thread and author index for a mailing list archive
+.SH SYNOPSIS
+.B ezmlm-archive
+[
+.B \-cCFTvV
+][
+.B \-f\fI msg1
+]
+][
+.B \-t\fI msg2
+]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-archive
+reads the index files from a message archive, and creates a subject index, a
+collection of subject files, and a collection of author files. These
+files are suitable as an index for WWW access to, and navigation through
+a mailing list archive by
+.BR ezmlm-cgi(1) .
+
+The index files read are created by
+.B ezmlm-idx(1)
+on a per-list basis and by
+.B ezmlm-send(1)
+on a per-message archive for a indexed list.
+
+The output files created are:
+.TP
+.I dir\fB/archive/threads/yyyymm
+The thread index. It contains one line per subject, starting with the
+number of the first message with that subject within the set
+investigated, ``:'', a 20 character
+subject hash, blank, ``\[n\]'' where ``n'' is the number of messages in the
+thread, blank, and the subject.
+The file ``yyyymm'' contains
+entries for all threads that have messages in the month ``yyyymm''
+or that have messages both before and after that month.
+The subject hash is a key to the subject files; the message number is
+a key to the index file.
+The lines are in ascending order by message number when the index is
+created
+.I de novo
+on an existing archive. When the messages are added one-by-one as in normal
+archive operation, ``n'' is the number of message in the thread
+.I for the particular month
+and the order is in reverse of latest message, i.e. the last extended thread
+is shown last. The message number accompanying a thread is
+always a message within the thread. It is the first in
+archives created
+on existing lists, and the last message in incrementally created archives.
+Use the corresponding subject index file to get a list of all
+messages in the thread in ascending order.
+.TP
+.I dir\fB/archive/subjects/xx/yyyyyyyyyyyyyyyyyy
+A subject file. The first line is the subject hash, a space, and the subject.
+This is followed by one line per message with this subject, in the format
+message number, ``:'', date (yyyymm), ``:'',
+author hash, blank, author from line. The lines are
+sorted by message number. The author hash is a key to the author files;
+the message number is a key to the index file. The file in the example
+would be for the subject hash ``xxyyyyyyyyyyyyyyyyyy''.
+.TP
+.I dir\fB/archive/authors/xx/yyyyyyyyyyyyyyyyyy
+An author file. The first line is the author hash, a space, and the author
+from line.
+This is followed by one line per message with this author, in the format
+message number, ``:'', date (yyyymm), ``:'',
+subject hash, blank, subject. The lines are
+sorted by message number. The subject hash is a key to the subject files;
+the message number is a key to the index file. The file in the example
+would be for the author hash ``xxyyyyyyyyyyyyyyyyyy''.
+
+.I dir\fB/archnum
+keeps track of the last message processed. Normally,
+.B ezmlm-archive
+will process entries for messages from one above the contents of this file
+up to an including the message number in
+.IR dir\fB/num .
+.SH OPTIONS
+.B ezmlm-archive
+writes messages in a crash-proof manner when run in normal mode. When overriding
+the normal message range with any of the options listed, the normal
+.B sync(3)
+of the output files is suppressed for efficiency. Should the computer crash
+during this time the state of the indices is not defined. Use the
+.B \-s
+option in the (extremely rare) cases where this would be a problem.
+.TP
+.B \-c
+Create a new index. This  overrides
+.I dir\fB/archnum
+causing
+.B ezmlm-archive
+to start with the first message in the archive. Synonym for
+.BR \-f\fI0 .
+.B NOTE:
+.B ezmlm-archive
+does not remove files in the index. While it will overwrite/update old files
+it will not remove files that are obsolete for other reasons.
+.TP
+.B \-C
+(Default.)
+Process entries starting with the message after the message listed in
+.IR dir\fB/archnum .
+.TP
+.B \-f\fI msg1
+Process messages from the archive section (set of 100 messages)
+containing message
+.IR msg1 .
+This is useful if you have removed part of the archive, as it will shorten
+processing time and decrease memory use.
+.B NOTE:
+.B ezmlm-archive
+does not remove files in the index. While it will overwrite/update old files
+it will not remove files that are obsolete for other reasons. The number of
+messages per thread will be incorrect when using of the
+.B \-f
+and
+.B \-t
+switches leads to partial re-indexing of already indexed messages.
+.TP
+.B \-F
+(Default.)
+Do not change the starting message from the default
+(see
+.BR \-C ).
+.TP
+.B \-s
+Always sync files.
+.TP
+.B \-S
+(Default.)
+Sync files, except when on of the message range modifying options is
+used.
+.TP
+.B \-t\fI msg2
+Process messages to message
+.I msg2
+instead of the last message in the archive. Again, files written are
+corrected, but other files are not explicitly removed.
+.TP
+.B \-T
+(Default.)
+Process entries for messages up to the last message in the archive.
+.TP
+.B \-v
+Display
+.B ezmlm-archive
+version info.
+.TP
+.B \-V
+Display
+.B ezmlm-archive
+version info.
+.SH "MEMORY USAGE"
+.B ezmlm-archive
+stores its linked lists in memory. On at 32-bit architecture, it uses
+12 bytes per message, 28 bytes per thread (plus one copy of the subject),
+and 20 bytes per author (plus one copy of the author from line).
+
+In normal list use, it processes only at most a few messages at a time,
+but for initial processing of a large archive, considerable amounts of
+memory may be used. Assuming
+40 bytes for subject/from line, 5 messages per thread, 100,000 messages,
+and 1000 authors, this is 2.5 MB. For 1,000,000 messages this is about 20 MB.
+
+Thus, for large archives, it may be useful to use the
+.I \-t
+switch to process the archive in multiple subsets, starting with e.g. the first
+100,000, then the next, and so on.
+.SH "SEE ALSO"
+ezmlm-cgi(1),
+ezmlm-idx(1),
+ezmlm-send(1),
+ezmlm(5)
+
diff --git a/ezmlm-archive.c b/ezmlm-archive.c
new file mode 100644 (file)
index 0000000..9026789
--- /dev/null
@@ -0,0 +1,479 @@
+/*$Id: ezmlm-archive.c,v 1.13 1999/11/28 20:13:32 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "alloc.h"
+#include "error.h"
+#include "stralloc.h"
+#include "str.h"
+#include "sig.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "getln.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "idxthread.h"
+#include "makehash.h"
+#include "idx.h"
+#include "errtxt.h"
+
+#define FATAL "ezmlm-archive: fatal: "
+#define WARNING "ezmlm-archive: warning: inconsistent index: "
+
+substdio ssin;
+char inbuf[1024];
+substdio ssout;
+char outbuf[1024];
+substdio ssnum;
+char numbuf[16];
+
+stralloc line = {0};
+stralloc num = {0};
+stralloc fn = {0};
+stralloc fnn = {0};
+
+char strnum[FMT_ULONG];
+int flagerror = 0;
+int flagsync = 1;      /* sync() by default, not for -c or -f or -t */
+char *dir;
+
+struct ca {
+  char *s;             /* start */
+  unsigned int l;      /* length */
+} ca;
+
+void die_usage() {
+  strerr_die1x(100,
+    "ezmlm-archive: usage: "
+       "ezmlm-archive [-cCFsSTvV] [-f min_msg] [-t max_msg] dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void close_proper(ss,s,sn)
+/* flush,sync,close,move sn->s) */
+substdio *ss;
+char *s, *sn;
+{
+   if (substdio_flush(ss) == -1)
+     strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/",s,": ");
+  if (flagsync)
+    if (fsync(ss->fd) == -1)
+       strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/",s,": ");
+  if (close(ss->fd) == -1)
+     strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/",s,": ");
+  if (rename(sn,s) == -1)
+     strerr_die6sys(111,FATAL,ERR_MOVE,dir,"/",sn,": ");
+}
+
+void write_threads(msgtable,subtable,authtable,datetable,from,to)
+/* Add the current threading data to the thread database without dups */
+/* Writes the subject index first, then processes the individual files */
+msgentry *msgtable; subentry *subtable; authentry *authtable;
+dateentry *datetable;
+unsigned long from,to;
+{
+  msgentry *pmsgt;
+  subentry *psubt,*psubtm, *psubtlast;
+  subentry *presubt = (subentry *)0;
+  authentry *pautht;
+  dateentry *pdatet;
+  char *cp,*cp1;
+  unsigned long msg;
+  unsigned long ulmsginthread;
+  unsigned long subnum;
+  unsigned long authnum;
+  unsigned long msgnum;
+  unsigned int pos,l;
+  unsigned int startdate,nextdate;
+  unsigned int startmsg,nextmsg;
+  int fd = -1;
+  int fdn = -1;
+  int match;
+  int ffound;
+  int lineno;
+  int res;
+
+  psubtm = subtable;           /* now for new threads */
+  pdatet = datetable;
+  nextmsg = 0L;
+  nextdate = pdatet->date;
+  while (psubtm->sub) {                /* these are in msgnum order */
+    if (!presubt)              /* for rewind */
+      if (psubtm->lastmsg >= nextmsg)
+       presubt = psubtm;       /* this thread extends beyond current month */
+    if (psubtm->firstmsg >= nextmsg) { /* done with this month */
+      if (fdn != -1) close_proper(&ssout,fn.s,fnn.s);
+      psubtlast = psubtm;              /* last thread done */
+      if (presubt)                     /* need to rewind? */
+       psubtm = presubt;               /* do it */
+      psubt = psubtm;                  /* tmp pointer to reset done flag */
+      presubt = (subentry *)0;         /* reset rewind pointer */
+      pdatet++;                                /* next month */
+      startdate = nextdate;            /* startdate */
+      nextdate = pdatet->date;         /* end date */
+      startmsg = nextmsg;              /* first message in month */
+      nextmsg = pdatet->msg;           /* first message in next month */
+      if (!stralloc_copys(&fn,"archive/threads/")) die_nomem();
+      if (!stralloc_catb(&fn,strnum,fmt_uint(strnum,startdate))) die_nomem();
+      if (!stralloc_copy(&fnn,&fn)) die_nomem();
+      if (!stralloc_0(&fn)) die_nomem();
+      if (!stralloc_cats(&fnn,"n")) die_nomem();
+      if (!stralloc_0(&fnn)) die_nomem();
+      if ((fdn = open_trunc(fnn.s)) == -1)
+       strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fnn.s,": ");
+      substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf));
+      if ((fd = open_read(fn.s)) == -1) {
+      if (errno != error_noent)
+             strerr_die6sys(111,FATAL,ERR_OPEN,dir,"/",fn.s,": ");
+      } else {
+       substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+      for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+             strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": ");
+      if (!match) break;
+      pos = scan_ulong(line.s,&msgnum);
+      pos++;                   /* skip ':' */
+      if (msgnum >= from)
+       continue;               /* ignore entries from threading range */
+      if (line.len < pos + HASHLEN) {
+       flagerror = -1;         /* and bad ones */
+       continue;
+      }
+      psubt = subtable;
+      cp = line.s + pos;
+      ffound = 0;              /* search among already known subjects */
+      for (;;) {
+       res = str_diffn(psubt->sub,cp,HASHLEN);
+       if (res < 0) {
+         if (psubt->higher)
+           psubt = psubt->higher;
+        else
+          break;
+       } else if (res > 0) {
+         if (psubt->lower)
+           psubt = psubt->lower;
+         else
+           break;
+       } else {
+         ffound = 1;
+         break;
+       }
+      }
+      if (!ffound) {
+       if (substdio_put(&ssout,line.s,line.len) == -1)
+         strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+      } else {                 /* new # of msg in thread */
+       cp += HASHLEN;          /* HASHLEN [#] Subject always \n at end */
+       if (*(cp++) == ' ' && *(cp++) == '[') {
+         cp += scan_ulong(cp,&ulmsginthread);
+         if (*cp == ']') {
+           psubt->msginthread += (unsigned char) (ulmsginthread & 0xff);
+         }
+       } else
+         flagerror = -5;
+      }
+    }
+    close(fd);
+  }
+  continue;
+  }
+
+    if (psubtm->firstmsg < nextmsg && psubtm->lastmsg >= startmsg) {
+    if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,psubtm->lastmsg)))
+               die_nomem();
+    if (!stralloc_cats(&line,":")) die_nomem();
+    if (!stralloc_catb(&line,psubtm->sub,HASHLEN)) die_nomem();
+    if (!stralloc_cats(&line," [")) die_nomem();
+    if (!stralloc_catb(&line,strnum,
+       fmt_ulong(strnum,(unsigned long) psubtm->msginthread)))
+               die_nomem();
+    if (!stralloc_cats(&line,"]")) die_nomem();
+    if (!stralloc_catb(&line,psubtm->sub + HASHLEN,psubtm->sublen - HASHLEN))
+                        die_nomem();   /* has \n */
+    if (substdio_put(&ssout,line.s,line.len) == -1)
+       strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+    }
+  psubtm++;
+  }
+  if (fdn != -1)
+    close_proper(&ssout,fn.s,fnn.s);
+
+  psubt = subtable;
+  while (psubt->sub) {         /* now the threads */
+    if (!stralloc_copys(&fn,"archive/subjects/")) die_nomem();
+    if (!stralloc_catb(&fn,psubt->sub,2)) die_nomem();
+    if (!stralloc_0(&fn)) die_nomem();
+    if (mkdir(fn.s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fn.s,": ");
+    fn.s[fn.len - 1] = '/';
+    if (!stralloc_catb(&fn,psubt->sub+2,HASHLEN-2)) die_nomem();
+    if (!stralloc_copy(&fnn,&fn)) die_nomem();
+    if (!stralloc_cats(&fnn,"n")) die_nomem();
+    if (!stralloc_0(&fn)) die_nomem();
+    if (!stralloc_0(&fnn)) die_nomem();
+    if ((fdn = open_trunc(fnn.s)) == -1)
+      strerr_die4sys(111,FATAL,ERR_CREATE,fnn.s,": ");
+    substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf));
+    if ((fd = open_read(fn.s)) == -1) {
+      if (errno != error_noent)
+         strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+      if (substdio_puts(&ssout,psubt->sub) == -1)      /* write subject */
+            strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+    } else {                                   /* copy data */
+       substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+       lineno = 0;
+       for (;;) {
+         if (getln(&ssin,&line,&match,'\n') == -1)
+             strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": ");
+          if (!match) break;
+         if (!lineno) {                        /* write subject */
+           if (line.len < HASHLEN + 1 || line.s[HASHLEN] != ' ')
+               flagerror = -3;
+           if (substdio_put(&ssout,line.s,line.len) == -1)
+              strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+           lineno = 1;
+           continue;
+         }
+         (void) scan_ulong(line.s,&msgnum);
+         if (msgnum >= from) break;
+         if (substdio_put(&ssout,line.s,line.len) == -1)
+            strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+       }
+       (void) close(fd);       /* close old index */
+      }
+
+    subnum = (unsigned long) (psubt - subtable + 1);   /* idx of this subj */
+    pmsgt = msgtable + psubt->firstmsg - from; /* first message entry */
+    for (msg = psubt->firstmsg; msg <= psubt->lastmsg; msg++) {
+      if (pmsgt->subnum == subnum) {
+        if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem();
+        if (!stralloc_cats(&line,":")) die_nomem();
+       if (!stralloc_catb(&line,strnum,fmt_uint(strnum,pmsgt->date)))
+               die_nomem();
+       if (!stralloc_cats(&line,":")) die_nomem();
+        if (pmsgt->authnum) {
+         pautht = authtable + pmsgt->authnum - 1;
+         cp = pautht->auth;
+         cp1 = cp + str_chr(cp,' ');
+         if (cp + HASHLEN != cp1)
+           strerr_die1x(100,ERR_BAD_INDEX);
+         if (!stralloc_cats(&line,cp))
+               die_nomem();                            /* hash */
+       } else
+          if (!stralloc_cats(&line,"\n")) die_nomem();
+       if (substdio_put(&ssout,line.s,line.len) == -1)
+         strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+      }
+      pmsgt++;
+    }
+    close_proper(&ssout,fn.s,fnn.s);
+    psubt++;
+  }
+
+                                       /* (no master author index) */
+  pautht = authtable;
+  while (pautht->auth) {               /* now the authors */
+    if (!stralloc_copys(&fn,"archive/authors/")) die_nomem();
+    if (!stralloc_catb(&fn,pautht->auth,2)) die_nomem();
+    if (!stralloc_0(&fn)) die_nomem();
+    if (mkdir(fn.s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fn.s,": ");
+    fn.s[fn.len - 1] = '/';
+    if (!stralloc_catb(&fn,pautht->auth+2,HASHLEN-2)) die_nomem();
+    if (!stralloc_copy(&fnn,&fn)) die_nomem();
+    if (!stralloc_cats(&fnn,"n")) die_nomem();
+    if (!stralloc_0(&fn)) die_nomem();
+    if (!stralloc_0(&fnn)) die_nomem();
+    if ((fdn = open_trunc(fnn.s)) == -1)
+      strerr_die4sys(111,FATAL,ERR_CREATE,fnn.s,": ");
+    substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf));
+      if ((fd = open_read(fn.s)) == -1) {
+       if (errno != error_noent)
+         strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+        else {                 /* didn't exist before: write author */
+          if (substdio_put(&ssout,pautht->auth,pautht->authlen) == -1)
+            strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+       }
+      } else {                                 /* copy data */
+       substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+       lineno = 0;
+       for (;;) {
+         if (getln(&ssin,&line,&match,'\n') == -1)
+             strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": ");
+          if (!match) break;
+         if (!lineno) {                        /* write author */
+           if (line.len < HASHLEN + 1 || line.s[HASHLEN] != ' ')
+               flagerror = - 4;
+           if (substdio_put(&ssout,line.s,line.len) == -1)
+              strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+           lineno = 1;
+           continue;
+         }
+         (void) scan_ulong(line.s,&msgnum);
+         if (msgnum >= from) break;
+         if (substdio_put(&ssout,line.s,line.len) == -1)
+            strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+       }
+       (void) close(fd);                       /* close old index */
+      }
+
+    authnum = (unsigned long) (pautht - authtable + 1);        /* idx of this auth */
+    pmsgt = msgtable + pautht->firstmsg - from;        /* first message entry */
+    for (msg = pautht->firstmsg; msg <= to; msg++) {
+      if (pmsgt->authnum == authnum) {
+        if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem();
+        if (!stralloc_cats(&line,":")) die_nomem();
+       if (!stralloc_catb(&line,strnum,fmt_uint(strnum,pmsgt->date)))
+               die_nomem();
+       if (!stralloc_cats(&line,":")) die_nomem();
+        if (pmsgt->subnum) {
+         psubt = subtable + pmsgt->subnum - 1;
+          if (!stralloc_catb(&line,psubt->sub,psubt->sublen))
+               die_nomem();
+       }
+       if (substdio_put(&ssout,line.s,line.len) == -1)
+         strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+      }
+      pmsgt++;
+    }
+    close_proper(&ssout,fn.s,fnn.s);
+    pautht++;
+  }
+}
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+  unsigned long archnum = 0L;
+  unsigned long to = 0L;
+  unsigned long max;
+  int fd;
+  int fdlock;
+  int flagcreate = 0;
+  int flagsyncall = 0;
+  int opt;
+  msgentry *msgtable;
+  subentry *subtable;
+  authentry *authtable;
+  dateentry *datetable;
+
+  (void) umask(022);
+  sig_pipeignore();
+
+  while ((opt = getopt(argc,argv,"cCf:FsSt:TvV")) != opteof)
+    switch (opt) {
+      case 'c':        flagcreate = 1;
+               flagsync = 0;
+               break;                  /* start at beginning of archive */
+      case 'C': flagcreate = 0;
+               break;  /* Do only archnum+1 => num */
+      case 'f': if (optarg) {
+                 (void) scan_ulong(optarg,&archnum);
+                 archnum = (archnum / 100) * 100;
+               }
+               flagsync = 0;
+               break;
+      case 'F': archnum = 0; break;
+      case 's': flagsyncall = 1; break;
+      case 'S': flagsyncall = 0; break;
+      case 't': if (optarg) {
+                 (void) scan_ulong(optarg,&to);
+               }
+               flagsync = 0;
+               break;
+      case 'T': to = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-archive version: ",EZIDX_VERSION);
+      default:
+        die_usage();
+    }
+
+  if (flagsyncall) flagsync = 1;       /* overrides */
+  dir = argv[optind++];
+  if (!dir) die_usage();
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  if (mkdir("archive/threads",0755) == -1)
+    if (errno != error_exist)
+      strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/threads: ");
+  if (mkdir("archive/subjects",0755) == -1)
+    if (errno != error_exist)
+      strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/subjects: ");
+  if (mkdir("archive/authors",0755) == -1)
+    if (errno != error_exist)
+      strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/authors: ");
+
+       /* Lock list to assure that no ezmlm-send is working on it */
+       /* and that the "num" message is final */
+  fdlock = open_append("lock");
+  if (fdlock == -1)
+    strerr_die2sys(111,FATAL,ERR_OPEN_LOCK);
+  if (lock_ex(fdlock) == -1) {
+    (void) close(fdlock);
+    strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK);
+  }
+                                       /* get num */
+  if (!getconf_line(&num,"num",0,FATAL,dir))
+    strerr_die1x(100,ERR_EMPTY_LIST);
+  (void) close(fdlock);
+
+  if (!stralloc_0(&num)) die_nomem();  /* parse num */
+  (void) scan_ulong(num.s,&max);
+  if (!to || to > max) to = max;
+
+  fdlock = open_append("archive/lock");        /* lock index */
+  if (fdlock == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/archive/lock: ");
+  if (lock_ex(fdlock) == -1) {
+    (void) close(fdlock);
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/archive/lock: ");
+  }
+  if (!flagcreate && !archnum) {       /* adjust archnum (from) / to */
+    if (getconf_line(&num,"archnum",0,FATAL,dir)) {
+      if (!stralloc_0(&num)) die_nomem();
+      (void) scan_ulong(num.s,&archnum);
+      archnum++;
+    }
+  }
+
+  if (archnum > to)
+    _exit(0);                          /* nothing to do */
+
+                                       /* do the subject threading */
+  idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
+       archnum,to,max,0,FATAL);
+                                       /* update the index */
+  write_threads(msgtable,subtable,authtable,datetable,archnum,to);
+                                       /* update archnum */
+  if ((fd = open_trunc("archnumn")) == -1)
+    strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archnumn: ");
+  substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
+  if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,to)) == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+  if (substdio_puts(&ssnum,"\n") == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": ");
+  close_proper(&ssnum,"archnum","archnumn");
+  switch (flagerror) {
+    case 0:
+       _exit(0);                               /* go bye-bye */
+    case -1:
+       strerr_die2x(99,WARNING,"threads entry with illegal format");
+    case -2:
+       strerr_die2x(99,WARNING,"thread in index, but threadfile missing");
+    case -3:
+       strerr_die2x(99,WARNING,"a subject file lacks subject");
+    case -4:
+       strerr_die2x(99,WARNING,"an author file lacks author/hash");
+    case -5:
+       strerr_die2x(99,WARNING,"threads entry lacks message count");
+    default:
+       strerr_die2x(99,WARNING,"something happened that isn't quite right");
+  }
+}
+
diff --git a/ezmlm-cgi.1 b/ezmlm-cgi.1
new file mode 100644 (file)
index 0000000..6103ed8
--- /dev/null
@@ -0,0 +1,349 @@
+.TH ezmlm-cgi 1
+.SH NAME
+ezmlm-cgi \- provide WWW access to the list archive
+.SH SYNOPSIS
+.B ezmlm-cgi
+.SH DESCRIPTION
+.B ezmlm-cgi
+is executed by the httpd daemon and generates HTTP/CGI/html 4.0-compliant
+self-referencing output of index pages for threads in a given month,
+messages in a thread, messages by a given author, messages by date,
+and messages themselves with full navigation controls. It uses the
+archive directly, aided by index files created by
+.BR ezmlm-idx(1) ,
+and
+.B ezmlm-send(1)
+as part of normal archive access and digest indexing, and
+by
+.BR ezmlm-archive(1) .
+
+.B ezmlm-cgi
+uses the httpd-supplied variables
+.B PATH_INFO
+to obtain the list number,
+.B QUERY_STRING
+to obtain the command, as well as
+.BR SERVER_NAME ,
+.BR SERVER_PORT ,
+and
+.B SCRIPT_NAME
+to create a self-referencing URL.
+
+When
+.B ezmlm-cgi
+is invoked without a command, it shows the threads for the
+current month.
+If no list number is supplied, the default list is shown (see below).
+.SH CONFIGURATION
+.B ezmlm-cgi
+expects to find configuration info in
+.B /etc/ezmlm/ezcgirc
+when run SUID root, or
+.B .ezcgirc
+otherwise. The entries in this file describe one list per line. Blank lines
+and comments
+starting with a ``#'' in position 1 are allowed and ignored. No extra
+blanks, tab, etc, are allowed. Entries must be
+of the following format:
+
+.EX
+.I listno;uid;listdir;listaddr;buttonbar;charset;style;bannerprog
+.EE
+
+.B where:
+.TP 5
+.I listno
+is the list number using ``0'' for the default list if desired;
+.TP 5
+.I uid
+the user id to switch to if installed SUID root (default invoking user id) and
+if preceded by ``-'' chroot() is suppressed for SUID root installations;
+.TP 5
+.I listdir
+ the absolute path to the list base directory (required);
+.TP 5
+.I listaddr
+the list address as local@host (required) and if preceded by ``-'' the
+``From:'' E-mail address is replaced by the posters name/handle as a
+further precaution against address harvesting;
+.TP 5
+.I buttonbar
+a set of comma-separated fields of the type
+.IR ``[Home]=http://example.com/list.html''.
+The text before the ``='' is the exact text displayed and the subsequent
+text should be the URL linked to that button. Use the braces to make the
+buttons be consistent with preexisting navigation buttons. It is desirable
+to add a ``[Help]'' button with a link to an explanation of the various
+displays generated by
+.BR ezmlm-cgi .
+.TP 5
+.I charset
+the character set used for the main pages (default ``iso-8859-1''); 
+.TP 5
+.I style
+the style sheet used (default none, which doesn't look pretty);
+.TP 5
+.I bannerprog
+the path to a banner program which is given
+the name of the script and the list as arguments (default none). The path
+is relative to ``listdir'' and can point anywhere in the file system. However,
+for SUID root installations access is normally restricted via
+.BR chroot(3) .
+(See SECURITY.)
+If
+.I ``bannerprog''
+starts with a less-than character (''<'') it is assumed to
+be a URL which is inserted as is, rather than executed.
+.TP 5
+.I ``;''
+the separator can be any non-numeric character and can be different for
+different
+.I ezcgirc
+lines. There
+is no quoting/escaping mechanism. Thus, choose a character not present in
+any of the arguments. ``bannerprog'' as the last argument is an exception,
+and may contain any characters except LF and NUL.
+.SH OPTIONS
+.TP 5
+If ``uid'' is preceded by a minus sign (``-''),
+.B ezmlm-cgi
+will not call
+.B chroot(3) .
+This potentially decreases security, but may be needed to
+execute ``bannerprog''.
+.TP 5
+If ``listaddr'' is preceded by a minus sign (``-''),
+.B ezmlm-cgi
+will, as a precaution against address harvesting robots,
+remove the sender's E-mail address also in the message view. This is
+already done in all other views. The archive user can still obtain the address
+by requesting the message by E-mail.
+.SH OUTPUT
+.B ezmlm-cgi
+outputs 5 different views.
+.TP
+.I thread index
+shows the threads which have messages in a given month. The subject is
+prefixed with the number of messages in the thread for the given month. When
+.B ezmlm-archive(1)
+is first run against an existing archive, the number is the total number of
+messages in the thread. The subject and author are links to the respective
+thread or author index. The threads are ordered in reverse order of latest
+message, i.e. the thread that last received a message is listed last. When
+.B ezmlm-archive(1)
+is run against an existing archive, the initial sort is in order of the
+first message in the thread.
+
+The subject in the
+.I thread index
+is a link to the last message in the thread.
+.TP
+.I thread
+shows the messages in the respective thread in date order. For each message
+the author is shown linked to the message.
+.TP
+.I author index
+shows the subject of all messages posted from a given address in order of
+arrival at the list. Links are to the messages.
+.TP
+.I message by date
+shows entries in order of arrival of sets of 100 messages. Links are to
+the message and to the author.
+.TP
+.I message
+shows the message itself. The message has links to the previous and next
+message by time, in the thread, or by the same author. There are also links
+to the other views, as well as links to subscribe, or request FAQ,
+the message or the thread by E-mail. The navigation bar is very concise
+to optimize appearance in
+.BR lynx .
+It is self-explanatory to anyone daring to experiment. For others, you may
+wish to supply a ``help'' button.
+The message subject is a
+.I mailto:
+link for a follow-up post to the list. 
+.SH "OUTPUT FORMATTING"
+.B ezmlm-cgi
+outputs html 4.0 in a format suitable for
+.I Lynx
+and other text-mode browsers. The format is designed for easy optional
+enhancement
+via CSS1/2 type
+style sheets in the format ``text/css''.
+.B ezmlm-cgi
+is self-documenting in this respect. Simply review the output in the different
+views and the sample style sheet to see the class structure.
+.SH "EXTERNAL LINKS TO MESSAGES"
+.B ezmlm-cgi
+will accept a PATH_INFO of the following format:
+
+.EX
+.I /listno/message
+.EE
+
+.B where:
+.TP 5
+.I listno
+is the list number per config file;
+.TP 5
+.I message
+is the message number.
+
+Thus,
+.B ezmlm-cgi\fI/2/20000
+will return message 20000 from list 2.
+
+.B ezmlm-cgi
+uses a second syntax based on QUERY_STRING for internal links. This
+command set is implemented only as far as required for normal
+.B ezmlm-cgi
+function. Useful are:
+.TP
+.B ezmlm-cgi\fB?listno?ams:message
+which will return in order the list of messages posted by the author of message
+.I message
+on list
+.IR listno ,
+and
+.TP
+.B ezmlm-cgi\fB?listno?sms:message
+which will return in order the list of messages with the same subject as message
+.I message
+.I message
+on list
+.IR listno ,
+i.e. the ``thread''.
+.SH ROBOTS
+There are many possible URLs for the same message.
+To still allow external indexing,
+.B ezmlm-cgi
+supports the command
+.I ezmlm-cgi/index
+which returns a page with links to all lists, except the default list. These
+links indirectly lead exactly once to each message.
+None of the links used contain
+a ``?''. Thus, to index the archives, allow access to scripts in the
+(separate)
+.I directory
+where
+.B ezmlm-cgi
+is installed, but deny access to
+.IR directory\fB/ezmlm-cgi\fI? .
+Any message will have a ``nofollow'' robot META tag, and any view reached by
+a URL based on QUERY_STRING will in addition have a ``noindex'' robot META tag
+to avoid trapping robots in the archive.
+.SH EXECUTION
+.B ezmlm-cgi
+can operate in three modes,
+.IR SUID\ root ,
+.IR SUID\ user ,
+and
+.IR normal .
+
+In
+.I normal
+and
+.I SUID user
+mode,
+.B ezmlm-cgi
+will read the configuration file
+.B .ezcgirc
+from the working directory set by the httpd daemon
+(per
+.B cgi
+definition this should be the same directory as
+.B ezmlm-cgi
+is in), then
+change directory to the list directory. ``uid'' is ignored.
+.I SUID user
+may be required to read the particular archive if it is not owned by the
+httpd user. For user installations or systems where
+the httpd user has access to all the lists,
+.I normal
+mode usually gives sufficient access.
+
+In
+.I SUID\ root
+mode,
+.B ezmlm-cgi
+will read the configuration info from
+.B /etc/ezmlm/ezcgirc
+then change directory to that directory, then
+change root to that directory, then change
+userid to ``uid''. If ``uid'' is not specified, it will change to the
+uid of the process invoking
+.B ezmlm-cgi
+(normally the httpd user). If the archive files are world-readable, but the list
+directory is not, it is safest to leave ``uid'' blank. The httpd user will still
+be able to read the files.
+.SH "EXECUTION OF BANNER PROGRAMS"
+A banner program can be specified in the config file. It is executed
+immediately before the end of the text. The formatting for
+``<BODY>'' is active and the banner program output is encapsulated in
+a ``<DIV class=banner>'' segment to allow additional formatting.
+The banner program is called for all summary views, but not for the message
+view itself.
+
+The banner program is give the list local name as argument 1, and the host
+name as argument 2. It is expected to exit 0 on success. The return code is
+checked, but the archive page (and whatever the banner program has already
+produced) is output even if the banner program fails.
+
+.B chroot(3)
+may make it difficult to run banner programs that depend on e.g. ``sh''
+or ``perl''. For this reason, the chroot call can be suppressed by prefixing
+the ``uid'' with a ``-''.
+.SH SECURITY
+.B ezmlm-cgi
+will refuse to run as root.
+
+.B ezmlm-cgi
+does not write or lock any files.
+
+.B ezmlm-cgi
+has a short well commented segment of code that potentially runs SUID root.
+Read the source to convince yourself that this is safe. If possible, install
+it SUID user, or not SUID at all, if that meets your needs (single list
+user, httpd user is list user, or httpd user has sufficient access to all
+list directories and archives).
+
+.B ezmlm-cgi
+will allow execution of banner programs that are located outside of the list
+directory. These are executed with the privileges of the userid set in the
+config file. If the program is installed SUID root, banner programs outside
+of the list directory are not normally accessible. Even when this is overridden,
+.B ezmlm-cgi
+will never execute the program with root permissions.
+
+Input to the CGI script is not propagated to the banner program.
+.SH BUGS
+.B ezmlm-send(1)
+updates the list message counter once a message is safely archived, but
+before it is accepted by
+.BR qmail(7) .
+Also, the
+.I index
+file is updated before the message is accepted by
+.BR qmail(7) .
+If
+.B qmail(7)
+fails,
+.B ezmlm-send(1)
+resets the counter before terminating. It is possible that in such a situation
+the message would be replaced by a different one.
+If
+.B ezmlm-cgi
+accesses a message that ultimately fails and in that time interval,
+it may expose a message that ultimately is replaced, especially when doing it
+via the ``Messages by date'' view which is based on the
+.I index
+file. In practice, this is relatively harmless. Avoiding it would require
+locking the list with significant implications for security and performance.
+.SH "SEE ALSO"
+ezmlm-archive(1),
+ezmlm-get(1),
+ezmlm-idx(1),
+ezmlm-send(1),
+ezmlm(5),
+qmail(7)
+
diff --git a/ezmlm-cgi.c b/ezmlm-cgi.c
new file mode 100644 (file)
index 0000000..9549aed
--- /dev/null
@@ -0,0 +1,2238 @@
+/*$Id: ezmlm-cgi.c,v 1.17 1999/12/24 04:21:26 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+/* Please leave. Will hopefully help pay for further improvement. */
+#define EZ_CRIGHT "<a href=\"http://www.lindeinc.com\">(c) 1999 Lin-De, Inc</a>"
+/******/
+#include <sys/types.h>
+#include "direntry.h"
+#include "datetime.h"
+#include "now.h"
+#include "stralloc.h"
+#include "strerr.h"
+#include "error.h"
+#include "env.h"
+#include "sig.h"
+#include "open.h"
+#include "getln.h"
+#include "case.h"
+#include "scan.h"
+#include "str.h"
+#include "fmt.h"
+#include "readwrite.h"
+#include "fork.h"
+#include "wait.h"
+#include "exit.h"
+#include "substdio.h"
+#include "getconf.h"
+#include "gen_alloc.h"
+#include "gen_allocdefs.h"
+#include "constmap.h"
+#include "byte.h"
+#include "subscribe.h"
+#include "errtxt.h"
+#include "makehash.h"
+#include "mime.h"
+#include "idx.h"
+#include "yyyymm.h"
+
+#define FATAL "ezmlm-cgi: fatal: "
+#define GET "-getv"
+#define THREAD "-threadv"
+#define SUBSCRIBE "-subscribe"
+#define FAQ "-faq"
+#define TXT_CGI_SUBSCRIBE "\">[eSubscribe]</a>\n"
+#define TXT_CGI_FAQ "\">[eFAQ]</a>\n"
+
+int flagshowhtml = 1;  /* show text/html parts. This leads to duplication */
+                       /* when both text/plain and text/html are in a     */
+                       /* multipart/alternative message, but it is assumed*/
+                       /* that text/html is not frivolous, but only used  */
+                       /* when the formatting is important. */
+int flagobscure = 0;   /* Don't remove Sender's E-mail address in message */
+                       /* view. Overridden by config file (- before list */
+                       /* name). */
+
+/**************** Header processing ***********************/
+char headers_used[] = "Subject\\From\\Date\\content-type\\"
+               "content-transfer-encoding\\mime-version";
+/* index of headers displayed (shown in order listed above) */
+int headers_shown[] = {1,1,1,0,0,0};
+/* index of specific headers */
+#define NO_HDRS 6
+#define HDR_SUBJECT 1
+#define HDR_FROM 2
+#define HDR_CT 4
+#define HDR_CTENC 5
+#define HDR_VERSION 6
+
+/* Need to add inits if you increase NO_HDRS */
+stralloc hdr[NO_HDRS] = { {0},{0},{0},{0},{0},{0} };
+/**************** Header processing ***********************/
+
+
+/* index of subject in above, first = 1 */
+
+/* TODO: Sort headers before display. Find a way to display the body with the*/
+/* correct charset, ideally letting the browser do the work (should really */
+/* be able to specify charset for DIV ! */
+
+/* ulong at least 32 bits. (Creating a Year 0xffffff problem ;-) */
+#define MAXULONG 0xffffffff
+
+char cmdstr[5] = "xxx:";
+#define ITEM "-msadiz"
+#define ITEM_MESSAGE 1
+#define ITEM_SUBJECT 2
+#define ITEM_AUTHOR 3
+#define ITEM_DATE 4
+#define ITEM_INDEX 5
+
+#define DIRECT "psnpn"
+#define DIRECT_SAME 0
+#define DIRECT_NEXT 1
+#define DIRECT_PREV -1
+/* use only as the argument for some functions. Terrible hack for date links */
+#define DIRECT_FIRST 3
+#define DIRECT_LAST 2
+
+char *dir = 0;
+char *local = 0;
+char *host = 0;
+char *home = 0;
+char *banner = 0;
+char *charset = 0;
+char *stylesheet = 0;
+char *cmd;
+char strnum[FMT_ULONG];
+/* these are the only headers we really care about for message display */
+/* one can always retrieve the complete message by E-mail */
+stralloc charg = {0};
+stralloc url = {0};
+stralloc author = {0};
+stralloc subject = {0};
+stralloc base = {0};
+stralloc line = {0};
+stralloc decline = {0};                /* for rfc2047-decoded headers and QP/base64 */
+stralloc cfline = {0};         /* from config file */
+stralloc fn = {0};
+stralloc dtline = {0};
+stralloc headers = {0};
+stralloc encoding = {0};
+stralloc content = {0};
+stralloc charsetbase = {0};
+stralloc curcharset = {0};
+stralloc sainit = {0};
+struct constmap headermap;
+unsigned long uid,euid;
+int recursion_level;
+int so = 0;
+int ss23 = 0;
+int state = 0;
+int newlevel;
+int match;     /* used everywhere and no overlap */
+int fd;                /* same; never >1 open */
+int cache;     /* 0 = don't; 1 = don't know; 2 = do */
+int child,wstat;
+int flagtoplevel;
+unsigned int flagmime;
+unsigned int cs,csbase;
+int flagrobot;
+int flagpre;
+int precharcount;
+char cn1 = 0;
+char cn2 = 0;
+char lastjp[] = "B";   /* to get back to the correct JP after line break */
+char *bannerargs[4];
+
+
+mime_info *mime_current = 0;
+mime_info *mime_tmp = 0;
+
+datetime_sec when;
+struct datetime dt;
+
+char inbuf[4096];
+substdio ssin;
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_syntax(char *s)
+{
+  strerr_die4x(100,FATAL,ERR_SYNTAX,"config file: ",s);
+}
+
+char outbuf[4096];
+substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,sizeof(outbuf));
+
+void oput(register char *s, register unsigned int l)
+/* unbuffered. Avoid extra copy as httpd buffers */
+{
+  if (substdio_put(&ssout,s,l) == -1)
+    strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+}
+
+void oputs(register char *s)
+{
+  oput(s,str_len(s));
+}
+
+/* this error is for things that happen only if program logic is screwed up */
+void die_prog(char *s) { strerr_die5x(100,FATAL,"program error (please send bug report to bugs@ezmlm.org): ",s," Command: ",cmd); }
+
+/* If we already issued a header than this will look ugly */
+void cgierr(char *s,char *s1,char *s2)
+{
+  strerr_warn4(FATAL,s,s1,s2,(struct strerr *)0);
+  oputs("Content-type: text/plain\n");
+  oputs("Status: 500 Couldn't do it\n\n");
+  oputs("I tried my best, but:\n\n");
+  if (s) oputs(s);
+  if (s1) oputs(s1);
+  if (s2) oputs(s2);
+  oputs("\n");
+  substdio_flush(&ssout);
+  _exit(0);
+}
+
+unsigned long msgnav[5]; /* 0 prev prev 1 prev 2 this 3 next 4 next-next */
+
+struct msginfo {       /* clean info on the target message */
+  char item;           /* What we want */
+  char direction;      /* Relation to current msg */
+  char axis;           /* Axis of desired movement [may be calculated] */
+  unsigned long source;        /* reference message number */
+  unsigned long target;
+  unsigned long date;
+  unsigned long *authnav;      /* msgnav structure */
+  unsigned long *subjnav;      /* msgnav structure */
+  char *author;
+  char *subject;
+  char *cgiarg;                        /* sub/auth as expected from axis */
+} msginfo;
+
+void toggle_flagpre(int flag)
+{
+  flagpre = flag;
+  precharcount = 0;
+  cn1 = 0; cn2 = 0;            /* just in case */
+}
+
+unsigned int decode_charset(register char *s, register unsigned int l)
+/* return charset code. CS_BAD means that base charset should be used, i.e. */
+/* that charset is empty or likely invalid. CS_NONE are charsets for which  */
+/* we don't need to do anything special. */
+{
+  unsigned int r;
+
+  if (case_startb(s,l,"iso-8859") || case_startb(s,l,"us-ascii") ||
+       case_startb(s,l,"utf")) /* at the moment, we can do utf-8 right */
+    return CS_NONE;            /* what is utf-7 (used by OE)? */
+  if (case_startb(s,l,"x-cp") ||
+       case_startb(s,l,"cp") ||
+       case_startb(s,l,"x-mac") ||
+       case_startb(s,l,"koi8")) return CS_NONE;
+  if (!l || *s == 'x' || *s == 'X') return CS_BAD;
+  if (case_startb(s,l,"iso-2022")) {
+    if (case_startb(s+8,l-8,"-cn"))
+      return CS_2022_CN;
+    if (case_startb(s+8,l-8,"-jp"))
+      return CS_2022_JP;
+    return CS_2022_KR;
+  }
+  if (case_startb(s,l,"cn-") ||
+               case_startb(s,l,"hz-gb") ||
+               case_startb(s,l,"gb") ||
+               case_startb(s,l,"big5"))
+    return CS_CN;              /* Only consideration for linebreak */
+  if (case_startb(s,l,"iso_8859") ||
+       case_startb(s,l,"latin") ||
+       case_startb(s,l,"windows")) return CS_NONE;
+/* Add other charsets here. Later we will add code to replace a detected */
+/* charset name with another, and to connect conversion routines, such as */
+/* between windows-1251/koi-8r/iso-8859-5 */
+  return CS_BAD;
+}
+
+void htmlencode_put (register char *s,register unsigned int l)
+/* At this time, us-ascii, iso-8859-? create no problems. We just encode  */
+/* some html chars. iso-2022 may have these chars as character components.*/
+/* cs is set for these, 3 for CN, 2 for others. Bit 0 set means 2 byte    */
+/* chars for SS2/SS3 shiftouts (JP doesn't use them, KR has single byte.  */
+/* If cs is set and we're shifted out (so set) we don't substitute. We    */
+/* also look for SI/SO to adjust so, and ESC to detect SS2/SS3. Need to   */
+/* ignore other ESC seqs correctly. JP doesn't use SI/SO, but uses        */
+/* ESC ( B/J and ESC $ B/@ analogously, so we use these to toggle so.     */
+/* "Roman", i.e. ESC ( J is treated as ascii - no differences in html-    */
+/* relevant chars. Together, this allows us to deal with all iso-2022-*   */
+/* as a package. see rfc1468, 1554, 1557, 1922 for more info.             */
+/* line break at 84 to avoid splits with lines just a little too long. */
+{
+  if (!cs) {           /* us-ascii & iso-8859- & unrecognized */
+    for (;l--;s++) {
+      precharcount++;
+      switch (*s) {
+        case '>': oputs("&gt;"); break;
+        case '<': oputs("&lt;"); break;
+        case '"': oputs("&quot;"); break;
+        case '&': oputs("&amp;"); break;
+       case '\n': precharcount = 0; oput(s,1); break;
+       case ' ':
+         if (precharcount >= 84 && flagpre) {
+           oput("\n",1);                       /* in place of ' ' */
+           precharcount = 0;
+         } else
+           oput(s,1);                          /* otherwise out with it. */
+         break;
+        default: oput(s,1); break;
+      }
+    }
+  } else if (cs == CS_CN) {                    /* cn-, gb*, big5 */
+    for (;l--;s++) {
+      precharcount++;
+      if (cn1) { cn2 = cn1; cn1 = 0; }         /* this is byte 2 */
+      else { cn2 = 0; cn1 = *s & 0x80; }       /* this is byte 1/2 or ascii */
+      if (!cn1 && !cn2) {                      /* ascii */
+       switch (*s) {
+          case '>': oputs("&gt;"); break;
+          case '<': oputs("&lt;"); break;
+          case '"': oputs("&quot;"); break;
+          case '&': oputs("&amp;"); break;
+         case '\n': precharcount = 0; oput(s,1); break;
+          case ' ':
+               if (precharcount >= 84 && flagpre) {
+                 oput("\n",1);         /* break in ascii sequence */
+                 precharcount = 0;
+               } else
+                 oput(s,1);
+               break;
+         default: oput(s,1); break;
+       }
+      } else if (precharcount >= 84 && flagpre && cn2) {
+         oput("\n",1);                 /* break after 2-byte code */
+         precharcount = 0;
+      }
+    }
+  } else {                                     /* iso-2022 => PAIN! */
+    for (;l--;s++) {
+      precharcount++;
+      if (ss23) {                              /* ss2/ss3 character */
+       ss23--;
+       oput(s,1);
+        continue;
+      }
+      if (so) {                                        /* = 0 ascii, = 1 SO charset */
+        if (!(*s & 0xe0)) {                    /* ctrl-char */
+         switch (*s) {
+           case ESC: state = 1; break;
+           case SI: so = 0; break;
+           case '\n': precharcount = 0; break;
+           default: break;
+         }
+       }
+       oput(s,1);
+      } else {                                 /* check only ascii */
+       switch (*s) {
+         case '>': oputs("&gt;"); break;
+         case '<': oputs("&lt;"); break;
+         case '"': oputs("&quot;"); break;
+         case '&': oputs("&amp;"); break;
+          case ' ':
+               if (precharcount >= 84 && flagpre) {
+                 oput("\n",1);         /* break in ascii sequence */
+                 precharcount = 0;
+               } else
+                 oput(s,1);
+               break;
+         default:
+                 oput(s,1);
+                 if (!(*s & 0xe0)) {
+                   switch (*s) {
+                     case SO: so = 1; break;
+                     case ESC: state = 1; break;
+                     case SI: so = 0; break;   /* shouldn't happen */
+                     case '\n': precharcount = 0; break;
+                     default: break;
+                   }
+                 }
+       }
+      }                /* by now all output is done, now ESC interpretation */
+      if (state) {
+               /* ESC code - don't count */
+         if (precharcount) precharcount--;
+         state++;
+         switch (state) {
+           case 2: break;                      /* this was the ESC */
+           case 3: switch (*s) {
+                       case 'N': ss23 = (cs & 1) + 1; state = 0; break;
+                       case 'O': ss23 = 2; state = 0; break;
+                       case '(': state = 20; so = 0; break;    /* JP ascii */
+                       case '$': break;                /* var S2/SS2/SS3 des*/
+                       case '.': state = 10;   /* g3 settings, one more char */
+                       default: state = 0; break;      /* or JP */
+               }
+               break;
+           case 4: switch (*s) {       /* s2/ss2/ss3 or JP 2 byte shift */
+                  case 'B':
+                  case '@': lastjp[0] = *s;
+                            so = 1; state = 0; break;  /* JP */
+                  default: break;                      /* other SS2/3 des */
+                }
+                break;
+           case 5:  state = 0; break;          /* 4th char of ESC $ *|+|) X */
+           case 11: state = 0; break;          /* 3nd char of ESC . */
+           case 21: state = 0; break;          /* ESC ( X for JP */
+           default: die_prog("bad state in htmlencode_put"); break;
+         }
+      } else if (so && flagpre && precharcount >= 84) {
+               /* 84 is nicer than 78/80 since most use GUI browser */
+               /* iso-2022-* line splitter here. SO only, SI done above */
+               /* For JP need even precharcount, add ESC ( B \n ESC $B */
+       if (so && !(precharcount & 1)) {        /* even */
+         precharcount = 0;                     /* reset */
+         if (cs == CS_2022_JP) {               /* JP uses ESC like SI/SO */
+           oputs(TOASCII);
+           oput("\n",1);
+           oputs(TOJP);
+           oput(lastjp,1);
+         } else {
+           if (so) {
+               /* For iso-2022-CN: nothing if SI, otherwise SI \n SO */
+               /* For iso-2022-KR same */
+             oputs(SI_LF_SO);
+           } else
+             oput("\n",1);
+         }
+       }
+      }
+    }
+  }
+}
+
+char hexchar[] = "0123456789ABCDEF";
+char enc_url[] = "%00";
+
+void urlencode_put (register char *s,register unsigned int l)
+{
+  for (;l--;s++) {
+    register unsigned char ch;
+    ch = (unsigned char) *s;
+    if (ch <= 32 || ch > 127 || byte_chr("?<>=/:%+#\"",10,ch) != 10) {
+      enc_url[2] = hexchar[ch & 0xf];
+      enc_url[1] = hexchar[(ch >> 4) & 0xf];
+      oput(enc_url,3);
+    } else
+      oput(s,1);
+  }
+}
+
+void urlencode_puts(register char *s)
+{
+  urlencode_put(s,str_len(s));
+}
+
+int checkhash(register char *s)
+{
+  register int l = HASHLEN;
+  while (l--) {
+    if (*s < 'a' || *s > 'p') return 0;        /* illegal */
+    s++;
+  }
+  if (*s) return 0;                    /* extraneous junk */
+  return 1;
+}
+
+int makefn(stralloc *sa,char item, unsigned long n, char *hash)
+{
+  if (!stralloc_copys(sa,"archive/")) die_nomem();
+  if (item == ITEM_MESSAGE) {
+    if (!stralloc_catb(sa,strnum,fmt_ulong(strnum, n / 100))) die_nomem();
+    if (!stralloc_cats(sa,"/")) die_nomem();
+    if (!stralloc_catb(sa,strnum,fmt_uint0(strnum,(unsigned int) (n % 100),2)))
+                       die_nomem();
+  } else if (item == ITEM_DATE) {
+    if (!stralloc_cats(sa,"threads/")) die_nomem();
+    if (!stralloc_catb(sa,strnum,fmt_ulong(strnum,n)))
+       die_nomem();
+  } else if (item == ITEM_INDEX) {
+    if (!stralloc_catb(sa,strnum,fmt_ulong(strnum, n / 100))) die_nomem();
+    if (!stralloc_cats(sa,"/index")) die_nomem();
+  } else {
+    if (item == ITEM_AUTHOR) {
+      if (!stralloc_cats(sa,"authors/")) die_nomem();
+    } else {
+      if (!stralloc_cats(sa,"subjects/")) die_nomem();
+    }
+    if (!hash) return 0;
+    if (!stralloc_catb(sa,hash,2)) die_nomem();
+    if (!stralloc_cats(sa,"/")) die_nomem();
+    if (!stralloc_catb(sa,hash+2,HASHLEN-2)) die_nomem();
+  }
+  if (!stralloc_0(sa)) die_nomem();
+  return 1;
+}
+
+void link(struct msginfo *infop,char item,char axis,unsigned long msg,
+               char *data,unsigned int l)
+/* links with targets other msg -> msg. If the link is for author, we    */
+/* still supply subject, since most navigation at the message level will */
+/* be along threads rather than author and we don't have an author index.*/
+{
+  char *cp;
+
+  cp = (char *) 0;
+       /* this should be separate routine. Works because all index views */
+       /* have at least a subject link */
+  if (axis == ITEM_SUBJECT && infop->target == msg)
+    oputs("<a name=b></a>");
+  oput(url.s,url.len);
+  cmdstr[0] = ITEM[item];
+  cmdstr[1] = ITEM[axis];
+  cmdstr[2] = DIRECT[DIRECT_SAME + 1];
+  if (item == ITEM_MESSAGE && axis == ITEM_AUTHOR) {
+    if (infop->subject) {
+      cmdstr[1] = ITEM[ITEM_SUBJECT];
+      cp = infop->subject;     /* always HASLEN in length due to decode_cmd */
+    }
+  }
+  oputs(cmdstr);               /* e.g. map: */
+  oput(strnum,fmt_ulong(strnum,msg));
+  if (!cp && l >= HASHLEN)
+    cp = data;
+  if (infop->date) {
+    oput(":",1);
+    oput(strnum,fmt_ulong(strnum,infop->date));
+  }
+  if (cp) {
+    oput(":",1);
+    oput(cp,HASHLEN);
+  }
+  switch (item) {
+    case ITEM_MESSAGE: oputs("\" class=mlk>"); break;
+    case ITEM_AUTHOR: oputs("#b\" class=alk>"); break;
+    case ITEM_SUBJECT: oputs("#b\" class=slk>"); break;
+    default: oputs("#b\">"); break;
+  }
+  if (HASHLEN + 1 < l)
+    htmlencode_put(data + HASHLEN + 1,l - HASHLEN - 1);
+  else
+    oputs("(none)");
+  oputs("</A>");
+}
+
+void linktoindex(struct msginfo *infop,char item)
+/* for links from message view back to author/subject/threads index */
+{
+  oput(url.s,url.len);
+  cmdstr[0] = ITEM[item];
+  cmdstr[1] = ITEM[item];
+  cmdstr[2] = DIRECT[DIRECT_SAME + 1];
+  oputs(cmdstr);               /* e.g. map: */
+  oput(strnum,fmt_ulong(strnum,infop->target));
+  if (infop->date) {
+    oput(":",1);
+    oput(strnum,fmt_ulong(strnum,infop->date));
+  }
+  switch (item) {
+    case ITEM_AUTHOR:
+      if (infop->author) {
+       oput(":",1);
+       oputs(infop->author);
+      }
+      break;
+    case ITEM_SUBJECT:
+      if (infop->subject) {
+       oput(":",1);
+       oputs(infop->subject);
+      }
+      break;
+    default:
+      break;
+  }
+  oputs("#b\"");
+}
+
+void link_msg(struct msginfo *infop,char axis,char direction)
+/* Creates <a href="mapa:123:aaaaa...."> using a maximum of available */
+/* info only for links where the target is a message */
+{
+  unsigned long msg;
+  char *acc;
+  oput(url.s,url.len);
+  cmdstr[0] = ITEM[ITEM_MESSAGE];
+  cmdstr[1] = ITEM[axis];
+  cmdstr[2] = DIRECT[direction + 1];
+  msg = infop->target;
+  acc = 0;
+      switch(axis) {
+       case ITEM_SUBJECT:
+         if (infop->subject)
+           acc = infop->subject;
+         if (infop->subjnav)   /* translate to message navigation */
+           if (infop->subjnav[direction]) {
+             msg = infop->subjnav[direction];
+             cmdstr[2] = DIRECT[DIRECT_SAME + 1];
+         }
+         acc = infop->subject;
+         break;
+       case ITEM_AUTHOR:
+         if (infop->author)
+           acc = infop->author;
+         if (infop->authnav)   /* translate to message navigation */
+           if (infop->authnav[direction]) {
+             msg = infop->authnav[direction];
+             cmdstr[2] = DIRECT[DIRECT_SAME + 1];
+           }
+         acc = infop->author;
+         break;
+       default:
+         break;
+       }
+       oputs(cmdstr);
+       oput(strnum,fmt_ulong(strnum,msg));
+       if (acc) {
+         oputs(":");
+         oputs(acc);
+       }
+       oputs("\">");
+}
+
+void justpress()
+{
+  oputs("?subject=");
+  urlencode_puts("Just Click \"SEND\"!");
+}
+
+void homelink()
+{
+  register char *cp,*cp1,*cp2;
+
+  if (home && *home) {
+    cp = home;
+    for(;;) {
+      cp1 = cp;
+      while(*cp1 && *cp1 != '=') cp1++;
+      if (!*cp1) break;
+      cp2 = cp1;
+      while(*cp2 && *cp2 != ',') cp2++;
+      oputs("<a href=\"");
+      oput(cp1 + 1,cp2 - cp1 - 1);
+      oputs("\">");
+      oput(cp,cp1 - cp);
+      oputs("</a>\n");
+      if (!*cp2) break;
+      cp = cp2 + 1;
+    }
+  }
+}
+
+void subfaqlinks()
+{
+  oputs("<a href=\"mailto:");
+  oputs(local);
+  oputs(SUBSCRIBE);
+  oputs("@");
+  oputs(host);
+  justpress();
+  oputs(TXT_CGI_SUBSCRIBE);
+  oputs("<a href=\"mailto:");
+  oputs(local);
+  oputs(FAQ);
+  oputs("@");
+  oputs(host);
+  justpress();
+  oputs(TXT_CGI_FAQ);
+}
+
+void msglinks(struct msginfo *infop)
+/* Creates the html for all links from one message view */
+{
+  oputs("<DIV class=msglinks><STRONG>Msg by: ");
+  link_msg(infop,ITEM_SUBJECT,DIRECT_PREV);
+  oputs("[&lt;-</A> ");
+  linktoindex(infop,ITEM_SUBJECT);
+  oputs(">thread</A> ");
+  link_msg(infop,ITEM_SUBJECT,DIRECT_NEXT);
+  oputs("-&gt;]</A> \n");
+  link_msg(infop,ITEM_MESSAGE,DIRECT_PREV);
+  oputs("[&lt;-</A> ");
+  linktoindex(infop,ITEM_INDEX);
+  oputs(">time</A> ");
+  link_msg(infop,ITEM_MESSAGE,DIRECT_NEXT);
+  oputs("-&gt;]</A> \n");
+  link_msg(infop,ITEM_AUTHOR,DIRECT_PREV);
+  oputs("[&lt;-</A> ");
+  linktoindex(infop,ITEM_AUTHOR);
+  oputs(">author</A> ");
+  link_msg(infop,ITEM_AUTHOR,DIRECT_NEXT);
+  oputs("-&gt;]</A> |\n");
+  linktoindex(infop,ITEM_DATE);
+  oputs(">[Threads]</A>\n");
+  homelink();
+  oputs("\n<a href=\"mailto:");
+  oputs(local);
+  oputs(GET);
+  strnum[fmt_ulong(strnum,infop->target)] = '\0';
+  oputs(strnum);
+  oputs("@");
+  oputs(host);
+  justpress();
+  oputs("\">[eMsg]</A>\n");
+  oputs("<a href=\"mailto:");
+  oputs(local);
+  oputs(THREAD);
+  oputs(strnum);
+  oputs("@");
+  oputs(host);
+  justpress();
+  oputs("\">[eThread]</A>\n");
+  subfaqlinks();
+  oputs("</STRONG></DIV>\n");
+}
+
+#define SPC_BASE 1
+#define SPC_BANNER 2
+
+void html_header(char *t,char *s, unsigned int l,char *class,int flagspecial)
+/* flagspecial: 0x1 => robot index; no style sheet, no BASE */
+/* flagspecial: 0x2 => banner, if available */
+{
+  oputs("Content-Type: text/html; charset=");
+  oput(curcharset.s,curcharset.len);
+
+  oputs("\nCache-Control: ");
+  switch (cache) {
+    case 0:
+       oputs("no-cache");              /* known upper border */
+       break;
+    case 1:
+       oputs("max-age=300");           /* 5 min - most lists aren't that fast*/
+       break;
+    case 2:
+       oputs("max-age=1209600");       /* 14 days is a long time */
+       break;
+  }
+  oputs("\n\n");
+  oputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n");
+  oputs("<HTML><HEAD>\n<TITLE>");
+  if (local) {
+    oputs(local);
+    oputs("@");
+    oputs(host);
+    oputs(": ");
+  }
+  if (t) oputs(t);
+  if (s) htmlencode_put(s,l);
+  oputs("</TITLE>\n");
+  if (class && *class && stylesheet && *stylesheet) {
+    oputs("<LINK href=\"");
+    oputs(stylesheet);
+    oputs("\" rel=\"stylesheet\" type=\"text/css\">\n");
+  }
+  if (!flagrobot)      /* robot access allowed to follow */
+    oputs("<META NAME=\"robots\" CONTENT=\"noindex\">\n");
+  if (flagrobot < 2)
+    oputs("<META NAME=\"robots\" CONTENT=\"nofollow\">\n");
+  if (flagspecial & SPC_BASE)
+    oput(base.s,base.len);
+  oputs("</HEAD>\n");
+  if (class && *class) {
+    oputs("<BODY class=");
+    oputs(class);
+    oputs(">\n");
+  } else
+    oputs("<BODY>\n");
+
+}
+
+void html_footer(int flagspecial)
+{
+  oputs("<HR><DIV class=copyright>");
+  oputs(EZ_CRIGHT);
+  oputs("</DIV>");
+  if ((flagspecial & SPC_BANNER) && banner && *banner) {
+    oputs("<DIV class=banner>\n");
+    if (*banner == '<') oputs(banner);
+    else {
+      substdio_flush(&ssout);
+      sig_pipeignore();
+      bannerargs[0] = banner;
+      bannerargs[1] = host;
+      bannerargs[2] = local;
+      bannerargs[3] = 0;
+       /* We log errors but just complete the page anyway, since we're */
+       /* already committed to output something. */
+      switch(child = fork()) {
+        case -1:
+          strerr_warn3(FATAL,ERR_FORK,"banner program: ",&strerr_sys);
+          break;
+        case 0:
+          execv(*bannerargs,bannerargs);
+          strerr_die3x(100,FATAL,ERR_EXECUTE,"banner program: ");
+         break;
+      }
+         /* parent */
+      wait_pid(&wstat,child);
+      if (wait_crashed(wstat))
+        strerr_warn2(FATAL,ERR_CHILD_CRASHED,(struct strerr *) 0);
+      if (wait_exitcode(wstat))
+        strerr_warn2(FATAL,ERR_CHILD_UNKNOWN,(struct strerr *) 0);
+    }
+    oputs("</DIV>\n");
+  }
+  oputs("</BODY>\n</HTML>\n");
+  substdio_flush(&ssout);
+}
+
+/* DATE functions */
+
+void datelink(struct msginfo *infop,unsigned long d,char direction)
+/* output a date with link back to thread index */
+{
+  oput(url.s,url.len);
+  cmdstr[0] = ITEM[ITEM_DATE];
+  cmdstr[1] = ITEM[ITEM_DATE];
+  cmdstr[2] = DIRECT[direction + 1];
+  oputs(cmdstr);
+  if (direction == DIRECT_LAST)
+    oput("0",1);       /* suppress msgnum to avoid going there */
+  else
+    oput(strnum,fmt_ulong(strnum,infop->target));
+  oputs(":");
+  oput(strnum,fmt_ulong(strnum,d));
+  oputs("#b\">");
+  switch (direction) {
+    case DIRECT_SAME:
+       if (dateline(&dtline,d) < 0) die_nomem();
+       oput(dtline.s,dtline.len);
+       break;
+    case DIRECT_PREV:
+       oputs("[&lt;-]");
+       break;
+    case DIRECT_NEXT:
+       oputs("[-&gt;]");
+       break;
+    case DIRECT_FIRST:
+       oputs("[&lt;&lt;-]");
+       break;
+    case DIRECT_LAST:
+       oputs("[-&gt;&gt;]");
+       break;
+  }
+  oputs("</A>");
+}
+
+void finddate(struct msginfo *infop)
+/* DIRECT_SAME works as DIRECT_PREV, dvs returns previous date or last date */
+{
+  DIR *archivedir;
+  direntry *d;
+  unsigned long ddate, startdate;
+  unsigned long below, above;
+
+  below = 0L;
+  above = MAXULONG;    /* creating a Y 0xffffff problem */
+  startdate = infop->date;
+  archivedir = opendir("archive/threads/");
+  if (!archivedir)
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/archive/threads: ");
+    else
+      strerr_die4sys(100,FATAL,ERR_OPEN,dir,"/archive/threads: ");
+
+  while ((d = readdir(archivedir))) {          /* dxxx/ */
+    if (str_equal(d->d_name,".")) continue;
+    if (str_equal(d->d_name,"..")) continue;
+    scan_ulong(d->d_name,&ddate);
+    if (!ddate) continue;      /* just in case some smart guy ... */
+    if (startdate) {
+      if (ddate > startdate && ddate < above) above = ddate;
+      if (ddate < startdate && ddate > below) below = ddate;
+    } else {
+      if (ddate < above) above = ddate;
+      if (ddate > below) below = ddate;
+    }
+  }
+  closedir(archivedir);
+
+  if (infop->direction == DIRECT_NEXT && above != MAXULONG || !below)
+       /* we always give a valid date as long as there is at least one */
+    infop->date = above;
+  else
+    infop->date = below;
+  return;
+}
+
+void latestdate(struct msginfo *infop,int flagfail)
+{
+  if (!flagfail) {
+    datetime_tai(&dt,now());
+    infop->date = ((unsigned long) dt.year + 1900) * 100 + dt.mon + 1;
+  } else {
+    infop->date = 0;
+    infop->direction = DIRECT_PREV;
+    finddate(infop);
+  }
+}
+
+void firstdate(struct msginfo *infop,int flagfail)
+{
+    infop->date = 0;
+    infop->direction = DIRECT_NEXT;
+    finddate(infop);
+}
+
+void getdate(struct msginfo *infop,int flagfail)
+/* infop->date has to be 0 or valid on entry. Month outside of [1-12] on */
+/* entry causes GIGO */
+{
+  if (!flagfail) {                             /* guess */
+    if (infop->direction == DIRECT_NEXT) {
+      infop->date++;
+      if (infop->date % 100 > 12) infop->date += (100 - 12);
+    } else if (infop->direction == DIRECT_PREV) {
+      infop->date--;
+      if (!infop->date % 100) infop->date -= (100 - 12);
+    }
+  } else
+    finddate(infop);
+  return;
+}
+
+indexlinks(struct msginfo *infop)
+{
+  unsigned long tmpmsg;
+
+  tmpmsg = infop->target;
+  infop->target = 1;
+  oputs("<DIV class=idxlinks><STRONG>");
+  linktoindex(infop,ITEM_INDEX);
+  oputs(">[&lt;&lt;-]</A>\n");
+  if (tmpmsg >= 100) infop->target = tmpmsg - 100;
+  linktoindex(infop,ITEM_INDEX);
+  oputs(">[&lt;-]</A>\n");
+  infop->target = tmpmsg + 100;
+  linktoindex(infop,ITEM_INDEX);
+  oputs(">[-&gt;]</A>\n");
+  infop->target = MAXULONG;
+  linktoindex(infop,ITEM_INDEX);
+  oputs(">[-&gt;&gt;]</A> |\n");
+  infop->target = tmpmsg;
+  linktoindex(infop,ITEM_DATE);
+  oputs(">[Threads by date]</A>\n");
+  subfaqlinks();
+  homelink();
+  oputs("</STRONG></DIV>\n");
+}
+
+int show_index(struct msginfo *infop)
+{
+  unsigned long thismsg;
+  unsigned int pos,l;
+  char ch;
+
+  (void) makefn(&fn,ITEM_INDEX,msginfo.target,"");
+  if ((fd = open_read(fn.s)) == -1)
+    if (errno == error_noent)
+      return 0;
+    else
+      strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  if (!stralloc_copyb(&line,strnum,
+       fmt_ulong(strnum,(unsigned long) (infop->target / 100))))
+               die_nomem();
+  if (!stralloc_cats(&line,"xx")) die_nomem();
+  html_header("Messages ",line.s,line.len,"idxbody",SPC_BANNER | SPC_BASE);
+  indexlinks(infop);
+  oputs("<HR><H1 id=\"idxhdr\">");
+  oputs("Messages ");
+  oput(line.s,line.len);
+  oputs("</H1>\n");
+  oputs("<HR><DIV class=idx>\n");
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match)
+      break;
+    pos = scan_ulong(line.s,&thismsg);
+    l = pos;
+    ch = line.s[pos++];
+    pos++;
+    if (line.len < pos + 1 + HASHLEN)
+       strerr_die2x(100,FATAL,"index line with truncated subject entry");
+    if (!stralloc_copyb(&subject,line.s+pos,HASHLEN)) die_nomem();
+    if (!stralloc_0(&subject)) die_nomem();
+    infop->axis = ITEM_SUBJECT;
+    infop->subject = subject.s;
+    oput(strnum,fmt_uint0(strnum,(unsigned int) thismsg % 100,2));
+    oputs(": ");
+    link(infop,ITEM_MESSAGE,ITEM_SUBJECT,thismsg,line.s+pos,line.len - pos - 1);
+    oputs("\n");
+    if (ch == ':') {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+      if (!match)
+        break;
+      pos = byte_chr(line.s,line.len,';');
+      if (pos != line.len) {
+       infop->date = date2yyyymm(line.s);
+       oputs("(");
+       link(infop,ITEM_AUTHOR,ITEM_AUTHOR,thismsg,line.s+pos+1,
+               line.len - pos - 2);
+       oputs(")<BR>\n");
+      }
+    }
+  }
+  close(fd);
+  oputs("\n</DIV><HR>\n");
+  indexlinks(infop);
+  html_footer(SPC_BANNER);
+  return 1;
+}
+
+void objectlinks(struct msginfo *infop, char item)
+{
+  oputs("<DIV class=objlinks><STRONG>\n");
+  if (item == ITEM_DATE) {
+    datelink(infop,0,DIRECT_FIRST);
+    datelink(infop,infop->date,DIRECT_PREV);
+    datelink(infop,infop->date,DIRECT_NEXT);
+    datelink(infop,0,DIRECT_LAST);
+    oputs("\n");
+  } else {
+    if (!infop->target) infop->axis = ITEM_DATE;
+    linktoindex(infop,ITEM_DATE);
+    oputs(">[Threads by date]</A>\n");
+  }
+  if (item != ITEM_INDEX) {
+    linktoindex(infop,ITEM_INDEX);
+    oputs(">[Messages by date]</A>\n");
+  }
+  homelink();
+  subfaqlinks();
+  oputs("</STRONG></DIV>\n");
+}
+
+int show_object(struct msginfo *infop,char item)
+/* shows thread, threads, author */
+/* infop has the info needed to access the author/subject/thread file */
+{
+  unsigned long lastdate,thisdate,thismsg;
+  char linkitem;
+  char targetitem;
+  unsigned int pos;
+
+  lastdate = 0L;
+  targetitem = ITEM_MESSAGE;                   /* default message is target */
+  switch (item) {
+    case ITEM_SUBJECT:
+       if (!makefn(&fn,ITEM_SUBJECT,0L,infop->subject)) return 0;
+       break;
+    case ITEM_AUTHOR:
+       if (!makefn(&fn,ITEM_AUTHOR,0L,infop->author)) return 0;
+       break;
+    case ITEM_DATE:
+       if (!makefn(&fn,ITEM_DATE,infop->date,"")) return 0;
+       break;
+    default:
+       die_prog("Bad object type in show_object");
+  }
+if ((fd = open_read(fn.s)) == -1)
+    if (errno == error_noent)
+      return 0;
+    else
+      strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  if (item != ITEM_DATE) {
+    if (getln(&ssin,&line,&match,'\n') == -1)  /* read subject */
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match || line.len < HASHLEN + 2)
+      strerr_die4x(111,FATAL,ERR_READ,fn.s,": nothing there");
+  }
+  switch (item) {
+    case ITEM_SUBJECT:
+       html_header("Thread on: ",line.s + HASHLEN + 1,
+               line.len - HASHLEN - 2,"subjbody",SPC_BANNER | SPC_BASE);
+       objectlinks(infop,item);
+       oputs("<HR><H1>On: ");
+       oput(line.s+HASHLEN+1,line.len-HASHLEN-2);
+       oputs("</H1>\n");
+       break;
+    case ITEM_AUTHOR:
+       html_header("Posts by: ",line.s + HASHLEN + 1,
+               line.len - HASHLEN - 2,"authbody",SPC_BANNER | SPC_BASE);
+       objectlinks(infop,item);
+       oputs("<HR><H1>By: ");
+       oput(line.s+HASHLEN+1,line.len-HASHLEN-2);
+       oputs("</H1>\n");
+       break;
+    case ITEM_DATE:
+/*     targetitem = ITEM_SUBJECT;*/    /* thread index is target */
+       thisdate = infop->date;
+       if (dateline(&dtline,infop->date) < 0) die_nomem();
+       html_header("Threads for ",
+               dtline.s,dtline.len,"threadsbody",SPC_BANNER | SPC_BASE);
+       objectlinks(infop,item);
+       oputs("<HR><H1>Threads for ");
+       oput(dtline.s,dtline.len);
+       oputs("</H1>\n");
+       break;
+    default: die_prog("unrecognized object type in show_object");
+  }
+
+  oputs("<DIV class=obj>\n");
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)  /* read subject */
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match)
+      break;
+    pos = scan_ulong(line.s,&thismsg);
+    if (line.s[pos++] != ':')
+       strerr_die4x(100,FATAL,"entry in ",fn.s," lacks message number");
+    if (item != ITEM_DATE) {           /* no date for threads by date */
+      pos += scan_ulong(line.s+pos,&thisdate);
+      infop->date = thisdate;
+      if (line.s[pos++] != ':')
+       strerr_die4x(100,FATAL,"entry in ",fn.s," lacks date");
+    }
+    if (line.len < pos + HASHLEN + 2)
+       strerr_die4x(100,FATAL,"entry in ",fn.s," lacks hash");
+    if (thisdate != lastdate) {
+      if (!lastdate)
+       oputs("<UL>\n");
+      else
+        oputs("<P>");
+      oputs("<LI><H2>");
+      datelink(infop,thisdate,DIRECT_SAME);
+      lastdate = thisdate;
+      oputs("</H2>\n");
+    }
+    if (item == ITEM_SUBJECT)
+      linkitem = ITEM_AUTHOR;
+    else
+      linkitem = ITEM_SUBJECT;
+    link(infop,targetitem,linkitem,thismsg,line.s+pos,line.len - pos - 1);
+    oputs("<BR>\n");
+  }
+  close(fd);
+  oputs("</UL>\n");
+  if (!infop->target)
+    oputs("<a name=b></a>");
+  oputs("<HR></DIV>\n");
+  objectlinks(infop,item);
+  html_footer(SPC_BANNER);
+  return 1;
+}
+
+void clear_mime()
+{
+  mime_current->charset.len = 0;       /* exist but need emptying */
+  mime_current->boundary.len = 0;
+  mime_current->ctype.len = 0;
+  mime_current->mimetype = MIME_NONE;
+  mime_current->ctenc = CTENC_NONE;
+  mime_current->cs = CS_NONE;
+}
+
+void new_mime()
+{
+    mime_tmp = mime_current;
+    if (mime_current)
+      mime_current = mime_current->next;
+    if (!mime_current) {
+      if (!(mime_current = (mime_info *) alloc(sizeof (mime_info))))
+       die_nomem();
+      mime_current->charset = sainit;          /* init */
+      mime_current->boundary = sainit;
+      mime_current->ctype = sainit;
+      mime_current->next = (mime_info *) 0;
+      mime_current->previous = mime_tmp;
+    }
+    clear_mime();
+    if (mime_tmp)
+      mime_current->level = mime_tmp->level + 1;
+    else
+      mime_current->level = 1;
+}
+
+void mime_getarg(stralloc *sa,char **s, unsigned int *l)
+/* copies next token or "token" into sa and sets s & l appropriately */
+/* for continuing the search */
+{
+  char *cp, *cpafter, *cpnext;
+
+      if (!*l || !**s) return;
+      if (**s == '"') {
+       (*s)++; (*l)--;
+       cp = *s; cpnext = cp + *l; cpafter = cpnext;
+       while (cp < cpafter) {
+         if (*cp == '"') {
+           break;
+         }
+         cp++;
+       }
+       cpnext = cp;
+      } else {
+       cp = *s; cpnext = cp + *l; cpafter = cpnext;
+       while (cp < cpafter) {
+         if (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ';') {
+           break;
+         }
+         cp++;
+       }
+       cpnext = cp;
+      }
+      if (!stralloc_copyb(sa,*s,cp - *s)) die_nomem();
+      *l = cpafter - cpnext;           /* always >= 0 */
+      *s = cpnext;
+      return;
+}
+
+void decode_mime_type(char *s,unsigned int l,unsigned int flagmime)
+{
+  char *st;
+  unsigned int r,lt;
+  if (!flagmime || !l) {               /* treat non-MIME as plain text */
+    mime_current->mimetype = MIME_TEXT_PLAIN;
+    if (!stralloc_copys(&curcharset,charset)) die_nomem();
+       /* should be us-ascii, but this is very likely better */
+    return;
+  }
+  r = MIME_APPLICATION_OCTETSTREAM;
+  while (l && (*s == ' ' || *s == '\t')) { s++; l--; } /* skip LWSP */
+  mime_getarg(&(mime_current->ctype),&s,&l);
+  st = mime_current->ctype.s;
+  lt = mime_current->ctype.len;
+  if (case_startb(st,lt,"text")) {                     /* text types */
+    r = MIME_TEXT; st+= 4; lt-= 4;
+    if (case_startb(st,lt,"/plain")) {
+      r = MIME_TEXT_PLAIN; st+= 6; lt-= 6;
+    } else if (case_startb(st,lt,"/html")) {
+      r = MIME_TEXT_HTML; st+= 5; lt-= 5;
+    } else if (case_startb(st,lt,"/enriched")) {
+      r = MIME_TEXT_ENRICHED; st+= 9; lt-= 9;
+    } else if (case_startb(st,lt,"/x-vcard")) {
+      r = MIME_TEXT_ENRICHED; st+= 8; lt-= 8;
+    }
+  } else if (case_startb(st,lt,"multipart")) {         /* multipart types */
+    r = MIME_MULTI; st += 9; lt-= 9;
+    if (case_startb(st,lt,"/alternative")) {
+      r = MIME_MULTI_ALTERNATIVE; st+= 12; lt-= 12;
+    } else if (case_startb(st,lt,"/mixed")) {
+      r = MIME_MULTI_MIXED; st+= 6; lt-= 6;
+    } else if (case_startb(st,lt,"/digest")) {
+      r = MIME_MULTI_DIGEST; st+= 7; lt-= 7;
+    } else if (case_startb(st,lt,"/signed")) {
+      r = MIME_MULTI_SIGNED; st+= 7; lt-= 7;
+    }
+  } else if (case_startb(st,lt,"message")) {           /* message types */
+    r = MIME_MESSAGE; st += 7; lt -= 7;
+    if (case_startb(st,lt,"/rfc822")) {
+      r = MIME_MESSAGE_RFC822; st+= 7; lt-= 7;
+    }
+  }
+  mime_current->mimetype = r;
+  while (l) {
+    while (l && (*s == ' ' || *s == '\t' || *s == ';' || *s == '\n')) {
+        s++; l--; }                                    /* skip ;LWSP */
+    if (case_startb(s,l,"boundary=")) {
+      s += 9; l-= 9;
+      mime_getarg(&(mime_current->boundary),&s,&l);
+    } else if (case_startb(s,l,"charset=")) {
+      s += 8; l-= 8;
+      mime_getarg(&(mime_current->charset),&s,&l);
+      cs = decode_charset(mime_current->charset.s,
+               mime_current->charset.len);
+      if (cs == CS_BAD) cs = csbase;                   /* keep base cs */
+      else
+       if (!stralloc_copy(&curcharset,&mime_current->charset)) die_nomem();
+    } else {                                           /* skip non LWSP */
+      for (;;) {
+       if (!l) break;
+       if (*s == '"') {
+         s++, l--;
+         while (l && *s != '"') { s++, l--; }
+         if (l) { s++, l--; }
+         break;
+       } else {
+         if (!l || *s == ' ' || *s == '\t' || *s == '\n') break;
+         s++; l--;
+       }
+      }
+    }
+  }
+  return;
+}
+
+void decode_transfer_encoding(register char *s,register unsigned int l)
+{
+  unsigned int r;
+  mime_current->ctenc = CTENC_NONE;
+  if (!l || (mime_current->mimetype & MIME_MULTI)) return;
+                       /* base64/QP ignored for multipart */
+  r = CTENC_NONE;
+  while (l && (*s == ' ' || *s == '\t')) { s++; l--; } /* skip LWSP */
+  if (case_startb(s,l,"quoted-printable")) {
+    r = CTENC_QP;
+  } else if (case_startb(s,l,"base64")) {
+    r = CTENC_BASE64;
+  }
+  mime_current->ctenc = r;
+  return;
+}
+
+int check_boundary()
+/* return 0 if no boundary, 1 if start, 2 if end */
+{
+  mime_info *tmp;
+
+  if (*line.s != '-' || line.s[1] != '-') return 0;
+  tmp = mime_current;
+  while (tmp) {
+    if (tmp->boundary.len) {
+    if (line.len > tmp->boundary.len + 2 &&
+       !case_diffb(line.s+2,tmp->boundary.len,tmp->boundary.s)) {
+      if (line.s[tmp->boundary.len + 2] == '-' &&
+               line.s[tmp->boundary.len + 3] == '-') { /* end */
+       mime_current = tmp;
+       clear_mime();
+       return 2;
+
+      } else {                                         /* start */
+       mime_current = tmp;
+       new_mime();
+       return 1;
+      }
+    }
+    }
+    tmp = tmp->previous;
+  }
+  if (!stralloc_copys(&curcharset,charset)) die_nomem();
+                       /* suprtfluous since header done by now */
+  cs = csbase;
+  return 0;
+}
+
+void start_message_page(struct msginfo *infop)
+/* header etc for message. Delayed to collect subject so that we can put */
+/* that in TITLE. This in turn needed for good looking robot index.      */
+/* Yep, not pretty, but it works and it's abhorrent to seek()/rewind     */
+/* and another hack: it's hard to mix charsets within a doc. So, we disp */
+/* messages entirely in the charset of the message. This is ok, since    */
+/* headers will be us-ascii or have encoded segments usually matching    */
+/* the charset in the message. Of course, we should be able to used e.g. */
+/* <DIV charset=iso-2022-jp> with internal resources as well as internal */
+/* ones. One might make other-charset messages external resources as well*/
+/* Now, the problem is that we need to "preview" MIME info _before_      */
+/* seeing the start boundary. */
+{
+  if (!stralloc_copyb(&decline,strnum,fmt_ulong(strnum,infop->target)))
+       die_nomem();
+  if (!stralloc_cats(&decline,":")) die_nomem();
+  if (!stralloc_0(&decline)) die_nomem();
+  decodeHDR(hdr[HDR_SUBJECT - 1].s,hdr[HDR_SUBJECT - 1].len,&line,"",FATAL);
+  if (!mime_current)
+    new_mime();                        /* allocate */
+  else
+    clear_mime();
+  decode_mime_type(hdr[HDR_CT - 1].s,hdr[HDR_CT - 1].len,
+       hdr[HDR_VERSION - 1].len);
+  html_header(decline.s,line.s,line.len - 1,
+               "msgbody",SPC_BASE);
+  msglinks(infop);
+  oputs("<DIV class=message>\n");
+}
+
+void show_part(struct msginfo *infop,int flagshowheaders,
+       int flagskip,int flagstartseen)
+/* if flagshowheaders we display headers, otherwise not */
+/* if flagstartseen we've already see the start boundary for this part, */
+/* if not we'll ignore what's there up to it */
+/* if flagskip we skip this part */
+{
+  char *cp;
+  int flaginheader;
+  int whatheader;
+  int flaggoodfield;
+  int flaghtml;
+  int btype,i;
+  unsigned int colpos,l,pos;
+  char linetype;
+
+  flaginheader = 1;
+  for (i = 0; i < NO_HDRS; i++) hdr[i].len = 0;
+  flaggoodfield = 1;
+  match = 1;
+  recursion_level++;                   /* one up */
+  for (;;) {
+    if (!match) return;
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match) return;
+    if ((btype = check_boundary())) {
+      if (flagpre) {
+       oputs("</PRE>");
+       toggle_flagpre(0);
+      }
+      if (mime_current->level < recursion_level) {
+        return;
+      }
+      if (btype == 1) {
+       flagstartseen = 1;
+       flaggoodfield = 1;
+       flaginheader = 1;
+      } else
+       flagstartseen = 0;
+      continue;
+    }
+    if (!flagstartseen) continue;      /* skip to start */
+    if (flaginheader) {
+      if (line.len == 1) {
+       if (flagshowheaders) {          /* rfc822hdr only */
+         if (flagtoplevel)
+           start_message_page(infop);  /* so we can put subj in TITLE */
+         oputs("<DIV class=rfc822hdr><HR>\n");
+         for (i = 0; i < NO_HDRS; i++) {
+           if (!hdr[i].len || !headers_shown[i]) continue;
+           if (i == HDR_SUBJECT - 1 && flagtoplevel)
+             oputs("<SPAN class=subject>");
+           oputs("<EM>");
+           oputs(constmap_get(&headermap,i + 1));
+           oputs(":</EM>");
+           decodeHDR(hdr[i].s,hdr[i].len,&line,"",FATAL);
+           if (i == HDR_SUBJECT - 1 && flagtoplevel) {
+             oputs("<A class=relk href=\"mailto:");
+             oputs(local);
+             oput("@",1);
+             oputs(host);
+             oputs("?subject=");
+             urlencode_put(line.s + 1,line.len - 2);
+             oputs("\">");
+           }
+           if (flagobscure && i == HDR_FROM - 1) {
+             oputs(" ");
+             decodeHDR(cp,author_name(&cp,line.s,line.len),&decline,"",FATAL);
+             htmlencode_put(decline.s,decline.len);
+           } else {
+             decodeHDR(hdr[i].s,hdr[i].len,&decline,"",FATAL);
+              htmlencode_put(decline.s,decline.len - 1);
+           }
+           if (i == HDR_SUBJECT - 1 && flagtoplevel)
+             oputs("</A></SPAN>");
+           oputs("\n<BR>");
+         }
+         oputs("</DIV>\n");
+       }
+        flaginheader = 0;
+       flagtoplevel = 0;
+        flaggoodfield = 1;
+       flaghtml = 0;
+       if (!flagmime)
+         flagmime = hdr[HDR_VERSION - 1].len;  /* MIME-Version header */
+       decode_mime_type(hdr[HDR_CT - 1].s,hdr[HDR_CT - 1].len,flagmime);
+       decode_transfer_encoding(hdr[HDR_CTENC - 1].s,hdr[HDR_CTENC - 1].len);
+       content.len = 0; encoding.len = 0;
+       switch (mime_current->mimetype) {
+         case MIME_MULTI_SIGNED:
+         case MIME_MULTI_MIXED:
+         case MIME_MULTI_ALTERNATIVE:
+         case MIME_MULTI_DIGEST:
+               show_part(infop,0,0,0);
+               recursion_level--;
+               flagstartseen = 0;
+               flaginheader = 1;
+               continue;
+         case MIME_MESSAGE_RFC822:
+               oputs("\n<PRE>");
+               toggle_flagpre(1);
+               flagshowheaders = 1;
+               flaginheader = 1;
+               flagmime = 0;           /* need new MIME-Version header */
+               continue;
+         case MIME_TEXT_HTML:
+               if (flagshowhtml) {
+                 oputs("<HR>\n");
+                 flaghtml = 1;
+               } else {
+                 oputs("<strong>[\"");
+                 oput(mime_current->ctype.s,mime_current->ctype.len);
+                 oputs("\" not shown]</strong>\n");
+                 flaggoodfield = 0;    /* hide */
+               }
+               continue;
+         case MIME_TEXT_PLAIN:
+         case MIME_TEXT:               /* in honor of Phil using "text" on */
+         case MIME_NONE:               /* the qmail list and rfc2045:5.2 */
+               oputs("<HR>\n<PRE>\n");
+               toggle_flagpre(1);
+               continue;
+         case MIME_TEXT_VCARD:
+         default:              /* application/octetstream...*/
+               oputs("<HR><strong>[\"");
+               oput(mime_current->ctype.s,mime_current->ctype.len);
+               oputs("\" not shown]</strong>\n");
+               flaggoodfield = 0;      /* hide */
+               continue;
+       }
+      } else if (line.s[0] != ' ' && line.s[0] != '\t') {
+       linetype = ' ';
+        flaggoodfield = 0;
+       colpos = byte_chr(line.s,line.len,':');
+       if ((whatheader = constmap_index(&headermap,line.s,colpos))) {
+          flaggoodfield = 1;
+         if (!stralloc_copyb(&hdr[whatheader - 1],line.s + colpos + 1,
+               line.len - colpos - 1)) die_nomem();
+       }
+      } else {
+       if (whatheader)
+         if (!stralloc_catb(&hdr[whatheader - 1],line.s,line.len))
+               die_nomem();
+      }
+    } else {
+      if (flaggoodfield) {
+       if (mime_current->ctenc) {
+         if (!stralloc_copy(&decline,&line)) die_nomem();
+         line.len = 0;
+         if (mime_current->ctenc == CTENC_QP)
+           decodeQ(decline.s,decline.len,&line);
+         else
+           decodeB(decline.s,decline.len,&line);
+       }
+       if (flaghtml)
+         oput(line.s,line.len);
+       else {
+          htmlencode_put(line.s,line.len);             /* body */
+       }
+      }
+    }
+  }
+}
+
+int show_message(struct msginfo *infop)
+{
+  char *psz;
+
+  if(!stralloc_copys(&headers,(char *) headers_used)) die_nomem();
+  if (!stralloc_0(&headers)) die_nomem();
+  psz = headers.s;
+  while (*psz) {
+    if (*psz == '\\') *psz = '\0';
+    ++psz;
+  }
+  if (!constmap_init(&headermap,headers.s,headers.len,0))
+       die_nomem();
+
+  (void) makefn(&fn,ITEM_MESSAGE,msginfo.target,"");
+  if ((fd = open_read(fn.s)) == -1)
+    if (errno == error_noent)
+      return 0;
+    else
+      strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  toggle_flagpre(0);
+  recursion_level = 0; /* recursion level for show_part */
+  flagmime = 0;                /* no active mime */
+  flagtoplevel = 1;    /* top message/rfc822 get special rx */
+  new_mime();          /* initiate a MIME info storage slot */
+
+  show_part(infop,1,0,1);      /* do real work, including html header etc */
+  if (flagpre)
+    oputs("</PRE>\n");
+  close(fd);
+  oputs("<HR></DIV>\n");
+  msglinks(infop);
+  html_footer(0);
+  return 1;
+}
+
+char decode_item(char ch)
+{
+  switch (ch) {
+       case 'm': return ITEM_MESSAGE;
+       case 'a': return ITEM_AUTHOR ;
+       case 's': return ITEM_SUBJECT;
+       case 'd': return ITEM_DATE   ;
+       case 'i': return ITEM_INDEX  ;
+       default: cgierr("Navigation command contains ",
+               "illegal item code","");
+  }
+  return 0;    /* never reached */
+}
+
+char decode_direction(char ch)
+{
+  switch (ch) {
+       case 's': return DIRECT_SAME;
+       case 'n': return DIRECT_NEXT;
+       case 'p': return DIRECT_PREV;
+       default: cgierr("Navigation command contains ",
+               "illegal direction code","");
+  }
+  return 0;    /* never reached */
+}
+
+int decode_cmd(char *s,struct msginfo *infop)
+/* decodes s into infop. Assures that no security problems slip through by */
+/* checking everything */
+/* commands xyd:123[:abc]. x what we want, y is the axis, d the direction. */
+/* 123 is the current message number. abc is a date/subject/author hash,   */
+/* depending on axis, or empty if not available. */
+/* returns: 0 no command+msgnum. */
+/*          1 empty or at least cmd + msgnum. */
+/*            Guarantee: Only legal values accepted */
+{
+  register char ch;
+
+  infop->source = 0L;
+  infop->date = 0L;
+  infop->author = (char *)0;
+  infop->subject = (char *)0;
+  infop->cgiarg = (char *)0;
+
+  if (!s || !*s) {     /* main index */
+    infop->item = ITEM_DATE;
+    infop->axis = ITEM_DATE;
+    infop->direction = DIRECT_SAME;
+    latestdate(&msginfo,0);
+    infop->target = MAXULONG;
+    return 1;
+  }
+  ch = *(s++);
+  if (ch >= '0' && ch <= '9') {        /* numeric - simplified cmd: msgnum ... */
+    s--;
+    infop->item = ITEM_MESSAGE;
+    infop->axis = ITEM_MESSAGE;
+    infop->direction = DIRECT_SAME;
+  } else {                     /* what:axis:direction:msgnum ... */
+    infop->item = decode_item(ch);
+    ch = *(s++);
+    infop->axis = decode_item(ch);
+    ch = *(s++);
+    infop->direction = decode_direction(ch);
+    if (*(s++) != ':') return 0;
+  }
+  s+= scan_ulong(s,&(infop->source));
+  if (*(s++) != ':') return 0;
+  if (*s >= '0' && *s <= '9') {        /* numeric nav hint [date] */
+    s+= scan_ulong(s,&(infop->date));
+    if (!*s++) return 1;       /* skip any char - should be ':' unless NUL */
+  }
+  if (checkhash(s)) {          /* Ignore if illegal rather than complaining*/
+    if (!stralloc_copyb(&charg,s,HASHLEN)) die_nomem();
+    if (!stralloc_0(&charg)) die_nomem();
+    infop->cgiarg = charg.s;
+  }
+  return 1;
+}
+
+int msg2hash(struct msginfo *infop)
+{
+  unsigned int pos;
+  unsigned long tmpmsg;
+
+  if (!infop->source) die_prog("source is 0 in msg2hash");
+  (void) makefn(&fn,ITEM_INDEX,infop->source,"");
+  if ((fd = open_read(fn.s)) == -1) {
+    if (errno == error_noent)
+      return 0;
+    else
+      strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+  }
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  for (;;) {
+        if (getln(&ssin,&line,&match,'\n') == -1)
+          strerr_die3sys(111,FATAL,ERR_READ,"index: ");
+        if (!match)
+         return 0;                             /* didn't find message */
+       if (*line.s == '\t') continue;          /* author line */
+        pos = scan_ulong(line.s,&tmpmsg);
+       if (tmpmsg == infop->source) {
+          if (line.s[pos++] != ':' || line.s[pos++] != ' ')
+           strerr_die3x(100,ERR_SYNTAX,fn.s,": missing subject separator");
+         if (line.len < HASHLEN + pos)
+           strerr_die3x(100,ERR_SYNTAX,fn.s,": missing subject hash");
+         if (!stralloc_copyb(&subject,line.s+pos,HASHLEN)) die_nomem();
+         if (!stralloc_0(&subject)) die_nomem();
+         infop->subject = subject.s;
+          if (getln(&ssin,&line,&match,'\n') == -1)
+            strerr_die3sys(111,FATAL,ERR_READ,"index: ");
+          if (!match)
+           strerr_die3x(100,ERR_SYNTAX,fn.s,
+               ": author info missing. Truncated?");
+         pos = byte_chr(line.s,line.len,';');
+         if (pos == line.len)
+           strerr_die3x(100,ERR_SYNTAX,fn.s,"missing ';' after date");
+         if (pos > 1)
+           infop->date = date2yyyymm(line.s+1);        /* ';' marks end ok */
+         pos++;
+         if (line.len < HASHLEN + pos)
+           strerr_die3x(100,ERR_SYNTAX,fn.s,": missing author hash");
+         if (!stralloc_copyb(&author,line.s+pos,HASHLEN)) die_nomem();
+         if (!stralloc_0(&author)) die_nomem();
+         infop->author = author.s;
+         close(fd);
+         return 1;     /* success */
+        }
+  }
+  close(fd);
+  return 0;            /* failed to match */
+}
+
+void setmsg(struct msginfo *infop)
+/* Reads the file corresponding to infop->axis and assumes fn.s is set */
+/* correctly for this. Sets up a msgnav structure and links it in      */
+/* correction for axis=author/subject. For axis=date it supports also  */
+/* direction=DIRECT_FIRST which will return the first message of the   */
+/* first thread in the date file. DIRECT_LAST is not supported.        */
+/* DIRECT_FIRST is supported ONLY for date. */
+{
+  if (infop->direction == DIRECT_SAME) {
+    infop->target = infop->source;
+    return;
+  }
+  if ((fd = open_read(fn.s)) == -1) {
+    if (errno == error_noent)
+      strerr_die4x(100,FATAL,ERR_OPEN,fn.s,
+       " in listmsgs. Rerun ezmlm-archive!");
+    else
+      strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+  }
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  if (infop->source != ITEM_DATE) {
+    if (getln(&ssin,&line,&match,'\n') == -1)  /* first line */
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match)
+      strerr_die3x(100,ERR_SYNTAX,fn.s,": first line missing");
+  }
+  msgnav[3] = 0L;              /* next */
+  msgnav[4] = 0L;              /* after */
+  infop->target = 0L;
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match) break;
+    msgnav[0] = msgnav[1];
+    msgnav[1] = msgnav[2];
+    (void) scan_ulong(line.s,&(msgnav[2]));
+    if (infop->direction == DIRECT_FIRST) break;
+    if (msgnav[2] == infop->source) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+      if (!match) break;
+      (void) scan_ulong(line.s,&(msgnav[3]));
+      if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+      if (!match) break;
+      (void) scan_ulong(line.s,&(msgnav[4]));
+      break;
+    }
+  }
+  close(fd);
+  switch (infop->axis) {
+    case ITEM_AUTHOR:
+      infop->authnav = msgnav + 2 + infop->direction;
+      infop->target = *(infop->authnav);
+      infop->subject = (char *)0;      /* what we know is not for this msg */
+      infop->date = 0;
+      break;
+    case ITEM_SUBJECT:
+      infop->subjnav = msgnav + 2 + infop->direction;
+      infop->target = *(infop->subjnav);
+      infop->author = (char *)0;       /* what we know is not for this msg */
+      infop->date = 0;
+      break;
+    case ITEM_DATE:
+      infop->target = msgnav[2];
+      infop->subject = (char *)0;      /* what we know is not for this msg */
+      infop->author = (char *)0;       /* what we know is not for this msg */
+    default:
+      die_prog("Bad item in setmsg");
+  }
+  return;
+}
+
+void auth2msg(struct msginfo *infop)
+{
+  if (!infop->author) die_prog("no such author in authmsg");
+  if (!makefn(&fn,ITEM_AUTHOR,0L,infop->author)) die_prog("auth2msg");
+  setmsg(infop);
+}
+
+void subj2msg(struct msginfo *infop)
+{
+  if (!infop->subject) die_prog("no such subject in subj2msg");
+  if (!makefn(&fn,ITEM_SUBJECT,0L,infop->subject)) die_prog("subj2msg");
+  setmsg(infop);
+}
+
+void date2msg(struct msginfo *infop)
+{
+  (void) makefn(&fn,ITEM_DATE,infop->date,"");
+  setmsg(infop);
+}
+
+void findlastmsg(struct msginfo *infop)
+{
+  if (!getconf_line(&line,"num",dir,0,FATAL))
+    cgierr("Sorry, there are no messages in the archive","","");
+  if (!stralloc_0(&line)) die_nomem();
+  (void) scan_ulong(line.s,&(infop->target));
+}
+
+int do_cmd(struct msginfo *infop)
+/* interprets msginfo to create msginfo. Upon return, msginfo can be trusted */
+/* to have all info needed, and that all info is correct. There may be more */
+/* info than needed. This can be used to build more specific links. NOTE:   */
+/* there is no guarantee that a message meeting the criteria actually exists*/
+{
+  infop->target = infop->source;
+
+  switch (infop->item) {
+       case ITEM_MESSAGE:      /* we want to get a message back */
+         {
+           switch (infop->axis) {
+             case ITEM_MESSAGE:
+               if (infop->direction == DIRECT_SAME)
+                 break;
+               else if (infop->direction == DIRECT_NEXT)
+                 (infop->target)++;
+               else {          /* previous */
+                 cache = 2;
+                 if (infop->target >= 2)
+                   (infop->target)--;
+                 else
+                   infop->target = 1;
+               }
+               break;
+             case ITEM_AUTHOR:
+                 infop->author = infop->cgiarg;
+               if (!infop->author)      /* we don't know author hash */
+                 if (!msg2hash(infop)) return 0;
+               auth2msg(infop);
+               break;
+             case ITEM_SUBJECT:
+                 infop->subject = infop->cgiarg;
+               if (!infop->subject)     /* we don't know Subject hash */
+                 if (!msg2hash(infop)) return 0;
+               subj2msg(infop);
+               break;
+           }
+           break;
+         }
+       case ITEM_AUTHOR:
+         switch (infop->axis) {
+           case ITEM_MESSAGE:
+             if (!infop->author)
+               if (!msg2hash(infop)) return 0;
+             break;
+           case ITEM_AUTHOR:
+             infop->author = infop->cgiarg;
+             if (!infop->author)
+               if (!msg2hash(infop)) return 0;
+               auth2msg(infop);
+             break;
+           case ITEM_SUBJECT:
+             infop->subject = infop->cgiarg;
+             if (!infop->subject)       /* we don't know Subject hash */
+               if (!msg2hash(infop)) return 0;
+             subj2msg(infop);
+             break;
+           }
+           break;
+       case ITEM_SUBJECT:
+         switch (infop->axis) {
+           case ITEM_MESSAGE:
+             if (!msg2hash(infop)) return 0;
+             break;
+           case ITEM_AUTHOR:
+             infop->author = infop->cgiarg;
+             if (!infop->author)
+               if (!msg2hash(infop)) return 0;
+             auth2msg(infop);
+             break;
+           case ITEM_SUBJECT:
+             infop->subject = infop->cgiarg;
+             if (!infop->subject)       /* we don't know Subject hash */
+               if (!msg2hash(infop)) return 0;
+             subj2msg(infop);
+             break;
+           }
+           break;
+         case ITEM_DATE:       /* want a date reference */
+           switch (infop->axis) {
+             case ITEM_MESSAGE:
+             case ITEM_AUTHOR:
+             case ITEM_SUBJECT:
+             case ITEM_DATE:
+               if (!infop->date && infop->source)
+                 if (!msg2hash(infop)) return 0;
+                 getdate(infop,0);
+               break;
+           }
+           break;
+         case ITEM_INDEX:      /* ignore direction etc - only for index */
+           if (!infop->target)
+             infop->target = infop->source;
+           if (!infop->target)
+             findlastmsg(infop);
+           break;
+  }
+  return 1;
+}
+
+void list_lists()
+{
+  unsigned long lno;
+  cache = 2;
+  flagrobot = 2;
+  html_header("Robot index of lists",0,0,0,0);
+  for (;;) {
+    if (getln(&ssin,&cfline,&match,'\n') == -1)                /* read line */
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match)
+      break;
+    if (cfline.s[0] == '#') continue;                  /* skip comment */
+    cfline.s[cfline.len - 1] = '\0';                   /* so all are sz */
+    (void) scan_ulong(cfline.s,&lno);                  /* listno for line */
+    if (lno) {                         /* don't expose default list */
+      oputs("<A href=\"");
+      oput(strnum,fmt_ulong(strnum,lno));
+      oputs("/index\">[link]</a>\n");
+   }
+  }
+  html_footer(0);
+}
+
+void list_list(unsigned long listno)
+/* Make one link [for list_set()] per set of 100 archive messages. */
+/* Assumption: Any directory DIR/archive/xxx where 'xxx' is a numeric,*/
+/* is part of the list archive and has in it an index file and one    */
+/* or more messages. */
+{
+  DIR *archivedir;
+  direntry *d;
+  unsigned long msgset;
+
+  flagrobot = 2;
+  strnum[fmt_ulong(strnum,listno)] = '\0';
+  archivedir = opendir("archive/");
+  if (!archivedir)
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/archive: ");
+    else
+      strerr_die4sys(100,FATAL,ERR_OPEN,dir,"/archive: ");
+
+  cache = 1;
+  html_header("Robot index for message sets in list",0,0,0,0);
+
+  while ((d = readdir(archivedir))) {
+    if (d->d_name[scan_ulong(d->d_name,&msgset)])
+       continue;               /* not numeric */
+    oputs("<a href=\"../");    /* from /ezcgi/0/index to /ezcgi/listno/index*/
+    oputs(strnum);
+    oputs("/index/");
+    oputs(d->d_name);
+    oputs("\">[link]</a>\n");
+  }
+  closedir(archivedir);
+  html_footer(0);
+}
+
+void list_set(unsigned long listno,unsigned long msgset)
+{
+  unsigned int msgfirst,msgmax;
+  unsigned long lastset;
+
+  flagrobot = 2;
+  findlastmsg(&msginfo);
+  if (!stralloc_copys(&line,"<a href=\"../")) die_nomem();
+  if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgset))) die_nomem();
+  lastset = msginfo.target / 100;
+  cache = 2;
+  msgfirst = 0;
+  if (!msgset)
+    msgfirst = 1;
+  msgmax = 99;
+  if (msgset > lastset) {              /* assure empty list */
+    msgmax = 0;
+    msgfirst = 1;
+  } else if (msgset == lastset) {
+    cache = 0;                         /* still changing */
+    msgmax = msginfo.target % 100;
+  }
+  html_header("Robot index for messages in set",0,0,0,0);
+  while (msgfirst <= msgmax) {
+    oput(line.s,line.len);
+    oput(strnum,fmt_uint0(strnum,msgfirst,2));
+    oputs("\">[link]</a>\n");
+    msgfirst++;
+  }
+  html_footer(0);
+}
+
+/**************** MAY BE SUID ROOT HERE ****************************/
+void drop_priv(int flagchroot)
+{
+  if (!uid) strerr_die2x(100,FATAL,ERR_SUID);          /* not as root */
+  if (!euid) {
+    if (flagchroot)
+      if (chroot(dir) == -1)                           /* chroot listdir */
+        strerr_die4sys(111,FATAL,"failed to chroot ",dir,": ");
+    if (setuid(uid) == -1)                             /* setuid */
+      strerr_die2sys(111,FATAL,ERR_SETUID);
+  }
+  euid = (unsigned long) geteuid();
+  if (!euid) strerr_die2x(100,FATAL,ERR_SUID);         /* setuid didn't do it*/
+}
+/*******************************************************************/
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+  char *cp,*cppath;
+  unsigned long listno,thislistno,tmpuid,msgset;
+  unsigned long msgnum = 0;
+  unsigned long port = 0L;
+  unsigned long tmptarget;
+  unsigned int pos,l;
+  int flagindex = 0;
+  int flagchroot = 1;          /* chroot listdir if SUID root */
+  int ret;
+  char sep;
+
+/******************** we may be SUID ROOT ******************************/
+  uid = (unsigned long) getuid();                      /* should be http */
+  euid = (unsigned long) geteuid();                    /* chroot only if 0 */
+
+  if (!euid) {
+    if ((fd = open_read(EZ_CGIRC)) == -1)              /* open config */
+      strerr_die4sys(111,FATAL,ERR_OPEN,EZ_CGIRC,": ");
+  } else {
+    if ((fd = open_read(EZ_CGIRC_LOC)) == -1)          /* open local config */
+      strerr_die4sys(111,FATAL,ERR_OPEN,EZ_CGIRC_LOC,": ");
+  }
+
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));   /* set up buffer */
+       /* ##### tainted info #####*/
+
+  cmd = env_get("QUERY_STRING");                       /* get command */
+  cppath = env_get("PATH_INFO");                       /* get path_info */
+
+  if (!cppath || !*cppath) {
+    if (cmd && *cmd) {
+      cmd += scan_ulong(cmd,&thislistno);
+      if (*cmd == ':') cmd++;                          /* allow ':' after ln*/
+    } else
+      thislistno = 0L;
+  } else {
+    cppath++;
+      cppath += scan_ulong(cppath,&thislistno);                /* this listno */
+      if (!thislistno || *cppath++ == '/') {
+       if (str_start(cppath,"index")) {
+          cppath += 5;
+         flagindex = 1;
+         if (!thislistno) {                            /* list index */
+           drop_priv(0);       /* <---- dropping privs */
+           list_lists();
+           close(fd);
+           _exit(0);
+         }
+       }
+      }                                                        /* rest done per list */
+    }
+
+  for (;;) {
+    if (getln(&ssin,&cfline,&match,'\n') == -1)                /* read line */
+      strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+    if (!match)
+      break;
+    if (*cfline.s == '#' || cfline.len == 1) continue; /* skip comment/blank */
+    cfline.s[cfline.len - 1] = '\0';                   /* so all are sz */
+    pos = scan_ulong(cfline.s,&listno);                        /* listno for line */
+    if (thislistno != listno) continue;
+    sep = cfline.s[pos++];
+    if (cfline.s[pos] == '-') {                                /* no chroot if -uid*/
+      flagchroot = 0;
+      pos++;
+    }
+    pos += scan_ulong(cfline.s+pos,&tmpuid);           /* listno for line */
+    if (tmpuid) uid = tmpuid;                          /* override default */
+    if (!cfline.s[pos++] == sep)
+      die_syntax("missing separator after user id");
+    if (cfline.s[pos] != '/')
+       die_syntax("dir");                              /* absolute path */
+    l = byte_chr(cfline.s + pos, cfline.len - pos,sep);
+    if (l == cfline.len - pos)                         /* listno:path:...*/
+      die_syntax("missing separator after path");
+    dir = cfline.s + pos;
+    pos += l;
+    cfline.s[pos++] = '\0';                            /* .../dir\0 */
+    break;     /* do rest after dropping priv */
+  }
+  close(fd);                                           /* don't accept uid 0*/
+  if (!dir) {
+    drop_priv(0);      /* don't trust cgierr. No dir, no chroot */
+    cgierr("list ",ERR_NOEXIST,"");
+  }
+  if (chdir(dir) == -1)                                        /* chdir listdir */
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+  drop_priv(flagchroot);
+
+/******************************* RELAX **********************************/
+
+/********************* continue to process config line ******************/
+
+  flagrobot = 0;
+  if (cfline.s[pos] == '-') {
+    flagobscure = 1;
+    pos++;
+  }
+  local = cfline.s + pos;
+  l = byte_chr(cfline.s + pos, cfline.len - pos,sep);  /* ... home */
+  if (l < cfline.len - pos) {                          /* optional */
+    pos += l;
+    cfline.s[pos++] = '\0';
+    home = cfline.s + pos;
+    l = byte_chr(cfline.s + pos, cfline.len - pos,sep);        /* ... charset */
+    if (l < cfline.len - pos) {                                /* optional */
+      pos += l;
+      cfline.s[pos++] = '\0';
+      charset = cfline.s + pos;
+      l = byte_chr(cfline.s+pos,cfline.len - pos,sep); /* ... stylesheet */
+      if (l < cfline.len - pos) {                      /* optional */
+        pos += l;
+        cfline.s[pos++] = '\0';
+        stylesheet = cfline.s + pos;
+        l = byte_chr(cfline.s+pos,cfline.len-pos,sep); /* ... bannerURL */
+       if (l < cfline.len - pos) {                     /* optional */
+         pos += l;
+         cfline.s[pos++] = '\0';
+         banner = cfline.s + pos;
+       }
+      }
+    }
+  }
+  if (!charset || !*charset)                           /* rfc822 default */
+    charset = EZ_CHARSET;
+  if (!stralloc_copys(&curcharset,charset)) die_nomem();
+  csbase = decode_charset(curcharset.s,curcharset.len);
+  if (csbase == CS_BAD) csbase = CS_NONE;
+  cs = csbase;
+  pos = + str_rchr(local,'@');
+  if (!local[pos])
+    die_syntax("listaddress lacks '@'");               /* require host */
+  local[pos++] = '\0';
+  host = local + pos;
+
+/********************* Accomodate robots and PATH_INFO ****************/
+
+  if (flagindex) {
+    if (*(cppath++) == '/') {          /* /2/index/123 */
+      cppath += scan_ulong(cppath,&msgset);
+      list_set(thislistno,msgset);
+    } else                             /* /2/index */
+      list_list(thislistno);
+    _exit(0);
+  }
+
+  if (cppath && *cppath) {             /* /2/msgnum */
+    flagrobot = 1;                     /* allow index, but "nofollow" */
+    scan_ulong(cppath,&msgnum);
+  }                                    /* dealt with normally */
+
+/********************* Get info from server on BASE etc ****************/
+
+  if (!stralloc_copys(&base,"<BASE href=\"http://")) die_nomem();
+  cp = env_get("SERVER_PORT");
+  if (cp) {                    /* port */
+    (void) scan_ulong(cp,&port);
+    if ((unsigned int) port == 443) {          /* https: */
+      if (!stralloc_copys(&base,"<BASE href=\"https://")) die_nomem();
+    }
+  }
+  if (port && (unsigned int) port != 80 && (unsigned int) port != 443) {
+      if (!stralloc_cats(&base,":")) die_nomem();
+      if (!stralloc_catb(&base,strnum,fmt_ulong(strnum,port))) die_nomem();
+  }
+  if (!(cp = env_get("HTTP_HOST")))
+    if (!(cp = env_get("SERVER_NAME")))
+      strerr_die2x(100,FATAL,"both HTTP_HOST and SERVER_NAME are empty");
+  if (!stralloc_cats(&base,cp)) die_nomem();
+  if (!(cp = env_get("SCRIPT_NAME")))
+    strerr_die2x(100,FATAL,"empty SCRIPT_NAME");
+  if (!stralloc_cats(&base,cp)) die_nomem();
+  if (!stralloc_cats(&base,"\">\n")) die_nomem();
+  if (!stralloc_copys(&url,"<A HREF=\"")) die_nomem();
+  pos = str_rchr(cp,'/');
+  if (cp[pos])
+    if (!stralloc_cats(&url,cp + pos + 1)) die_nomem();
+  if (!stralloc_cats(&url,"?")) die_nomem();
+  if (thislistno) {
+    if (!stralloc_catb(&url,strnum,fmt_ulong(strnum,thislistno))) die_nomem();
+    if (!stralloc_cats(&url,":")) die_nomem();
+  }
+
+  cache = 1;                           /* don't know if we want to cache */
+
+/****************************** Get command ****************************/
+
+  if (msgnum) {                                /* to support /listno/msgno */
+   msginfo.target = msgnum;
+   msginfo.item = ITEM_MESSAGE;
+   cache = 2;
+  } else {
+      (void) decode_cmd(cmd,&msginfo);
+      if (!do_cmd(&msginfo))
+       cgierr("I'm sorry, Dave ... I can't do that, Dave ...","","");
+  }
+
+  switch (msginfo.item) {
+    case ITEM_MESSAGE:
+       if (!show_message(&msginfo)) {          /* assume next exists ... */
+         cache = 0;                            /* border cond. - no cache */
+         msginfo.target = msginfo.source;      /* show same */
+         msginfo.subjnav = 0;
+         msginfo.authnav = 0;
+         ret = show_message(&msginfo);
+       }
+       break;
+    case ITEM_AUTHOR:
+       if (!show_object(&msginfo,ITEM_AUTHOR))
+         cgierr ("I couldn't find the author for that message","","");
+       break;
+    case ITEM_SUBJECT:
+       if (!show_object(&msginfo,ITEM_SUBJECT))
+         cgierr ("I couldn't find the subject for that message","","");
+       break;
+    case ITEM_DATE:
+       if (!show_object(&msginfo,ITEM_DATE)) {
+         finddate(&msginfo);
+         ret = show_object(&msginfo,ITEM_DATE);
+       }
+       break;
+    case ITEM_INDEX:
+       if (!show_index(&msginfo)) {
+         tmptarget = msginfo.target;
+         findlastmsg(&msginfo);
+         cache = 0;                    /* latest one - no cache */
+         if (!msginfo.target || msginfo.target > tmptarget) {
+           cache = 2;                  /* won't change */
+            firstdate(&msginfo,1);     /* first thread index */
+           msginfo.direction = DIRECT_FIRST;
+           date2msg(&msginfo);         /* (may not be 1 if parts removed) */
+         }
+         ret = show_index(&msginfo);
+       }
+       break;
+    default:
+       strerr_die2x(100,FATAL,"bad item in main");
+  }
+  if (!ret) {
+    findlastmsg(&msginfo);             /* as last resort; last msgindex */
+    cache = 0;
+    ret = show_message(&msginfo);
+  }
+
+ _exit(0);
+}
diff --git a/ezmlm-check.1 b/ezmlm-check.1
new file mode 100644 (file)
index 0000000..e2e07d7
--- /dev/null
@@ -0,0 +1,52 @@
+.TH ezmlm-check 1
+.SH NAME
+ezmlm-check \- Mails back results of ezmlm list check
+.SH SYNOPSIS
+.B ezmlm-check
+[
+.B \-sS
+]
+.I [dir]
+.SH DESCRIPTION
+.B ezmlm-check
+mails useful environment variables to SENDER via
+.BR qmail-inject .
+It is usually invoked for debugging purposes in a
+.I .qmail
+file to determine the value of relevant environment variables.
+If
+.I dir
+is specified,
+.B ezmlm-check
+attempts to evaluate the
+.I ezmlm
+mailing list set up in
+.I dir
+and return information about the setup as well as possible
+errors.
+
+.B ezmlm-check
+will flag errors with
+.BR ``???\ ERROR'' ,
+likely errors with
+.BR ``???'' ,
+and potential errors/problems with
+.BR ``!!!'' .
+
+If
+.B ezmlm-check
+is invoked from the shell, it will print to stdout.
+In this case, diagnostics are more limited,
+since important environment variables
+normally supplied by qmail are not available.
+.SH OPTIONS
+.TP 5
+.B \-s
+(Default.) List subscribers.
+.TP 5
+.B \-S
+Do not list subscribers.
+.SH "SEE ALSO"
+ezmlm(5),
+qmail(7),
+qmail-inject(8)
diff --git a/ezmlm-check.sh b/ezmlm-check.sh
new file mode 100644 (file)
index 0000000..b844d1b
--- /dev/null
@@ -0,0 +1,670 @@
+
+# [should have a bin/sh line and EZPATH/QMPATH added above by make]
+#
+# script to diagnose ezmlm lists
+# call as is for environment only, or as ezmlm-check 'DIR' for more info
+
+listsubscribers=yes
+if [ "$1" = '-S' ] ; then
+  listsubscribers=no
+  shift
+else
+    if [ "$1" = '-s' ] ; then
+      shift
+    fi
+fi
+
+QINJECT="${QMPATH}/bin/qmail-inject"
+EZLIST="${EZPATH}/ezmlm-list"
+MYNAME='ezmlm-check'
+MYDTLINE="Delivered-To: ${MYNAME}"
+FATAL="${MYNAME}: fatal:"
+EZERR="??? ERROR:"
+EZWARN="!!! Warning:"
+# This should be a ``grep'' that does regexps. Needs to recognize ^ and $.
+GREP='grep'
+CAT='cat'
+CUT='cut'
+ECHO='echo'
+# Needed to isolate some lines in the DIR/editor ... files
+HEAD='head'
+TAIL='tail'
+# needed to count characters in $USER
+WC='wc'
+# should mark executables with '*' and list one file per line
+LS='ls -F1'
+# should list links as: "... symlink -> file"
+LLS='ls -l'
+if [ ! -x "$QINJECT" ]; then
+  ${ECHO} "$FATAL edit script to for path to qmail-inject"
+  exit 100
+fi
+
+if [ -z "$SENDER" ] ; then
+       RCP="${CAT}"
+else
+       RCP="$QINJECT"
+       if ${CAT} - | ${GREP} "${MYDTLINE}" >/dev/null 2>&1
+         then
+           ${ECHO} "FATAL this message is looping: it already has my Delivered-To line (#5.4.6)"
+           exit 100
+       fi
+fi
+
+if [ ! -z "$1" -a ! -d "$1" ]; then
+  ${ECHO} "$FATAL $1 is not a directory"; exit 100
+fi
+
+# reset variables
+GET=''; DIGEST=''; FLAGARCH=''; FLAGIND=''; INLOCAL=''; INLOCALOK=''; INHOST=''
+MANAGE=''; OUTLOCAL=''; OUTHOST=''; SPEC=''; SRESTRICT=''; STORE=''; REMOTE=''
+MODSUB=''; MODPOST=''; SPEC=''
+
+(
+       ${ECHO} "Delivered-To: ezmlm-check"
+       ${ECHO} "To: $SENDER"
+       ${ECHO} "Subject: ${MYNAME} results"
+       ${ECHO}
+       ${ECHO} "Important environment variables:"
+       ${ECHO}
+       ${ECHO} "SENDER ='$SENDER'"
+       ${ECHO} "NEWSENDER ='$NEWSENDER'"
+       ${ECHO} "RECIPIENT ='$RECIPIENT'"
+       ${ECHO} "USER ='$USER'"
+       ${ECHO} "DEFAULT ='$DEFAULT'"
+       ${ECHO} "LOCAL ='$LOCAL'"
+       ${ECHO} "HOST ='$HOST'"
+       ${ECHO} "---------------------------------------------------"
+       if [ ! -z "$1" ]; then
+         ${ECHO} "Checking basic list setup:"
+         ${ECHO}
+         if [ ! -r "$1/mailinglist" ]; then
+           ${ECHO} "$EZERR $1/mailinglist does not exist"
+         fi
+         if [ -e "$1/num" ]; then
+           if [ ! -w "$1/num" ]; then
+             ${ECHO} "$EZERR $1/num is not writable to $USER"
+           else
+             NUM=`${CAT} "$1/num" | ${HEAD} -1`
+             ${ECHO} "... latest message was message # $NUM"
+            fi
+         else
+           ${ECHO} "... no num. This must be a new list ..."
+         fi
+         ${ECHO}
+         if [ -e "$1/lock" -a ! -w "$1/lock" ]; then
+           ${ECHO} "$EZERR User $USER does not have write premission to $1/lock"
+         fi
+         if [ -e "$1/lockbounce" -a ! -w "$1/lockbounce" ]; then
+           ${ECHO} "$EZERR User $USER does not have write premission to $1/lockbounce"
+         fi
+         if [ ! -r "$1/inlocal" ]; then
+           ${ECHO} "$EZERR $1/inlocal does not exist"
+         elif [ ! -r "$1/inhost" ]; then
+             ${ECHO} "$EZERR $1/inhost does not exist"
+         else
+           INLOCAL=`${CAT} "$1/inlocal"| ${HEAD} -1`
+            INHOST=`${CAT} "$1/inhost"| ${HEAD} -1`
+           if [ -z "$HOST" ]; then
+             ${ECHO} "$EZERR HOST is empty. Likely running from the command"
+             ${ECHO} "    line. Run from $1/editor to check if HOST matches"
+             ${ECHO} "    $1/inhost and LOCAL matches $1/inlocal."
+             ${ECHO} "    Mismatches here are the most common setup error."
+             ${ECHO}
+           else
+             if [ "$HOST" != "$INHOST" ]; then
+               ${ECHO} "$EZERR HOST does not match $1/inhost"
+             else
+               ${ECHO} "... $1/inhost OK"
+             fi
+             if ${ECHO} "$LOCAL" | ${GREP} -G "^$INLOCAL" >/dev/null 2>&1
+              then
+               ${ECHO} "... $1/inlocal OK"
+             else
+               ${ECHO} \
+                "$EZERR LOCAL does not begin with contents of $1/inlocal"
+             fi
+           fi
+         fi
+         if [ ! -r "$1/outlocal" ]; then
+           ${ECHO} "$EZERR $1/outlocal does not exist"
+         else
+           OUTLOCAL=`${CAT} "$1/outlocal"| ${HEAD} -1`
+         fi
+         if [ ! -r "$1/outhost" ]; then
+             ${ECHO} "$EZERR $1/outhost does not exist"
+          else
+             OUTHOST=`${CAT} "$1/outhost"| ${HEAD} -1`
+         fi
+         ${ECHO} "... The list is named ${OUTLOCAL}@${OUTHOST}"
+         if [ "$OUTHOST" != "$INHOST" ]; then
+           HOSTMATCH='1';
+           ${ECHO}
+           ${ECHO} "??? $1/inhost and $1/outhost do not"
+           ${ECHO} "    match. This is very unusual ..."
+         fi
+         if ${ECHO} "$INLOCAL" | ${GREP} "^${USER}" >/dev/null ; then
+           USERSTART='1'; INLOCALOK='1'
+         fi
+         if [ -z "$USERSTART" ]; then
+           ${ECHO}
+           ${ECHO} "??? $1/inlocal does not start with the user name."
+           ${ECHO} "    This is an error, unless $INLOCAL starts with"
+           ${ECHO} "    an alias of \"$USER\"."
+         fi
+         if [ "$INLOCAL" = "$OUTLOCAL" ]; then
+           ${ECHO} "... $1/inlocal matches $1/outlocal"
+           ${ECHO} "    suggesting that this is a regular user-owned list."
+           CHARS=`${ECHO} " $USER" | ${WC} -c`
+           LIST=`${ECHO} "$OUTLOCAL" | cut -c$CHARS-`
+         else
+           if  ${ECHO} "$INLOCAL" | ${GREP} "$OUTLOCAL$" >/dev/null ; then
+             if [ ! -z "$USERSTART" ]; then
+               ${ECHO} "... It appears that $OUTHOST is a virtual domain"
+               ${ECHO} "    controlled by $USER."
+               LIST="$OUTLOCAL"
+               if [ ! -z "$HOSTMATCH" ]; then
+                 ${ECHO} "   This part of the setup appears correct."
+               fi
+             else
+               ${ECHO}
+               ${ECHO} "$EZWARN $1/inlocal ends with the contents"
+               ${ECHO} "    of $1/outlocal, but does not start with"
+               ${ECHO} "    $USER. If this message persists when you"
+               ${ECHO} "    run this program from $1/editor,"
+               ${ECHO} "    there is a setup error."
+             fi
+           else
+             ${ECHO}
+             ${ECHO} "$EZWARN $1/inlocal does not end with the contents"
+             ${ECHO} "    of $1/outlocal. This is almost always wrong."
+           fi
+          fi
+         if [ ! -r "$1/editor" ]; then
+             ${ECHO} "$EZERR $1/editor does not exist"
+         else
+           ${ECHO}
+           ${ECHO} "$1/editor:"
+           ${ECHO} "============================"
+           ${CAT} "$1/editor"
+           ${ECHO} "============================"
+           ${ECHO}
+         fi
+         if [ ! -r "$1/manager" ]; then
+             ${ECHO} "$EZERR $1/manager does not exist"
+         else
+           ${ECHO} "$1/manager:"
+           ${ECHO} "============================"
+           ${CAT} "$1/manager"
+           ${ECHO} "============================"
+           ${ECHO}
+         fi
+         if [ ! -r "$1/bouncer" ]; then
+             ${ECHO} "$EZERR $1/bouncer does not exist"
+         else
+           ${ECHO} "$1/bouncer:"
+           ${ECHO} "============================"
+           ${CAT} "$1/bouncer"
+           ${ECHO} "============================"
+           ${ECHO}
+         fi
+         if [ ! -r "$1/owner" ]; then
+             ${ECHO} "$EZERR $1/owner does not exist"
+         else
+           ${ECHO} "$1/owner:"
+           ${ECHO} "============================"
+           ${CAT} "$1/owner"
+           ${ECHO} "============================"
+           ${ECHO}
+           OWNER=`${GREP} "@" < $1/owner`
+         fi
+         if [ ! -r "$1/headeradd" ]; then
+             ${ECHO} "$EZERR $1/headeradd does not exist"
+         else
+           ${ECHO} "$1/headeradd:"
+           ${ECHO} "============================"
+           ${CAT} "$1/headeradd"
+           ${ECHO} "============================"
+           ${ECHO}
+         fi
+         if [ ! -r "$1/headerremove" ]; then
+             ${ECHO} "$EZERR $1/headerremove does not exist"
+         else
+           ${ECHO} "$1/headerremove:"
+           ${ECHO} "============================"
+           ${CAT} "$1/headerremove"
+           ${ECHO} "============================"
+           ${ECHO}
+         fi
+         ${ECHO} "---------------------------------------------------"
+         ${ECHO} "Checking standard options:"
+         ${ECHO}
+         if [ -r "$1/public" ]; then
+           ${ECHO} "... public"
+         else
+           ${ECHO} "... not public"
+         fi
+         if [ -r "$1/archived" ]; then
+           FLAGARCH='1'
+           ${ECHO} "... archived"
+         else
+           ${ECHO} "... not archived"
+         fi
+         if [ -r "$1/indexed" ]; then
+           FLAGARCH='1'
+           FLAGIND='1'
+           ${ECHO} "... indexed"
+         else
+           ${ECHO} "... not indexed"
+         fi
+         if [ ! -z "$FLAGARCH" ]; then
+            if [ ! -d "$1/archive" ]; then
+             ${ECHO} "$EZERR $1/archive is not a directory"
+           else
+             if [ ! -z "$NUM" -a ! -r "$1/archive/0/index" \
+                       -a ! -z "$FLAGIND" ]; then
+               ${ECHO} "$EZWARN list is archived, but there is no index."
+               ${ECHO} "    Please run ezmlm-idx!"
+             fi
+            fi
+          fi
+          if [ ! -d "$1/bounce" ]; then
+           ${ECHO} "$EZERR $1/bounce is not a directory"
+         fi
+         if [ -r "$1/prefix" ]; then
+           PREFIX=`${HEAD} -1 "$1/prefix"`
+           ${ECHO} "... using $1/prefix as subject prefix: $PREFIX"
+           ${ECHO}
+         fi
+         if [ -r "$1/sublist" ]; then
+           ${ECHO} "... this is a sublist for:"
+           ${HEAD} -1 < "$1/sublist"
+         else
+           ${ECHO} "... not a sublist"
+         fi
+          if [ ! -d "$1/text" ]; then
+           ${ECHO} "$EZERR $1/text is not a directory"
+         fi
+         ${ECHO} "... Contents of $1/text not checked"
+         ${ECHO}
+         if [ ! -z "$OWNER" ]; then
+           ${ECHO} "... Mail to owner goes to: $OWNER"
+         else
+           ${ECHO} "$EZWARN Mail to owner seems not to be forwarded."
+           ${ECHO} "    Remember to check the mailbox once in a while!"
+         fi
+         ${ECHO}
+         ${ECHO} "--------------------------------------------------"
+         ${ECHO}
+         ${ECHO} "... Links should be:"
+         ${ECHO} "    ~/.qmail-{list} -> $1/editor"
+         ${ECHO} "    ~/.qmail-{list}-default -> $1/manager"
+         ${ECHO} "    ~/.qmail-{list}-owner -> $1/owner"
+         ${ECHO} "    ~/.qmail-{list}-return-default -> $1/bouncer"
+         if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then
+           ${ECHO}
+           ${ECHO} "    As far as I can see, '{list}' should be '$LIST'."
+           ${ECHO} "    If so and if .qmail files should be in $HOME ..."
+           BN="$HOME/.qmail-$LIST"
+           FN="$BN"
+           if ${LLS} "$FN" 2>/dev/null | ${GREP} "$1/editor$" >/dev/null ; then
+             ${ECHO} "      $FN is OK"
+           else
+             ${ECHO} "???    $FN is BAD"
+           fi
+           FN="$BN-default"
+           if ${LLS} "$FN" | ${GREP} "$1/manager$" >/dev/null ; then
+             ${ECHO} "      $FN OK"
+           else
+             ${ECHO} "???    $FN is BAD"
+           fi
+           FN="$BN-owner"
+           if ${LLS} "$FN" | ${GREP} "$1/owner$" >/dev/null ; then
+             ${ECHO} "      $FN is OK"
+           else
+             ${ECHO} "???    $FN is BAD"
+           fi
+           FN="$BN-return-default"
+           if ${LLS} "$FN" | ${GREP} "$1/bouncer$" >/dev/null ; then
+             ${ECHO} "      $FN is OK"
+           else
+             ${ECHO} "???    $FN is BAD"
+           fi
+         fi
+         ${ECHO} "--------------------------------------------------"
+         ${ECHO} "Checking subscribers:"
+         ${ECHO}
+          if [ ! -d "$1/subscribers" ]; then
+           ${ECHO} "$EZERR $1/subscribers is not a directory"
+         else
+            if [ ! -x "$EZLIST" ]; then
+             ${ECHO} "$EZLIST is not available for listing"
+           else
+             if [ "$listsubscribers" = "yes" ] ; then
+               ${ECHO} "... Subscribers are:"
+                if ${EZLIST} "$1" | ${GREP} '@' ; then
+                 :
+               else
+                 ${ECHO} "$EZWARN no subscribers!"
+                fi
+             else
+               if ${EZLIST} "$1" | ${GREP} '@' >/dev/null 2>&1 ; then
+                 ${ECHO} "... There are subscribers."
+               else
+                 ${ECHO} "$EZWARN no subscribers!"
+               fi
+             fi
+            fi
+         fi
+         ${ECHO}
+         ${ECHO} "--------------------------------------------------"
+         ${ECHO} "Checking for digest:"
+         ${ECHO}
+         if ${GREP} 'ezmlm-tstdig' < $1/editor >/dev/null 2>&1 ; then
+            if ${GREP} -1 'ezmlm-tstdig' < $1/editor \
+               | ${TAIL} -1 | ${GREP} 'ezmlm-get' >/dev/null; then
+             ${ECHO} "... integrated digest via $1/editor"
+             DIGEST='1'
+             ${ECHO}
+           fi
+         fi
+         if [ -z "$DIGEST" ]; then
+           ${ECHO} "... no digest via $1/editor"
+         else
+           ${ECHO} "... links should be:"
+           ${ECHO} "    ~/.qmail-{list}-digest-return-default -> $1/bouncer"
+           ${ECHO} "    ~/.qmail-{list}-digest-owner -> $1/owner"
+           if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then
+             ${ECHO}
+             ${ECHO} "    As far as I can see, '{list}' should be '$LIST'."
+             ${ECHO} "    If so and if .qmail files should be in $HOME ..."
+             BN="$HOME/.qmail-$LIST"
+             FN="$BN-digest-return-default"
+             if ${LLS} "$FN" 2>/dev/null | \
+                       ${GREP} "$1/bouncer$" >/dev/null ; then
+               ${ECHO} "      $FN is OK"
+             else
+               ${ECHO} "???    $FN is BAD"
+             fi
+             FN="$BN-digest-owner"
+             if ${LLS} "$FN" 2>/dev/null | \
+                       ${GREP} "$1/owner$" >/dev/null ; then
+               ${ECHO} "      $FN is OK"
+             else
+               ${ECHO} "???    $FN is BAD"
+             fi
+           fi
+         fi
+         if [ -d "$1/digest" ]; then
+           if [ ! -d "$1/digest/subscribers" ]; then
+             ${ECHO} "$EZERR $1/digest exists, but $1/digest/subscribers"
+             ${ECHO} "$EZERR is not a directory"
+             ${ECHO}
+           else
+             if [ ! -x "$EZLIST" ]; then
+               ${ECHO} "$EZLIST is not available for listing"
+             else
+               if [ "$listsubscribers" = "yes" ] ; then
+                 ${ECHO}
+                 ${ECHO} "... Digest subscribers are:"
+                  if ${EZLIST} "$1" | ${GREP} '@' ; then
+                   :
+                 else
+                   ${ECHO} "$EZWARN no subscribers!"
+                  fi
+               else
+                 if ${EZLIST} "$1" | ${GREP} '@' >/dev/null 2>&1 ; then
+                   ${ECHO} "... There are digest subscribers."
+                 else
+                   ${ECHO} "$EZWARN no subscribers!"
+                 fi
+               fi
+              fi
+             ${ECHO}
+            fi
+         fi
+         ${ECHO} "---------------------------------------------------"
+         ${ECHO} "Checking for subscription moderation/remote admin:"
+         ${ECHO}
+         if [ -r "$1/remote" ]; then
+           FLAGMOD='1'
+           ${ECHO} "... set up for remote administration"
+           REMOTE=`${CAT} "$1/remote"| ${HEAD} -1`
+            if ${ECHO} "$REMOTE" | ${GREP} -G "^/" >/dev/null 2>&1
+              then
+               MODDIR="$REMOTE"
+             else
+               MODDIR="$1/mod"
+           fi
+           REMOTE='1'
+         else
+           ${ECHO} "... no remote admin"
+          fi
+         if [ -r "$1/modsub" ]; then
+           FLAGMOD='1'
+           ${ECHO} "... subscription moderated"
+           MODSUB=`${CAT} "$1/modsub"| ${HEAD} -1`
+            if ${ECHO} "$MODSUB" | ${GREP} -G "^/" >/dev/null 2>&1
+           then
+              MODDIR="$MODSUB"
+           elif [ -z "$MODDIR" ]; then
+             MODDIR="$1/mod"
+           fi
+         else
+           ${ECHO} "... no subscription moderation"
+         fi
+         if [ "$FLAGMOD" = '1' ]; then
+           ${ECHO}
+           ${ECHO} "Mods/remote admins stored based in $MODDIR:"
+           ${ECHO}
+           if [ ! -d "$MODDIR" ]; then
+             ${ECHO} "$EZERR moderator dir $MODDIR doesn't exist!"
+           elif [ -e "$MODDIR/lock" -a ! -w "$MODDIR/lock" ]; then
+             ${ECHO} "$EZERR $MODDIR/lock is not writable to user $USER"
+           elif [ ! -x "$EZLIST" ]; then
+             ${ECHO} "${EZLIST} not available for listing"
+           else
+             if ${EZLIST} "$MODDIR" | ${GREP} '@' ; then
+                 :
+             else
+                 ${ECHO} "$EZERR no subscription moderators/remote admins!"
+             fi
+           fi
+           ${ECHO}
+         fi
+         ${ECHO} "---------------------------------------------------"
+         ${ECHO} "Checking for message moderation:"
+         ${ECHO}
+         if ${GREP} 'ezmlm-gate' < "$1/editor" > /dev/null 2>&1; then
+            GATE='1'
+         fi
+         if ${GREP} 'ezmlm-store' < "$1/editor" > /dev/null 2>&1; then
+            STORE='1'
+         fi
+         FLAGMOD=''
+         if [ -r "$1/modpost" ]; then
+           FLAGMOD='1'
+           MODPOST=`${CAT} "$1/modpost" | ${HEAD} -1`
+            if ${ECHO} "$MODPOST" | ${GREP} -G "^/" >/dev/null 2>&1
+              then
+             MODDIR="$MODPOST"
+           else
+             MODDIR="$1/mod"
+           fi
+         fi
+         if [ "$STORE" = '1' -a -z "$FLAGMOD" ]; then
+             ${ECHO} "??? it looks from $1/editor like the list is set up"
+             ${ECHO} "    for message moderation. However, since $1/modpost"
+              ${ECHO} "    doesn't exist, ezmlm-store posts them directly. If"
+              ${ECHO} "    this is not intended, please create $1/modpost."
+             ${ECHO}
+             FLAGMOD='1'
+             MODDIR="$1/mod"
+         elif [ -z "$STORE" -a -z "$GATE" -a "$FLAGMOD" = '1' ]; then 
+             ${ECHO} "??? $1/modpost exists, leading me to think you'd like"
+             ${ECHO} "    message moderation, but I can't find any call to"
+             ${ECHO} "    ezmlm-store in $1/editor."
+             ${ECHO}
+         elif [ -z "$STORE" -a "$GATE" = '1' ]; then
+             if [ -z "$FLAGMOD" ]; then
+               ${ECHO} "??? The list is set up with ezmlm-gate in $1/editor."
+               ${ECHO} "    However, since $1/modpost does not exist all"
+               ${ECHO} "    messages will be accepted!"
+               FLAGMOD='1'
+               MODDIR="$1/mod"
+             else
+               ${ECHO} "... The list is set up with ezmlm-gate in $1/editor."
+               ${ECHO} "    Since $1/modpost exists, subscriber messages"
+               ${ECHO} "    will be accepted and others will be send for"
+               ${ECHO} "    moderation."
+             fi
+         fi
+         if [ "$FLAGMOD" = '1' ]; then
+           ${ECHO} "... message moderated"
+           ${ECHO}
+           ${ECHO} "Message moderators based in $MODDIR:"
+           ${ECHO}
+           if [ ! -d "$MODDIR" ]; then
+             ${ECHO} "$EZERR moderator dir $MODDIR doesn't exist!"
+           elif [ -e "$MODDIR/lock" -a ! -w "$MODDIR/lock" ]; then
+             ${ECHO} "$EZERR $MODDIR/lock is not writable to user $USER"
+           elif [ ! -x "$EZLIST" ]; then
+             ${ECHO} "${EZLIST} not available for listing"
+           else
+             if ${EZLIST} "$MODDIR" | ${GREP} '@' ; then
+                 :
+             else
+                 ${ECHO} "$EZERR no message moderators!"
+             fi
+           fi
+           ${ECHO}
+           MT="120"
+           if [ -r "$1/modtime" ]; then
+             MODTIME=`${CAT} "$1/modtime" | ${HEAD} -1`
+             if [ "$MODTIME" -eq 0 ]; then
+               MT="120"
+             elif [ "$MODTIME" -lt 24 ]; then
+               MT="24"
+             elif [ "$MODTIME" -gt 240 ]; then
+               MT="240"
+             else
+               MT="${MODTIME}"
+             fi
+           fi
+           ${ECHO} "... Messages awaiting moderation time out after $MT hours"
+           if [ ! -d "$1/mod/pending" ]; then
+             ${ECHO} "$EZERR $MODDIR/pending is not a directory"
+           else
+             MODNUM=`${LS} "$1/mod/pending" | ${GREP} -c '*'`
+             ${ECHO} "... there are $MODNUM messages awaiting moderator action"
+           fi
+           if [ ! -d "$1/mod/accepted" ]; then
+             ${ECHO} "$EZERR $MODDIR/accepted is not a directory"
+           fi
+           if [ ! -d "$1/mod/rejected" ]; then
+             ${ECHO} "$EZERR $MODDIR/rejected is not a directory"
+           fi
+           if [ ! -r "$1/moderator" ]; then
+             ${ECHO} "$EZERR $1/moderator is not readable to user $USER"
+           else
+             if ${GREP} 'ezmlm-moderate' < "$1/moderator" >/dev/null 2>&1
+             then
+               :
+             else
+               ${ECHO} "$EZERR $1/moderator lacks ezmlm-moderate entry"
+             fi
+             ${ECHO}
+             ${ECHO} "$1/moderator:"
+             ${ECHO} "============================"
+             ${CAT} "$1/moderator"
+             ${ECHO} "============================"
+             ${ECHO} 
+           fi
+           ${ECHO}
+           ${ECHO} "... Links should be:"
+           ${ECHO} "    ~/.qmail-{list}-accept-default -> $1/moderator"
+           ${ECHO} "    ~/.qmail-{list}-reject-default -> $1/moderator"
+           ${ECHO}
+           if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then
+             ${ECHO}
+             ${ECHO} "    As far as I can see, '{list}' should be '$LIST'."
+             ${ECHO} "    If so and if .qmail files should be in $HOME ..."
+             BN="$HOME/.qmail-$LIST"
+             FN="$BN-accept-default"
+             if ${LLS} "$FN" 2>/dev/null | \
+                       ${GREP} "$1/moderator$" >/dev/null ; then
+               ${ECHO} "      $FN is OK"
+             else
+               ${ECHO} "???    $FN is BAD"
+             fi
+             FN="$BN-reject-default"
+             if ${LLS} "$FN" 2>/dev/null | \
+                       ${GREP} "$1/moderator$" >/dev/null ; then
+               ${ECHO} "      $FN is OK"
+             else
+               ${ECHO} "???    $FN is BAD"
+             fi
+           fi
+          else
+           ${ECHO} "... no message moderation"
+          fi   
+         ${ECHO}
+         ${ECHO} "---------------------------------------------------"
+         ${ECHO} "Checking for SENDER checks:"
+         ${ECHO}
+         if ${GREP} 'ezmlm-issubn -n' < "$1/editor" >/dev/null 2>&1 ; then
+           ${ECHO} "... Some type of blacklisting in use"
+           SRESTRICT='1'
+         fi
+         if ${GREP} 'ezmlm-issubn' < "$1/editor" |\
+           ${GREP} -v -- '-n' >/dev/null 2>&1 ; then
+           ${ECHO} "... Some type of SENDER check in use for posts"
+           SRESTRICT='1'
+         fi
+         if [ -z "$SRESTRICT" ]; then
+           ${ECHO} "... no SENDER restrictions found for posts"
+         fi
+         ${ECHO}
+         GET=` ${GREP} 'ezmlm-get' < "$1/manager" | \
+               ${CUT} -d' ' -f2- | ${CUT} -d\' -f1`
+         if ${ECHO} "$GET" | ${GREP} 's' >/dev/null ; then
+           ${ECHO} "... Only subscribers may access the archive"
+         else
+           ${ECHO} "... no SENDER restrictions for archive access"
+         fi
+         ${ECHO}
+         ${ECHO} "---------------------------------------------------"
+         ${ECHO} "Checking for special options:"
+         ${ECHO}
+         MANAGE=` ${GREP} 'ezmlm-manage' < "$1/manager" | \
+               ${CUT} -d' ' -f2- | ${CUT} -d\' -f1`
+         if ${ECHO} "$MANAGE" | ${GREP} 'e' >/dev/null ; then
+           ${ECHO} "... remote editing of $1/text/ files enabled"
+           SPEC='1'
+         fi
+         if ${ECHO} "$MANAGE" | ${GREP} 'l' >/dev/null ; then
+           ${ECHO} "... remote listing of subscribers enabled"
+           SPEC='1'
+         fi
+         if [ "$SPEC" = '1' -a -z "$REMOTE" ] ; then
+           ${ECHO} \
+             "$EZERR but remote admin is not enabled, so this will not work!"
+         fi
+         ${ECHO} "---------------------------------------------------"
+       fi
+       ${ECHO}
+       ${ECHO} "EXT ='$EXT'"
+       ${ECHO} "EXT1 ='$EXT1'"
+       ${ECHO} "EXT2 ='$EXT2'"
+       ${ECHO} "EXT3 ='$EXT3'"
+       ${ECHO} "EXT4 ='$EXT4'"
+       ${ECHO} "DTLINE = $DTLINE"
+       ${ECHO} "RPLINE = $RPLINE"
+       ${ECHO} "UFLINE = $UFLINE"
+       ${ECHO} "---------------------------------------------------"
+       ${ECHO}
+       ${ECHO} "Hope that helps!"
+) | "$RCP" || exit 100
+
+exit 99
+
diff --git a/ezmlm-clean.1 b/ezmlm-clean.1
new file mode 100644 (file)
index 0000000..652507e
--- /dev/null
@@ -0,0 +1,117 @@
+.TH ezmlm-clean 1
+.SH NAME
+ezmlm-clean \- clean moderation directory
+.SH SYNOPSIS
+.B ezmlm-clean [mMrRvV]
+.I dir
+.SH DESCRIPTION
+If
+.I dir\fB/modpost
+exists,
+.B ezmlm-clean
+sends out messages for timed-out posts in the moderation directory
+and removes stubs for rejected and accepted posts
+for the mailing list stored in
+.IR dir .
+If
+.I dir\fB/modpost
+does not exist,
+.B ezmlm-clean
+does nothing and exits.
+
+.B ezmlm-clean
+reads
+.I dir\fB/modtime
+and extracts a time-out ``time'' in hours from it. If ``time'' is 0 or
+.I dir\fB/modtime
+is empty or doesn't exist,
+a default of 120 h is used. If a time is given, it is limited to
+the range 24 h to 240 h.
+
+.B ezmlm-clean
+then looks through
+.I dir\fB/mod/accepted/
+and
+.I dir\fB/mod/rejected/
+and removes message stubs older than ``time''. ``Time'' is
+a minimum retention time. Since the files are processed only
+when
+.B ezmlm-clean
+is run, the delay before a message is timed-out may
+be substantially longer if the list does not receive many messages.
+
+Message age
+determined by the time parsed
+.I from the file name,
+not from the creation time.
+Thus, there is no good way to extend the life of
+the file by e.g. touching it. Also, files in these directories are not
+checked for the proper format. Thus, most non-message files in these
+directories will be deleted the first time
+.B ezmlm-clean
+is run.
+
+For messages in
+.I dir\fB/mod/pending/
+no action is taken on read-only files. Messages without the owner execute
+bit set are silently removed, as they are the result of incomplete
+.B ezmlm-store(1)
+executions. For other messages, a notification of the time out is sent
+to the sender, before the file is removed.
+
+.B ezmlm-clean
+logs errors to the mail log.
+Re-delivery should be avoided by suffixing any
+.I \.qmail
+line invoking
+.B ezmlm-clean
+with '|| exit 0'.
+.SH OPTIONS
+.TP
+.B \-m
+(Default.)
+The timed-out post is sent as a MIME enclosure.
+.TP
+.B \-M
+The timed-out post is appended to the message.
+.TP
+.B \-r
+(Default.)
+The timed-out post is returned to sender.
+.TP
+.B \-R
+The timed-out post is discarded without sender notification.
+.B Note:
+.B ezmlm-clean
+is normally run from both
+.I dir\fB/editor
+and
+.IR dir\fB/moderator .
+To suppress sender notification, the switch needs to be specified
+for all invocations of
+.BR ezmlm-clean .
+.TP
+.B \-v
+Display
+.B ezmlm-clean
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-clean
+version information.
+.SH "CHARACTER SETS"
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-clean
+will use the character set listed for all messages. Otherwise, the
+default ``us-ascii'' will be used. The character set can be suffixed
+by ``:'' followed by a code. If the code is ``Q'', outgoing messages are 
+sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded.
+Otherwise, text is sent as is.
+.SH "SEE ALSO"
+ezmlm-make(1),
+ezmlm-moderate(1),
+ezmlm-store(1),
+ezmlm(5)
diff --git a/ezmlm-clean.c b/ezmlm-clean.c
new file mode 100644 (file)
index 0000000..ce8c04f
--- /dev/null
@@ -0,0 +1,355 @@
+/*$Id: ezmlm-clean.c,v 1.30 1999/05/12 22:15:26 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "sig.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "case.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "seek.h"
+#include "quote.h"
+#include "datetime.h"
+#include "now.h"
+#include "date822fmt.h"
+#include "direntry.h"
+#include "cookie.h"
+#include "sgetopt.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "copy.h"
+#include "idx.h"
+#include "mime.h"
+
+int flagmime = MOD_MIME;       /* default is message as attachment */
+int flagreturn = 1;            /* default return timed-out messages */
+char flagcd = '\0';            /* default: no transferencoding */
+stralloc fnmsg = {0};
+
+/* When ezmlm-clean is run, messages and message stubs in pending/      */
+/* rejected/accepted are erased if they are older than delay hours.     */
+/* Timeouts in h for messages. If modtime has a number, it is made to be*/
+/* in the range DELAY_MIN..DELAY_MAX. If the number is 0 or there is no */
+/* number, DELAY_DEFAULT is used. Messages that are read-only are       */
+/* ignored. Messages in 'pending' that have the execute bit set result  */
+/* in an informative reply to the poster. Any defects in the message    */
+/* format, inability to open the file, etc, result in a maillog entry   */
+/* whereafter the message is erased. */
+
+/* The defines are in "idx.h" */
+
+#define FATAL "ezmlm-clean: fatal: "
+
+void die_read()
+{
+  strerr_die4x(111,FATAL,ERR_READ,fnmsg.s,": ");
+}
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-clean: usage: ezmlm-clean [-mMrRvV] dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+datetime_sec when;
+unsigned int older;
+struct datetime dt;
+
+char textbuf[1024];
+substdio sstext;
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+
+char *dir;
+char strnum[FMT_ULONG];
+char date[DATE822FMT];
+char boundary[COOKIE];
+datetime_sec hashdate;
+
+stralloc outhost = {0};
+stralloc outlocal = {0};
+stralloc mailinglist = {0};
+stralloc listid = {0};
+stralloc quoted = {0};
+stralloc line = {0};
+stralloc modtime = {0};
+stralloc to = {0};
+stralloc charset = {0};
+
+int flagconf;
+int fd;
+int match;
+unsigned long msgnum = 0;
+                       /* counter to make message-id unique, since we may */
+                       /* send out several msgs. This is not bullet-proof.*/
+                       /* Duplication occurs if we do x>1 msg && another  */
+                       /* ezmlm started within x seconds, and with the    */
+                       /* same pid. Very unlikely.                        */
+
+void transferenc()
+{
+       if (flagcd) {
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"Quoted-Printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n\n");
+}
+void readconfigs()
+/* gets outlocal, outhost, etc. This is done only if there are any timed-out*/
+/* messages found, that merit a reply to the author. */
+{
+
+  getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+  getconf_line(&listid,"listid",0,FATAL,dir);
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  set_cpouthost(&outlocal);
+  set_cpoutlocal(&outlocal);
+}
+
+void sendnotice(d)
+char *d;
+/* sends file pointed to by d to the address in the return-path of the  */
+/* message. */
+{
+  unsigned int x,y;
+  char *err;
+
+      if (!flagconf) {
+        readconfigs();
+      }
+      if (qmail_open(&qq, (stralloc *) 0) == -1)
+        strerr_die2x(111,FATAL,ERR_QMAIL_QUEUE);
+
+      fd = open_read(d);
+      if (fd == -1)
+        strerr_die4sys(111,FATAL,ERR_OPEN,d,": ");
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      if (getln(&sstext,&line,&match,'\n') == -1) die_read();
+      if (!match) die_read();
+      if (!case_startb(line.s,line.len,"return-path:")) die_read();
+      x = 12 + byte_chr(line.s + 12,line.len-12,'<');
+      y = byte_rchr(line.s + x,line.len-x,'>');
+      if (x != line.len && x+y != line.len) {
+        if (!stralloc_copyb(&to,line.s+x+1, y-1)) die_nomem();
+        if (!stralloc_0(&to)) die_nomem();
+      } else
+        die_read();
+      qmail_puts(&qq,"Mailing-List: ");
+      qmail_put(&qq,mailinglist.s,mailinglist.len);
+      qmail_puts(&qq,"\nList-ID: ");
+      qmail_put(&qq,listid.s,listid.len);
+      qmail_puts(&qq,"\nDate: ");
+      datetime_tai(&dt,when);
+      qmail_put(&qq,date,date822fmt(date,&dt));
+      qmail_puts(&qq,"Message-ID: <");
+      if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,
+               (unsigned long) when + msgnum++))) die_nomem();
+      if (!stralloc_append(&line,".")) die_nomem();
+      if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+      if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+      if (!stralloc_cat(&line,&outhost)) die_nomem();
+      if (!stralloc_0(&line)) die_nomem();
+      qmail_puts(&qq,line.s);
+               /* "unique" MIME boundary as hash of messageid */
+      cookie(boundary,"",0,"",line.s,"");
+      qmail_puts(&qq,">\nFrom: ");
+      if (!quote(&quoted,&outlocal)) die_nomem();
+      qmail_put(&qq,quoted.s,quoted.len);
+      qmail_puts(&qq,"-help@");
+      qmail_put(&qq,outhost.s,outhost.len);
+      qmail_puts(&qq,"\nSubject: ");
+      qmail_puts(&qq,TXT_RETURNED_POST);
+      qmail_put(&qq,quoted.s,quoted.len);
+      qmail_puts(&qq,"@");
+      qmail_put(&qq,outhost.s,outhost.len);
+      qmail_puts(&qq, "\nTo: ");
+      qmail_puts(&qq,to.s);
+      if (flagmime) {
+        if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+          if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+            if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+              flagcd = charset.s[charset.len - 1];
+              charset.s[charset.len - 2] = '\0';
+            }
+          }
+        } else
+          if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+        if (!stralloc_0(&charset)) die_nomem();
+        qmail_puts(&qq,"\nMIME-Version: 1.0\n");
+        qmail_puts(&qq,"Content-Type: multipart/mixed;\n\tboundary=");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"\n\n--");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+        qmail_puts(&qq,charset.s);
+        transferenc();
+      } else
+      qmail_puts(&qq,"\n\n");
+
+      copy(&qq,"text/top",flagcd,FATAL);
+      copy(&qq,"text/mod-timeout",flagcd,FATAL);
+      if (flagcd == 'B') {
+        encodeB("",0,&line,2,FATAL);
+        qmail_put(&qq,line.s,line.len);
+      }
+
+      if (flagmime) {
+        qmail_puts(&qq,"\n--");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n");
+      }
+
+      if (seek_begin(fd) == -1)
+        strerr_die4sys(111,FATAL,ERR_SEEK,d,": ");
+
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      if (substdio_copy(&ssqq,&sstext) != 0) die_read();
+      close (fd);
+
+      if (flagmime) {
+        qmail_puts(&qq,"\n--");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"--\n");
+      }
+
+      if (!stralloc_copy(&line,&outlocal)) die_nomem();
+      if (!stralloc_cats(&line,"-return-@")) die_nomem();
+      if (!stralloc_cat(&line,&outhost)) die_nomem();
+      if (!stralloc_0(&line)) die_nomem();
+      qmail_from(&qq,line.s);          /* sender */
+        qmail_to(&qq,to.s);
+
+     if (*(err = qmail_close(&qq)) != '\0')
+       strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE, err + 1);
+
+     strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+     strerr_warn2("ezmlm-clean: info: qp ",strnum,0);
+}
+
+void dodir(dirname,reply)
+char *dirname; int reply;
+/* parses file names in directory 'dirname'. Files that are not owner */
+/* writable (w) are ignored. If the files are older (by name!) than   */
+/* now-delay, action is taken:                                        */
+/* If the owner x bit is not set, the file is erased.                 */
+/* If it is set and reply is not set, the file is erased. If both are */
+/* set, a notice about the timeout is sent to the poster. If this     */
+/* fails due to a message-related error (format, etc) the file is     */
+/* erased even though no notice is sent. For temporary errors (like   */
+/* out-of-memory) the message is left intact for the next run. If the */
+/* notice is sent successfully, the file is erased. All this is to    */
+/* do the best possible without risking a rerun of the .qmail file,   */
+/* which could result in a redelivery of the action request and a     */
+/* second (incorrect) reply to the moderator's request.               */
+
+/* NOTE: ALL non-hidden files in this dir are processed and merci-    */
+/* lessly deleted. No checks for proper file name. E.g. 'HELLO'       */
+/* => time 0 => will be deleted on the next ezmlm-clean run.          */
+{
+  DIR *moddir;
+  direntry *d;
+  unsigned long modtime;
+  struct stat st;
+
+  moddir = opendir(dirname);
+  if (!moddir)
+    strerr_die6sys(0,FATAL,ERR_OPEN,dir,"/",dirname,": ");
+  while ((d = readdir(moddir))) {
+    if (d->d_name[0] == '.') continue;
+    scan_ulong(d->d_name,&modtime);
+    if (modtime < older) {
+      if (!stralloc_copys(&fnmsg,dirname)) die_nomem();
+      if (!stralloc_cats(&fnmsg,d->d_name)) die_nomem();
+      if (!stralloc_0(&fnmsg)) die_nomem();
+      if((stat(fnmsg.s,&st) != -1) && (st.st_mode & 0200)) {
+        if(reply && (st.st_mode & 0100)) {
+                       /* unlink unless there was a TEMPORARY */
+                       /* not message-related error notifying */
+                       /* poster and msg x bit set.  Leave r/o*/
+                       /* messages alone. Non-x bit msg are   */
+                       /* trash. Just unlink, don't notify    */
+          sendnotice(fnmsg.s);
+          unlink(fnmsg.s);
+        } else
+          unlink(fnmsg.s);
+      }
+    }
+  }
+  closedir(moddir);
+}
+
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  int fdlock;
+  int delay;
+  int opt;
+  (void) umask(022);
+  sig_pipeignore();
+  when = now();
+
+  while ((opt = getopt(argc,argv,"mMrRvV")) != opteof)
+    switch(opt) {
+      case 'm': flagmime = 1; break;
+      case 'M': flagmime = 0; break;
+      case 'r': flagreturn = 1; break;
+      case 'R': flagreturn = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-clean version: ", EZIDX_VERSION);
+                /* not reached */
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  getconf_line(&modtime,"modtime",0,FATAL,dir);
+  if (!stralloc_0(&modtime)) die_nomem();
+  scan_ulong(modtime.s,&delay);
+  if (!delay) delay = DELAY_DEFAULT;
+  else if (delay < DELAY_MIN) delay = DELAY_MIN;
+  else if (delay > DELAY_MAX) delay = DELAY_MAX;
+  older = (unsigned long) when - 3600L * delay;        /* delay is in hours */
+
+  fdlock = open_append("mod/lock");
+  if (fdlock == -1)
+    strerr_die4sys(0,FATAL,ERR_OPEN,dir,"/mod/lock: ");
+  if (lock_ex(fdlock) == -1)
+    strerr_die4sys(0,FATAL,ERR_OBTAIN,dir,"/mod/lock: ");
+
+  flagconf = 0;
+  dodir("mod/pending/",flagreturn);
+  dodir("mod/accepted/",0);
+  dodir("mod/rejected/",0);
+  _exit(0);
+}
+
diff --git a/ezmlm-cron.1 b/ezmlm-cron.1
new file mode 100644 (file)
index 0000000..98fa3e2
--- /dev/null
@@ -0,0 +1,245 @@
+.TH ezmlm-cron 1
+.SH NAME
+ezmlm-cron \- Sets up digest request messages generation via crond
+.SH SYNOPSIS
+.B ezmlm-cron
+[
+.B \-cCdDlL
+][
+.B \-w \fIdow
+][
+.B \-t \fIhh:mm
+][
+.B \-i \fIhrs
+]
+.I listadr code[f]
+.SH DESCRIPTION
+.B ezmlm-cron
+is a very restrictive interface to
+.BR crond(8) .
+It edits the effective user's ~/crontab (see crontab(5))
+file. It then executes
+.B crontab(1)
+to update crond(8) with the changes.
+
+.B ezmlm-cron
+sets up the generation of trigger messages to the list
+.I listadr
+and the digest code
+.IR code .
+A optional digest format specifier
+.I f
+can be added to
+.IR code .
+
+.B ezmlm-cron
+reads
+.IR dir\fB/ezcronrc ,
+where
+.I dir
+is the home directory of the effective user. The first line of this file is the
+host name, 'host', to which bounces should be sent. Any bounces for lists
+set up by 'user' will go to 'user@host'. Subsequent lines are entries
+for users made up of:
+.IR user:local:host:num:[list1[,list2...]] .
+The ':'-separated parameters are:
+.TP
+.I user
+the user name to which this line corresponds.
+.TP
+.I local
+the list address must start with exactly these characters (case sensitive).
+If this field is empty, any list local address is allowed.
+.TP
+.I host
+the list host name must exactly match this parameter (case insensitive).
+If this field is empty, any list host address is allowed. (Host names for
+the list and the digest list must still match.)
+.TP
+.I num
+the user is permitted a maximum of
+.I num
+entries.
+.TP
+.I list1 [,list2...]
+a set of complete list names separated by commas. The user may edit
+entries for these lists, even if they do not match the criteria set
+above. If these lists exist, they are counted in determining
+.IR num .
+No while space is allowed before or between list names. If no list names
+are specified, the final ':' can be omitted.
+
+The first line matching the executing user will be used.
+
+If
+.B ezmlm-cron
+is installed SUID
+.IR euser ,
+the configuration and crontab files from that user's home directory
+will be used for all
+.B ezmlm-cron
+actions. This way, users on a system can be given limited
+.B crond(8)
+access via
+.B ezmlm-cron
+restricted by
+.I dir\fB/ezcronrc
+and to the generation of digest trigger messages. This is especially
+useful for users without shell access or access to
+.BR crond(8) .
+.I euser
+is usually 'ezmlm'.
+To install
+.B ezmlm-cron
+SUID ezmlm:
+
+.EX
+  # chown ezmlm /usr/local/bin/ezmlm/ezmlm-cron
+  # chmod 4555 /usr/local/bin/ezmlm/ezmlm-cron
+.EE
+
+.B ezmlm-cron
+refuses to run if installed SUID root.
+.B ezmlm-cron
+when executed by 'root',
+will still use the files in ~root.
+
+To allow
+.B crond(8)
+access, you may need to list the effective user (all users allowed access
+or ~ezmlm if
+.B ezmlm-cron
+is installed SUID ezmlm) in
+.BR /etc/cron.allow .
+See
+.B crontab(1)
+for further information.
+.SH OPTIONS
+The
+.BR \-c ,
+.BR \-d ,
+and
+.B \-l
+switches are mutually exclusive.
+
+.TP
+.B \-c
+List user entry from
+.IR ezcronrc .
+.TP
+.B \-C
+(Default.)
+Do not list user entry.
+.TP
+.B \-d
+Delete entry.
+.B ezmlm-cron
+will search
+.I ~euser\fB/crontab
+for an entry belonging to the executing user, permitted by
+.I ~euser\fB/ezcronrc
+and matching the command line arguments supplied.
+.I code
+is ignored and may be omitted.
+.TP
+.B \-D
+(Default.)
+Do not delete entry.
+.TP
+.B \-i\fI hrs
+Generate trigger message with
+.I hrs
+hours interval. Accepted intervals are 0, 1 ,2, 3, 6, 12, 24, 48, and 72 hours.
+Other numbers will be silently adjusted upwards to the nearest accepted
+interval
+(intervals above 72 hours will result in weekly trigger messages).
+.TP
+.B \-l
+List entries. If no other command line arguments are given,
+.B ezmlm-cron
+lists the entries created in the name of the user. If
+.I listadr
+is given,
+.B ezmlm-cron
+will list the entries for all the matching lists, even if the entries
+were not set up by the current user. Arguments, if given, still have to
+comply with the rules set in
+.IR ezcronrc .
+
+Crude
+.B crontab(5)
+lines are listed. These are taken from the ~/crontab file. Usually,
+these are active entries, although if the last execution of
+.B crontab(1)
+failed, they may not be.
+.TP
+.B \-L
+(Default.)
+Do not list entry.
+.TP
+.B \-t\fI hh:mm
+The time for the trigger message. Other trigger messages will be sent
+.I hrs
+hours before and after this time.
+.TP
+.B \-w\fI dow
+The days of the week on which trigger messages are sent. day 0 and 7 are
+Sunday, 1 is Monday, etc (see crontab(5)). The string specified for
+.I dow
+must consists of single comma-separated digits in the range '0'-'7'
+only. The default is every day, except for
+.I hrs
+of 48 (default Monday, Wednesday, Friday), 72 (default Monday and Thursday),
+or greater than 72 (default Monday).
+Both
+.I hrs
+and
+.I dow
+can be specified. In this case, trigger messages are sent
+on the day specified by
+.I dow
+at the interval
+specified by
+.IR hrs .
+If
+.I hrs
+is greater than 24 h, it is ignored and
+trigger messages are generated daily or as specified by
+.IR dow .
+.SH FILES
+.TP
+.I ~euser/ezcronrc
+The configuration file for
+.BR ezmlm-cron .
+.I euser
+is the effective user id. This is the executing user, unless
+.B ezmlm-cron
+is installed SUID
+.IR otheruser ,
+in which case it is
+.IR otheruser .
+.TP
+.I ~euser/crontab
+The file edited by
+.BR ezmlm-cron .
+.I euser
+is the effective user.
+.TP
+.I ~euser/crontabl
+The lock file used to assure that only one process at a time is editing the
+.B crond(8)
+settings.
+.I euser
+is the effective user.
+.SH BUGS
+.B ezmlm-cron
+should use the output of 'crontab -l' to list crontab lines, rather than
+parse the crontab file (and assume that the last execution of
+.B crontab(1)
+was successful).
+.SH "SEE ALSO"
+crond(8),
+crontab(1),
+crontab(5),
+ezmlm(5),
+ezmlm-get(1)
diff --git a/ezmlm-cron.c b/ezmlm-cron.c
new file mode 100644 (file)
index 0000000..e35f7ea
--- /dev/null
@@ -0,0 +1,507 @@
+#include <sys/types.h>
+#include <pwd.h>
+#include "strerr.h"
+#include "stralloc.h"
+#include "sgetopt.h"
+#include "substdio.h"
+#include "error.h"
+#include "str.h"
+#include "fmt.h"
+#include "fork.h"
+#include "wait.h"
+#include "readwrite.h"
+#include "auto_qmail.h"
+#include "auto_cron.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-cron: fatal: "
+
+void die_usage()
+{
+ strerr_die2x(100,FATAL,
+  "usage: ezmlm-cron [-cCdDlLvV] [-w dow] [-t hh:mm] [-i hrs] listadr code");
+}
+
+void die_dow()
+{
+  strerr_die2x(100,FATAL,ERR_DOW);
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+unsigned long deltah = 24L;    /* default interval 24h */
+unsigned long hh = 4L;         /* default time 04:12 */
+unsigned long mm = 12L;
+char *dow = "*";               /* day of week */
+char *qmail_inject = "/bin/qmail-inject ";
+char strnum[FMT_ULONG];
+unsigned long uid,euid;
+
+stralloc line = {0};
+stralloc rp = {0};
+stralloc addr = {0};
+stralloc user = {0};
+stralloc euser = {0};
+stralloc dir = {0};
+stralloc listaddr = {0};
+
+struct passwd *ppasswd;
+
+int opt,match;
+int hostmatch;
+int localmatch;
+unsigned long dh,t;
+int founduser = 0;
+int listmatch = 0;
+int flagconfig = 0;
+int flagdelete = 0;
+int flaglist = 0;
+int flagdigit = 0;
+int flagours;
+int foundlocal;
+int foundmatch = 0;
+int nolists = 0;
+int maxlists;
+unsigned int pos,pos2,poslocal,len;
+unsigned int lenhost,lenlocal;
+unsigned int part0start,part0len;
+int fdlock,fdin,fdout;
+
+char *local = (char *) 0;      /* list = local@host */
+char *host = (char *) 0;
+char *code = (char *) 0;       /* digest code */
+char *cp;
+
+void die_syntax()
+{
+  if (!stralloc_0(&line)) die_nomem();
+  strerr_die5x(100,FATAL,TXT_EZCRONRC," ",ERR_SYNTAX,line.s);
+}
+
+void die_argument()
+{
+  strerr_die2x(100,FATAL,ERR_NOT_CLEAN);
+}
+
+int isclean(addr,flagaddr)
+       /* assures that addr has only letters, digits, "-_" */
+       /* also checks allows single '@' if flagaddr = 1 */
+       /* returns 1 if clean, 0 otherwise */
+  char *addr;
+  int flagaddr;                /* 1 for addresses with '@', 0 for other args */
+{
+  unsigned int pos;
+  register char ch;
+  register char *cp;
+  if (flagaddr) {              /* shoud have one '@' */
+    pos = str_chr(addr,'@');
+    if (!pos || !addr[pos])
+      return 0;                        /* at least 1 char for local */
+    if (!addr[pos+1])
+      return 0;                        /* host must be at least 1 char */
+    pos++;
+    case_lowerb(addr+pos,str_len(addr)-pos);
+  } else
+    pos = 0;
+  pos +=  str_chr(addr + pos,'@');
+  if (addr[pos])               /* but no more */
+    return 0;
+  cp = addr;
+  while ((ch = *(cp++)))
+    if (!(ch >= 'a' && ch <= 'z') &&
+        !(ch >= 'A' && ch <= 'Z') &&
+        !(ch >= '0' && ch <= '9') &&
+        ch != '.' && ch != '-' && ch != '_' && ch != '@')
+      return 0;
+  return 1;
+}
+
+char inbuf[512];
+substdio ssin;
+
+char outbuf[512];
+substdio ssout;
+
+void main(argc,argv)
+int argc;
+char **argv;
+
+{
+  int child;
+  char *sendargs[4];
+  int wstat;
+
+  (void) umask(077);
+  sig_pipeignore();
+
+  while ((opt = getopt(argc,argv,"cCdDi:lLt:w:vV")) != opteof)
+    switch (opt) {
+      case 'c': flagconfig = 1; break;
+      case 'C': flagconfig = 0; break;
+      case 'd': flagdelete = 1; break;
+      case 'D': flagdelete = 0; break;
+      case 'i': scan_ulong(optarg,&deltah); break;
+      case 'l': flaglist = 1; break;
+      case 'L': flaglist = 0; break;
+      case 't':
+                pos = scan_ulong(optarg,&hh);
+                if (!optarg[pos++] == ':') die_usage();
+                pos = scan_ulong(optarg + pos,&mm);
+                break;
+      case 'w':
+                dow = optarg;
+                cp = optarg - 1;
+                while (*(++cp)) {
+                  if (*cp >= '0' && *cp <= '7') {
+                    if (flagdigit) die_dow();
+                    flagdigit = 1;
+                  } else if (*cp == ',') {
+                    if (!flagdigit) die_dow();
+                    flagdigit = 0;
+                  } else
+                    die_dow();
+                }
+                break;
+      case 'v':
+      case 'V': strerr_die2x(100,"ezmlm-cron version: ",EZIDX_VERSION);
+      default:
+                die_usage();
+    }
+  if (flaglist + flagdelete + flagconfig > 1)
+    strerr_die2x(100,FATAL,ERR_EXCLUSIVE);
+  uid = getuid();
+  if (uid && !(euid = geteuid()))
+    strerr_die2x(100,FATAL,ERR_SUID);
+  if (!(ppasswd = getpwuid(uid)))
+    strerr_die2x(100,FATAL,ERR_UID);
+  if (!stralloc_copys(&user,ppasswd->pw_name)) die_nomem();
+  if (!stralloc_0(&user)) die_nomem();
+  if (!(ppasswd = getpwuid(euid)))
+    strerr_die2x(100,FATAL,ERR_EUID);
+  if (!stralloc_copys(&dir.s,ppasswd->pw_dir)) die_nomem();
+  if (!stralloc_0(&dir)) die_nomem();
+  if (!stralloc_copys(&euser,ppasswd->pw_name)) die_nomem();
+  if (!stralloc_0(&euser)) die_nomem();
+
+  if (chdir(dir.s) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir.s,": ");
+
+  local = argv[optind++];      /* list address, optional for -c & -l */
+  if (!local) {
+    if (!flagconfig && !flaglist)
+      die_usage();
+    lenlocal = 0;
+    lenhost = 0;
+  } else {
+    if (!stralloc_copys(&listaddr,local)) die_nomem();
+    if (!isclean(local,1))
+      die_argument();
+    pos = str_chr(local,'@');
+    lenlocal = pos;
+    local[pos] = '\0';
+    host = local + pos + 1;
+    lenhost = str_len(host);
+    code = argv[optind];
+    if (!code) {               /* ignored for -l, -c, and -d */
+      if (flagdelete || flaglist || flagconfig)
+                               /* get away with not putting code for delete */
+        code = "a";    /* a hack - so what! */
+      else
+        die_usage();
+    } else
+      if (!isclean(code,0))
+        die_argument();
+  }
+  if ((fdin = open_read(TXT_EZCRONRC)) == -1)
+    strerr_die6sys(111,FATAL,ERR_OPEN,dir.s,"/",TXT_EZCRONRC,": ");
+       /* first line is special */
+  substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
+  if (getln(&ssin,&line,&match,'\n') == -1)
+    strerr_die6sys(111,FATAL,ERR_READ,dir.s,"/",TXT_EZCRONRC,": ");
+
+  if (!match)
+    strerr_die6sys(111,FATAL,ERR_READ,dir.s,"/",TXT_EZCRONRC,": ");
+       /* (since we have match line.len has to be >= 1) */
+  line.s[line.len - 1] = '\0';
+  if (!isclean(line.s,0))       /* host for bounces */
+    strerr_die4x(100,ERR_CFHOST,dir.s,"/",TXT_EZCRONRC);
+  if (!stralloc_copys(&rp,line.s)) die_nomem();
+
+  match = 1;
+  for(;;) {
+    if (!match) break;         /* to allow last line without '\n' */
+    if (getln(&ssin,&line,&match,'\n') == -1)
+    strerr_die6sys(111,FATAL,ERR_READ,dir.s,"/",TXT_EZCRONRC,": ");
+    if (!line.len)
+      break;
+    line.s[line.len-1] = '\0';
+    if (!case_startb(line.s,line.len,user.s))
+      continue;
+    pos = user.len - 1;
+    if (pos >= line.len || line.s[pos] != ':')
+      continue;
+    founduser = 1;              /* got user line */
+    break;
+  }
+  close(fdin);
+  if (!founduser)
+    strerr_die2x(100,FATAL,ERR_BADUSER);
+  
+  if (flagconfig) {
+    line.s[line.len-1] = '\n'; /* not very elegant ;-) */
+    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
+    if (substdio_put(&ssout,line.s,line.len) == -1)
+      strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+    if (substdio_flush(&ssout) == -1)
+      strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+    _exit(0);
+  }
+  ++pos;                               /* points to first ':' */
+  len = str_chr(line.s+pos,':');       /* second ':' */
+    if (!line.s[pos + len])
+      die_syntax();
+  if (!local) {                                /* only -d and std left */
+    localmatch = 1;
+    hostmatch = 1;
+  } else {
+    hostmatch = 0;
+    if (len <= str_len(local))
+      if (!str_diffn(line.s+pos,local,len))
+        localmatch = 1;
+  }
+  pos += len + 1;
+  len = str_chr(line.s + pos,':');     /* third */
+  if (!line.s[pos + len])
+    die_syntax();
+  if (local) {                         /* check host */
+    if (len == 0)                      /* empty host => any host */
+      hostmatch = 1;
+    else
+      if (len == str_len(host))
+        if (!case_diffb(line.s+pos,len,host))
+          hostmatch = 1;
+  }
+  pos += len + 1;
+  pos += scan_ulong(line.s+pos,&maxlists);
+  if (line.s[pos]) {                   /* check additional lists */
+    if (line.s[pos] != ':')
+      die_syntax();
+    if (line.s[pos+1+str_chr(line.s+pos+1,':')])
+      die_syntax();    /* reminder lists are not separated by ':'  */
+                       /* otherwise a ':' or arg miscount will die */
+                       /* silently */
+    if (local) {
+      while (++pos < line.len) {
+        len = str_chr(line.s + pos,'@');
+        if (len == lenlocal && !str_diffn(line.s + pos,local,len)) {
+          pos += len;
+          if (!line.s[pos]) break;
+          pos++;
+          len = str_chr(line.s+pos,',');
+            if (len == lenhost && !case_diffb(line.s+pos,len,host)) {
+              listmatch = 1;
+              break;
+            }
+        }
+        pos += len;
+      }
+    }
+  }
+  if (!listmatch) {
+    if (!hostmatch)
+      strerr_die2x(100,FATAL,ERR_BADHOST);
+    if (!localmatch)
+      strerr_die2x(100,FATAL,ERR_BADLOCAL);
+  }
+       /* assemble correct line */
+  if (!flaglist) {
+    if (!stralloc_copyb(&addr,strnum,fmt_ulong(strnum,mm))) die_nomem();
+    if (!stralloc_cats(&addr," ")) die_nomem();
+    dh = 0L;
+    if (deltah <= 3L) dh = deltah;
+    else if (deltah <= 6L) dh = 6L;
+    else if (deltah <= 12L) dh = 12L;
+    else if (deltah <= 24L) dh = 24L;
+    else if (deltah <= 48L) {
+      if (dow[0] == '*') dow = "1,3,5";
+    } else if (deltah <= 72L) {
+      if (dow[0] == '*') dow = "1,4";
+    } else
+    if (dow[0] == '*') dow = "1";
+
+    if (!dh) {
+      if (!stralloc_cats(&addr,"*")) die_nomem();
+    } else {
+      if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,hh))) die_nomem();
+      for (t = hh + dh; t < hh + 24L; t+=dh) {
+        if (!stralloc_cats(&addr,",")) die_nomem();
+        if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,t % 24L))) die_nomem();
+      }
+    }
+    if (!stralloc_cats(&addr," * * ")) die_nomem();
+    if (!stralloc_cats(&addr,dow)) die_nomem();
+    if (!stralloc_cats(&addr," ")) die_nomem();
+    part0start = addr.len;             /* /var/qmail/bin/qmail-inject */
+    if (!stralloc_cats(&addr,auto_qmail)) die_nomem();
+    if (!stralloc_cats(&addr,qmail_inject)) die_nomem();
+    part0len = addr.len - part0start;
+    if (!stralloc_cats(&addr,local)) die_nomem();
+    if (!stralloc_cats(&addr,"-dig-")) die_nomem();
+    if (!stralloc_cats(&addr,code)) die_nomem();
+    if (!stralloc_cats(&addr,"@")) die_nomem();
+    if (!stralloc_cats(&addr,host)) die_nomem();
+               /* feed 'Return-Path: <user@host>' to qmail-inject */
+    if (!stralloc_cats(&addr,"%Return-path: <")) die_nomem();
+    if (!stralloc_cats(&addr,user.s)) die_nomem();
+    if (!stralloc_cats(&addr,"@")) die_nomem();
+    if (!stralloc_cat(&addr,&rp)) die_nomem();
+    if (!stralloc_cats(&addr,">\n")) die_nomem();
+  }
+  if (!stralloc_0(&addr)) die_nomem();
+
+  if (!flaglist) {
+       /* now to rewrite crontab we need to lock */
+    fdlock = open_append("crontabl");
+    if (fdlock == -1)
+      strerr_die4sys(111,FATAL,ERR_OPEN,dir.s,"/crontabl: ");
+    if (lock_ex(fdlock) == -1) {
+      close(fdlock);
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir.s,"/crontabl: ");
+    }
+  } /* if !flaglist */
+  if ((fdin = open_read("crontab")) == -1) {
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_READ,dir.s,"/crontab: ");
+  } else
+    substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
+  if (flaglist)
+    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
+  else {
+    if ((fdout = open_trunc("crontabn")) == -1)
+      strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: ");
+    substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
+  }
+  line.len = 0;
+
+  if (fdin != -1) {
+    for (;;) {
+      if (!flaglist && line.len) {
+        line.s[line.len-1] = '\n';
+        if (substdio_put(&ssout,line.s,line.len) == -1)
+          strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: ");
+      }
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die4sys(111,FATAL,ERR_READ,dir.s,"/crontab: ");
+      if (!match)
+        break;
+      flagours = 0;                    /* assume entry is not ours */
+      foundlocal = 0;
+      line.s[line.len - 1] = '\0';     /* match so at least 1 char */
+      pos = 0;
+      while (line.s[pos] == ' ' && line.s[pos] == '\t') ++pos;
+      if (line.s[pos] == '#')
+        continue;                      /* cron comment */
+      pos = str_chr(line.s,'/');
+      if (!str_start(line.s+pos,auto_qmail)) continue;
+      pos += str_len(auto_qmail);
+      if (!str_start(line.s+pos,qmail_inject)) continue;
+      pos += str_len(qmail_inject);
+      poslocal = pos;
+      pos = byte_rchr(line.s,line.len,'<');    /* should be Return-Path: < */
+      if (pos == line.len)
+        continue;                      /* not ezmlm-cron line */
+      pos++;
+     len = str_chr(line.s+pos,'@');
+      if (len == user.len - 1 && !str_diffn(line.s+pos,user.s,len)) {
+        flagours = 1;
+        ++nolists;             /* belongs to this user */
+      }
+      if (!local) {
+        foundlocal = 1;
+      } else {
+        pos = poslocal + str_chr(line.s+poslocal,'@');
+        if (pos + lenhost +1 >= line.len) continue;
+        if (case_diffb(line.s+pos+1,lenhost,host)) continue;
+        if (line.s[pos+lenhost+1] != '%') continue;
+                               /* check local */
+        if (poslocal + lenlocal + 5 >= line.len) continue;
+        if (!str_start(line.s+poslocal,local)) continue;
+        pos2 = poslocal+lenlocal;
+        if (!str_start(line.s+pos2,"-dig-")) continue;
+        foundlocal = 1;
+      }
+      if (foundlocal) {
+        foundmatch = 1;
+        if (flaglist && (local || flagours)) {
+          if (substdio_put(&ssout,line.s,line.len) == -1)
+            strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+          if (substdio_put(&ssout,"\n",1) == -1)
+            strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+        }
+        line.len = 0;          /* same - kill line */
+        if (flagours)
+          --nolists;
+      }
+    }
+    close(fdin);
+  }
+  if (flaglist) {
+    if (substdio_flush(&ssout) == -1)
+      strerr_die3sys(111,FATAL,ERR_FLUSH,"stdout: ");
+    if (foundmatch)            /* means we had a match */
+      _exit(0);
+    else
+      strerr_die2x(100,FATAL,ERR_NO_MATCH);
+  }
+       /* only -d and regular use left */
+
+  if (nolists >= maxlists && !flagdelete)
+    strerr_die2x(100,FATAL,ERR_LISTNO);
+  if (!flagdelete)
+    if (substdio_put(&ssout,addr.s,addr.len-1) == -1)
+      strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: ");
+  if (flagdelete && !foundlocal)
+    strerr_die2x(111,FATAL,ERR_NO_MATCH);
+  if (substdio_flush(&ssout) == -1)
+    strerr_die4sys(111,FATAL,ERR_FLUSH,dir.s,"/crontabn: ");
+  if (fsync(fdout) == -1)
+    strerr_die4sys(111,FATAL,ERR_SYNC,dir.s,"/crontabn++: ");
+  if (close(fdout) == -1)
+    strerr_die4sys(111,FATAL,ERR_CLOSE,dir.s,"/crontabn: ");
+  if (rename("crontabn","crontab") == -1)
+    strerr_die4sys(111,FATAL,ERR_MOVE,dir.s,"/crontabn: ");
+  sendargs[0] = "sh";
+  sendargs[1] = "-c";
+
+  if (!stralloc_copys(&line,auto_cron)) die_nomem();
+  if (!stralloc_cats(&line,"/crontab '")) die_nomem();
+  if (!stralloc_cats(&line,dir.s)) die_nomem();
+  if (!stralloc_cats(&line,"/crontab'")) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  sendargs[2] = line.s;
+  sendargs[3] = 0;
+  switch(child = fork()) {
+      case -1:
+        strerr_die2sys(111,FATAL,ERR_FORK);
+      case 0:
+        if (setreuid(euid,euid) == -1)
+          strerr_die2sys(100,FATAL,ERR_SETUID);
+        execvp(*sendargs,sendargs);
+        if (errno == error_txtbsy || errno == error_nomem ||
+            errno == error_io)
+          strerr_die4sys(111,FATAL,ERR_EXECUTE,sendargs[2],": ");
+        else
+          strerr_die4sys(100,FATAL,ERR_EXECUTE,sendargs[2],": ");
+  }
+         /* parent */
+  wait_pid(&wstat,child);
+  if (wait_crashed(wstat))
+    strerr_die2x(111,FATAL,ERR_CHILD_CRASHED);
+  switch(wait_exitcode(wstat)) {
+      case 0:
+        _exit(0);
+      default:
+        strerr_die2x(111,FATAL,ERR_CRONTAB);
+  }
+}
diff --git a/ezmlm-gate.1 b/ezmlm-gate.1
new file mode 100644 (file)
index 0000000..cd45cd5
--- /dev/null
@@ -0,0 +1,116 @@
+.TH ezmlm-gate 1
+.SH NAME
+ezmlm-gate \- Gate posts depending on message SENDER
+.SH SYNOPSIS
+.B ezmlm-gate [-cCmMpPrRsSvV] [-q file]
+.I dir [moddir1] [moddir2 ...]
+.SH DESCRIPTION
+.B ezmlm-gate
+checks if SENDER is in it least one of the subscriber lists
+with base directory
+.IR moddir1 ,
+.IR moddir2 ,
+etc.
+If it is, the message is posted via
+.B ezmlm-send 
+to the list in
+.IR dir .
+If not, the message is sent for moderation via
+.BR ezmlm-store .
+
+The default is to send the message for moderation.
+.SH OPTIONS
+.TP
+.B \-cCmMpPrRsS
+Passed on to ezmlm-store(1) and ezmlm-send(1).
+.TP
+.B \-cCrR
+Passed on to ezmlm-send(1).
+.TP
+.B \-q\fI file
+Execute arbitration programs in
+.IR file .
+Lines in
+.I file
+are executed just like in regular
+.IR .qmail
+files with the difference that all lines are assumed to be program
+names. See
+.BR dot-qmail(5) .
+Programs are executed by /bin/sh and the message is on stdin of the
+executed program.
+The leading ``|'' is optional. Comments and blank lines are allowed. If a
+program exits 111, delivery is deferred. If it exits 99, the message is
+sent to the list. If it exits 0, the next line is executed. If it exits
+with any other exit code, the message is sent for moderation. Subscriber
+status per
+.IR moddir1 ,
+.IR moddir2 ,
+etc, is tested only if all the programs have been executed and the final
+exit code is 0. Thus, programs can cause moderation (100), posting (99), or
+defer the decision to the next program and ultimately to subscriber status.
+.TP
+.B \-v
+Display version information.
+.TP
+.B \-V
+Display version information.
+
+.SH USAGE
+.B ezmlm-gate
+is best used if you want to restrict posts to a set of addresses using
+SENDER checks. Obviously, this is not secure, but it 
+can help quite a bit to keep
+garbage off the list. For more secure setups, see
+.BR ezmlm-store(1) .
+For other arbitration such as SPAM protection, use the
+.B \-q
+option. For instance, invoking
+.B ezmlm-reject(1)
+here would cause failing messages to be sent for moderation rather that being
+rejected.
+
+Set up the list with a
+.B ezmlm-gate
+line in
+.I dir\fB/editor
+and touch
+.IR dir\fB/modpost .
+Add the moderator(s) (usually the list owner):
+
+.EX
+.B ezmlm-sub
+.I dir\fB/mod
+moderator@host
+.EE
+
+This will via
+.B ezmlm-send
+directly distribute
+all posts from subscriber addresses and send out the rest for moderation
+to the moderator(s) via
+.BR ezmlm-store .
+To test several subscriber databases, e.g. the list and the list-digest
+subscribers, add the corresponding list directories to the
+.B ezmlm-gate
+command line.
+
+This can be expanded to include users that post from addresses other than
+the one they are subscribed as: just create another directory 'addl', and
+a 'subscribers' subdirectory of it, and add 'addl' to the
+.B ezmlm-gate
+command line. Now just add all problem addresses to the 'addl' address
+database using
+.BR ezmlm-sub .
+The entire point is that post from subscribers of any union
+of list go through, posts from identified 'aliases' go through and all
+others go for approval to the list owner. Thus, legitimate users are never
+rejected and 'aliases' rapidly identified by the owner/moderator and
+their handling automated one by one, by simply adding them to 'addl'.
+.SH "SEE ALSO"
+dot-qmail(5),
+ezmlm(5),
+ezmlm-issubn(1),
+ezmlm-reject(1),
+ezmlm-send(1),
+ezmlm-store(1)
diff --git a/ezmlm-gate.c b/ezmlm-gate.c
new file mode 100644 (file)
index 0000000..25d9b59
--- /dev/null
@@ -0,0 +1,213 @@
+/*$Id: ezmlm-gate.c,v 1.18 1999/10/09 16:49:56 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "strerr.h"
+#include "error.h"
+#include "env.h"
+#include "sig.h"
+#include "str.h"
+#include "seek.h"
+#include "fork.h"
+#include "wait.h"
+#include "exit.h"
+#include "getconf.h"
+#include "auto_bin.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
+#include "subscribe.h"
+
+#define FATAL "ezmlm-gate: fatal: "
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-gate: usage: ezmlm-gate [-cCmMpPqrRsSvV] "
+                       "dir [moddir [...]]");
+}
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+stralloc line = {0};
+stralloc cmds = {0};
+stralloc send = {0};
+stralloc sendopt = {0};
+stralloc storeopt = {0};
+void *psql = (void *) 0;
+
+char szchar[2] = "-";
+  char *sendargs[4];
+  int child;
+  int wstat;
+  char *pmod;
+
+int mailprog(s)
+  char *s;
+{
+    int r;
+
+    sendargs[0] = "/bin/sh";   /* 100 perm error, 111 temp, 99 dom ok */
+    sendargs[1] = "-c";                /* 0 rec ok, others bounce */
+    sendargs[2] = s;
+    sendargs[3] = (char *)0;
+    switch(child = fork()) {
+      case -1:
+       strerr_die2sys(111,FATAL,ERR_FORK);
+      case 0:
+       execv(*sendargs,sendargs);
+       if (errno == error_txtbsy || errno == error_nomem ||
+         errno == error_io)
+               strerr_die5sys(111,FATAL,ERR_EXECUTE,
+                 "/bin/sh -c ",sendargs[2],": ");
+        else
+               strerr_die5sys(100,FATAL,ERR_EXECUTE,
+                 "/bin/sh -c ",sendargs[2],": ");
+    }
+         /* parent */
+    wait_pid(&wstat,child);
+    if (wait_crashed(wstat))
+       strerr_die2x(111,FATAL,ERR_CHILD_CRASHED);
+    switch((r = wait_exitcode(wstat))) {
+      case 0: case 99: case 100: break;
+      case 111:                                        /* temp error */
+        strerr_die2x(111,FATAL,ERR_CHILD_TEMP);
+      default:
+        strerr_die2x(100,FATAL,ERR_REJECT);    /* other errors => bounce */
+    }
+    if (seek_begin(0) == -1)                   /* rewind */
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+    return r;
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  char *sender;
+  char *moddir;
+  char *queryext = (char *) 0;
+  int opt;
+  int ret = 0;
+  unsigned int i,j,k;
+
+  umask(022);
+  sig_pipeignore();
+       /* storeopts to ezmlm-store only. Others to both (ezmlm-store may */
+       /* pass them on to ezmlm-send. */
+  if (!stralloc_copys(&sendopt," -")) die_nomem();
+  if (!stralloc_copys(&storeopt," -")) die_nomem();
+
+  while ((opt = getopt(argc,argv,
+      "cCmMpPq:Q:sSrRt:T:vV")) != opteof)
+    switch(opt) {      /* pass on unrecognized options */
+      case 'c':                        /* ezmlm-send flags */
+      case 'C':
+      case 'r':
+      case 'R':
+        szchar[0] = opt;
+        if (!stralloc_append(&sendopt,szchar)) die_nomem();
+        break;
+      case 'm':                        /* ezmlm-store flags */
+      case 'M':
+      case 'p':
+      case 'P':
+      case 's':
+      case 'S':
+        szchar[0] = opt;
+        if (!stralloc_append(&storeopt,szchar)) die_nomem();
+        break;
+      case 'q':                        /* allow both qQ to be nice */
+      case 'Q': if (optarg) queryext = optarg; break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-gate version: ",EZIDX_VERSION);
+      default:                 /* ezmlm-store flags */
+        die_usage();
+    }
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  sender = env_get("SENDER");
+
+  pmod = (char *) 0;
+
+  if (queryext) {
+    getconf(&cmds,queryext,1,FATAL,dir);
+    i = 0;
+    for (j = 0;j < cmds.len; ++j)
+      if (!cmds.s[j]) {
+       switch (cmds.s[i]) {
+         case '\0': case '#': break;   /* ignore blank/comment */
+         case '|':
+               ret = mailprog(cmds.s + i + 1); break;
+         default:
+               ret = mailprog(cmds.s + i); break;
+       }
+       if (ret) break;
+       i = j + 1;
+    }
+    if (!ret || ret == 99)             /* 111 => temp error */
+      pmod = "";                       /* 0, 99 => post */
+                                       /* other => moderate */
+  }
+  moddir = argv[optind++];
+  if (moddir && !ret) {                        /* if exit 0 and moddir, add issub */
+    pmod = (char *) 0;
+    while (moddir && !pmod && sender) {
+      pmod = issub(moddir,sender,(char *) 0,FATAL);
+      closesql();
+      moddir = argv[optind++];
+    }
+  }
+
+  sendargs[0] = "sh";
+  sendargs[1] = "-c";
+  if (!stralloc_copys(&send,auto_bin)) die_nomem();
+  if (pmod) {
+    if (!stralloc_cats(&send,"/ezmlm-send")) die_nomem();
+    if (sendopt.len > 2)
+      if (!stralloc_cat(&send,&sendopt)) die_nomem();
+
+  } else {
+    if (!stralloc_cats(&send,"/ezmlm-store")) die_nomem();
+    if (storeopt.len > 2)
+      if (!stralloc_cat(&send,&storeopt)) die_nomem();
+    if (sendopt.len > 2)
+      if (!stralloc_cat(&send,&sendopt)) die_nomem();
+  }
+  if (!stralloc_cats(&send," '")) die_nomem();
+  if (!stralloc_cats(&send,dir)) die_nomem();
+  if (!stralloc_cats(&send,"'")) die_nomem();
+  if (!stralloc_0(&send)) die_nomem();
+  sendargs[2] = send.s;
+  sendargs[3] = 0;
+
+  switch(child = fork()) {
+    case -1:
+      strerr_die2sys(111,FATAL,ERR_FORK);
+    case 0:
+      execvp(*sendargs,sendargs);
+      if (errno == error_txtbsy || errno == error_nomem ||
+          errno == error_io)
+        strerr_die4sys(111,FATAL,ERR_EXECUTE,sendargs[2],": ");
+      else
+        strerr_die4sys(100,FATAL,ERR_EXECUTE,sendargs[2],": ");
+   }
+         /* parent */
+   wait_pid(&wstat,child);
+   if (wait_crashed(wstat))
+     strerr_die2x(111,FATAL,ERR_CHILD_CRASHED);
+   switch(wait_exitcode(wstat)) {
+     case 100:
+       strerr_die2x(100,FATAL,ERR_CHILD_FATAL);
+     case 111:
+        strerr_die2x(111,FATAL,ERR_CHILD_TEMP);
+     case 0:
+       _exit(0);
+     default:
+       strerr_die2x(111,FATAL,ERR_CHILD_UNKNOWN);
+   }
+}
+
diff --git a/ezmlm-get.1 b/ezmlm-get.1
new file mode 100644 (file)
index 0000000..12c4e3b
--- /dev/null
@@ -0,0 +1,464 @@
+.TH ezmlm-get 1
+.SH NAME
+ezmlm-get \- handles mailing list archive retrieval and digests
+.SH SYNOPSIS
+.B ezmlm-get
+[
+.B \-bBcCpPsSvV
+][
+.B \-f
+.I format
+]
+.I dir
+[
+.I digestcode[f]
+]
+.SH OPTIONS
+.TP
+.B \-b
+(Default.)
+Copy administrative information and the request to the bottom of replies.
+This informs the recipient of other commands, and allows some error tracking
+in case the recipient did not originate the request.
+.TP
+.B \-B
+Suppress the normal administrative information and request copy. This may make
+it harder for the recipient to diagnose problems and learn commands.
+.TP
+.B \-c
+(Default.)
+Process and reply to commands (does not affect digests).
+.TP
+.B \-C
+Ignore all commands except digest.
+.TP
+.B \-f \fIformat
+.B ezmlm-get
+will use
+.I format
+as the default format for all returned message collections. The default
+is 'm' for MIME with a header subset (see below). Format specifiers
+send with individual requests override the default set with the
+.B \-f
+switch.
+.TP
+.B \-p
+\-get, \-index, and \-thread commands are available to all users,
+provided other flags are permissive. This overrides normal behavior,
+which is to allow archive retrieval only to moderators, when
+.I dir\fB/public
+does not exist. This is useful to set up non-public lists that still give
+users archive access.
+.TP
+.B \-P
+\-get, \-index, and \-thread commands are available
+only to moderators, even if
+.I dir\fB/public
+exists. The
+.B \-C
+and
+.B \-s
+flags can restrict this further. This is useful for public lists with
+archive retrieval restricted to a subset of users (moderators).
+.TP
+.B \-s
+\-get, \-index, and \-thread requests are processed only if
+.B SENDER
+is a subscriber.
+.TP
+.B \-S
+(Default.)
+Anyone can issue \-get, \-index, and \-thread requests.
+.TP
+.B \-v
+Print version info.
+.TP
+.B \-V
+Print version info.
+.SH DESCRIPTION
+.B ezmlm-get
+handles archive retrieval and optionally makes and sends out
+digests for the mailing list
+stored in
+.IR dir .
+Subscribers of the digest list are stored in
+.IR dir\fB/digest/subscribers/ .
+
+The contents of
+.I dir\fB/headeradd
+are added to the header of outgoing messages.
+
+.B ezmlm-get
+is normally invoked from a
+.B .qmail(7)
+file.
+
+It reads a mail message from its standard input,
+and a mail envelope from the
+.BR SENDER ,
+.BR LOCAL ,
+and
+.BR HOST
+environment variables.
+
+.B ezmlm-get
+uses
+.B LOCAL
+to determine where it is invoked. If
+.B LOCAL
+is the list local name only,
+.B ezmlm-get
+assumes it is run from
+.I dir\fB/editor
+to produce a digest.
+The digest is sent directly to the digest list subscribers.
+
+If
+.B LOCAL
+is empty or undefined,
+.B ezmlm-get
+assumes it is run from the command line or a script. In this case
+it behaves as if run from
+.I dir\fB/editor
+and sends out a digest to the digest subscribers.
+
+Otherwise,
+.B ezmlm-get
+expects
+.B LOCAL
+to be of the form
+.IR list\fB-\fIaction .
+Here
+.I list
+is the first line of
+.IR dir\fB/inlocal
+and
+.I action
+is a request.
+The output is sent to the envelope sender.
+
+.BR ezmlm-get
+checks
+.I action
+for
+.BR dig\.\fIdigestcode ,
+.BR index ,
+.BR thread ,
+and
+.BR get .
+If 
+.I action
+is one of these,
+.B ezmlm-get
+handles the request and sends a reply. If successful, it
+exits 99 (ignore remaining
+.B .qmail(7)
+file entries).
+If
+.I action
+is not one of these,
+.B ezmlm-get
+exits 0 (success) to pass the message on to later handlers,
+such as
+.BR ezmlm-manage(1) .
+
+.B ezmlm-get
+expects
+.B HOST
+to match the first line of
+.IR dir\fB/inhost .
+
+.BR ezmlm-dig\.\fIdigestcode
+returns a digest of messages received since the last digest, unless
+numerical arguments are given.
+.I digestcode
+must be alphanumeric, and match (case-insensitive)
+.I digestcode
+on the
+.B ezmlm-get
+command line. Otherwise, the request will be ignored. This is to restrict
+digest creation. The body of the requesting message up to the first line
+starting with '-' is copied into the
+.I administrivia 
+section of the digest. This is followed by the contents of
+.IR dir\fB/text/digest ,
+if this file exists.
+
+.B Note:
+Anyone who can read your
+.I dir\fB/manager
+file, digest-requesting scripts, or mail log knows the
+.I digestcode
+and can trigger digests.
+
+.B ezmlm-get
+copies
+.I dir\fB/mailinglist
+into a
+.B Mailing-List
+field in its response.
+If the incoming message has a
+.B Mailing-List
+field,
+.B ezmlm-get
+refuses to respond.
+.B ezmlm-get
+also refuses to respond to bounce messages.
+
+If
+.I dir\fB/listid
+exists,
+.B ezmlm-get
+will assume that the format is correct and
+create a ``List-ID:'' header by placing the contents after the
+text ``List-ID: ''. 
+
+If
+.I dir\fB/qmqpservers
+exists,
+.B ezmlm-get will use
+.B qmail-qmqp(1)
+to send digests. Other messages are sent by the normal qmail mechanism.
+
+If
+.I dir\fB/public
+does not exist,
+.B ezmlm-get
+rejects all archive retrieval attempts, unless the
+.B \-p
+command line switch is used.
+
+Archive retrieval actions can be of the form
+.BR action[f] , 
+.BR action[f].\fInum 
+or 
+.BR action[f].\fInum_num2 ,
+where 
+.I num
+is the message number for the action or
+.I num_num2
+the range of message numbers for the action.
+
+.B f
+is an optional format specifier for
+.IR \-get ,
+.IR \-thread ,
+and
+.I \-dig
+requests. It is allowed, but ignored for
+.I \-index
+requests. Currently, the following are allowed:
+
+.TP
+.B r
+rfc1153. This is a ``plain'' non-MIME format for dumb clients.
+.TP
+.B m
+(Default.) MIME
+.I multipart/digest 
+with a subset of ordered headers sorted.
+Currently, the following headers are
+included in the order listed:
+Date:,
+To:,
+From:,
+Reply-To:,
+Cc:,
+MIME-Version:,
+Content-Type:,
+Message-ID:,
+and Keywords:.
+This can be customized with the optional file
+.IR dir\fB/digheaders ,
+which should contain the desired headers up to but not including the colon.
+
+The format is no longer compliant
+with rfc1153, as the rfc1153 format is incompatible with rfc2046, which
+which the format is (should be) compatible.
+.TP
+.B x
+MIXED: This is the same as the default MIME
+format, except that the Content-Type is
+.IR multipart/mixed .
+This helps circumnavigate a Pine bug: when the digest is
+content-transfer-encoded, Pine will refuse to display the initial
+text/plain part of a 
+.I multipart/digest
+message, but display the same part of a
+.I multipart/mixed
+message. Some MUAs for some strange reason treat the two multipart formats
+differently. In some cases, ``x'' works better than ``m''.
+.TP
+.B v
+VIRGIN: This is MIME
+.I multipart/digest 
+with messages returned without any header filtering.
+.TP
+.B n
+NATIVE: This is VIRGIN format without threading, i.e. messages are
+presented in numerical order and the message index is suppressed.
+
+.PP
+For flexibility and backwards compatibility, the '.' separating the action from
+the first argument can be replaced by '\-',
+or omitted.
+Any non-alphanumeric character can separate
+.I num2
+from
+.IR num .
+.PP
+
+If
+.I action
+is
+.IR dig.digestcode ,
+.B ezmlm-get
+returns a digest of the messages received since the last digest, and updates
+the digest issue counter.
+
+If
+.I action
+is
+.IR get ,
+.B ezmlm-get
+sends back message(s)
+.I num
+or
+.I num
+through
+.IR num2 .
+from
+.IR dir\fB/archive/ .
+If
+.I num
+is omitted and
+.I dir\fB/dignum
+does not exist or is 0, the latest HISTGET message (default 30) are
+returned. Otherwise,
+the messages since the latest digest are returned including the last
+message in that digest, so that always at least 1 message is send. If the
+number of messages
+exceeds MAXGET (default 100), only the MAXGET last messages are returned.
+if
+.I num
+is greater than the latest message in the archive _and_
+.I num2
+is specified, the latest messages back to HISTGET before the end of the
+latest digest up to MAXGET messages are returned. This is a good way of
+always getting at least the latest 30 messages without knowing the latest
+message number. A link with such a command could be put into e.g.
+.IR dir\fB/text/sub-ok .
+
+.I num
+and
+.I num2
+are adjusted to make both > 0, and
+.I num2
+>=
+.IR num .
+If either is greater than
+the largest message number processed, it is silently
+set to the largest message number.
+At most 100 messages are
+returned.
+
+If
+.I action
+is
+.BI index ,
+.B ezmlm-get
+sends back the subjects and authors of the message(s)
+.I num
+or
+.IR num
+through
+.I num2
+in sets of 100 from
+.IR dir\fB/archive/ .
+.I num
+and
+.I num2
+are reasonable adjusted as for 'get'. No warnings are
+sent. At most 20 sets of 100 message entries are returned per request. If
+.I num
+is omitted,
+.B ezmlm-get
+returns the last 100-200 message entries, which automatically gives
+information about the last message number.
+
+If
+.I action
+is
+.BI thread ,
+.B ezmlm-get
+sends back the message(s) that have an index subject entry identical to
+that of message
+.I num 
+from
+.IR dir\fB/archive/ .
+
+If
+.I num2
+is given it is ignored. If
+.I num
+is out of range, and error
+message is returned. The message range scanned for the subject is limited
+to 2000 messages before and after the master message, i.e. the
+.BR thread
+argument.
+This limit protects very large archives.
+Most threads are expected to be considerably more short-lived.
+In the unlikely event that there are further messages,
+these can be retrieved by a second request for the 
+highest/lowest message returned in the first request.
+.SH "CHARACTER SETS"
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-get
+will use the character set listed for all messages. Otherwise, the
+default ``us-ascii'' will be used. The character set can be suffixed
+by ``:'' followed by a code. If the code is ``Q'', outgoing messages are 
+sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded.
+Otherwise, text is sent as is.
+.SH "FILES"
+.TP
+.I dir\fB/dignum
+The last message included in the latest normal mode digest.
+.TP
+.I dir\fB/digissue
+The issue number of the latest normal mode digest.
+.TP
+.I dir\fB/text/get-bad
+Returned if a/the message cannot be found.
+.TP
+.I dir\fB/text/digest
+Copied into the
+.I Administrivia
+section of digests after the body of the requesting message.
+.TP
+.I dir\fB/charset
+The character set used for all
+.B ezmlm-get
+messages (see above).
+If not present, the default, ``us-ascii'', is used without encoding.
+.SH BUGS
+The digest format per rfc2046
+should (but is not required to) be multipart/mixed
+with the table-of-contents a text/plain part, and the entire remainder of
+the digest a multipart/digest part. The multipart/digest in turn should 
+contain all the messages. Many
+MUA's fail to split out the individual messages from such a hierarchy, so the
+format used by
+.B ezmlm-get
+is a simple multipart/digest, explicitly typing the table-of-contents
+to text/plain, with the ``x'' format changing the mail content-type to
+multipart/mixed.
+.SH "SEE ALSO"
+ezmlm-make(1),
+ezmlm-manage(1),
+ezmlm-send(1),
+ezmlm(5),
+qmail-command(8),
+qmail-qmqp(1)
+
diff --git a/ezmlm-get.c b/ezmlm-get.c
new file mode 100644 (file)
index 0000000..f8146ac
--- /dev/null
@@ -0,0 +1,1459 @@
+/*$Id: ezmlm-get.c,v 1.113 1999/11/22 01:47:45 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "alloc.h"
+#include "error.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "sig.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "case.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "seek.h"
+#include "quote.h"
+#include "datetime.h"
+#include "now.h"
+#include "date822fmt.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "cookie.h"
+#include "makehash.h"
+#include "copy.h"
+#include "constmap.h"
+#include "subscribe.h"
+#include "idxthread.h"
+#include "idx.h"
+#include "mime.h"
+#include "errtxt.h"
+
+int flagdo = 1;                        /* React to commands (doesn't affect -dig)*/
+int flagbottom = 1;            /* copy text/bottom + request */
+int flagpublic = 2;            /* 0 = non-public, 1 = public, 2 = respect*/
+                               /* dir/public. */
+char flagcd = '\0';            /* default: don't use quoted-printable */
+int flagsub = 0;               /* =1 subscribers only for get/index/thread */
+char *digsz =
+               "from\\to\\subject\\reply-to\\date\\message-id\\cc\\"
+               "mime-version\\content-type\\content-transfer-encoding";
+
+#define FATAL "ezmlm-get: fatal: "
+
+void die_usage() {
+  strerr_die1x(100,
+    "ezmlm-get: usage: "
+       "ezmlm-get [-bBcClLpPsSvV] [-f fmt] [digestcode]");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badaddr()
+{
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+stralloc inhost = {0};
+stralloc outhost = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc listname = {0};
+stralloc mailinglist = {0};
+stralloc qmqpservers = {0};
+stralloc fn = {0};
+stralloc moddir = {0};
+stralloc charset = {0};
+stralloc mydtline = {0};
+stralloc digheaders = {0};
+stralloc seed = {0};
+struct constmap digheadersmap;
+
+char schar[] = "00_";
+stralloc listno = {0};
+void *psql = (void *) 0;
+
+datetime_sec when;
+struct datetime dt;
+unsigned long cumsize = 0L;    /* cumulative msgs / 256 */
+unsigned long cumsizen = 0L;   /* new cumulative msgs / 256 */
+unsigned long max = 0L;                /* Last message in archive */
+unsigned long msgsize = 0L;    /* for digest accounting */
+datetime_sec digwhen;          /* last digest */
+
+char strnum[FMT_ULONG];
+char szmsgnum[FMT_ULONG];
+char date[DATE822FMT];
+char boundary[COOKIE];
+char hashout[COOKIE];
+stralloc line = {0};
+stralloc line2 = {0};
+stralloc qline = {0};
+stralloc quoted = {0};
+stralloc msgnum = {0};
+stralloc num = {0};
+stralloc subject = {0};
+
+/* for copy archive */
+stralloc archdate = {0};
+stralloc archfrom = {0};
+stralloc archto = {0};
+stralloc archcc = {0};
+stralloc archsubject = {0};
+stralloc archmessageid = {0};
+stralloc archkeywords = {0};
+stralloc archblanklines = {0};
+char archtype=' ';
+
+/* for mods on non-public lists (needed for future fuzzy sub dbs) */
+stralloc mod = {0};            /* moderator addr for non-public lists */
+char *pmod = (char *) 0;       /* pointer to above */
+
+/* for digest */
+stralloc ddir = {0};
+stralloc edir = {0};
+
+int act = AC_NONE;             /* Action we do */
+int flageditor = 0;            /* if we're invoked for within dir/editor */
+struct stat st;
+
+int flaglocked = 0;            /* if directory is locked */
+int flagarchived;              /* if list is archived */
+int flagindexed;               /* if list is indexed */
+int flagq = 0;                 /* don't use 'quoted-printable' */
+
+char *dir;
+char *workdir;
+char *sender;
+char *digestcode;
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+
+int subto(s,l)
+char *s;
+unsigned int l;
+{
+  qmail_put(&qq,"T",1);
+  qmail_put(&qq,s,l);
+  qmail_put(&qq,"",1);
+  return (int) l;
+}
+
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+
+substdio ssnum;
+char numbuf[16];
+
+substdio sstext;
+char textbuf[1024];
+
+substdio ssindex;
+char indexbuf[1024];
+
+int fdlock;
+
+void lockup()
+/* lock unless locked */
+{
+  if(!flaglocked) {
+    fdlock = open_append("lock");
+    if (fdlock == -1)
+      strerr_die2sys(111,FATAL,ERR_OPEN_LOCK);
+    if (lock_ex(fdlock) == -1) {
+      close(fdlock);
+      strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK);
+    }
+    flaglocked = 1;
+  }
+}
+
+void unlock()
+/* unlock if locked */
+{
+  if (flaglocked) {
+    close(fdlock);
+    flaglocked = 0;
+  }
+}
+
+void code_qput(s,n)
+char *s;
+unsigned int n;
+{
+    if (!flagcd)
+      qmail_put(&qq,s,n);
+    else {
+      if (flagcd == 'B')
+        encodeB(s,n,&qline,0,FATAL);
+      else
+        encodeQ(s,n,&qline,FATAL);
+      qmail_put(&qq,qline.s,qline.len);
+      msgsize += qline.len;
+    }
+}
+
+void transferenc()
+{
+       if (flagcd) {
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"Quoted-printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n\n");
+}
+
+void zapnonsub(szerr)
+/* fatal error if flagsub is set and sender is not a subscriber */
+/* expects the current dir to be the list dir. Error is szerr */
+/* added check for undefined sender as a precaution */
+char *szerr;
+{
+  if (sender && *sender) {     /* "no sender" is not a subscriber */
+    if (!flagsub)
+      return;
+    if (issub(dir,sender,(char *) 0,FATAL))
+      return;          /* subscriber */
+    if (issub(ddir.s,sender,(char *) 0,FATAL))
+      return;          /* digest subscriber */
+    if (issub(edir.s,sender,(char *) 0,FATAL))
+      return;          /* allow addresses */
+  }
+  strerr_die4x(100,FATAL,ERR_SUBSCRIBER_CAN,szerr,ERR_571);
+}
+
+void tosender()
+{
+  qmail_puts(&qq,"To: ");
+  if (!quote2(&quoted,sender)) die_nomem();
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"\n");
+}
+
+void get_num()
+{
+/* read dir/num -> max. max/cumsizen left alone if not present */
+/* Both of these should have been initialized to 0L */
+
+  unsigned int pos;
+  if (getconf_line(&num,"num",0,FATAL,dir)) {
+    if(!stralloc_0(&num)) die_nomem();
+    pos = scan_ulong(num.s,&max);
+    if (num.s[pos] == ':') pos++;
+    scan_ulong(num.s+pos,&cumsizen);
+  }
+}
+
+unsigned long dignum()
+{
+/* return dignum if exists, 0 otherwise. */
+
+  unsigned long retval;
+  if (!stralloc_copys(&num,"")) die_nomem();   /* zap */
+  getconf_line(&num,"dignum",0,FATAL,dir);
+  if(!stralloc_0(&num)) die_nomem();
+  scan_ulong(num.s,&retval);
+  return retval;
+}
+
+void write_ulong(num,cum,dat,fn,fnn)
+/* write num to "fnn" add ':' & cum if cum <>0, then move "fnn" to "fn" */
+char *fn, *fnn;
+unsigned long num,cum,dat;
+{
+  int fd;
+
+  fd = open_trunc(fnn);
+  if (fd == -1)
+     strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fnn,": ");
+  substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
+  if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,num)) == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+  if (substdio_puts(&ssnum,":") == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+  if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,cum)) == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+  if (dat) {
+    if (substdio_puts(&ssnum,":") == -1)
+       strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+    if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,dat)) == -1)
+       strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+  }
+  if (substdio_puts(&ssnum,"\n") == -1)
+     strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn,": ");
+  if (substdio_flush(&ssnum) == -1)
+     strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/",fnn,": ");
+  if (fsync(fd) == -1)
+     strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/",fnn,": ");
+  if (close(fd) == -1)
+     strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/",fnn,": ");
+  if (rename(fnn,fn) == -1)
+     strerr_die4sys(111,FATAL,ERR_MOVE,fnn,": ");
+}
+
+void normal_bottom(format)
+char format;
+/* Copies bottom text and the original message to the new message */
+{
+  if (flagbottom) {
+    copy(&qq,"text/bottom",flagcd,FATAL);
+    if (flagcd && format != RFC1153) {
+      if (flagcd == 'B') {
+       encodeB("",0,&line,2,FATAL);    /* flush */
+       qmail_put(&qq,line.s,line.len);
+      }
+      qmail_puts(&qq,"\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"\nContent-Type: message/rfc822");
+      qmail_puts(&qq,"\nContent-Disposition: inline; filename=request.msg\n\n");
+    }
+    qmail_puts(&qq,"Return-Path: <");
+    if (!quote2(&quoted,sender)) die_nomem();
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,">\n");
+    if (seek_begin(0) == -1)
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+    if (substdio_copy(&ssqq,&ssin2) != 0)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+  } else {
+    if (flagcd == 'B' && format != RFC1153) {
+      encodeB("",0,&line,2,FATAL);     /* flush */
+      qmail_put(&qq,line.s,line.len);
+    }
+  }
+}
+
+void presub(from,to,subject,factype,format)
+/* Starts within header, outputs "subject" and optional headers, terminates*/
+/* header and handles output before table-of-contents                      */
+unsigned long from,to;
+stralloc *subject;
+int factype;           /* action type (AC_THREAD, AC_GET, AC_DIGEST) */
+char format;           /* output format type (see idx.h) */
+{
+  qmail_puts(&qq,"MIME-Version: 1.0\n");
+  switch(format) {
+    case MIME:
+    case VIRGIN:
+    case NATIVE:
+    case MIXED:
+        qmail_puts(&qq,"Content-Type: multipart/");
+        if (format == MIXED)
+         qmail_puts(&qq,"mixed");
+        else
+          qmail_puts(&qq,"digest");
+       qmail_puts(&qq,"; boundary=");
+        qmail_put(&qq,boundary,COOKIE);
+       qmail_puts(&qq,"\nSubject: ");
+       qmail_put(&qq,subject->s,subject->len);
+       qmail_puts(&qq,"\n\n\n--");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+       qmail_puts(&qq,charset.s);
+       transferenc();  /* content-transfer-enc header if needed */
+        qmail_puts(&qq,"\n");
+       break;
+    case RFC1153:
+       qmail_puts(&qq,"Content-type: text/plain; charset=");
+       qmail_puts(&qq,charset.s);
+       qmail_puts(&qq,"\nSubject: ");
+       qmail_put(&qq,subject->s,subject->len);
+       qmail_puts(&qq,"\n\n");
+       flagcd = '\0';  /* We make 8-bit messages, not QP/bas64 for rfc1153 */
+        break;         /* Since messages themselves aren't encoded */
+    }
+    if (!stralloc_cats(subject,"\n\n")) die_nomem();
+    code_qput(subject->s,subject->len);
+    if (format != NATIVE && factype != AC_THREAD && factype != AC_INDEX) {
+      if (!stralloc_copys(&line,TXT_TOP_TOPICS)) die_nomem();
+      if (!stralloc_cats(&line,TXT_TOP_MESSAGES)) die_nomem();
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,from))) die_nomem();
+      if (!stralloc_cats(&line,TXT_TOP_THROUGH)) die_nomem();
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,to))) die_nomem();
+      if (!stralloc_cats(&line,TXT_TOP_LAST)) die_nomem();
+      code_qput(line.s,line.len);
+    }
+}
+
+void postsub(factype,format)
+/* output after TOC and before first message. */
+int factype;           /* action type (AC_THREAD, AC_GET, AC_DIGEST) */
+char format;           /* output format type (see idx.h) */
+{
+    code_qput(TXT_ADMINISTRIVIA,str_len(TXT_ADMINISTRIVIA));
+    if(factype == AC_DIGEST) {
+      copy(&qq,"text/digest",flagcd,FATAL);
+      if (flagcd == 'B') {
+        encodeB("",0,&line,2,FATAL);   /* flush */
+        qmail_put(&qq,line.s,line.len);
+      }
+     } else
+      normal_bottom(format);
+    if (!flagcd || format == RFC1153)
+      qmail_puts(&qq,"\n----------------------------------------------------------------------\n");
+    else
+      qmail_puts(&qq,"\n");
+}
+
+void postmsg(format)
+char format;
+{
+    switch(format) {
+       case MIME:
+       case VIRGIN:
+       case NATIVE:
+        case MIXED:
+                qmail_puts(&qq,"\n--");
+                qmail_put(&qq,boundary,COOKIE);                /* digest boundary */
+                qmail_puts(&qq,"--\n");
+               break;
+       case RFC1153:
+               qmail_puts(&qq,"End of ");
+               qmail_put(&qq,listname.s,listname.len);
+               qmail_puts(&qq," Digest");
+               qmail_puts(&qq,"\n***********************************\n");
+               break;
+    }
+}
+
+void copymsg(msg,fd,format)
+/* Copy archive message "msg" itself from open file handle fd, in "format" */
+unsigned long msg; int fd; char format;
+{
+  int match;
+  int flaginheader;
+  int flagskipblanks;
+  int flaggoodfield;
+
+  switch(format) {
+    case VIRGIN:
+    case NATIVE:
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      for (;;) {
+        if (getln(&sstext,&line,&match,'\n') == -1)
+           strerr_die4sys(111,FATAL,ERR_READ,line.s,": ");
+        if (match) {
+           qmail_put(&qq,line.s,line.len);
+          msgsize += line.len;
+        } else
+           break;
+      }
+      break;
+    case MIME:
+    case MIXED:
+      flaginheader = 1;
+      flaggoodfield = 0;
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      for (;;) {
+        if (getln(&sstext,&line,&match,'\n') == -1)
+           strerr_die4sys(111,FATAL,ERR_READ,line.s,": ");
+        if (match) {
+          if (flaginheader) {
+            if (line.len == 1) {
+              flaginheader = 0;
+              flaggoodfield = 1;
+            } else if (line.s[0] != ' ' && line.s[0] != '\t') {
+              flaggoodfield = 0;
+              if (constmap(&digheadersmap,line.s,
+                       byte_chr(line.s,line.len,':')))
+                flaggoodfield = 1;
+            }
+            if (flaggoodfield) {
+              qmail_put(&qq,line.s,line.len);          /* header */
+             msgsize += line.len;
+           }
+          } else {
+            qmail_put(&qq,line.s,line.len);            /* body */
+           msgsize += line.len;
+         }
+        } else
+          break;
+      }
+      break;
+    case RFC1153:              /* Not worth optimizing. Rarely used */
+      flaginheader = 1;
+      flagskipblanks = 1;      /* must skip terminal blanks acc to rfc1153 */
+      archtype = ' ';          /* rfc1153 requires ordered headers */
+      if (!stralloc_copys(&archblanklines,"")) die_nomem();
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      for (;;) {
+        if (getln(&sstext,&line,&match,'\n') == -1)
+           strerr_die4sys(111,FATAL,ERR_READ,line.s,": ");
+        if (match) {
+          if (flaginheader) {
+            if (line.len == 1) {
+              flaginheader = 0;
+              if (archdate.len) {
+                qmail_put(&qq,archdate.s,archdate.len);
+                archdate.len = 0;
+               msgsize += archdate.len;
+              }
+              if (archto.len) {
+                qmail_put(&qq,archto.s,archto.len);
+               msgsize += archto.len;
+                archto.len = 0;
+              }
+              if (archfrom.len) {
+                qmail_put(&qq,archfrom.s,archfrom.len);
+               msgsize += archfrom.len;
+                archfrom.len = 0;
+              }
+              if (archcc.len) {
+                qmail_put(&qq,archcc.s,archcc.len);
+               msgsize += archcc.len;
+                archcc.len = 0;
+              }
+              if (archsubject.len) {
+                qmail_put(&qq,archsubject.s,archsubject.len);
+               msgsize += archsubject.len;
+                archsubject.len = 0;
+              }
+              if (archmessageid.len) {
+                qmail_put(&qq,archmessageid.s,archmessageid.len);
+               msgsize += archmessageid.len;
+                archmessageid.len = 0;
+              }
+              if (archkeywords.len) {
+                qmail_put(&qq,archkeywords.s,archkeywords.len);
+               msgsize += archkeywords.len;
+                archkeywords.len = 0;
+              }
+              qmail_puts(&qq,"\n");
+            } else if (line.s[0] == ' ' || line.s[0] == '\t') {
+              switch (archtype) {      /* continuation lines */
+                case ' ':
+                  break;
+                case 'D':
+                  if (!stralloc_cat(&archdate,&line)) die_nomem(); break;
+                case 'F':
+                  if (!stralloc_cat(&archfrom,&line)) die_nomem(); break;
+                case 'T':
+                  if (!stralloc_cat(&archto,&line)) die_nomem(); break;
+                case 'C':
+                  if (!stralloc_cat(&archcc,&line)) die_nomem(); break;
+                case 'S':
+                  if (!stralloc_cat(&archsubject,&line)) die_nomem(); break;
+                case 'M':
+                  if (!stralloc_cat(&archmessageid,&line)) die_nomem(); break;
+                case 'K':
+                  if (!stralloc_cat(&archkeywords,&line)) die_nomem(); break;
+                default:
+                  strerr_die2x(111,FATAL,
+                      "Program error: Bad archive header type");
+              }
+            } else {
+              archtype = ' ';
+              if (case_startb(line.s,line.len,"cc:")) {
+                archtype='C';
+                if (!stralloc_copy(&archcc,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"date:")) {
+                archtype='D';
+                if (!stralloc_copy(&archdate,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"from:")) {
+                archtype='F';
+                if (!stralloc_copy(&archfrom,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"keywords:")) {
+                archtype='K';
+                if (!stralloc_copy(&archkeywords,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"message-id:")) {
+                archtype='M';
+                if (!stralloc_copy(&archmessageid,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"subject:")) {
+                archtype='S';
+                if (!stralloc_copy(&archsubject,&line)) die_nomem();
+              }
+              else if (case_startb(line.s,line.len,"to:")) {
+                archtype='T';
+                if (!stralloc_copy(&archto,&line)) die_nomem();
+              }
+            }
+          } else if (line.len == 1) {
+            if (!flagskipblanks)
+              if (!stralloc_copys(&archblanklines,"\n")) die_nomem();
+          } else {
+            if (archblanklines.len) {
+              qmail_put(&qq,archblanklines.s,archblanklines.len);
+              archblanklines.len = 0;
+            }
+            flagskipblanks = 0;
+            qmail_put(&qq,line.s,line.len);
+           msgsize += line.len;
+          }
+        } else
+          break;
+      }
+      break;
+    default:
+      strerr_die2x(100,FATAL,"Program error: bad format in copymsg()");
+  }
+}
+
+void mime_getbad(msg)
+/* Message not found as a MIME multipart */
+unsigned long msg;
+{
+   qmail_puts(&qq,"\n--");
+   qmail_put(&qq,boundary,COOKIE);
+   qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+   qmail_puts(&qq,charset.s);
+   qmail_puts(&qq,"\nContent-Disposition: inline; filename=\"");
+   qmail_put(&qq,listname.s,listname.len);
+   qmail_puts(&qq,"_");
+   qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
+   qmail_puts(&qq,".ezm\"\n");
+   transferenc();
+   copy(&qq,"text/get-bad",flagcd,FATAL);
+}
+
+void msgout(msg,format)
+/* Outputs message (everything that's needed per message) */
+unsigned long msg; char format;
+{
+  int fd;
+  unsigned int len;
+
+    if (!stralloc_copys(&fn,"archive/")) die_nomem();
+
+    len = fmt_ulong(strnum, msg / 100);
+    if (!stralloc_catb(&fn,strnum,len)) die_nomem();
+    if (!stralloc_cats(&fn,"/")) die_nomem();
+    len = fmt_uint0(strnum, (unsigned int) (msg % 100),2);
+    if (!stralloc_catb(&fn,strnum,len)) die_nomem();
+    if (!stralloc_0(&fn)) die_nomem();
+
+    switch(format) {
+      case MIME:
+      case VIRGIN:
+      case NATIVE:
+      case MIXED:
+       fd = open_read(fn.s);
+       if (fd == -1) {
+         if (errno != error_noent)
+           strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+          else
+            mime_getbad(msg);
+        } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
+         close(fd);
+          mime_getbad(msg);
+        } else {
+          qmail_puts(&qq,"\n--");
+          qmail_put(&qq,boundary,COOKIE);
+          qmail_puts(&qq,"\nContent-Type: message/rfc822");
+          qmail_puts(&qq,"\nContent-Disposition: inline; filename=\"");
+         qmail_put(&qq,listname.s,listname.len);
+         qmail_puts(&qq,"_");
+         qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
+         qmail_puts(&qq,".ezm\"\n\n");
+          copymsg(msg,fd,format);
+         close(fd);
+        }
+       break;
+      case RFC1153:
+       fd = open_read(fn.s);
+       if (fd == -1) {
+         if (errno != error_noent)
+           strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+         else {
+           qmail_puts(&qq,"\n== ");
+           qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
+           qmail_puts(&qq," ==\n\n");
+           copy(&qq,"text/get-bad",flagcd,FATAL);
+          }
+        } else {
+          if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
+           close(fd);
+           qmail_puts(&qq,"\n== ");
+           qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
+           qmail_puts(&qq," ==\n\n");
+           copy(&qq,"text/get-bad",flagcd,FATAL);
+         } else {
+           copymsg(msg,fd,format);
+           close(fd);
+          }
+       }
+       qmail_puts(&qq,"\n------------------------------\n\n");
+       break;
+      default:
+        strerr_die2x(100,FATAL,"Program error: Unrecognized format in msgout");
+        break;
+    }
+}
+
+void digest(msgtable,subtable,authtable,from,to,subj,factype,format)
+/* Output digest range from-to as per msgtable/subtable (from mkthread(s)). */
+/* "Subject is the subject of the _entire_ digest/set. */
+msgentry *msgtable; subentry *subtable; authentry *authtable;
+unsigned long from,to; stralloc *subj; int factype; char format;
+{
+  msgentry *pmsgt;
+  subentry *psubt;
+  char *cp;
+  int ffirstmsg;
+  unsigned int len;
+  unsigned long msg;
+  unsigned long subnum;
+
+  psubt = subtable;
+  presub(from,to,subj,factype,format);
+
+  if (format != NATIVE) {
+    while (psubt->sub) {
+      ffirstmsg = 1;
+               /* ptr to first message with this subject */
+      pmsgt = msgtable + psubt->firstmsg - from;
+      subnum = (unsigned long) (psubt - subtable +1);
+      for (msg=psubt->firstmsg; msg<=to; msg++) {
+        if (pmsgt->subnum == subnum) {
+          if(ffirstmsg) {
+            ffirstmsg = 0;
+            if (!stralloc_copys(&line,"\n")) die_nomem();
+           if (psubt->sublen <= HASHLEN + 2) {
+              if (!stralloc_cats(&line,"(null)\n")) die_nomem();
+           } else
+              if (!stralloc_catb(&line,psubt->sub + HASHLEN + 1,
+               psubt->sublen - HASHLEN - 1)) die_nomem();
+          } else
+            if (!stralloc_copys(&line,"")) die_nomem();
+          if (!stralloc_cats(&line,"\t")) die_nomem();
+          if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem();
+          if (!stralloc_cats(&line,TXT_BY)) die_nomem();
+          if (pmsgt->authnum) {
+           cp = authtable[pmsgt->authnum - 1].auth;
+           len = authtable[pmsgt->authnum - 1].authlen;
+           if (len > HASHLEN) {
+              if (!stralloc_catb(&line,cp + HASHLEN + 1,
+               len - HASHLEN - 1)) die_nomem();
+           } else
+             if (!stralloc_catb(&line,cp,len)) die_nomem();
+         } else
+            if (!stralloc_cats(&line,"\n")) die_nomem();
+          code_qput(line.s,line.len);
+        }
+        pmsgt++;
+      }
+      psubt++;
+    }
+  }
+  postsub(factype,format);
+
+  psubt = subtable;
+  while (psubt->sub) {
+    pmsgt = msgtable + psubt->firstmsg - from;
+    subnum = (unsigned long) (psubt - subtable +1);
+    for (msg=psubt->firstmsg; msg<=to; msg++) {
+      if (pmsgt->subnum == subnum)
+        msgout(msg,format);
+      pmsgt++;
+    }
+    psubt++;
+  }
+  postmsg(format);
+  idx_destroythread(msgtable,subtable,authtable);
+}
+
+void doheaders()
+{
+  int flaggoodfield,match;
+
+  if (act == AC_DIGEST)
+    copy(&qq,"headeradd",'H',FATAL);
+
+  qmail_puts(&qq,"Mailing-List: ");
+  qmail_put(&qq,mailinglist.s,mailinglist.len);
+  if (getconf_line(&line,"listid",0,FATAL,dir)) {
+    qmail_puts(&qq,"\nList-ID: ");
+    qmail_put(&qq,line.s,line.len);
+  }
+  qmail_puts(&qq,"\nDate: ");
+  qmail_put(&qq,date,date822fmt(date,&dt));
+  qmail_puts(&qq,"Message-ID: <");
+  if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+     die_nomem();
+  if (!stralloc_append(&line,".")) die_nomem();
+  if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+  if (!stralloc_cat(&line,&outhost)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  qmail_puts(&qq,line.s);
+               /* "unique" MIME boundary as hash of messageid */
+  makehash(line.s,line.len,boundary);
+  qmail_puts(&qq,">\nFrom: ");
+  if (!quote(&quoted,&outlocal)) die_nomem();
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"-help@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,"\n");
+  if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem();
+  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
+  if (!stralloc_cats(&mydtline,"@")) die_nomem();
+  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
+  if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+
+  qmail_put(&qq,mydtline.s,mydtline.len);
+
+  flaggoodfield = 0;
+  if (act != AC_DIGEST)
+    for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (!match) break;
+    if (line.len == 1) break;
+    if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
+      flaggoodfield = 0;
+      if (case_startb(line.s,line.len,"mailing-list:"))
+        if (flageditor)                        /* we may be running from a sublist */
+          flaggoodfield = 0;
+        else
+          strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+      if (line.len == mydtline.len)
+       if (byte_equal(line.s,line.len,mydtline.s))
+          strerr_die2x(100,FATAL,ERR_LOOPING);
+      if (case_startb(line.s,line.len,"delivered-to:"))
+        flaggoodfield = 1;
+      if (case_startb(line.s,line.len,"received:"))
+        flaggoodfield = 1;
+    }
+    if (flaggoodfield)
+      qmail_put(&qq,line.s,line.len);
+  }
+}
+
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *def;
+  char *local;
+  char *action = "";
+  char *psz;
+  char *err;
+  int fd;
+  unsigned int i,j;
+  int flagremote;
+  int flagqmqp = 0;
+  int match;
+  int goodexit = 0;                    /* exit code for normal exit */
+                                       /* in manager this will be set to 0 */
+  unsigned long from,u,to,issue,prevmax,mno;
+  unsigned long chunk;
+  unsigned long subs;
+  unsigned int pos,pos1;
+  unsigned int len;
+  int opt;
+  char outformat = DEFAULT_FORMAT;     /* default output format */
+  msgentry *msgtable;
+  subentry *subtable;
+  authentry *authtable;
+  dateentry *datetable;
+
+  (void) umask(022);
+  sig_pipeignore();
+  when = now();
+  datetime_tai(&dt,when);
+
+  while ((opt = getopt(argc,argv,"bBcCf:pPsSt:vV")) != opteof)
+    switch (opt) {
+      case 'b': flagbottom = 1; break; /* add text/bottom (default) */
+      case 'B': flagbottom = 0; break; /* suppress text/bottom */
+      case 'c': flagdo = 1; break;     /* do commands */
+      case 'C': flagdo = 0; break;     /* ignore commands X dig */
+      case 'f': if (FORMATS[str_chr(FORMATS,optarg[0])])
+                   outformat = optarg[0];
+                break;
+      case 'p': flagpublic = 1; break; /* always public */
+      case 'P': flagpublic = 0; break; /* never public = only mods do cmd*/
+                                       /* def = 2: respect DIR/public */
+      case 's': flagsub = 1; break;    /* only subs have archive access */
+      case 'S': flagsub = 0; break;    /* everyone has archive access */
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-get version: ",EZIDX_VERSION);
+      default:
+        die_usage();
+    }
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+  if (chdir(dir) == -1)
+    strerr_die4x(111,FATAL,ERR_SWITCH,dir,": ");
+
+  digestcode = argv[optind];   /* code to activate digest (-digest-code)*/
+                               /* ignore any extra args */
+
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  if (!stralloc_copy(&subject,&outlocal)) die_nomem(); /* for subjects */
+  if (!stralloc_copy(&listname,&outlocal)) die_nomem();        /* for content disp */
+
+  local = env_get("LOCAL");
+  def = env_get("DEFAULT");
+  sender = env_get("SENDER");
+  if (local && *local) {       /* in editor local = inlocal */
+    if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
+    if (!*sender)
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
+    if (str_equal(sender,"#@[]"))
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
+    if (!sender[str_chr(sender,'@')])
+      strerr_die2x(100,FATAL,ERR_ANONYMOUS);
+    if (def) {                 /* qmail>=1.02 support only */
+      if (*def) {
+       action = def;
+       goodexit = 99;
+      } else
+       _exit(0);               /* list-@host should do -help from manager */
+    } else {                   /* editor */
+      act = AC_DIGEST;         /* on list-@host ! */
+      flageditor = 1;          /* to avoid Mailing-list error on sublists */
+                               /* when running out of dir/editor. */
+    }
+    if (case_starts(action,"dig")) {
+      action += 3;
+      if (action[0] == '-' || action [0] == '.') {
+        action++;
+       if (!digestcode)
+            strerr_die2x(100,FATAL,ERR_BAD_DIGCODE);
+        len = str_len(digestcode);
+        if (len <= str_len(action) && case_startb(action,len,digestcode)) {
+          if (FORMATS[str_chr(FORMATS,*(action+len))])
+            outformat = *(action+len);
+          act = AC_DIGEST;
+        } else
+          strerr_die2x(100,FATAL,ERR_BAD_DIGCODE);
+      }
+    }
+  } else                       /* Command line operation */
+    act = AC_DIGEST;
+
+       /* Things we deal with. If anything else just die with success!   */
+       /* At the moment this is -index, -thread, and -get.               */
+       /* If flagdo = 0 we only service -dig commands. This is to support*/
+       /* "secret" lists that are still archived and digested. -c on     */
+       /* cmd line. */
+
+  if (act == AC_NONE) {
+    if (case_equals(action,ACTION_DIGEST)) {
+      act = AC_GET;            /* list-digest@ => msg since last digest */
+      action = ACTION_GET;
+    } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET))
+      act = AC_GET;
+    else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX))
+      act = AC_INDEX;
+    else if (case_starts(action,ACTION_THREAD) ||
+        case_starts(action,ALT_THREAD))
+      act = AC_THREAD;
+  }
+  if (act == AC_NONE)                  /* not for us. Pass the buck. */
+    _exit(0);
+  if (act != AC_INDEX) {               /* need to do header processing */
+    if(!getconf(&digheaders,"digheaders",0,FATAL,dir)) {
+      if(!stralloc_copys(&digheaders,digsz)) die_nomem();
+      if (!stralloc_0(&digheaders)) die_nomem();
+      psz = digheaders.s;
+      while (*psz) {
+        if (*psz == '\\') *psz = '\0';
+        ++psz;
+      }
+    }
+    if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0))
+       die_nomem();
+  }
+  if (act != AC_DIGEST) {
+    if (!flagdo)                       /* only do digests */
+      strerr_die2x(100,FATAL,ERR_NOCMD);
+    if (flagpublic == 2)
+      flagpublic = getconf_line(&line,"public",0,FATAL,dir);
+    if (!flagpublic) {
+               /* This all to take care of non-public lists. They should*/
+               /* still do digests, but do other things only for        */
+               /* moderators that have remote access. Since this is rare*/
+               /* efforts have been made to keep everything that's not  */
+               /* needed elsewhere in here.                   */
+      getconf_line(&moddir,"modsub",0,FATAL,dir);
+      flagremote = getconf_line(&line,"remote",0,FATAL,dir);
+      if (!flagremote)
+        strerr_die2x(100,FATAL,ERR_NOT_PUBLIC);
+      if (!moddir.len || moddir.s[0] != '/') {
+        if (line.len && line.s[0] == '/') {
+          if (!stralloc_copy(&moddir,&line)) die_nomem();
+        } else {
+          if (!stralloc_copys(&moddir,dir)) die_nomem();
+          if (!stralloc_cats(&moddir,"/mod")) die_nomem();
+        }
+      }
+      if (!stralloc_0(&moddir)) die_nomem();
+      pmod = issub(moddir.s,sender,(char *) 0,FATAL);
+      if (!pmod)                       /* sender = moderator? */
+        strerr_die2x(100,FATAL,ERR_NOT_PUBLIC);
+      else {
+        if (!stralloc_copys(&mod,pmod)) die_nomem();
+        if (!stralloc_0(&mod)) die_nomem();
+        pmod = mod.s;          /* send to address in list not matching bait */
+      }
+    }
+  }
+
+  flagindexed = getconf_line(&line,"indexed",0,FATAL,dir);
+  flagarchived = getconf_line(&line,"archived",0,FATAL,dir);
+
+  if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+    if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+      if (charset.s[charset.len - 1] == 'B' ||
+                charset.s[charset.len - 1] == 'Q') {
+        flagcd = charset.s[charset.len - 1];
+        charset.s[charset.len - 2] = '\0';
+      }
+    }
+  } else
+    if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+  if (!stralloc_0(&charset)) die_nomem();
+  getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  set_cpouthost(&outhost);
+
+    if (!stralloc_copys(&ddir,dir)) die_nomem();
+    if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+    if (!stralloc_0(&ddir)) die_nomem();
+  if (act == AC_DIGEST) {
+    workdir = ddir.s;
+    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
+    if (getconf_line(&line,"chunk",0,FATAL,dir)) {
+      if (!stralloc_0(&line)) die_nomem();
+      (void) scan_ulong(line.s,&chunk);                /* same chunk as main list */
+      if (chunk == 0)                          /* limit range to 1-53 */
+       chunk = 1L;
+      else if (chunk > 52)
+       chunk = 52L;
+    } else {
+      chunk = 0L;                              /* maybe direct qmqp? */
+      if (!stralloc_copys(&line,QMQPSERVERS)) die_nomem();
+      if (!stralloc_cats(&line,"/0")) die_nomem();
+      if (!stralloc_0(&line)) die_nomem();
+      flagqmqp = getconf(&qmqpservers,line.s,0,FATAL,dir);
+    }
+  } else
+    workdir = dir;
+
+  if (!stralloc_copys(&edir,dir)) die_nomem(); /* not needed for -dig, but */
+  if (!stralloc_cats(&edir,"/allow")) die_nomem();     /* be safe */
+  if (!stralloc_0(&edir)) die_nomem();
+  set_cpoutlocal(&outlocal);           /* needed for copy */
+
+  if (flagqmqp) {
+    if (qmail_open(&qq,&qmqpservers) == -1)            /* open qmail */
+      strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+  } else if (qmail_open(&qq,(stralloc *) 0) == -1)     /* open qmail */
+      strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+
+  set_cpnum("");       /* default for <#n#> replacement */
+
+  if (act == AC_DIGEST) {
+/* -dig{.|-}'digestcode'[f] returns an rfc1153 digest                        */
+/* of messages from the archive. Messages                                    */
+/* dignum+1 through the last message received by the list are processed and  */
+/* dignum is updated to the last message processed. digissue is advanced.    */
+
+    if (!flagarchived)
+      strerr_die2x(100,FATAL,ERR_NOT_ARCHIVED);
+
+    get_num();                         /* max = last successful message */
+    to = max;
+    lockup();                  /* another digest could corrupt dignum */
+                               /* but will be saved only if flagdigrange==0 */
+    if(getconf_line(&num,"dignum",0,FATAL,dir)) {
+      if(!stralloc_0(&num)) die_nomem();
+      pos = scan_ulong(num.s,&prevmax);
+      if (num.s[pos] == ':') pos++;
+      pos += 1 + scan_ulong(num.s+pos,&cumsize);       /* last cumsize */
+      if (num.s[pos] == ':') pos++;
+      scan_ulong(num.s+pos,&digwhen);                  /* last reg dig */
+    } else {
+      prevmax = 0L;
+      cumsize = 0L;
+      digwhen = 0L;
+    }
+    mno = prevmax + 1L;
+    if(!max || mno > max)      /* if a digest-list is "sending" the request, */
+                               /* don't make noise: errors go to postmaster!*/
+      strerr_die2x(goodexit,FATAL,ERR_EMPTY_DIGEST);
+    szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0';
+    set_cpnum(szmsgnum);       /* for copy */
+                               /* prepare subject to get entropy for tagmsg*/
+    if (!stralloc_cats(&subject," Digest ")) die_nomem();
+    if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1))
+          die_nomem();         /* skip trailing in date '\n' */
+    if (!stralloc_cats(&subject," Issue ")) die_nomem();
+    if (getconf_line(&num,"digissue",0,FATAL,dir)) {
+      if(!stralloc_0(&num)) die_nomem();
+      scan_ulong(num.s,&issue);
+      issue++;
+    } else {
+      issue = 1;
+    }
+    if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue)))
+      die_nomem();
+                                       /* use the subject as entropy */
+    if (!stralloc_copy(&line,&subject)) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+
+    if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem();
+    seed.len = HASHLEN + 1;
+    seed.s[HASHLEN] = '\0';
+    makehash(line.s,line.len,seed.s);
+    if (chunk) {                       /* only if slaves are used */
+      qmail_puts(&qq,"Ezauth: ");
+      qmail_put(&qq,seed.s,HASHLEN);
+      qmail_puts(&qq,"\n");
+    }
+
+    doheaders();
+    qmail_puts(&qq,"To: ");
+    if (!quote(&quoted,&listname)) die_nomem();
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,"@");
+    qmail_put(&qq,outhost.s,outhost.len);
+    qmail_puts(&qq,"\n");
+    if (flagindexed && (outformat != NATIVE))
+      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
+       mno,to,max,flaglocked,FATAL);
+    else
+      idx_mklist(&msgtable,&subtable,&authtable,mno,to,FATAL);
+    digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat);
+
+    write_ulong(issue,0L,0L,"digissue","digissuen");
+    write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn");
+  }
+
+  else if (act == AC_GET) {
+
+/* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted   */
+/* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET.  */
+
+    if (!flagarchived)
+      strerr_die2x(100,FATAL,ERR_NOT_ARCHIVED);
+    zapnonsub(ACTION_GET);             /* restrict to subs if requested */
+    tosender();
+                               /* for rfc1153 */
+    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
+    if (!stralloc_cats(&subject,action)) die_nomem();
+
+    to = 0;
+    pos = str_len(ACTION_GET);
+    if (!case_starts(action,ACTION_GET))
+      pos = str_len(ALT_GET);
+    if (FORMATS[str_chr(FORMATS,action[pos])]) {
+       outformat = action[pos];
+       ++pos;
+    }
+                                       /* optional - or . after '-get' */
+    if (action[pos] == '-' || action[pos] == '.') pos++;
+    get_num();                         /* max = last successful message */
+                                       /* accept any separator. It may be  */
+                                       /* the terminal '\n', but then      */
+                                       /* scan will = 0 on the \0 so should*/
+                                       /* be safe                          */
+    if (!max)
+      strerr_die2x(100,FATAL,ERR_EMPTY_LIST);
+    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
+    set_cpnum(szmsgnum);       /* for copy this is the latest message arch'd*/
+    doheaders();
+    if(action[pos += scan_ulong(action + pos,&u)])
+      scan_ulong(action + pos + 1, &to);
+    if (u == 0 && to == 0) {           /* default: messages since last */
+                                       /* digest, or last MAXGET if too many */
+      to= max;
+      u = dignum();
+      if (u == 0) {            /* no digest => last up to HISTGET msgs */
+       to = max;
+       if (max > HISTGET) u = max - HISTGET; else u = 1;
+      }
+      if (to - u >= MAXGET) u = to - MAXGET + 1;       /* max MAXGET */
+    } else if (u > max) {
+      if (to) {                        /* -get.999999_x returns 30 and msg since last*/
+       to = max;               /* digest 30*/
+        u = dignum();
+       if (u > HISTGET) u -= HISTGET; else u = 1;
+        if (to - u >= MAXGET) u = to - MAXGET + 1;
+      } else
+       u = max;
+    }
+    if (u == 0) u = 1;                 /* -get.5 => 1-5 */
+    if (to < u) to = u;                        /* -get23_2 => 23 */
+    if (to >= u + MAXGET) to = u + MAXGET - 1;
+                                       /* no more than MAXGET at a time */
+    if (to > max) to = max;
+    if (flagindexed && (outformat != NATIVE))  /* fake out threading */
+      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
+       u,to,max,0,FATAL);
+    else
+      idx_mklist(&msgtable,&subtable,&authtable,u,to,FATAL);
+    digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat);
+  }
+
+  else if (act == AC_INDEX) {
+
+/* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/
+/* sets of 100.                                                              */
+/* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */
+/* limited to num+MAXINDEX to limit the amount of data sent.                 */
+
+    if (!flagindexed)
+      strerr_die2x(100,FATAL,ERR_NOT_INDEXED);
+    if (flagsub)
+    zapnonsub(ACTION_INDEX);   /* restrict to subs if requested */
+    to = 0;
+    pos = str_len(ACTION_INDEX);
+    if (!case_starts(action,ACTION_INDEX))
+      pos = str_len(ALT_INDEX);
+    if (FORMATS[str_chr(FORMATS,action[pos])]) {
+       outformat = action[pos];                /* ignored, but be nice ... */
+       ++pos;
+    }
+    get_num();                         /* max = last successful message */
+    if (!max)
+      strerr_die2x(100,FATAL,ERR_EMPTY_LIST);
+    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
+    set_cpnum(szmsgnum);       /* for copy this is the latest message arch'd*/
+
+    doheaders();
+    tosender();
+    if (!stralloc_cats(&subject," Result of: ")) die_nomem();
+    if (!stralloc_cats(&subject,action)) die_nomem();
+    presub(1,1,&subject,AC_INDEX,outformat);
+
+    if (action[pos] == '-' || action[pos] == '.') pos++;
+    if(action[pos += scan_ulong(action + pos,&u)])
+      scan_ulong(action + pos + 1, &to);
+
+    if (u == 0 && to == 0) { to = max; u = max - 100; }
+    if (u <= 0) u = 1;
+    if (u > max) u = max;
+    if (to < u) to = u;
+    if (to > u + MAXINDEX) to = u+MAXINDEX;    /* max MAXINDEX index files */
+    if (to > max) to = max;
+    u /= 100;
+    to /= 100;
+    while (u <= to) {
+      if (!stralloc_copys(&fn,"archive/")) die_nomem();
+      if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem();
+      if (!stralloc_cats(&fn,"/index")) die_nomem();
+      if (!stralloc_0(&fn)) die_nomem();
+
+      if (u == max/100)        /* lock if last index file in archive */
+        lockup();
+
+      fd = open_read(fn.s);
+      if (fd == -1)
+        if (errno != error_noent)
+          strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": ");
+        else
+          code_qput(TXT_NOINDEX,str_len(TXT_NOINDEX));
+      else {
+        substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+        for (;;) {
+          if (getln(&sstext,&line,&match,'\n') == -1)
+            strerr_die4sys(111,FATAL,ERR_READ,fn.s,": ");
+          if (match) {
+            if (line.s[0] != '\t') {   /* subject line */
+              pos = byte_chr(line.s,line.len,' ');
+             if (pos && pos != line.len && line.s[pos - 1] == ':')
+                pos1 = pos + HASHLEN + 1;      /* after hash */
+              if (pos1 >= line.len) {  /* bad! */
+                pos = 0;
+                pos1 = 0;              /* output as is */
+              }
+              if (!stralloc_copyb(&line2,line.s,pos)) die_nomem();
+              if (!stralloc_catb(&line2,line.s+pos1,line.len-pos1)) die_nomem();
+            } else {
+             pos = byte_chr(line.s,line.len,';');
+             if (pos + HASHLEN + 1 < line.len && pos > 15 &&
+                               line.s[pos + 1] != ' ') {
+                 if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem();
+                 pos++;
+                 if (!stralloc_catb(&line2,line.s + pos + HASHLEN,
+                       line.len - pos - HASHLEN)) die_nomem();
+             } else                    /* old format - no author hash */
+                if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem();
+           }
+            code_qput(line2.s,line2.len);
+          } else
+            break;
+        }
+        close(fd);
+      }
+
+      if (u == max/100)        /* unlock if last index in archive file */
+        unlock();
+
+      u++;
+    }
+    normal_bottom(outformat);
+    postmsg(outformat);
+  }
+
+  else if (act == AC_THREAD) {
+
+/* -thread[f][-|.]num returns messages with subject matching message        */
+/* 'num' in the subject index. If 'num' is not in[1..last_message] an error */
+/* message is returned.                                                     */
+
+    if (!flagarchived)
+      strerr_die2x(100,FATAL,ERR_NOT_ARCHIVED);
+    if (!flagindexed)
+      strerr_die2x(100,FATAL,ERR_NOT_INDEXED);
+
+    zapnonsub(ACTION_THREAD);          /* restrict to subs if requested*/
+
+    get_num();                         /* max = last successful message */
+    if (!max)
+      strerr_die2x(100,FATAL,ERR_EMPTY_LIST);
+    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
+    set_cpnum(szmsgnum);       /* for copy this is the latest message arch'd*/
+
+    doheaders();
+    tosender();
+                               /* for rfc1153 */
+    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
+    if (!stralloc_cats(&subject,action)) die_nomem();
+
+    to = 0;
+    pos = str_len(ACTION_THREAD);
+    if (!case_starts(action,ACTION_THREAD))
+      pos = str_len(ALT_THREAD);
+    if (FORMATS[str_chr(FORMATS,action[pos])]) {
+       outformat = action[pos];
+       ++pos;
+    }
+    if (action[pos] == '-' || action[pos] == '.') pos++;
+    if(action[pos += scan_ulong(action + pos,&u)])
+      scan_ulong(action + pos + 1, &to);
+
+    if(u == 0 || u > max) {
+      if (!stralloc_cats(&subject,"\n\n")) die_nomem();
+      qmail_puts(&qq,"Subject: ");
+      qmail_put(&qq,subject.s,subject.len);
+      copy(&qq,"text/get-bad",flagcd,FATAL);
+    } else {   /* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */
+      if (u > THREAD_BEFORE)
+        from = u-THREAD_BEFORE;
+      else
+        from = 1L;
+      if (u + THREAD_AFTER > max) {
+        idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0,FATAL);
+        digest(msgtable,subtable,authtable,from,max,&subject,
+               AC_THREAD,outformat);
+      } else {
+        idx_mkthread(&msgtable,&subtable,&authtable,
+               from,u+THREAD_AFTER,u,max,0,FATAL);
+        digest(msgtable,subtable,authtable,from,u+THREAD_AFTER,
+                       &subject,AC_THREAD,outformat);
+      }
+    }
+  }
+
+  else
+       /* This happens if the initial check at the beginning of 'main'    */
+       /* matches something that isn't matched here. Conversely, just     */
+       /* adding an action here is not enough - it has to be added to the */
+       /* initial check as well.                                          */
+
+    strerr_die2x(100,FATAL,
+      "Program error: I'm supposed to deal with this but I didn't");
+
+  if (!stralloc_copy(&line,&outlocal)) die_nomem();
+  if (act == AC_DIGEST) {
+    if (chunk) {
+      if (!stralloc_cats(&line,"-return-g-")) die_nomem();
+    } else
+      if (!stralloc_cats(&line,"-return-")) die_nomem();
+    strnum[fmt_ulong(strnum,mno)] = '\0';
+    if (!stralloc_cats(&line,strnum)) die_nomem();
+    if (!stralloc_cats(&line,"-@")) die_nomem();
+
+    if (!stralloc_cat(&line,&outhost)) die_nomem();
+    if (!stralloc_cats(&line,"-@[]")) die_nomem();
+  } else {
+    if (!stralloc_cats(&line,"-return-@")) die_nomem();
+    if (!stralloc_cat(&line,&outhost)) die_nomem();
+  }
+  if (!stralloc_0(&line)) die_nomem();
+
+  qmail_from(&qq,line.s);
+  if (act == AC_DIGEST) {       /* Do recipients */
+    tagmsg(workdir,mno,seed.s,"d",hashout,qq.msgbytes,chunk,FATAL);
+    if (chunk) {
+      if (!stralloc_copys(&line,"T")) die_nomem();
+      if (!stralloc_cat(&line,&outlocal)) die_nomem();
+      if (!stralloc_cats(&line,"-s-d-")) die_nomem();
+      if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem();
+      if (!stralloc_cats(&line,"-")) die_nomem();
+      if (!stralloc_cats(&line,strnum)) die_nomem();
+      if (!stralloc_cats(&line,"-")) die_nomem();
+      if (!stralloc_copys(&line2,"@")) die_nomem();
+      if (!stralloc_cat(&line2,&outhost)) die_nomem();
+      if (!stralloc_0(&line2)) die_nomem();
+      j = 0;
+      for (i = 0; i <= 52; i += chunk) {               /* To slaves */
+        qmail_put(&qq,line.s,line.len);
+        schar[0] = '0' + i / 10;
+        schar[1] = '0' + (i % 10);
+        qmail_put(&qq,schar,3);
+        j += (chunk - 1);
+        if (j > 52) j = 52;
+        schar[0] = '0' + j / 10;
+        schar[1] = '0' + (j % 10);
+        qmail_put(&qq,schar,2);
+        qmail_put(&qq,line2.s,line2.len);
+      }
+    } else
+      subs = putsubs(workdir,0L,52L,&subto,1,FATAL);
+  } else {                     /* if local is set, sender is checked */
+    if (pmod)
+      qmail_to(&qq,pmod);
+    else
+      qmail_to(&qq,sender);
+  }
+
+  if (*(err = qmail_close(&qq)) == '\0') {     /* Done. Skip rest. */
+    if (act == AC_DIGEST) {
+      if (chunk)
+       (void) logmsg(workdir,mno,0L,0L,2);
+      else
+        (void) logmsg(workdir,mno,0L,subs,4);
+    }
+    closesql();                        /* close db connection */
+    unlock();                  /* NOP if nothing locked */
+    strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+    strerr_die2x(goodexit,"ezmlm-get: info: qp ",strnum);
+  } else {                     /* failed. Reset last msg & issue for digest */
+    if(act == AC_DIGEST) {
+      issue--;
+      write_ulong(issue,0L,0L,"digissue","digissuen");
+      write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn");
+    }
+    unlock();                  /* NOP if nothing locked */
+    strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+  }
+}
diff --git a/ezmlm-glconf.1 b/ezmlm-glconf.1
new file mode 100644 (file)
index 0000000..df054be
--- /dev/null
@@ -0,0 +1,54 @@
+.TH ezmlm-glconf 1
+.SH NAME
+ezmlm-glconf \- create config file for global ezmlm-request address
+.SH SYNOPSIS
+.B ezmlm-glconf
+[
+.B \-n
+]
+.IR dotdir [dotdir1 ...] >
+.I config_file
+.SH DESCRIPTION
+.B ezmlm-glconf
+scans
+.IR dotdir ,
+usually the users home directory,
+for files of type
+.BR .qmail-return-*-default .
+For normal ezmlm-lists, these are links to
+.B bouncer
+files, which on their last line have a call to
+.B ezmlm-return(1)
+or
+.BR ezmlm-warn(1).
+.B ezmlm-glconf
+extracts the list directory from these,
+and builds a
+line for
+.I config_file
+from the information in the list directory. The first line of
+the
+.B /text/info
+file of the list is assumed to contain a brief description of the list. If
+not found ``no information available'' is used.
+
+.B ezmlm-glconf
+output is sorted alphabetically by list name and if a digest list
+exists, the digest list entry immediately follows the list entry.
+
+.SH OPTIONS
+.TP
+.B \-n
+Add information on the current number of subscribers to the list information.
+.SH CONFIGURATION
+The descriptive text
+.B ezmlm-glconf
+uses for digest lists and the text used if
+.B /text/info
+is not readable/available can be changed by editing the script.
+.SH "SEE ALSO"
+ezmlm-glmake(1),
+ezmlm-request(1),
+ezmlm-return(1),
+ezmlm-warn(1),
+ezmlm(5)
diff --git a/ezmlm-glconf.sh b/ezmlm-glconf.sh
new file mode 100644 (file)
index 0000000..73f2e0d
--- /dev/null
@@ -0,0 +1,107 @@
+# above should be a definition of EZPATH and the /bin/sh line
+# automatically added at build time.
+#########################################################################
+# Script to build ezmlm-request config file for the global interface
+#      Lists are presented in alphabetical order and digest lists are
+#      directly after the main list. Digest list info is only that
+#      they are digest of the main list. If the -n switch is used,
+#      the current number of subscribers is added to the info text.
+#
+# Usage: ezmlm-glconf [-n] dotdir [dotdir1 ...] > config
+#      where ``dotdir'' is the directory where the users .qmail files
+#      reside (usually ``~''), and ``config'' is the config file for
+#      ezmlm-request servicing the global interface.
+#
+#      Note: This config file will provide info on all lists available
+#      and allow ``which'' for all lists. You may want to edit the
+#      output before using it.
+##########################################################################
+
+# Change if you change the name of the command
+NAME='ezmlm-glconf'
+
+# Info text used for list-digest
+DIGTXT='Digest of'
+# ``subscribers'' for stating subscriber number
+SUBTXT='subscribers'
+# Info text if dir/text/info doesn't exist/is not readable
+INFOTXT='No information available'
+
+# Set full path if you use the script as root or if the commands
+# are not in your path.
+HEAD='head'
+TAIL='tail'
+CAT='cat'
+CUT='cut'
+GREP='grep'
+ECHO='echo'
+LS='ls'
+SORT='sort'
+SED='sed'
+WC='wc'
+
+# Nothing more to configure
+##########################################################################
+
+SUB=''
+EZLIST="${EZPATH}/ezmlm-list"
+FATAL="${NAME}: fatal: "
+WARN="${NAME}: warning: "
+USAGE="${NAME} [-n] dotdir [dotdir1 ...] > config"
+
+if [ "$1" = "-n" ]; then
+       shift
+       if [ ! -x "${EZLIST}" ]; then
+               echo "${WARN} ezmlm-list not found. Edit ezmlm binary path."
+       else
+               SUB='yes'
+       fi
+fi
+
+if [ -z "$1" ]; then
+       ${ECHO} "$USAGE"
+       exit 100
+fi
+
+
+(
+while [ -n "$1" ]; do
+  for i in `${LS} $1/.qmail-*-return-default` ; do
+       INFO=''
+                                       # get list directory
+       if [ -r "$i" ] ; then
+               DIR=`${TAIL} -1 "$i" | ${CUT} -d\' -f2`
+                                       # only dir that exists
+               if [ -d "$DIR" ] ; then
+                       INFOFN="${DIR}/text/info"
+                       if [ -r "${INFOFN}" ]; then
+                               INFO=`${HEAD} -1 ${INFOFN}`
+                       else
+                               INFO="$INFOTXT"
+                               ${ECHO} "$WARN No info for list in $DIR" 1>&2
+                       fi
+
+                       OUTLOCAL=`${CAT} $DIR/outlocal`
+                       OUTHOST=`${CAT} $DIR/outhost`
+                       if [ -z "$SUB" ]; then
+                               SUBN=''
+                       else
+                               NO=`${EZLIST} ${DIR} | ${WC} -l |${SED} 's/ //g'`
+                               SUBN=" (${NO} ${SUBTXT})"
+                       fi
+                       ${ECHO} "$i" | ${GREP} 'digest-return' >/dev/null && \
+                               { INFO="${DIGTXT} $OUTLOCAL@$OUTHOST."; \
+                               OUTLOCAL="${OUTLOCAL}~digest" ; }
+                       ${ECHO} "$OUTLOCAL@$OUTHOST:$DIR:${INFO}${SUBN}"
+               else
+                       ${ECHO} "$WARN $DIR not readable - list ignored" 1>&2
+               fi
+       else
+               ${ECHO} "$WARN $i ignored: doesn't point to readable file" 1>&2
+       fi
+  done ;
+  shift
+done;
+) | ${SORT} | ${SED} 's/~digest@/-digest@/'
+                                       # list-digest after list
+                                       # "~"-cludge needed to get order right
diff --git a/ezmlm-idx.1 b/ezmlm-idx.1
new file mode 100644 (file)
index 0000000..60a07ea
--- /dev/null
@@ -0,0 +1,97 @@
+.TH ezmlm-idx 1
+.SH NAME
+ezmlm-idx \- create index for mailing list archive
+.SH SYNOPSIS
+.B ezmlm-idx
+[
+.B \-dDF
+][
+.B \-f\I msg
+]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-idx
+reads all archived messages for the list in
+.I dir
+from
+.IR dir\fB/archive/
+and creates a message index. The index file format is identical to
+that produced by
+.B ezmlm-send(1)
+(when
+.IR dir\fB/indexed
+is present).
+
+.B ezmlm-idx
+will ignore messages that do not have the owner execute bit set.
+
+.B ezmlm-idx
+will create the the index file under a different name and then
+move it into place.
+
+If 
+.IR dir\fB/indexed
+does not exist,
+.B ezmlm-idx
+will create it to enable the use of the newly created subject and author index.
+
+.B ezmlm-idx
+will remove reply-indicators and the prefix from the subject before
+entry into the index, as described for
+.BR ezmlm-send(1) .
+.B ezmlm-idx
+will decode rfc2047 encoded subject and author headers. When unfolding
+split lines,
+.B ezmlm-idx
+will remove redundant escape sequences for the character
+set specified in
+.IR dir\fB/charset .
+
+.B ezmlm-idx
+calculates a subject hash based on the normalized subject header. Normalization
+removes linear whitespace, case information, and message reply indicators.
+The subject hash is used by
+.B ezmlm-get(1)
+for message threading.
+.SH OPTIONS
+.TP
+.B \-d
+Use the ``Date:'' header for date information, rather than the top ``Received:''
+header. This is unreliable, but useful when messages have been transferred from
+another type of archive by mailing them to ezmlm.
+.B ezmlm-idx
+converts dates with two-digit years ``xx'' to 19xx if xx is >= 70. Otherwise,
+20xx is assumed.
+.TP
+.B \-D
+(Default.)
+Use the ``Received:'' header, not the ``Date:'' header. This is more reliable
+since this is the header added by the receiving qmail. Also, this results
+in always correctly formatted dates in the same time zone (usually UTC).
+.TP
+.B \-f\fI msg
+Start indexing with the archive section containing message
+.IR msg .
+This is useful if you have removed part of the archive and do not want to
+create (empty) directories and index files for these. It also decreases
+.B ezmlm-idx
+memory use.
+.TP
+.B \-F
+(Default.)
+Start indexing from message 1.
+.TP
+.B \-v
+Display
+.B ezmlm-idx
+version info.
+.TP
+.B \-V
+Display
+.B ezmlm-idx
+version info.
+.SH "SEE ALSO"
+ezmlm-archive(1),
+ezmlm-get(1),
+ezmlm-send(1),
+ezmlm(5)
diff --git a/ezmlm-idx.c b/ezmlm-idx.c
new file mode 100644 (file)
index 0000000..c552357
--- /dev/null
@@ -0,0 +1,337 @@
+/*$Id: ezmlm-idx.c,v 1.29 1999/10/29 02:49:14 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "stralloc.h"
+#include "subfd.h"
+#include "strerr.h"
+#include "error.h"
+#include "lock.h"
+#include "slurp.h"
+#include "open.h"
+#include "getln.h"
+#include "sgetopt.h"
+#include "case.h"
+#include "scan.h"
+#include "str.h"
+#include "fmt.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "substdio.h"
+#include "idx.h"
+#include "mime.h"
+#include "errtxt.h"
+#include "getconf.h"
+#include "makehash.h"
+
+#define FATAL "ezmlm-idx: fatal: "
+
+char strnum[FMT_ULONG];
+char hash[HASHLEN];
+
+stralloc fnadir = {0};
+stralloc fnif = {0};
+stralloc fnifn = {0};
+stralloc fnaf = {0};
+
+stralloc line = {0};
+stralloc lines = {0};
+stralloc dummy = {0};
+
+int fdindexn;
+int fdlock;
+int fd;
+int flagdate = 0;      /* use 'Received:' header by default, =1 -> 'Date:' */
+
+       /* for reading index and in ezmlm-idx for reading message */
+static substdio ssin;
+static char inbuf[1024];
+
+substdio ssindex;
+char indexbuf[1024];
+
+struct stat st;
+
+stralloc subject = {0};
+stralloc author = {0};
+stralloc authmail = {0};
+stralloc received = {0};
+stralloc prefix = {0};
+stralloc charset = {0};
+
+struct strerr index_err;
+
+stralloc num = {0};
+
+char buf0[256];
+substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-idx: usage: ezmlm-idx [-dDF] [-f msg] dir");
+
+}
+
+void die_nomem()
+{
+  strerr_die2x(100,FATAL,ERR_NOMEM);
+}
+
+int idx_get_trimsubject()
+
+/* reads an open message from 'fd', extracts the subject (if any), and    */
+/* returns the subject in 'sub', the author in 'author', and the received */
+/* rfc822 date to 'received'. 'fatal' is a program-specific error string. */
+/* returns: 0 - no reply no prefix */
+/*          1 - reply no prefix */
+/*          2 - prefix no reply */
+/*          3 - reply & prefix */
+/* No terminal '\n' in any of the strallocs! */
+{
+char *cp;
+int foundsubject = 0;
+int issubject = 0;
+int isfrom = 0;
+int foundreceived = 0;
+int foundfrom = 0;
+int match;
+int r;
+unsigned int pos,pos1;
+
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2x(111,FATAL,ERR_READ_INPUT);
+    if (match) {
+      if (line.len == 1)
+        break;
+      if (*line.s == ' ' || *line.s == '\t') {
+                               /* continuation */
+        if (issubject) {
+          if (!stralloc_cat(&subject,&line)) die_nomem();
+        } else if (isfrom)
+          if (!stralloc_cat(&author,&line)) die_nomem();
+      } else {
+        issubject = 0;
+        isfrom = 0;
+        if (!foundsubject && case_startb(line.s,line.len,"Subject:")) {
+          if (!stralloc_copyb(&subject,line.s+8,line.len-8)) die_nomem();
+          foundsubject = 1;
+          issubject = 1;
+        } else if (!foundfrom && case_startb(line.s,line.len,"From:")) {
+          if (!stralloc_copyb(&author,line.s+5,line.len-5)) die_nomem();
+          foundfrom = 1;
+          isfrom = 1;
+        } else if (!flagdate && !foundreceived &&
+            case_startb(line.s,line.len,"Received:")) {
+          pos = byte_chr(line.s,line.len,';');
+          if (pos != line.len)
+            if (!stralloc_copyb(&received,line.s+pos+2,line.len - pos - 3))
+              die_nomem();
+          foundreceived = 1;
+        } else if (flagdate && !foundreceived &&
+            case_startb(line.s,line.len,"Date:")) {
+          if (line.len < 22) continue;                         /* illegal */
+          pos = 6 + byte_chr(line.s+6,line.len-6,',');
+          if (pos == line.len)
+            pos = 5;
+          ++pos;
+          while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;     /* dd */
+          pos1 = pos + 3;
+          while (++pos1 < line.len && line.s[pos1] != ' ');            /* mo */
+          ++pos1;
+          if (!stralloc_copyb(&received,line.s+pos,pos1 - pos))
+              die_nomem();                                     /* '01 Jun ' */
+          if (pos1 + 2 < line.len) {
+            if (line.s[pos1 + 2] == ' ') {                     /* 2-digit */
+              if (line.s[pos1] >= '7') {                       /* >= 70 */
+              if (!stralloc_cats(&received,"19")) die_nomem();
+              } else if (!stralloc_cats(&received,"20")) die_nomem();
+              pos = pos1 + 3;                                  /* 2 digit */
+            } else
+              pos = pos1 + 5;                                  /* 4 digit */
+            if (pos < line.len) {
+              pos += byte_chr(line.s+pos,line.len-pos,' ');    /* after time */
+              if (pos < line.len) {
+                ++pos;                                         /* zone */
+                while (line.s[pos] != ' ' && line.s[pos] != '\n') ++pos;
+              } else
+                pos = line.len - 1;    /* no zone. Illegal; better than 0 */
+              if (!stralloc_catb(&received,line.s+pos1,pos - pos1))
+                       die_nomem();
+              foundreceived = 1;
+              continue;
+            }
+          }
+          received.len = 0;            /* bad format - scrap */
+        }
+      }
+    } else
+      break;
+  }
+
+  if (foundsubject) {
+    concatHDR(subject.s,subject.len,&lines,FATAL);     /* make 1 line */
+    decodeHDR(lines.s,lines.len,&line,charset.s,FATAL);        /* decode mime */
+    r= unfoldHDR(line.s,line.len,&subject,charset.s,&prefix,1,FATAL);
+                                                /* trim mime */
+  }
+  else {
+    r = 0;
+    subject.len = 0;
+  }
+  return r;
+}
+
+int main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir,*cp;
+  unsigned long msgnum = 0L;
+  unsigned long msgmax;
+  int opt,r;
+
+  while ((opt = getopt(argc,argv,"dDf:FvV")) != opteof)
+    switch (opt) {
+      case 'd': flagdate = 1; break;
+      case 'D': flagdate = 0; break;
+      case 'f': if (optarg) (void) scan_ulong(optarg,&msgnum); break;
+      case 'F': msgnum = 0L;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-archive version: ",EZIDX_VERSION);
+      default: die_usage();
+  }
+  dir = argv[optind];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(100,FATAL,ERR_SWITCH,dir,": ");
+
+  (void) umask(022);
+  sig_pipeignore();
+                       /* obtain lock to write index files */
+  fdlock = open_append("lock");
+  if (fdlock == -1)
+    strerr_die2sys(100,FATAL,ERR_OPEN_LOCK);
+  if (lock_ex(fdlock) == -1)
+    strerr_die2sys(100,FATAL,ERR_OBTAIN_LOCK);
+
+  getconf_line(&charset,"charset",0,FATAL,dir);
+  if (!stralloc_0(&charset)) die_nomem();
+
+  getconf_line(&prefix,"prefix",0,FATAL,dir);
+                                       /* support rfc2047-encoded prefix */
+  decodeHDR(prefix.s,prefix.len,&line,charset.s,FATAL);
+  unfoldHDR(line.s,line.len,&prefix,charset.s,&dummy,0,FATAL);
+                                       /* need only decoded one */
+
+                       /* Get message number */
+  switch(slurp("num",&num,32)) {
+    case -1:
+      strerr_die4sys(100,FATAL,ERR_READ,dir,"/num: ");
+    case 0:
+      strerr_die4x(100,FATAL,dir,"/num",ERR_NOEXIST);
+  }
+  if (!stralloc_0(&num)) die_nomem();
+  scan_ulong(num.s,&msgmax);
+  if (msgnum > msgmax) _exit(0);
+  if (msgnum) {
+    msgnum = (msgnum / 100) * 100 - 1;
+  }
+  while (++msgnum <= msgmax) {
+    if (msgnum == 1 || !(msgnum % 100)) {
+      if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
+      if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100)))
+       die_nomem();
+      if (!stralloc_copy(&fnifn,&fnadir)) die_nomem();
+      if (!stralloc_copy(&fnif,&fnadir)) die_nomem();
+      if (!stralloc_cats(&fnif,"/index")) die_nomem();
+      if (!stralloc_cats(&fnifn,"/indexn")) die_nomem();
+      if (!stralloc_0(&fnadir)) die_nomem();
+      if (!stralloc_0(&fnifn)) die_nomem();
+      if (!stralloc_0(&fnif)) die_nomem();
+
+                       /* May not exist, so be nice and make it */
+      if (mkdir(fnadir.s,0755) == -1)
+       if (errno != error_exist)
+         strerr_die4sys(100,FATAL,ERR_CREATE,fnadir.s,": ");
+
+                       /* Open index */
+      fdindexn = open_trunc(fnifn.s);
+      if (fdindexn == -1)
+        strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s,": ");
+
+                       /* set up buffers for index */
+      substdio_fdbuf(&ssindex,write,fdindexn,indexbuf,sizeof(indexbuf));
+
+                       /* Get subject without the 'Subject: ' */
+                       /* make sure there is one */
+    }
+
+    if (!stralloc_copys(&fnaf,fnadir.s)) die_nomem();
+    if (!stralloc_cats(&fnaf,"/")) die_nomem();
+    if (!stralloc_catb(&fnaf,strnum,
+       fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem();
+    if (!stralloc_0(&fnaf)) die_nomem();
+    fd = open_read(fnaf.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(100,FATAL,ERR_READ,fnaf.s,": ");
+    } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100)))
+        close(fd);
+    else {
+      subject.len = 0;         /* clear in case they're missing in msg */
+      author.len = 0;
+      received.len = 0;
+      r = idx_get_trimsubject();
+      close(fd);
+      if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem();
+      if (!stralloc_cats(&line,": ")) die_nomem();
+      makehash(subject.s,subject.len,hash);
+      if (!stralloc_catb(&line,hash,HASHLEN)) die_nomem();
+      if (!stralloc_cats(&line," ")) die_nomem();
+      if (r & 1)       /* reply */
+       if (!stralloc_cats(&line,"Re: ")) die_nomem();
+      if (!stralloc_cat(&line,&subject)) die_nomem();
+      if (!stralloc_cats(&line,"\n\t")) die_nomem();
+      if (!stralloc_cat(&line,&received)) die_nomem();
+      if (!stralloc_cats(&line,";")) die_nomem();
+
+      concatHDR(author.s,author.len,&lines,FATAL);
+      mkauthhash(lines.s,lines.len,hash);
+      if (!stralloc_catb(&line,hash,HASHLEN)) die_nomem();
+
+      decodeHDR(cp,author_name(&cp,lines.s,lines.len),&author,charset.s,FATAL);
+      (void) unfoldHDR(author.s,author.len,&lines,charset.s,&prefix,0,FATAL);
+
+      if (!stralloc_cats(&line," ")) die_nomem();
+      if (!stralloc_cat(&line,&lines)) die_nomem();
+      if (!stralloc_cats(&line,"\n")) die_nomem();
+      if (substdio_put(&ssindex,line.s,line.len) == -1)
+          strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s, ": ");
+    }
+
+    if (!((msgnum + 1) % 100) ||
+               (msgnum == msgmax)) {   /* last in this set */
+      if (substdio_flush(&ssindex) == -1)
+        strerr_die4sys(100,FATAL,ERR_FLUSH,fnifn.s, ": ");
+      if (fsync(fdindexn) == -1)
+        strerr_die4sys(100,FATAL,ERR_SYNC,fnifn.s, ": ");
+      if (fchmod(fdindexn,MODE_ARCHIVE | 0700) == -1)
+        strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s, ": ");
+      if (close(fdindexn) == -1)
+        strerr_die4sys(100,FATAL,ERR_CLOSE,fnifn.s,": ");
+      if (rename(fnifn.s,fnif.s) == -1)
+        strerr_die4x(111,FATAL,ERR_MOVE,fnifn.s,": ");
+    }
+  }
+  fd = open_append("indexed");
+  if (fd == -1)
+    strerr_die4sys(100,FATAL,ERR_CREATE,dir,"/indexed: ");
+  close(fd);
+  close(fdlock);
+  _exit(0);
+}
+
diff --git a/ezmlm-issubn.1 b/ezmlm-issubn.1
new file mode 100644 (file)
index 0000000..59affa0
--- /dev/null
@@ -0,0 +1,74 @@
+.TH ezmlm-issubn 1
+.SH NAME
+ezmlm-issubn \- test to see if an address is subscribed to a mailing list
+.SH SYNOPSIS
+.B ezmlm-issubn
+[
+.B \-nN
+]
+.I dir
+.I [ dir1 ... ]
+.SH DESCRIPTION
+.B ezmlm-issubn
+checks to see if the address obtained from the environment variable
+.I SENDER
+is subscribed to the mailing list stored in
+.I dir 
+or the mailing list in
+.I dir1 
+or ...
+
+If
+.I SENDER
+is not defined
+.B ezmlm-issubn
+exits with an error.
+
+If
+.I SENDER
+is on [any of] the mailing list[s],
+.B ezmlm-issubn
+exits with a zero exit code.
+
+If
+.I box\fB@\fIdomain
+is not on the mailing list,
+.B ezmlm-issubn
+exits 99. This exit code is non-success from a shell point of view, but to
+qmail it means "success and skip remaining lines in the .qmail file). Thus,
+a simple way to execute a delivery if the
+.ezmlm-issubn
+criteria are met is to place the
+.B ezmlm-issubn
+line first, followed by the action line. If SENDER is a subscriber, the
+action line is executed, if not, the line is ignored without the generation
+of an error condition. To generate a fatal error, just:
+
+.EX
+|/path/ezmlm-issubn
+.I dir1 ...
+|| (echo "err msg"; exit 100)
+
+|/path/action_for_subscribers
+|/path/more_for_subscribers
+.EE
+
+.B ezmlm-issubn
+exits 100 on permanent and 111 on temporary errors.
+.SH OPTIONS
+.TP
+.B \-n
+Negate exit code. Exit 99 if SENDER is a subscriber and exit 0 if not.
+This is useful when trying to exclude SENDERs.
+.TP
+.B \-N
+(Default.)
+Normal exit codes: 0 is the address is in any of the lists, 99 if not.
+.SH "SEE ALSO"
+ezmlm-list(1),
+ezmlm-manage(1),
+ezmlm-make(1),
+ezmlm-send(1),
+ezmlm-sub(1),
+ezmlm-unsub(1),
+ezmlm(5)
diff --git a/ezmlm-issubn.c b/ezmlm-issubn.c
new file mode 100644 (file)
index 0000000..3440b23
--- /dev/null
@@ -0,0 +1,64 @@
+/*$Id: ezmlm-issubn.c,v 1.13 1999/08/07 20:45:16 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "strerr.h"
+#include "env.h"
+#include "subscribe.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-issubn: fatal: "
+
+void *psql = (void *) 0;
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-issubn: usage: ezmlm-issubn [-nN] dir [dir1 ...]");
+}
+
+void die_sender()
+{
+  strerr_die2x(100,FATAL,ERR_NOSENDER);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  char *addr;
+  int flagsub = 0;
+  int opt;
+
+  addr = env_get("SENDER");
+  if (!addr) die_sender();     /* REQUIRE sender */
+
+  while ((opt = getopt(argc,argv,"nNvV")) != opteof)
+    switch(opt) {
+      case 'n': flagsub = 99; break;
+      case 'N': flagsub = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-issubn version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind];
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  while ((dir = argv[optind++])) {
+    if (dir[0] != '/')
+      strerr_die2x(100,FATAL,ERR_SLASH);
+    if (issub(dir,addr,(char *) 0,FATAL)) {
+      closesql();
+      _exit(flagsub);          /* subscriber */
+    }
+  }
+  closesql();
+  if (flagsub)                 /* not subscriber anywhere */
+    _exit(0);
+  else
+    _exit(99);
+}
diff --git a/ezmlm-limit.1 b/ezmlm-limit.1
new file mode 100644 (file)
index 0000000..e977a10
--- /dev/null
@@ -0,0 +1,127 @@
+.TH ezmlm-limit 1
+.SH NAME
+ezmlm-limit \- Limits traffic to list
+.SH SYNOPSIS
+.B ezmlm-limit
+[
+.B -f\fI file
+][
+.B -dDF
+][
+.B \-t
+.I secs
+][
+.B -n
+.I msgs
+]
+.I dir
+
+.B ezmlm-limit
+is intended to limit traffic to a list in case an outside
+source sends excessive messages. Traffic is limited by converting the list
+to a message moderated list, or by deferring messages.
+
+.B ezmlm-limit
+reads
+.IR dir\fB/loopnum .
+If it does not exist or contains a time stamp more than
+.I secs
+seconds old, it is updated.
+If it exists, contains a time stamp less than
+.I secs
+seconds old, and
+.I msgs
+messages or more have passed since
+.I dir\fB/loopnum
+was created,
+.B ezmlm-limit
+creates
+.IR dir\fB/modpost .
+For lists set up with
+.B ezmlm-store(1)
+this results in future messages being moderated.
+
+As long as
+.I dir\fB/modpost
+does not exist,
+.B ezmlm-store(1)
+will simply forward the message to
+.BR ezmlm-send(1).
+Once
+.I dir\fB/modpost
+exists, messages will be queued for moderation. Thus, in case of error (such
+as misconfigured auto responders) subscribers are spared
+messages in excess of the limit. However, no messages are lost, since the
+moderator(s) can (selectively) approve queued messages. 
+
+If
+.I dir\fB/modpost
+already exists,
+.B ezmlm-limit
+will not take any action.
+
+Resetting the list requires manual
+removal of
+.IR dir\fB/modpost . Queued messages can be managed with regular moderation
+or approved in bulk with
+.BR ezmlm-accept(1) .
+
+.B ezmlm-limit
+is not required for normal lists, since qmail and
+ezmlm loop detection prevent problems caused by regular bounces. However,
+it affords some protection against malice, and severely misconfigured
+subscribers.
+
+.SH OPTIONS
+.TP
+.B \-d
+Defer excess traffic. Excess messages are deferred and qmail will re-deliver. As
+a consequence, traffic will be throttled to the maximum allowed. Due to qmail
+delivery back-off, messages may not be disseminated in the order received. If
+traffic is continuously above or close to the limit, some messages may be
+delayed for a long time or even bounced.
+.TP
+.B \-D
+(Default.)
+Make the list moderated once excess traffic is detected. This requires the
+list to be configured up with
+.B ezmlm-store(1)
+rather than
+.BR ezmlm-send(1) ,
+which is easiest done by first creating a message moderated list, then removing
+.IR dir\fB/modpost .
+.TP
+.B \-n\fI msgs
+Trigger after
+.I msgs
+messages (default 30).
+.TP
+.B \-f\fI file
+Instead of
+.I dir\fB/loopnum
+use
+.I file
+as the time stamp. This allows the use of multiple instances of
+.B ezmlm-limit
+for the same list. For instance, you may allow 60 messages per hour with one
+instance and 150 messages per day with another. If
+.I file
+is relative, this is relative to
+.IR dir .
+.TP
+.B \-F
+(Default.)
+Use
+.I dir\fB/loopnum
+as the time stamp.
+.TP
+.B \-t\fI secs
+Check the number of messages within period of
+.I secs
+seconds (default 3600 seconds).
+.SH "SEE ALSO"
+ezmlm-accept(1),
+ezmlm-make(1),
+ezmlm-send(1),
+ezmlm-store(1),
+ezmlm(5)
diff --git a/ezmlm-limit.c b/ezmlm-limit.c
new file mode 100644 (file)
index 0000000..9e21774
--- /dev/null
@@ -0,0 +1,134 @@
+/*$Id: ezmlm-limit.c,v 1.2 1999/10/31 18:58:48 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include "stralloc.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "sig.h"
+#include "lock.h"
+#include "getconf.h"
+#include "fmt.h"
+#include "now.h"
+#include "sgetopt.h"
+#include "error.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-limit: fatal: "
+#define INFO "ezmlm-limit: info: "
+
+unsigned long deltasecs = LIMSECS;     /* interval to test over (seconds) */
+unsigned long deltanum = LIMMSG;       /* max no messages in interval */
+                                       /* see idx.h. Usually 30 msg/3600 secs*/
+int flagd = 0;                         /* =0 create modpost, =1 ignore */
+                                       /* excess, =2 defer excess */
+int flagmod;                           /* list moderated */
+int flagloop;
+char *fn = TXT_LOOPNUM;
+
+void die_usage()
+{
+  strerr_die1x(100,
+       "ezmlm-limit: usage: ezmlm-limit [-f file] [-dDF] [-n messages]"
+       " [-t secs] dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_new() { strerr_die4sys(111,FATAL,ERR_WRITE,fn,": "); }
+
+stralloc line = {0};
+
+substdio ssnew;
+char newbuf[16];
+
+char strnum[FMT_ULONG];
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  int opt;
+  unsigned int pos;
+  unsigned long num, loopnum, when;
+  unsigned long loopwhen = 0L;
+  unsigned long numwhen = 0L;
+  int fd,fdlock;
+
+  (void) umask(022);
+  sig_pipeignore();
+  when = (unsigned long) now();
+
+  while ((opt = getopt(argc,argv,"dDf:Fn:t:")) != opteof)
+    switch(opt) {
+      case 'd': flagd = 1; break;
+      case 'D': flagd = 0; break;
+      case 'f': if (optarg && *optarg) fn = optarg; break;
+      case 'F': fn = TXT_LOOPNUM;
+      case 'n':
+                if (optarg)
+                  scan_ulong(optarg,&deltanum);
+                break;
+      case 't':
+                if (optarg)
+                  scan_ulong(optarg,&deltasecs);
+                break;
+      default:
+       die_usage();
+  }
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  if (argv[optind])
+    die_usage();       /* avoid common error of putting options after dir */
+  if ((flagmod = getconf_line(&line,"modpost",0,FATAL,dir)))
+    _exit(0);          /* already mod */
+                       /* lock for num and for writing loopnum */
+  fdlock = open_append("lock");
+  if (fdlock == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/lock: ");
+  if (lock_ex(fdlock) == -1)
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/lock: ");
+
+  if (!getconf_line(&line,"num",0,FATAL,dir))
+    _exit(99);                                         /* no msgs */
+  if(!stralloc_0(&line)) die_nomem();
+  pos = scan_ulong(line.s,&num);                       /* current msg */
+  if ((flagloop = getconf_line(&line,fn,0,FATAL,dir))) {
+    if(!stralloc_0(&line)) die_nomem();
+    pos = scan_ulong(line.s,&loopnum);                 /* msg when written */
+    if (line.s[pos] == ':')
+      scan_ulong(line.s+pos+1,&loopwhen);              /* time written */
+  }
+  if (!flagloop || loopwhen + deltasecs < when || loopwhen > when) {
+                                       /* loopnum too old, bad or not there */
+      fd = open_trunc(fn);             /* no need to write crash-proof */
+      if (fd == -1) die_new();
+      substdio_fdbuf(&ssnew,write,fd,newbuf,sizeof(newbuf));
+      if (substdio_put(&ssnew,strnum,fmt_ulong(strnum,num)) == -1) die_new();
+      if (substdio_puts(&ssnew,":") == -1) die_new();
+      if (substdio_put(&ssnew,strnum,fmt_ulong(strnum,when)) == -1) die_new();
+      if (substdio_puts(&ssnew,"\n") == -1) die_new();
+      if (substdio_flush(&ssnew) == -1) die_new();
+      close(fd);
+  } else if (num >= loopnum + deltanum) {      /* excess messages */
+    if (!flagd) {
+      if ((fd = open_append("modpost")) == -1) /* create dir/modpost */
+         strerr_die3sys(111,FATAL,ERR_WRITE,"subpost:");
+      else {
+        close(fd);
+        unlink(fn);
+        strerr_die2x(0,INFO,ERR_EXCESS_MOD);
+      }
+    } else
+        strerr_die2x(111,FATAL,ERR_EXCESS_DEFER);
+  }
+  _exit(0);
+}
index 38e140a..352989a 100644 (file)
@@ -3,6 +3,11 @@
 ezmlm-list \- show the addresses on a mailing list
 .SH SYNOPSIS
 .B ezmlm-list
 ezmlm-list \- show the addresses on a mailing list
 .SH SYNOPSIS
 .B ezmlm-list
+[
+.B \-n\fI msgnum
+] [
+.B \-aAmMnNvV
+]
 .I dir
 .SH DESCRIPTION
 .B ezmlm-list
 .I dir
 .SH DESCRIPTION
 .B ezmlm-list
@@ -16,6 +21,40 @@ the addresses in a mailing list are under the control
 of a possibly malicious remote user.
 .B ezmlm-list
 does not strip control characters.
 of a possibly malicious remote user.
 .B ezmlm-list
 does not strip control characters.
+.SH "GENERAL OPTIONS"
+.TP
+.B \-m
+(Default.)
+Use SQL support if available.
+.TP
+.B \-M
+Do not use SQL support even if available.
+This option can be used to manipulate
+a normal local subscriber database even for lists with SQL support.
+.TP
+.B \-n
+Print only the number of subscribers.
+.TP
+.B \-N
+(Default.)
+List subscriber addresses, one per line.
+.TP
+.B \-v
+Display
+.B ezmlm-list(1)
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-list(1)
+version information.
+.SH "SEE ALSO"
+ezmlm-list(1),
+ezmlm-manage(1),
+ezmlm-make(1),
+ezmlm-send(1),
+ezmlm-sub(1),
+ezmlm(5)
 .SH "SEE ALSO"
 ezmlm-sub(1),
 ezmlm-unsub(1),
 .SH "SEE ALSO"
 ezmlm-sub(1),
 ezmlm-unsub(1),
index c6ec801..644c514 100644 (file)
@@ -1,62 +1,88 @@
-#include "stralloc.h"
-#include "substdio.h"
-#include "getln.h"
+/*$Id: ezmlm-list.c,v 1.15 1999/09/12 20:25:33 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
 #include "strerr.h"
 #include "strerr.h"
-#include "error.h"
 #include "readwrite.h"
 #include "readwrite.h"
+#include "substdio.h"
+#include "subscribe.h"
 #include "exit.h"
 #include "exit.h"
-#include "open.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-list: fatal: "
 
 #define FATAL "ezmlm-list: fatal: "
+
+int flagnumber = 0;    /* default list subscribers, not number of */
+
+void *psql = (void *) 0;
+
+char strnum[FMT_ULONG];
+
 void die_write()
 {
 void die_write()
 {
-  strerr_die2sys(111,FATAL,"unable to write: ");
+  strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: ");
+}
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-list: usage: ezmlm-list [-mMnNvV] dir");
 }
 
 }
 
-char outbuf[1024];
-substdio out = SUBSTDIO_FDBUF(write,1,outbuf,sizeof(outbuf));
-char inbuf[1024];
-substdio in;
+static char outbuf[512];
+static substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,sizeof(outbuf));
 
 
-stralloc line = {0};
+int subwrite(s,l)
+char *s;
+unsigned int l;
+{
+  return substdio_put(&ssout,s,l) | substdio_put(&ssout,"\n",1);
+}
 
 
-char fn[14] = "subscribers/?";
+int dummywrite(s,l)
+char *s;               /* ignored */
+unsigned int l;
+{
+  return (int) l;
+}
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
   char *dir;
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
   char *dir;
-  int fd;
-  int match;
+  int flagmysql = 1;   /* use if supported */
+  unsigned long n;
+  int opt;
 
 
-  dir = argv[1];
-  if (!dir) strerr_die1x(100,"ezmlm-list: usage: ezmlm-list dir");
+  while ((opt = getopt(argc,argv,"mMnNvV")) != opteof)
+    switch(opt) {
+      case 'm': flagmysql = 1; break;
+      case 'M': flagmysql = 0; break;
+      case 'n': flagnumber = 1; break;
+      case 'N': flagnumber = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+       "ezmlm-list version: ezmlml-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
 
 
-  if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+  dir = argv[optind++];
+  if (!dir) die_usage();
 
 
-  for (fn[12] = 64;fn[12] < 64 + 53;++fn[12]) {
-    fd = open_read(fn);
-    if (fd == -1) {
-      if (errno != error_noent)
-       strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
-    }
-    else {
-      substdio_fdbuf(&in,read,fd,inbuf,sizeof(inbuf));
-      for (;;) {
-        if (getln(&in,&line,&match,'\0') == -1)
-         strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
-       if (!match) break;
-       if (line.s[str_chr(line.s,'\n')])
-         strerr_die3x(111,FATAL,"newline in ",fn);
-       if (substdio_puts(&out,line.s + 1)) die_write();
-       if (substdio_put(&out,"\n",1) == -1) die_write();
-      }
-    }
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
 
 
-  }
+  if (dir[0] != '/')
+    strerr_die2x(100,FATAL,ERR_SLASH);
 
 
-  if (substdio_flush(&out) == -1) die_write();
+  if (flagnumber) {
+    n = putsubs(dir,0L,52L,dummywrite,flagmysql,FATAL);
+    if (substdio_put(&ssout,strnum,fmt_ulong(strnum,n)) == -1) die_write(FATAL);
+    if (substdio_put(&ssout,"\n",1) == -1) die_write(FATAL);
+  } else
+    (void) putsubs(dir,0L,52L,subwrite,flagmysql,FATAL);
+  if (substdio_flush(&ssout) == -1) die_write(FATAL);
+  closesql();
   _exit(0);
 }
   _exit(0);
 }
index 834feed..ef898d8 100644 (file)
@@ -4,12 +4,19 @@ ezmlm-make \- create a new mailing list
 .SH SYNOPSIS
 .B ezmlm-make
 [
 .SH SYNOPSIS
 .B ezmlm-make
 [
-.B \-aApP
+.B \-+
+][
+.B \-a..zABD..Z
+][
+.B \-C03..9 arg
 ]
 .I dir
 ]
 .I dir
+[
 .I dot
 .I local
 .I host
 .I dot
 .I local
 .I host
+.I [digestcode]
+]
 .SH DESCRIPTION
 .B ezmlm-make
 sets up a new mailing list,
 .SH DESCRIPTION
 .B ezmlm-make
 sets up a new mailing list,
@@ -20,6 +27,45 @@ All mailing list information is stored in a new directory,
 .IR dir .
 .I dir
 must be an absolute pathname, starting with a slash.
 .IR dir .
 .I dir
 must be an absolute pathname, starting with a slash.
+.I dot
+must be an absolute file name starting with a slash. Arguments other than
+.I dir
+may be omitted when editing an existing list, using the
+.B \-e
+or
+.B \-+
+options (see below).
+
+.B ezmlm-make
+is controlled by a template,
+.BR .ezmlmrc .
+Described here is the behavior with the default template file.
+.B ezmlm-make
+will print a warning message before continuing,
+if the ezmlmrc version does not match the
+.B ezmlm-make
+version.
+
+.B ezmlm-make also creates
+.IR dir\fB/config ,
+where it stores all configuration information. By reading this file, you
+can rapidly get information about how the list is set up.
+.B ezmlm-make
+when used with the
+.B \-e
+switch will read information from this file. Thus, when using
+.B ezmlm-make
+.BR \-e ,
+you only need to specify the desired switches and switch arguments and
+.IR dir .
+With the
+.B \-+
+switch all switches become sticky, i.e. the default for all switches (and
+command line arguments) becomes the switches and arguments active for the
+list to be edited. Note that the choice of config file also is sticky,
+except when running
+.B ezmlm-make
+as root.
 
 .B ezmlm-make
 sets up four
 
 .B ezmlm-make
 sets up four
@@ -38,12 +84,49 @@ these
 .B .qmail
 files.
 
 .B .qmail
 files.
 
+For message moderated lists,
+.B ezmlm-make
+sets up two additional
+.B .qmail
+files:
+.IR dot\fB-accept-default
+and
+.IR dot\fB-reject-default .
+
+For digested lists,
+.B ezmlm-make
+sets up another two
+.B .qmail
+file:
+.IR dot\fB-digest-return-default
+and
+.IR dot\fB-digest-owner .
+
+If
+.I digestcode
+is specified, digest creation by
+.B ezmlm-get(1)
+via trigger messages to the
+.I local\fB/@\fIhost\fB-dig.\fIdigestcode
+address is enabled.
+
+By default,
+.B ezmlm-make
+sets up lists to add a ``X-No-Archive: yes'' header to outgoing messages.
+Public archiving servers will interpret this header as a
+request not to archive messages from
+the list. It this in not what you desire, remove this header from
+.B ezmlmrc
+for global effects, or from
+.I dir\fB/headeradd
+for the specific list.
+
 Typical use of
 .B ezmlm-make
 by a normal user:
 
 .EX
 Typical use of
 .B ezmlm-make
 by a normal user:
 
 .EX
-   ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net
+   ezmlm-make ~joe/SOS ~joe/.qmail-sos joe-sos isp.net
 .EE
 
 Typical use of
 .EE
 
 Typical use of
@@ -54,34 +137,872 @@ by
 .EX
    ezmlm-make ~alias/SOS ~alias/.qmail-sos sos isp.net
 .EE
 .EX
    ezmlm-make ~alias/SOS ~alias/.qmail-sos sos isp.net
 .EE
+.EX
+   chown -R alias ~alias/SOS 
+.EE
+
+Typical use of
+.B ezmlm-make
+by a normal user enabling automatic digests:
+
+.EX
+   ezmlm-make -d ~joe/SOS ~joe/.qmail-sos joe-sos isp.net
+.EE
+
+Typical use of
+.B ezmlm-make
+to change an existing list in ~joe/SOS to a message moderated list with
+remote administration, and enabling the remote administrator(s) to retrieve
+a subscriber list and to edit
+.I dir\fB/text
+files (digest are still enabled):
+
+.EX
+   ezmlm-make -emrldn ~joe/SOS
+.EE
+
+Mail can arrive at any time!
+For safe editing, turn on the sticky bit of the home directory before
+editing the list setup,
+then turn it off again (see
+.BR dot-qmail(5) ).
+
+Moderator addresses are added with
+
+.EX
+  ezmlm-sub ~joe/SOS/mod mod1@host1 mod2@host2 ...
+.EE
+
+.B ezmlm-make
+also creates the necessary text files in
+.IR dir\fB/text/ .
+
+.B ezmlm-make
+has a large number of switches to control all aspects of list generation.
+Only defaults or a small subset of switches are necessary for most list
+setups. Other options are present primarily to allow a external CGI script
+or other graphical user interface to use
+.B ezmlm-make
+to manipulate ezmlm list setups.
+.SH "VIRTUAL DOMAINS"
+For virtual domains,
+.B qmail(5)
+prefixes the name of the controlling user to the LOCAL part of the recipient
+address.
+.B ezmlm(5)
+needs to be informed of this in order to correctly interpret list commands.
+This is done by adjusting
+.IR dir\fB/inlocal .
+This adaptation is necessary only when ezmlm is used with qmail version 1.01
+or earlier.
+
+To create the list ``tl@virtual.dom'' where ``virtual.dom'' is controlled
+by ``vu'' (virtual.dom:vu), change identity to ``vu'' or chown files to
+that user after:
+
+.EX
+       ezmlm-make ~vu/dir ~vu/.qmail-tl tl virtual.dom
+.EE
+
+.EX
+       echo "vu-tl" > ~vu/inlocal
+.EE
+
+Thus, create the list exactly as for a list under ``alias'', but adjust
+.I dir\fB/inlocal
+to the list local name prefixed with the controlling user name.
 .SH OPTIONS
 .SH OPTIONS
+All
+.B ezmlm-make
+letter switches except
+.BR \-v
+and
+.B \-V
+are available for interpretation via
+.IR ezmlmrc .
+Switches
+.BR -e ,
+.BR -E ,
+.BR -c ,
+and
+.BR -C
+have special meaning within the program.
+.I ezmlmrc
+customization should respect the function of the switches described here.
+.TP 5
+.B \-+
+Switches currently active for the list
+will be used, as modified by the current command line.
+Thus,
+.B \-+
+makes switches ``sticky''. By default,
+only switches specified on the current command line will be used.
+This switch implies
+.BR \-e 
+as it is meaningless except in edit mode. Note that the config file choice
+(see
+.B \-c
+and
+.BR \-C )
+is also sticky.
+.B ezmlmrc(5)
+is set up so that most text files (and
+.IR DIR\fB/headeradd ,
+.IR DIR\fB/headerremove )
+are not overwritten if they already exist so as to preserve
+manual customizations. If
+.I local
+is specified
+.B ezmlm-make
+overrides this behavior and all files are rewritten. You can also force
+.B ezmlm-make
+to rewrite all files by using
+.BR \-++ .
 .TP 5
 .B \-a
 .TP 5
 .B \-a
-(Default.) Archived.
+(Default.) Archived and configured with
+.B ezmlm-get(1)
+for archive access.
 .B ezmlm-make
 will touch
 .B ezmlm-make
 will touch
-.IR dir\fB/archived ,
+.I dir\fB/archived
+and
+.I dir\fB/indexed
 so that
 so that
-.B ezmlm-send
+.B ezmlm-send(1)
 will archive new messages.
 .TP
 .B \-A
 Not archived.
 .TP 5
 will archive new messages.
 .TP
 .B \-A
 Not archived.
 .TP 5
+.B \-b
+Block archive. Only moderators are allowed to access the archive.
+.TP 5
+.B \-B
+(Default.)
+Archive access is open to anyone or subscribers only, depending
+on the
+.B \-g
+switch.
+.TP 5
+.B \-c
+Config.
+Use
+.I .ezmlmrc
+(see CONFIGURATION) from the directory where
+.I dot
+resides.
+.B ezmlm-make
+otherwise uses the
+system wide ezmlmrc
+file (normally /etc/ezmlmrc and if not found there, the ezmlmrc file
+in the ezmlm binary directory).
+The
+.B \-c
+switch may cause you to execute
+.B ezmlm-make
+based on a
+configuration file controlled by another user.
+.B ezmlm-make
+does not allow periods in any tag to restrict all actions to within
+.IR dir .
+Be careful with this option setting up lists for other users,
+especially when running
+.B ezmlm-make
+as root.
+.TP 5
+.B \-C\fI arg
+Like
+.BR \-c ,
+but use file
+.I arg
+as the ezmlmrc file.
+Use
+.B \-C\fI ''
+to override a default when using
+.B \-+
+or
+.BR \-e .
+.TP 5
+.B \-d
+Digest.
+.B ezmlm-make
+will set up the
+.I local\fB\-digest@host
+digest list to disseminate digest of the list messages. By default, this
+is done when 30 messages, 48 hours, or 64 kbytes of message body text have
+accumulated since the last digest. Use the
+.B \-4
+switch to override these defaults. See
+.B ezmlm-tstdig(1)
+and
+.B ezmlm-get(1)
+for more info.
+.TP 5
+.B \-D
+(Default.)
+No digest.
+Do not set up the digest list.
+.TP 5
+.B \-e
+Edit.
+.B ezmlm-make
+will remove links before creating them and accept
+if directories to be created are already present.
+.b ezmlm-make
+will also (via entries in
+.IR ezmlmrc )
+remove flags that are present but not desired for the current list.
+Thus, this option can be used to reconfigure existing lists without affecting
+moderator and subscriber lists or message archive. All desired
+.B ezmlm-make
+switches
+need to be specified. To make all switches sticky, i.e. only specify the
+ones changed from the previous setup, use
+.BR \-+ .
+Command line arguments other
+than
+.I dir
+can be omitted.
+In the unlikely case where
+.I dot
+is changed, you must manually remove the old links.
+Mail can arrive at any time!
+For safe editing, turn on the sticky bit of the home directory before
+using the edit function,
+then turn it off again (see
+.BR dot-qmail(5) ).
+.B ezmlmrc(5)
+is set up so that most text files (and
+.IR DIR\fB/headeradd ,
+.IR DIR\fB/headerremove )
+are not overwritten if they already exist so as to preserve
+manual customizations. If
+.I local
+is specified
+.B ezmlm-make
+overrides this behavior and all files are rewritten. You can also force
+.B ezmlm-make
+to rewrite all files by using
+.BR \-ee .
+.TP 5
+.B \-E
+(Default.)
+No edit.
+.B ezmlm-make
+will abort if directories or links to be created already exist. This prevents
+accidental reconfiguration of a pre-existing list, since the first action
+is to create the list directory.
+.TP 5
+.B \-f
+Prefix.
+.B ezmlm-make
+will set up the list so that the outgoing subject will be prefixed
+with the list name.
+.TP 5
+.B \-F
+(Default.)
+No prefix.
+.TP 5
+.B \-g
+Guard archive.
+Archive access requests from unrecognized SENDERs will be rejected.
+This restriction is safe, since replies are sent to the SENDER address.
+.TP 5
+.B \-G
+(Default.)
+Do not guard archive.
+Archive access request from any SENDER will be serviced.
+.TP 5
+.B \-h
+Help subscription. Subscriptions do not require confirmation. Strongly
+recommended against, since anyone can subscribe any address,
+but may be useful for some subscription moderated lists.
+.TP 5
+.B \-H
+(Default.)
+Subscription requires confirmation by reply to a message sent to the
+subscription address.
+.TP 5
+.B \-i
+Indexed for WWW archive access.
+.B ezmlm-make
+will create the list so that
+.B ezmlm-archive(1)
+is invoked to maintain an index suitable for use by
+.BR ezmlm-cgi(1) .
+.TP 5
+.B \-I
+(Default.)
+The list is created without
+.BR ezmlm-archive(1) .
+.TP 5
+.B \-j
+Jump off. Unsubscribe does not require confirmation. Strongly recommended
+against, since anyone can unsubscribe any address, but may be useful
+in some situations.
+.TP 5
+.B \-J
+(Default.)
+Unsubscribe requires confirmation by a reply to a message sent to the
+subscription address.
+.TP 5
+.B \-k
+kill.
+.B ezmlm-make
+sets up
+.IR dir\fB/deny/ .
+It sets up the list so that posts from addresses in
+.I dir\fB/deny/
+are rejected. This is useful in combination with the
+.B \-u
+switch to temporarily restrain offenders, such as misconfigured auto-responders
+or automatic spammers.
+It can also be used in combination with
+.B \-m
+to filter out SENDERs from whom the moderators do not want to see
+posts (again, bad
+re-mailers and spammers come to mind).
+
+To add/remove blacklisted addresses:
+
+.EX
+.B ezmlm-sub \fIdir\fB/deny \fIbad@host
+.EE
+
+.EX
+.B ezmlm-unsub \fIdir\fB/deny \fIbad@host
+.EE
+
+.TP 5
+.B \-K
+(Default.)
+Not kill.
+.I dir\fB/deny/
+is not created, and even if it exists, the contents will be ignored.
+.TP 5
+.B \-l
+List subscribers.
+.B ezmlm-make
+sets up the list so that remote administrators can request a subscriber list,
+and search the subscriber log.
+.TP 5
+.B \-L
+(Default.)
+The subscriber list cannot be obtained.
+.TP 5
+.B \-m
+Message moderation. (Please note that the 
+.B \-u switch modifies
+the action of this switch.)
+.B ezmlm-make
+will touch
+.I dir\fB/modpost
+and create
+.I dir\fB/mod/
+and
+.IR dir\fB/mod/subscribers/ ,
+where the moderator addresses are stored.
+.B ezmlm-make
+also creates
+.IR dir\fB/mod/pending/ ,
+.IR dir\fB/mod/accepted/ ,
+and
+.IR dir\fB/mod/rejected/ .
+These directories are used to queue messages awaiting moderation.
+.I dir\fB/editor
+will be set up to run
+.B ezmlm-store(1)
+to store incoming messages in the moderation queue and send moderation
+requests to the moderators.
+.I dir\fB/moderator
+will be set up to run
+.B ezmlm-moderate
+to process moderator
+.I accept
+or
+.I reject
+requests.
+
+To add/remove moderators:
+
+.EX
+.B ezmlm-sub \fIdir\fB/mod \fImoderator@host
+.EE
+
+.EX
+.B ezmlm-unsub \fIdir\fB/mod \fImoderator@host
+.EE
+
+.TP 5
+.B \-M
+(Default.)
+Message posting is not moderated.
+.TP 5
+.B \-n
+New text file.
+.B ezmlm-make
+sets up the list to allow remote administrators to edit files in
+.IR dir\fB/text/ .
+.TP 5
+.B \-N
+(Default.)
+Not new text file.
+Text file editing not allowed.
+.TP 5
+.B \-o
+Others rejected.
+Posts from addresses other than moderators are rejected. This is
+applicable to message moderated lists only
+(see
+.BR \-m ).
+The switch has no effect on other lists.
+.TP 5
+.B \-O
+(Default.)
+Others not rejected.
+For moderated lists, all posts are forwarded to the moderators.
+The switch has effects only on message moderated lists.
+.TP 5
 .B \-p
 (Default.) Public.
 .B ezmlm-make
 will touch
 .IR dir\fB/public ,
 so that
 .B \-p
 (Default.) Public.
 .B ezmlm-make
 will touch
 .IR dir\fB/public ,
 so that
-.B ezmlm-manage
-will respond to administrative requests.
+.B ezmlm-manage(1)
+will respond to administrative requests and
+.B ezmlm-get
+will allow archive retrieval.
 .TP
 .B \-P
 Private.
 .TP
 .B \-P
 Private.
+.B ezmlm-manage(1)
+and
+.B ezmlm-get(1)
+will allow only digest creation, remote administration, and archive
+retrieval by remote administrators, (if the list is configured with these
+options).
+.TP
+.B \-q
+ReQuest address is serviced.
+.B ezmlm-make
+will configure the list to process commands sent in the subject to
+.IR local\fB-request@\fIhost .
+This is done by adding a
+.B ezmlm-request(1)
+line to
+.IR dir\fB/manager .
+.TP
+.B \-Q
+(Default.)
+Do not process messages sent to the ``request'' address.
+.TP
+.B \-r
+Remote admin.
+.B ezmlm-make
+enables remote administration by touching
+.IR dir\fB/remote .
+Moderator(s) can unsubscribe and subscribe
+any address.
+See the
+.B \-m
+option on how moderator addresses are stored and manipulated.
+.TP
+.B \-R
+(Default.) No remote administration.
+.TP
+.B \-s
+Subscription moderation.
+.B ezmlm-make
+enables subscription moderation by touching
+.IR dir\fB/modsub .
+This affects subscriptions for both the main list and the digest list.
+See the
+.B \-m
+option on how moderator addresses are stored and manipulated.
+.TP
+.B \-S
+(Default.) Subscriptions are not moderated.
+.TP 5
+.B \-t
+Trailer.
+.B ezmlm-make
+will create
+.I dir\fB/text/trailer
+to set up the list to add a trailer to outgoing messages.
+.TP 5
+.B \-T
+No trailer.
+(Default.)
+.TP 5
+.B \-u
+User posts only.
+.B ezmlm-make
+sets up the list
+so that posts and archive access is restricted to subscribers.
+These are addresses subscribed to the main list, the digest, or added
+manually to the address database in
+.I dir\fB/allow/
+which accommodates addresses from e.g. subscribers working from an address
+other than their subscriber address.
+
+Posts from unrecognized SENDER addresses will be rejected.
+This is relatively easily defeated for posts.
+More secure alternatives are message moderated lists configured with the
+.B ezmlm-make \-m
+switch (without the
+.B \-u
+switch).
+
+There is no reason to combine of SENDER checks on posts with message
+moderation. Therefore, the combination of the
+.B \-u
+switch with the
+.B \-m
+switch is used for a configuration with SENDER restrictions (like with
+.B \-u
+alone), with the difference that posts from non-subscribers will be sent for
+moderation instead of being rejected. This allows the list admin to let
+non-subscribers post occasionally, as well as to catch subscribers posting
+from non-subscriber addresses.
+.TP
+.B \-U
+(Default.)
+Do not restrict posts based on SENDER address.
+.TP 5
+.B \-v
+Display
+.B ezmlm-make
+version information.
+.TP 5
+.B \-V
+Display
+.B ezmlm-make
+version information.
+.TP 5
+.B \-w
+Remove the
+.B ezmlm-warn(1)
+invocations from the list setup. It is assumed that
+.B ezmlm-warn(1)
+for both
+.I local@host
+and
+.I local\fB-digest@\fIhost
+will be run by other means, such as crond.
+If the list is set up with SQL support (see
+.BR \-6 ),
+restrict the list to a subset of addresses by adding the list name to
+the
+.I dir\fB/sql ,
+.I dir\fB/allow/sql ,
+.I dir\fB/digest/sql ,
+configuration files. Useful only when setting up the main list
+for a large distributed list supported by a SQL address database.
+Also, bounces will be handled by
+.B ezmlm-receipt(1)
+rather than
+.BR ezmlm-return(1) .
+As the main list will have only sublists as subscribers, it is desirable
+to log bounces and feedback messages rather than to remove a bouncing
+subscriber.
+.TP 5
+.B \-W
+(Default.)
+No address restriction. Normal
+use of
+.B ezmlm-warn(1)
+and
+.BR ezmlm-return(1) .
+.TP 5
+.B \-x
+eXtra.
+.B ezmlm-make
+will configure the list with a few extras:
+.I dir\fB/mimeremove
+will be configured to strip annoying mime parts such as excel spreadsheets,
+rtf text, html text etc from the messages. Messages consisting solely of
+this Content-type will be rejected. See
+.B ezmlm-send(1)
+and
+.B ezmlm-reject(1)
+for more info.
+.TP 5
+.B \-0 \fImainlist@host
+Make the list a sublist of list
+.IR mainlist@host .
+.TP 5
+.B \-3 \fIfromarg
+.B ezmlm-make
+sets up the list to replace the ``From:'' header of the message with
+``From:
+.IR fromarg ''.
+.TP 5
+.B \-4 \fItstdigopts
+.B ezmlm-make
+replaces the
+.B ezmlm-tstdig(1)
+switches used for digest generation with the text in
+.IR tstdigopts .
+This is part of a command line, NOT a specific switch. It should normally
+be placed within single quotes. This switch is mainly for programmatic
+use. For changing list defaults, it is usually easier to create a custom
+.I ~/.ezmlmrc
+file and edit it. The default is '-t24 -m30 -k64'. (See
+.B ezmlm-tstdig(1)
+for more info.)
+.TP
+.B \-5 \fIowner@host
+.B ezmlm-make
+will configure the list to forward mail directed to the list owner to
+.IR owner@host .
+.TP
+.B \-6\fI\ host:port:user:password:datab:table
+SQL connect info. Use the sql
+.IR host
+(default localhost),
+connecting to
+.I port
+(default port for SQL server) as
+.I user
+with
+.I password
+using database
+.I datab
+(default ezmlm)
+and the table root name
+.I table
+(default ezmlm)
+This will have no effect unless the ezmlm programs
+are compiled with SQL support.
+.TP
+.B \-7 \fI/msg_mod_path
+Make
+.I /path
+the path to the database for message moderators, if the list is set up for
+message moderation.
+.I /msg_mod_path
+must be an absolute pathname, starting with a slash. If not, it will be ignored.
+.TP
+.B \-8 \fI/sub_mod_path
+Make
+.I /sub_mod_path
+the path to the database for subscription moderators, if the list is set up for
+subscription moderation.
+.I /sub_mod_path
+must be an absolute pathname, starting with a slash. If not, it will be ignored.
+.TP
+.B \-9 \fI/rem_adm_path
+Make
+.I /path
+the path to the database for remote administrators, if the list is set up for
+remote administration.
+.I /rem_adm_path
+must be an absolute pathname, starting with a slash. If not, it will be ignored.
+.SH "LIST EDITING"
+When
+.B ezmlm-make
+is used with the
+.B \-e
+switch, and the list was previously created or edited with a
+new (ezmlm-idx >= 0.23) version of
+.BR ezmlm-make ,
+all arguments other than
+.I dir
+can be omitted. In this case, arguments will be read from
+.IR dir\fB/config .
+The appropriate flags must always be specified. To override
+.IR dot ,
+.IR local ,
+.IR host ,
+or
+.IR code ,
+all arguments must be specified.
+.SH CONFIGURATION
+This version of
+.B ezmlm-make
+is template driven. The template file consists of plain text with four types
+of tags. Both start in
+the first position of the line.
+No other text is allowed on the same line. For
+security reasons, no periods are allowed anywhere in a tag.
+Any line with a ``#'' in position 1 is ignored,
+as is any text preceding the first tag.
+.TP
+.B </filename#aI/>
+The following text will be copied to
+.IR dir\fB/filename
+if the options specified after the ``#'' are active, in this case
+.I archived
+and not
+.IR indexed .
+Any number of flags can be specified. This
+is used to adapt the files and
+messages to the type of list created. If no flags are
+used, the ``#'' can be omitted. If the file name is the same as the previous
+tag, or if it is omitted, the text will be added to the previous file.
+When a new file is opened the previous file is closed. Attempts to add
+more text to a already closed file overwrites its contents.
+
+An alternative to specify that a flag, e.g. ``4'' should not be active is
+to prefix the switch with ``^'', e.g. use ``^4''.
+The ``E'' flag is treated in a special manner. When the list
+is being edited, it evaluates to false if the file already exists,
+true if it does not. Thus, files using this condition are not overwritten
+when editing. This is useful for files that you frequently customize manually.
+.TP
+.B </-filename#eA/>
+.IR dir\fB/filename
+will be erased, if the options after the ``#'' are active, in this case
+.I not archived
+and
+.IR edit .
+.TP
+.B </+directory#aI/>
+The directory ``directory'' is created if the flags specified are active, in
+this case
+.I archived
+and not
+.IR indexed .
+If no flags are specified, the ``#'' can be
+omitted.
+.TP
+.B </:link/directory#aI/>
+.B dot\fI\-link
+is symlinked to
+.I dir/directory
+if the flags specified are active, in
+this case
+.I archived
+and not
+.IR indexed .
+If no flags are specified, the ``#'' can be
+omitted.
+.PP
+In addition,
+.I local
+is substituted for
+.BR <#L#> ,
+the part of
+.I dot
+between the first 2 hyphens (if any) for
+.BR <#1#> ,
+the part of
+.I dot
+between the second and third hyphen (if any) for
+.BR <#2#> ,
+.I host
+for
+.BR <#H#> ,
+.I dir
+for
+.BR <#D#> ,
+.I dot
+for
+.BR <#T#> ,
+.I digestcode
+for
+.BR <#C#> ,
+the set of all active flags for
+.BR <#F#> ,
+the config file used for
+.BR <#X#> ,
+and the path to the
+.B ezmlm
+binaries for
+.BR <#B#>
+anywhere in the text. Other tags of this format are copied to the files as is.
+
+.BR <#l#> ,
+.BR <#h#> ,
+.BR <#n#> ,
+.BR <#A#> ,
+.BR <#R#> ,
+will be substituted on-the-fly where appropriate for the
+.IR local
+or
+.IR local\fB\-digest
+local part of the list address, the
+.IR host ,
+the subscriber address or the moderation accept address,
+the message number, 
+and the subscription reply address or moderation reject address, respectively.
+The use of
+.BR <#l#>
+is to allow the same text file to be used for requests pertaining to both
+the main list and the digest list.
+.BR <#h#>
+makes it possible to share some files between lists.
+.BR <#n#>
+is defined only by programs where this makes sense, i.e.
+.B ezmlm-send(1)
+and
+.B ezmlm-get(1)
+
+In the absence of
+.B \-e
+and
+.B \-+
+switches,
+.B ezmlm-make
+will create the list directory before processing the template file, and
+create
+.I dir\fB/key
+after all other actions.
+
+.B ezmlm-make
+will use
+.B /etc/ezmlmrc
+and if not found
+.B ezmlmrc
+in the ezmlm binary directory. This can be overridden with the
+.B \-c
+and
+.B \-C
+switches.
+.SH BUGS
+.B ezmlm-make
+deals with the template file as us-ascii.
+Any occurrence of
+the characters ``</'' at the beginning of a line will disrupt
+.B ezmlm-make
+operation.
+Any occurrence of tags with the format ``<#X#>'' with 
+with 'X' being any digit, 'B', 'C', 'D', 'F', 'H', 'L', or 'T'
+will be substituted by
+.BR ezmlm-make .
+Any occurrence of a tag of this format with 'X' being 'h', 'l', 'A',
+or 'R' will be
+substituted by
+.B ezmlm-store
+and
+.B ezmlm-manage
+at run time.
+.B ezmlm-send
+will substitute tags with 'h' and 'l', and tags with 'n' will be replaced
+by the current message number.
+.B ezmlm-get
+will substitute tags ``<#h#>'', ``<#l#>'' in the same way. The
+tag ``<#n#>'' will be replaced by the digest message number which is the
+number of the first message in the digest.
+
+In practice, these character sequences are unlikely to occur in any
+multi-byte character set text. They also will not occur by chance
+in
+single-byte character sets where '<', '/', and '#'
+retain their us-ascii codes.
+.SH BUGS
+.B ezmlm-make
+cannot deal with ezmlmrc lines containing NUL (they will be truncated
+at the NUL). This needs to be fixed to make it 8-bit clean.
 .SH "SEE ALSO"
 .SH "SEE ALSO"
+ezmlm-clean(1),
+ezmlm-get(1),
 ezmlm-manage(1),
 ezmlm-manage(1),
+ezmlm-moderate(1),
 ezmlm-send(1),
 ezmlm-send(1),
+ezmlm-store(1),
 ezmlm-sub(1),
 ezmlm-unsub(1),
 ezmlm(5)
 ezmlm-sub(1),
 ezmlm-unsub(1),
 ezmlm(5)
index 09d2b3e..11fc6f4 100644 (file)
@@ -1,3 +1,6 @@
+/*Id: ezmlm-make.c,v 1.31 1997/12/08 23:44:02 lindberg Exp lindberg $*/
+/*$Name: ezmlm-idx-040 $*/
+
 #include <sys/types.h>
 #include <sys/time.h>
 #include "sgetopt.h"
 #include <sys/types.h>
 #include <sys/time.h>
 #include "sgetopt.h"
 #include "substdio.h"
 #include "str.h"
 #include "auto_bin.h"
 #include "substdio.h"
 #include "str.h"
 #include "auto_bin.h"
+#include "getln.h"
+#include "error.h"
+#include "lock.h"
+#include "errtxt.h"
+#include "idx.h"
+
+                       /* defaults. All other flags are false = 0 */
+char  *defflags="ap";          /* archived list -a */
+                               /* public list -p */
+                               /* no ezmlm-archive -I */
+                               /* no text edit for remote admin -D */
+                               /* not in edit mode -E */
+                               /* no subs list for remote admin -L */
+                               /* no remote admin -R */
+                               /* no message moderation -M */
+                               /* no subscription moderation -S */
+                               /* don't use .ezmlmrc from dot-file dir -C */
+                               /* no prefix -F */
+                               /* no trailer -T */
+
+#define NO_FLAGS ('z' - 'a' + 1)
+int flags[NO_FLAGS];           /* holds flags */
+
+char *popt[10];
+stralloc dotplus = {0};
+stralloc dirplus = {0};
+stralloc line = {0};
 
 #define FATAL "ezmlm-make: fatal: "
 
 #define FATAL "ezmlm-make: fatal: "
+#define WARNING "ezmlm-make: warning: "
 
 void die_usage()
 {
 
 void die_usage()
 {
-  strerr_die1x(100,"ezmlm-make: usage: ezmlm-make [ -aApP ] dir dot local host");
+ strerr_die1x(100,
+  "ezmlm-make: usage: ezmlm-make [-+] [ -a..zA..Z03..9 ] dir dot local host");
 }
 void die_relative()
 {
 }
 void die_relative()
 {
-  strerr_die2x(100,FATAL,"dir must start with slash");
+  strerr_die2x(100,FATAL,ERR_SLASH);
 }
 void die_newline()
 {
 }
 void die_newline()
 {
-  strerr_die2x(100,FATAL,"newlines not allowed");
+  strerr_die2x(100,FATAL,ERR_NEWLINE);
 }
 void die_quote()
 {
 }
 void die_quote()
 {
-  strerr_die2x(100,FATAL,"quotes not allowed");
+  strerr_die2x(100,FATAL,ERR_QUOTE);
 }
 void die_nomem()
 {
 }
 void die_nomem()
 {
-  strerr_die2x(111,FATAL,"out of memory");
+  strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
+void die_read()
+{
+  strerr_die4sys(111,FATAL,ERR_READ,dirplus.s,": ");
 }
 
 }
 
+stralloc cmdline = {0};
+stralloc outline = {0};
+substdio sstext;
+char textbuf[1024];
+
+stralloc fname = {0};          /* file name */
+stralloc oldfname = {0};       /* file name from prevoius tag */
+stralloc dname = {0};          /* directory name */
+stralloc lname = {0};          /* link name */
+stralloc template = {0};       /* template file name */
+stralloc ext1 = {0};           /* dot = dir/.qmail-ext1-ext2-list */
+stralloc ext2 = {0};
+stralloc f = {0};
 stralloc key = {0};
 struct timeval tv;
 stralloc key = {0};
 struct timeval tv;
+char sz[2] = "?";
 
 void keyadd(u)
 unsigned long u;
 {
   char ch;
 
 void keyadd(u)
 unsigned long u;
 {
   char ch;
-  ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
-  ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
-  ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
-  ch = u; if (!stralloc_append(&key,&ch)) die_nomem();
+  ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+  ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+  ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8;
+  ch = (char) u; if (!stralloc_append(&key,&ch)) die_nomem();
 }
 
 void keyaddtime()
 }
 
 void keyaddtime()
@@ -54,11 +105,8 @@ void keyaddtime()
 
 char *dir;
 char *dot;
 
 char *dir;
 char *dot;
-char *local;
-char *host;
-
-stralloc dotplus = {0};
-stralloc dirplus = {0};
+char *local = (char *) 0;
+char *host = (char *) 0;
 
 void dirplusmake(slash)
 char *slash;
 
 void dirplusmake(slash)
 char *slash;
@@ -76,8 +124,12 @@ char *slash;
   if (!stralloc_cats(&dotplus,dash)) die_nomem();
   if (!stralloc_0(&dotplus)) die_nomem();
   dirplusmake(slash);
   if (!stralloc_cats(&dotplus,dash)) die_nomem();
   if (!stralloc_0(&dotplus)) die_nomem();
   dirplusmake(slash);
+  if (flags['e' - 'a'])
+    if (unlink(dotplus.s) == -1)
+      if (errno != error_noent)
+        strerr_die4x(111,FATAL,ERR_DELETE,dotplus.s,": ");
   if (symlink(dirplus.s,dotplus.s) == -1)
   if (symlink(dirplus.s,dotplus.s) == -1)
-    strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_CREATE,dotplus.s,": ");
   keyaddtime();
 }
 
   keyaddtime();
 }
 
@@ -86,14 +138,15 @@ char *slash;
 {
   dirplusmake(slash);
   if (mkdir(dirplus.s,0755) == -1)
 {
   dirplusmake(slash);
   if (mkdir(dirplus.s,0755) == -1)
-    strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": ");
+    if ((errno != error_exist) || !flags['e' - 'a'])
+      strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": ");
   keyaddtime();
 }
 
 substdio ss;
 char ssbuf[SUBSTDIO_OUTSIZE];
 
   keyaddtime();
 }
 
 substdio ss;
 char ssbuf[SUBSTDIO_OUTSIZE];
 
-void fopen(slash)
+void f_open(slash)
 char *slash;
 {
   int fd;
 char *slash;
 {
   int fd;
@@ -101,335 +154,508 @@ char *slash;
   dirplusmake(slash);
   fd = open_trunc(dirplus.s);
   if (fd == -1)
   dirplusmake(slash);
   fd = open_trunc(dirplus.s);
   if (fd == -1)
-    strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_CREATE,dirplus.s,": ");
 
   substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf));
 }
 
 
   substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf));
 }
 
-void fput(buf,len)
+void f_put(buf,len)
 char *buf;
 unsigned int len;
 {
   if (substdio_bput(&ss,buf,len) == -1)
 char *buf;
 unsigned int len;
 {
   if (substdio_bput(&ss,buf,len) == -1)
-    strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": ");
 }
 }
-void fputs(buf)
+void f_puts(buf)
 char *buf;
 {
   if (substdio_bputs(&ss,buf) == -1)
 char *buf;
 {
   if (substdio_bputs(&ss,buf) == -1)
-    strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_WRITE,dirplus.s,": ");
 }
 
 }
 
-void fclose()
+void f_close()
 {
   if (substdio_flush(&ss) == -1)
 {
   if (substdio_flush(&ss) == -1)
-    strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_FLUSH,dirplus.s,": ");
   if (fsync(ss.fd) == -1)
   if (fsync(ss.fd) == -1)
-    strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_SYNC,dirplus.s,": ");
   if (close(ss.fd) == -1) /* NFS stupidity */
   if (close(ss.fd) == -1) /* NFS stupidity */
-    strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+    strerr_die4sys(111,FATAL,ERR_CLOSE,dirplus.s,": ");
   keyaddtime();
 }
 
   keyaddtime();
 }
 
+void frm(slash)
+char *slash;
+{
+  dirplusmake(slash);
+  if (unlink(dirplus.s) == -1)
+    if (errno != error_noent)
+    strerr_die4sys(111,FATAL,ERR_DELETE,dirplus.s,": ");
+}
+
+
 void main(argc,argv)
 int argc;
 char **argv;
 {
 void main(argc,argv)
 int argc;
 char **argv;
 {
+  unsigned long euid;
   int opt;
   int opt;
-  int flagarchived;
-  int flagpublic;
+  int flagdo;
+  int flagnot;
+  int flagover;
+  int flagnotexist;
+  int flagforce = 0;
+  int flagforce_p = 0;
+  int usecfg = 0;
+  int match;
+  unsigned int next,i,j;
+  int last;
+  unsigned int slpos,hashpos,pos;
+  int fdin,fdlock,fdtmp;
+  char *p;
+  char *oldflags = (char *) 0;
+  char *code = (char *) 0;
+  char *cfname = (char *) 0;           /* config file if spec as -C cf_file */
+  char ch;
 
 
-  keyadd(getpid());
-  keyadd(getppid());
-  keyadd(getuid());
-  keyadd(getgid());
+  keyadd((unsigned long) getpid());
+  keyadd((unsigned long) getppid());
+  euid = (unsigned long) geteuid();
+  keyadd(euid);
+  keyadd((unsigned long) getgid());
   gettimeofday(&tv,(struct timezone *) 0);
   keyadd(tv.tv_sec);
 
   gettimeofday(&tv,(struct timezone *) 0);
   keyadd(tv.tv_sec);
 
-  umask(077);
-
-  flagarchived = 1;
-  flagpublic = 1;
+  (void) umask(077);
+       /* flags with defined use. vV for version. Others free */
 
 
-  while ((opt = getopt(argc,argv,"aApP")) != opteof)
-    switch(opt) {
-      case 'a': flagarchived = 1; break;
-      case 'A': flagarchived = 0; break;
-      case 'p': flagpublic = 1; break;
-      case 'P': flagpublic = 0; break;
-      default:
-       die_usage();
-    }
+  for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) {
+    flags[pos] = 0;
+  }
+  for (pos = 0; pos < 10; popt[pos++] = (char *) 0);
+
+  while ((opt = getopt(argc,argv,
+   "+aAbBcC:dDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0:3:4:5:6:7:8:9:"))
+           != opteof) {
+    if (opt == 'v' || opt == 'V')
+      strerr_die2x(0,"ezmlm-make version: ezmlm-0.53+",EZIDX_VERSION);
+    if (opt =='C')     /* treat this like nl switch to allow override of -c*/
+      cfname = optarg;
+    if (opt >= 'a' && opt <= 'z') {
+      flags[opt - 'a'] = 3;            /* Dominant "set" */
+      if (opt == 'e') flagforce++;     /* two 'e' => ignore 'E' */
+    } else if (opt >= 'A' && opt <= 'Z')
+      flags[opt - 'A'] = 2;            /* Dominant "unset" */
+    else if (opt >= '0' && opt <= '9')
+      popt[opt-'0'] = optarg;
+    else if (opt == '+') {
+      flagforce_p++;           /* two '+' => ignore 'E' */
+      flags['e' - 'a'] = 3;    /* -+ implies -e */
+      usecfg = 1;
+    } else
+      die_usage();
+  }
   argv += optind;
 
   argv += optind;
 
-  if (!(dir = *argv++)) die_usage();
-  if (!(dot = *argv++)) die_usage();
-  if (!(local = *argv++)) die_usage();
-  if (!(host = *argv++)) die_usage();
+  if (flagforce_p > 1 || flagforce > 1)
+    flagforce = 1;
+  else
+    flagforce = 0;
 
 
+  if (!(dir = *argv++)) die_usage();
   if (dir[0] != '/') die_relative();
   if (dir[str_chr(dir,'\'')]) die_quote();
   if (dir[str_chr(dir,'\n')]) die_newline();
   if (dir[0] != '/') die_relative();
   if (dir[str_chr(dir,'\'')]) die_quote();
   if (dir[str_chr(dir,'\n')]) die_newline();
-  if (local[str_chr(local,'\n')]) die_newline();
-  if (host[str_chr(host,'\n')]) die_newline();
 
 
-  dcreate("");
-  dcreate("/archive");
-  dcreate("/subscribers");
-  dcreate("/bounce");
-  dcreate("/text");
+  if (flags['e' - 'a'] & 1) {  /* lock for edit */
+    dirplusmake("/lock");
+    fdlock = open_append(dirplus.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,FATAL,ERR_OPEN,dirplus.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,FATAL,ERR_OBTAIN,dirplus.s,": ");
+
+                               /* for edit, try to get args from dir/config */
+    dirplusmake("/config");
+    if ((fdin = open_read(dirplus.s)) == -1) {
+      if (errno != error_noent) die_read();
+    } else {
+      substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf));
+      for (;;) {
+       if (getln(&sstext,&line,&match,'\n') == -1) die_read();
+       if (!match) break;
+       if (line.s[0] == '#') continue;
+       if (line.len == 1) break;
+       if (line.s[1] != ':') break;
+       line.s[line.len - 1] = '\0';
+             if (!stralloc_cat(&cmdline,&line)) die_nomem();
+      }
+      close(fdin);
+      pos = 0;
+      while (pos < cmdline.len) {
+       ch = cmdline.s[pos];
+       pos += 2;
+       switch (ch) {
+         case 'X': if (euid && !flags['c' - 'a'] && (!cfname))
+                       cfname = cmdline.s + pos;       /* cmdline overrides */
+                   break;      /* for safety: ignore if root */
+          case 'T': dot = cmdline.s + pos; break;
+          case 'L': local = cmdline.s + pos; break;
+          case 'H': host = cmdline.s + pos; break;
+          case 'C': code = cmdline.s + pos; break;
+          case 'D': break;     /* no reason to check */
+          case 'F': oldflags = cmdline.s + pos; break;
+          default:
+                 if (ch == '0' || (ch >= '3' && ch <= '9')) {
+                   if (usecfg && !popt[ch - '0'])
+                     popt[ch - '0'] = cmdline.s + pos;
+                 } else
+                   strerr_die4x(111,FATAL,dirplus.s,ERR_SYNTAX,
+                        cmdline.s+pos);
+                 break;
+        }
+        pos += str_len(cmdline.s + pos) + 1;
+      }
+    }
+  }
 
 
+  if (p = *argv++) {
+    dot = p;
+    if (p = *argv++) {
+      if (!local || str_diff(local,p))
+       flagforce = 1;          /* must rewrite if list name changed */
+      local = p;
+      if (p = *argv++) {
+       if (!host || str_diff(host,p))
+         flagforce = 1;        /* must rewrite if list name changed */
+        host = p;
+        if (p = *argv++) {
+          code = p;
+        }
+      }
+    }
+  }
+  if (!dot || !local || !host) die_usage();
+  if (dot[0] != '/') die_relative();           /* force absolute dot */
+
+                       /* use flags from config, overridden with new values */
+                       /* if there are old flags, we're in "edit" and "-+" */
+                       /* Previous versions only wrote _set_ flags to */
+                       /* to DIR/confiag. We need to make sure that we */
+                       /* don't apply the defaults for non-specified ones! */
+  if (usecfg && oldflags && flags['e' - 'a']) {
+    while ((ch = *(oldflags++))) {
+      if (ch >= 'a' && ch <= 'z') {            /* unset flags ignored */
+        if (ch != 'e')
+          if (!flags[ch - 'a'])                        /* cmd line overrides */
+           flags[ch - 'a'] = 1;
+      }
+    }
+  }
 
 
-  linkdotdir("-owner","/owner");
-  linkdotdir("-default","/manager");
-  linkdotdir("-return-default","/bouncer");
-  linkdotdir("","/editor");
+  if (!usecfg) {                               /* apply defaults */
+    while (( ch = *(defflags++))) {            /* gets used up! */
+      if (ch >= 'a' && ch <= 'z') {            /* defensive! */
+       if (!flags[ch - 'a'])                   /* cmdline still overrides */
+         flags[ch - 'a'] = 1;
+      }
+    }
+  }
 
 
-  fopen("/lock"); fclose();
-  fopen("/lockbounce"); fclose();
-  if (flagpublic) {
-    fopen("/public"); fclose();
+  for (pos = 0; pos < (unsigned int) NO_FLAGS; pos++) {        /* set real flags */
+    if (flags[pos] & 2)                                /* 2 = "dominant" 0 */
+      flags[pos] = flags[pos] & 1;             /* 3 = "dominant" 1 */
   }
   }
-  if (flagarchived) {
-    fopen("/archived"); fclose();
+
+  if (local[str_chr(local,'\n')]) die_newline();
+  if (host[str_chr(host,'\n')]) die_newline();
+
+       /* build 'f' for <#F#> */
+  if (!stralloc_ready(&f,28)) die_nomem();
+  if (!stralloc_copys(&f,"-")) die_nomem();
+  for (ch = 0; ch <= 'z' - 'a'; ch++) {                /* build string with flags */
+    if (flags[ch])
+      sz[0] = 'a' + ch;
+    else
+      sz[0] = 'A' + ch;
+    if (!stralloc_append(&f,sz)) die_nomem();
+  }
+
+  fdin = -1;   /* assure failure for .ezmlmrc in case flags['c'-'a'] = 0 */
+  slpos = str_len(dot);
+  while ((--slpos > 0) && dot[slpos] != '/');
+  if (dot[slpos] == '/') {
+    if (!stralloc_copyb(&template,dot,slpos+1)) die_nomem();   /* dot dir */
+    slpos += str_chr(dot+slpos,'-');
+    if (dot[slpos]) {
+      slpos++;
+      pos = slpos + str_chr(dot+slpos,'-');
+      if (dot[pos]) {
+        if (!stralloc_copyb(&ext1,dot+slpos,pos-slpos)) die_nomem();
+        pos++;
+        slpos = pos + str_chr(dot+pos,'-');
+        if (dot[slpos])
+          if (!stralloc_copyb(&ext2,dot+pos,slpos-pos)) die_nomem();
+      }
+    }
+  }
+  if (!stralloc_0(&ext1)) die_nomem();
+  if (!stralloc_0(&ext2)) die_nomem();
+  popt[1] = ext1.s;
+  popt[2] = ext2.s;
+       /* if 'c', template already has the dot directory. If 'C', cfname */
+       /* (if exists and != '') points to the file name to use instead. */
+  if (flags['c'-'a'] || (cfname && *cfname)) {
+    if (!flags['c'-'a']) {     /* i.e. there is a cfname specified */
+      if (!stralloc_copys(&template,cfname)) die_nomem();
+    } else
+      if (!stralloc_cats(&template,TXT_DOTEZMLMRC)) die_nomem();
+  if (!stralloc_0(&template)) die_nomem();
+  if ((fdin = open_read(template.s)) == -1)
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+    else
+      strerr_die3x(100,FATAL,template.s,ERR_NOEXIST);
+  } else {                     /* /etc/ezmlmrc */
+    if (!stralloc_copys(&template,TXT_ETC_EZMLMRC)) die_nomem();
+    if (!stralloc_0(&template)) die_nomem();
+    if ((fdin = open_read(template.s)) == -1)
+      if (errno != error_noent)
+        strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+      else {                   /* ezbin/ezmlmrc */
+       if (!stralloc_copys(&template,auto_bin)) die_nomem();
+       if (!stralloc_cats(&template,TXT_EZMLMRC)) die_nomem();
+       if (!stralloc_0(&template)) die_nomem();
+       if ((fdin = open_read(template.s)) == -1)
+         if (errno != error_noent)
+           strerr_die4sys(111,FATAL,ERR_OPEN,template.s,": ");
+         else
+           strerr_die3x(100,FATAL,template.s,ERR_NOEXIST);
+      }
   }
   }
-  fopen("/num"); fputs("0\n"); fclose();
-  fopen("/inhost"); fputs(host); fputs("\n"); fclose();
-  fopen("/outhost"); fputs(host); fputs("\n"); fclose();
-  fopen("/inlocal"); fputs(local); fputs("\n"); fclose();
-  fopen("/outlocal"); fputs(local); fputs("\n"); fclose();
-
-  fopen("/mailinglist");
-  fputs("contact ");
-  fputs(local); fputs("-help@"); fputs(host); fputs("; run by ezmlm\n");
-  fclose();
-
-  fopen("/owner");
-  fputs(dir); fputs("/Mailbox\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
-  fputs("' || exit 0\n");
-  fclose();
-
-  fopen("/manager");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-manage '"); fputs(dir); fputs("'\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
-  fputs("' || exit 0\n");
-  fclose();
-
-  fopen("/editor");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-reject\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-send '"); fputs(dir); fputs("'\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
-  fputs("' || exit 0\n");
-  fclose();
-
-  fopen("/bouncer");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir);
-  fputs("' || exit 0\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-weed\n");
-  fputs("|"); fputs(auto_bin); fputs("/ezmlm-return '"); fputs(dir); fputs("'\n");
-  fclose();
-
-  fopen("/headerremove");
-  fputs("\
-return-path\n\
-return-receipt-to\n\
-content-length\n\
-");
-  fclose();
-
-  fopen("/headeradd");
-  fclose();
-
-
-  fopen("/text/top");
-  fputs("Hi! This is the ezmlm program. I'm managing the\n");
-  fputs(local); fputs("@"); fputs(host); fputs(" mailing list.\n\n");
-  fclose();
-
-  fopen("/text/bottom");
-  fputs("\n--- Here are the ezmlm command addresses.\n\
-\n\
-I can handle administrative requests automatically.\n\
-Just send an empty note to any of these addresses:\n\n   <");
-  fputs(local); fputs("-subscribe@"); fputs(host); fputs(">:\n");
-  fputs("   Receive future messages sent to the mailing list.\n\n   <");
-  fputs(local); fputs("-unsubscribe@"); fputs(host); fputs(">:\n");
-  fputs("   Stop receiving messages.\n\n   <");
-  fputs(local); fputs("-get.12345@"); fputs(host); fputs(">:\n");
-  fputs("   Retrieve a copy of message 12345 from the archive.\n\
-\n\
-DO NOT SEND ADMINISTRATIVE REQUESTS TO THE MAILING LIST!\n\
-If you do, I won't see them, and subscribers will yell at you.\n\
-\n\
-To specify God@heaven.af.mil as your subscription address, send mail\n\
-to <");
-  fputs(local); fputs("-subscribe-God=heaven.af.mil@"); fputs(host);
-  fputs(">.\n\
-I'll send a confirmation message to that address; when you receive that\n\
-message, simply reply to it to complete your subscription.\n\
-\n");
-  fputs("\n--- Below this line is a copy of the request I received.\n\n");
-  fclose();
-
-  fopen("/text/sub-confirm");
-  fputs("To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-added to this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Your mailer should have a Reply feature that uses this address automatically.\n\
-\n\
-This confirmation serves two purposes. First, it verifies that I am able\n\
-to get mail through to you. Second, it protects you in case someone\n\
-forges a subscription request in your name.\n\
-\n");
-  fclose();
-
-  fopen("/text/unsub-confirm");
-  fputs("To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-removed from this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Your mailer should have a Reply feature that uses this address automatically.\n\
-\n\
-I haven't checked whether your address is currently on the mailing list.\n\
-To see what address you used to subscribe, look at the messages you are\n\
-receiving from the mailing list. Each message has your address hidden\n\
-inside its return path; for example, God@heaven.af.mil receives messages\n\
-with return path ...-God=heaven.af.mil.\n\
-\n");
-  fclose();
-
-  fopen("/text/sub-ok");
-  fputs("Acknowledgment: I have added the address\n\
-\n\
-!A\n\
-\n\
-to this mailing list.\n\
-\n");
-  fclose();
-
-  fopen("/text/unsub-ok");
-  fputs("Acknowledgment: I have removed the address\n\
-\n\
-!A\n\
-\n\
-from this mailing list.\n\
-\n");
-  fclose();
-
-  fopen("/text/sub-nop");
-  fputs("Acknowledgment: The address\n\
-\n\
-!A\n\
-\n\
-is on this mailing list.\n\
-\n");
-  fclose();
-
-  fopen("/text/unsub-nop");
-  fputs("Acknowledgment: The address\n\
-\n\
-!A\n\
-\n\
-is not on this mailing list.\n\
-\n");
-  fclose();
-
-  fopen("/text/sub-bad");
-  fputs("Oops, that confirmation number appears to be invalid.\n\
-\n\
-The most common reason for invalid numbers is expiration. I have to\n\
-receive confirmation of each request within ten days.\n\
-\n\
-I've set up a new confirmation number. To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-added to this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Sorry for the trouble.\n\
-\n");
-  fclose();
-
-  fopen("/text/unsub-bad");
-  fputs("Oops, that confirmation number appears to be invalid.\n\
-\n\
-The most common reason for invalid numbers is expiration. I have to\n\
-receive confirmation of each request within ten days.\n\
-\n\
-I've set up a new confirmation number. To confirm that you would like\n\
-\n\
-!A\n\
-\n\
-removed from this mailing list, please send an empty reply to this address:\n\
-\n\
-!R\n\
-\n\
-Sorry for the trouble.\n\
-\n");
-  fclose();
-
-  fopen("/text/get-bad");
-  fputs("Sorry, I don't see that message.\n\n");
-  fclose();
-
-  fopen("/text/bounce-bottom");
-  fputs("\n\
---- Below this line is a copy of the bounce message I received.\n\n");
-  fclose();
-
-  fopen("/text/bounce-warn");
-  fputs("\n\
-Messages to you seem to have been bouncing. I've attached a copy of\n\
-the first bounce message I received.\n\
-\n\
-If this message bounces too, I will send you a probe. If the probe bounces,\n\
-I will remove your address from the mailing list, without further notice.\n\
-\n");
-  fclose();
-
-  fopen("/text/bounce-probe");
-  fputs("\n\
-Messages to you seem to have been bouncing. I sent you a warning\n\
-message, but it bounced. I've attached a copy of the bounce message.\n\
-\n\
-This is a probe to check whether your address is reachable. If this\n\
-probe bounces, I will remove your address from the mailing list, without\n\
-further notice.\n\
-\n");
-  fclose();
-
-  fopen("/text/bounce-num");
-  fputs("\n\
-I've kept a list of which messages bounced from your address. Copies of\n\
-these messages may be in the archive. To get message 12345 from the\n\
-archive, send an empty note to ");
-  fputs(local); fputs("-get.12345@"); fputs(host); fputs(".\n\
-Here are the message numbers:\n\
-\n");
-  fclose();
-
-  fopen("/text/help");
-  fputs("\
-This is a generic help message. The message I received wasn't sent to\n\
-any of my command addresses.\n\
-\n");
-  fclose();
-
-  fopen("/key");
-  fput(key.s,key.len);
-  fclose();
 
 
+  dcreate("");         /* This is all we do, the rest is up to ezmlmrc */
+                       /* do it after opening template to avoid aborts */
+                       /* with created DIR. Well we also write DIR/key */
+                       /* at the end except in -e[dit] mode.           */
+
+  substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf));
+  if (!stralloc_0(&oldfname)) die_nomem();             /* init oldfname */
+  flagdo = 0;
+
+  if (getln(&sstext,&line,&match,'\n') == -1)
+    strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+  if (!match)
+    strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+  i = str_rchr(EZIDX_VERSION,'-');                     /* check version */
+  if (EZIDX_VERSION[i]) i++;
+  j = 0;
+  while (line.s[j] == EZIDX_VERSION[i] && j < line.len &&
+               EZIDX_VERSION[i] != '.' && EZIDX_VERSION[i]) {
+    i++; j++;                                          /* major */
+  }                                                    /* first minor */
+  if (EZIDX_VERSION[i] != '.' || j + 1 >= line.len ||
+               EZIDX_VERSION[i+1] != line.s[j+1])
+    strerr_warn2(WARNING,ERR_VERSION, (struct strerr *) 0);
+
+  for (;;) {
+    if (getln(&sstext,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,template.s,": ");
+    if (!match)
+      break;
+    if (line.s[0] == '#')                              /* comment */
+      continue;
+    if (!stralloc_0(&line)) die_nomem();
+    if (line.s[0] == '<' && line.s[1] == '/') {                /* tag */
+    if (line.s[str_chr(line.s,'.')])
+      strerr_die3x(100,FATAL,ERR_PERIOD,line.s);
+      flagdo = 1;
+      flagover = 0;
+      hashpos = 0;
+      pos = str_chr(line.s+2,'#')+2;
+      if (line.s[pos]) {
+        hashpos = pos;
+        pos++;
+        flagnot = 0;
+        while ((ch = line.s[pos]) &&
+              (line.s[pos] != '/' && line.s[pos+1] != '>')) {
+          if (ch == '^') {
+            flagnot = 1;
+            pos++;
+            continue;
+          }
+                       /* E is ignored. For files => create unless exists */
+         if (ch == 'E' && !flagnot ||  ch == 'e' && flagnot) {
+               if (flags['e' - 'a'] && !flagforce)
+           flagover = 1;               /* ignore #E & #^e, but set flagover */
+          } else if (ch >= 'a' && ch <= 'z')
+            flagdo &= (flags[ch - 'a'] ^ flagnot);
+          else if (ch >= 'A' && ch <= 'Z')
+            flagdo &= !(flags[ch - 'A'] ^ flagnot);
+          else if (ch >= '0' && ch <= '9')
+            flagdo &= (popt[ch - '0'] && *popt[ch - '0']) ^flagnot;
+          flagnot = 0;
+          pos++;
+        }
+        if (line.s[pos] != '/' || line.s[pos+1] != '>')
+          strerr_die3x(100,FATAL,ERR_ENDTAG,line.s);
+      } else {
+        flagdo = 1;
+        pos = 2;       /* name needs to be >= 1 char */
+        while (line.s[pos = str_chr(line.s+pos,'/')+pos]) {
+          if (line.s[pos+1] == '>')
+            break;
+          pos++;
+        }
+        if (!line.s[pos])
+          strerr_die3x(100,FATAL,ERR_ENDTAG,line.s);
+      }
+      if (hashpos)
+        pos = hashpos; /* points to after file name */
+
+      if (line.s[2] == '+') {                  /* mkdir */
+        if (!flagdo)
+          continue;
+        if (!stralloc_copys(&dname,"/")) die_nomem();
+        if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem();
+        if (!stralloc_0(&dname)) die_nomem();
+        dcreate(dname.s);
+        flagdo = 0;
+        continue;
+      } else if (line.s[2] == ':') {           /* ln -s */
+        if (!flagdo)
+          continue;
+        slpos = str_chr(line.s + 3,'/') + 3;
+        if (slpos >= pos)
+          strerr_die3x(100,FATAL,ERR_LINKDIR,line.s);
+        if (!stralloc_copyb(&dname,line.s+slpos,pos-slpos)) die_nomem();
+        if (!stralloc_copyb(&lname,line.s+3,slpos-3)) die_nomem();
+        if (!stralloc_0(&dname)) die_nomem();
+        if (!stralloc_0(&lname)) die_nomem();
+        linkdotdir(lname.s,dname.s);
+        flagdo = 0;
+        continue;
+      } else if (line.s[2] == '-') {           /* rm */
+        if (!flagdo)
+          continue;
+        if (!stralloc_copys(&dname,"/")) die_nomem();
+        if (!stralloc_catb(&dname,line.s+3,pos-3)) die_nomem();
+        if (!stralloc_0(&dname)) die_nomem();
+        frm(dname.s);
+        flagdo = 0;
+        continue;
+      }
+                                               /* only plain files left */
+                                               /* first get file name */
+      if (pos > 2) {                   /* </#ai/> => add to open file */
+        if (!stralloc_copyb(&fname,line.s+1,pos-1)) die_nomem();
+        if (!stralloc_0(&fname)) die_nomem();
+      }
+
+      if (str_diff(fname.s, oldfname.s)) {
+       flagnotexist = 1;
+                       /* Treat special case of #E when editing which _should*/
+                       /* write only if the file does not exist. flagover */
+                       /* is set if we need to check */
+        if (flagover) {        /* skip if exists */
+         dirplusmake(fname.s);         /* decided by FIRST tag for file */
+         fdtmp = open_read(dirplus.s);
+         if (fdtmp == -1) {
+           if (errno != error_noent)
+             strerr_die3sys(111,ERR_OPEN,dirplus.s,": ");
+          } else {
+           flagnotexist = 0;           /* already there - don't do it */
+           close(fdtmp);
+         }
+        }
+        if (oldfname.len > 1) {
+          f_close();
+          if (!stralloc_copys(&oldfname,"")) die_nomem();
+          if (!stralloc_0(&oldfname)) die_nomem();
+          }
+          if (flagdo && flagnotexist) {
+            if (!fname.len)
+              strerr_die3x(100,FATAL,ERR_FILENAME,line.s);
+            f_open(fname.s);
+           if (!stralloc_copy(&oldfname,&fname)) die_nomem();
+          }
+        }
+       if (flagdo) flagdo = flagnotexist;
+        continue;
+    } else if (!flagdo)
+      continue;                        /* part not to go out */
+    last = -1;
+    next = 0;
+    outline.len = 0;
+    for (;;) {
+      pos = next + str_chr(line.s+next,'<');
+      if (line.s[pos] &&
+          line.s[pos+1] == '#' &&
+          line.s[pos+2] &&
+          line.s[pos+3] == '#' &&
+          line.s[pos+4] == '>') {      /* host/local */
+        if (!stralloc_catb(&outline,line.s+last+1,pos-last-1))
+                die_nomem();
+        switch (line.s[pos+2]) {
+          case 'B':            /* path to ezmlm binaries (no trailing /) */
+            if (!stralloc_cats(&outline,auto_bin)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'C':            /* digestcode */
+            if (code && *code)
+              if (!stralloc_cats(&outline,code)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'D':            /* listdir */
+            if (!stralloc_cats(&outline,dir)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'F':            /* flags */
+            if (!stralloc_cat(&outline,&f)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'H':            /* hostname */
+            if (!stralloc_cats(&outline,host)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'L':            /* local */
+            if (!stralloc_cats(&outline,local)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'T':            /* dot */
+            if (!stralloc_cats(&outline,dot)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          case 'X':            /* config file name */
+            if (cfname)
+             if (!stralloc_cats(&outline,cfname)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+          default:             /* copy unknown tag as is for e.g. <#A#> and*/
+                               /* <#R#> to be processed by -manage/store   */
+                                /* stuff in args for <#0#> .. <#9#> */
+            if ((line.s[pos+2] >= '0') && (line.s[pos+2] <= '9')) {
+              if (popt[line.s[pos+2] - '0'])
+                if (!stralloc_cats(&outline,popt[line.s[pos+2]-'0']))
+                  die_nomem();
+            } else
+              if (!stralloc_catb(&outline,line.s+pos,5)) die_nomem();
+            last = pos + 4; next = pos + 5; break;
+        }
+      } else {                 /* not tag */
+        if (line.s[pos]) {
+          next++;
+        } else {
+          if (!stralloc_catb(&outline,line.s+last+1,line.len-last-1))
+            die_nomem();
+          f_puts(outline.s);
+          break;
+        }
+      }
+    }
+  }
+
+  close(fdin);
+  if (oldfname.len > 1)
+    f_close();
+
+  if (!flags['e' - 'a']) {     /* don't redo key when editing a list */
+    f_open("/key");
+    f_put(key.s,key.len);
+    f_close();
+  }
   _exit(0);
 }
   _exit(0);
 }
+
index a68438f..940a766 100644 (file)
@@ -2,13 +2,14 @@
 .SH NAME
 ezmlm-manage \- automatically manage a mailing list
 .SH SYNOPSIS
 .SH NAME
 ezmlm-manage \- automatically manage a mailing list
 .SH SYNOPSIS
-.B ezmlm-manage
+.B ezmlm-manage [-bBcCdDeEfFlLmMsSqQuUvV]
 .I dir
 .SH DESCRIPTION
 .B ezmlm-manage
 handles administrative requests for the mailing list
 stored in
 .I dir
 .SH DESCRIPTION
 .B ezmlm-manage
 handles administrative requests for the mailing list
 stored in
-.IR dir .
+.IR dir ,
+as well as for the associated digest list.
 
 .B ezmlm-manage
 is normally invoked from a
 
 .B ezmlm-manage
 is normally invoked from a
@@ -52,6 +53,56 @@ expects
 to match the first line of
 .IR dir\fB/inhost .
 
 to match the first line of
 .IR dir\fB/inhost .
 
+If
+.I list
+is the first line of
+.IR dir\fB/inlocal
+followed by ``-digest'', the request is assumed to be for the
+associated digest list.
+.B ezmlm-manage
+handles these requests similarly, except that digest list subscriber addresses
+are stored in
+.IR dir\fB/digest/subscribers ,
+rather than in
+.IR dir\fB/subscribers .
+
+If
+.I list
+.IR dir\fB/inlocal
+followed by ``-allow'', the request is assumed to be for the
+associated
+.I dir\fB/allow/
+database. This database is used to store aliases of subscribers for lists
+allowing only posts only if the envelope sender is a subscriber.
+Actions on the
+.I dir\fB/allow/
+database follow the same rules as for the main list. The ezmlm messages are
+the same as those used for normal subscription, but refer to the
+.I list\fB-allow@\fIhost
+list. As this feature is designed for advanced uses and remote administrators
+only, this is not a problem.
+.B NOTE:
+No message is sent out to confirm additions to or removals from this
+database. However, the user can
+verify the change using the
+.I query
+action.
+The
+.I list\fB-deny
+addresses similarly controls
+.I dir\fB/deny/
+database for blocking posts with certain envelope senders.
+This database is available
+to remote administrators only, and only if the list has been set up with
+this feature (see
+.BR ezmlm-manage(1) ).
+.B NOTE:
+No message is sent out to confirm additions to or removals from this database.
+However, the remote admin can
+verify the change using the
+.I query
+action.
+
 .B ezmlm-manage
 copies
 .I dir\fB/mailinglist
 .B ezmlm-manage
 copies
 .I dir\fB/mailinglist
@@ -65,6 +116,186 @@ field,
 refuses to respond.
 .B ezmlm-manage
 also refuses to respond to bounce messages.
 refuses to respond.
 .B ezmlm-manage
 also refuses to respond to bounce messages.
+.SH OPTIONS
+.TP 5
+.B \-b
+(Default.)
+.B ezmlm-manage
+will add general instructions and the request to the outgoing message.
+.TP 5
+.B \-B
+.B ezmlm-manage
+will not add general instructions and the request to the outgoing message.
+This information gives the recipient of a confirmation request some
+information about the inciting message. Use of this switch will deny the
+recipient that information.
+.TP 5
+.B \-c
+(Default.)
+.B ezmlm-manage
+will reply to
+.I \-get
+commands.
+.TP
+.B \-C
+.B ezmlm-manage
+will not reply to
+.I \-get
+commands. This is useful for closed lists, where the owner for
+some reason wants to keep an archive, without making it available.
+.TP 5
+.B \-d
+Alias for the
+.B \-e
+switch for backwards compatibility.
+.TP 5
+.B \-D
+Alias for the
+.B \-E
+switch for backwards compatibility.
+.TP 5
+.B \-e
+.B ezmlm-manage
+allows remote administrators to edit files in
+.I dir\fB/text/
+via E-mail.
+.TP 5
+.B \-E
+(Default.)
+Text file editing not allowed.
+.TP 5
+.B \-f
+(Default.)
+The information in the ``From:'' is extracted from subscribe confirm
+messages and added to
+.I dir\fB/Log
+together with the subscriber address. This makes it easier for the list owner
+to help a subscriber who cannot determine his/her subscription address. If the
+.B \-S
+switch is used, the information is instead extracted from the subscribe
+request.
+.TP 5
+.B \-F
+Ignore ``From:'' headers.
+.TP 5
+.B \-l
+.B ezmlm-manage
+will send a subscriber list in reply to the 
+.I \-list
+command and
+the number of subscribers in reply to the
+.I \-listn
+comman if
+.I dir\fB/modsub
+or
+.I dir\fB/remote
+exist and target (the address the reply is to be sent to) is a moderator.
+.TP 5
+.B \-L
+(Default.)
+.B ezmlm-manage
+will ignore the
+.I \-list
+and
+.I \-listn
+commands.
+.TP 5
+.B \-m
+For lists with moderated subscription, require moderator approval also
+for unsubscribe requests. Remote admins are normally informed about
+unsuccessful unsubscribes. This creates problems when there is more
+than one moderator. Therefore, when the
+.B \-m
+switch is used, the notification is suppressed. Moderators can still
+determine the result by using the
+.I \-query
+command.
+.TP 5
+.B \-M
+(Default.)
+Requests to unsubscribe from moderated lists do not require moderator approval.
+.TP 5
+.I \-n
+(Default.)
+Target addresses
+will be notified if the are added or removed from the subscriber list.
+.TP 5
+.I \-N
+Target addresses will not be notified if they are added/removed from the
+subscriber list by remote admin or moderator action. Also, the target will
+not be notified if they were successfully added/removed when the
+.B \-S
+and
+.B \-U
+switches, respectively, are used.
+.TP 5
+.B \-q
+(Default.)
+Quiet. The list-owner is not notified of subscription events.
+.TP 5
+.B \-Q
+The list-owner is notified about failed unsubscribe attempts. Usually, these
+are from subscribers that do not remember their subscription address and
+require administrative assistance. Remote admins are notified when a unsubscribe
+request initiated by them fails. Thus, the owner is not notified about these
+events even if the
+.B \-Q
+switch is used.
+.TP 5
+.B \-QQ
+As for
+.BR \-Q ,
+and in addition, the list-owner is notified about all additions to or removals
+from the subscriber database. This is sometimes desired by owners of small
+lists.
+.TP 5
+.B \-s
+(Default.)
+.B ezmlm-manage
+will handle subscriptions with the normal target handshake.
+.TP 5
+.B \-S
+.B ezmlm-manage
+will eliminate the target handshake from the subscription
+process. This allows anyone to subscribe anybody else. DO NOT use this
+option, unless you know what you are doing. This option may be useful for 
+some moderated lists.
+.TP 5
+.B \-u
+(Default.)
+.B ezmlm-manage
+will handle unsubscribe requests with the normal target
+handshake.
+.TP 5
+.B \-U
+.B ezmlm-manage
+will eliminate the target handshake from the unsubscription
+process. This allows anyone to unsubscribe anybody else. DO NOT use this
+option, unless you know what you are doing.
+.TP 5
+.B \-v
+Display
+.B ezmlm-manage
+version information.
+.TP 5
+.B \-V
+Display
+.B ezmlm-manage
+version information.
+.SH "CHARACTER SETS"
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-manage
+will use the character set listed for all messages. Otherwise, the
+default ``us-ascii'' will be used. The character set can be suffixed
+by ``:'' followed by a code. If the code is ``Q'', outgoing messages are 
+sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded.
+Otherwise, text is sent as is.
+
+Incoming text for the
+.I \-edit
+is accepted unencoded or in either of these encodings.
 .SH SUBSCRIPTIONS
 If
 .I action
 .SH SUBSCRIPTIONS
 If
 .I action
@@ -75,7 +306,25 @@ where
 is an appropriate code
 (depending on the target, the approximate time, and other factors),
 .B ezmlm-manage
 is an appropriate code
 (depending on the target, the approximate time, and other factors),
 .B ezmlm-manage
-adds the target to the mailing list.
+adds the target to the mailing list
+if subscriptions are not moderated.
+For subscription moderated lists,
+.B ezmlm-manage
+sends a confirmation request to the moderators with the right
+.BR tc.\fIcookie
+address in its response.
+If
+.I action
+is
+.BR tc.\fIcookie ,
+where
+.I cookie
+is an appropriate code
+(depending on the target, the approximate time, and other factors),
+.B ezmlm-manage
+adds the target to the mailing list. If the target was not already a
+subscriber, a welcome message is sent to the target.
 
 If
 .I action
 
 If
 .I action
@@ -97,12 +346,84 @@ Actions of
 and
 .B unsubscribe
 are used in the same way to delete the target from the mailing list.
 and
 .B unsubscribe
 are used in the same way to delete the target from the mailing list.
+Unsubscribes do not require moderator confirmation.
+
+Actions of
+.B vc.\fIcookie
+are used to confirm moderator-initiated unsubscribes for lists configured
+with remote administration (see MODERATION).
+
+If
+.I action
+is
+.BR query ,
+.B ezmlm-manage
+returns a message to the target indicating whether or not the target address
+is a subscriber.
+
+If
+.I action
+is
+.B info
+or
+.BR faq ,
+.B ezmlm-manage
+returns the contents of
+.I dir\fB/text/info
+or
+.IR dir\fB/text/info ,
+respectively.
 
 If
 .I dir\fB/public
 does not exist,
 .B ezmlm-manage
 rejects all subscription and unsubscription attempts.
 
 If
 .I dir\fB/public
 does not exist,
 .B ezmlm-manage
 rejects all subscription and unsubscription attempts.
+However, if the list is configured with remote administration,
+moderator-initiated subscribe and unsubscribe requests will still be
+honored. Also, if
+.I action
+is
+.IR help ,
+.B ezmlm-manage
+will still send help.
+.SH "TEXT FILE EDITING"
+If
+.I action
+is
+.BR edit ,
+the
+.B \-e
+switch is used, and the target address is that of a remote administrator,
+.B ezmlm-manage
+will reply with a list of editable file in
+.I dir\fB/text/
+and instructions for editing. Cookies for editing expire approximately 27.8
+hours after they are issued, or when a file has been changed, whichever is
+sooner. The size of the updated file is limited to 5120 bytes.
+
+If
+.I action
+is
+.BR edit.\fIfile ,
+the
+.B \-e
+switch is used, and the target address is that of a remote administrator,
+.B ezmlm-manage
+will return an editable copy of
+.IR file .
+
+If
+.I action
+is
+.BR ed.\fIcookie ,
+.B ezmlm-manage
+will verify that the edit cookie is still valid and that the file has
+not been modified since the cookie was issued. If the cookie passes
+these tests,
+.B ezmlm-manage
+will update
+.IR dir\fB/text\fI/file .
 .SH "ARCHIVE RETRIEVALS"
 If
 .I action
 .SH "ARCHIVE RETRIEVALS"
 If
 .I action
@@ -112,18 +433,146 @@ is
 sends back message
 .I num
 from
 sends back message
 .I num
 from
-.IR dir\fB/archive .
+.IR dir\fB/archive/ .
+This can be disabled with the
+.B \-C
+command line switch.
 
 If
 .I dir\fB/public
 does not exist,
 .B ezmlm-manage
 rejects all archive retrieval attempts.
 
 If
 .I dir\fB/public
 does not exist,
 .B ezmlm-manage
 rejects all archive retrieval attempts.
+.SH MODERATION
+If
+.I dir\fB/modsub
+exists, subscriptions are moderated. Users can
+unsubscribe without moderator action, but moderator confirmation is required
+for subscriptions.
+
+If
+.I dir\fB/modsub
+starts with a forward slash, it is assumed that the content this is the base
+directory for the moderator database (
+.IR moddir ).
+Otherwise,
+.I moddir
+is assumed to be
+.IR dir\fB/mod/ .
+
+The moderator names are assumed
+to be stored in a set of files in
+.IR /moddir\fB/subscribers/ .
+
+I to add, remove, and list moderators, use respectively:
+
+.EX
+.B ezmlm-sub
+.I moddir
+.IR user@host
+.EE
+
+.EX
+.B ezmlm-unsub
+.I moddir
+.IR user@host
+.EE
+
+.EX
+.B ezmlm-list
+.I moddir
+.EE
+
+Subscription requests from potential
+subscribers will be sent for a second round of confirmation to all the
+moderators.
+If a moderator approves the request, a message confirming the
+subscription will be sent to the subscriber. The
+subscriber will not know which moderator approved the subscription.
+
+If more than one moderator replies to the confirmation request, the subscriber
+will not receive duplicate messages about being on (or not on) the mailing list.
+
+Unsubscribe requests from users are handled as for non-moderated lists.
+
+All subscribe confirmation requests requiring moderator action have a subject of
+.B CONFIRM subscribe to\fI listname@host.
+All unsubscribe confirmation requests in reply to moderator-initiated
+unsubscribe dialogs have a subject of
+.B CONFIRM unsubscribe from\fI listname@host.
+
+If
+.I dir\fB/remote
+exists (remote administration), moderators can initiate a request to
+subscribe a user 'username@userhost' by sending mail to
+.IR listname-subscribe\fB\-username=userhost\fI@host .
+The moderator (not the subscriber) will receive the confirmation request,
+and can complete the transaction. Moderators' request to unsubscribe
+users are handled analogously. Once an address is successfully added to
+or removed from the subscriber database by a moderator or remote admin,
+the user is notified of the action. If a moderator or remote admin's subscribe
+confirmation does not result in a change, i.e. if the address already was a
+subscriber, no notification is sent. If a remote admin's
+unsubscribe confirmation does not result in a change, i.e. the address was
+not a subscriber, a notification is sent to the remote admin. This is to make
+the remote admin aware that the address unsubscribed most likely is not the
+subscriber's subscription address.
+
+.I dir\fB/remote
+starts with a forward slash, it is assumed that the content this is the base
+directory for the moderator database (
+.IR moddir ).
+The moderator names are assumed
+to be stored in a set of files in
+.IR /moddir\fB/subscribers/ .
+If both
+.I dir\fB/modsub
+and
+.I dir\fB/remote
+exist, and both contain directory names, the directory name in
+.I dir\fB/modsub
+is used, and the
+.I dir\fB/remote
+entry is ignored.
+
+It is possible to set up
+a mailinglist for moderators only by using
+.I dir\fB/mod/
+as the list directory. Make sure that such a list is not public! Otherwise,
+anyone can become a moderator by subscribing to this list.
+
+If action is
+.B \-help
+and target is a moderator,
+.B ezmlm-manage
+will in addition to the usual help send
+.I dir\fB/text/mod-help
+containing instructions for moderators.
+
+If action is
+.B \-list
+and target is a moderator, the list is set up for subscription moderation
+or remote administration, and the
+.I \-l
+command line switch is used,
+.B ezmlm-manage
+will reply with an unsorted subscriber list. Extensions for digest subscribers
+and auxillary databases are supported (see above).
+
+If action is
+.BR \-log ,
+.B ezmlm-manage
+will reply with the contents of the
+.I Log
+file with the same access restrictions as for the
+.B \-list
+action.
 .SH "SEE ALSO"
 ezmlm-make(1),
 ezmlm-return(1),
 ezmlm-send(1),
 ezmlm-sub(1),
 ezmlm-unsub(1),
 .SH "SEE ALSO"
 ezmlm-make(1),
 ezmlm-return(1),
 ezmlm-send(1),
 ezmlm-sub(1),
 ezmlm-unsub(1),
+ezmlm-list(1),
 ezmlm(5),
 qmail-command(8)
 ezmlm(5),
 qmail-command(8)
index d40ba0f..134c5a0 100644 (file)
@@ -1,3 +1,6 @@
+/*$Id: ezmlm-manage.c,v 1.86 1999/12/23 02:43:55 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "error.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "error.h"
 #include "fmt.h"
 #include "subscribe.h"
 #include "cookie.h"
 #include "fmt.h"
 #include "subscribe.h"
 #include "cookie.h"
+#include "sgetopt.h"
+#include "copy.h"
+#include "errtxt.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-manage: fatal: "
 
 #define FATAL "ezmlm-manage: fatal: "
-void die_usage() { strerr_die1x(100,"ezmlm-manage: usage: ezmlm-manage dir"); }
-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+#define INFO "ezmlm-manage: info: "
+
+int flagverbose = 0;   /* default: Owner not informed about subdb changes */
+                       /* 1 => notified for failed unsub, 2 => for all */
+int flagnotify = 1;    /* notify subscriber of completed events. 0 also */
+                       /* suppresses all subscriber communication for */
+                       /* [un]sub if -U/-S is used */
+int flagbottom = 1;    /* default: copy request & admin info to message */
+int flaglist = 0;      /* default: do not reply to -list */
+int flagget = 1;       /* default: service -get requests */
+int flagsubconf = 1;   /* default: require user-confirm for subscribe */
+int flagunsubconf = 1; /* default: require user-confirm for unsubscribe */
+int flagunsubismod = 0;        /* default: do not require moderator approval to */
+                       /* unsubscribe from moderated list */
+int flagedit = 0;      /* default: text file edit not allowed */
+int flagstorefrom = 1; /* default: store from: line for subscribes */
+char flagcd = '\0';    /* default: do not use _Q_uoted printable or _B_ase64 */
+char encin = '\0';     /* encoding of incoming message */
+int flagdig = 0;       /* request is not for digest list */
+
+static const char hex[]="0123456789ABCDEF";
+char urlstr[] = "%00"; /* to build a url-encoded version of a char */
+
+int act = AC_NONE;     /* desired action */
+unsigned int actlen = 0;/* str_len of above */
+char *dir;
+char *workdir;
+char *sender;
+void *psql = (void *) 0;
+
+void die_usage() {
+  strerr_die1x(100,"ezmlm-manage: usage: ezmlm-manage "
+               "[-bBcCdDeEfFlLmMnNqQsSuUvV] dir"); }
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
 void die_badaddr()
 {
 void die_badaddr()
 {
-  strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)");
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+void die_cookie()
+{
+  strerr_die2x(100,FATAL,ERR_MOD_COOKIE);
 }
 
 stralloc inhost = {0};
 }
 
 stralloc inhost = {0};
@@ -37,34 +83,200 @@ stralloc inlocal = {0};
 stralloc outlocal = {0};
 stralloc key = {0};
 stralloc mailinglist = {0};
 stralloc outlocal = {0};
 stralloc key = {0};
 stralloc mailinglist = {0};
+stralloc mydtline = {0};
+stralloc target = {0};
+stralloc verptarget = {0};
+stralloc confirm = {0};
+stralloc line = {0};
+stralloc qline = {0};
+stralloc quoted = {0};
+stralloc moddir = {0};
+stralloc ddir = {0};
+stralloc modsub = {0};
+stralloc remote = {0};
+stralloc from = {0};
+stralloc to = {0};
+stralloc owner = {0};
+stralloc fromline = {0};
+stralloc text = {0};
+stralloc fnedit = {0};
+stralloc fneditn = {0};
+stralloc charset = {0};
 
 datetime_sec when;
 struct datetime dt;
 
 datetime_sec when;
 struct datetime dt;
+int match;
+unsigned int max;
 
 char strnum[FMT_ULONG];
 char date[DATE822FMT];
 char hash[COOKIE];
 
 char strnum[FMT_ULONG];
 char date[DATE822FMT];
 char hash[COOKIE];
+char boundary[COOKIE];
 datetime_sec hashdate;
 datetime_sec hashdate;
-stralloc target = {0};
-stralloc confirm = {0};
-stralloc line = {0};
-stralloc quoted = {0};
 
 
-int hashok(action)
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+
+substdio sstext;       /* editing texts and reading "from" */
+char textbuf[512];
+
+substdio ssfrom;       /* writing "from" */
+char frombuf[512];
+
+int fdlock;
+
+void lock()
+{
+    fdlock = open_append("lock");
+    if (fdlock == -1)
+      strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/lock: ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/lock: ");
+}
+
+void unlock()
+{
+    close(fdlock);
+}
+
+void make_verptarget()
+/* puts target with '=' instead of last '@' into stralloc verptarget */
+/* and does set_cpverptarget */
+{
+  unsigned int i;
+
+  i = str_rchr(target.s,'@');
+  if (!stralloc_copyb(&verptarget,target.s,i)) die_nomem();
+  if (target.s[i]) {
+    if (!stralloc_append(&verptarget,"=")) die_nomem();
+    if (!stralloc_cats(&verptarget,target.s + i + 1)) die_nomem();
+  }
+  if (!stralloc_0(&verptarget)) die_nomem();
+  set_cpverptarget(verptarget.s);
+}
+
+void store_from(frl,adr)
+/* rewrites the from file removing all that is older than 1000000 secs  */
+/* and add the curent from line (frl). Forget it if there is none there.*/
+/* NOTE: This is used only for subscribes to moderated lists!           */
+stralloc *frl; /* from line */
+char *adr;
+{
+  int fdin;
+  int fdout;
+  unsigned long linetime;
+
+  if (!flagstorefrom || !frl->len) return;     /* nothing to store */
+  lock();
+  if ((fdout = open_trunc("fromn")) == -1)
+    strerr_die3sys(111,FATAL,ERR_OPEN,"fromn: ");
+  substdio_fdbuf(&ssfrom,write,fdout,frombuf,(int) sizeof(frombuf));
+  if ((fdin = open_read("from")) == -1) {
+    if (errno != error_noent)
+      strerr_die3sys(111,FATAL,ERR_OPEN,"from: ");
+  } else {
+      substdio_fdbuf(&sstext,read,fdin,textbuf,(int) sizeof(textbuf));
+      for (;;) {
+       if (getln(&sstext,&line,&match,'\n') == -1)
+       strerr_die3sys(111,FATAL,ERR_READ,"from: ");
+       if (!match) break;
+       (void) scan_ulong(line.s,&linetime);
+       if (linetime + 1000000 > when && linetime <= when)
+         if (substdio_bput(&ssfrom,line.s,line.len))
+           strerr_die3sys(111,FATAL,ERR_WRITE,"fromn: ");
+      }
+      close(fdin);
+  }                                    /* build new entry */
+  if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_append(&line," ")) die_nomem();
+  if (!stralloc_cats(&line,adr)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  if (!stralloc_catb(&line,frl->s,frl->len)) die_nomem();
+  if (!stralloc_append(&line,"\n")) die_nomem();
+  if (substdio_bput(&ssfrom,line.s,line.len) == -1)
+    strerr_die3sys(111,FATAL,ERR_WRITE,"fromn: ");
+  if (substdio_flush(&ssfrom) == -1)
+    strerr_die3sys(111,FATAL,ERR_WRITE,"fromn: ");
+  if (fsync(fdout) == -1)
+    strerr_die3sys(111,FATAL,ERR_SYNC,"fromn: ");
+  if (close(fdout) == -1)
+    strerr_die3sys(111,FATAL,ERR_CLOSE,"fromn: ");
+  if (rename("fromn","from") == -1)
+    strerr_die3sys(111,FATAL,ERR_MOVE,"from: ");
+  unlock();
+}
+
+char *get_from(adr,act)
+/* If we captured a from line, it will be from the subscriber, except   */
+/* when -S is used when it's usually from the subscriber, but of course */
+/* could be from anyone. The matching to stored data is required only   */
+/* to support moderated lists, and in cases where a new -sc is issued   */
+/* because an old one was invalid. In this case, we read through the    */
+/* from file trying to match up a timestamp with that starting in       */
+/* *(act+3). If the time stamp matches, we compare the target address   */
+/* itself. act + 3 must be a legal part of the string returns pointer to*/
+/* fromline, NULL if not found. Since the execution time from when to   */
+/* storage may differ, we can't assume that the timestamps are in order.*/
+
+char *adr;             /* target address */
+char *act;             /* action */
+{
+  int fd;
+  char *fl;
+  unsigned int pos;
+  unsigned long thistime;
+  unsigned long linetime;
+
+  if (!flagstorefrom) return 0;
+  if (fromline.len) {  /* easy! We got it in this message */
+    if (!stralloc_0(&fromline)) die_nomem(FATAL);
+    return fromline.s;
+  }                    /* need to recover it from DIR/from */
+  fl = 0;
+  (void) scan_ulong(act+3,&thistime);
+  if ((fd = open_read("from")) == -1)
+    if (errno == error_noent)
+      return 0;
+    else
+      strerr_die3x(111,FATAL,ERR_READ,"from: ");
+  substdio_fdbuf(&sstext,read,fd,textbuf,(int) sizeof(textbuf));
+  for (;;) {
+    if (getln(&sstext,&fromline,&match,'\n') == -1)
+      strerr_die3sys(111,FATAL,ERR_READ,"from: ");
+    if (!match) break;
+    fromline.s[fromline.len - 1] = (char) 0;
+       /* now:time addr\0fromline\0 read all. They can be out of order! */
+    pos = scan_ulong(fromline.s,&linetime);
+    if (linetime != thistime) continue;
+    if (!str_diff(fromline.s + pos + 1,adr)) {
+      pos = str_len(fromline.s);
+      if (pos < fromline.len) {
+       fl = fromline.s + pos + 1;
+       break;
+      }
+    }
+  }
+  close(fd);
+  return fl;
+}
+
+int hashok(action,ac)
 char *action;
 char *action;
+char *ac;
 {
   char *x;
 {
   char *x;
-  unsigned long u;
+  datetime_sec u;
 
 
-  x = action + 4;
+  x = action + 3;
   x += scan_ulong(x,&u);
   hashdate = u;
   if (hashdate > when) return 0;
   if (hashdate < when - 1000000) return 0;
 
   u = hashdate;
   x += scan_ulong(x,&u);
   hashdate = u;
   if (hashdate > when) return 0;
   if (hashdate < when - 1000000) return 0;
 
   u = hashdate;
-  strnum[fmt_ulong(strnum,u)] = 0;
-  cookie(hash,key.s,key.len,strnum,target.s,action + 1);
+  strnum[fmt_ulong(strnum,(unsigned long) u)] = 0;
+  cookie(hash,key.s,key.len - flagdig,strnum,target.s,ac);
 
   if (*x == '.') ++x;
   if (str_len(x) != COOKIE) return 0;
 
   if (*x == '.') ++x;
   if (str_len(x) != COOKIE) return 0;
@@ -77,127 +289,528 @@ int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
   qmail_put(&qq,buf,len);
   return len;
 }
   qmail_put(&qq,buf,len);
   return len;
 }
+
 char qqbuf[1];
 char qqbuf[1];
-substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
 
 
-char inbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
-substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+int code_qput(s,n)
+char *s;
+unsigned int n;
+{
+    if (!flagcd)
+      qmail_put(&qq,s,n);
+    else {
+      if (flagcd == 'B')
+        encodeB(s,n,&qline,0,FATAL);
+      else
+        encodeQ(s,n,&qline,FATAL);
+      qmail_put(&qq,qline.s,qline.len);
+    }
+    return 0;          /* always succeeds */
+}
 
 
-substdio sstext;
-char textbuf[1024];
+int subto(s,l)
+char *s;
+unsigned int l;
+{
+  qmail_put(&qq,"T",1);
+  qmail_put(&qq,s,l);
+  qmail_put(&qq,"",1);
+  return (int) l;
+}
 
 
-void copy(fn)
-char *fn;
+int code_subto(s,l)
+char *s;
+unsigned int l;
 {
 {
-  int fd;
-  int match;
+  code_qput(s,l);
+  code_qput("\n",1);
+  return (int) l;
+}
 
 
-  fd = open_read(fn);
-  if (fd == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
+int dummy_to(s,l)
+char *s;       /* ignored */
+unsigned int l;
+{
+  return (int) l;
+}
 
 
-  substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
-  for (;;) {
-    if (getln(&sstext,&line,&match,'\n') == -1)
-      strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
-
-    if (match)
-      if (line.s[0] == '!') {
-       if (line.s[1] == 'R') {
-         qmail_puts(&qq,"   ");
-         qmail_puts(&qq,confirm.s);
-         qmail_puts(&qq,"\n");
-         continue;
-       }
-       if (line.s[1] == 'A') {
-         qmail_puts(&qq,"   ");
-         qmail_puts(&qq,target.s);
-         qmail_puts(&qq,"\n");
-         continue;
-       }
+void transferenc()
+{
+       if (flagcd) {
+          qmail_puts(&qq,"\n--");
+          qmail_put(&qq,boundary,COOKIE);
+          qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+          qmail_puts(&qq,charset.s);
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"quoted-printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n");
+}
+
+void to_owner()
+{
+       if (!stralloc_copy(&owner,&outlocal)) die_nomem();
+       if (!stralloc_cats(&owner,"-owner@")) die_nomem();
+       if (!stralloc_cat(&owner,&outhost)) die_nomem();
+       if (!stralloc_0(&owner)) die_nomem();
+       qmail_to(&qq,owner.s);
+}
+
+void mod_bottom()
+{
+      copy(&qq,"text/mod-sub",flagcd,FATAL);
+      copy(&qq,"text/bottom",flagcd,FATAL);
+      code_qput(TXT_SUPPRESSED,str_len(TXT_SUPPRESSED));
+      if (flagcd) {
+        qmail_puts(&qq,"\n--");
+        qmail_put(&qq,boundary,COOKIE);
+        qmail_puts(&qq,"--\n");
       }
       }
+      if (flagcd == 'B') {
+        encodeB("",0,&line,2,FATAL);   /* flush */
+        qmail_put(&qq,line.s,line.len);
+      }
+      qmail_from(&qq,from.s);
+}
+void msg_headers()
+               /* Writes all the headers up to but not including subject */
+{
+  int flaggoodfield;
+  int flagfromline;
+  int flaggetfrom;
+  unsigned int pos;
 
 
+  qmail_puts(&qq,"Mailing-List: ");
+  qmail_put(&qq,mailinglist.s,mailinglist.len);
+  if(getconf_line(&line,"listid",0,FATAL,dir)) {
+    qmail_puts(&qq,"\nList-ID: ");
     qmail_put(&qq,line.s,line.len);
     qmail_put(&qq,line.s,line.len);
+  }
+  if (!quote(&quoted,&outlocal)) die_nomem();  /* quoted has outlocal */
+  qmail_puts(&qq,"\nList-Help: <mailto:");     /* General rfc2369 headers */
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"-help@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,">\nList-Post: <mailto:");
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,">\nList-Subscribe: <mailto:");
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"-subscribe@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,">\nDate: ");
+  datetime_tai(&dt,when);
+  qmail_put(&qq,date,date822fmt(date,&dt));
+  qmail_puts(&qq,"Message-ID: <");
+  if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+     die_nomem();
+  if (!stralloc_append(&line,".")) die_nomem();
+  if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+  if (!stralloc_cat(&line,&outhost)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  qmail_puts(&qq,line.s);
+               /* "unique" MIME boundary as hash of messageid */
+  cookie(boundary,"",0,"",line.s,"");
+  qmail_puts(&qq,">\nFrom: ");
+  qmail_put(&qq,quoted.s,quoted.len);
+  if (act == AC_HELP)          /* differnt "From:" for help to break auto- */
+    qmail_puts(&qq,"-return-@");       /* responder loops */
+  else
+    qmail_puts(&qq,"-help@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,"\nTo: ");
+  if (!quote2(&quoted,target.s)) die_nomem();
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"\n");
+  if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem();
+  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
+  if (!stralloc_cats(&mydtline,"@")) die_nomem();
+  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
+  if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+  qmail_put(&qq,mydtline.s,mydtline.len);
 
 
-    if (!match)
-      break;
+  flaggoodfield = 0;
+  flagfromline = 0;
+       /* do it for -sc, but if the -S flag is used, do it for -subscribe */
+  flaggetfrom = flagstorefrom &&
+        ((act == AC_SC) || ((act == AC_SUBSCRIBE) && !flagsubconf));
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (!match) break;
+    if (line.len == 1) break;
+    if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
+      flagfromline = 0;
+      flaggoodfield = 0;
+      if (case_startb(line.s,line.len,"mailing-list:"))
+        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+      if (line.len == mydtline.len)
+       if (byte_equal(line.s,line.len,mydtline.s))
+          strerr_die2x(100,FATAL,ERR_LOOPING);
+      if (case_startb(line.s,line.len,"delivered-to:"))
+        flaggoodfield = 1;
+      else if (case_startb(line.s,line.len,"received:"))
+        flaggoodfield = 1;
+      else if (case_startb(line.s,line.len,"content-transfer-encoding:")) {
+        pos = 26;
+        while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
+        if (case_startb(line.s+pos,line.len-pos,"base64"))
+          encin = 'B';
+        else if (case_startb(line.s+pos,line.len-pos,"quoted-printable"))
+          encin = 'Q';
+      } else if (flaggetfrom && case_startb(line.s,line.len,"from:")) {
+       flagfromline = 1;               /* for logging subscriber data */
+       pos = 5;
+       while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
+        if (!stralloc_copyb(&fromline,line.s + pos,line.len - pos - 1))
+         die_nomem();
+      }
+    } else {
+      if (flagfromline == 1)           /* scrap terminal '\n' */
+        if (!stralloc_catb(&fromline,line.s,line.len - 1)) die_nomem();
+    }
+    if (flaggoodfield)
+      qmail_put(&qq,line.s,line.len);
+  }
+  qmail_puts(&qq,"MIME-Version: 1.0\n");
+  if (flagcd) {
+    qmail_puts(&qq,"Content-Type: multipart/mixed; charset=");
+    qmail_puts(&qq,charset.s);
+    qmail_puts(&qq,";\n\tboundary=");
+    qmail_put(&qq,boundary,COOKIE);
+  } else {
+    qmail_puts(&qq,"Content-type: text/plain; charset=");
+    qmail_puts(&qq,charset.s);
   }
   }
+  qmail_puts(&qq,"\n");
+}
 
 
-  close(fd);
+int geton(action)
+char *action;
+{
+  char *fl;
+  int r;
+  unsigned int i;
+  unsigned char ch;
+
+  fl = get_from(target.s,action);              /* try to match up */
+  switch((r = subscribe(workdir,target.s,1,fl,"+",1,-1,(char *) 0,FATAL))) {
+    case 1:
+           qmail_puts(&qq,"List-Unsubscribe: <mailto:");       /*rfc2369 */
+           qmail_put(&qq,outlocal.s,outlocal.len);
+           qmail_puts(&qq,"-unsubscribe-");
+               /* url-encode since verptarget is controlled by sender */
+               /* note &verptarget ends in '\0', hence len - 1! */
+           for (i = 0; i < verptarget.len - 1; i++) {
+             ch = verptarget.s[i];
+             if (str_chr("\"?;<>&/:%+#",ch) < 10 ||
+                        (ch <= ' ') || (ch & 0x80)) {
+               urlstr[1] = hex[ch / 16];
+               urlstr[2] = hex[ch & 0xf];
+               qmail_put(&qq,urlstr,3);
+             } else {
+               qmail_put(&qq,verptarget.s + i, 1);
+             }
+           }
+           qmail_puts(&qq,"@");
+           qmail_put(&qq,outhost.s,outhost.len);       /* safe */
+           qmail_puts(&qq,">\n");
+            qmail_puts(&qq,TXT_WELCOME);
+           if (!quote(&quoted,&outlocal)) die_nomem();
+            qmail_put(&qq,quoted.s,quoted.len);
+            qmail_puts(&qq,"@");
+            qmail_put(&qq,outhost.s,outhost.len);
+            qmail_puts(&qq,"\n");
+            transferenc();
+           if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
+           if (!stralloc_append(&confirm,"unsubscribe-")) die_nomem();
+           if (!stralloc_cats(&confirm,verptarget.s)) die_nomem();
+           if (!stralloc_append(&confirm,"@")) die_nomem();
+           if (!stralloc_cat(&confirm,&outhost)) die_nomem();
+           if (!stralloc_0(&confirm)) die_nomem();
+           set_cpconfirm(confirm.s);                   /* for !R in copy */
+            copy(&qq,"text/top",flagcd,FATAL);
+            copy(&qq,"text/sub-ok",flagcd,FATAL);
+            break;
+    default:
+            if (str_start(action,ACTION_TC))
+              strerr_die2x(0,INFO,ERR_SUB_NOP);
+            qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+            transferenc();
+            copy(&qq,"text/top",flagcd,FATAL);
+            copy(&qq,"text/sub-nop",flagcd,FATAL);
+            break;
+  }
+  if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
+    strerr_die3x(0,INFO,ERR_EXTRA_SUB,target.s);
+  return r;
 }
 
 }
 
-stralloc mydtline = {0};
+int getoff(action)
+char *action;
+{
+  int r;
+
+  switch((r = subscribe(workdir,target.s,0,"","-",1,-1,(char *) 0,FATAL))) {
+                       /* no comment for unsubscribe */
+    case 1:
+            qmail_puts(&qq,TXT_GOODBYE);
+            if (!quote(&quoted,&outlocal)) die_nomem();
+            qmail_put(&qq,quoted.s,quoted.len);
+            qmail_puts(&qq,"@");
+            qmail_put(&qq,outhost.s,outhost.len);
+            qmail_puts(&qq,"\n\n");
+            transferenc();
+            copy(&qq,"text/top",flagcd,FATAL);
+            copy(&qq,"text/unsub-ok",flagcd,FATAL);
+            break;
+    default:
+            qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+            transferenc();
+            copy(&qq,"text/top",flagcd,FATAL);
+            copy(&qq,"text/unsub-nop",flagcd,FATAL);
+            break;
+  }
+  if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
+    strerr_die3x(0,INFO,ERR_EXTRA_UNSUB,target.s);
+  return r;
+}
 
 
-void main(argc,argv)
+void doconfirm(act)
+/* This should only be called with valid act for sub/unsub confirms. If act */
+/* is not ACTION_SC or ACTION_TC, it is assumed to be an unsubscribe conf.*/
+char *act;     /* first letter of desired confirm request only as STRING! */
+{
+  unsigned int i;
+
+  strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
+  cookie(hash,key.s,key.len-flagdig,strnum,target.s,act);
+  if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
+  if (!stralloc_append(&confirm,"-")) die_nomem();
+  if (!stralloc_catb(&confirm,act,1)) die_nomem();
+  if (!stralloc_cats(&confirm,"c.")) die_nomem();
+  if (!stralloc_cats(&confirm,strnum)) die_nomem();
+  if (!stralloc_append(&confirm,".")) die_nomem();
+  if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem();
+  if (!stralloc_append(&confirm,"-")) die_nomem();
+  if (!stralloc_cats(&confirm,verptarget.s)) die_nomem();
+  if (!stralloc_append(&confirm,"@")) die_nomem();
+  if (!stralloc_cat(&confirm,&outhost)) die_nomem();
+  if (!stralloc_0(&confirm)) die_nomem();
+  set_cpconfirm(confirm.s);            /* for copy */
+
+  qmail_puts(&qq,"Reply-To: ");
+  if (!quote2(&quoted,confirm.s)) die_nomem();
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"\n");
+  if (!stralloc_0(&confirm)) die_nomem();
+
+  qmail_puts(&qq,"Subject: ");
+  if (*act == ACTION_SC[0] || *act == ACTION_UC[0])
+    qmail_puts(&qq,TXT_USRCONFIRM);
+  else
+    qmail_puts(&qq,TXT_MODCONFIRM);
+  if (*act == ACTION_SC[0] || *act == ACTION_TC[0])
+    qmail_puts(&qq,TXT_SUBSCRIBE_TO);
+  else
+    qmail_puts(&qq,TXT_UNSUBSCRIBE_FROM);
+  if (!quote(&quoted,&outlocal)) die_nomem();
+  qmail_put(&qq,quoted.s,quoted.len);
+  qmail_puts(&qq,"@");
+  qmail_put(&qq,outhost.s,outhost.len);
+  qmail_puts(&qq,"\n");
+  transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+}
+
+void sendtomods()
+{
+  putsubs(moddir.s,0L,52L,subto,1,FATAL);
+}
+
+void copybottom()
+{
+  if (flagbottom || act == AC_HELP) {
+    copy(&qq,"text/bottom",flagcd,FATAL);
+    if (flagcd) {
+      if (flagcd == 'B') {
+       encodeB("",0,&line,2,FATAL);    /* flush */
+       qmail_put(&qq,line.s,line.len);
+      }
+      qmail_puts(&qq,"\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"\nContent-Type: message/rfc822");
+      qmail_puts(&qq,"\nContent-Disposition: inline; filename=request.msg\n\n");
+    }
+    qmail_puts(&qq,"Return-Path: <");
+    if (!quote2(&quoted,sender)) die_nomem();
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,">\n");
+    if (seek_begin(0) == -1)
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+    if (substdio_copy(&ssqq,&ssin2) != 0)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (flagcd) {
+      qmail_puts(&qq,"\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"--\n");
+    }
+  } else {
+    if (flagcd == 'B') {
+      encodeB("",0,&line,2,FATAL);     /* flush even if no bottom */
+      qmail_put(&qq,line.s,line.len);
+    }
+  }
+
+  qmail_from(&qq,from.s);
+}
+
+int main(argc,argv)
 int argc;
 char **argv;
 {
 int argc;
 char **argv;
 {
-  char *dir;
-  char *sender;
-  char *host;
   char *local;
   char *local;
+  char *def;
   char *action;
   char *action;
+  char *x, *y;
+  char *fname;
+  char *pmod;
+  char *err;
+  char *cp,*cpfirst,*cplast,*cpnext,*cpafter;
+  int flagmod;
+  int flagremote;
+  int flagpublic;
+  int opt,r;
+  unsigned int i;
+  unsigned int len;
   int fd;
   int fd;
-  int i;
-  int flagconfirm;
-  int flaghashok;
-  int flaggoodfield;
-  int match;
+  int flagdone;
+  register char ch;
 
 
-  umask(022);
+  (void) umask(022);
   sig_pipeignore();
   when = now();
 
   sig_pipeignore();
   when = now();
 
-  dir = argv[1];
+  while ((opt = getopt(argc,argv,"bBcCdDeEfFlLmMnNqQsSuUvV")) != opteof)
+    switch(opt) {
+      case 'b': flagbottom = 1; break;
+      case 'B': flagbottom = 0; break;
+      case 'c': flagget = 1; break;
+      case 'C': flagget = 0; break;
+      case 'd':
+      case 'e': flagedit = 1; break;
+      case 'D':
+      case 'E': flagedit = 0; break;
+      case 'f': flagstorefrom = 1; break;
+      case 'F': flagstorefrom = 0; break;
+      case 'l': flaglist = 1; break;
+      case 'L': flaglist = 0; break;
+      case 'm': flagunsubismod = 1; break;
+      case 'M': flagunsubismod = 0; break;
+      case 'n': flagnotify = 1; break;
+      case 'N': flagnotify = 0; break;
+      case 's': flagsubconf = 1; break;
+      case 'S': flagsubconf = 0; break;
+      case 'q': flagverbose = 0; break;
+      case 'Q': flagverbose++; break;
+      case 'u': flagunsubconf = 1; break;
+      case 'U': flagunsubconf = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-manage version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind];
   if (!dir) die_usage();
 
   sender = env_get("SENDER");
   if (!dir) die_usage();
 
   sender = env_get("SENDER");
-  if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+  if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
   local = env_get("LOCAL");
   local = env_get("LOCAL");
-  if (!local) strerr_die2x(100,FATAL,"LOCAL not set");
-  host = env_get("HOST");
-  if (!host) strerr_die2x(100,FATAL,"HOST not set");
+  if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+  def = env_get("DEFAULT");
 
   if (!*sender)
 
   if (!*sender)
-    strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)");
+    strerr_die2x(100,FATAL,ERR_BOUNCE);
   if (!sender[str_chr(sender,'@')])
   if (!sender[str_chr(sender,'@')])
-    strerr_die2x(100,FATAL,"I don't reply to senders without host names (#5.7.2)");
+    strerr_die2x(100,FATAL,ERR_ANONYMOUS);
   if (str_equal(sender,"#@[]"))
   if (str_equal(sender,"#@[]"))
-    strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)");
+    strerr_die2x(100,FATAL,ERR_BOUNCE);
 
   if (chdir(dir) == -1)
 
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
 
   switch(slurp("key",&key,32)) {
     case -1:
 
   switch(slurp("key",&key,32)) {
     case -1:
-      strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
     case 0:
     case 0:
-      strerr_die3x(100,FATAL,dir,"/key does not exist");
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
   }
   getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
   }
   getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
-  getconf_line(&inhost,"inhost",1,FATAL,dir);
-  getconf_line(&inlocal,"inlocal",1,FATAL,dir);
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  set_cpouthost(&outhost);
+  if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+    if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+      if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+        flagcd = charset.s[charset.len - 1];
+        charset.s[charset.len - 2] = '\0';
+      }
+    }
+  } else
+    if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+  if (!stralloc_0(&charset)) die_nomem();
 
 
-  if (inhost.len != str_len(host)) die_badaddr();
-  if (case_diffb(inhost.s,inhost.len,host)) die_badaddr();
-  if (inlocal.len > str_len(local)) die_badaddr();
-  if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+  if (def)                     /* qmail-1.02 */
+    action = def;              /* .qmail-list-default */
+  else {                       /* older version of qmail */
+    getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+    if (inlocal.len > str_len(local)) die_badaddr();
+    if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+    action = local + inlocal.len;
+    if (*(action++) != '-') die_badaddr();
+                               /* has to be '-' to match link. Check anyway */
+  }
 
 
-  action = local + inlocal.len;
+  if (!stralloc_copys(&ddir,dir)) die_nomem();
 
 
-  switch(slurp("public",&line,1)) {
-    case -1:
-      strerr_die4sys(111,FATAL,"unable to read ",dir,"/public: ");
-    case 0:
-      strerr_die2x(100,FATAL,"sorry, I've been told to reject all requests (#5.7.2)");
+  if (case_starts(action,"digest")) {                  /* digest */
+    action += 6;
+    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
+    if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+    flagdig = FLD_DIGEST;
+  } else if (case_starts(action,ACTION_ALLOW)) {       /* allow */
+    action += str_len(ACTION_ALLOW);
+    if (!stralloc_append(&outlocal,"-")) die_nomem();
+    if (!stralloc_cats(&outlocal,ACTION_ALLOW)) die_nomem();
+    if (!stralloc_cats(&ddir,"/allow")) die_nomem();
+    flagdig = FLD_ALLOW;
+  } else if (case_starts(action,ACTION_DENY)) {                /* deny */
+    action += str_len(ACTION_DENY);
+    if (!stralloc_append(&outlocal,"-")) die_nomem();
+    if (!stralloc_cats(&outlocal,ACTION_DENY)) die_nomem();
+    if (!stralloc_cats(&ddir,"/deny")) die_nomem();
+    flagdig = FLD_DENY;
   }
   }
+  if (flagdig)                         /* zap '-' after db specifier */
+    if (*(action++) != '-') die_badaddr();
+
+  if (!stralloc_0(&ddir)) die_nomem();
+  workdir = ddir.s;
+  set_cpoutlocal(&outlocal);
 
   if (!stralloc_copys(&target,sender)) die_nomem();
   if (action[0]) {
 
   if (!stralloc_copys(&target,sender)) die_nomem();
   if (action[0]) {
-    i = 1 + str_chr(action + 1,'-');
+    i = str_chr(action,'-');
     if (action[i]) {
       action[i] = 0;
       if (!stralloc_copys(&target,action + i + 1)) die_nomem();
     if (action[i]) {
       action[i] = 0;
       if (!stralloc_copys(&target,action + i + 1)) die_nomem();
@@ -207,138 +820,488 @@ char **argv;
     }
   }
   if (!stralloc_0(&target)) die_nomem();
     }
   }
   if (!stralloc_0(&target)) die_nomem();
-  if (!stralloc_copys(&confirm,"")) die_nomem();
+  set_cptarget(target.s);      /* for copy() */
+  make_verptarget();
 
 
-  if (qmail_open(&qq) == -1)
-    strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
+  flagmod = getconf_line(&modsub,"modsub",0,FATAL,dir);
+  flagremote = getconf_line(&remote,"remote",0,FATAL,dir);
 
 
-  qmail_puts(&qq,"Mailing-List: ");
-  qmail_put(&qq,mailinglist.s,mailinglist.len);
-  qmail_puts(&qq,"\nDate: ");
-  datetime_tai(&dt,when);
-  qmail_put(&qq,date,date822fmt(date,&dt));
-  qmail_puts(&qq,"Message-ID: <");
-  qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) when));
-  qmail_puts(&qq,".");
-  qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid()));
-  qmail_puts(&qq,".ezmlm@");
-  qmail_put(&qq,outhost.s,outhost.len);
-  qmail_puts(&qq,">\nFrom: ");
-  if (!quote(&quoted,&outlocal)) die_nomem();
-  qmail_put(&qq,quoted.s,quoted.len);
-  qmail_puts(&qq,"-help@");
-  qmail_put(&qq,outhost.s,outhost.len);
-  qmail_puts(&qq,"\nTo: ");
-  if (!quote2(&quoted,target.s)) die_nomem();
-  qmail_put(&qq,quoted.s,quoted.len);
-  qmail_puts(&qq,"\n");
+  if (case_equals(action,ACTION_LISTN) ||
+               case_equals(action,ALT_LISTN))
+    act = AC_LISTN;
+  else if (case_equals(action,ACTION_LIST) ||
+               case_equals(action,ALT_LIST))
+    act = AC_LIST;
+  else if (case_starts(action,ACTION_GET) ||
+               case_starts(action,ALT_GET))
+    act = AC_GET;
+  else if (case_equals(action,ACTION_HELP) ||
+               case_equals(action,ALT_HELP))
+    act = AC_HELP;
+  else if (case_starts(action,ACTION_EDIT) ||
+               case_starts(action,ALT_EDIT))
+    act = AC_EDIT;
+  else if (case_starts(action,ACTION_LOG))
+   { act = AC_LOG; actlen = str_len(ACTION_LOG); }
+  else if (case_starts(action,ALT_LOG))
+   { act = AC_LOG; actlen = str_len(ALT_LOG); }
 
 
-  flaghashok = 1;
-  if (str_start(action,"-sc.")) flaghashok = hashok(action);
-  if (str_start(action,"-uc.")) flaghashok = hashok(action);
-
-  flagconfirm = 0;
-  if (str_equal(action,"-subscribe")) flagconfirm = 1;
-  if (str_equal(action,"-unsubscribe")) flagconfirm = 1;
-  if (!flaghashok) flagconfirm = 1;
-  
-  if (flagconfirm) {
-    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
-    cookie(hash,key.s,key.len,strnum,target.s,action + 1);
-    if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
-    if (!stralloc_cats(&confirm,"-")) die_nomem();
-    if (!stralloc_catb(&confirm,action + 1,1)) die_nomem();
-    if (!stralloc_cats(&confirm,"c.")) die_nomem();
-    if (!stralloc_cats(&confirm,strnum)) die_nomem();
-    if (!stralloc_cats(&confirm,".")) die_nomem();
-    if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem();
-    if (!stralloc_cats(&confirm,"-")) die_nomem();
-    i = str_rchr(target.s,'@');
-    if (!stralloc_catb(&confirm,target.s,i)) die_nomem();
-    if (target.s[i]) {
-      if (!stralloc_cats(&confirm,"=")) die_nomem();
-      if (!stralloc_cats(&confirm,target.s + i + 1)) die_nomem();
+                       /* NOTE: act is needed in msg_headers(). */
+                       /* Yes, this needs to be cleaned up! */
+
+  if (flagmod || flagremote) {
+    if (modsub.len && modsub.s[0] == '/') {
+      if (!stralloc_copy(&moddir,&modsub)) die_nomem();
+    } else if (remote.len && remote.s[0] == '/') {
+      if (!stralloc_copy(&moddir,&remote)) die_nomem();
+    } else {
+      if (!stralloc_copys(&moddir,dir)) die_nomem();
+      if (!stralloc_cats(&moddir,"/mod")) die_nomem();
     }
     }
-    if (!stralloc_cats(&confirm,"@")) die_nomem();
-    if (!stralloc_cat(&confirm,&outhost)) die_nomem();
-    if (!stralloc_0(&confirm)) die_nomem();
+    if (!stralloc_0(&moddir)) die_nomem();
+               /* for these the reply is 'secret' and goes to sender  */
+               /* This means that they can be triggered from a SENDER */
+               /* that is not a mod, but never send to a non-mod */
+    if (act == AC_NONE || flagdig == FLD_DENY) /* None of the above */
+      pmod = issub(moddir.s,sender,(char *) 0,FATAL);
+                               /* sender = moderator? */
+    else
+      pmod = issub(moddir.s,target.s,(char *) 0,FATAL);
+                               /* target = moderator? */
+   } else
+     pmod = 0;                 /* always 0 for non-mod/remote lists */
+                               /* if DIR/public is missing, we still respond*/
+                               /* to requests from moderators for remote    */
+                               /* admin and modsub lists. Since pmod   */
+                               /* is false for all non-mod lists, only it   */
+                               /* needs to be tested. */
+  if ((flagpublic = slurp("public",&line,1)) == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/public: ");
+  if (!flagpublic && !(pmod && flagremote) &&
+                !case_equals(action,ACTION_HELP))
+      strerr_die2x(100,FATAL,ERR_NOT_PUBLIC);
 
 
-    qmail_puts(&qq,"Reply-To: ");
-    if (!quote2(&quoted,confirm.s)) die_nomem();
-    qmail_put(&qq,quoted.s,quoted.len);
-    qmail_puts(&qq,"\n");
+  if (flagdig == FLD_DENY)
+    if (!pmod || !flagremote)  /* only mods can do */
+      strerr_die1x(100,ERR_NOT_ALLOWED);
+
+  if (act == AC_NONE) {                /* none of the above */
+    if (case_equals(action,ACTION_SUBSCRIBE) ||
+               case_equals(action,ALT_SUBSCRIBE))
+      act = AC_SUBSCRIBE;
+    else if (case_equals(action,ACTION_UNSUBSCRIBE)
+               || case_equals(action,ALT_UNSUBSCRIBE))
+      act = AC_UNSUBSCRIBE;
+    else if (str_start(action,ACTION_SC)) act = AC_SC;
   }
   }
-  if (!stralloc_0(&confirm)) die_nomem();
 
 
-  qmail_puts(&qq,"Subject: ezmlm response\n");
+  if (!stralloc_copy(&from,&outlocal)) die_nomem();
+  if (!stralloc_cats(&from,"-return-@")) die_nomem();
+  if (!stralloc_cat(&from,&outhost)) die_nomem();
+  if (!stralloc_0(&from)) die_nomem();
 
 
-  if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem();
-  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
-  if (!stralloc_cats(&mydtline,"@")) die_nomem();
-  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
-  if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+  if (qmail_open(&qq,(stralloc *) 0) == -1)
+    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+  msg_headers();
 
 
-  qmail_put(&qq,mydtline.s,mydtline.len);
+  if (act == AC_SUBSCRIBE) {
+    if (pmod && flagremote) {
+      doconfirm(ACTION_TC);
+      copy(&qq,"text/mod-sub-confirm",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,pmod);
+    } else if (flagsubconf) {
+      doconfirm(ACTION_SC);
+      copy(&qq,"text/sub-confirm",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,target.s);
+    } else {                           /* normal subscribe, no confirm */
+      r = geton(action);               /* should be rarely used. */
+      copybottom();
+      if (flagnotify) qmail_to(&qq,target.s);
+      if (r && flagverbose > 1) to_owner();
+    }
 
 
-  flaggoodfield = 0;
-  for (;;) {
-    if (getln(&ssin,&line,&match,'\n') == -1)
-      strerr_die2sys(111,FATAL,"unable to read input: ");
-    if (!match) break;
-    if (line.len == 1) break;
-    if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
-      flaggoodfield = 0;
-      if (case_startb(line.s,line.len,"mailing-list:"))
-        strerr_die2x(100,FATAL,"incoming message has Mailing-List (#5.7.2)");
-      if (line.len == mydtline.len)
-       if (byte_equal(line.s,line.len,mydtline.s))
-          strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)");
-      if (case_startb(line.s,line.len,"delivered-to:"))
-        flaggoodfield = 1;
-      if (case_startb(line.s,line.len,"received:"))
-        flaggoodfield = 1;
+  } else if (act == AC_SC) {
+    if (hashok(action,ACTION_SC)) {
+      if (flagmod && !(pmod && str_equal(sender,target.s))) {
+        store_from(&fromline,target.s);        /* save from line, if requested */
+                                       /* since transaction not complete */
+        doconfirm(ACTION_TC);
+        copy(&qq,"text/mod-sub-confirm",flagcd,FATAL);
+        copybottom();
+        sendtomods();
+      } else {
+        r = geton(action);
+        copybottom();
+        qmail_to(&qq,target.s);
+       if (r && flagverbose > 1) to_owner();
+      }
+    } else {
+      doconfirm(ACTION_SC);
+      copy(&qq,"text/sub-bad",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,target.s);
     }
     }
-    if (flaggoodfield)
-      qmail_put(&qq,line.s,line.len);
-  }
-  if (seek_begin(0) == -1)
-    strerr_die2sys(111,FATAL,"unable to seek input: ");
 
 
-  qmail_puts(&qq,"\n");
-  copy("text/top");
-  if (str_equal(action,"-subscribe"))
-    copy("text/sub-confirm");
-  else if (str_equal(action,"-unsubscribe"))
-    copy("text/unsub-confirm");
-  else if (str_start(action,"-sc.")) {
-    if (!flaghashok)
-      copy("text/sub-bad");
-    else
-      switch(subscribe(target.s,1)) {
-        case -1: strerr_die1(111,FATAL,&subscribe_err);
-        case -2: strerr_die1(100,FATAL,&subscribe_err);
-       case 1: log("+",target.s); copy("text/sub-ok"); break;
-       default: copy("text/sub-nop"); break;
+  } else if (str_start(action,ACTION_TC)) {
+    if (hashok(action,ACTION_TC)) {
+      r = geton(action);
+      mod_bottom();
+      if (flagnotify) qmail_to(&qq,target.s);  /* unless suppressed */
+      if (r && flagverbose > 1) to_owner();
+    } else {
+      if (!pmod || !flagremote)        /* else anyone can get a good -tc. */
+        die_cookie();
+      doconfirm(ACTION_TC);
+      copy(&qq,"text/sub-bad",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,pmod);
+    }
+
+  } else if (act == AC_UNSUBSCRIBE) {
+    if (flagunsubconf) {
+      if (pmod && flagremote) {
+        doconfirm(ACTION_VC);
+        copy(&qq,"text/mod-unsub-confirm",flagcd,FATAL);
+        copybottom();
+       qmail_to(&qq,pmod);
+      } else {
+        doconfirm(ACTION_UC);
+        copy(&qq,"text/unsub-confirm",flagcd,FATAL);
+        copybottom();
+        qmail_to(&qq,target.s);
       }
       }
-  }
-  else if (str_start(action,"-uc.")) {
-    if (!flaghashok)
-      copy("text/unsub-bad");
-    else
-      switch(subscribe(target.s,0)) {
-        case -1: strerr_die1(111,FATAL,&subscribe_err);
-        case -2: strerr_die1(100,FATAL,&subscribe_err);
-       case 1: log("-",target.s); copy("text/unsub-ok"); break;
-       default: copy("text/unsub-nop"); break;
+    } else if (flagunsubismod && flagmod) {
+        doconfirm(ACTION_VC);
+        copy(&qq,"text/mod-unsub-confirm",flagcd,FATAL);
+        copybottom();
+        sendtomods();
+    } else {
+      r = getoff(action);
+      copybottom();
+      if (!r || flagnotify) qmail_to(&qq,target.s);
+               /* tell owner if problems (-Q) or anyway (-QQ) */
+      if (flagverbose && (!r || flagverbose > 1)) to_owner();
+    }
+
+  } else if (str_start(action,ACTION_UC)) {
+    if (hashok(action,ACTION_UC)) {
+       /* unsub is moderated only on moderated list if -m unless the */
+       /* target == sender == a moderator */
+      if (flagunsubismod && flagmod) {
+        doconfirm(ACTION_VC);
+        copy(&qq,"text/mod-unsub-confirm",flagcd,FATAL);
+        copybottom();
+        sendtomods();
+      } else {
+        r = getoff(action);
+        copybottom();
+        if (!r || flagnotify) qmail_to(&qq,target.s);
+               /* tell owner if problems (-Q) or anyway (-QQ) */
+       if (flagverbose && (!r || flagverbose > 1)) to_owner();
       }
       }
-  }
-  else if (str_start(action,"-get.")) {
+    } else {
+      doconfirm(ACTION_UC);
+      copy(&qq,"text/unsub-bad",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,target.s);
+    }
+
+  } else if (str_start(action,ACTION_VC)) {
+    if (hashok(action,ACTION_VC)) {
+      r = getoff(action);
+      if (!r && flagmod)
+        strerr_die2x(0,INFO,ERR_UNSUB_NOP);
+      mod_bottom();
+      if (r) {                         /* success to target */
+       qmail_to(&qq,target.s);
+        if (flagverbose > 1) to_owner();
+      } else                           /* NOP to sender = admin. Will take */
+        qmail_to(&qq,sender);          /* care of it. No need to tell owner */
+               /* if list is moderated skip - otherwise bad with > 1 mod */
+    } else {
+      if (!pmod || !flagremote)        /* else anyone can get a good -vc. */
+        die_cookie();
+      doconfirm(ACTION_VC);
+      copy(&qq,"text/unsub-bad",flagcd,FATAL);
+      copybottom();
+      qmail_to(&qq,pmod);
+    }
+
+  } else if (act == AC_LIST || act == AC_LISTN) {
+
+    if (!flaglist || (!flagmod && !flagremote))
+      strerr_die2x(100,FATAL,ERR_NOT_AVAILABLE);
+    if (!pmod)
+      strerr_die2x(100,FATAL,ERR_NOT_ALLOWED);
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+
+    if (act == AC_LIST) {
+      (void) code_qput(TXT_LISTMEMBERS,str_len(TXT_LISTMEMBERS));
+      i = putsubs(workdir,0L,52L,code_subto,1,FATAL);
+    } else                     /* listn */
+      i = putsubs(workdir,0L,52L,dummy_to,1,FATAL);
+
+    (void) code_qput("\n  ======> ",11);
+    (void) code_qput(strnum,fmt_ulong(strnum,i));
+    (void) code_qput("\n",1);
+    copybottom();
+    qmail_to(&qq,pmod);
+
+  } else if (act == AC_LOG) {
+    action += actlen;
+    if (*action == '.' || *action == '_') ++action;
+    if (!flaglist || !flagremote)
+      strerr_die2x(100,FATAL,ERR_NOT_AVAILABLE);
+    if (!pmod)
+      strerr_die2x(100,FATAL,ERR_NOT_ALLOWED);
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    searchlog(workdir,action,code_subto,FATAL);
+    copybottom();
+    qmail_to(&qq,pmod);
+
+  } else if (act == AC_EDIT) {
+       /* only remote admins and only if -e is specified may edit */
+    if (!flagedit || !flagremote)
+      strerr_die2x(100,FATAL,ERR_NOT_AVAILABLE);
+    if (!pmod)
+      strerr_die2x(100,FATAL,ERR_NOT_ALLOWED);
+    len = str_len(ACTION_EDIT);
+    if (!case_starts(action,ACTION_EDIT))
+      len = str_len(ALT_EDIT);
+    if (action[len]) {                 /* -edit.file, not just -edit */
+      if (action[len] != '.')
+        strerr_die2x(100,FATAL,ERR_BAD_REQUEST);
+      if (!stralloc_copys(&fnedit,"text/")) die_nomem();
+      if (!stralloc_cats(&fnedit,action+len+1)) die_nomem();
+      if (!stralloc_0(&fnedit)) die_nomem();
+      case_lowerb(fnedit.s,fnedit.len);
+      i = 5;   /* after the "text/" */
+      while ((ch = fnedit.s[i++])) {
+        if (((ch > 'z') || (ch < 'a')) && (ch != '_'))
+          strerr_die2x(100,FATAL,ERR_BAD_NAME);
+        if (ch == '_') fnedit.s[i-1] = '-';
+      }
+      switch(slurp(fnedit.s,&text,1024)) {     /* entire file! */
+        case -1:
+          strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fnedit.s,": ");
+        case 0:
+          strerr_die5x(100,FATAL,dir,"/",fnedit.s,ERR_NOEXIST);
+      }
+      if (!stralloc_copy(&line,&text)) die_nomem();
+      {                /* get rid of nulls to use cookie */
+        register char *s; register unsigned int n;
+        s = line.s; n = line.len;
+        while(n--) { if (!*s) *s = '_'; ++s; }
+      }
+      if (!stralloc_cat(&line,&fnedit)) die_nomem();   /* including '\0' */
+      strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
+      cookie(hash,key.s,key.len,strnum,line.s,"-e");
+      if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
+      if (!stralloc_append(&confirm,"-")) die_nomem();
+      if (!stralloc_catb(&confirm,ACTION_ED,LENGTH_ED)) die_nomem();
+      if (!stralloc_cats(&confirm,strnum)) die_nomem();
+      if (!stralloc_append(&confirm,".")) die_nomem();
+               /* action part has been checked for bad chars */
+      if (!stralloc_cats(&confirm,action + len + 1)) die_nomem();
+      if (!stralloc_append(&confirm,".")) die_nomem();
+      if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem();
+      if (!stralloc_append(&confirm,"@")) die_nomem();
+      if (!stralloc_cat(&confirm,&outhost)) die_nomem();
+      if (!stralloc_0(&confirm)) die_nomem();
+      set_cpconfirm(confirm.s);
+
+      qmail_puts(&qq,"Reply-To: ");
+      if (!quote2(&quoted,confirm.s)) die_nomem();
+      qmail_put(&qq,quoted.s,quoted.len);
+      qmail_puts(&qq,"\n");
+      if (!stralloc_0(&confirm)) die_nomem();
+
+      qmail_puts(&qq,TXT_EDIT_RESPONSE);
+      qmail_puts(&qq,action+len+1);    /* has the '_' not '-' */
+      qmail_puts(&qq,TXT_EDIT_FOR);
+      if (!quote(&quoted,&outlocal)) die_nomem();
+      qmail_put(&qq,quoted.s,quoted.len);
+      qmail_puts(&qq,"@");
+      qmail_put(&qq,outhost.s,outhost.len);
+      qmail_puts(&qq,"\n");
+      transferenc();
+      copy(&qq,"text/top",flagcd,FATAL);
+      copy(&qq,"text/edit-do",flagcd,FATAL);
+      (void) code_qput(TXT_EDIT_START,str_len(TXT_EDIT_START));
+      (void) code_qput("\n",1);
+      (void) code_qput(text.s,text.len);
+      (void) code_qput(TXT_EDIT_END,str_len(TXT_EDIT_END));
+      (void) code_qput("\n",1);
+
+    } else {   /* -edit only, so output list of editable files */
+      qmail_puts(&qq,TXT_EDIT_LIST);
+      transferenc();
+      copy(&qq,"text/top",flagcd,FATAL);
+      copy(&qq,"text/edit-list",flagcd,FATAL);
+    }
+    qmail_puts(&qq,"\n\n");
+    copybottom();
+    qmail_to(&qq,pmod);
+
+  } else if (str_start(action,ACTION_ED)) {
+    datetime_sec u;
+    int flaggoodfield;
+    x = action + LENGTH_ED;
+    x += scan_ulong(x,&u);
+    if ((u > when) || (u < when - 100000)) die_cookie();
+    if (*x == '.') ++x;
+    fname = x;
+    x += str_chr(x,'.');
+    if (!*x) die_cookie();
+    *x = (char) 0;
+    ++x;
+    if (!stralloc_copys(&fnedit,"text/")) die_nomem();
+    if (!stralloc_cats(&fnedit,fname)) die_nomem();
+    if (!stralloc_0(&fnedit)) die_nomem();
+    y = fnedit.s + 5;          /* after "text/" */
+    while (*++y) {             /* Name should be guaranteed by the cookie, */
+                               /* but better safe than sorry ... */
+      if (((*y > 'z') || (*y < 'a')) && (*y != '_'))
+          strerr_die2x(100,FATAL,ERR_BAD_NAME);
+      if (*y == '_') *y = '-';
+    }
+
+    lock();                    /* file must not change while here */
+
+    switch (slurp(fnedit.s,&text,1024)) {
+      case -1:
+        strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fnedit.s,": ");
+      case 0:
+        strerr_die5x(100,FATAL,dir,"/",fnedit.s,ERR_NOEXIST);
+    }
+    if (!stralloc_copy(&line,&text)) die_nomem();
+    {          /* get rid of nulls to use cookie */
+      register char *s; register unsigned int n;
+      s = line.s; n = line.len;
+      while(n--) { if (!*s) *s = '_'; ++s; }
+    }
+    if (!stralloc_cat(&line,&fnedit)) die_nomem();     /* including '\0' */
+    strnum[fmt_ulong(strnum,(unsigned long) u)] = 0;
+    cookie(hash,key.s,key.len,strnum,line.s,"-e");
+    if (str_len(x) != COOKIE) die_cookie();
+    if (byte_diff(hash,COOKIE,x)) die_cookie();
+       /* cookie is ok, file exists, lock's on, new file ends in '_' */
+    if (!stralloc_copys(&fneditn,fnedit.s)) die_nomem();
+    if (!stralloc_append(&fneditn,"_")) die_nomem();
+    if (!stralloc_0(&fneditn)) die_nomem();
+    fd = open_trunc(fneditn.s);
+    if (fd == -1)
+      strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fneditn.s,": ");
+    substdio_fdbuf(&sstext,write,fd,textbuf,sizeof(textbuf));
+    if (!stralloc_copys(&quoted,"")) die_nomem();      /* clear */
+    if (!stralloc_copys(&text,"")) die_nomem();
+
+    for (;;) {                 /* get message body */
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      if (!stralloc_cat(&text,&line)) die_nomem();
+    }
+    if (encin) {       /* decode if necessary */
+      if (encin == 'B')
+        decodeB(text.s,text.len,&line,FATAL);
+      else
+        decodeQ(text.s,text.len,&line,FATAL);
+      if (!stralloc_copy(&text,&line)) die_nomem();
+    }
+    cp = text.s;
+    cpafter = text.s+text.len;
+    flaggoodfield = 0;
+    flagdone = 0;
+    len = 0;
+    while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
+      i = byte_chr(cp,cpnext-cp,'%');
+      if (i != (unsigned int) (cpnext - cp)) {
+        if (!flaggoodfield) {  /* TXT_EDIT_START/END */
+          if (case_startb(cp+i,cpnext-cp-i,TXT_EDIT_START)) {
+               /* start tag. Store users 'quote characters', e.g. '> ' */
+            if (!stralloc_copyb(&quoted,cp,i)) die_nomem();
+            flaggoodfield = 1;
+            cp = cpnext + 1;
+            cpfirst = cp;
+            continue;
+          }
+        } else
+          if (case_startb(cp+i,cpnext-cp-i,TXT_EDIT_END)) {
+            flagdone = 1;
+            break;
+          }
+      }
+      if (flaggoodfield) {
+        if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT)
+          strerr_die1x(100,ERR_EDSIZE);
+
+        if (quoted.len && cpnext-cp >= (int) quoted.len &&
+                       !str_diffn(cp,quoted.s,quoted.len))
+          cp += quoted.len;    /* skip quoting characters */
+        cplast = cpnext - 1;
+        if (*cplast == '\r')   /* CRLF -> '\n' for base64 encoding */
+          *cplast = '\n';
+        else
+          ++cplast;
+        if (substdio_put(&sstext,cp,cplast-cp+1) == -1)
+            strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fneditn.s,": ");
+      }
+      cp = cpnext + 1;
+    }
+    if (!flagdone)
+      strerr_die2x(100,FATAL,ERR_NO_MARK);
+    if (substdio_flush(&sstext) == -1)
+      strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fneditn.s,": ");
+    if (fsync(fd) == -1)
+      strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/",fneditn.s,": ");
+    if (fchmod(fd, 0600) == -1)
+      strerr_die6sys(111,FATAL,ERR_CHMOD,dir,"/",fneditn.s,": ");
+    if (close(fd) == -1)
+      strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/",fneditn.s,": ");
+    if (rename(fneditn.s,fnedit.s) == -1)
+      strerr_die6sys(111,FATAL,ERR_MOVE,dir,"/",fneditn.s,": ");
+
+    unlock();
+    qmail_puts(&qq,TXT_EDIT_SUCCESS);
+    qmail_puts(&qq,fname);
+    qmail_puts(&qq,TXT_EDIT_FOR);
+    if (!quote(&quoted,&outlocal)) die_nomem();
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,"@");
+    qmail_put(&qq,outhost.s,outhost.len);
+    qmail_puts(&qq,"\n");
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/edit-done",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,sender);      /* not necessarily from mod */
+
+  } else if (act == AC_GET) {
+
     unsigned long u;
     struct stat st;
     char ch;
     int r;
     unsigned long u;
     struct stat st;
     char ch;
     int r;
+    unsigned int pos;
+
+    if (!flagget)
+      strerr_die2x(100,FATAL,ERR_NOT_AVAILABLE);
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+
+    pos = str_len(ACTION_GET);
+    if (!case_starts(action,ACTION_GET))
+      pos = str_len(ALT_GET);
 
 
-    scan_ulong(action + 5,&u);
+    if (action[pos] == '.' || action [pos] == '_') pos++;
+    scan_ulong(action + pos,&u);
 
     if (!stralloc_copys(&line,"archive/")) die_nomem();
     if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100))) die_nomem();
 
     if (!stralloc_copys(&line,"archive/")) die_nomem();
     if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100))) die_nomem();
@@ -349,20 +1312,20 @@ char **argv;
     fd = open_read(line.s);
     if (fd == -1)
       if (errno != error_noent)
     fd = open_read(line.s);
     if (fd == -1)
       if (errno != error_noent)
-       strerr_die4sys(111,FATAL,"unable to open ",line.s,": ");
+       strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
       else
       else
-        copy("text/get-bad");
+        copy(&qq,"text/get-bad",flagcd,FATAL);
     else {
       if (fstat(fd,&st) == -1)
     else {
       if (fstat(fd,&st) == -1)
-       copy("text/get-bad");
+        copy(&qq,"text/get-bad",flagcd,FATAL);
       else if (!(st.st_mode & 0100))
       else if (!(st.st_mode & 0100))
-       copy("text/get-bad");
+        copy(&qq,"text/get-bad",flagcd,FATAL);
       else {
         substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
        qmail_puts(&qq,"> ");
        for (;;) {
          r = substdio_get(&sstext,&ch,1);
       else {
         substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
        qmail_puts(&qq,"> ");
        for (;;) {
          r = substdio_get(&sstext,&ch,1);
-         if (r == -1) strerr_die4sys(111,FATAL,"unable to read ",line.s,": ");
+         if (r == -1) strerr_die4sys(111,FATAL,ERR_READ,line.s,": ");
          if (r == 0) break;
          qmail_put(&qq,&ch,1);
          if (ch == '\n') qmail_puts(&qq,"> ");
          if (r == 0) break;
          qmail_put(&qq,&ch,1);
          if (ch == '\n') qmail_puts(&qq,"> ");
@@ -371,33 +1334,72 @@ char **argv;
       }
       close(fd);
     }
       }
       close(fd);
     }
-  }
-  else
-    copy("text/help");
+    copybottom();
+    qmail_to(&qq,target.s);
 
 
-  copy("text/bottom");
+  } else if (case_starts(action,ACTION_QUERY) ||
+               case_starts(action,ALT_QUERY)) {
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    if (pmod) {        /* pmod points to static storage in issub(). Need to do this */
+               /* before calling issub() again */
+      if (!stralloc_copys(&to,pmod)) die_nomem();
+      if (!stralloc_0(&to)) die_nomem();
+    } else {
+      if (!stralloc_copy(&to,&target)) die_nomem();
+    }
+    if (issub(workdir,target.s,(char *) 0,FATAL))
+      copy(&qq,"text/sub-nop",flagcd,FATAL);
+    else
+      copy(&qq,"text/unsub-nop",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,to.s);
 
 
-  qmail_puts(&qq,"Return-Path: <");
-  if (!quote2(&quoted,sender)) die_nomem();
-  qmail_put(&qq,quoted.s,quoted.len);
-  qmail_puts(&qq,">\n");
-  if (substdio_copy(&ssqq,&ssin2) != 0)
-    strerr_die2sys(111,FATAL,"unable to read input: ");
+  } else if (case_starts(action,ACTION_INFO) ||
+               case_starts(action,ALT_INFO)) {
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/info",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,target.s);
 
 
-  if (!stralloc_copy(&line,&outlocal)) die_nomem();
-  if (!stralloc_cats(&line,"-return-@")) die_nomem();
-  if (!stralloc_cat(&line,&outhost)) die_nomem();
-  if (!stralloc_0(&line)) die_nomem();
-  qmail_from(&qq,line.s);
+  } else if (case_starts(action,ACTION_FAQ) ||
+               case_starts(action,ALT_FAQ)) {
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/faq",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,target.s);
 
 
-  qmail_to(&qq,target.s);
+  } else if (pmod && (act == AC_HELP)) {
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/mod-help",flagcd,FATAL);
+    copy(&qq,"text/help",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,pmod);
 
 
-  switch(qmail_close(&qq)) {
-    case 0:
+  } else {
+    act = AC_HELP;
+    qmail_puts(&qq,TXT_EZMLM_RESPONSE);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/help",flagcd,FATAL);
+    copybottom();
+    qmail_to(&qq,sender);
+  }
+
+  if (*(err = qmail_close(&qq)) == '\0') {
       strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
       strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+      closesql();
       strerr_die2x(0,"ezmlm-manage: info: qp ",strnum);
       strerr_die2x(0,"ezmlm-manage: info: qp ",strnum);
-    default:
-      /* don't worry about undoing actions; everything is idempotent */
-      strerr_die2x(111,FATAL,"temporary qmail-queue error");
+  } else {
+      closesql();
+      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
   }
 }
   }
 }
+
diff --git a/ezmlm-mktab b/ezmlm-mktab
new file mode 120000 (symlink)
index 0000000..feb8cc6
--- /dev/null
@@ -0,0 +1 @@
+sub_std/ezmlm-mktab
\ No newline at end of file
diff --git a/ezmlm-mktab.1 b/ezmlm-mktab.1
new file mode 100644 (file)
index 0000000..e593986
--- /dev/null
@@ -0,0 +1,61 @@
+.TH ezmlm-mktab 1
+.SH NAME
+ezmlm-mktab \- create SQL table definition for ezmlm list
+.SH SYNOPSIS
+.B ezmlm-mktab
+[
+.B \-dC
+]
+.I table_root
+.SH DESCRIPTION
+.B ezmlm-mktab
+takes
+.I table_root
+and prints table definitions for
+.IR table_root ,
+.IR table_root\fB_slog ,
+etc. All subscriber
+and log tables are defined, although normally only a subset are used.
+
+.B ezmlm-mktab
+also can also print the SQL drop commands to remove the same tables.
+.SH OPTIONS
+.TP
+.B \-C
+Do not print the table definitions for list creation. By default, table
+definitions are printed.
+.TP
+.B \-d
+Print table drop commands. Normally, they are omitted. When printed, they
+are printed before the table definitions, so that existing tables are removed,
+then recreated.
+.SH USAGE
+.B ezmlm-mktab
+.B \-d
+.I list \fR | mysql -hhost -uuser -p -f db
+
+This connects to the mysql server on ``host'' as ``user'' (prompting for
+the password) and in database ``db'' creates tables
+.IR list ,
+.IR list\fB_slog ,
+.IR list\fB_mlog ,
+the corresponding table sets for address lists
+.IR list\fB_allow ,
+.IR list\fB_deny ,
+.IR list\fB_digest,
+.IR list\fB_mod,
+as well as
+.IR list\fB_name ,
+.IR list\fB_digest_name ,
+.IR list\fB_cookie ,
+and
+.IR list\fB_digest_cookie .
+
+Since the
+.B \-d
+switch is used, any of these tables already existing are first dropped,
+with loss of any data already in them.
+.SH "SEE ALSO"
+ezmlm-send(1),
+ezmlm(5),
+mysql(1)
diff --git a/ezmlm-moderate.1 b/ezmlm-moderate.1
new file mode 100644 (file)
index 0000000..a05c891
--- /dev/null
@@ -0,0 +1,170 @@
+.TH ezmlm-moderate 1
+.SH NAME
+ezmlm-moderate \- process moderator actions for message
+acceptance and rejection
+.SH SYNOPSIS
+.B ezmlm-moderate [-cCmMrRvV]
+.B [-t\fI reply-to@host\fB]
+.I dir ['/path/program args']
+
+.SH DESCRIPTION
+.B ezmlm-moderate
+reads a mail message, expecting it to contain an
+.I -accept
+or 
+.I -reject
+action request for the mailing list stored in
+.I dir.
+
+.B ezmlm-moderate
+verifies the cookie sent as part of the action request, and if correct
+attempts to find the corresponding message in
+.IR dir\fB/mod/pending/ .
+If the message is found, it is either rejected or posted to the list,
+depending on the action request.
+
+Posts to the list are handled by
+piping the message to
+.B ezmlm-send(1)
+located in the ezmlm binary directory, as set at compile time. This is
+usually the directory that ezmlm-moderate resides in.
+.B ezmlm-send(1)
+is provided with
+.I dir
+as the first argument.
+
+If the optional second argument is given,
+.B ezmlm-moderate
+pipes the message to that program, as executed by sh.
+No parameters are supplied.
+
+.I dir
+is passed as an argument to
+.BR ezmlm-send(1) ,
+but NOT to any program specified as the optional
+.B ezmlm-moderate
+command line argument.
+
+.B ezmlm-moderate
+does not bother to correctly set sender.
+.B ezmlm-send(1)
+doesn't care, and any other program that might be used can parse the
+sender from the first line of the message, which is always
+.I Return-Path: <address@host.domain>
+as build from SENDER originally passed to
+.BR ezmlm-store(1) .
+
+If the message is rejected, an optional moderator comment is copied into the
+notification to the message sender.
+A moderator comment is any text in the
+.I -reject
+request found between two lines with ``%%%'' starting in one of the first
+5 positions of the line. The easiest is to use lines consisting of ``%%%''
+only. If the characters preceeding the ``%%%'' are found at the beginning
+of any lines within the comment, the characters are removed. This is to
+appropriately ignore any ``quote marks'' that you mail program might place at
+the beginning of lines in a reply.
+
+.B ezmlm-moderate
+messages are sent ``From:''
+.IR list-owner@listhost .
+This allows the poster to easily complain to the owner of the list, in case
+s/he objects. An optional ``Reply-To:'' header can be added via the
+.BR \-r\fI\ reply-to@host .
+
+Once the message has been successfully accepted or rejected, it is removed from
+.I dir\fB/mod/pending/
+and a stub is created in
+.I dir\fB/mod/accepted/
+or
+.IR dir\fB/mod/rejected/ ,
+respectively.
+This is done in order to be able to notify the senders of later moderation
+requests about the fate of the message.
+
+A failure to find the message in
+.I dir\fB/mod/pending/
+is most often caused by the message already having been accepted or rejected
+by another moderator. Therefore,
+.B ezmlm-moderate
+looks in
+.I dir\fB/mod/accepted/
+and
+.I dir\fB/mod/rejected/
+for a message stub. If found, 
+.B ezmlm-moderate
+notifies the sender in the form of a fatal error
+if the fate of the message was different from
+that intended by the current action request.
+Otherwise, the fate of the message is silently logged.
+
+If the message is not found, it has timed out and the message or
+the message stub has been removed by
+.BR ezmlm-clean(1) .
+In this case,
+.B ezmlm-moderate
+notifies the moderator of the failure, but can no longer discern the fate
+of the original message. Again, notification is in the form of a fatal
+error from qmail.
+
+At the beginning of the message,
+.B ezmlm-moderate
+prints a new
+.B Mailing-List
+field with the contents of
+.IR dir\fB/mailinglist .
+It rejects the message if there is already a
+.B Mailing-List
+field.
+
+.B ezmlm-moderate
+does not distribute bounce messages:
+if the environment variable
+.B SENDER
+is set, and is either empty or
+.BR #@[] ,
+.B ezmlm-moderate
+rejects the message.
+.SH OPTIONS
+.TP
+.B \-cCrR
+Passed on to ezmlm-send(1).
+.TP
+.B \-m
+(Default.)
+The rejected post is sent as a MIME enclosure.
+.TP
+.B \-M
+The rejected post is appended to the message.
+.TP
+.B \-t\fI reply-to@host
+A ``Reply-To:
+.IR reply-to@host ''
+header will be added to the moderation request.
+.TP
+.TP
+.B \-v
+Display
+.B ezmlm-moderate
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-moderate
+version information.
+.SH "CHARACTER SETS"
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-moderate
+will use the character set listed for all messages. Otherwise, the
+default ``us-ascii'' will be used. The character set can be suffixed
+by ``:'' followed by a code. If the code is ``Q'', outgoing messages are 
+sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded.
+Otherwise, text is sent as is.
+.SH "SEE ALSO"
+ezmlm-clean(1),
+ezmlm-make(1),
+ezmlm-send(1),
+ezmlm-store(1),
+ezmlm(5)
diff --git a/ezmlm-moderate.c b/ezmlm-moderate.c
new file mode 100644 (file)
index 0000000..363d207
--- /dev/null
@@ -0,0 +1,611 @@
+/*$Id: ezmlm-moderate.c,v 1.42 1999/10/09 16:49:56 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "case.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "error.h"
+#include "sig.h"
+#include "fork.h"
+#include "wait.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "seek.h"
+#include "quote.h"
+#include "datetime.h"
+#include "now.h"
+#include "date822fmt.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "auto_bin.h"
+#include "cookie.h"
+#include "errtxt.h"
+#include "copy.h"
+#include "idx.h"
+
+int flagmime = MOD_MIME;       /* default is message as attachment */
+char flagcd = '\0';            /* default: do not use transfer encoding */
+
+#define FATAL "ezmlm-moderate: fatal: "
+#define INFO "ezmlm-moderate: info: "
+
+void die_usage() { strerr_die1x(100,
+    "ezmlm-moderate: usage: ezmlm-moderate [-cCmMrRvV] [-t replyto] "
+    "dir [/path/ezmlm-send]"); }
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badformat() { strerr_die2x(100,FATAL,ERR_BAD_REQUEST); }
+
+void die_badaddr() {
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+stralloc outhost = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc key = {0};
+stralloc mydtline = {0};
+stralloc mailinglist = {0};
+stralloc accept = {0};
+stralloc reject = {0};
+stralloc to = {0};
+stralloc send = {0};
+stralloc sendopt = {0};
+stralloc comment = {0};
+stralloc charset = {0};
+datetime_sec when;
+struct datetime dt;
+
+char strnum[FMT_ULONG];
+char date[DATE822FMT];
+char hash[COOKIE];
+char boundary[COOKIE];
+stralloc line = {0};
+stralloc qline = {0};
+stralloc text = {0};
+stralloc quoted = {0};
+stralloc fnbase = {0};
+stralloc fnmsg = {0};
+stralloc fnnew = {0};
+stralloc fnsub = {0};
+char subbuf[256];
+substdio sssub;
+
+char *dir;
+
+struct stat st;
+
+struct qmail qq;
+
+void code_qput(s,n)
+char *s;
+unsigned int n;
+{
+    if (!flagcd)
+      qmail_put(&qq,s,n);
+    else {
+      if (flagcd == 'B')
+        encodeB(s,n,&qline,0,FATAL);
+      else
+        encodeQ(s,n,&qline,FATAL);
+      qmail_put(&qq,qline.s,qline.len);
+    }
+}
+
+void transferenc()
+{
+       if (flagcd) {
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"Quoted-printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n\n");
+}
+
+int checkfile(fn)
+char *fn;
+/* looks for DIR/mod/{pending|rejected|accept}/fn.*/
+/* Returns:                                       */
+/*          1 found in pending                    */
+/*          0 not found                           */
+/*         -1 found in accepted                   */
+/*         -2 found in rejected                   */
+/* Handles errors.                                */
+/* ALSO: if found, fnmsg contains the o-terminated*/
+/* file name.                                     */
+{
+  
+  if (!stralloc_copys(&fnmsg,"mod/pending/")) die_nomem();
+  if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+  if (!stralloc_0(&fnmsg)) die_nomem();
+  if (stat(fnmsg.s,&st) == -1) {
+    if (errno != error_noent)
+      strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+  } else
+      return 1;
+
+  if (!stralloc_copys(&fnmsg,"mod/accepted/")) die_nomem();
+  if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+  if (!stralloc_0(&fnmsg)) die_nomem();
+  if (stat(fnmsg.s,&st) == -1) {
+    if (errno != error_noent)
+      strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+  } else
+      return -1;
+
+  if (!stralloc_copys(&fnmsg,"mod/rejected/")) die_nomem();
+  if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+  if (!stralloc_0(&fnmsg)) die_nomem();
+  if (stat(fnmsg.s,&st) == -1) {
+    if (errno != error_noent)
+      strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+  } else
+      return -2;
+  return 0;
+}
+
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+
+char inbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+
+substdio sstext;
+char textbuf[1024];
+
+void maketo()
+/* expects line to be a return-path line. If it is and the format is valid */
+/* to is set to to the sender. Otherwise, to is left untouched. Assuming   */
+/* to is empty to start with, it will remain empty if no sender is found.  */
+{
+  unsigned int x, y;
+
+    if (case_startb(line.s,line.len,"return-path:")) {
+      x = 12 + byte_chr(line.s + 12,line.len-12,'<');
+      if (x != line.len) {
+        y = byte_rchr(line.s + x,line.len-x,'>');
+        if (y + x != line.len) {
+          if (!stralloc_copyb(&to,line.s+x+1,y-1)) die_nomem();
+          if (!stralloc_0(&to)) die_nomem();
+        }              /* no return path-> no addressee. A NUL in the sender */
+      }                        /* is no worse than a faked sender, so no problem */
+    }
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *sender;
+  char *def;
+  char *local;
+  char *action;
+  int flaginheader;
+  int flagcomment;
+  int flaggoodfield;
+  int flagdone;
+  int fd, fdlock;
+  int match;
+  char *err;
+  char encin = '\0';
+  char szchar[2] = "-";
+  char *replyto = (char *) 0;
+  unsigned int start,confnum;
+  unsigned int pos,i;
+  int child;
+  int opt;
+  char *sendargs[4];
+  char *cp,*cpnext,*cpfirst,*cplast,*cpafter;
+  int wstat;
+
+  (void) umask(022);
+  sig_pipeignore();
+  when = now();
+
+  if (!stralloc_copys(&sendopt," -")) die_nomem();
+  while ((opt = getopt(argc,argv,"cCmMrRt:T:vV")) != opteof)
+    switch(opt) {      /* pass on ezmlm-send options */
+      case 'c':                        /* ezmlm-send flags */
+      case 'C':
+      case 'r':
+      case 'R':
+        szchar[0] = (char) opt & 0xff;
+        if (!stralloc_append(&sendopt,szchar)) die_nomem();
+        break;
+      case 'm': flagmime = 1; break;
+      case 'M': flagmime = 0; break;
+      case 't':
+      case 'T': if (optarg) replyto = optarg; break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-moderate version: ",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+
+  sender = env_get("SENDER");
+  if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
+  local = env_get("LOCAL");
+  if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+  def = env_get("DEFAULT");
+
+  if (!*sender)
+    strerr_die2x(100,FATAL,ERR_BOUNCE);
+  if (!sender[str_chr(sender,'@')])
+    strerr_die2x(100,FATAL,ERR_ANONYMOUS);
+  if (str_equal(sender,"#@[]"))
+    strerr_die2x(100,FATAL,ERR_BOUNCE);
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  switch(slurp("key",&key,32)) {
+    case -1:
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
+    case 0:
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
+  }
+  getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  set_cpoutlocal(&outlocal);   /* for copy() */
+  set_cpouthost(&outhost);     /* for copy() */
+
+  if (def) {                   /* qmail>=1.02 */
+       /* local should be >= def, but who knows ... */
+    cp = local + str_len(local) - str_len(def) - 2;
+    if (cp < local) die_badformat();
+    action = local + byte_rchr(local,cp - local,'-');
+    if (action == cp) die_badformat();
+    action++;
+  } else {                     /* older versions of qmail */
+    getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+    if (inlocal.len > str_len(local)) die_badaddr();
+    if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+    action = local + inlocal.len;
+    if (*(action++) != '-') die_badaddr();
+  }
+
+  if (!action[0]) die_badformat();
+  if (!str_start(action,ACTION_ACCEPT) && !str_start(action,ACTION_REJECT))
+    die_badformat();
+  start = str_chr(action,'-');
+  if (!action[start]) die_badformat();
+  confnum = 1 + start + str_chr(action + start + 1,'.');
+  if (!action[confnum]) die_badformat();
+  confnum += 1 + str_chr(action + confnum + 1,'.');
+  if (!action[confnum]) die_badformat();
+  if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem();
+  if (!stralloc_0(&fnbase)) die_nomem();
+  cookie(hash,key.s,key.len,fnbase.s,"","a");
+  if (byte_diff(hash,COOKIE,action+confnum+1))
+    die_badformat();
+
+  fdlock = open_append("mod/lock");
+  if (fdlock == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/mod/lock: ");
+  if (lock_ex(fdlock) == -1)
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/mod/lock: ");
+
+  switch(checkfile(fnbase.s)) {
+    case 0:
+      strerr_die2x(100,FATAL,ERR_MOD_TIMEOUT);
+    case -1:                   /* only error if new request != action taken */
+      if (str_start(action,ACTION_ACCEPT))
+        strerr_die2x(0,INFO,ERR_MOD_ACCEPTED);
+      else
+        strerr_die2x(100,FATAL,ERR_MOD_ACCEPTED);
+    case -2:
+      if (str_start(action,ACTION_REJECT))
+        strerr_die2x(0,INFO,ERR_MOD_REJECTED);
+      else
+        strerr_die2x(100,FATAL,ERR_MOD_REJECTED);
+    default:
+      break;
+  }
+/* Here, we have an existing filename in fnbase with the complete path */
+/* from the current dir in fnmsg. */
+
+  if (str_start(action,ACTION_REJECT)) {
+
+    if (qmail_open(&qq, (stralloc *) 0) == -1)
+      strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+
+
+                               /* Build recipient from msg return-path */
+    fd = open_read(fnmsg.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,FATAL,ERR_OPEN,fnmsg.s,": ");
+      else
+        strerr_die2x(100,FATAL,ERR_MOD_TIMEOUT);
+    }
+    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+
+    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    maketo();                  /* extract SENDER from return-path */
+                                               /* Build message */
+    qmail_puts(&qq,"Mailing-List: ");
+    qmail_put(&qq,mailinglist.s,mailinglist.len);
+    if(getconf_line(&line,"listid",0,FATAL,dir)) {
+      qmail_puts(&qq,"\nList-ID: ");
+      qmail_put(&qq,line.s,line.len);
+    }
+    qmail_puts(&qq,"\nDate: ");
+    datetime_tai(&dt,when);
+    qmail_put(&qq,date,date822fmt(date,&dt));
+    qmail_puts(&qq,"Message-ID: <");
+    if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+       die_nomem();
+    if (!stralloc_append(&line,".")) die_nomem();
+    if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+    if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+    if (!stralloc_cat(&line,&outhost)) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+    qmail_puts(&qq,line.s);
+               /* "unique" MIME boundary as hash of messageid */
+    cookie(boundary,"",0,"",line.s,"");
+    qmail_puts(&qq,">\nFrom: ");
+    if (!quote(&quoted,&outlocal)) die_nomem();
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,"-owner@");
+    qmail_put(&qq,outhost.s,outhost.len);
+    if (replyto) {
+      qmail_puts(&qq,"\nReply-To: ");
+      qmail_puts(&qq,replyto);
+    }
+    qmail_puts(&qq, "\nTo: ");
+    qmail_puts(&qq,to.s);
+    qmail_puts(&qq,"\nSubject: ");
+    qmail_puts(&qq,TXT_RETURNED_POST);
+    qmail_put(&qq,quoted.s,quoted.len);
+    qmail_puts(&qq,"@");
+    qmail_put(&qq,outhost.s,outhost.len);
+
+    if (flagmime) {
+      if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+        if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+          if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+            flagcd = charset.s[charset.len - 1];
+            charset.s[charset.len - 2] = '\0';
+          }
+        }
+      } else
+        if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+      if (!stralloc_0(&charset)) die_nomem();
+      qmail_puts(&qq,"\nMIME-Version: 1.0\n");
+      qmail_puts(&qq,"Content-Type: multipart/mixed;\n\tboundary=");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"\n\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+      qmail_puts(&qq,charset.s);
+      transferenc();
+    }
+    copy(&qq,"text/top",flagcd,FATAL);
+    copy(&qq,"text/mod-reject",flagcd,FATAL);
+
+    flagcomment = 0;
+    flaginheader = 1;
+    if (!stralloc_copys(&text,"")) die_nomem();
+    if (!stralloc_ready(&text,1024)) die_nomem(); 
+    for (;;) {         /* copy moderator's rejection comment */
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      if (flaginheader) {
+        if (case_startb(line.s,line.len,"Content-Transfer-Encoding:")) {
+          pos = 26;
+          while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
+          if (case_startb(line.s+pos,line.len-pos,"base64"))
+            encin = 'B';
+          else if (case_startb(line.s+pos,line.len-pos,"quoted-printable"))
+            encin = 'Q';
+        }
+        if (line.len == 1)
+          flaginheader = 0;
+      } else
+        if (!stralloc_cat(&text,&line)) die_nomem();
+    }  /* got body */
+    if (encin) {
+      if (encin == 'B')
+        decodeB(text.s,text.len,&line,FATAL);
+      else
+        decodeQ(text.s,text.len,&line,FATAL);
+      if (!stralloc_copy(&text,&line)) die_nomem();
+    }
+    cp = text.s;
+    cpafter = text.s + text.len;
+    if (!stralloc_copys(&line,"\n>>>>> -------------------- >>>>>\n"))
+                       die_nomem();
+    flaggoodfield = 0;
+    flagdone = 0;
+    while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
+      i = byte_chr(cp,cpnext-cp,'%');
+      if (i <= 5 && cpnext-cp >= 8) {
+                               /* max 5 "quote characters" and space for %%% */
+        if (cp[i+1] == '%' && cp[i+2] == '%') {
+          if (!flaggoodfield) {                                        /* Start tag */
+            if (!stralloc_copyb(&quoted,cp,i)) die_nomem();    /* quote chars*/
+            flaggoodfield = 1;
+            cp = cpnext + 1;
+            cpfirst = cp;
+            continue;
+          } else {                                             /* end tag */
+            if (flagdone)      /* 0 no comment lines, 1 comment line */
+              flagdone = 2;    /* 2 at least 1 comment line & end tag */
+            break;
+          }
+        }
+      }
+      if (flaggoodfield) {
+        cplast = cpnext - 1;
+        if (*cplast == '\r')   /* CRLF -> '\n' for base64 encoding */
+          *cplast = '\n';
+        else
+          ++cplast;
+                       /* NUL is now ok, so the test for it was removed */
+        flagdone = 1;
+        i = cplast - cp + 1;
+        if (quoted.len && quoted.len <= i &&
+               !str_diffn(cp,quoted.s,quoted.len)) {   /* quote chars */
+          if (!stralloc_catb(&line,cp+quoted.len,i-quoted.len)) die_nomem();
+        } else
+          if (!stralloc_catb(&line,cp,i)) die_nomem(); /* no quote chars */
+      }
+      cp = cpnext + 1;
+    }
+    if (flagdone == 2) {
+    if (!stralloc_cats(&line,"<<<<< -------------------- <<<<<\n")) die_nomem();
+      code_qput(line.s,line.len);
+    }
+    if (flagcd == 'B') {
+      encodeB("",0,&line,2,FATAL);
+      qmail_put(&qq,line.s,line.len);
+    }
+    if (flagmime) {
+      qmail_puts(&qq,"\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n");
+    } else
+      qmail_puts(&qq,"\n");
+    if (seek_begin(fd) == -1)
+      strerr_die4sys(111,FATAL,ERR_SEEK,fnmsg.s,": ");
+
+    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+    if (substdio_copy(&ssqq,&sstext) != 0)
+      strerr_die4sys(111,FATAL,ERR_READ,fnmsg.s,": ");
+    close(fd);
+
+    if (flagmime) {
+      qmail_puts(&qq,"\n--");
+      qmail_put(&qq,boundary,COOKIE);
+      qmail_puts(&qq,"--\n");
+    }
+
+    if (!stralloc_copy(&line,&outlocal)) die_nomem();
+    if (!stralloc_cats(&line,"-return-@")) die_nomem();
+    if (!stralloc_cat(&line,&outhost)) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+    qmail_from(&qq,line.s);
+    if (to.len)
+      qmail_to(&qq,to.s);
+
+    if (!stralloc_copys(&fnnew,"mod/rejected/")) die_nomem();
+    if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
+    if (!stralloc_0(&fnnew)) die_nomem();
+
+/* this is strictly to track what happended to a message to give informative */
+/* messages to the 2nd-nth moderator that acts on the same message. Since    */
+/* this isn't vital we ignore errors. Also, it is no big ideal if unlinking  */
+/* the old file fails. In the worst case it gets acted on again. If we issue */
+/*  a temp error the reject will be redone, which is slightly worse.         */
+
+    if (*(err = qmail_close(&qq)) == '\0') {
+        fd = open_trunc(fnnew.s);
+        if (fd != -1)
+          close(fd);
+        unlink(fnmsg.s);
+        strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+        strerr_die2x(0,"ezmlm-moderate: info: qp ",strnum);
+    } else
+        strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+
+  } else if (str_start(action,ACTION_ACCEPT)) {
+        fd = open_read(fnmsg.s);
+        if (fd == -1)
+          if (errno !=error_noent)
+            strerr_die4sys(111,FATAL,ERR_OPEN,fnmsg.s,": ");
+          else /* shouldn't happen since we've got lock */
+            strerr_die3x(100,FATAL,fnmsg.s,ERR_MOD_TIMEOUT);
+
+    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+                               /* read "Return-Path:" line */
+    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    maketo();                  /* extract SENDER to "to" */
+    env_put2("SENDER",to.s);   /* set SENDER */
+    if (seek_begin(fd) == -1)  /* rewind, since we read an entire buffer */
+      strerr_die4sys(111,FATAL,ERR_SEEK,fnmsg.s,": ");
+
+/* ##### NO REASON TO USE SH HERE ##### */
+        sendargs[0] = "/bin/sh";
+        sendargs[1] = "-c";
+        if (argc > optind) {
+          sendargs[2] = argv[optind];
+        } else {
+          if (!stralloc_copys(&send,auto_bin)) die_nomem();
+          if (!stralloc_cats(&send,"/ezmlm-send")) die_nomem();
+          if (sendopt.len > 2)
+            if (!stralloc_cat(&send,&sendopt)) die_nomem();
+          if (!stralloc_cats(&send," '")) die_nomem();
+          if (!stralloc_cats(&send,dir)) die_nomem();
+          if (!stralloc_cats(&send,"'")) die_nomem();
+          if (!stralloc_0(&send)) die_nomem();
+          sendargs[2] = send.s;
+        }
+        sendargs[3] = 0;
+
+    switch(child = fork()) {
+      case -1:
+        strerr_die2sys(111,FATAL,ERR_FORK);
+      case 0:          /* child */
+        close(0);
+        dup(fd);       /* make fnmsg.s stdin */
+        execv(*sendargs,sendargs);
+        if (errno == error_txtbsy || errno == error_nomem ||
+            errno == error_io)
+          strerr_die5sys(111,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+        else
+          strerr_die5sys(100,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+       }
+         /* parent */
+      wait_pid(&wstat,child);
+      close(fd);
+      if (wait_crashed(wstat))
+        strerr_die3x(111,FATAL,sendargs[2],ERR_CHILD_CRASHED);
+      switch(wait_exitcode(wstat)) {
+        case 100:
+          strerr_die2x(100,FATAL,"Fatal error from child");
+        case 111:
+           strerr_die2x(111,FATAL,"Temporary error from child");
+        case 0:
+          break;
+        default:
+          strerr_die2x(111,FATAL,"Unknown temporary error from child");
+      }
+      if (!stralloc_copys(&fnnew,"mod/accepted/")) die_nomem();
+
+      if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
+      if (!stralloc_0(&fnnew)) die_nomem();
+/* ignore errors */
+      fd = open_trunc(fnnew.s);
+      if (fd != -1)
+        close(fd);
+      unlink(fnmsg.s);
+      _exit(0);
+   }
+}
diff --git a/ezmlm-receipt.1 b/ezmlm-receipt.1
new file mode 100644 (file)
index 0000000..cc6531c
--- /dev/null
@@ -0,0 +1,129 @@
+.TH ezmlm-receipt 1
+.SH NAME
+ezmlm-receipt \- handle sublist replies at the main list
+.SH SYNOPSIS
+.B ezmlm-receipt
+[
+.B \-dD
+]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-receipt
+handles mail from sublists of the main list
+stored in
+.I dir
+and, if it exists, the associated main digest list.
+.B ezmlm-receipt
+is used for main list with only sublists as subscribers. It is not
+useful for normal mailing lists.
+
+.B ezmlm-receipt
+is normally invoked from a
+.B .qmail
+file.
+It reads a mail message from its standard input,
+and a mail envelope from the
+.BR SENDER ,
+.BR LOCAL ,
+and
+.BR HOST
+environment variables.
+
+.B ezmlm-receipt
+has two functions. It takes the place of
+.B ezmlm-receipt(1)
+for main lists that have only sublists as subscribers.
+Bounces do not lead to removal of the bouncing
+address.
+.B emzlm-receipt
+saves the
+bounce, and logs the event to the mail log.
+.B ezmlm-receipt
+also saves the bounce to
+.I dir\fB/bounce/dnnn.ppp
+where
+.B nnn
+is a time stamp and
+.B ppp
+the PID of the process. A maximum of 50 bounces are saved. Further bounces
+are discarded until room is made in the bounce directory by manually removing
+files.
+If the list uses and SQL
+database, the even is logged to the _mlog table instead, and only if the
+distribution cookie matches. The bounce is still saved, but only if it
+contained a matching distribution cookie.
+
+.B ezmlm-receipt
+also handles feedback messages from the sublist. These are used to monitor
+that the sublist is able to send out messages. Receipt of feedback messages
+is logged to the mail log.
+If the list uses and SQL
+database, the even is logged to the _mlog table instead, and only if the
+distribution cookie matches.
+.SH OPTIONS
+.TP
+.B \-d
+.B ezmlm-receipt
+will assume the message is for a digest list.
+Normally,
+.B ezmlm-receipt
+will autodetect this from the bounce address. Autodetection makes
+.B ezmlm-receipt
+less flexible and will be removed in future versions.
+.TP
+.B \-D
+.B ezmlm-receipt
+will assume that the bounce is for a normal (non-digest) list.
+Normally,
+.B ezmlm-receipt
+will autodetect this from the bounce address. Autodetection makes
+.B ezmlm-receipt
+less flexible and will be removed in future versions.
+.B \-D
+will become the default.
+.SH ADDRESSES
+.B ezmlm-receipt
+handles mail sent to any of the following addresses:
+.TP
+.I local\fB\-return\-
+Trash.
+A help message or subscription acknowledgment bounced.
+.TP
+.I local\fB\-return\-\fImsg\fB\-\fIbox\fB=\fIdomain
+Distribution bounce.
+Message number
+.I msg
+was lost on the way to the sublist
+.IR box\fB@\fIdomain .
+.TP
+.I local\fB\-return\-\fImsg\fB\-
+Pre-VERP distribution bounce, in QSBMF format.
+Message number
+.I msg
+was lost on the way to one or more sublists;
+.B ezmlm-receipt
+will parse the bounce to figure out the addresses.
+.TP
+.I local\fB\-return\-receipt
+Feedback message from a sublist.
+.B ezmlm-receipt
+will figure out message number and sublist address from the envelope sender.
+
+For all the above addresses if,
+.I local
+is followed by
+.IR \-digest ,
+messages are assumed to relate to the digest list, and are stored in
+.I dir\fB/digest/bounce
+rather than in
+.I dir \fB/bounce .
+.SH "SEE ALSO"
+ezmlm-manage(1),
+ezmlm-make(1),
+ezmlm-return(1),
+ezmlm-send(1),
+ezmlm-sub(1),
+ezmlm-unsub(1),
+ezmlm-weed(1),
+ezmlm(5),
+qmail-command(8)
diff --git a/ezmlm-receipt.c b/ezmlm-receipt.c
new file mode 100644 (file)
index 0000000..7b664f9
--- /dev/null
@@ -0,0 +1,374 @@
+/*$Id: ezmlm-receipt.c,v 1.10 1999/02/05 04:57:44 lindberg Exp $*/
+/*$Name: ezmlm-idx-0324 $*/
+/* Handles receipts and bounces from sublists at the main list */
+/* Set up instead of ezmlm-return in DIR/bouncer of main list */
+
+#include <sys/types.h>
+#include "direntry.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "case.h"
+#include "quote.h"
+#include "getln.h"
+#include "substdio.h"
+#include "error.h"
+#include "readwrite.h"
+#include "fmt.h"
+#include "now.h"
+#include "seek.h"
+#include "idx.h"
+#include "errtxt.h"
+
+#define FATAL "ezmlm-receipt: fatal: "
+#define INFO "ezmlm-receipt: info: "
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-receipt: usage: ezmlm-receipt [-dD] dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badaddr()
+{
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+void die_trash()
+{
+  strerr_die2x(0,INFO,"trash address");
+}
+
+stralloc line = {0};
+stralloc quoted = {0};
+stralloc intro = {0};
+stralloc bounce = {0};
+stralloc header = {0};
+stralloc failure = {0};
+stralloc paragraph = {0};
+stralloc ddir = {0};
+stralloc outhost = {0};
+stralloc outlocal = {0};
+stralloc inlocal = {0};
+stralloc tagline = {0};
+stralloc listaddr = {0};
+stralloc fndate = {0};
+stralloc fndir = {0};
+stralloc fndatenew = {0};
+
+void die_datenew()
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); }
+void die_msgin()
+{ strerr_die2sys(111,FATAL,ERR_READ_INPUT); }
+
+char strnum[FMT_ULONG];
+char inbuf[1024];
+substdio ssin;
+
+char outbuf[256];      /* small - rarely used */
+substdio ssout;
+
+unsigned long when;
+unsigned long addrno = 0L;
+
+char *sender;
+char *dir;
+char *workdir;
+void **psql = (void **) 0;
+stralloc listno = {0};
+
+
+void doit(addr,msgnum,when,bounce)
+/* Just stores address\0nsgnum\0 followed by bounce. File name is          */
+/* dttt.ppp[.n], where 'ttt' is a time stamp, 'ppp' the pid, and 'n' the   */
+/* number when there are more than 1 addresses in a pre-VERP bounce. In    */
+/* this case, the first one is just dttt.ppp, the decond dttt.ppp.2, etc.  */
+/* For a main list, bounces come from sublists. They are rare and serious. */
+char *addr;
+unsigned long msgnum;
+unsigned long when;
+stralloc *bounce;
+{
+  int fd;
+  unsigned int pos;
+  DIR *bouncedir;
+  direntry *d;
+  unsigned int no;
+
+  if (!stralloc_copys(&fndir,workdir)) die_nomem();
+  if (!stralloc_cats(&fndir,"/bounce")) die_nomem();
+  if (!stralloc_0(&fndir)) die_nomem();
+  bouncedir = opendir(fndir.s);
+  if (!bouncedir)
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+    else
+      strerr_die3x(111,FATAL,fndir.s,ERR_NOEXIST);
+
+  no = MAX_MAIN_BOUNCES;       /* no more than this many allowed */
+  while (no && (d = readdir(bouncedir))) {
+    if (str_equal(d->d_name,".")) continue;
+    if (str_equal(d->d_name,"..")) continue;
+    --no;
+  }
+  closedir(bouncedir);
+  if (!no)                     /* max no of bounces exceeded */
+    strerr_die2x(0,INFO,ERR_MAX_BOUNCE);
+                               /* save bounce */
+  if (!stralloc_copys(&fndate,workdir)) die_nomem();
+  if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+  pos = fndate.len - 1;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_cats(&fndate,".")) die_nomem();
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+        die_nomem();
+  if (addrno) {        /* so that pre-VERP bounces make a d... file per address */
+               /* for the first one we use the std-style fname */
+    if (!stralloc_cats(&fndate,".")) die_nomem();
+    if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem();
+  }
+  addrno++;    /* get ready for next */
+  if (!stralloc_0(&fndate)) die_nomem();
+  if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
+  fndatenew.s[pos] = 'D';
+
+  fd = open_trunc(fndatenew.s);
+  if (fd == -1) die_datenew();
+  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
+  if (substdio_puts(&ssout,addr) == -1) die_datenew();
+  if (substdio_put(&ssout,"",1) == -1) die_datenew();
+  if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1)
+       die_datenew();
+  if (substdio_put(&ssout,"",1) == -1) die_datenew();
+
+  if (substdio_puts(&ssout,"Return-Path: <") == -1) die_datenew();
+  if (!quote2(&quoted,sender)) die_nomem();
+  if (substdio_put(&ssout,quoted.s,quoted.len) == -1) die_datenew();
+  if (substdio_puts(&ssout,">\n") == -1) die_datenew();
+  if (substdio_put(&ssout,bounce->s,bounce->len) == -1) die_datenew();
+  if (substdio_flush(&ssout) == -1) die_datenew();
+  if (fsync(fd) == -1) die_datenew();
+  if (close(fd) == -1) die_datenew(); /* NFS stupidity */
+  if (rename(fndatenew.s,fndate.s) == -1)
+    strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *local;
+  char *host;
+  char *action;
+  char *def;
+  int flagdig = 1;
+  int flaghaveintro;
+  int flaghaveheader;
+  int match;
+  unsigned long msgnum;
+  unsigned int i;
+  unsigned int len;
+  char *cp;
+
+  umask(022);
+  sig_pipeignore();
+
+  when = (unsigned long) now();
+
+  dir = argv[1];
+  if (!dir) die_usage();
+  if (*dir == '-') {
+    if (dir[1] == 'd') {
+      flagdig = 2;
+    } else if (dir[1] == 'D') {
+      flagdig = 0;
+    } else
+      die_usage();
+    dir = argv[2];
+    if (!dir) die_usage();
+  }
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  sender = env_get("SENDER");
+  def = env_get("DEFAULT");
+  local = env_get("LOCAL");
+
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  workdir = dir;
+  if (def) {                           /* qmail>=1.02 */
+    action = def;                      /* now see if -digest-return- */
+    if (flagdig == 1) {
+      flagdig = 0;
+      if (str_len(local) >= str_len(def) + 14)
+       if (str_start(local + str_len(local) - 14 - str_len(def),"digest-"))
+         flagdig = 2;
+    }
+  } else {                             /* older version of qmail */
+    getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+    if (inlocal.len > str_len(local)) die_badaddr();
+    if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+    action = local + inlocal.len;
+    if (flagdig == 1) {
+      flagdig = 0;
+      if (str_start(action,"-digest")) {
+       flagdig = 2;
+       action += 7;
+      }
+    }
+    if (!str_start(action,"-return-")) die_badaddr();
+    action += 8;
+  }
+  if (flagdig) {
+    if (!stralloc_copys(&ddir,dir)) die_nomem();
+    if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+    if (!stralloc_0(&ddir)) die_nomem();
+    workdir = ddir.s;
+    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
+  }
+  if (!*action) die_trash();
+
+  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+
+  if (!case_diffs(action,"receipt")) {
+    host = sender + str_rchr(sender,'@');
+    if (*host)
+      *(host++) = '\0';
+    cp = sender;
+                               /* check recipient in case it's a bounce*/
+    while (*(cp++)) {          /* decode sender */
+      cp += str_chr(cp,'-');
+      if (case_starts(cp,"-return-")) {
+        if (!scan_ulong(cp + 8,&msgnum))
+          strerr_die2x(100,FATAL,"bad VERP format for receipt");
+         *cp = '\0';
+        if (!stralloc_copys(&listaddr,sender)) die_nomem();
+        if (!stralloc_append(&listaddr,"@")) die_nomem();
+        if (!stralloc_cats(&listaddr,host)) die_nomem();
+        if (!stralloc_0(&listaddr)) die_nomem();
+        break;
+      }
+    }
+    for(;;) {                                          /* Get X-tag from hdr*/
+      if (getln(&ssin,&line,&match,'\n') == -1) die_msgin();
+      if (!match)
+        break;
+
+      if (line.len == 1) break;
+      if (case_startb(line.s,line.len,TXT_TAG)) {
+       len = str_len(TXT_TAG);
+        if (!stralloc_catb(&tagline,line.s +len,line.len - len -1)) die_nomem();
+               /* NOTE: tagline is dirty! We quote it for sql and rely on */
+               /* std log clean for maillog */
+        break;
+      }
+    }
+               /* feedback ok even if not sub. Will be filtered by subreceipt*/
+               /* For instance, main list feedback is ok, but !issub. */
+    subreceipt(workdir,msgnum,&tagline,listaddr.s,2,INFO,FATAL);
+    closesql();
+    _exit(0);
+  }
+                               /* not receipt - maybe bounce */
+                               /* no need to lock. dttt.pid can be assumed */
+                               /* to be unique and if not would be over- */
+                               /* written even with lock */
+  action += scan_ulong(action,&msgnum);
+  if (*action != '-') die_badaddr();
+  ++action;
+               /* scan bounce for tag. It'll be in the BODY! */
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (!match) break;
+    if (case_startb(line.s,line.len,TXT_TAG)) {
+      len = str_len(TXT_TAG);
+      if (!stralloc_catb(&tagline,line.s +len,line.len - len -1)) die_nomem();
+               /* NOTE: tagline is dirty! We quote it for sql and rely on */
+               /* std log clean for maillog */
+      break;
+    }
+  }
+  if (seek_begin(0) == -1)
+    strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+
+  if (*action) {       /* normal bounce */
+
+    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+    i = str_rchr(action,'=');
+    if (!stralloc_copyb(&listaddr,action,i)) die_nomem();
+    if (action[i]) {
+      if (!stralloc_cats(&listaddr,"@")) die_nomem();
+      if (!stralloc_cats(&listaddr,action + i + 1)) die_nomem();
+    }
+    if (!stralloc_0(&listaddr)) die_nomem();
+               /* don't check for sub, since issub() doesn't see sublists */
+    switch (subreceipt(workdir,msgnum,&tagline,listaddr.s,-1,INFO,FATAL)) {
+       case -1: strerr_die2x(0,INFO,ERR_COOKIE);
+       case -2: strerr_die2x(0,INFO,ERR_NOT_ACTIVE);
+       default: doit(listaddr.s,msgnum,when,&bounce);
+    }
+    closesql();
+    _exit(0);
+  }                    /* pre-VERP bounce, in QSBMF format */
+
+  flaghaveheader = 0;
+  flaghaveintro = 0;
+
+  for (;;) {
+    if (!stralloc_copys(&paragraph,"")) die_nomem();
+    for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) die_trash();
+      if (!stralloc_cat(&paragraph,&line)) die_nomem();
+      if (line.len <= 1) break;
+    }
+
+    if (!flaghaveheader) {
+      if (!stralloc_copy(&header,&paragraph)) die_nomem();
+      flaghaveheader = 1;
+      continue;
+    }
+
+    if (!flaghaveintro) {
+      if (paragraph.s[0] == '-' && paragraph.s[1] == '-')
+        continue;              /* skip MIME boundary if it exists */
+      if (paragraph.len < 15) die_trash();
+      if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
+      if (!stralloc_copy(&intro,&paragraph)) die_nomem();
+      flaghaveintro = 1;
+      continue;
+    }
+
+    if (paragraph.s[0] == '-')
+      break;
+
+    if (paragraph.s[0] == '<') {       /* find address */
+      if (!stralloc_copy(&failure,&paragraph)) die_nomem();
+
+      if (!stralloc_copy(&bounce,&header)) die_nomem();
+      if (!stralloc_cat(&bounce,&intro)) die_nomem();
+      if (!stralloc_cat(&bounce,&failure)) die_nomem();
+
+      i = byte_chr(failure.s,failure.len,'\n');
+      if (i < 3) die_trash();
+
+      if (!stralloc_copyb(&listaddr,failure.s + 1,i - 3)) die_nomem();
+      if (byte_chr(listaddr.s,listaddr.len,'\0') == listaddr.len) {
+        if (!stralloc_0(&listaddr)) die_nomem();
+        if (subreceipt(workdir,msgnum,&tagline,listaddr.s,-1,INFO,FATAL) == 0)
+         doit(listaddr.s,msgnum,when,&bounce);
+      }
+    }
+  }
+  closesql();
+  _exit(0);
+}
+
index cb8cb7a..643ceb8 100644 (file)
@@ -4,29 +4,149 @@ ezmlm-reject \- reject messages unsuitable for distribution
 .SH SYNOPSIS
 .B ezmlm-reject
 [
 .SH SYNOPSIS
 .B ezmlm-reject
 [
-.B \-cCsS
+.B \-bBcChHqQsStT
+][
+.I dir
 ]
 .SH DESCRIPTION
 .B ezmlm-reject
 reads a mail message from its standard input.
 It rejects the message if it sees something it doesn't like.
 ]
 .SH DESCRIPTION
 .B ezmlm-reject
 reads a mail message from its standard input.
 It rejects the message if it sees something it doesn't like.
+
+If the message has a ``Precedence: junk'' header,
+.B ezmlm-reject
+exits 99 causing the message to be ignored. This causes replies from (some)
+vacation programs to be ignored.
+
+If
+.I dir
+is specified,
+.B ezmlm-reject
+reads
+.I dir\fB/msgsize
+for a maximum:minimum message body size in bytes. Either number will be ignored
+if 0 or omitted.
+.B ezmlm-reject
+will also look for
+.I dir\fB/mimereject
+and 
+.IR dir\fB/mimeremove .
+if
+.IR dir\fB/mimereject
+exists,
+Messages of the Content-Types specified or with MIME parts of these
+types will be rejected.
+If
+.I dir\fB/mimeremove
+exists,
+.B ezmlm-reject
+will reject messages of the Content-Types specified. These content-types will
+be accepted as parts of a composite MIME message. They will be
+stripped out later by
+.BR ezmlm-send(1) .
+
+.B ezmlm-reject
+will exit 100 (permanent error) for rejections. If the list address is not in
+the message ``To:'' or ``Cc:'' headers and the
+.B \-t
+switch is active, the exit code is 100 or 99, depending on the
+.B \-q
+switch (see below).
+If you would like to forward messages instead of rejecting them, you can
+into the appropriate .qmail file put:
+
+.EX
+       |condredirect newaddress except /path/ezmlm-reject DIR
+.EE
+
+Now rejected posts will
+go to this address, and the recipient can take appropriate action.
 .SH OPTIONS
 .TP
 .SH OPTIONS
 .TP
+.B \-b
+Reject the message if the message body starts ``subscribe''
+or ``unsubscribe''. If the
+.B \-c
+switch is specified, messages will also be rejected if the subject starts
+with these words.
+.B \-B
+(Default.)
+Do not reject messages starting ``subscribe'' or ``unsubscribe''.
+.TP
 .B \-c
 (Default.)
 Commands are not permitted in the Subject line.
 .B \-c
 (Default.)
 Commands are not permitted in the Subject line.
-A Subject line consisting solely of HELP, SUBSCRIBE, or UNSUBSCRIBE
+A Subject line consisting solely of HELP, REMOVE, SUBSCRIBE, or UNSUBSCRIBE
 is rejected.
 .TP
 .B \-C
 Commands are permitted in the subject line.
 .TP
 is rejected.
 .TP
 .B \-C
 Commands are permitted in the subject line.
 .TP
+.B \-h
+Reject message if any of the headers in
+.I dir\fB/headerreject
+occur in the header. Mailing-List headers of other mailing list managers
+can be put into this file, one per line, to prevent processing of messages
+from other mailing lists.
+.I dir
+must be specified.
+
+A reasonable set of headers would be: ``Mailing-List'', ``X-ml-name'',
+\``ml-name'',``X-loop'',``X-listprocessor-version'',``X-mailing-list''. Case
+is not important.
+.TP
+.B \-H
+(Default.)
+Ignore
+.IR dir\fB/headerreject .
+.B \-q
+Quiet. If the message due to the lack of the list address (see
+.BR \-t )
+is not accepted, this is logged but no error message is sent to the sender.
+.TP
+.B \-q
+Quiet. If a message due to the lack of the list address (see
+.BR \-t )
+is not accepted,
+the message is silently ignored.
+.TP
+.B \-Q
+(Default.)
+Not quiet. If a message due to the lack of the list address (see
+.BR \-t )
+is not accepted,
+the sender is notified by an error message.
+.TP
 .B \-s
 (Default.)
 A nonempty Subject line is required.
 .TP
 .B \-S
 A Subject line is not required.
 .B \-s
 (Default.)
 A nonempty Subject line is required.
 .TP
 .B \-S
 A Subject line is not required.
+.TP
+.B \-t
+(Default.)
+Reject messages that do not have the list address in the ``To:'' or ``Cc:''
+header(s).
+.B ezmlm-reject
+needs access to
+.I dir\fB/outhost
+and
+.I dir\fB/outlocal
+to check this. This check is silently omitted if
+.I dir
+is not specified, to assure backwards compatibility with existing ezmlm lists.
+.TP
+.B \-T
+Do not require the list address in the ``To:'' or ``Cc:'' header(s).
+.SH BUGS
+.B ezmlm-reject
+does not handle rfc822 comments in ``Content-Type:'' lines if present
+before the type or boundary.
+This could be used to defeat the
+MIME rejection function.
+OTOH, this function is intended to reduce garbage, not guarantee
+its elimination.
 .SH "SEE ALSO"
 ezmlm-send(1),
 qmail-command(8)
 .SH "SEE ALSO"
 ezmlm-send(1),
 qmail-command(8)
index ffeea99..55195e0 100644 (file)
 #include "stralloc.h"
 #include "getln.h"
 #include "sgetopt.h"
 #include "stralloc.h"
 #include "getln.h"
 #include "sgetopt.h"
+#include "getconf.h"
+#include "constmap.h"
+#include "fmt.h"
+#include "qmail.h"
+#include "seek.h"
+#include "scan.h"
+#include "env.h"
+#include "errtxt.h"
+#include "idx.h"
 
 
-int flagrejectcommands = 1;
-int flagneedsubject = 1;
+#define FATAL "ezmlm-reject: fatal: "
 
 
+int flagrejectcommands = 1;    /* reject if subject is simple command */
+int flagneedsubject = 1;       /* reject if subject is missing */
+int flagtook = 0;              /* reject unless listaddress in To: or Cc: */
+int exitquiet = 100;           /* reject with error (100) rather than exit */
+                               /* quietly (99) if listaddress missing */
+int flagheaderreject = 0;      /* don't reject messages with headers from */
+                               /* other mailing lists. */
+int flagbody = 0;              /* =1 => reject is subject or body starts with*/
+                               /* "subscribe" or "unsubscribe" */
+int flagforward = 0;           /* =1 => forward commands to list-request */
+int flagparsemime = 0;
 int flaghavesubject = 0;
 int flaghavecommand = 0;
 int flaghavesubject = 0;
 int flaghavecommand = 0;
+int flagcheck = 0;             /* set after boundary is found in body, */
+                               /* until blank line */
 
 
+stralloc mimeremove = {0};
+stralloc mimereject = {0};
+stralloc headerreject = {0};
+
+struct constmap mimeremovemap;
+struct constmap mimerejectmap;
+struct constmap headerrejectmap;
+
+char strnum[FMT_ULONG];
 char buf0[256];
 char buf0[256];
-substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
+substdio ssin = SUBSTDIO_FDBUF(read,0,buf0,(int) sizeof(buf0));
+substdio ssin2 = SUBSTDIO_FDBUF(read,0,buf0,(int) sizeof(buf0));
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
+
 stralloc line = {0};
 stralloc line = {0};
+stralloc to = {0};
+stralloc outhost = {0};
+stralloc outlocal = {0};
+stralloc content = {0};
+stralloc subject = {0};
+stralloc boundary = {0};
+stralloc precd = {0};
+stralloc mydtline = {0};
+
+void die_nomem()
+{
+  strerr_die2x(100,FATAL,ERR_NOMEM);
+}
+
+void die_usage()
+{
+  strerr_die2x(100,FATAL,"usage: ezmlm-reject [-bBcCfFhHqQsStT] [dir]");
+}
+
+unsigned int findlocal(sa,n)
+       /* n is index of '@' within sa. Returns index to last postition */
+       /* of local, n otherwise. */
+stralloc *sa;          /* line */
+unsigned int n;
+{
+  char *first;
+  register char *s;
+  register int level = 0;
+
+  first = sa->s;
+  s = sa->s + n;
+  if (s <= first) return n;
+  while (--s >= first) {
+    switch (*s) {
+      case ' ': case '\t': case '\n': break;
+      case ')':
+        if (--s <= first) return n;
+        if (*s == '\\') break;
+        ++level; ++s;
+        while (level && --s > first) {
+          if (*s == ')') if (*(s-1) != '\\') ++level;
+          if (*s == '(') if (*(s-1) != '\\') --level;
+        }
+        break;
+      case '"':
+        --s;
+        if (s < first) return n;
+        return (unsigned int) (s - first);
+      default:
+        return (unsigned int) (s - first);
+    }
+#include "env.h"
+  }
+}
+
+unsigned int findhost(sa,n)
+       /* s in index to a '@' within sa. Returns index to first pos of */
+       /* host part if there is one, n otherwise. */
+stralloc *sa;          /* line */
+unsigned int n;
+{
+  char *last;
+  register char *s;
+  register int level = 0;
+
+  last = sa->s + sa->len - 1;
+  s = sa->s + n;
+  if (s >= last) return n;
+  while (++s <= last) {
+    switch (*s) {
+      case ' ': case '\t': case '\n': break;
+      case '(':
+        ++level;
+        while (level && (++s < last)) {
+          if (*s == ')') --level; if (!level) break;
+          if (*s == '(') ++level;
+          if (*s == '\\') ++s;
+        }
+        break;
+      case '"':
+        while (++s < last) {
+          if (*s == '"') break;
+          if (*s == '\\') ++s;
+        }
+        break;
+      default:
+        return (unsigned int) (s - sa->s);
+    }
+  }
+}
+
+int getto(sa)
+       /* find list address in line. If found, return 1, else return 0. */
+  stralloc *sa;
+{
+  unsigned int pos = 0;
+  unsigned int pos1;
+
+  if (!sa->len) return 0;              /* no To: or Cc: line */
+  while ((pos += 1 + byte_chr(sa->s+pos+1,sa->len-pos-1,'@')) != sa->len) {
+    pos1 = findhost(sa,pos);
+    if (pos1 == pos) break;
+    if (pos1 + outhost.len <= sa->len)
+      if (!case_diffb(sa->s+pos1,outhost.len,outhost.s)) { /* got host */
+        pos1 = findlocal(sa,pos);
+        if (pos1 == pos) break;
+        ++pos1;                                /* avoids 1 x 2 below */
+        if (pos1 >= outlocal.len)
+        if (!case_diffb(sa->s+pos1-outlocal.len,outlocal.len,outlocal.s))
+          return 1;                    /* got local as well */
+     }
+  }
+  return 0;
+}
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
+  unsigned long maxmsgsize = 0L;
+  unsigned long minmsgsize = 0L;
+  unsigned long msgsize = 0L;
   int opt;
   int opt;
-  char *x;
-  int len;
+  char linetype = ' ';
+  char *cp, *cpstart, *cpafter;
+  char *dir;
+  char *err;
+  char *sender;
+  unsigned int len;
   int match;
 
   int match;
 
-  while ((opt = getopt(argc,argv,"cCsS")) != opteof)
+  while ((opt = getopt(argc,argv,"bBcCfFhHqQsStT")) != opteof)
     switch(opt) {
     switch(opt) {
+      case 'b': flagbody = 1; break;
+      case 'B': flagbody = 0; break;
       case 'c': flagrejectcommands = 1; break;
       case 'C': flagrejectcommands = 0; break;
       case 'c': flagrejectcommands = 1; break;
       case 'C': flagrejectcommands = 0; break;
+      case 'f': flagforward = 1; break;
+      case 'F': flagforward = 0; break;
+      case 'h': flagheaderreject = 1; break;
+      case 'H': flagheaderreject = 0; break;
+      case 'q': exitquiet = 99; break;
+      case 'Q': exitquiet = 100; break;
       case 's': flagneedsubject = 1; break;
       case 'S': flagneedsubject = 0; break;
       case 's': flagneedsubject = 1; break;
       case 'S': flagneedsubject = 0; break;
-      default:
-       strerr_die1x(100,"ezmlm-reject: usage: ezmlm-reject [ -cCsS ]");
+      case 't': flagtook = 0; break;
+      case 'T': flagtook = 1; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-reject: version ezmlm-0.53+",EZIDX_VERSION);
+
+      default: die_usage();
+    }
+  dir = argv[optind];
+  if (dir) {
+    if (chdir(dir) == -1)
+      strerr_die4x(111,FATAL,ERR_SWITCH,dir,": ");
+    flagparsemime = 1;         /* only if dir do we have mimeremove/reject */
+    if (getconf_line(&line,"msgsize",0,FATAL,dir)) {
+      if (!stralloc_0(&line)) die_nomem();
+      len = scan_ulong(line.s,&maxmsgsize);
+      if (line.s[len] == ':')
+        scan_ulong(line.s+len+1,&minmsgsize);
     }
     }
+    if (!flagtook || flagforward) {
+      getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+      getconf_line(&outhost,"outhost",1,FATAL,dir);
+    }
+    if (flagforward) {
+      if (!stralloc_copys(&mydtline,"Delivered-To: command forwarder for "))
+       die_nomem();
+      if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
+      if (!stralloc_cats(&mydtline,"@")) die_nomem();
+      if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
+      if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+    }
+  } else {
+    flagtook = 1;              /* if no "dir" we can't get outlocal/outhost */
+    flagforward = 0;           /* nor forward requests */
+  }
 
 
+  if (flagparsemime) {         /* set up MIME parsing */
+    getconf(&mimeremove,"mimeremove",0,FATAL,dir);
+      constmap_init(&mimeremovemap,mimeremove.s,mimeremove.len,0);
+    getconf(&mimereject,"mimereject",0,FATAL,dir);
+      constmap_init(&mimerejectmap,mimereject.s,mimereject.len,0);
+  }
+  if (flagheaderreject) {
+    if (!dir) die_usage();
+    getconf(&headerreject,"headerreject",1,FATAL,dir);
+    constmap_init(&headerrejectmap,headerreject.s,headerreject.len,0);
+  }
   for (;;) {
   for (;;) {
-    if (getln(&ss0,&line,&match,'\n') == -1)
-      strerr_die2sys(111,"ezmlm-reject: fatal: ","unable to read input: ");
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
     if (!match) break;
     if (!match) break;
+    if (flagheaderreject)
+      if (constmap(&headerrejectmap,line.s,byte_chr(line.s,line.len,':')))
+        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+
     if (line.len == 1) break;
     if (line.len == 1) break;
+    cp = line.s; len = line.len;
+    if ((*cp == ' ' || *cp == '\t')) {
+      switch(linetype) {
+       case 'T': if (!stralloc_catb(&to,cp,len-1)) die_nomem(); break;
+       case 'S': if (!stralloc_catb(&subject,cp,len-1)) die_nomem(); break;
+       case 'C': if (!stralloc_catb(&content,cp,len-1)) die_nomem(); break;
+       case 'P': if (!stralloc_catb(&precd,cp,len-1)) die_nomem(); break;
+       default: break;
+      }
+    } else {
+      if (!flagtook &&
+               (case_startb(cp,len,"to:") || case_startb(cp,len,"cc:"))) {
+       linetype = 'T';         /* cat so that To/Cc don't overwrite */
+        if (!stralloc_catb(&to,line.s + 3,line.len - 4)) die_nomem();
+      } else if ((flagneedsubject || flagrejectcommands) &&
+                        case_startb(cp,len,"subject:")) {
+       if (!stralloc_copyb(&subject,cp+8,len-9)) die_nomem();
+       linetype = 'S';
+      } else if (case_startb(cp,len,"content-type:")) {
+       if (!stralloc_copyb(&content,cp+13,len-14)) die_nomem();
+       linetype = 'C';
+      } else if (case_startb(cp,len,"precedence:")) {
+       if (!stralloc_copyb(&precd,cp+11,len-12)) die_nomem();
+       linetype = 'P';
+      } else {
+       if (flagforward && line.len == mydtline.len) {
+         if (!byte_diff(line.s,line.len,mydtline.s))
+            strerr_die2x(100,FATAL,ERR_LOOPING);
+        }
+        linetype = ' ';
+      }
+    }
+  }
+  if (precd.len >= 4 &&
+               (!case_diffb(precd.s + precd.len - 4,4,"junk") ||
+               !case_diffb(precd.s + precd.len - 4,4,"bulk")))
+         strerr_die1x(99,ERR_JUNK);    /* ignore precedence junk/bulk */
+  cp = subject.s;
+  len = subject.len;
+  while (len && (cp[len-1] == ' ' || cp[len-1] == '\t')) --len;
+  while (len && ((*cp == ' ') || (*cp == '\t'))) { ++cp; --len; }
+  flaghavesubject = 1;
+
+  if (flagbody)
+    if (len > 9 && case_starts(cp,"subscribe") ||
+       len > 11 && case_starts(cp,"unsubscribe"))
+      flaghavecommand = 1;
 
 
-    x = line.s; len = line.len - 1;
-    while (len && ((x[len - 1] == ' ') || (x[len - 1] == '\t'))) --len;
+  switch(len) {
+    case 0: flaghavesubject = 0; break;
+    case 4: if (!case_diffb("help",4,cp)) flaghavecommand = 1; break;
+    case 6:    /* Why can't they just leave an empty subject empty? */
+           if (!case_diffb("(null)",6,cp))
+              flaghavesubject = 0;
+            else
+           if (!case_diffb("(none)",6,cp))
+              flaghavesubject = 0;
+            else
+              if (!case_diffb("remove",6,cp))
+               flaghavecommand = 1;
+            break;
+    case 9: if (!case_diffb("subscribe",9,cp)) flaghavecommand = 1; break;
+    case 11: if (!case_diffb("unsubscribe",11,cp)) flaghavecommand = 1; break;
+    case 12: if (!case_diffb("(no subject)",12,cp)) flaghavesubject = 0; break;
+    default: break;
+  }
 
 
-    if (case_startb(x,len,"subject:")) {
-      x += 8; len -= 8;
-      while (len && ((*x == ' ') || (*x == '\t'))) { ++x; --len; }
-      if (len) {
-        flaghavesubject = 1;
+  if (!flagtook && !getto(&to))
+    strerr_die2x(exitquiet,FATAL,ERR_NO_ADDRESS);
 
 
-        if (len == 4)
-          if (!case_diffb("help",4,x))
-            flaghavecommand = 1;
+  if (flagneedsubject && !flaghavesubject)
+    strerr_die2x(100,FATAL,ERR_NO_SUBJECT);
 
 
-        if (len == 9)
-          if (!case_diffb("subscribe",9,x))
-            flaghavecommand = 1;
+  if (flagrejectcommands && flaghavecommand)
+    if (flagforward) {                 /* flagforward => forward */
+      sender = env_get("SENDER");
+      if (!sender || !*sender)         /* can't [won't] forward */
+        strerr_die2x(100,FATAL,ERR_SUBCOMMAND);
+      if (qmail_open(&qq,(stralloc *) 0) == -1)        /* open queue */
+       strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+      qmail_put(&qq,mydtline.s,mydtline.len);
+      if (seek_begin(0) == -1)
+       strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+      if (substdio_copy(&ssqq,&ssin2) != 0)
+       strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!stralloc_copy(&to,&outlocal)) die_nomem();
+      if (!stralloc_cats(&to,"-request@")) die_nomem();
+      if (!stralloc_cat(&to,&outhost)) die_nomem();
+      if (!stralloc_0(&to)) die_nomem();
+      qmail_from(&qq,sender);
+      qmail_to(&qq,to.s);
+      if (*(err = qmail_close(&qq)) == '\0') {
+        strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+        strerr_die2x(99,"ezmlm-request: info: forward qp ",strnum);
+      } else
+        strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+    } else
+      strerr_die2x(100,FATAL,ERR_SUBCOMMAND);
 
 
-        if (len == 11)
-          if (!case_diffb("unsubscribe",11,x))
-            flaghavecommand = 1;
+  if (content.len) {                   /* MIME header */
+    cp = content.s;
+    len = content.len;
+    while (len && *cp == ' ' || *cp == '\t') { ++cp; --len; }
+    cpstart = cp;
+    if (*cp == '"') {                  /* might be commented */
+      ++cp; cpstart = cp;
+      while (len && *cp != '"') { ++cp; --len; }
+    } else {
+      while (len && *cp != ' ' && *cp != '\t' && *cp != ';') {
+        ++cp; --len;
       }
     }
       }
     }
-  }
 
 
-  if (flagneedsubject && !flaghavesubject)
-    strerr_die1x(100,"\
-ezmlm-reject: fatal: I need a nonempty Subject line in every message.\n\
-If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\
-Do not send administrative requests to the mailing list.\n\
-Send an empty message to ...-help@... for automated assistance.");
+    if (flagparsemime)
+    if (constmap(&mimeremovemap,cpstart,cp-cpstart) ||
+       constmap(&mimerejectmap,cpstart,cp-cpstart)) {
+      *(cp) = (char) 0;
+      strerr_die5x(100,FATAL,ERR_BAD_TYPE,cpstart,"'",ERR_SIZE_CODE);
+    }
 
 
-  if (flagrejectcommands && flaghavecommand)
-    strerr_die1x(100,"\
-ezmlm-reject: fatal: Your Subject line looks like a command word.\n\
-If you are trying to subscribe or unsubscribe, WRONG ADDRESS!\n\
-Do not send administrative requests to the mailing list.\n\
-Send an empty message to ...-help@... for automated assistance.");
+    cpafter = content.s+content.len;
+    while((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) {
+      ++cp;
+      while (cp < cpafter && (*cp == ' ') || (*cp == '\t')) ++cp;
+      if (case_startb(cp,cpafter - cp,"boundary=")) {
+        cp += 9;                       /* after boundary= */
+        if (cp < cpafter && *cp == '"') {
+          ++cp;
+          cpstart = cp;
+          while (cp < cpafter && *cp != '"') ++cp;
+         if (cp == cpafter)
+               strerr_die1x(100,ERR_MIME_QUOTE);
+        } else {
+          cpstart = cp;
+          while (cp < cpafter &&
+             *cp != ';' && *cp != ' ' && *cp != '\t') ++cp;
+        }
+        if (!stralloc_copys(&boundary,"--")) die_nomem();
+        if (!stralloc_catb(&boundary,cpstart,cp-cpstart))
+               die_nomem();
+       break;
+      }
+    }          /* got boundary, now parse for parts */
+  }
 
 
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (!match) break;
+    if (line.len == 1) {
+      flagcheck = 0;
+      continue;
+               /* Doesn't do continuation lines. _very_ unusual, and worst */
+               /* case one slips through that shouldn't have */
+    } else if (flagcheck && case_startb(line.s,line.len,"content-type:")) {
+        cp = line.s + 13;
+       len = line.len - 14;                    /* zap '\n' */
+        while (*cp == ' ' || *cp == '\t') { ++cp; --len; }
+        cpstart = cp;
+       if (*cp == '"') {                       /* quoted */
+         ++cp; cpstart = cp;
+         while (len && *cp != '"') { ++cp; --len; }
+        } else {                               /* not quoted */
+          while (len && *cp != ' ' && *cp != '\t' && *cp != ';') {
+           ++cp; --len;
+         }
+        }
+       if (flagparsemime && constmap(&mimerejectmap,cpstart,cp-cpstart)) {
+          *cp = '\0';
+          strerr_die4x(100,FATAL,ERR_BAD_PART,cpstart,ERR_SIZE_CODE);
+        }
+    } else if (boundary.len && *line.s == '-' && line.len > boundary.len &&
+       !str_diffn(line.s,boundary.s,boundary.len)) {
+        flagcheck = 1;
+    } else {
+      if (!msgsize && flagbody)
+       if (case_startb(line.s,line.len,"subscribe") ||
+               case_startb(line.s,line.len,"unsubscribe"))
+         strerr_die2x(100,FATAL,ERR_BODYCOMMAND);
+      if (!flagcheck) {
+         msgsize += line.len;
+         if (maxmsgsize && msgsize > maxmsgsize) {
+           strnum[fmt_ulong(strnum,maxmsgsize)] = 0;
+           strerr_die5x(100,FATAL,ERR_MAX_SIZE,strnum," bytes",ERR_SIZE_CODE);
+         }
+      }
+    }
+  }
+  if (msgsize < minmsgsize) {
+    strnum[fmt_ulong(strnum,minmsgsize)] = 0;
+        strerr_die5x(100,FATAL,ERR_MIN_SIZE,strnum," bytes",ERR_SIZE_CODE);
+  }
   _exit(0);
 }
   _exit(0);
 }
diff --git a/ezmlm-request.1 b/ezmlm-request.1
new file mode 100644 (file)
index 0000000..4f63e19
--- /dev/null
@@ -0,0 +1,216 @@
+.TH ezmlm-request 1
+.SH NAME
+ezmlm-request \- Process subject line and body ezmlm commands
+.SH SYNOPSIS
+.B ezmlm-request
+[
+.B \-f\fI config
+]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-request
+processes ezmlm commands in the subject line or message body.
+.B ezmlm-request
+enables these uses to send the message to
+.I list\fB\-request\fI@host
+with the complete command address line in the subject field,
+or with commands and arguments separated by white
+space.
+.B ezmlm-request
+uses the text to construct a ezmlm command message to the list.
+If the subject does not start with a letter,
+.B ezmlm-request
+instead uses the first body line that starts with a letter. Processing
+terminates if a line with a hyphen in the first position is encountered.
+
+All commands are expected to be in ezmlm command address format or formatted
+as:
+
+.EX
+.BR command [list@listhost [user@userhost]]
+.EE
+
+.B ezmlm-request
+when invoked with the
+.B \-f
+switch and a configuration file (see below), ignores the subject and processes
+the first body line (per rules above) in conjunction with the configuration
+file. It also services the 
+.B lists
+and
+.B which
+commands. This can be used
+to construct a global list interface, similar to that used by some other
+mailing list managers.
+
+Messages at the 
+.I list\fB\-request\fI@host
+are restricted to the local list. When
+.B ezmlm-request
+is invoked with the
+.B \-f\fI config
+switch, command messages are limited to lists in
+.I config
+or at the local host.
+
+Invalid requests for an existing ezmlm list will
+lead to a ``help'' message from
+.BR ezmlm-manage(1) .
+.SH OPTIONS
+.TP
+.B \-f\fI config
+Function as a global interface to ezmlm lists in accordance with
+.IR config.
+This file consists of lines starting in the first position
+with ``list@host:listdir:description''. Lines that are blank or start
+ with ``#'' are ignored. ``listdir''
+and ``description'' are optional. If only ``list@host'' is given, the list
+is used to restrict commands (see below), but not listed. To allow the list
+to be shown by a ``list'' command, use ``list@host:''. To specify only
+the list name and description, use ``list@host::description''.
+If ``listdir'' is
+present, the
+.B which
+command attempts to determine if the user is a subscriber of the list.
+.B NOTE:
+this will work only if the user running
+.B ezmlm-request
+has read access to the lists subscriber database.
+
+If ``listhost'' is not specified,
+.B ezmlm-request
+will use the ``listhost'' from the first
+.I config
+entry matching ``listlocal''. If ``listhost'' is specified, but not found
+in
+.IR config ,
+it is set to the contents of
+.IR dir\fB/outhost .
+.SH USAGE
+Place an invocation of
+.B ezmlm-request
+in
+.I dir\fB/manager
+anywhere before the
+.B ezmlm-manage(1)
+line.
+
+Alternatively, set up
+.I dir\fB/request
+with an invocation of
+.BR ezmlm-request .
+Make a link from
+.I ~/.qmail-list-request
+to this file.
+
+For the global interface, place 
+.B /path/ezmlm-request -f \fIconfig dir
+into a file.
+Link
+.I ~/.qmail-ezmlm
+and
+.I ~/.qmail-ezmlm-default
+to this file. The latter allows
+.B ezmlm-request
+to handle its own bounces as well as to reply to messages to e.g.
+\``user-ezmlm-lists@listhost''.
+Create
+.IR dir\fB/inlocal
+and
+.IR dir\fB/outlocal
+with ``user-ezmlm'',
+.IR dir\fB/outhost
+with ``listhost'',
+.IR dir\fB/headerremove
+with headers to be stripped (copy from a list),
+.IR dir/text\fB/help ,
+.IR dir/text\fB/top ,
+and
+.I dir/text\fB/bottom
+with the appropriate texts.
+Also, create
+.I config
+with the appropriate contents.
+
+Mail to ``user-ezmlm@listhost'' will now be answered by
+.BR ezmlm-request .
+.SH "RECOGNIZED COMMANDS"
+Any command not recognized by
+.B ezmlm-request
+is assumed to be valid, as long as it consists of only letters, numbers,
+hyphen, underscore, period, and ``+''. This allows
+.B ezmlm-request
+to correctly handle commands added by the list owner.
+
+A number of commands are recognized by
+.B ezmlm-request
+but not processed. Instead they are mapped to
+.B help 
+without arguments. These
+are:
+.BR system ,
+.BR put ,
+and
+.BR set .
+
+.B ezmlm-request
+also handles a number of aliases for ezmlm commands. Since
+.B ezmlm-request
+only passes on requests to the list, local restrictions apply.
+For commands that have aliases, accepted aliases are listed:
+.TP
+.B subscribe
+sub
+.TP
+.B unsubscribe
+unsub, signoff, remove.
+.TP
+.B index
+ind.
+.TP
+.B list
+recipients, showdist, review, rev, who.
+.TP
+
+Some commands are handled differently when used without arguments:
+.TP
+.B query
+Treated like ``which''.
+.TP
+.B list
+Treated like ``lists''.
+.SH BUGS
+.B ezmlm-request
+places stricter requirements on addresses than rfc822. Thus, some addresses
+that are rfc822-compliant cannot be used as
+.B ezmlm-request
+command arguments. If you fix this,
+please send a patch to lindberg@id.wustl.edu. I think qmail has the same
+restriction, though.
+
+.B ezmlm-request
+uses NUL as a line terminator internally. Thus, if will fail if NUL is found
+within the line it tries to interpret as a command. It is harmless, other than
+that the remainder of the line will be ignored.
+
+The
+.B ezmlm-request
+\``which''
+command does not differentiate between a list for which the command is not
+available, a list for which the subscriber db is not accessible, and a list
+for which the address is not a subscriber. This should be considered a feature.
+.SH BUGS
+.B ezmlm-request
+when used as a global interface and receiving multipart messages assumes that
+the first line of the fist part is the command. Further, it assumes that the
+first line starting``--'' is the first MIME boundary. This is virtually
+always true, but it is easy to construct legal messages that do not fit these
+assumptions.
+.B ezmlm-request
+in the global interface role
+will fail if this first part or the entire message is base64 encoded.
+.SH "SEE ALSO"
+ezmlm-get(1),
+ezmlm-manage(1),
+ezmlm-send(1),
+ezmlm(5)
diff --git a/ezmlm-request.c b/ezmlm-request.c
new file mode 100644 (file)
index 0000000..661616d
--- /dev/null
@@ -0,0 +1,826 @@
+/*$Id: ezmlm-request.c,v 1.34 1999/08/18 01:50:04 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "subfd.h"
+#include "strerr.h"
+#include "error.h"
+#include "qmail.h"
+#include "env.h"
+#include "sig.h"
+#include "open.h"
+#include "getln.h"
+#include "case.h"
+#include "str.h"
+#include "datetime.h"
+#include "date822fmt.h"
+#include "now.h"
+#include "quote.h"
+#include "readwrite.h"
+#include "exit.h"
+#include "substdio.h"
+#include "getconf.h"
+#include "constmap.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "byte.h"
+#include "seek.h"
+#include "errtxt.h"
+#include "copy.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-request: fatal: "
+#define INFO "ezmlm-request: info: "
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-request: usage: ezmlm-request [-f lists.cfg] dir");
+}
+
+void die_nomem()
+{
+  strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
+void die_badaddr()
+{
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+char strnum[FMT_ULONG];
+
+void *psql = (void *) 0;
+
+char *userlocal = (char *) 0;
+char *userhost = (char *) 0;
+char *listlocal = (char *) 0;
+char *listhost = (char *) 0;
+char *cfname = (char *) 0;
+char *command = "help";
+stralloc line = {0};
+stralloc qline = {0};
+stralloc usr = {0};
+stralloc lhost = {0};
+stralloc subject = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc listname = {0};
+stralloc hostname = {0};
+stralloc outhost = {0};
+stralloc headerremove = {0};
+stralloc mailinglist = {0};
+stralloc cmds = {0};
+stralloc from = {0};
+stralloc to = {0};
+stralloc charset = {0};
+char *boundary = "zxcaeedrqcrtrvthbdty";       /* cheap "rnd" MIME boundary */
+int flagcd = '\0';                             /* no encoding by default */
+
+struct constmap headerremovemap;
+struct constmap commandmap;
+int flaggotsub = 0;            /* Found a subject */
+       /* cmdstring has all commands seperated by '\'. cmdxlate maps each */
+       /* command alias to the basic command, which is used to construct  */
+       /* the command address (positive numbers) or handled by this       */
+       /* program (negative numbers). Note: Any command not matched is    */
+       /* used to make a command address, so ezmlm request can handle     */
+       /* ("transmit") user-added commands.                               */
+const char *cmdstring =
+               "system\\help\\"                        /* 1,2 */
+               "subscribe\\unsubscribe\\index\\"       /* 3,4,5 */
+               "info\\list\\query\\"                   /* 6,7,8 */
+               "sub\\unsub\\remove\\signoff\\"         /* 9,10,11,12 */
+               "lists\\which\\"                        /* 13,14 */
+               "ind\\rev\\review\\recipients\\"        /* 15,16,17,18 */
+               "who\\showdist\\"                       /* 19,20 */
+               "put\\set";                             /* 21,22 */
+
+       /* map aliases. -> 0 not recognized. -> 1 recognized will be made    */
+       /* help and arguments scrapped. < 0 handled locally. HELP without    */
+       /* args also handled locally */
+                       /* the last are not supported -> help */
+const int cmdxlate[] = { 0,1,2,3,4,5,6,7,8,3,4,4,4,-13,-14,5,7,7,7,7,7,
+                       1,1 };
+
+       /* If there are no arguments (listlocal = 0) then commands are mapped*/
+       /* through this. This way, help, list, query, ... can mean something */
+       /* here even though they have local funcions at the lists if used    */
+       /* with arguments. (Made same lengh as cmdxlate in case of bugs.)    */
+       /* Note: This is used ONLY for the global interface */
+const int noargsxlate[] = { 0,1,-2,3,4,5,-2,-13,-14,9,10,11,12,13,14,15,16,17,
+                       18,19,20,21,22 };
+
+       /* these need to be defined as the index of the corresponding      */
+       /* commands. They are handled by ezmlm-request. NOTE: Help is >0!  */
+#define EZREQ_LISTS 13
+#define EZREQ_WHICH 14
+#define EZREQ_HELP  2
+#define EZREQ_BAD 1
+
+substdio sstext;
+char textbuf[1024];
+datetime_sec when;
+struct datetime dt;
+char date[DATE822FMT];
+
+struct qmail qq;
+
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
+
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+
+substdio ssout;
+char outbuf[1];
+
+stralloc mydtline = {0};
+
+void transferenc()
+{
+       if (flagcd) {
+          qmail_puts(&qq,"\n--");
+          qmail_puts(&qq,boundary);
+          qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+          qmail_puts(&qq,charset.s);
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"quoted-printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        }
+}
+
+int code_qput(s,n)
+char *s;
+unsigned int n;
+{
+    if (!flagcd)
+      qmail_put(&qq,s,n);
+    else {
+      if (flagcd == 'B')
+        encodeB(s,n,&qline,0,FATAL);
+      else
+        encodeQ(s,n,&qline,FATAL);
+      qmail_put(&qq,qline.s,qline.len);
+    }
+    return 0;          /* always succeeds */
+}
+
+/* Checks the argument. Only  us-ascii letters, numbers, ".+-_" are ok. */
+/* NOTE: For addresses this is more restrictive than rfc821/822.        */
+void checkarg(s)
+char *s;
+{
+  register char *cp;
+  register char ch;
+  cp = s;
+  if (!cp) return;                             /* undef is ok */
+  while ((ch = *cp++)) {
+    if (ch >= 'a' && ch <= 'z')
+        continue;                              /* lc letters */
+    if (ch >= '0' && ch <='9')                 /* digits */
+       continue;
+    if (ch == '.' || ch == '-' || ch == '_' || ch == '+')
+       continue;                               /* ok chars */
+    if (ch >= 'A' && ch <= 'Z') continue;      /* UC LETTERS */
+    strerr_die4x(100,ERR_NOT_CLEAN,": \"",s,"\"");
+  }
+  return;
+}
+
+/* parses line poited to by cp into sz:s as per:                        */
+/* 1. listlocal-command-userlocal=userhost@listhost                     */
+/* 2. command userlocal@userhost                                        */
+/* 3. command userlocal@userhost listlocal@listhost                     */
+/* 4. command listlocal@listhost                                        */
+/* 5. command listlocal[@listhost] userlocal@userhost                   */
+/* 6. which [userlocal@userhost]                                       */
+/* The first 3 are valid only if !cfname, i.e. -request operation and   */
+/* listlocal and listhost are always set to outlocal@outhost. Options   */
+/* 4-5 are for the global address (cfname is set). Here listhost is     */
+/* taken from the first list in *cfname matching listlocal, or set to   */
+/* outhost, if not specified. If specified, it's accepted if it matches */
+/* a list in *cfname and silently set to outhost otherwise. Pointers to */
+/* unspecified parts are set to NULL in this routine to be dealt with   */
+/* elsewhere. "Which" special argument order (6) is fixed elsewhere.    */
+/* If listhost is not given, "@outhost" is added. Absence of 'userhost' */
+/* is accepted to allow commands that take arguments that are not       */
+/* addresses (e.g. -get12-34).                                          */
+
+void parseline(cp)
+char *cp;
+
+{
+  register char *cp1, *cp2;
+  char *cp3;
+
+  cp1 = cp;
+  while (*cp1) {                               /* make tabs into spaces */
+    if (*cp1 == '\t') *cp1 = ' ';
+    ++cp1;
+  }
+                                       /* NOTE: outlocal has '\0' added! */
+  if (outlocal.len < str_len(cp) && cp[outlocal.len -1] == '-' &&
+       case_starts(cp,outlocal.s))      {      /* normal ezmlm cmd */
+    command = cp + outlocal.len;               /* after the '-' */
+    listlocal = outlocal.s;
+    listhost = outhost.s;
+    cp1 = command;
+    while (*cp1 && *cp1 != '-') ++cp1;         /* find next '-' */
+    if (*cp1) {
+      *cp1 = '\0';
+      userlocal = ++cp1;                       /* after '-' */
+      cp1 = cp1 + str_rchr(cp1,'@');           /* @ _or_ end */
+      *cp1 = '\0';                             /* last '=' in userlocal */
+      cp1 = userlocal + str_rchr(userlocal,'=');
+      if (*cp1) {                              /* found '=' */
+        *cp1 = '\0';                           /* zap */
+        userhost = cp1 + 1;                    /* char after '=' */
+      }
+    }
+  } else {                             /* '@' before ' ' means complete cmd */
+    if (str_chr(cp,'@') < str_chr(cp,' '))     /* addr where inlocal failed */
+       strerr_die2x(100,FATAL,ERR_REQ_LOCAL);
+                                               /* to match */
+    command = cp;
+    cp1 = cp + str_chr(cp,' ');
+    if (*cp1) {
+      *cp1++ = '\0';
+      while (*cp1 && *cp1 == ' ') ++cp1;       /* skip spaces */
+    }
+    cp2 = 0;
+    if (*cp1) {                                        /* argument */
+      cp2 = cp1 + str_chr(cp1,' ');
+      cp3 = cp2;
+      while (*cp2 && *cp2 == ' ') ++cp2;       /* skip spaces */
+      *cp3 = '\0';
+
+      if (!*cp2)
+        cp2 = 0;
+      else {
+        cp3 = cp2 + str_chr(cp2,' ');
+        *cp3 = '\0';
+      }
+    } else
+      cp1 = 0;
+
+    if (!cfname && !cp2) {     /* the single arg is user if we serve a */
+      cp2 = cp1;               /* list. It's list if we serve "domo@" */
+      cp1 = 0;
+    }
+    if (cp2) {
+      userlocal = cp2;
+      cp2 += str_chr(cp2,'@');
+      if (*cp2) {
+        *cp2++ = '\0';
+        userhost = cp2;
+      }
+    }
+    if (cp1) {
+      listlocal = cp1;
+      cp1 += str_chr(cp1,'@');
+      if (*cp1) {
+        *cp1++ = '\0';
+        listhost = cp1;
+      }
+    }
+  }
+  checkarg(command);                   /* better safe than sorry */
+  checkarg(userlocal); checkarg(userhost);
+  checkarg(listlocal); checkarg(listhost);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  char *local;
+  char *action;
+  char *def;
+  char *sender;
+  char *psz;
+  char *err;
+  int cmdidx;
+  int flagsub;
+  int flagok;
+  int flagnosubject;
+  int match;
+  int flaginheader;
+  int flagbadfield;
+  int flagmultipart = 0;
+  int fd;
+  int opt;
+  unsigned int pos,pos1,len,last;
+
+  (void)umask(022);
+  sig_pipeignore();
+
+  while ((opt = getopt(argc,argv,"f:F:vV")) != opteof)
+    switch(opt) {
+      case 'F':
+      case 'f': if (optarg) cfname = optarg; break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-request version: ",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+       /* do minimum to identify request for this program in case */
+       /* it's invoked in line with e.g. ezmlm-manage */
+
+  def = env_get("DEFAULT");
+  if (def) {                   /* qmail>=1.02 */
+    action = def;
+  } else if (cfname) {         /* older qmail OR just list-mdomo */
+    local = env_get("LOCAL");
+    if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+    len = str_len(local);
+    if (len >= 8 && !case_diffb(local + len - 8,8,"-return-")) {
+      action = "return-";      /* our bounce with qmail<1.02 */
+    } else
+      action = "";             /* list-mdomo-xxx won't work for older lists */
+  } else {                     /* older qmail versions */
+    local = env_get("LOCAL");
+    if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+    getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+    if (inlocal.len > str_len(local)) die_badaddr();
+    if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+    action = local + inlocal.len;
+    if (*action)
+      if (*(action++) != '-') die_badaddr();   /* check anyway */
+  }
+       /* at this point action = "request" or "request-..." for std use; */
+       /* "" for majordomo@ */
+  if (!cfname) {                               /* expect request */
+    if (case_starts(action,ACTION_REQUEST))
+      action += str_len(ACTION_REQUEST);
+    else if (case_starts(action,ALT_REQUEST))
+      action += str_len(ALT_REQUEST);
+    else
+      _exit(0);                                        /* not for us */
+  }
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+
+  if (!stralloc_copy(&listname,&outlocal)) die_nomem();
+  if (!stralloc_copy(&hostname,&outhost)) die_nomem();
+  if (!stralloc_0(&outlocal)) die_nomem();
+  if (!stralloc_0(&outhost)) die_nomem();
+
+  sender = env_get("SENDER");
+  if (!sender) strerr_die2x(99,INFO,ERR_NOSENDER);
+  if (!*sender)
+    strerr_die2x(99,INFO,ERR_BOUNCE);
+  if (!sender[str_chr(sender,'@')])
+    strerr_die2x(99,INFO,ERR_ANONYMOUS);
+  if (str_equal(sender,"#@[]"))
+    strerr_die2x(99,INFO,ERR_BOUNCE);
+
+  getconf(&headerremove,"headerremove",1,FATAL,dir);
+  constmap_init(&headerremovemap,headerremove.s,headerremove.len,0);
+
+  if (!stralloc_copys(&mydtline,
+       "Delivered-To: request processor for ")) die_nomem();
+  if (!stralloc_cats(&mydtline,outlocal.s)) die_nomem();
+  if (!stralloc_cats(&mydtline,"@")) die_nomem();
+  if (!stralloc_cats(&mydtline,outhost.s)) die_nomem();
+  if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+
+  flagnosubject = 1;
+  if (action[0]) {     /* mainly to allow ezmlm-lists or ezmlm-which with */
+    flagnosubject = 0; /* a command address rather than a complete msg */
+    command = action;
+    if (str_start(action,"return"))            /* kill bounces */
+      strerr_die2x(0,INFO,ERR_BOUNCE);
+    pos = 1 + str_chr(action + 1,'-');
+    if (action[pos]) {                         /* start of target */
+      action[pos] = '\0';
+      userlocal = action + pos + 1;
+      pos = str_rchr(userlocal,'=');           /* the "pseudo-@" */
+      if (userlocal[pos]) {
+       userlocal[pos] = '\0';
+        userhost = userlocal + pos + 1;
+      }
+    }
+  } else {
+    for (;;) {                                 /* Get Subject: */
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+        if (line.len == 1)
+        break;
+        if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
+          flagsub = 0;
+
+          if (case_startb(line.s,line.len,"mailing-list:"))
+            strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+          else if (case_startb(line.s,line.len,"Subject:")) {
+            flaggotsub = 1;
+            pos = 8;
+            last = line.len - 2;               /* skip terminal '\n' */
+            while (line.s[last] == ' ' || line.s[last] == '\t') --last;
+            while (pos <= last &&
+               (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
+            if (!stralloc_copyb(&subject,line.s+pos,last-pos+1)) die_nomem();
+          } else if (case_startb(line.s,line.len,"content-type:")) {
+           pos = 13; last = line.len - 2;      /* not cont-line - ok */
+            while (pos <= last &&
+               (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
+           if (case_startb(line.s+pos,line.len - pos,"multipart/"))
+             flagmultipart = 1;
+         } else if (line.len == mydtline.len)
+            if (!byte_diff(line.s,line.len,mydtline.s))
+               strerr_die2x(100,FATAL,ERR_LOOPING);
+        } else if (flagsub) {  /* Continuation line */
+          pos = 1;
+          len = line.len - 2;  /* skip terminal '\n' */
+          while (line.s[len] == ' ' || line.s[len] == '\t') --len;
+          while (pos < len &&
+               (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
+          if (!stralloc_append(&subject," ")) die_nomem();
+          if (!stralloc_copy(&subject,line.s+pos,len-pos+1)) die_nomem();
+      }
+      if (!match)
+        break;
+    }
+    if (!cfname) {              /* listserv@/majordomo@ ignore */
+      register char ch;
+      if (!stralloc_0(&subject)) die_nomem();
+      ch = *subject.s;         /* valid commands/list names start w letter */
+      if ((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A')) {
+        parseline(subject.s);
+        flagnosubject = 0;
+      }
+    }
+    if (cfname || flagnosubject) {
+      for (;;) {                                       /* parse body */
+        if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+        if (!match) break;
+       if (line.len == 1 && flagmultipart != 2) continue;
+               /* lazy MIME cludge assumes first '--...' is start border */
+               /* which is virtually always true */
+       if (flagmultipart == 1) {               /* skip to first border */
+         if (*line.s != '-' || line.s[1] != '-') continue;
+         flagmultipart = 2;
+         continue;
+       } else if (flagmultipart == 2) {        /* skip content info */
+         if (line.len != 1) continue;
+         flagmultipart = 3;                    /* may be part within part */
+         continue;                             /* and blank line */
+       } else if (flagmultipart == 3) {
+         if (*line.s == '-' && line.s[1] == '-') {
+           flagmultipart = 2;                  /* part within part */
+           continue;
+         }
+       }
+        {
+         register char ch;
+         ch = *line.s;
+        if (line.len == 1 ||
+          !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
+          continue;                            /* skip if not letter pos 1 */
+        }
+                       /* Here we have a body line with something */
+        if (!stralloc_copy(&subject,&line)) die_nomem();       /* save it */
+        subject.s[subject.len-1] = '\0';
+        parseline(subject.s);
+        break;
+      }
+    }
+  }
+       /* Do command substitution */
+  if (!stralloc_copys(&cmds,cmdstring)) die_nomem();
+  if (!stralloc_0(&cmds)) die_nomem();
+  psz = cmds.s;
+  while (*psz) {
+    if (*psz == '\\') *psz = '\0';
+    ++psz;
+  }
+  if (!constmap_init(&commandmap,cmds.s,cmds.len,0)) die_nomem();
+  cmdidx = cmdxlate[constmap_index(&commandmap,command,str_len(command))];
+  if (cmdidx == EZREQ_BAD) {   /* recognized, but not supported -> help */
+    listlocal = 0;             /* needed 'cause arguments are who-knows-what */
+    listhost = 0;
+    userlocal = 0;
+    userhost = 0;
+    cmdidx = EZREQ_HELP;
+  }
+  if (cfname && !listlocal && !userlocal && cmdidx > 0)
+    cmdidx = noargsxlate[cmdidx];       /* some done differently if no args */
+
+       /* =0 not found. This is treated as a list command! */
+  if (cmdidx < 0 && !cfname) {
+    cmdidx = EZREQ_HELP;
+  }
+  if (qmail_open(&qq,(stralloc *) 0) == -1)
+    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+
+  if (cmdidx >= 0) {
+       /* Things handled elsewhere. We do want to handle a simple HELP */
+       /* without arguments for e.g. majordomo@ from our own help file */
+
+    if (!stralloc_copys(&from,sender)) die_nomem();
+    if (!stralloc_0(&from)) die_nomem();
+    if (!listlocal) {
+      if (cfname)
+        strerr_die1x(100,ERR_REQ_LISTNAME);
+      else
+       listlocal = outlocal.s; /* This is at the -request address */
+    }
+       /* if !cfname listhost is made outhost. If cfname, listhost=outhost */
+       /* is ok. listhost=0 => first match in config. Other listhost is ok */
+       /* only if match is found. Otherwise it's set to outhost. */
+
+    if (!cfname || (listhost && !case_diffs(listhost,outhost.s)))
+      listhost = outhost.s;
+    else {                      /* Check listhost against config file */
+      pos = str_len(listlocal);
+      fd = open_read(cfname);
+      if (fd == -1)
+        strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": ");
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      flagok = 0;                      /* got listhost match */
+      for (;;) {
+        if (getln(&sstext,&line,&match,'\n') == -1)
+          strerr_die3sys(111,FATAL,ERR_READ,cfname);
+        if (!match)
+          break;
+        if (line.len <= 1 || line.s[0] == '#')
+          continue;
+        if ((pos < line.len) && (line.s[pos] == '@') &&
+               !byte_diff(line.s,pos,listlocal)) {
+          last = byte_chr(line.s,line.len,':');
+          if (!stralloc_copyb(&lhost,line.s+pos+1,last-pos-1)) die_nomem();
+          if (!stralloc_0(&lhost)) die_nomem();
+          if (listhost) {
+            if (!case_diffs(listhost,lhost.s)) {
+              flagok = 1;
+              break;                   /* host did match */
+            } else
+              continue;                        /* host didn't match */
+          } else {                     /* none given - grab first */
+            listhost = lhost.s;
+            flagok = 1;
+            break;
+          }
+        }
+      }
+      if (!flagok)
+        listhost = outhost.s;
+      close(fd);
+    }
+    if (!listhost)
+      listhost = outhost.s;
+    if (!userlocal) {
+      if (!stralloc_copys(&usr,sender)) die_nomem();
+      if (!stralloc_0(&usr)) die_nomem();
+      userlocal = usr.s;
+      userhost = usr.s + byte_rchr(usr.s,usr.len-1,'@');
+      if (!*userhost)
+        userhost = 0;
+      else {
+        *userhost = '\0';
+        ++userhost;
+      }
+    }
+
+    if (!stralloc_copys(&to,listlocal)) die_nomem();
+    if (!stralloc_cats(&to,"-")) die_nomem();
+    if (cmdidx) {                      /* recognized - substitute */
+      if (!stralloc_cats(&to,constmap_get(&commandmap,cmdidx)))
+                die_nomem();
+    } else                             /* not recognized - use as is */
+      if (!stralloc_cats(&to,command)) die_nomem();
+
+    if (!stralloc_cats(&to,"-")) die_nomem();
+    if (!stralloc_cats(&to,userlocal)) die_nomem();
+    if (userhost) {                    /* doesn't exist for e.g. -get */
+      if (!stralloc_cats(&to,"=")) die_nomem();
+      if (!stralloc_cats(&to,userhost)) die_nomem();
+    }
+    if (!stralloc_cats(&to,"@")) die_nomem();
+    if (!stralloc_cats(&to,listhost)) die_nomem();
+    if (!stralloc_0(&to)) die_nomem();
+
+    qmail_put(&qq,mydtline.s,mydtline.len);
+
+    flaginheader = 1;
+    flagbadfield = 0;
+
+    if (seek_begin(0) == -1)
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+    substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+
+    for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+
+      if (flaginheader && match) {
+        if (line.len == 1)
+          flaginheader = 0;
+        if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
+          flagbadfield = 0;
+          if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
+           flagbadfield = 1;
+        }
+      }
+      if (!(flaginheader && flagbadfield))
+        qmail_put(&qq,line.s,line.len);
+      if (!match)
+        break;
+    }
+  } else {                             /* commands we deal with */
+    cmdidx = - cmdidx;                 /* now positive */
+    if (cmdidx == EZREQ_WHICH) {       /* arg is user, not list */
+      userlocal = listlocal; listlocal = 0;
+      userhost = listhost; listhost = 0;
+    }
+    if (!stralloc_copys(&from,outlocal.s)) die_nomem();
+    if (!stralloc_cats(&from,"-return-@")) die_nomem();
+    if (!stralloc_cats(&from,outhost.s)) die_nomem();
+    if (!stralloc_0(&from)) die_nomem();
+
+    if (userlocal) {
+      if (!stralloc_copys(&to,userlocal)) die_nomem();
+      if (!stralloc_cats(&to,"@")) die_nomem();
+      if (userhost) {
+        if (!stralloc_cats(&to,userhost)) die_nomem();
+       } else {
+        if (!stralloc_cats(&to,outhost.s)) die_nomem();
+      }
+    } else
+      if (!stralloc_copys(&to,sender)) die_nomem();
+    if (!stralloc_0(&to)) die_nomem();
+
+       /* now we need to look for charset and set flagcd appropriately */
+
+    if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+      if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+        if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+          flagcd = charset.s[charset.len - 1];
+          charset.s[charset.len - 2] = '\0';
+        }
+      }
+    } else
+      if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+    if (!stralloc_0(&charset)) die_nomem();
+    set_cpoutlocal(&listname);         /* necessary in case there are <#l#> */
+    set_cpouthost(&hostname);          /* necessary in case there are <#h#> */
+                                       /* we don't want to be send to a list*/
+    qmail_puts(&qq,"Mailing-List: ezmlm-request");
+    if (getconf(&line,"listid",0,FATAL)) {
+      qmail_puts(&qq,"List-ID: ");
+      qmail_put(&qq,line.s,line.len);
+    }
+    qmail_puts(&qq,"\nDate: ");
+    when = now();
+    datetime_tai(&dt,when);
+    qmail_put(&qq,date,date822fmt(date,&dt));
+    qmail_puts(&qq,"Message-ID: <");
+    if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+       die_nomem();
+    if (!stralloc_append(&line,".")) die_nomem();
+    if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+    if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+    if (!stralloc_cats(&line,outhost.s)) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+    qmail_puts(&qq,line.s);
+    qmail_puts(&qq,">\nFrom: ");
+    if (!quote2(&line,outlocal.s)) die_nomem();
+    qmail_put(&qq,line.s,line.len);
+    if (cmdidx == EZREQ_HELP)
+      qmail_puts(&qq,"-return-@");
+    else
+      qmail_puts(&qq,"-help@");
+    qmail_puts(&qq,outhost.s);
+    qmail_puts(&qq,"\n");
+    qmail_put(&qq,mydtline.s,mydtline.len);
+    qmail_puts(&qq,"To: ");
+    if (!quote2(&line,to.s)) die_nomem();
+    qmail_put(&qq,line.s,line.len);
+    qmail_puts(&qq,"\n");
+    qmail_puts(&qq,"MIME-Version: 1.0\n");
+    if (flagcd) {
+      qmail_puts(&qq,"Content-Type: multipart/mixed; charset=");
+      qmail_puts(&qq,charset.s);
+      qmail_puts(&qq,";\n\tboundary=");
+      qmail_puts(&qq,boundary);
+    } else {
+      qmail_puts(&qq,"Content-type: text/plain; charset=");
+      qmail_puts(&qq,charset.s);
+    }
+    qmail_puts(&qq,"\nSubject: ");
+    if (!quote2(&line,outlocal.s)) die_nomem();
+    qmail_put(&qq,line.s,line.len);
+    qmail_puts(&qq,TXT_RESULTS);
+    transferenc();
+    copy(&qq,"text/top",flagcd,FATAL);
+   if (cmdidx == EZREQ_LISTS || cmdidx == EZREQ_WHICH) {
+      switch (cmdidx) {
+        case EZREQ_LISTS:
+          code_qput("LISTS:",6);
+          break;
+        case EZREQ_WHICH:
+          code_qput("WHICH (",7);
+          code_qput(to.s,to.len - 1);
+          code_qput("):\n\n",4);
+          break;
+        default: break;
+      }
+      fd = open_read(cfname);
+      if (fd == -1)
+        strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": ");
+      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+      for (;;) {
+        if (getln(&sstext,&line,&match,'\n') == -1)
+          strerr_die3sys(111,FATAL,ERR_READ,cfname);
+        if (!match)
+          break;
+        if (line.len <= 1 || line.s[0] == '#')
+          continue;
+        if (!stralloc_0(&line)) die_nomem();
+        pos = str_chr(line.s,':');
+        if (!line.s[pos])
+          break;
+        line.s[pos] = '\0';
+        ++pos;
+        pos1 = pos + str_chr(line.s + pos,':');
+        if (line.s[pos1]) {
+          line.s[pos1] = '\0';
+          ++pos1;
+        } else
+          pos1 = 0;
+
+        switch (cmdidx) {
+          case EZREQ_LISTS:
+            code_qput("\n\n\t",3);
+            code_qput(line.s,pos-1);
+            code_qput("\n",1);
+            if (pos1) {
+              code_qput(line.s+pos1,line.len-2-pos1);
+            }
+            break;
+          case EZREQ_WHICH:
+            if (issub(line.s+pos,to.s,(char *) 0,FATAL)) {
+              code_qput(line.s,pos-1);
+              code_qput("\n",1);
+            }
+           closesql();         /* likely different dbs for different lists */
+            break;
+        }
+      }
+      code_qput("\n",1);
+      close(fd);
+    } else
+      copy(&qq,"text/help",flagcd,FATAL);
+
+    copy(&qq,"text/bottom",flagcd,FATAL);
+    if (flagcd) {
+      if (flagcd == 'B') {
+        encodeB("",0,&line,2,FATAL);   /* flush */
+        qmail_put(&qq,line.s,line.len);
+      }
+       qmail_puts(&qq,"\n--");
+       qmail_puts(&qq,boundary);
+       qmail_puts(&qq,"\nContent-Type: message/rfc822");
+       qmail_puts(&qq,
+               "\nContent-Disposition: inline; filename=request.msg\n\n");
+    }
+    qmail_puts(&qq,"Return-Path: <");
+    if (!quote2(&line,sender)) die_nomem();
+    qmail_put(&qq,line.s,line.len);
+    qmail_puts(&qq,">\n");
+    if (seek_begin(0) == -1)
+      strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
+    if (substdio_copy(&ssqq,&ssin2) != 0)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (flagcd) {
+      qmail_puts(&qq,"\n--");
+      qmail_puts(&qq,boundary);
+      qmail_puts(&qq,"--\n");
+    }
+  }
+  qmail_from(&qq,from.s);
+  qmail_to(&qq,to.s);
+  if (*(err = qmail_close(&qq)) != '\0')
+      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+
+  strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+  strerr_die3x(99,INFO, "qp ",strnum);
+}
index 3f84989..e3a8e89 100644 (file)
@@ -3,12 +3,16 @@
 ezmlm-return \- handle mailing list bounces
 .SH SYNOPSIS
 .B ezmlm-return
 ezmlm-return \- handle mailing list bounces
 .SH SYNOPSIS
 .B ezmlm-return
+[
+.B \-dD
+]
 .I dir
 .SH DESCRIPTION
 .B ezmlm-return
 handles bounces for the mailing list
 stored in
 .I dir
 .SH DESCRIPTION
 .B ezmlm-return
 handles bounces for the mailing list
 stored in
-.IR dir .
+.I dir
+and, if it exists, the associated digest list.
 
 .B ezmlm-return
 is normally invoked from a
 
 .B ezmlm-return
 is normally invoked from a
@@ -21,6 +25,30 @@ and a mail envelope from the
 and
 .BR HOST
 environment variables.
 and
 .BR HOST
 environment variables.
+
+.B ezmlm-return
+exits 99, not 0, upon success.
+.SH OPTIONS
+.TP
+.B \-d
+.B ezmlm-return
+will assume the bounce is for a digest list.
+Normally,
+.B ezmlm-return
+will autodetect this from the bounce address. Autodetection makes
+.B ezmlm-return
+less flexible and will be removed in future versions.
+.TP
+.B \-D
+.B ezmlm-return
+will assume that the bounce is for a normal (non-digest) list.
+Normally,
+.B ezmlm-return
+will autodetect this from the bounce address. Autodetection makes
+.B ezmlm-return
+less flexible and will be removed in future versions.
+.B \-D
+will become the default.
 .SH ADDRESSES
 .B ezmlm-return
 handles mail sent to any of the following addresses:
 .SH ADDRESSES
 .B ezmlm-return
 handles mail sent to any of the following addresses:
@@ -59,6 +87,21 @@ bounced.
 will remove
 .I box\fB@\fIdomain
 from the mailing list.
 will remove
 .I box\fB@\fIdomain
 from the mailing list.
+.TP
+.I local\fB\-return\-receipt\-\fIcookie\-fImsg\-
+A receipt from the list. This is logged. For SQL supporting lists,
+.I cookie
+is verified and receipt logged only if the cookie is correct. The arrival
+of the receipt shows that qmail at the sending host is running.
+
+For all the above addresses if,
+.I local
+is followed by
+.IR \-digest ,
+bounces are assumed to be from the digest list, and are stored in
+.I dir\fB/digest/bounce
+rather than in
+.I dir \fB/bounce .
 .SH "SEE ALSO"
 ezmlm-manage(1),
 ezmlm-make(1),
 .SH "SEE ALSO"
 ezmlm-manage(1),
 ezmlm-make(1),
index 3bc2421..7ca3fb2 100644 (file)
@@ -1,3 +1,7 @@
+/*$Id: ezmlm-return.c,v 1.26 1999/08/07 20:50:52 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include <sys/types.h>
+#include "direntry.h"
 #include "stralloc.h"
 #include "str.h"
 #include "env.h"
 #include "stralloc.h"
 #include "str.h"
 #include "env.h"
 #include "now.h"
 #include "cookie.h"
 #include "subscribe.h"
 #include "now.h"
 #include "cookie.h"
 #include "subscribe.h"
-#include "issub.h"
+#include "errtxt.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-return: fatal: "
 
 #define FATAL "ezmlm-return: fatal: "
-void die_usage() { strerr_die1x(100,"ezmlm-return: usage: ezmlm-return dir"); }
-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+#define INFO "ezmlm-return: info: "
+void die_usage()
+{ strerr_die1x(100,"ezmlm-return: usage: ezmlm-return [-dD] dir"); }
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
 void die_badaddr()
 {
 void die_badaddr()
 {
-  strerr_die2x(100,FATAL,"I do not accept messages at this address (#5.1.1)");
+  strerr_die2x(100,FATAL,ERR_BAD_RETURN_ADDRESS);
 }
 void die_trash()
 {
 }
 void die_trash()
 {
-  strerr_die1x(0,"ezmlm-return: info: trash address");
+  strerr_die2x(99,INFO,"trash address");
 }
 
 char outbuf[1024];
 }
 
 char outbuf[1024];
@@ -38,21 +45,37 @@ substdio ssin;
 char strnum[FMT_ULONG];
 char hash[COOKIE];
 char hashcopy[COOKIE];
 char strnum[FMT_ULONG];
 char hash[COOKIE];
 char hashcopy[COOKIE];
+char *hashp = (char *) 0;
 unsigned long cookiedate;
 unsigned long cookiedate;
+unsigned long addrno = 0L;
+unsigned long addrno1 = 0L;
+stralloc fndir = {0};
 stralloc fndate = {0};
 stralloc fndatenew = {0};
 stralloc fnhash = {0};
 stralloc fnhashnew = {0};
 stralloc fndate = {0};
 stralloc fndatenew = {0};
 stralloc fnhash = {0};
 stralloc fnhashnew = {0};
+void *psql = (void *) 0;
 
 stralloc quoted = {0};
 
 stralloc quoted = {0};
+stralloc ddir = {0};
 char *sender;
 char *sender;
+char *dir;
+char *workdir;
 
 void die_hashnew()
 
 void die_hashnew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fnhashnew.s,": "); }
 void die_datenew()
 void die_datenew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); }
 void die_msgin()
 void die_msgin()
-{ strerr_die2sys(111,FATAL,"unable to read input: "); }
+{ strerr_die2sys(111,FATAL,ERR_READ_INPUT); }
+
+void makedir(s)
+char *s;
+{
+  if (mkdir(s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die4x(111,FATAL,ERR_CREATE,s,": ");
+}
 
 void dowit(addr,when,bounce)
 char *addr;
 
 void dowit(addr,when,bounce)
 char *addr;
@@ -60,16 +83,31 @@ unsigned long when;
 stralloc *bounce;
 {
   int fd;
 stralloc *bounce;
 {
   int fd;
+  unsigned int wpos;
+  unsigned long wdir,wfile;
 
 
-  if (!issub(addr)) return;
+  if (!issub(workdir,addr,(char *) 0,FATAL)) return;
 
 
-  if (!stralloc_copys(&fndate,"bounce/w")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_copys(&fndate,workdir)) die_nomem();
+  if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  fndate.s[fndate.len - 1] = '/';      /* replace '\0' */
+  wpos = fndate.len - 1;
+  wdir = when / 10000;
+  wfile = when - 10000 * wdir;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wdir))) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  makedir(fndate.s);
+  --fndate.len;                                /* remove terminal '\0' */
+  if (!stralloc_cats(&fndate,"/w")) die_nomem();
+  wpos = fndate.len - 1;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,wfile))) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+       die_nomem();
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
-  fndatenew.s[7] = 'W';
+  fndatenew.s[wpos] = 'W';
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
@@ -86,7 +124,7 @@ stralloc *bounce;
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   if (rename(fndatenew.s,fndate.s) == -1)
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   if (rename(fndatenew.s,fndate.s) == -1)
-    strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+    strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
 }
 
 void doit(addr,msgnum,when,bounce)
 }
 
 void doit(addr,msgnum,when,bounce)
@@ -97,16 +135,37 @@ stralloc *bounce;
 {
   int fd;
   int fdnew;
 {
   int fd;
   int fdnew;
+  unsigned int pos;
+  unsigned long ddir,dfile;
 
 
-  if (!issub(addr)) return;
+  if (!issub(workdir,addr,(char *) 0,FATAL)) return;
 
 
-  if (!stralloc_copys(&fndate,"bounce/d")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,when))) die_nomem();
+  if (!stralloc_copys(&fndate,workdir)) die_nomem();
+  if (!stralloc_cats(&fndate,"/bounce/d")) die_nomem();
+  if (!stralloc_0(&fndate)) die_nomem();
+  makedir(fndate.s);
+  fndate.s[fndate.len-1] = '/';                /* replace terminal '\0' */
+  ddir = when / 10000;
+  dfile = when - 10000 * ddir;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,ddir))) die_nomem();
+  if (!stralloc_copy(&fndir,&fndate)) die_nomem();
+  if (!stralloc_0(&fndir)) die_nomem();        /* make later if necessary (new addr)*/
+  if (!stralloc_cats(&fndate,"/d")) die_nomem();
+  pos = fndate.len - 2;
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,dfile))) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
   if (!stralloc_cats(&fndate,".")) die_nomem();
-  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+        die_nomem();
+  if (addrno) {        /* so that pre-VERP bounces make a d... file per address */
+               /* for the first one we use the std-style fname */
+    if (!stralloc_cats(&fndate,".")) die_nomem();
+    if (!stralloc_catb(&fndate,strnum,fmt_ulong(strnum,addrno))) die_nomem();
+  }
+  addrno++;    /* get ready for next */
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
   if (!stralloc_0(&fndate)) die_nomem();
   if (!stralloc_copy(&fndatenew,&fndate)) die_nomem();
-  fndatenew.s[7] = 'D';
+  fndatenew.s[pos] = '_';      /* fndate = bounce/d/nnnn/dmmmmmm */
+                               /* fndatenew = bounce/d/nnnn_dmmmmmm */
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
 
   fd = open_trunc(fndatenew.s);
   if (fd == -1) die_datenew();
@@ -123,11 +182,21 @@ stralloc *bounce;
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   cookie(hash,"",0,"",addr,"");
   if (close(fd) == -1) die_datenew(); /* NFS stupidity */
 
   cookie(hash,"",0,"",addr,"");
-  if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem();
-  if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem();
+  if (!stralloc_copys(&fnhash,workdir)) die_nomem();
+  if (!stralloc_cats(&fnhash,"/bounce/h")) die_nomem();
+  if (!stralloc_0(&fnhash)) die_nomem();
+  makedir(fnhash.s);
+  fnhash.s[fnhash.len - 1] = '/';              /* replace terminal '\0' */
+  if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
+  if (!stralloc_0(&fnhash)) die_nomem();
+  makedir(fnhash.s);
+  --fnhash.len;                                        /* remove terminal '\0' */
+  if (!stralloc_cats(&fnhash,"/h")) die_nomem();
+  pos = fnhash.len - 1;
+  if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
   if (!stralloc_0(&fnhash)) die_nomem();
   if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem();
   if (!stralloc_0(&fnhash)) die_nomem();
   if (!stralloc_copy(&fnhashnew,&fnhash)) die_nomem();
-  fnhashnew.s[7] = 'H';
+  fnhashnew.s[pos] = 'H';
 
   fdnew = open_trunc(fnhashnew.s);
   if (fdnew == -1) die_hashnew();
 
   fdnew = open_trunc(fnhashnew.s);
   if (fdnew == -1) die_hashnew();
@@ -136,9 +205,10 @@ stralloc *bounce;
   fd = open_read(fnhash.s);
   if (fd == -1) {
     if (errno != error_noent)
   fd = open_read(fnhash.s);
   if (fd == -1) {
     if (errno != error_noent)
-      strerr_die4sys(111,FATAL,"unable to read ",fnhash.s,": ");
+      strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
+    makedir(fndir.s);
     if (rename(fndatenew.s,fndate.s) == -1)
     if (rename(fndatenew.s,fndate.s) == -1)
-      strerr_die6sys(111,FATAL,"unable to rename ",fndatenew.s," to ",fndate.s,": ");
+      strerr_die6sys(111,FATAL,ERR_MOVE,fndatenew.s," to ",fndate.s,": ");
   }
   else {
     substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
   }
   else {
     substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
@@ -148,7 +218,7 @@ stralloc *bounce;
     }
     close(fd);
     if (unlink(fndatenew.s) == -1)
     }
     close(fd);
     if (unlink(fndatenew.s) == -1)
-      strerr_die4sys(111,FATAL,"unable to unlink ",fndatenew.s,": ");
+      strerr_die4sys(111,FATAL,ERR_DELETE,fndatenew.s,": ");
   }
   if (substdio_puts(&ssout,"   ") == -1) die_hashnew();
   if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew();
   }
   if (substdio_puts(&ssout,"   ") == -1) die_hashnew();
   if (substdio_put(&ssout,strnum,fmt_ulong(strnum,msgnum)) == -1) die_hashnew();
@@ -158,7 +228,7 @@ stralloc *bounce;
   if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */
 
   if (rename(fnhashnew.s,fnhash.s) == -1)
   if (close(fdnew) == -1) die_hashnew(); /* NFS stupidity */
 
   if (rename(fnhashnew.s,fnhash.s) == -1)
-    strerr_die6sys(111,FATAL,"unable to rename ",fnhashnew.s," to ",fnhash.s,": ");
+    strerr_die6sys(111,FATAL,ERR_MOVE,fnhashnew.s," to ",fnhash.s,": ");
 }
 
 stralloc bounce = {0};
 }
 
 stralloc bounce = {0};
@@ -167,14 +237,11 @@ stralloc header = {0};
 stralloc intro = {0};
 stralloc failure = {0};
 stralloc paragraph = {0};
 stralloc intro = {0};
 stralloc failure = {0};
 stralloc paragraph = {0};
+int flagmasterbounce = 0;
 int flaghaveheader;
 int flaghaveintro;
 
 stralloc key = {0};
 int flaghaveheader;
 int flaghaveintro;
 
 stralloc key = {0};
-stralloc inhost = {0};
-stralloc outhost = {0};
-stralloc inlocal = {0};
-stralloc outlocal = {0};
 
 char msginbuf[1024];
 substdio ssmsgin;
 
 char msginbuf[1024];
 substdio ssmsgin;
@@ -183,16 +250,22 @@ void main(argc,argv)
 int argc;
 char **argv;
 {
 int argc;
 char **argv;
 {
-  char *dir;
-  char *host;
   char *local;
   char *action;
   char *local;
   char *action;
+  char *def;
+  char *ret;
+  char *cp;
   unsigned long msgnum;
   unsigned long cookiedate;
   unsigned long when;
   unsigned long msgnum;
   unsigned long cookiedate;
   unsigned long when;
+  unsigned long listno = 0L;
   int match;
   int match;
-  int i;
+  unsigned int i;
+  int flagdig = 0;
+  int flagmaster = 0;
+  int flagreceipt = 0;
   int fdlock;
   int fdlock;
+  register char ch;
 
   umask(022);
   sig_pipeignore();
 
   umask(022);
   sig_pipeignore();
@@ -200,104 +273,158 @@ char **argv;
 
   dir = argv[1];
   if (!dir) die_usage();
 
   dir = argv[1];
   if (!dir) die_usage();
+  if (*dir == '-') {                   /* for normal use */
+    if (dir[1] == 'd') {
+      flagdig = 1;
+    } else if (dir[1] == 'D') {
+      flagdig = 0;
+    } else
+      die_usage();
+    dir = argv[2];
+    if (!dir) die_usage();
+  }
 
   sender = env_get("SENDER");
 
   sender = env_get("SENDER");
-  if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+  if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
   local = env_get("LOCAL");
   local = env_get("LOCAL");
-  if (!local) strerr_die2x(100,FATAL,"LOCAL not set");
-  host = env_get("HOST");
-  if (!host) strerr_die2x(100,FATAL,"HOST not set");
+  if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+  def = env_get("DEFAULT");            /* qmail-1.02 */
 
   if (chdir(dir) == -1)
 
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
 
   switch(slurp("key",&key,32)) {
     case -1:
 
   switch(slurp("key",&key,32)) {
     case -1:
-      strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
     case 0:
     case 0:
-      strerr_die3x(100,FATAL,dir,"/key does not exist");
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
   }
   }
-  getconf_line(&inhost,"inhost",1,FATAL,dir);
-  getconf_line(&inlocal,"inlocal",1,FATAL,dir);
-  getconf_line(&outhost,"outhost",1,FATAL,dir);
-  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
-
-  if (inhost.len != str_len(host)) die_badaddr();
-  if (case_diffb(inhost.s,inhost.len,host)) die_badaddr();
-  if (inlocal.len > str_len(local)) die_badaddr();
-  if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+  workdir = dir;
+  action = def;
 
 
-  action = local + inlocal.len;
-
-  if (!str_start(action,"-return-")) die_badaddr();
-  action += 8;
+    if (str_start(action,"receipt-")) {
+      flagreceipt = 1;
+      action += 8;
+    }
+    ch = *action;              /* -d -digest, -m -master, -g -getmaster */
+    if (ch && action[1] == '-') {
+      switch (ch) {
+       case 'g': flagmaster = 1; flagdig = 1; action += 2; break;
+       case 'm': flagmaster = 1; action += 2; break;
+       default: break;
+      }
+    }
+  if (flagdig) {
+    if (!stralloc_copys(&ddir,dir)) die_nomem();
+    if (!stralloc_cats(&ddir,"/digest")) die_nomem();
+    if (!stralloc_0(&ddir)) die_nomem();
+    workdir = ddir.s;
+  }
 
   if (!*action) die_trash();
 
 
   if (!*action) die_trash();
 
-  if (str_start(action,"probe-")) {
-    action += 6;
-    action += scan_ulong(action,&cookiedate);
-    if (now() - cookiedate > 3000000) die_trash();
-    if (*action++ != '.') die_trash();
-    i = str_chr(action,'-');
-    if (i != COOKIE) die_trash();
-    byte_copy(hashcopy,COOKIE,action);
-    action += COOKIE;
-    if (*action++ != '-') die_trash();
-    i = str_rchr(action,'=');
-    if (!stralloc_copyb(&line,action,i)) die_nomem();
-    if (action[i]) {
-      if (!stralloc_cats(&line,"@")) die_nomem();
-      if (!stralloc_cats(&line,action + i + 1)) die_nomem();
-    }
-    if (!stralloc_0(&line)) die_nomem();
-    strnum[fmt_ulong(strnum,cookiedate)] = 0;
-    cookie(hash,key.s,key.len,strnum,line.s,"P");
-    if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
-
-    if (subscribe(line.s,0) == 1) log("-probe",line.s);
-    _exit(0);
+  if (flagreceipt || flagmaster)                       /* check cookie */
+    if (str_chr(action,'-') == COOKIE) {
+      action[COOKIE] = '\0';
+      hashp = action;
+      action += COOKIE + 1;
   }
 
   }
 
-  fdlock = open_append("lockbounce");
-  if (fdlock == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
-  if (lock_ex(fdlock) == -1)
-    strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: ");
-
-  if (str_start(action,"warn-")) {
-    action += 5;
-    action += scan_ulong(action,&cookiedate);
-    if (now() - cookiedate > 3000000) die_trash();
-    if (*action++ != '.') die_trash();
-    i = str_chr(action,'-');
-    if (i != COOKIE) die_trash();
-    byte_copy(hashcopy,COOKIE,action);
-    action += COOKIE;
-    if (*action++ != '-') die_trash();
-    i = str_rchr(action,'=');
-    if (!stralloc_copyb(&line,action,i)) die_nomem();
-    if (action[i]) {
-      if (!stralloc_cats(&line,"@")) die_nomem();
-      if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+  if (!flagreceipt) {
+    if (!flagmaster && str_start(action,"probe-")) {
+      action += 6;
+      action += scan_ulong(action,&cookiedate);
+      if (now() - cookiedate > 3000000) die_trash();
+      if (*action++ != '.') die_trash();
+      i = str_chr(action,'-');
+      if (i != COOKIE) die_trash();
+      byte_copy(hashcopy,COOKIE,action);
+      action += COOKIE;
+      if (*action++ != '-') die_trash();
+      i = str_rchr(action,'=');
+      if (!stralloc_copyb(&line,action,i)) die_nomem();
+      if (action[i]) {
+       if (!stralloc_cats(&line,"@")) die_nomem();
+       if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+      }
+      if (!stralloc_0(&line)) die_nomem();
+      strnum[fmt_ulong(strnum,cookiedate)] = 0;
+      cookie(hash,key.s,key.len,strnum,line.s,"P");
+      if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+      (void) subscribe(workdir,line.s,0,"","-probe",1,-1,(char *) 0,FATAL);
+      _exit(99);
     }
     }
+
+    if (!stralloc_copys(&line,workdir)) die_nomem();
+    if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
     if (!stralloc_0(&line)) die_nomem();
     if (!stralloc_0(&line)) die_nomem();
-    strnum[fmt_ulong(strnum,cookiedate)] = 0;
-    cookie(hash,key.s,key.len,strnum,line.s,"W");
-    if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
 
 
-    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
-    dowit(line.s,when,&bounce);
-    _exit(0);
+    fdlock = open_append(line.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": ");
+
+    if (!flagmaster && str_start(action,"warn-")) {
+      action += 5;
+      action += scan_ulong(action,&cookiedate);
+      if (now() - cookiedate > 3000000) die_trash();
+      if (*action++ != '.') die_trash();
+      i = str_chr(action,'-');
+      if (i != COOKIE) die_trash();
+      byte_copy(hashcopy,COOKIE,action);
+      action += COOKIE;
+      if (*action++ != '-') die_trash();
+      i = str_rchr(action,'=');
+      if (!stralloc_copyb(&line,action,i)) die_nomem();
+      if (action[i]) {
+        if (!stralloc_cats(&line,"@")) die_nomem();
+        if (!stralloc_cats(&line,action + i + 1)) die_nomem();
+      }
+      if (!stralloc_0(&line)) die_nomem();
+      strnum[fmt_ulong(strnum,cookiedate)] = 0;
+      cookie(hash,key.s,key.len,strnum,line.s,"W");
+      if (byte_diff(hash,COOKIE,hashcopy)) die_trash();
+
+      if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+      dowit(line.s,when,&bounce);
+      _exit(99);
+    }
   }
   }
-
   action += scan_ulong(action,&msgnum);
   action += scan_ulong(action,&msgnum);
-  if (*action != '-') die_badaddr();
-  ++action;
+  if (*action++ != '-') die_badaddr();
+  cp = action;
+  if (*action >= '0' && *action <= '9') {              /* listno */
+    action += scan_ulong(action,&listno);
+    listno++;                                  /* logging is 1-53, not 0-52 */
+  }
 
 
-  if (*action) {
-    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
+  if (hashp) {         /* scrap bad cookies */
+      if ((ret = checktag(workdir,msgnum,0L,"x",(char *) 0,hashp))) {
+        if (*ret)
+         strerr_die2x(111,FATAL,*ret);
+       else
+         die_trash();
+      } else if (flagreceipt) {
+       if (!(ret = logmsg(dir,msgnum,listno,0L,5))) {
+         closesql();
+         strerr_die6x(99,INFO,"receipt:",cp," [",hashp,"]");
+       }
+       if (*ret) strerr_die2x(111,FATAL,ret);
+       else strerr_die2x(0,INFO,ERR_DONE);
+      } else if (*action) {    /* post VERP master bounce */
+       if ((ret = logmsg(dir,msgnum,listno,0L,-1))) {
+         closesql();
+         strerr_die4x(0,INFO,"bounce [",hashp,"]");
+       }
+       if (*ret) strerr_die2x(111,FATAL,ret);
+       else strerr_die2x(99,INFO,ERR_DONE);
+      }
+   } else if (flagreceipt || flagmaster)
+       die_badaddr();
 
 
+  if (*action) {
     i = str_rchr(action,'=');
     if (!stralloc_copyb(&line,action,i)) die_nomem();
     if (action[i]) {
     i = str_rchr(action,'=');
     if (!stralloc_copyb(&line,action,i)) die_nomem();
     if (action[i]) {
@@ -305,11 +432,12 @@ char **argv;
       if (!stralloc_cats(&line,action + i + 1)) die_nomem();
     }
     if (!stralloc_0(&line)) die_nomem();
       if (!stralloc_cats(&line,action + i + 1)) die_nomem();
     }
     if (!stralloc_0(&line)) die_nomem();
+    if (slurpclose(0,&bounce,1024) == -1) die_msgin();
     doit(line.s,msgnum,when,&bounce);
     doit(line.s,msgnum,when,&bounce);
-    _exit(0);
+    _exit(99);
   }
 
   }
 
-  /* pre-VERP bounce, in QSBMF format */
+  /* pre-VERP bounce, in QSBMF format. Receipts are never pre-VERP */
 
   substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf));
 
 
   substdio_fdbuf(&ssmsgin,read,0,msginbuf,sizeof(msginbuf));
 
@@ -332,6 +460,8 @@ char **argv;
     }
 
     if (!flaghaveintro) {
     }
 
     if (!flaghaveintro) {
+      if (paragraph.s[0] == '-' && paragraph.s[1] == '-')
+        continue;              /* skip MIME boundary if it exists */
       if (paragraph.len < 15) die_trash();
       if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
       if (!stralloc_copy(&intro,&paragraph)) die_nomem();
       if (paragraph.len < 15) die_trash();
       if (str_diffn(paragraph.s,"Hi. This is the",15)) die_trash();
       if (!stralloc_copy(&intro,&paragraph)) die_nomem();
@@ -355,10 +485,23 @@ char **argv;
       if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem();
       if (byte_chr(line.s,line.len,'\0') == line.len) {
         if (!stralloc_0(&line)) die_nomem();
       if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem();
       if (byte_chr(line.s,line.len,'\0') == line.len) {
         if (!stralloc_0(&line)) die_nomem();
-        doit(line.s,msgnum,when,&bounce);
+        if (flagmaster) {                              /* bounced msg slave! */
+         if ((i = str_rchr(line.s,'@')) >= 5) {        /* 00_52@host */
+           line.s[i] = '\0';                           /* 00_52 */
+           (void) scan_ulong(line.s + i - 5,&listno);
+             if ((ret = logmsg(dir,msgnum,listno + 1,0L,-1)) && *ret)
+               strerr_die2x(111,FATAL,ret);
+           strerr_warn3(INFO,"bounce ",line.s + i - 5,(struct strerr *) 0);
+           flagmasterbounce = 1;
+         }
+       } else
+         doit(line.s,msgnum,when,&bounce);
       }
     }
   }
       }
     }
   }
-
-  _exit(0);
+  closesql();
+  if (flagmasterbounce)
+    strerr_die3x(0,"[",hashp,"]");
+  else
+    _exit(99);
 }
 }
index ff70976..b7ccc59 100644 (file)
@@ -3,6 +3,11 @@
 ezmlm-send \- distribute a message to a mailing list
 .SH SYNOPSIS
 .B ezmlm-send
 ezmlm-send \- distribute a message to a mailing list
 .SH SYNOPSIS
 .B ezmlm-send
+[
+.B \-cCrRvV
+] [
+.B \-h\fI header
+]
 .I dir
 .SH DESCRIPTION
 .B ezmlm-send
 .I dir
 .SH DESCRIPTION
 .B ezmlm-send
@@ -14,9 +19,34 @@ If
 exists,
 .B ezmlm-send
 records a copy of the message in the
 exists,
 .B ezmlm-send
 records a copy of the message in the
-.I dir\fB/archive
+.I dir\fB/archive/
 directory.
 
 directory.
 
+If
+.I dir\fB/indexed
+exists,
+.B ezmlm-send
+adds the subject, author and time stamp of the message to the index, kept with
+the message in a subdirectory of
+.IR dir\fB/archive/ .
+The subject is processed to make reply-subject entries identical to
+original
+message subject entries.
+The subject index is used for the archive retrieval functions of
+.BR ezmlm-get(1) .  
+Use
+.B ezmlm-idx(1)
+to create a subject index from a preexisting archive.
+
+Subject and author lines are decoded if they are encoded per rfc2047. When
+split lines are unfolded, the number of escape sequences for
+iso-2022-* character sets is minimized. For instance, two
+consequtive toascii sequences are reduced.
+This processing is done for the character set specified in
+.IR dir\fB/charset .
+The result of this process is the same for a given subject, irrespective
+of encoding.
+
 At the beginning of the message,
 .B ezmlm-send
 prints a new
 At the beginning of the message,
 .B ezmlm-send
 prints a new
@@ -27,10 +57,24 @@ It rejects the message if there is already a
 .B Mailing-List
 field.
 
 .B Mailing-List
 field.
 
+If
+.I dir\fB/listid
+exists,
+.B ezmlm-send
+will assume that the format is correct and
+create a ``List-ID:'' header by placing the contents after the
+text ``List-ID: ''. 
+
+Next,
+.B ezmlm-send
+prints all the new fields listed in
+.IR dir\fB/headeradd .
+Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in these headers
+are replaced by the list host name, list local name, and message number,
+respectively.
+
 .B ezmlm-send
 .B ezmlm-send
-then prints all the new fields listed in
-.IR dir\fB/headeradd ,
-followed by an appropriate
+then prints an appropriate
 .B Delivered-To
 line.
 
 .B Delivered-To
 line.
 
@@ -39,6 +83,63 @@ deletes any incoming fields with names listed in
 .IR dir\fB/headerremove .
 
 .B ezmlm-send
 .IR dir\fB/headerremove .
 
 .B ezmlm-send
+removes MIME parts specified in
+.I dir\fB/mimeremove
+before archiving and distribution of the message.
+
+If
+.I dir\fB/text/trailer
+exists,
+.B ezmlm-send
+adds the trailer to simple text/plain messages in the same encoding as used for
+the the message. However, if the encoding is ``base64'' it is not safe
+to do this and the header is suppressed.
+For composite MIME messages, the trailer is added as a separate
+part, with the character set and encoding specified in
+.IR dir\fB/charset .
+The trailer is not added to multipart/alternative messages.
+Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in
+.I dir\fB/text/trailer
+are replaced by the list host name, list local name, and message number,
+respectively.
+
+If
+.I dir\fB/prefix
+exists,
+.B ezmlm-send
+will prefix the subject line with the first line of this
+file. A space will be added to separate
+.B prefix
+from the subject text.
+.B prefix
+is ignored for sublists. If
+.I dir\fB/prefix
+contains a ``#'', the last ``#'' will be replaced by the message number.
+Any prefix starting with text of a
+reply indicator (``Re:'', ``Re[n]:'', etc) will cause problems.
+The prefix may be
+rfc2047 encoded. Rfc2047 Iso-2022-* encoded prefixes
+.I must
+end in ascii.
+
+The prefix feature and especially the message number feature
+modify the message in violation
+with Internet mail standards. The features have been implemented by popular
+demand. Use at your own peril.
+
+.I dir\fB/sequence
+is ignored as of ezmlm-idx-0.32. Use
+.I dir\fB/headeradd
+with substitution to achieve the same goal.
+
+If
+.I dir\fB/qmqpservers
+exists,
+.B ezmlm-send will use
+.B qmail-qmqp(1)
+to send messages.
+
+.B ezmlm-send
 does not distribute bounce messages:
 if the environment variable
 .B SENDER
 does not distribute bounce messages:
 if the environment variable
 .B SENDER
@@ -46,6 +147,60 @@ is set, and is either empty or
 .BR #@[] ,
 .B ezmlm-send
 rejects the message.
 .BR #@[] ,
 .B ezmlm-send
 rejects the message.
+.SH OPTIONS
+.TP
+.B \-c
+No longer supported. Ignored for backwards compatibility.
+.TP
+.B \-C
+No longer supported. Ignored for backwards compatibility.
+.B ezmlm-send
+has to parse the subscriber database.
+.TP
+.B \-h\fI header
+If the list is a sublist, i.e.
+.I dir\fB/sublist
+exists,
+.I header
+is required in all messages to the list. This option is used
+when ezmlm is used to run a sublist of a lists run by a different
+mailing list
+manager that uses
+.I header
+rather than ``Mailing-List'' to identify messages from the list.
+Anything after the first colon (if present) in
+.I header
+is ignored.
+.TP
+.B \-r
+Copy incoming ``Received:'' headers to the outgoing message.
+.TP
+.B \-R
+(Default.)
+Do not copy incoming ``Received:'' headers, except the one added by
+the (last) listhost, to the outgoing message.
+In some
+cases, especially for sublists,
+the messages can have a large number of ``Received:''
+headers. This may lead to bounces for some users due to
+sendmail ``hopcounts'' set too low somewhere in the mail path. These users can
+subscribe and receive warning and probe messages, but no list messages, unless
+the number of ``Received:'' headers is reduced.
+
+Pre-list ``Received:'' headers are of little interest to normal list
+subscribers. ``Received:'' headers are
+still copied to the archive and available
+to anyone from there for message tracking purposes.
+.TP
+.B \-v
+Display
+.B ezmlm-send
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-send
+version information.
 .SH "SUBLISTS"
 If
 .I dir\fB/sublist
 .SH "SUBLISTS"
 If
 .I dir\fB/sublist
@@ -77,10 +232,71 @@ Third,
 does not add its own
 .B Mailing-List
 field.
 does not add its own
 .B Mailing-List
 field.
+
+Fourth,
+.B ezmlm-send
+uses the incoming message number for the outgoing message, if the list
+is not archived and the incoming SENDER has the correct format.
+This allows you to refer bounce warning recipients to the main list for
+archive retrieval of the missed messages. If the sublist archives
+message, it is assumed that missed messages will be retrieved from the sublist
+archive.
+
+The list
+still increments
+.I dir\fB/num
+for each message. If the sublist is archived, use of incoming message number
+for archive storage would be a security risk. In this case, the local sublist
+message number is used.
+.SH "OPTION USAGE"
+In general, the use of a prefix is discouraged. It wastes subject line space,
+creates trouble when MUAs add non-standard reply indicators. However, many
+users expect it not because it is useful, but because they are used to it.
+
+The
+.B \-C
+switch prevents posts from being set to SENDER. Rather than just copying
+out subscriber address files,
+.B ezmlm-send
+has to parse them to look for SENDER. This makes it less efficient. Also,
+it is useful for the SENDER to see the post to know that it has made it
+to the list, and it's context to other subscribers, i.e. where it came
+within the traffic of messages on the list.
+
+Avoiding SENDER as a recipient is useful in small lists, such as small
+teams with varying members, where ezmlm serves mainly as an efficient tool
+to keep the team connected without administrator intervention. Here the
+overhead of subscriber list parsing is negligible.
+.SH "CHARACTER SETS"
+If the list is indexed,
+.B ezmlm-send
+will keep a message index. rfc2047-encoded subject and from lines will be
+decoded.
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-send
+will eliminate redundant escape sequences from the headers according to
+the character set specified in this file.
+Only character sets using escape sequences need this support. Currently,
+supported are iso-2022-jp*, iso-2022-kr, and iso-2022-cn*. Only iso-2022-jp
+has been tested extensively.
+
+The character set can be suffixed
+by ``:'' followed by a code. Recognized codes are ``Q'' 
+for ``Quoted-Printable'', and ``B'' for ``base64''.
+
+For
+.BR ezmlm-send ,
+this affects the format of the trailer, if a trailer is specified and if the
+message is a multipart mime message
 .SH "SEE ALSO"
 .SH "SEE ALSO"
+ezmlm-get(1),
+ezmlm-idx(1),
 ezmlm-manage(1),
 ezmlm-make(1),
 ezmlm-sub(1),
 ezmlm-unsub(1),
 ezmlm-reject(1),
 ezmlm-manage(1),
 ezmlm-make(1),
 ezmlm-sub(1),
 ezmlm-unsub(1),
 ezmlm-reject(1),
-ezmlm(5)
+ezmlm(5),
+qmail-qmqp(1)
index 5748891..fa2913e 100644 (file)
@@ -1,3 +1,5 @@
+/* $Id: ezmlm-send.c,v 1.77 1999/10/29 02:49:14 lindberg Exp $*/
+/* $Name: ezmlm-idx-040 $*/
 #include "stralloc.h"
 #include "subfd.h"
 #include "strerr.h"
 #include "stralloc.h"
 #include "subfd.h"
 #include "strerr.h"
 #include "substdio.h"
 #include "getconf.h"
 #include "constmap.h"
 #include "substdio.h"
 #include "getconf.h"
 #include "constmap.h"
-
+#include "byte.h"
+#include "sgetopt.h"
+#include "quote.h"
+#include "subscribe.h"
+#include "mime.h"
+#include "errtxt.h"
+#include "makehash.h"
+#include "cookie.h"
+#include "idx.h"
+#include "copy.h"
+
+int flagnoreceived = 1;                /* suppress received headers by default. They*/
+                               /* are still archived. =0 => archived and */
+                               /* copied. */
+int flaglog = 1;               /* for lists with mysql support, use tags */
+                               /* and log traffic to the database */
 #define FATAL "ezmlm-send: fatal: "
 
 void die_usage()
 {
 #define FATAL "ezmlm-send: fatal: "
 
 void die_usage()
 {
-  strerr_die1x(100,"ezmlm-send: usage: ezmlm-send dir");
+  strerr_die1x(100,"ezmlm-send: usage: ezmlm-send [-cClLqQrR] [-h header] dir");
 }
 void die_nomem()
 {
 }
 void die_nomem()
 {
-  strerr_die2x(111,FATAL,"out of memory");
+  strerr_die2x(111,FATAL,ERR_NOMEM);
 }
 
 }
 
+       /* for writing new index file indexn later moved to index. */
+substdio ssindexn;
+char indexnbuf[1024];
+
 char strnum[FMT_ULONG];
 char strnum[FMT_ULONG];
+char szmsgnum[FMT_ULONG];
+char hash[HASHLEN];
 
 stralloc fnadir = {0};
 stralloc fnaf = {0};
 
 stralloc fnadir = {0};
 stralloc fnaf = {0};
+stralloc fnif = {0};
+stralloc fnifn = {0};
 stralloc fnsub = {0};
 stralloc line = {0};
 stralloc fnsub = {0};
 stralloc line = {0};
+stralloc qline = {0};
+stralloc lines = {0};
+stralloc subject = {0};
+stralloc from = {0};
+stralloc received = {0};
+stralloc prefix = {0};
+stralloc content = {0};
+stralloc boundary = {0};
+stralloc charset = {0};
+stralloc dcprefix = {0};
+stralloc dummy = {0};
+stralloc qmqpservers = {0};
+
+void die_indexn()
+{
+  strerr_die4x(111,FATAL,ERR_WRITE,fnifn.s,": ");
+}
 
 
+void *psql = (void *) 0;
+
+unsigned long innum;
+unsigned long outnum;
+unsigned long msgnum;
+unsigned long hash_lo = 0L;
+unsigned long hash_hi = 52L;
+unsigned long msgsize = 0L;
+unsigned long cumsize = 0L;    /* cumulative archive size bytes / 256 */
+char flagcd = '\0';            /* no transfer-encoding for trailer */
+char encin = '\0';
+int flagindexed;
+int flagfoundokpart;           /* Found something to pass on. If multipart */
+                               /* we set to 0 and then set to 1 for any */
+                               /* acceptable mime part. If 0 -> reject */
+int flagreceived;
+int flagprefixed;
+unsigned int serial = 0;
 int flagarchived;
 int fdarchive;
 int flagarchived;
 int fdarchive;
+int fdindex;
+int fdindexn;
+char hashout[COOKIE+1];
+
 substdio ssarchive;
 char archivebuf[1024];
 
 substdio ssarchive;
 char archivebuf[1024];
 
@@ -48,7 +112,9 @@ stralloc outlocal = {0};
 stralloc outhost = {0};
 stralloc headerremove = {0};
 struct constmap headerremovemap;
 stralloc outhost = {0};
 stralloc headerremove = {0};
 struct constmap headerremovemap;
-stralloc headeradd = {0};
+stralloc mimeremove = {0};
+struct constmap mimeremovemap;
+char *dir;
 
 struct qmail qq;
 substdio ssin;
 
 struct qmail qq;
 substdio ssin;
@@ -56,7 +122,10 @@ char inbuf[1024];
 substdio ssout;
 char outbuf[1];
 
 substdio ssout;
 char outbuf[1];
 
-int mywrite(fd,buf,len)
+char textbuf[512];
+substdio sstext;
+
+unsigned int mywrite(fd,buf,len)
 int fd;
 char *buf;
 unsigned int len;
 int fd;
 char *buf;
 unsigned int len;
@@ -65,23 +134,33 @@ unsigned int len;
   return len;
 }
 
   return len;
 }
 
+int subto(s,l)
+char *s;
+unsigned int l;
+{
+  qmail_put(&qq,"T",1);
+  qmail_put(&qq,s,l);
+  qmail_put(&qq,"",1);
+  return (int) l;
+}
+
 void die_archive()
 {
 void die_archive()
 {
-  strerr_die4sys(111,FATAL,"unable to write to ",fnaf.s,": ");
+  strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": ");
 }
 void die_numnew()
 {
 }
 void die_numnew()
 {
-  strerr_die2sys(111,FATAL,"unable to create numnew: ");
+  strerr_die3sys(111,FATAL,ERR_CREATE,"numnew: ");
 }
 
 }
 
-void put(buf,len) char *buf; int len;
+void qa_put(buf,len) char *buf; unsigned int len;
 {
   qmail_put(&qq,buf,len);
   if (flagarchived)
     if (substdio_put(&ssarchive,buf,len) == -1) die_archive();
 }
 
 {
   qmail_put(&qq,buf,len);
   if (flagarchived)
     if (substdio_put(&ssarchive,buf,len) == -1) die_archive();
 }
 
-void puts(buf) char *buf;
+void qa_puts(buf) char *buf;
 {
   qmail_puts(&qq,buf);
   if (flagarchived)
 {
   qmail_puts(&qq,buf);
   if (flagarchived)
@@ -91,8 +170,8 @@ void puts(buf) char *buf;
 int sublistmatch(sender)
 char *sender;
 {
 int sublistmatch(sender)
 char *sender;
 {
-  int i;
-  int j;
+  unsigned int i;
+  unsigned int j;
 
   j = str_len(sender);
   if (j < sublist.len) return 0;
 
   j = str_len(sender);
   if (j < sublist.len) return 0;
@@ -109,14 +188,12 @@ char *sender;
 
 substdio ssnumnew;
 char numnewbuf[16];
 
 substdio ssnumnew;
 char numnewbuf[16];
-unsigned long msgnum;
-stralloc num = {0};
 
 char buf0[256];
 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
 
 void numwrite()
 
 char buf0[256];
 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
 
 void numwrite()
-{
+{              /* this one deals with msgnum, not outnum! */
   int fd;
 
   fd = open_trunc("numnew");
   int fd;
 
   fd = open_trunc("numnew");
@@ -124,70 +201,277 @@ void numwrite()
   substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf));
   if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1)
     die_numnew();
   substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf));
   if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1)
     die_numnew();
+  if (substdio_puts(&ssnumnew,":") == -1) die_numnew();
+  if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,cumsize)) == -1)
+    die_numnew();
+
   if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew();
   if (substdio_flush(&ssnumnew) == -1) die_numnew();
   if (fsync(fd) == -1) die_numnew();
   if (close(fd) == -1) die_numnew(); /* NFS stupidity */
   if (rename("numnew","num") == -1)
   if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew();
   if (substdio_flush(&ssnumnew) == -1) die_numnew();
   if (fsync(fd) == -1) die_numnew();
   if (close(fd) == -1) die_numnew(); /* NFS stupidity */
   if (rename("numnew","num") == -1)
-    strerr_die2sys(111,FATAL,"unable to move numnew to num: ");
+    strerr_die3sys(111,FATAL,ERR_MOVE,"numnew: ");
 }
 
 stralloc mydtline = {0};
 
 }
 
 stralloc mydtline = {0};
 
+int idx_copy_insertsubject()
+/* copies old index file up to but not including msg, then adds a line with */
+/* 'sub' trimmed of reply indicators, then closes the new index and moves it*/
+/* to the name 'index'. Errors are dealt with directly, and if the routine  */
+/* returns, it was successful. 'fatal' points to a program-specific error   */
+/* string. Sub is not destroyed, but from is!!!                             */
+/* returns 1 if reply-indicators were found, 0 otherwise.                   */
+/* no terminal \n or \0 in any of the strallocs! */
+{
+  char *cp;
+  unsigned long idx;
+  int match;
+  int r;
+  unsigned int pos;
+
+  if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
+  if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,outnum / 100)))
+       die_nomem();
+  if (!stralloc_copy(&fnif,&fnadir)) die_nomem();
+  if (!stralloc_copy(&fnifn,&fnif)) die_nomem();
+  if (!stralloc_cats(&fnif,"/index")) die_nomem();
+  if (!stralloc_cats(&fnifn,"/indexn")) die_nomem();
+  if (!stralloc_0(&fnif)) die_nomem();
+  if (!stralloc_0(&fnifn)) die_nomem();
+  if (!stralloc_0(&fnadir)) die_nomem();
+
+                       /* may not exists since we run before ezmlm-send */
+  if (mkdir(fnadir.s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die4x(111,FATAL,ERR_CREATE,fnadir.s,": ");
+
+                       /* Open indexn */
+  fdindexn = open_trunc(fnifn.s);
+  if (fdindexn == -1)
+    strerr_die4x(111,FATAL,ERR_WRITE,fnifn.s,": ");
+
+                       /* set up buffers for indexn */
+  substdio_fdbuf(&ssindexn,write,fdindexn,indexnbuf,sizeof(indexnbuf));
+
+  concatHDR(subject.s,subject.len,&lines,FATAL);       /* make 1 line */
+  decodeHDR(lines.s,lines.len,&qline,charset.s,FATAL); /* decode mime */
+  r = unfoldHDR(qline.s,qline.len,&lines,charset.s,&dcprefix,1,FATAL);
+                                                /* trim mime */
+
+  fdindex = open_read(fnif.s);
+  if (fdindex == -1) {
+    if (errno != error_noent)
+      strerr_die4x(111,FATAL,ERR_OPEN, fnif.s, ": ");
+  } else {
+    substdio_fdbuf(&ssin,read,fdindex,inbuf,sizeof(inbuf));
+    for(;;) {
+      if (getln(&ssin,&qline,&match,'\n') == -1)
+        strerr_die4sys(111,FATAL,ERR_READ, fnif.s, ": ");
+      if (!match)
+        break;
+      pos = scan_ulong(qline.s,&idx);
+      if (!idx)                                /* "impossible!" */
+        strerr_die2x(111,FATAL,ERR_BAD_INDEX);
+      if (idx >= outnum)
+        break;                         /* messages always come in order */
+      if (substdio_put(&ssindexn,qline.s,qline.len) == -1)
+        die_indexn();
+      if (qline.s[pos] == ':') {       /* has author line */
+        if (getln(&ssin,&qline,&match,'\n') == -1)
+          strerr_die4x(111,FATAL,ERR_READ, fnif.s, ": ");
+        if (!match && qline.s[0] != '\t')      /* "impossible! */
+          strerr_die2x(111,FATAL,ERR_BAD_INDEX);
+        if (substdio_put(&ssindexn,qline.s,qline.len) == -1)
+          die_indexn();
+      }
+    }
+    close(fdindex);
+  }
+  if (!stralloc_copyb(&qline,strnum,fmt_ulong(strnum,outnum))) die_nomem();
+  if (!stralloc_cats(&qline,": ")) die_nomem();        /* ':' for new ver */
+  makehash(lines.s,lines.len,hash);
+  if (!stralloc_catb(&qline,hash,HASHLEN)) die_nomem();
+  if (!stralloc_cats(&qline," ")) die_nomem();
+  if (r & 1)           /* reply */
+    if (!stralloc_cats(&qline,"Re: ")) die_nomem();
+  if (!stralloc_cat(&qline,&lines)) die_nomem();
+  if (!stralloc_cats(&qline,"\n\t")) die_nomem();
+  if (!stralloc_cat(&qline,&received)) die_nomem();
+  if (!stralloc_cats(&qline,";")) die_nomem();
+
+  concatHDR(from.s,from.len,&lines,FATAL);
+  mkauthhash(lines.s,lines.len,hash);
+
+  if (!stralloc_catb(&qline,hash,HASHLEN)) die_nomem();
+  if (!stralloc_cats(&qline," ")) die_nomem();
+
+  decodeHDR(cp,author_name(&cp,lines.s,lines.len),&from,charset.s,FATAL);
+  (void) unfoldHDR(from.s,from.len,&lines,charset.s,&dcprefix,0,FATAL);
+  if (!stralloc_cat(&qline,&lines)) die_nomem();
+
+  if (!stralloc_cats(&qline,"\n")) die_nomem();
+  if (substdio_put(&ssindexn,qline.s,qline.len) == -1) die_indexn();
+  if (substdio_flush(&ssindexn) == -1) die_indexn();
+  if (fsync(fdindexn) == -1) die_indexn();
+  if (fchmod(fdindexn,MODE_ARCHIVE | 0700) == -1) die_indexn();
+  if (close(fdindexn) == -1) die_indexn(); /* NFS stupidity */
+  if (rename(fnifn.s,fnif.s) == -1)
+    strerr_die4x(111,FATAL,ERR_MOVE,fnifn.s,": ");
+  return r;
+}
+
+void transferenc()
+{
+       if (flagcd) {
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"Quoted-printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n\n");
+}
+
+void getcharset()
+{
+    if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+      if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+        if (charset.s[charset.len - 1] == 'B' ||
+                       charset.s[charset.len - 1] == 'Q') {
+          flagcd = charset.s[charset.len - 1];
+          charset.s[charset.len - 2] = '\0';
+        }
+      }
+    } else
+      if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+
+    if (!stralloc_0(&charset)) die_nomem();
+}
+
 void main(argc,argv)
 int argc;
 char **argv;
 {
 void main(argc,argv)
 int argc;
 char **argv;
 {
-  int fd;
-  char *dir;
+  unsigned long subs;
   int fdlock;
   char *sender;
   int fdlock;
   char *sender;
+  char *mlheader = (char *) 0;
+  char *ret;
+  char *err;
   int flagmlwasthere;
   int flagmlwasthere;
+  int flagqmqp = 0;    /* don't use qmqp by default */
+  int flaglistid = 0;  /* no listid header added */
   int match;
   int match;
-  int i;
-  char ch;
+  unsigned int i;
+  int r,fd;
   int flaginheader;
   int flagbadfield;
   int flaginheader;
   int flagbadfield;
+  int flagbadpart;
+  int flagseenext;
+  int flagsubline;
+  int flagfromline;
+  int flagcontline;
+  int flagarchiveonly;
+  int flagtrailer;
+  unsigned int pos;
+  int opt;
+  char *cp, *cpstart, *cpafter;
 
   umask(022);
   sig_pipeignore();
 
 
   umask(022);
   sig_pipeignore();
 
-  dir = argv[1];
+  while ((opt = getopt(argc,argv,"cCh:H:lLrRqQs:S:vV")) != opteof)
+    switch(opt) {
+      case 'c': case 'C': break;       /* ignore for backwards compat */
+      case 'h':
+      case 'H': mlheader = optarg;     /* Alternative sublist check header */
+                mlheader[str_chr(mlheader,':')] = '\0';
+                break;
+      case 'l': flaglog = 1; break;
+      case 'L': flaglog = 0; break;
+      case 'r': flagnoreceived = 0; break;
+      case 'R': flagnoreceived = 1; break;
+      case 's':
+      case 'S':        pos = scan_ulong(optarg,&hash_lo);
+               if (!optarg[pos++]) break;
+               (void) scan_ulong(optarg+pos,&hash_hi);
+               if (hash_hi > 52L) hash_hi = 52L;
+               if (hash_lo > hash_hi) hash_lo = hash_hi;
+
+ break;
+      case 'q': flagqmqp = 0; break;
+      case 'Q': flagqmqp = 1; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-send version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+
+  dir = argv[optind++];
   if (!dir) die_usage();
 
   sender = env_get("SENDER");
 
   if (chdir(dir) == -1)
   if (!dir) die_usage();
 
   sender = env_get("SENDER");
 
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
 
   fdlock = open_append("lock");
   if (fdlock == -1)
 
   fdlock = open_append("lock");
   if (fdlock == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",dir,"/lock: ");
+    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/lock: ");
   if (lock_ex(fdlock) == -1)
   if (lock_ex(fdlock) == -1)
-    strerr_die4sys(111,FATAL,"unable to obtain ",dir,"/lock: ");
-
-  if (qmail_open(&qq) == -1)
-    strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/lock: ");
 
   flagarchived = getconf_line(&line,"archived",0,FATAL,dir);
 
   flagarchived = getconf_line(&line,"archived",0,FATAL,dir);
+  flagindexed = getconf_line(&line,"indexed",0,FATAL,dir);
+  getcharset();
+  flagprefixed = getconf_line(&prefix,"prefix",0,FATAL,dir);
+  if (prefix.len) {            /* encoding and serial # support */
+                               /* no sanity checks - you put '\n' or '\0' */
+                               /* into the coded string, you pay */
+
+    decodeHDR(prefix.s,prefix.len,&line,charset.s,FATAL);
+    (void) unfoldHDR(line.s,line.len,&dcprefix,charset.s,&dummy,0,FATAL);
+    if (!stralloc_copy(&dcprefix,&line)) die_nomem();
+    serial = byte_rchr(prefix.s,prefix.len,'#');
+  }
+  if ((fd = open_read("text/trailer")) == -1) {        /* see if there is a trailer */
+    if (errno == error_noent) flagtrailer = 0;
+    else strerr_die2sys(111,ERR_OPEN,"text/trailer: ");
+  } else {
+    close(fd);
+    flagtrailer = 1;
+  }
 
 
-  getconf_line(&num,"num",1,FATAL,dir);
-  if (!stralloc_0(&num)) die_nomem();
-  scan_ulong(num.s,&msgnum);
-  ++msgnum;
+  getconf(&mimeremove,"mimeremove",0,FATAL,dir);
+
+  if (getconf_line(&line,"num",0,FATAL,dir)) { /* Now non-FATAL, def=0 */
+    if (!stralloc_0(&line)) die_nomem();
+    cp = line.s + scan_ulong(line.s,&msgnum);
+    ++msgnum;
+    if (*cp++ == ':')
+      scan_ulong(cp,&cumsize);
+  } else
+    msgnum = 1L;                       /* if num not there */
 
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
 
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
-  getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+  set_cpoutlocal(&outlocal);
+  set_cpouthost(&outhost);
   flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir);
 
   flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir);
 
-  getconf(&headerremove,"headerremove",1,FATAL,dir);
-  constmap_init(&headerremovemap,headerremove.s,headerremove.len,0);
+  if (flagqmqp) {                      /* forward compatibility ;-) */
+    if (!stralloc_copys(&line,QMQPSERVERS)) die_nomem();
+    if (!stralloc_cats(&line,"/0")) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+    (void) getconf_line(&qmqpservers,line.s,0,FATAL,dir);
+  }
 
 
-  getconf(&headeradd,"headeradd",1,FATAL,dir);
-  for (i = 0;i < headeradd.len;++i)
-    if (!headeradd.s[i])
-      headeradd.s[i] = '\n';
+  getconf(&headerremove,"headerremove",1,FATAL,dir);
+  if (!constmap_init(&headerremovemap,headerremove.s,headerremove.len,0))
+       die_nomem();
 
   if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem();
   if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
 
   if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem();
   if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
@@ -197,123 +481,326 @@ char **argv;
 
   if (sender) {
     if (!*sender)
 
   if (sender) {
     if (!*sender)
-      strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)");
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
     if (str_equal(sender,"#@[]"))
     if (str_equal(sender,"#@[]"))
-      strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)");
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
     if (flagsublist)
       if (!sublistmatch(sender))
     if (flagsublist)
       if (!sublistmatch(sender))
-        strerr_die2x(100,FATAL,"this message is not from my parent list (#5.7.2)");
+        strerr_die2x(100,FATAL,ERR_NOT_PARENT);
   }
   }
+  innum = msgnum;                              /* innum = incoming */
+  outnum = msgnum;                             /* outnum = outgoing */
+  if (flagsublist && !flagarchived) {          /* msgnum = archive */
+    pos = byte_rchr(sublist.s,sublist.len,'@');        /* checked in sublistmatch */
+    if (str_start(sender+pos,"-return-"))
+      pos += 8;
+      pos += scan_ulong(sender+pos,&innum);
+      if (!flagarchived && innum && sender[pos] == '-')
+        outnum = innum;
+  }
+  szmsgnum[fmt_ulong(szmsgnum,outnum)] = '\0';
+  set_cpnum(szmsgnum);                         /* for copy */
 
   if (flagarchived) {
     if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
 
   if (flagarchived) {
     if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
-    if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100))) die_nomem();
+    if (!stralloc_catb(&fnadir,strnum,
+               fmt_ulong(strnum,outnum / 100))) die_nomem();
     if (!stralloc_copy(&fnaf,&fnadir)) die_nomem();
     if (!stralloc_cats(&fnaf,"/")) die_nomem();
     if (!stralloc_copy(&fnaf,&fnadir)) die_nomem();
     if (!stralloc_cats(&fnaf,"/")) die_nomem();
-    if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem();
+    if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,
+               (unsigned int) (outnum % 100),2))) die_nomem();
     if (!stralloc_0(&fnadir)) die_nomem();
     if (!stralloc_0(&fnaf)) die_nomem();
 
     if (mkdir(fnadir.s,0755) == -1)
       if (errno != error_exist)
     if (!stralloc_0(&fnadir)) die_nomem();
     if (!stralloc_0(&fnaf)) die_nomem();
 
     if (mkdir(fnadir.s,0755) == -1)
       if (errno != error_exist)
-       strerr_die4sys(111,FATAL,"unable to create ",fnadir.s,": ");
+       strerr_die4sys(111,FATAL,ERR_CREATE,fnadir.s,": ");
     fdarchive = open_trunc(fnaf.s);
     if (fdarchive == -1)
     fdarchive = open_trunc(fnaf.s);
     if (fdarchive == -1)
-      strerr_die4sys(111,FATAL,"unable to write ",fnaf.s,": ");
+      strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": ");
 
     substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf));
 
     substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf));
+                                               /* return-path to archive */
+    if (!stralloc_copys(&line,"Return-Path: <")) die_nomem();
+    if (sender) {                              /* same as qmail-local */
+      if (!quote2(&qline,sender)) die_nomem();
+      for (i = 0;i < qline.len;++i) if (qline.s[i] == '\n') qline.s[i] = '_';
+      if (!stralloc_cat(&line,&qline)) die_nomem();
+    }
+    if (!stralloc_cats(&line,">\n")) die_nomem();
+    if (substdio_put(&ssarchive,line.s,line.len) == -1) die_archive();
   }
 
   }
 
+  if (flagqmqp) {
+    if (qmail_open(&qq,&qmqpservers) == -1)            /* open qmqp */
+      strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+  } else if (qmail_open(&qq,(stralloc *) 0) == -1)     /* open queue */
+      strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+
   if (!flagsublist) {
   if (!flagsublist) {
-    puts("Mailing-List: ");
-    put(mailinglist.s,mailinglist.len);
-    puts("\n");
+    getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+    qa_puts("Mailing-List: ");
+    qa_put(mailinglist.s,mailinglist.len);
+    if (getconf_line(&line,"listid",0,FATAL,dir)) {
+      flaglistid = 1;
+      qmail_puts(&qq,"\nList-ID: ");
+      qmail_put(&qq,line.s,line.len);
+    }
+    qa_puts("\n");
   }
   }
-  put(headeradd.s,headeradd.len);
-  put(mydtline.s,mydtline.len);
+  copy(&qq,"headeradd",'H',FATAL);
+  qa_put(mydtline.s,mydtline.len);
 
   flagmlwasthere = 0;
   flaginheader = 1;
 
   flagmlwasthere = 0;
   flaginheader = 1;
+  flagfoundokpart = 1;
   flagbadfield = 0;
   flagbadfield = 0;
-
+  flagbadpart = 0;
+  flagseenext = 0;
+  flagsubline = 0;
+  flagfromline = 0;
+  flagreceived = 0;
   for (;;) {
     if (getln(&ss0,&line,&match,'\n') == -1)
   for (;;) {
     if (getln(&ss0,&line,&match,'\n') == -1)
-      strerr_die2sys(111,FATAL,"unable to read input: ");
-
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
     if (flaginheader && match) {
     if (flaginheader && match) {
-      if (line.len == 1)
+      if (line.len == 1) {             /* end of header */
        flaginheader = 0;
        flaginheader = 0;
-      if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
-       flagbadfield = 0;
+        if (flagindexed)               /* std entry */
+          r = idx_copy_insertsubject();        /* all indexed lists */
+        if (flagprefixed && !flagsublist) {
+          qa_puts("Subject:");
+          if (!flagindexed) {          /* non-indexed prefixed lists */
+            concatHDR(subject.s,subject.len,&lines,FATAL);
+            decodeHDR(lines.s,lines.len,&qline,charset.s,FATAL);
+            r = unfoldHDR(qline.s,qline.len,&lines,
+                       charset.s,&dcprefix,1,FATAL);
+          }
+          if (!(r & 2)) {
+            qmail_puts(&qq," ");
+            if (serial == prefix.len)
+              qmail_put(&qq,prefix.s,prefix.len);
+            else {
+              qmail_put(&qq,prefix.s,serial);
+              qmail_puts(&qq,szmsgnum);
+              qmail_put(&qq,prefix.s+serial+1,prefix.len-serial-1);
+            }
+          }
+          qa_put(subject.s,subject.len);
+        }
+               /* do other stuff to do with post header processing here */
+       if (content.len) {              /* get MIME boundary, if exists */
+          concatHDR(content.s,content.len,&qline,FATAL);
+          if (!stralloc_copy(&content,&qline)) die_nomem();
+
+         if (flagtrailer &&            /* trailer only for some multipart */
+               case_startb(content.s,content.len,"multipart/"))
+           if (!case_startb(content.s+10,content.len-10,"mixed") &&
+               !case_startb(content.s+10,content.len-10,"digest") &&
+               !case_startb(content.s+10,content.len-10,"parallel"))
+             flagtrailer = 0;
+
+           cp = content.s;
+           cpafter = cp + content.len; /* check after each ';' */
+           while ((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) {
+             ++cp;
+             while (cp < cpafter &&
+                       (*cp == ' ' || *cp == '\t' || *cp == '\n')) ++cp;
+             if (case_startb(cp,cpafter-cp,"boundary=")) {
+               cp += 9;                        /* after boundary= */
+               if (*cp == '"') {       /* quoted boundary */
+                 ++cp;
+                 cpstart = cp;
+                 while (cp < cpafter && *cp != '"') ++cp;
+                if (cp == cpafter)
+                       strerr_die1x(100,ERR_MIME_QUOTE);
+               } else {                        /* non-quoted boundary */
+                 cpstart = cp;         /* find terminator of boundary */
+                 while (cp < cpafter && *cp != ';' &&
+                       *cp != ' ' && *cp != '\t' && *cp != '\n') ++cp;
+               }
+               if (!stralloc_copys(&boundary,"--")) die_nomem();
+               if (!stralloc_catb(&boundary,cpstart,cp-cpstart))
+                       die_nomem();
+                flagfoundokpart = 0;
+               if (!constmap_init(&mimeremovemap,mimeremove.s,mimeremove.len,0))
+                       die_nomem();
+               flagbadpart = 1;                /* skip before first boundary */
+               qa_puts("\n");          /* to make up for the lost '\n' */
+            }
+          }
+        }
+      } else if ((*line.s != ' ') && (*line.s != '\t')) {
+        flagsubline = 0;
+        flagfromline = 0;
+        flagbadfield = 0;
+        flagarchiveonly = 0;
+        flagcontline = 0;
        if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
          flagbadfield = 1;
        if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
          flagbadfield = 1;
-       if (case_startb(line.s,line.len,"mailing-list:"))
-         flagmlwasthere = 1;
-       if (line.len == mydtline.len)
+        if ((flagnoreceived || !flagreceived) &&
+               case_startb(line.s,line.len,"Received:")) {
+            if (!flagreceived) {               /* get date from first rec'd */
+              flagreceived = 1;                        /* line (done by qmail) */
+              pos = byte_chr(line.s,line.len,';');
+              if (pos != line.len)             /* has '\n' */
+                if (!stralloc_copyb(&received,line.s+pos+2,line.len - pos - 3))
+                  die_nomem();
+            } else {                           /* suppress, but archive */
+              flagarchiveonly = 1;             /* but do not suppress the */
+              flagbadfield = 1;                        /* top one added by qmail */
+            }
+       } else if (case_startb(line.s,line.len,"Mailing-List:"))
+         flagmlwasthere = 1;           /* sublists always ok ezmlm masters */
+       else if (mlheader && case_startb(line.s,line.len,mlheader))
+         flagmlwasthere = 1;           /* mlheader treated as ML */
+        else if ((mimeremove.len || flagtrailer) &&    /* else no MIME need*/
+               case_startb(line.s,line.len,"Content-Type:")) {
+          if (!stralloc_copyb(&content,line.s+13,line.len-13)) die_nomem();
+          flagcontline = 1;
+       } else if (case_startb(line.s,line.len,"Subject:")) {
+          if (!stralloc_copyb(&subject,line.s+8,line.len-8)) die_nomem();
+         flagsubline = 1;
+          if (flagprefixed && !flagsublist)    /* don't prefix for sublists */
+           flagbadfield = 1;                   /* we'll print our own */
+        } else if (flagtrailer &&
+                case_startb(line.s,line.len,"Content-Transfer-Encoding:")) {
+          cp = line.s + 26;
+          cpafter = cp + line.len;
+          while (cp < cpafter && (*cp == ' ' || *cp == '\t')) ++cp;
+          if (case_startb(cp,cpafter-cp,"base64")) encin = 'B';
+          else if (case_startb(cp,cpafter-cp,"Quoted-Printable")) encin = 'Q';
+        } else if (flaglistid && case_startb(line.s,line.len,"list-id:"))
+         flagbadfield = 1;             /* suppress if we added our own */
+       else if (flagindexed) {
+
+          if (case_startb(line.s,line.len,"From:")) {
+            flagfromline = 1;
+            if (!stralloc_copyb(&from,line.s+5,line.len-5)) die_nomem();
+          }
+        } else if (line.len == mydtline.len)
          if (!byte_diff(line.s,line.len,mydtline.s))
          if (!byte_diff(line.s,line.len,mydtline.s))
-            strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)");
+            strerr_die2x(100,FATAL,ERR_LOOPING);
+      } else {                 /* continuation lines */
+        if (flagsubline) {
+         if (!stralloc_cat(&subject,&line)) die_nomem();
+        } else if (flagfromline) {
+         if (!stralloc_cat(&from,&line)) die_nomem();
+        } else if (flagcontline) {
+          if (!stralloc_cat(&content,&line)) die_nomem();
+        }
       }
       }
-    }
-
-    if (!(flaginheader && flagbadfield))
-      put(line.s,line.len);
+    } else                             /* body */
+      msgsize += line.len;             /* always for tstdig support */
+
+    if (!(flaginheader && flagbadfield)) {
+      if (boundary.len && line.len > boundary.len &&
+               !str_diffn(line.s,boundary.s,boundary.len)) {
+        if (line.s[boundary.len] == '-' && line.s[boundary.len+1] == '-') {
+          flagbadpart = 0;             /* end boundary should be output */
+          if (flagtrailer) {
+            qmail_puts(&qq,"\n");
+            qmail_put(&qq,boundary.s,boundary.len);
+            qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+            qmail_puts(&qq,charset.s);
+            transferenc();             /* trailer for multipart message */
+           copy(&qq,"text/trailer",flagcd,FATAL);
+            if (flagcd == 'B') {       /* need to do our own flushing */
+              encodeB("",0,&qline,2,FATAL);
+              qmail_put(&qq,qline.s,qline.len);
+            }
+         }
+        } else {                       /* new part */
+            flagbadpart = 1;           /* skip lines */
+            if (!stralloc_copy(&lines,&line)) die_nomem();     /* but save */
+            flagseenext = 1;           /* need to check Cont-type */
+        }
+      } else if (flagseenext) {                /* last was boundary, now stored */
+        if (case_startb(line.s,line.len,"content-type:")) {
+          flagseenext = 0;             /* done thinking about it */
+          cp = line.s + 13;                    /* start of type */
+          while (*cp == ' ' || *cp == '\t') ++cp;
+          cpstart = cp;                        /* end of type */
+          while (*cp != '\n' && *cp != '\t' && *cp != ' ' && *cp != ';') ++cp;
+         if (constmap(&mimeremovemap,cpstart,cp-cpstart)) {
+            flagbadpart = 1;
+          } else {
+           flagfoundokpart = 1;
+            qa_put(lines.s,lines.len); /* saved lines */
+            flagbadpart = 0;           /* do this part */
+          }
+        } else if (line.len == 1) {    /* end of content desc */
+          flagbadpart = 0;             /* default type, so ok */
+          flagseenext = 0;             /* done thinking about it */
+        } else                         /* save line in cont desc */
+          if (!stralloc_cat(&lines,&line)) die_nomem();
+      }
+      if (!flagbadpart)
+        qa_put(line.s,line.len);
 
 
+    } else if (flagarchiveonly && flagarchived)        /* received headers */
+      if (substdio_put(&ssarchive,line.s,line.len) == -1) die_archive();
     if (!match)
       break;
   }
     if (!match)
       break;
   }
+  if (!boundary.len && flagtrailer) {
+    qmail_puts(&qq,"\n");              /* trailer for non-multipart message */
+    if (!encin || encin == 'Q') {      /* can add for QP, but not for base64 */
+      copy(&qq,"text/trailer",encin,FATAL);
+      qmail_puts(&qq,"\n");            /* no need to flush for plain/QP */
+    }
+  }
 
 
-  if (flagsublist)
-    if (!flagmlwasthere)
-      strerr_die2x(100,FATAL,"sublist messages must have Mailing-List (#5.7.2)");
-  if (!flagsublist)
+  cumsize += (msgsize + 128L) >> 8;    /* round to 256 byte 'records' */
+                                       /* check message tag */
+  if (flagsublist) {                   /* sublists need tag if selected/suppt*/
+    if (flaglog)
+      if ((ret = checktag(dir,innum,hash_lo+1L,"m",(char *) 0,hashout))) {
+        if (*ret) strerr_die2x(111,FATAL,ret);
+        else strerr_die2x(100,FATAL,ERR_NOT_PARENT);
+      }
+    if (!flagmlwasthere)               /* sublists need ML header */
+      strerr_die2x(100,FATAL,ERR_SUBLIST);
+  } else                               /* others are not allowed to have one */
     if (flagmlwasthere)
     if (flagmlwasthere)
-      strerr_die2x(100,FATAL,"message already has Mailing-List (#5.7.2)");
+      strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+  if (!flagfoundokpart)                        /* all parts were on the strip list */
+      strerr_die2x(100,FATAL,ERR_BAD_ALL);
 
   if (flagarchived) {
     if (substdio_flush(&ssarchive) == -1) die_archive();
     if (fsync(fdarchive) == -1) die_archive();
 
   if (flagarchived) {
     if (substdio_flush(&ssarchive) == -1) die_archive();
     if (fsync(fdarchive) == -1) die_archive();
-    if (fchmod(fdarchive,0744) == -1) die_archive();
+    if (fchmod(fdarchive,MODE_ARCHIVE | 0700) == -1) die_archive();
     if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */
   }
 
     if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */
   }
 
-  numwrite();
+  if (flaglog) {
+    tagmsg(dir,innum,sender,"m",hashout,qq.msgbytes,53L,FATAL);
+    hashout[COOKIE] = '\0';
+  }
 
 
+  numwrite();
   if (!stralloc_copy(&line,&outlocal)) die_nomem();
   if (!stralloc_cats(&line,"-return-")) die_nomem();
   if (!stralloc_copy(&line,&outlocal)) die_nomem();
   if (!stralloc_cats(&line,"-return-")) die_nomem();
-  if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem();
+  if (!stralloc_cats(&line,szmsgnum)) die_nomem();
   if (!stralloc_cats(&line,"-@")) die_nomem();
   if (!stralloc_cat(&line,&outhost)) die_nomem();
   if (!stralloc_cats(&line,"-@[]")) die_nomem();
   if (!stralloc_0(&line)) die_nomem();
   if (!stralloc_cats(&line,"-@")) die_nomem();
   if (!stralloc_cat(&line,&outhost)) die_nomem();
   if (!stralloc_cats(&line,"-@[]")) die_nomem();
   if (!stralloc_0(&line)) die_nomem();
-
-  qmail_from(&qq,line.s);
-
-  for (i = 0;i < 53;++i) {
-    ch = 64 + i;
-    if (!stralloc_copys(&fnsub,"subscribers/")) die_nomem();
-    if (!stralloc_catb(&fnsub,&ch,1)) strerr_die2x(111,FATAL,"out of memory");
-    if (!stralloc_0(&fnsub)) strerr_die2x(111,FATAL,"out of memory");
-    fd = open_read(fnsub.s);
-    if (fd == -1) {
-      if (errno != error_noent)
-       strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": ");
-    }
-    else {
-      substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
-      substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf));
-      if (substdio_copy(&ssout,&ssin) != 0)
-       strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": ");
-      close(fd);
-    }
-  }
-
-  switch(qmail_close(&qq)) {
-    case 0:
+  qmail_from(&qq,line.s);                      /* envelope sender */
+  subs = putsubs(dir,hash_lo,hash_hi,subto,1,FATAL);   /* subscribers */
+  if (flagsublist) hash_lo++;
+
+  if (*(err = qmail_close(&qq)) == '\0') {
+      if (flaglog)                             /* mysql logging */
+       (void) logmsg(dir,outnum,hash_lo,subs,flagsublist ? 3 : 4);
+      closesql();
       strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
       strerr_die2x(0,"ezmlm-send: info: qp ",strnum);
       strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
       strerr_die2x(0,"ezmlm-send: info: qp ",strnum);
-    default:
+  } else {
       --msgnum;
       --msgnum;
+      cumsize -= (msgsize + 128L) >> 8;
       numwrite();
       numwrite();
-      strerr_die2x(111,FATAL,"temporary qmail-queue error");
+      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
   }
 }
   }
 }
diff --git a/ezmlm-split.1 b/ezmlm-split.1
new file mode 100644 (file)
index 0000000..9c4e3e4
--- /dev/null
@@ -0,0 +1,171 @@
+.de Vb
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH ezmlm-split 1
+.SH NAME
+ezmlm-split \- distribute (un)subscribe requests to sublists
+.SH SYNOPSIS
+.B ezmlm-split
+.I dir
+[
+.B \-dD
+][
+.I splitfile
+]
+.SH DESCRIPTION
+If the action is
+.I \-subscribe
+or
+.IR \-unsubscribe ,
+.B ezmlm-split
+analyzes the target of the request,
+ computing a hash in the range 0-52 from
+the address, and determines the ``domain key'', i.e. 
+the two top levels of the host address in reverse order.
+Thus, the domain entry for ``d@a.b.c'' becomes ``c.b''
+and the one for ``d@a'' becomes ``a''.
+
+The hash and domain parts are then tested against successive lines of
+.I splitfile
+(default is
+.IR dir\fB/split ).
+If a match is found, the request is forwarded to the corresponding
+sublist, and
+.B ezmlm-split
+exits 99. If a match is not found or action is not
+.I \-subscribe
+or
+.IR \-unsubscribe ,
+.B ezmlm-split
+exits 0.
+
+In
+.IR splitfile ,
+blank lines and lines with ``#'' in position 1 are ignored. Other lines are
+expected to be of the format ``dom:low:hi:list@host'', where ``dom'' is
+the top level domain, ``low''-``hi'' the range of the hash (defaults 0 and 52),
+and ``list@host'' the name of the corresponding list (default is the
+local list). A line is considered to match if the address hash is
+between ``low'' and ``hi'' inclusive and ``dom'' is empty,
+or if the ``domain key'' matches ``dom'' for the full length of ``dom''. Thus,
+the address ``user@aol.com'' would match ``com'' and ``aol.com'',
+but not ``host.com''.
+
+If the domain
+specified is the top level domain up to 3 characters, the split is identical
+as that used by the SQL subscriber interface. This is recommended.
+There can be several entries for a given sublist.
+
+.B ezmlm-split
+can be used also for list with SQL-based sublisting. In this case,
+addresses matching the
+.I splitfile
+are forwarded to the respective non-SQL sublist, and non-matching addresses
+are handed by the SQL sublist.
+
+.SH OPTIONS
+.TP
+.B \-d
+(Default.)
+Do. Forward requests to the appropriate list.
+.TP
+.B \-D
+Do not process messages. Rather, read addresses, one per line from stdin, and
+print ``sublist@host: address'' where ``sublist@host'' is the address to which
+the request would have been forwarded in normal operation. This is used to
+process a set of existing addresses into a set of address collections, one
+per sublist. The output can be sorted and easily processed into a set of files,
+one per sublist containing the addresses that sublist handles.
+.SH "SPLIT LIST SETUP"
+To use a hierarchy of sublists, set up the master list and add a
+.B ezmlm-split
+line before the
+.B ezmlm-manage(1)
+line in
+.IR dir\fB/manager .
+Create any number of sublists of the main list on other local or
+distant hosts. Ideally, these should be non-archived, to point to the correct
+message numbers of the main list archive (see
+.BR ezmlm-send(1) .
+You can use
+.B ezmlm-make -C\fIezmlmsubrc
+for this. If you don't, use the text files from the main list, except
+.IR bounce-bottom .
+Next, create
+.I split
+in the main list directory to achieve an appropriate split. Load splitting
+between several local hosts is best achieved by hash, with a blank domain.
+Geographical splitting with hosts in different countries is best done
+via ``domain'' and naturally, a large domain can be subdivided by hash.
+
+Subscribers will receive all messages 'From:' the main list. When they
+subscribe or unsubscribe, the request will be forwarded to the appropriate
+sublist, which will handle the confirmation. All information, except
+.I bounce-bottom
+refers the user to the main list. Thus, to the user the list appears as
+a single list with the address of the main list, and distribution among
+sublists is at the discretion of the administrator of the main list.
+
+.SH "ADDING/REMOVING SUBLISTS"
+In general, the main list should be disabled, while changing the sublist
+split. This can be done by changing the mode of
+.I dir\fB/lock
+to 0 or by setting the sticky bit for the home directory of the user
+controlling the list.
+
+To remove a sublist, edit the lines for that sublist in the splitfile to
+point to another list, and add the existing subscribers of the removed
+sublist to the sublist taking the load.
+When splitting a sublist into several sublists, create the new sublists,
+and edit the split file to distribute the load
+between them (usually by hash). Process the subscribers of the old list
+with:
+
+.Vb 1
+ | ezmlm-split -D dir | sort | program
+.Ve
+where to get one file of addresses per new sublist, ``program'' could be:
+
+.Vb 12
+\&#!/usr/bin/perl
+\&while (<>) {
+\&  ($f,$t) = split (':');
+\&  $t =~ s/^\ //;
+\&  if ($f ne $of) {
+\&    $of = $f;
+\&    close(OUT) if ($of);
+\&    open(OUT,">$f") or die("Unable to open $f");
+\&  }
+\&  print OUT $t;
+\&}
+\&close(OUT) if ($of);
+.Ve
+
+Remove all subscribers from the old list,
+and add the respective subscribers to each list.
+
+For any more drastic reorganizations, collect all the subscribes of the
+affected sublists, create the new subscriber lists, and update the
+subscribers of the affected lists.
+
+Reorganizations are easier done when lists use SQL support. By
+temporarily using SQL support, reorganizations can be done on running
+lists even when normally using
+.B ezmlm-split
+and local subscriber databases.
+.SH "SEE ALSO"
+ezmlm-list(1),
+ezmlm-make(1),
+ezmlm-manage(1),
+ezmlm-sub(1)
+ezmlm-unsub(1),
+ezmlm(5),
+ezmlmrc(5),
+ezmlmsubrc(5)
diff --git a/ezmlm-split.c b/ezmlm-split.c
new file mode 100644 (file)
index 0000000..f115358
--- /dev/null
@@ -0,0 +1,316 @@
+/*$Id: ezmlm-split.c,v 1.6 1999/05/12 22:17:54 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "sig.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "case.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "quote.h"
+#include "now.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-split: fatal: "
+#define INFO "ezmlm-split: info: "
+
+int flagdo = 1;                /* default is manager function */
+
+char *sender;
+char *split;
+stralloc outhost = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc target = {0};
+stralloc lctarget = {0};
+stralloc line = {0};
+stralloc domain = {0};
+stralloc name = {0};
+stralloc from = {0};
+stralloc to = {0};
+char strnum[FMT_ULONG];
+unsigned long lineno;
+int flagfound;
+
+void die_usage() {
+  strerr_die1x(100,"ezmlm-split: usage: ezmlm-split [-dD] dir [splitfile]"); }
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badaddr()
+{
+  strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+void die_syntax()
+{
+  strnum[fmt_ulong(strnum,lineno)] = '\0';
+  strerr_die6x(111,FATAL,split," syntax error line ",strnum,": ",line.s);
+}
+
+char spbuf[1024];      /* should normally hold entire file */
+substdio sssp;
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return (int) len;
+}
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
+
+char outbuf[1];
+substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,(int) sizeof(outbuf));
+
+char inbuf[1024];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
+
+int findname()
+/* returns 1 if a matching line was found, 0 otherwise. name will contain */
+/* the correct list address in either case */
+{
+  char *cpat,*cp,*cpname,*cp1,*cp2,*cplast;
+  unsigned long u;
+  uint32 h;
+  unsigned char hash,hash_hi,hash_lo;
+  unsigned int pos,pos_name,pos_hi;
+  char ch;
+  int fd,match;
+
+  /* make case insensitive hash */
+  flagfound = 0;                       /* default */
+  cpname = "";                         /* default */
+  if (!stralloc_copy(&lctarget,&target)) die_nomem();
+  case_lowerb(lctarget.s,lctarget.len -1);
+  h = 5381;
+  cp = lctarget.s;
+  while ((ch = *cp++)) {
+    h = (h + (h << 5)) ^ (uint32) ch;
+  }
+  hash = (h % 53);
+
+  /* make domain pointer */
+  cpat = lctarget.s + str_chr(lctarget.s,'@');
+  if (!*cpat)
+    strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s);
+  cplast = cpat + str_len(cpat) - 1;
+  if (*cplast == '.') --cplast;                /* annonying special case */
+  cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
+  if (cp1 != cplast) {                 /* got one '.' */
+    if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
+    cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
+    if (cp2 == cp1) cp2 = cpat;
+    ++cp2;
+    if (!stralloc_append(&domain,".")) die_nomem();
+    if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
+  } else                               /* no '.' */
+    if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
+  if (!stralloc_0(&domain)) die_nomem();
+
+  if ((fd = open_read(split)) == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,split,": ");
+  substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf));
+  lineno = 0;
+  for (;;) {   /* dom:hash_lo:hash_hi:listaddress */
+    if (getln(&sssp,&line,&match,'\n') == -1)
+      strerr_die4sys(111,FATAL,ERR_READ,split,": ");
+     lineno++;
+    if (!match)
+      break;
+    if (line.s[0] == '#') continue;    /* comment */
+    line.s[line.len - 1] = '\0';       /* no need to allow \0 in lines */
+    if (!line.s[pos = str_chr(line.s,':')])
+      continue;                                /* usually blank line */
+    line.s[pos] = '\0';
+    if (pos == 0 ||                    /* no domain */
+         (case_starts(domain.s,line.s))) {     /* or matching domain */
+       if (!line.s[++pos]) die_syntax();
+       pos_hi = pos + str_chr(line.s + pos,':');
+       if (!line.s[pos_hi]) die_syntax();
+       pos_hi++;
+       (void) scan_ulong(line.s + pos, &u);    /* scan_uint() not in ezmlm */
+       hash_lo = (unsigned char) u;
+       (void) scan_ulong(line.s + pos_hi, &u);
+       hash_hi = (unsigned char) u;
+       pos_name = pos_hi + str_chr(line.s + pos_hi,':');
+       if (pos_hi == pos_name) hash_hi = 52L;  /* default hi = 52 */
+       if (line.s[pos_name]) pos_name++;
+       if (hash > hash_hi || hash < hash_lo) continue; /* not us */
+       cpname = line.s + pos_name;
+       while (*cpname &&                               /* isolate name */
+           (*cpname == ' ' || *cpname == '\t')) cpname++;
+       pos = line.len - 2;
+       while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' ||
+               line.s[pos] == '\t')) line.s[pos--] = '\0';
+       break;
+    }
+  }
+  close(fd);
+
+  if (*cpname) {
+    if (!stralloc_copys(&name,cpname)) die_nomem();
+    if (byte_chr(name.s,name.len,'@') == name.len) {   /* local sublist */
+      if (!stralloc_append(&name,"@")) die_nomem();
+      if (!stralloc_cat(&name,&outhost)) die_nomem();
+    }
+    if (!stralloc_0(&name)) die_nomem();
+    return 1;
+  } else {                     /* match without name or no match =>this list */
+    if (!stralloc_copy(&name,&outlocal)) die_nomem();
+    if (!stralloc_append(&name,"@")) die_nomem();
+    if (!stralloc_cat(&name,&outhost)) die_nomem();
+    if (!stralloc_0(&name)) die_nomem();
+    return 0;
+  }
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  char *local;
+  char *action;
+  char *def;
+  char *dtline;
+  char *nhost;
+  char *err;
+  unsigned int i;
+  int match;
+  int optind = 1;
+
+  sig_pipeignore();
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+  if (dir[0] == '-') {
+    if (dir[1] == 'd') flagdo = 1;
+    else if (dir[1] == 'D') flagdo = 0;
+    else die_usage();
+    if (!(dir = argv[optind++])) die_usage();
+  }
+  if (!(split = argv[optind]))
+    split = "split";
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+
+  if (flagdo) {
+    sender = env_get("SENDER");
+    if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
+    if (!*sender)
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
+    if (!sender[str_chr(sender,'@')])
+      strerr_die2x(100,FATAL,ERR_ANONYMOUS);
+    if (str_equal(sender,"#@[]"))
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
+
+    def = env_get("DEFAULT");
+    if (def) {
+      action = def;
+    } else {
+      local = env_get("LOCAL");
+      if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+      getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+      if (inlocal.len > str_len(local)) die_badaddr();
+      if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+      action = local + inlocal.len + 1;
+    }
+    if (!stralloc_copys(&target,sender)) die_nomem();
+    if (action[0]) {
+      i = str_chr(action,'-');
+      if (action[i]) {
+        action[i] = '\0';
+        if (!stralloc_copys(&target,action + i + 1)) die_nomem();
+        i = byte_rchr(target.s,target.len,'=');
+        if (i < target.len)
+         target.s[i] = '@';
+      }
+    }
+    if (!stralloc_0(&target)) die_nomem();
+
+    if (case_diffs(action,ACTION_SUBSCRIBE) &&
+      case_diffs(action,ALT_SUBSCRIBE) &&
+      case_diffs(action,ACTION_UNSUBSCRIBE) &&
+      case_diffs(action,ALT_UNSUBSCRIBE))
+    _exit(0);                  /* not for us */
+
+    if (findname()) {
+                               /* new sender */
+      if (!stralloc_copy(&from,&outlocal)) die_nomem();
+      if (!stralloc_cats(&from,"-return-@")) die_nomem();
+      if (!stralloc_cat(&from,&outhost)) die_nomem();
+      if (!stralloc_0(&from)) die_nomem();
+      if (name.s[i = str_rchr(name.s,'@')]) {          /* name must have '@'*/
+       nhost = name.s + i;
+       *(nhost++) = '\0';
+      }
+      if (!stralloc_copys(&to,name.s)) die_nomem();    /* local */
+      if (!stralloc_append(&to,"-")) die_nomem();      /* - */
+      if (!stralloc_cats(&to,action)) die_nomem();     /* subscribe */
+      if (!stralloc_append(&to,"-")) die_nomem();      /* - */
+      if (target.s[i = str_rchr(target.s,'@')])
+       target.s[i] = '=';
+      if (!stralloc_cats(&to,target.s)) die_nomem();   /* target */
+      if (!stralloc_append(&to,"@")) die_nomem();      /* - */
+      if (!stralloc_cats(&to,nhost)) die_nomem();      /* host */
+      if (!stralloc_0(&to)) die_nomem();
+      dtline = env_get("DTLINE");
+      if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE);
+
+      if (qmail_open(&qq,(stralloc *) 0) == -1)
+        strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+      qmail_puts(&qq,dtline);                          /* delivered-to */
+      if (substdio_copy(&ssqq,&ssin) != 0)
+        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      qmail_from(&qq,from.s);
+      qmail_to(&qq,to.s);
+
+      if (*(err = qmail_close(&qq)) != '\0')
+        strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
+
+      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+      strerr_die3x(99,INFO,"qp ",strnum);
+    }
+    _exit(0);
+  } else {
+
+    for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+         strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      if (line.len == 1) continue;     /* ignore blank lines */
+      if (line.s[0] == '#') continue;  /* ignore comments */
+      if (!stralloc_copy(&target,&line)) die_nomem();
+      target.s[target.len - 1] = '\0';
+      (void) findname();
+      if (!stralloc_cats(&name,": ")) die_nomem();
+      if (!stralloc_cats(&name,target.s)) die_nomem();
+      if (!stralloc_append(&name,"\n")) die_nomem();
+      if (substdio_put(&ssout,name.s,name.len) == -1)
+       strerr_die2sys(111,ERR_WRITE,"output: ");
+    }
+    if (substdio_flush(&ssout) == -1)
+      strerr_die2sys(111,ERR_FLUSH,"output: ");
+    _exit(0);
+  }
+}
+
+
diff --git a/ezmlm-store.1 b/ezmlm-store.1
new file mode 100644 (file)
index 0000000..1350577
--- /dev/null
@@ -0,0 +1,210 @@
+.TH ezmlm-store 1
+.SH NAME
+ezmlm-store \- store messages posted to a moderated lists and send
+moderation requests to the moderator(s).
+.SH SYNOPSIS
+.B ezmlm-store [-bBcCmMpPrRsSvV]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-store
+reads a mail message and
+stores it in
+.I dir\fB/mod/pending/.
+.B ezmlm-store
+also sends a moderation request with a copy of the message to the list of
+moderators stored in
+.I dir\fB/mod/subscribers/.
+If
+.I dir\fB/modpost
+contains a directory name,
+.IR moddir ,
+with a leading forward slash, the moderator list in
+.I /moddir/subscribers/
+is used instead. This allows separate sets of moderators for
+subscription and message moderation, as
+well as the use of the same moderator list for several
+.B ezmlm
+mailing lists, owned by the same user. If the
+.B \-s
+switch is used, the moderators are divided into two sets. Those pointed to by
+.I dir\fB/modpost
+which will receive confirmation requests for posts with their SENDER address,
+and those stored with the base directory
+.I dir\fB/mod/
+which will receive moderation requests for messages posted from SENDERs not
+part of the first group. This can be used to have a set of trusted
+users (``moderating'' themselves to thwart SENDER faking), and a set of more
+traditional moderators, which receive approval requests for other posts.
+
+.B Note:
+The contents of
+.I dir\fB/modpost
+do not affect the location of the message moderation queue.
+
+If SENDER is a moderator, the request is sent
+to that moderator only.
+
+The moderation request includes cookies for message rejection and acceptance.
+The moderator can take either action by replying to the appropriate address.
+For moderator convenience, the
+.I accept
+address is given in
+the ``Reply-To:'' header, and the
+.I reject
+address in the ``From:'' header.
+
+If the list is set up with remote administration and the sender is not a
+moderator, the ``Cc:'' header will contain a confirmation address to add
+the sender to the ``allow'' database. This allows the moderator to both
+approve the post and add the sender to the list of accepted posters by
+replying to ``all''.
+
+The (default) subject of all message moderation requests is
+.B MODERATE for\fI listname@host.
+
+Once the request has been successfully sent to the moderators, 
+.B ezmlm-store
+sets the owner-execute bit of the message in
+.I dir\fB/mod/pending/.
+Messages without this bit set are the result of incomplete executions of
+.B ezmlm-store
+and are ignored.
+
+At the beginning of the message,
+.B ezmlm-store
+prints a new
+.B Mailing-List
+field with the contents of
+.IR dir\fB/mailinglist .
+It rejects the message if there is already a
+.B Mailing-List
+field.
+
+.B ezmlm-store
+does not distribute bounce messages:
+if the environment variable
+.B SENDER
+is set, and is either empty or
+.BR #@[] ,
+.B ezmlm-store
+rejects the message.
+.SH OPTIONS
+.TP
+.B \-b
+(Default.)
+With the moderation request,
+send both headers and body of the message to be moderated.
+.TP
+.B \-B
+With the moderation request,
+send header, but not body of the message to be moderated.
+This may be useful if moderation is used to allow one or a few poorly
+connected addresses to post, and posts are very large (e.g. when the list
+is used as a distribution channel of e.g. catalogs).
+.TP
+.B \-cCrR
+Passed on to
+.B ezmlm-send(1)
+in case this program is executed. This happens only if
+.I dir\fB/modpost
+does not exist.
+.TP
+.B \-m
+(Default.)
+The post is sent as a MIME enclosure.
+.TP
+.B \-M
+The post is appended to the message.
+.TP
+.B \-s
+The contents of
+.I dir\fB/modpost
+with the default
+.I dir\fB/mod/
+are used as the base directory for self-approving users, whereas
+.I dir\fB/mod/
+is used as the base directory
+for the moderators to whom approval requests for other
+posts are sent.
+.TP
+.B \-S
+(Default.)
+The contents of
+.I dir\fB/modpost
+with the default
+.I dir\fB/mod/
+are used as the base directory
+for the moderators for all moderator functions.
+.TP
+.B \-p
+(Default.)
+Anyone can post. Posts that are not from a moderator are sent out to
+all moderators for approval. Posts that are from a moderator are
+sent only to that moderator.
+.TP
+.B \-P
+Only moderators can post. Those posts are sent to the posting moderator
+for approval. Posts from other addresses are bounced. This can be used
+to relatively securely restrict posts to messages originating from
+a given set of addresses.
+.TP
+.B \-v
+Display
+.B ezmlm-manage
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-manage
+version information.
+.SH USAGE
+First of all, remember that
+.B ezmlm-store
+will simply execute
+.B ezmlm-send(1)
+unless
+.I dir\fB/modpost
+exists.
+For the switches, use
+.B \-P
+for lists where only moderators can post securely, i.e. they are
+asked to approve their own posts after posting,
+whereas other SENDERs are rejected. For
+low-security more convenient versions of this type of restriction, see
+.BR ezmlm-gate(1) .
+
+Normally (no switches),
+posts from moderators are sent for approval only to the sending
+moderator, whereas posts from other addresses are sent to all moderators.
+Thus, you can set up an announcement list by adding all potential posters
+as moderators. However, you may also want to allow others to post, as
+long as the posts are approved. This would be default
+.B ezmlm-store
+function.
+
+To make the set of ``approved posters'' who approve their own posts, different
+from the set of addresses that approve posts from other users, use the
+.B \-s
+switch. Add a directory name to
+.IR dir\fB/modpost .
+This directory is the base directory of the ``approved posters''
+database. Add the moderators for other posts to
+.I dir\fB/mod/
+using
+.BR ezmlm-sub(1) .
+.SH "CHARACTER SETS"
+If
+.I dir\fB/charset
+exists,
+.B ezmlm-store
+will use the character set listed for all messages. Otherwise, the
+default ``us-ascii'' will be used. The character set can be suffixed
+by ``:'' followed by a code. If the code is ``Q'', outgoing messages are 
+sent as ``Quoted-Printable'', if it is '`B'' they are sent ``base64'' encoded.
+Otherwise, text is sent as is.
+.SH "SEE ALSO"
+ezmlm-clean(1),
+ezmlm-manage(1),
+ezmlm-make(1),
+ezmlm-moderate(1),
+ezmlm(5)
diff --git a/ezmlm-store.c b/ezmlm-store.c
new file mode 100644 (file)
index 0000000..d293cfa
--- /dev/null
@@ -0,0 +1,506 @@
+/*$Id: ezmlm-store.c,v 1.52 1999/10/09 16:49:56 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "stralloc.h"
+#include "subfd.h"
+#include "strerr.h"
+#include "error.h"
+#include "qmail.h"
+#include "env.h"
+#include "lock.h"
+#include "sig.h"
+#include "open.h"
+#include "getln.h"
+#include "str.h"
+#include "fmt.h"
+#include "readwrite.h"
+#include "auto_bin.h"
+#include "fork.h"
+#include "wait.h"
+#include "exit.h"
+#include "substdio.h"
+#include "getconf.h"
+#include "datetime.h"
+#include "now.h"
+#include "date822fmt.h"
+#include "cookie.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
+#include "copy.h"
+#include "subscribe.h"
+#include "mime.h"
+
+int flagmime = MOD_MIME;       /* default is message as attachment */
+int flagpublic = 1;            /* default anyone can post */
+                               /* =0 for only moderators can */
+int flagself = 0;              /* `modpost` mods approve own posts */
+                               /* but mod/ is used for moderators */
+                               /* of other posts. Def=no=0 */
+char flagcd = '\0';            /* default: don't use quoted-printable */
+int flagbody = 1;              /* body of message enclosed with mod request */
+                               /* 0 => headers only */
+
+#define FATAL "ezmlm-store: fatal: "
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-store: usage: ezmlm-store [-cCmMpPrRsSvV] dir");
+}
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+stralloc fnmsg = {0};
+
+void die_msg() { strerr_die4sys(111,FATAL,ERR_WRITE,fnmsg.s,": "); }
+
+int fdmsg;
+int fdmod;
+int pid;
+int match;
+
+char strnum[FMT_ULONG];
+char date[DATE822FMT];
+char hash[COOKIE];
+char boundary[COOKIE];
+datetime_sec when;
+struct datetime dt;
+struct stat st;
+
+void *psql = (void *) 0;
+
+stralloc fnbase = {0};
+stralloc line = {0};
+stralloc mailinglist = {0};
+stralloc outlocal = {0};
+stralloc outhost = {0};
+stralloc mydtline = {0};
+stralloc returnpath = {0};
+stralloc accept = {0};
+stralloc action = {0};
+stralloc reject = {0};
+stralloc quoted = {0};
+stralloc key = {0};
+stralloc subject = {0};
+stralloc moderators = {0};
+stralloc charset = {0};
+stralloc sendopt = {0};
+
+struct qmail qq;
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+  qmail_put(&qq,buf,len);
+  return len;
+}
+
+int subto(s,l)
+char *s;
+unsigned int l;
+{
+  qmail_put(&qq,"T",1);
+  qmail_put(&qq,s,l);
+  qmail_put(&qq,"",1);
+  return (int) l;
+}
+
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+
+substdio ssin;
+char inbuf[1024];
+
+substdio ssmsg;
+char msgbuf[1024];
+
+substdio sstext;
+char textbuf[512];
+
+substdio sssub;
+char subbuf[512];
+
+void transferenc()
+{
+       if (flagcd) {
+         qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+          if (flagcd == 'Q')
+            qmail_puts(&qq,"Quoted-Printable\n\n");
+          else
+           qmail_puts(&qq,"base64\n\n");
+        } else
+          qmail_puts(&qq,"\n\n");
+}
+
+void makehash(act)
+stralloc *act;                                 /* has to be 0-terminated  */
+/* act is expected to be -reject-ddddd.ttttt or -accept-ddddd.ttttt        */
+/* The routine will add .hash@outhost to act. act will NOT be 0-terminated */
+{
+  int d;
+
+  d = 2 + str_chr(act->s + 1,'-');
+  cookie(hash,key.s,key.len,act->s + d,"","a");
+  *(act->s + act->len - 1) = '.';      /* we put a '.' Bad, but works */
+  if (!stralloc_catb(act,hash,COOKIE)) die_nomem();
+  if (!stralloc_cats(act,"@")) die_nomem();
+  if (!stralloc_cat(act,&outhost)) die_nomem();
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  int fdlock;
+  char *sender;
+  int match;
+  int flaginheader;
+  int flagmodpost;
+  int flagremote;
+  char *pmod;
+  char *err;
+  int opt;
+  unsigned int i;
+  char szchar[2] = "-";
+  char *sendargs[4];
+  int child,wstat;
+
+  (void) umask(022);
+  sig_pipeignore();
+
+  if (!stralloc_copys(&sendopt," -")) die_nomem();
+  while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvV")) != opteof)
+    switch(opt) {
+      case 'b': flagbody = 1; break;
+      case 'B': flagbody = 0; break;
+      case 'm': flagmime = 1; break;
+      case 'M': flagmime = 0; break;
+      case 'p': flagpublic = 1; break; /* anyone can post (still moderated)*/
+      case 'P': flagpublic = 0; break; /* only moderators can post */
+      case 's': flagself = 1; break;   /* modpost and DIR/mod diff fxns */
+      case 'S': flagself = 0; break;   /* same fxn */
+      case 'c':                                /* ezmlm-send flags */
+      case 'C':
+      case 'r':
+      case 'R':
+        szchar[0] = (char) opt & 0xff;
+        if (!stralloc_append(&sendopt,szchar)) die_nomem();
+        break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-store version: ",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  sender = env_get("SENDER");
+
+  if (sender) {
+    if (!*sender || str_equal(sender,"#@[]"))
+      strerr_die2x(100,FATAL,ERR_BOUNCE);
+  }
+
+  dir = argv[optind];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  flagmodpost = getconf_line(&moderators,"modpost",0,FATAL,dir);
+  flagremote = getconf_line(&line,"remote",0,FATAL,dir);
+  if (!flagmodpost) {                  /* not msg-mod. Pipe to ezmlm-send */
+    sendargs[0] = "/bin/sh";
+    sendargs[1] = "-c";
+    if (!stralloc_copys(&line,auto_bin)) die_nomem();
+    if (!stralloc_cats(&line,"/ezmlm-send")) die_nomem();
+    if (sendopt.len > 2)
+      if (!stralloc_cat(&line,&sendopt)) die_nomem();
+    if (!stralloc_cats(&line," '")) die_nomem();
+    if (!stralloc_cats(&line,dir)) die_nomem();
+    if (!stralloc_cats(&line,"'")) die_nomem();
+    if (!stralloc_0(&line)) die_nomem();
+    sendargs[2] = line.s;
+    sendargs[3] = 0;
+    switch(child = fork()) {
+      case -1:
+        strerr_die2sys(111,FATAL,ERR_FORK);
+      case 0:
+        execvp(*sendargs,sendargs);
+        if (errno == error_txtbsy || errno == error_nomem ||
+            errno == error_io)
+          strerr_die5sys(111,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+        else
+          strerr_die5sys(100,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+    }
+         /* parent */
+    wait_pid(&wstat,child);
+    if (wait_crashed(wstat))
+      strerr_die2x(111,FATAL,ERR_CHILD_CRASHED);
+    switch(wait_exitcode(wstat)) {
+      case 100:
+        strerr_die2x(100,FATAL,"Fatal error from child");
+      case 111:
+         strerr_die2x(111,FATAL,"Temporary error from child");
+      case 0:
+        _exit(0);
+      default:
+        strerr_die2x(111,FATAL,"Unknown temporary error from child");
+    }
+  }
+
+  if (!moderators.len || !(moderators.s[0] == '/')) {
+    if (!stralloc_copys(&moderators,dir)) die_nomem();
+    if (!stralloc_cats(&moderators,"/mod")) die_nomem();
+  }
+  if (!stralloc_0(&moderators)) die_nomem();
+
+  if (sender) {
+      pmod = issub(moderators.s,sender,(char *) 0,FATAL);
+      closesql();
+                               /* sender = moderator? */
+  } else
+    pmod = 0;
+
+  if (!pmod && !flagpublic)
+    strerr_die2x(100,FATAL,ERR_NO_POST);
+
+  switch(slurp("key",&key,32)) {
+    case -1:
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
+    case 0:
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
+  }
+
+  getconf_line(&outhost,"outhost",1,FATAL,dir);
+  getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+
+  fdlock = open_append("mod/lock");
+  if (fdlock == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/mod/lock: ");
+  if (lock_ex(fdlock) == -1)
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/mod/lock: ");
+
+  if (!stralloc_copys(&mydtline,"Delivered-To: moderator for ")) die_nomem();
+  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
+  if (!stralloc_append(&mydtline,"@")) die_nomem();
+  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
+  if (!stralloc_cats(&mydtline,"\n")) die_nomem();
+
+  if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem();
+  if (sender) {
+    if (!stralloc_cats(&returnpath,sender)) die_nomem();
+    for (i = 14; i < returnpath.len;++i)
+      if (returnpath.s[i] == '\n' || !returnpath.s[i] )
+        returnpath.s[i] = '_';
+               /* NUL and '\n' are bad, but we don't quote since this is */
+               /* only for ezmlm-moderate, NOT for SMTP */
+  }
+  if (!stralloc_cats(&returnpath,">\n")) die_nomem();
+
+ pid = getpid();               /* unique file name */
+ for (i = 0;;++i)              /* got lock - nobody else can add files */
+  {
+   when = now();               /* when is also used later for date! */
+   if (!stralloc_copys(&fnmsg,"mod/pending/")) die_nomem();
+   if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem();
+   if (!stralloc_append(&fnbase,".")) die_nomem();
+   if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem();
+   if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem();
+   if (!stralloc_0(&fnmsg)) die_nomem();
+   if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break;
+   /* really should never get to this point */
+   if (i == 2)
+     strerr_die2x(111,FATAL,ERR_UNIQUE);
+   sleep(2);
+  }
+
+  if (!stralloc_copys(&action,"-")) die_nomem();
+  if (!stralloc_cats(&action,ACTION_REJECT)) die_nomem();
+  if (!stralloc_cat(&action,&fnbase)) die_nomem();
+  if (!stralloc_0(&action)) die_nomem();
+  makehash(&action);
+  if (!quote(&quoted,&outlocal)) die_nomem();
+  if (!stralloc_copy(&reject,&quoted)) die_nomem();
+  if (!stralloc_cat(&reject,&action)) die_nomem();
+  if (!stralloc_0(&reject)) die_nomem();
+
+  if (!stralloc_copys(&action,"-")) die_nomem();
+  if (!stralloc_cats(&action,ACTION_ACCEPT)) die_nomem();
+  if (!stralloc_cat(&action,&fnbase)) die_nomem();
+  if (!stralloc_0(&action)) die_nomem();
+  makehash(&action);
+  if (!stralloc_copy(&accept,&quoted)) die_nomem();
+  if (!stralloc_cat(&accept,&action)) die_nomem();
+  if (!stralloc_0(&accept)) die_nomem();
+
+  set_cpoutlocal(&outlocal);
+  set_cpouthost(&outhost);
+  set_cptarget(accept.s);      /* for copy () */
+  set_cpconfirm(reject.s);
+
+  fdmsg = open_trunc(fnmsg.s);
+  if (fdmsg == -1)
+    strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": ");
+  substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf));
+
+  if (qmail_open(&qq, (stralloc *) 0) == -1)           /* Open mailer */
+    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
+
+  qmail_puts(&qq,"Mailing-List: ");
+  qmail_put(&qq,mailinglist.s,mailinglist.len);
+  if (getconf_line(&line,"listid",0,FATAL,dir)) {
+    qmail_puts(&qq,"List-ID: ");
+    qmail_put(&qq,line.s,line.len);
+  }
+  qmail_puts(&qq,"\nDate: ");
+  datetime_tai(&dt,when);
+  qmail_put(&qq,date,date822fmt(date,&dt));
+  qmail_puts(&qq,"Message-ID: <");
+  if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+     die_nomem();
+  if (!stralloc_append(&line,".")) die_nomem();
+  if (!stralloc_catb(&line,strnum,
+               fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+  if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+  if (!stralloc_cat(&line,&outhost)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  qmail_puts(&qq,line.s);
+               /* "unique" MIME boundary as hash of messageid */
+  cookie(boundary,"",0,"",line.s,"");
+  qmail_puts(&qq,">\nFrom: ");
+  qmail_puts(&qq,reject.s);
+  qmail_puts(&qq,"\nReply-To: ");
+  qmail_puts(&qq,accept.s);
+  if (!pmod && flagremote) {   /* if remote admin add -allow- address */
+    qmail_puts(&qq,"\nCc: ");  /* for ezmlm-gate users */
+    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
+    cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t");
+    if (!stralloc_copy(&line,&outlocal)) die_nomem();
+    if (!stralloc_cats(&line,"-allow-tc.")) die_nomem();
+    if (!stralloc_cats(&line,strnum)) die_nomem();
+    if (!stralloc_append(&line,".")) die_nomem();
+    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
+    if (!stralloc_append(&line,"-")) die_nomem();
+    i = str_rchr(sender,'@');
+    if (!stralloc_catb(&line,sender,i)) die_nomem();
+    if (sender[i]) {
+      if (!stralloc_append(&line,"=")) die_nomem();
+      if (!stralloc_cats(&line,sender + i + 1)) die_nomem();
+    }
+    qmail_put(&qq,line.s,line.len);
+    qmail_puts(&qq,"@");
+    qmail_put(&qq,outhost.s,outhost.len);
+  }
+  qmail_puts(&qq,"\nTo: Recipient list not shown: ;");
+  if (!stralloc_copys(&subject,"\nSubject: ")) die_nomem();
+  if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem();
+  if (!quote(&quoted,&outlocal)) die_nomem();
+  if (!stralloc_cat(&subject,&quoted)) die_nomem();
+  if (!stralloc_append(&subject,"@")) die_nomem();
+  if (!stralloc_cat(&subject,&outhost)) die_nomem();
+  if (flagmime) {
+    if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+      if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+        if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+          flagcd = charset.s[charset.len - 1];
+          charset.s[charset.len - 2] = '\0';
+        }
+      }
+    } else
+      if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+    if (!stralloc_0(&charset)) die_nomem();
+    qmail_puts(&qq,"\nMIME-Version: 1.0\n");
+    qmail_puts(&qq,"Content-Type: multipart/mixed;\n\tboundary=");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_put(&qq,subject.s,subject.len);
+    qmail_puts(&qq,"\n\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+    qmail_puts(&qq,charset.s);
+    transferenc();
+  } else {
+    qmail_put(&qq,subject.s,subject.len);
+    qmail_puts(&qq,"\n\n");
+  }
+  copy(&qq,"text/mod-request",flagcd,FATAL);
+  if (flagcd == 'B') {
+    encodeB("",0,&line,2,FATAL);
+    qmail_put(&qq,line.s,line.len);
+  }
+  if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg();
+  if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg();
+  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+
+  if (flagmime) {
+    qmail_puts(&qq,"\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n");
+  }
+
+  qmail_put(&qq,returnpath.s,returnpath.len);
+  qmail_put(&qq,mydtline.s,mydtline.len);
+  flaginheader = 1;
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+    if (!match) break;
+    if (line.len == 1) flaginheader = 0;
+    if (flaginheader) {
+      if ((line.len == mydtline.len) &&
+               !byte_diff(line.s,line.len,mydtline.s)) {
+       close(fdmsg);                   /* be nice - clean up */
+       unlink(fnmsg.s);
+        strerr_die2x(100,FATAL,ERR_LOOPING);
+      }
+      if (case_startb(line.s,line.len,"mailing-list:")) {
+       close(fdmsg);                   /* be nice - clean up */
+       unlink(fnmsg.s);
+        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+      }
+    }
+
+    if (flagbody || flaginheader)      /* skip body if !flagbody */
+      qmail_put(&qq,line.s,line.len);
+    if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg();
+  }
+
+  if (flagmime) {
+    qmail_puts(&qq,"\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"--\n");
+  }
+
+/* close archive before qmail. Loss of qmail will result in re-run, and   */
+/* worst case this results in a duplicate msg sitting orphaned until it's */
+/* cleaned out.                                                           */
+
+  if (substdio_flush(&ssmsg) == -1) die_msg();
+  if (fsync(fdmsg) == -1) die_msg();
+  if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg();
+  if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */
+
+  close(fdlock);
+
+  if (!stralloc_copy(&line,&outlocal)) die_nomem();
+  if (!stralloc_cats(&line,"-return-@")) die_nomem();
+  if (!stralloc_cat(&line,&outhost)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  qmail_from(&qq,line.s);                      /* envelope sender */
+  if (pmod)                                    /* to moderator only */
+    qmail_to(&qq,pmod);
+  else {
+    if (flagself) {                            /* to all moderators */
+      if (!stralloc_copys(&moderators,dir)) die_nomem();
+      if (!stralloc_cats(&moderators,"/mod")) die_nomem();
+      if (!stralloc_0(&moderators)) die_nomem();
+    }
+    putsubs(moderators.s,0,52,subto,1,FATAL);
+  }
+
+  if (*(err = qmail_close(&qq)) == '\0') {
+      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
+      strerr_die2x(0,"ezmlm-store: info: qp ",strnum);
+  } else
+      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1);
+}
index 219b88f..ae4bf68 100644 (file)
@@ -3,9 +3,20 @@
 ezmlm-sub \- manually add addresses to a mailing list
 .SH SYNOPSIS
 .B ezmlm-sub
 ezmlm-sub \- manually add addresses to a mailing list
 .SH SYNOPSIS
 .B ezmlm-sub
+[
+.B \-HmMnNsSvV
+][
+.B \-h
+.I hash
+]
+.B 
 .I dir
 [
 .I dir
 [
-.I box\fB@\fIdomain ...
+.I box\fB@\fIdomain 
+[
+.I name
+]
+.I ...
 ]
 .SH DESCRIPTION
 .B ezmlm-sub
 ]
 .SH DESCRIPTION
 .B ezmlm-sub
@@ -13,12 +24,20 @@ adds each address
 .I box\fB@\fIdomain
 to the mailing list stored in
 .IR dir .
 .I box\fB@\fIdomain
 to the mailing list stored in
 .IR dir .
+.I name
+is added as a comment to the subscription log, if the
+.B \-n
+switch is used.
+
+If no argument is given on the command line,
+.B ezmlm-sub
+processes stdin.
 
 If
 .I box\fB@\fIdomain
 is already on the mailing list,
 .B ezmlm-sub
 
 If
 .I box\fB@\fIdomain
 is already on the mailing list,
 .B ezmlm-sub
-leaves it there.
+leaves it there and does not modify the subscription log.
 
 .B ezmlm-sub
 converts
 
 .B ezmlm-sub
 converts
@@ -28,11 +47,61 @@ to lowercase before adding
 to the mailing list.
 
 .I box\fB@\fIdomain
 to the mailing list.
 
 .I box\fB@\fIdomain
-cannot be longer than 400 characters.
+cannot be longer than 400 characters (255 characters with mysql support).
+.SH "GENERAL OPTIONS"
+.TP
+.B \-n
+Assume arguments are pairs of
+.I box\fB@\fIdomain
+and
+.IR name
+(or other subscriber info)
+rather than addresses alone.
+.B ezmlm-sub(1)
+will add the first argument in each pair to the subscriber list. If it is
+a new address,
+.I name
+will be added to the subscription log.
+.TP
+.B \-N
+(Default.)
+Arguments are all addresses of the type
+.IR box\fB@\fIdomain .
+.TP
+.B \-v
+Display
+.B ezmlm-sub(1)
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-sub(1)
+version information.
+.SH "MYSQL OPTIONS"
+These option is silently ignored in the absence of mysql support.
+.TP
+.B \-h \fIhash
+With mysql support the argument is used as the hash. The argument should
+be between 1 and 99. The hash is used in
+in the distribution of addresses between sublists. As the hash is normally
+between 0 and 52, controlling the hash makes it possible to add addresses
+that cannot be manipulated remotely.
+.TP
+.B \-m
+(Default.)
+Use SQL support if available.
+.TP
+.B \-M
+Do not use SQL support even if available. This option can be used to build
+a normal local subscriber database even for lists with SQL support. Use
+in combination with
+.B ezmlm-list(1)
+to convert an SQL address db to a ezmlm standard address database.
 .SH "SEE ALSO"
 ezmlm-list(1),
 ezmlm-manage(1),
 ezmlm-make(1),
 .SH "SEE ALSO"
 ezmlm-list(1),
 ezmlm-manage(1),
 ezmlm-make(1),
+ezmlm-receipt(1),
 ezmlm-send(1),
 ezmlm-unsub(1),
 ezmlm(5)
 ezmlm-send(1),
 ezmlm-unsub(1),
 ezmlm(5)
index 85fce6a..62e3166 100644 (file)
@@ -1,9 +1,32 @@
+/*$Id: ezmlm-sub.c,v 1.18 1999/08/02 02:57:57 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
 #include "strerr.h"
 #include "subscribe.h"
 #include "strerr.h"
 #include "subscribe.h"
-#include "log.h"
+#include "sgetopt.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "getln.h"
+#include "errtxt.h"
+#include "scan.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-sub: fatal: "
 
 #define FATAL "ezmlm-sub: fatal: "
-#define WARNING "ezmlm-sub: warning: "
+
+void *psql = (void *) 0;
+
+char inbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+
+stralloc line = {0};
+
+void die_usage() {
+  strerr_die1x(100,
+       "ezmlm-sub: usage: ezmlm-sub [-mMvV] [-h hash] [-n] dir "
+               "[box@domain [name]] ...");
+}
+
+int flagname = 0;
 
 void main(argc,argv)
 int argc;
 
 void main(argc,argv)
 int argc;
@@ -11,23 +34,81 @@ char **argv;
 {
   char *dir;
   char *addr;
 {
   char *dir;
   char *addr;
+  char *comment;
+  char *cp;
+  char ch;
+  int opt;
+  int match;
+  int flagmysql = 1;   /* use mysql if supported */
+  int forcehash = -1;
+  unsigned int u;
+
+  (void) umask(022);
+  while ((opt = getopt(argc,argv,"h:HmMnNvV")) != opteof)
+    switch(opt) {
+      case 'h': (void) scan_ulong(optarg,&u); forcehash = 0; break;
+      case 'H': forcehash = -1; break;
+      case 'm': flagmysql = 1; break;
+      case 'M': flagmysql = 0; break;
+      case 'n': flagname = 1; break;
+      case 'N': flagname = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-sub version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+
+  if (dir[0] != '/')
+    strerr_die2x(100,FATAL,ERR_SLASH);
 
 
-  dir = argv[1];
-  if (!dir)
-    strerr_die1x(100,"ezmlm-sub: usage: ezmlm-sub dir box@domain ...");
   if (chdir(dir) == -1)
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
-
-  argv += 2;
-  while (addr = *argv++)
-    switch(subscribe(addr,1)) {
-      case -1:
-       strerr_die1(111,FATAL,&subscribe_err);
-      case -2:
-       strerr_warn4(WARNING,"cannot subscribe ",addr,": ",&subscribe_err);
-       break;
-      case 1:
-       log("+manual",addr);
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  if (forcehash == 0) forcehash = (int) u;
+
+  if (argv[optind]) {
+    if (flagname) {
+               /* allow repeats and last addr doesn't need comment */
+      while ((addr = argv[optind++])) {
+        (void) subscribe(dir,addr,1,argv[optind],"+manual",
+               flagmysql,forcehash,(char *) 0,FATAL);
+        if (!argv[optind++]) break;
+      }
+    } else {
+
+      while ((addr = argv[optind++]))
+        (void) subscribe(dir,addr,1,"","+manual",flagmysql,
+               forcehash,(char *) 0,FATAL);
+    }
+  } else {             /* stdin */
+    for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+       strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      if (line.len == 1 || *line.s == '#') continue;
+      line.s[line.len - 1] = '\0';
+      comment = (char *) 0;
+      if (flagname) {
+       cp = line.s;
+       while ((ch = *cp)) {
+         if (ch == '\\') {
+            if (!*(++cp)) break;
+         } else if (ch == ' ' || ch == '\t' || ch == ',') break;
+         cp++;
+        }
+        if (ch) {
+         *cp = '\0';
+         comment = cp + 1;
+        }
+      }
+      (void) subscribe(dir,line.s,1,comment,"+manual",flagmysql,
+               forcehash,(char *) 0,FATAL);
     }
     }
+  }
+  closesql();
   _exit(0);
 }
   _exit(0);
 }
diff --git a/ezmlm-test.1 b/ezmlm-test.1
new file mode 100644 (file)
index 0000000..65dee58
--- /dev/null
@@ -0,0 +1,153 @@
+.TH ezmlm-test 1
+.SH NAME
+ezmlm-test \- test ezmlm programs
+.SH SYNOPSIS
+.B ezmlm-test
+[
+.B \-on
+][
+.B \-h\fI host
+][
+.B \-u\fI user
+][
+.B \-l\fI sqluser
+][
+.B \-t\fI sqltable
+][
+.B \-d\fI sqldatabase
+][
+.B \-p\fI sqlpassword
+][
+.B \-s\fI section
+]
+.I dir
+.SH DESCRIPTION
+.B ezmlm-test
+is run from the ezmlm build directory. It will test most of the functions
+of most of the programs in ezmlm-idx>=0.313. The program prints status
+and error messages to stdout. It requires that qmail runs on the host and that
+mail delivery to a local user functions. By default, it runs as the
+user ``eztest'' who should have read and execute permission to the files
+in the build directory.
+
+For testing with an SQL database (requires ezmlm-idx>=0.32; see
+.BR -p ),
+you need to have first created the tables in the database, e.g. using
+.BR ezmlm-mktab .
+A number of switches allow overriding the default connection information.
+
+.B ezmlm-test
+creates the list ``eztest-__tstlist@host''
+in the directory ``~/__TSTDIR''. This directory and ``~/.qmail-__tstlist*''
+will be overwritten/removed by the program. In addition,
+the file ``~/__TSTDIR_err'' is created. In cases of error, it often contains
+the error message form the failing program.
+
+.B ezmlm-test
+should complete without error.
+As many invocations of the programs test several functions it is not easy
+to determine what went wrong if
+.B ezmlm-test
+fails. Usually, ``~/__TSTDIR__err'' gives some leads, but then debugging
+of the particular program is required. Usually, this involves recreating
+the failing circumstances, including environment variables.
+.SH OPTIONS
+.TP
+.B \-d\fI sqldatabase
+If SQL support is tested, use
+.I sqldatabase
+as the database, overriding the default ``ezmlm''. See
+.BR \-p .
+.TP
+.B \-h\fI host
+Connect to an SQL server on
+.IR host ,
+if an SQL database is used (see
+.BR \-p ).
+Default is empty, which for most database managers defaults to
+localhost/unix socket. To specify a non-default port,
+add ``:port'' to the host name.
+.TP
+.B \-l\fI sqluser
+Connect as
+.I sqluser
+to the SQL server, if an SQL database is used (see
+.BR \-p ).
+By default, it is the same as the executing user as
+specified by the
+.B \-u
+switch or the default ``eztest''.
+.TP
+.B \-n
+Test assuming qmail>=1.02 and ezmlm-idx>=0.32. Normally, this is auto-detected.
+This switch is for testing of
+.B ezmlm-test
+and unlikely to be generally useful.
+.TP
+.B \-o
+Test assuming an old (<1.02) version of qmail which does not support
+the DEFAULT environment variable. Normally, this is auto-detected, and
+DEFAULT support is used if qmail>=1.02 and ezmlm-idx>=0.32. The ``old''
+style works with all versions of qmail, but requires adjustments for
+virtual domains. DEFAULT support makes these adjustments unnecessary.
+.TP
+.B \-p\fI sqlpassword
+Test with SQL support, and use
+.I sqlpassword
+as the connection password. By default, local databases, rather than an
+SQL database are used for testing. To use the SQL database with an
+empty password, specify
+.BR \-p\ '' .
+.TP
+.B \-s\fI section
+Restart
+.B ezmlm-test
+from section
+.IR section .
+This can be used to resume execution if the 30 s given for mail delivery
+was not sufficient for the test message to be delivered. ``9'' can be
+used to clean up any files remaining after incomplete execution of
+.BR ezmlm-test .
+This option should not be needed.
+.TP
+.B \-t\fI sqltable
+Use
+.I sqltable
+as the table root name for the SQL database tables, if an SQL database
+is used (see
+.BR \-p ).
+Default is ``list''.
+.TP
+.B \-u\fI user
+Execute
+.B ezmlm-test
+as
+.IR user .
+Default is ``eztest''. The program refuses to run, unless the effective
+user name matches this user name.
+.SH BUGS
+On some systems, some of the tests give a broken pipe error. This is because
+code needs to be added to the make_message function to capture error messages.
+These errors can be safely ignored for now. 
+.SH "SEE ALSO"
+ezmlm(5),
+ezmlm-clean(1),
+ezmlm-gate(1),
+ezmlm-get(1),
+ezmlm-idx(1),
+ezmlm-issubn(1),
+ezmlm-list(1),
+ezmlm-make(1),
+ezmlm-manage(1),
+ezmlm-mktab(1),
+ezmlm-moderate(1),
+ezmlm-request(1),
+ezmlm-return(1),
+ezmlm-send(1),
+ezmlm-split(1),
+ezmlm-store(1),
+ezmlm-sub(1),
+ezmlm-tstdig(1),
+ezmlm-unsub(1),
+ezmlm-warn(1)
+
diff --git a/ezmlm-test.sh b/ezmlm-test.sh
new file mode 100644 (file)
index 0000000..a1d03b8
--- /dev/null
@@ -0,0 +1,2366 @@
+# Above should have been added a QMPATH definition
+# DEBUG=1
+# This program is meant to test ezmlm-idx.
+# Several criteria have to be met for this to work:
+# 0. you need to have qmail installed allowing mail delivery to
+#    "eztest@host" and subaddresses.
+# 2. you need to have a user "eztest" or edit the script to change to a
+#      user that exists on your system.
+# 3. you need to be that user when you invoke this script and the script
+#      needs to reside in the same dir as the binaries you want to test.
+# 4. this user needs to have execute permission for the build dir
+#
+# The script will use ~eztest/__TSTDIR and ~eztest/__TSTDIR__err and destroy
+# any files therein. Both user name and directory names etc can be configured
+# below, but this should only very rarely be necessary.
+#
+# This program is experimental and not yet properly documented. Please
+# send comments to lindberg@id.wustl.edu. I'm attempting to make this a
+# rigorous test for future ezmlm+idx installations so that full function
+# can be verified when upgrading to a new version.
+
+# must be absolute
+EZBIN=`pwd`
+
+# the user that should run the scripts (test list is created in this
+# users home directory).
+EZTEST='eztest'
+
+# HOST is normally set from /var/qmail/control/me. Set it here to override
+HOST=''
+
+# Version of ezmlm-idx for which this test script is designed
+OLD_VER='ezmlm-idx-031'                # ezmlm-idx-0.31x
+VER='ezmlm-idx-0.40'
+EZVER='40'                     # default version
+
+#does the current version have qmail<1.02 support?
+OLD_QMAIL='n'
+
+# basedir for test list. It and all files therein are destroyed by
+# the script
+DIR="$HOME/__TSTDIR"
+
+# part that follows user name of local name of the list
+LIST='__tstlist'
+
+# file not within listdir where some error output is stored. If something
+# fails, this file may have more info.
+ERR="${DIR}__err"
+
+# file that can hold crated test msg to avoid sigpipe
+TMP="${DIR}/__tmp"
+
+# defaults for SQL version - overridden by command line switches
+TABLE='list'
+DB='ezmlm'
+SQLHOST=''
+SQLUSR="$EZTEST"       # -u overrides, -l overrides that
+
+# sets umask so that qmail paternalism doesn't complain. With most
+# installations, there is a umask in the user's profile. 022 should be ok,
+# but 002 is safer.
+
+UMASK='umask 002'
+
+#programs:
+# to report disk usage summary
+DU='du -s'
+# Need full path in case qmail doesn't have these in the path
+ECHO=`which echo` 2>/dev/null || ECHO='echo'
+GREP=`which grep` 2>/dev/null || GREP='grep'
+# std programs
+HEAD='head'
+MKDIR='mkdir'
+MV='mv'
+# a ps command that would list qmail if running. This works for RedHat Linux
+PS='ps auxw'
+RM='rm'
+SED='sed'
+STRINGS='strings'
+TAIL='tail'
+UNSET='unset'
+WC='wc'
+# if you don't have this, you can put 'echo "user"' where user is the current
+# login user name.
+WHOAMI='whoami'
+
+###################### END CONFIRGRABLE ITEMS #########################
+SQLUSER=''     # must be empty
+ARR='-------------------->'
+ALLOW='allow'
+DENY='deny'
+DASH='-'
+# switch for ezmlm-return
+DLC='-d'
+DUC='-D'
+# file for ezmlm-request testing
+REQ="${DIR}/__req"
+# Set if we've found bug from old version
+BUG=''
+# Use RDBMS, set if -p was specified even if PW empty, e.g. Postgres
+USESQL=''
+# process arguments
+
+SECT="1"
+while [ ! -z "$1" ]; do                # not everyone has getopt :-(
+       case "$1" in
+               -/)
+                       DASH='-/'; shift;;
+               -d)
+                       DB="$2"; shift; shift;;
+               -h)
+                       SQLHOST="$2"; shift; shift;;
+               -l)
+                       SQLUSER="$2"; shift; shift;;
+               -n)
+                       QMVER=n; shift;;
+               -o)
+                       QMVER=o; shift;;
+               -p)
+                       PW="$2"; USESQL=1; shift; shift;;
+               -u)
+                       EZTEST="$2"; SQLUSR="$2"; shift; shift;;
+               -s)
+                       SECT="$2"; shift; shift;;
+               -t)
+                       TABLE="$2"; shift; shift;;
+               --)
+                       shift; break;;
+               *)
+                       ${ECHO} "$i"
+                       ${ECHO} "Usage: ezmlm-test [-/] [-on] [-u user]" \
+                               "[-p sqlpassword [-l sqluser] [-d sqldb]" \
+                               "[-t sqltable] [-h sqlhost]] [-s section]"
+                       ${ECHO}
+                       ${ECHO} "args have to be separated from switches!"
+                       ${ECHO}
+                       ${ECHO} "defaults: -d ezmlm"
+                       ${ECHO} "          -h [empty => RDBMS default]"
+                       ${ECHO} "          -l eztest or -u arg if specified"
+                       ${ECHO} "          -n/o [autodetected]"
+                       ${ECHO} "          -p [empty - don't use SQL support]"
+                       ${ECHO} "          -s 1 [run test from beginning]"
+                       ${ECHO} "          -t list"
+                       ${ECHO} "          -u eztest"
+                       ${ECHO}
+                       exit 99;;
+       esac
+done
+
+if [ -z "$SQLUSER" ]; then
+       SQLUSER="$SQLUSR"
+fi
+
+USER=`${WHOAMI}` >/dev/null 2>&1 || \
+       { ${ECHO} "whoami doesn't work. If you're not \"${EZTEST}\" the";
+         ${ECHO} "will fail."; USER="${EZTEST}"; }
+
+if [ "$USER" != "${EZTEST}" ]; then 
+  ${ECHO} "Must be user ${EZTEST} to execute"; exit 99
+fi
+LOC="$EZTEST-$LIST"
+# calculate position in LOCAL where [normally] default starts
+LOCLEN=`${ECHO} "$LOC-" | ${WC} -c | ${SED} 's/ //g'`
+REJLEN=`${ECHO} "$LOC-reject-" | ${WC} -c | ${SED} 's/ //g'`
+ACCLEN=`${ECHO} "$LOC-accept-" | ${WC} -c | ${SED} 's/ //g'`
+
+${UMASK} >/dev/null || \
+      {
+       ${ECHO} "Umask failed. Usually, this is OK. Fix this if ezmlm-test"
+       ${ECHO} "fails and messages remain queued with the qmail error"
+       ${ECHO} "'Uh-oh: .qmail file is writable'."
+       ${ECHO}
+      }
+
+DOT="$HOME/.qmail$DASH$LIST"
+
+if [ "$SECT" != "1" ]; then
+       ${ECHO} "Starting with section $SECT ..."
+fi
+# test addresses. These are all within the list dir and all addresses
+# are subaddresses of the list address. You can change this, but it is
+# usually pointless.
+SINK='sink'
+SINKDIR="${DIR}/${SINK}"
+SND="${LOC}-${SINK}"
+
+# moddir
+MODACC='modacc'
+MODDIR="${DIR}/${MODACC}"
+MOD="$LOC-${MODACC}"
+
+# digdir
+DIGGG='dig'
+DIGDIR="${DIR}/${DIGGG}"
+DIG="$LOC-${DIGGG}"
+
+# mandir
+MANAG="man"
+MANDIR="${DIR}/${MANAG}"
+MAN="$LOC-${MANAG}"
+
+# bouncedir
+BOUNCE='bnc'
+BNC="$LOC-bnc"
+
+if [ -z "$HOST" ]; then
+  HOST=`${HEAD} -1 ${QMPATH}/control/me` || \
+       { ${ECHO} "unable to get host name. Set HOST in script" ; exit 99; }
+fi
+
+if [ ! -x "${EZBIN}/ezmlm-make" ]; then
+       ${ECHO} "can't execute ${EZBIN}/ezmlm-make. Most likely, user ``$USER''"
+       ${ECHO} "doesn't have execute permission to files in directory"
+       ${ECHO} "``${EZBIN}''. Adjust permissions or edit the script to"
+       ${ECHO} "use a different test user."
+       exit 99
+fi
+
+if [ ! -x "${QMPATH}/bin/qmail-local" ]; then
+       ${ECHO} "can't find qmail-local. Please correct the path in the script"
+       exit 99
+fi
+if [ ! -x "${QMPATH}/bin/qmail-inject" ]; then
+       ${ECHO} "can't find qmail-inject. Please correct the path in the script"
+       exit 99
+fi
+# Check if qmail is running. Don't fail if not, as it's most likely a
+# ps issue and not a lack of qmail.
+${PS} | ${GREP} qmai\l-send >/dev/null 2>&1 || \
+       {
+        ${ECHO} "qmail isn't running or ps doesn't work as expected. If"
+        ${ECHO} "qmail is not running, this script will fail. Will continue..."
+       }
+
+###############################
+# message generating function #
+###############################
+make_body()
+{
+  ${ECHO} "This is a simple message body"
+  ${ECHO} "--bound123ary"
+  ${ECHO} "Content-type: Text/pLAIn"
+  ${ECHO}
+  ${ECHO} "plain text"
+  ${ECHO} "--bound123ary"
+  ${ECHO} "Content-type: texT/Html"
+  ${ECHO}
+  ${ECHO} "html text"
+  ${ECHO} "--bound123ary--"
+  ${ECHO}
+  ${ECHO} "junk after boundary"
+  return 0
+}
+
+make_message()
+{
+  ${ECHO} "ReCEIved: #LAST#"
+  ${ECHO} "ReCeIved: #PENULTIMATE#"
+  ${ECHO} "retuRN-RECeipt-to: nobody"
+  ${ECHO} "To: $TO"
+  ${ECHO} "CC: "
+  ${ECHO} " $CC"
+  ${ECHO} "FROM: $FROM"
+  if [ ! -z "$CONTENT" ]; then
+       ${ECHO} "MIME-Version: 1.0"
+       ${ECHO} "Content-type: $CONTENT;"
+       ${ECHO} " boundary=bound123ary${AFTERBOUND}"
+  fi
+  if [ ! -z "$SUBJECT" ]; then
+       ${ECHO} "Subject: $SUBJECT"
+  fi
+  ${ECHO}
+  make_body
+  return 0
+}
+
+############################
+# function to test testmsg #
+############################
+send_test()
+{
+  {
+       ${ECHO} "X-num: #TSTMSG$1#"
+       ${ECHO} "To: ${SND}@$HOST"
+  } | ${QMPATH}/bin/qmail-inject
+  return 0
+}
+
+############################
+# sleeping 5 secs function #
+############################
+sleep_5()
+{
+  sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "."
+  sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "."
+  sleep 1; ${ECHO} -n "${1}"
+  return 0
+}
+
+################################
+# waiting for delivery fuction #
+################################
+wait_test()
+{
+${ECHO} -n "max 35s for delivery: "
+sleep_5 5s
+TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+if [ -z "$TSTMSG" ]; then
+  sleep_5 10s
+  TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+  if [ -z "$TSTMSG" ]; then
+    sleep_5 15s
+    TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+    if [ -z "$TSTMSG" ]; then
+      sleep_5 20s
+      TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+      if [ -z "$TSTMSG" ]; then
+        sleep_5 25s
+        TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+        if [ -z "$TSTMSG" ]; then
+          sleep_5 30s
+          TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null`
+          if [ -z "$TSTMSG" ]; then
+               ${ECHO}
+               ${ECHO} "Delivery of test message failed. Fix qmail or wait"
+               ${ECHO} "longer and continue with argument \"-s $1\""
+               exit 100
+          fi
+        fi
+      fi
+    fi
+  fi
+fi
+sleep_5 OK
+${ECHO}
+${RM} -f "$TSTMSG" > "${ERR}" 2>&1 || \
+       { ${ECHO} "failed to remove test message for section $1"; exit 100; }
+TSTMSG=''
+return 0
+}
+
+########################
+# remove old test list #
+########################
+if [ "$SECT" = "1" ]; then
+  if [ $USESQL ]; then
+       ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${MAN}@$HOST" "${DIG}@$HOST" \
+               >"${ERR}" 2>&1
+       ${EZBIN}/ezmlm-unsub "${DIR}/mod" "${MOD}@$HOST" \
+               >"${ERR}" 2>&1
+       ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "aaa@bbb" "ccc@ddd" "eee@fff" \
+               >"${ERR}" 2>&1
+  fi
+  ${RM} -rf "${DIR}" ${DOT}* "${ERR}" >/dev/null 2>&1
+fi
+${ECHO}
+
+#################
+# check version #
+#################
+
+# assume ezmlm-idx and ezmlm-test are different versions
+SAME_VER='n'
+
+TMP_VER=`${EZBIN}/ezmlm-make -V 2>&1` || \
+       {
+               ${ECHO} "This program only works with ezmlm-idx"
+               exit 100
+       }
+# ezmlm-idx-0313 does not support DEFAULT, so no sense testing it
+THIS_VER=`${ECHO} "$TMP_VER" | cut -d'+' -f2`
+${ECHO} "$THIS_VER" | ${GREP} "ezmlm-idx" > /dev/null 2>&1 ||
+  THIS_VER=`${ECHO} "$TMP_VER" | cut -d' ' -f4`
+
+${ECHO} "testing ezmlm-idx:    $THIS_VER"
+${ECHO} "Using FQDN host name: $HOST"
+
+${ECHO} "$THIS_VER" | ${GREP} "$OLD_VER" >/dev/null 2>&1
+if [ "$?" = "0"        ]; then
+       DLC=''
+       DUC=''
+       EZVER='31'
+       QMVER='o'
+       ALLOW='extra'           # support old nomenclature
+       DENY='blacklist'
+else
+       ${ECHO} "$THIS_VER" | ${GREP} "$VER" >/dev/null 2>&1
+       if [ "$?" != "0" ]; then
+               ${ECHO} "Warning: ezmlm-make version is not $VER"
+               ${ECHO} "         test info may not be reliable"
+               ${ECHO}
+       fi
+########## should add testing of From line logging for non-0.31x
+       SW_FROM="-f"
+fi
+
+# Now see if we support old qmail
+
+  ${ECHO} "$THIS_VER" | ${GREP} "ezmlm-idx-0.32" >/dev/null 2>&1 && \
+       EZVER='32'; 
+
+if [ "$EZVER" != '31' -a "$EZVER" != '32' -a "$QMVER" = 'o' ]; then
+       ${ECHO} "Sorry, this version of ezmlm-idx requires qmail>=1.02"
+       exit 100;
+fi
+
+if [ "$SECT" = "1" ]; then
+##############
+# ezmlm-make #
+##############
+  ${ECHO} -n "ezmlm-make (1/2):     "
+
+# edit non-existant list
+  ${EZBIN}/ezmlm-make -e -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \
+       "$LOC" "$HOST" > /dev/null 2>&1 && \
+       { ${ECHO} "ezmlm-make failed reject edit of non-existing list:"
+         exit 100; }
+
+# make simple test list
+  ${EZBIN}/ezmlm-make -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \
+       "$LOC" "$HOST" || \
+       { ${ECHO} "ezmlm-make failed to create test list"; exit 100; }
+
+# remake simple test list which should fail
+  ${EZBIN}/ezmlm-make -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \
+       "$LOC" "$HOST" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject creation of existing list"; exit 100; }
+
+# edit the list (add digest)
+  ${EZBIN}/ezmlm-make -+d -C${EZBIN}/ezmlmrc "${DIR}" || \
+       { ${ECHO} "ezmlm-make failed to edit test list"; exit 100; }
+
+# edit the list (add digest)
+  ${MV} "${DIR}/config" "${DIR}/config~"
+  ${EZBIN}/ezmlm-make -ed -C${EZBIN}/ezmlmrc "${DIR}" "$DOT" "$LOC" "$HOST" \
+       >/dev/null 2>&1 || \
+       { ${ECHO} "failed without DIR/config: 0.313 bug, fixed in 0.314."
+         ${ECHO} -n "ezmlm-make ......     "
+         BUG="${BUG} config"
+       }
+  ${MV} "${DIR}/config~" "${DIR}/config"
+
+  ${GREP} "ezmlm-weed" "${DIR}/bouncer" >/dev/null 2>&1 || \
+       { ${ECHO} "no ezmlm-weed in bouncer"; exit 100; }
+  ${GREP} "ezmlm-return" "${DIR}/bouncer" >/dev/null 2>&1 || \
+       { ${ECHO} "no ezmlm-return in bouncer: 0.32 bug, fixed in 0.321."
+         ${ECHO} -n "ezmlm-make ......     "
+         BUG="${BUG} return"
+       }
+# digest/bouncer only for >=0.32
+  if [  "$EZVER" != '31' ]; then
+    if [ ! -f "${DIR}/digest/bouncer" ]; then
+       echo "failed to create digest/bouncer"; exit 100;
+    fi
+    ${GREP} "ezmlm-weed" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \
+       { ${ECHO} "no ezmlm-weed in bouncer"; exit 100; }
+    ${GREP} "ezmlm-return" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \
+       { ${ECHO} "no ezmlm-return in digest/bouncer: 0.32 bug, OK in 0.321."
+         ${ECHO} -n "ezmlm-make ......     "
+         BUG="${BUG} return"
+       }
+  fi
+  ${ECHO} "OK"
+
+# Add sql files for sql testing
+RDBMS='STD'
+${ECHO} -n "Using RDBMS support:  "
+if [ $USESQL ]; then
+  ${EZBIN}/ezmlm-make -+6 "$SQLHOST::$SQLUSER:$PW:$DB:$TABLE" \
+       -C${EZBIN}/ezmlmrc "${DIR}"|| \
+       { ${ECHO} "ezmlm-make failed to add SQL config info"; exit 100; }
+
+  ${STRINGS} ${EZBIN}/ezmlm-sub | ${GREP} -i 'MySQL' >/dev/null 2>&1 && \
+       RDBMS='MySQL'
+  ${STRINGS} ${EZBIN}/ezmlm-sub | ${GREP} -i 'libpq.' >/dev/null 2>&1 && \
+       RDBMS='PostgreSQL'
+  if [ "$RDBMS" = 'STD' ]; then
+       ${ECHO} "No recognized support. If none, will default to std dbs."
+  else
+       ${ECHO} "$RDBMS. Hope empty tables exist."
+  fi
+
+else
+       ${ECHO} "No."
+fi
+
+###############################################################
+# set up subscriber/moderator/sender/digest recipient account #
+###############################################################
+  ${MKDIR} "$SINKDIR" "$SINKDIR/new" "$SINKDIR/cur" "$SINKDIR/tmp" || \
+       { ${ECHO} "mkdir for sinkdir failed"; exit 100; }
+  ${ECHO} "${SINKDIR}/" > "$DOT-$SINK"
+# link for qmail version testing 
+  ${ECHO} '|echo $DEFAULT >' "${DIR}/default" > "$DOT-$SINK-default"
+  ${ECHO} "${SINKDIR}/" >> "$DOT-$SINK-default"
+
+  ${MKDIR} "$MODDIR" "$MODDIR/new" "$MODDIR/cur" "$MODDIR/tmp" || \
+       { ${ECHO} "mkdir for moddir failed"; exit 100; }
+  ${ECHO} "${MODDIR}/" > "$DOT-$MODACC"
+
+  ${MKDIR} "$MANDIR" "$MANDIR/new" "$MANDIR/cur" "$MANDIR/tmp" || \
+       { ${ECHO} "mkdir for mandir failed"; exit 100; }
+  ${ECHO} "${MANDIR}/" > "$DOT-$MANAG"
+
+  ${MKDIR} "$DIGDIR" "$DIGDIR/new" "$DIGDIR/cur" "$DIGDIR/tmp" || \
+       { ${ECHO} "mkdir for digdir failed"; exit 100; }
+  ${ECHO} "${DIGDIR}/" > "$DOT-$DIGGG"
+
+fi
+
+###########################
+# determine qmail version #
+###########################
+
+if [ "$SECT" != "9" ]; then
+
+${ECHO} "Subject: zzz-test" > "${DIR}/__tmp"
+${QMPATH}/bin/qmail-local "$EZTEST" "$HOME" "$SND-zzz" "$DASH" \
+               "$LIST-$SINK-zzz" "$HOST" \
+               "<>" '' < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "-failed to deliver message with qmail-local"; exit 100; }
+
+if [ ! -r "${DIR}/default" ]; then
+       ${ECHO} "qmail-local failed to deliver the message. Can't determine"
+       ${ECHO} "qmail version"
+       exit 99
+fi
+
+if [ `cat "${DIR}/default"` = "zzz" ]; then
+       if [ -z "$QMVER" ]; then
+               QMVER="n"
+       fi
+else
+       if [ -z "$QMVER" ]; then
+               QMVER="o"
+       fi
+fi
+
+${ECHO} -n "testing for qmail:    "
+if [ "$QMVER" = "n" ]; then
+       ${ECHO} ">=1.02"
+else
+       ${ECHO} "[any]"
+fi
+
+# if testing for old version, make sure DEFAULT is not defined. If printenv
+# is not available, we hope for the best and continue. unset should work ...
+# Set BADUNSET if unset doesn't do the job
+
+A='a'
+export A
+${UNSET} A
+[ -z "$A" ] || BADUNSET='y'
+
+${UNSET} DEFAULT
+
+if [ "$QMVER" = "o" ]; then
+  printenv PATH >/dev/null 2>&1 && \
+    printenv DEFAULT > /dev/null 2>&1 && \
+      { ${ECHO} "Can't test for old version of qmail if DEFAULT is defined. ";
+      ${ECHO} "Please undefine it."; exit 99; }
+fi
+
+# correct bouncer for our binaries:
+###################################
+# NOTE: This is duplicated (and should be) after next ezmlm-make block.
+  ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/bouncer"
+  ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/digest/bouncer"
+  if [ "$EZVER" = "31" ]; then # autodetecting bouncer for 0.31x
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer"
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer"
+  else                         # split bouncer with args for later versions
+       # edited for ezmlm-new
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer"
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer"
+  fi
+
+# if testing qmail>=1.02, remove inlocal/inhost - shouldn't be used
+  if [ "$QMVER" = "n" ]; then
+       ${RM} -f "${DIR}/inlocal" "${DIR}/inhost" > /dev/null || \
+         { ${ECHO} "failed to remove inlocal/inhost for testlist"; exit 100; }
+  fi
+
+###########################
+# set up bouncing account #
+###########################
+  ${ECHO} "|${GREP} 'MAILER-DAEMON' >/dev/null && exit 99" > "$DOT-$BOUNCE"
+  ${ECHO} "|exit 100" > "$DOT-$BOUNCE"
+
+fi
+
+###################################################
+# account to receive digests and archive excerpts #
+###################################################
+
+if [ "$SECT" = "1" ]; then
+
+#####################
+# test ezmlm-reject #
+#####################
+  ${ECHO} -n "ezmlm-reject:         "
+  FROM="$EZTEST"
+  TO="$EZTEST-__tstlist@$HOST"
+  SUBJECT="test"
+  CONTENT="multipart/mixed"
+  CC="<>"
+  BODY=''
+
+# with directory
+  make_message | ${EZBIN}/ezmlm-reject "${DIR}" || \
+       { ${ECHO} "failed to accept good message with dir"; \
+       exit 100; }
+# without directory
+
+  make_message | ${EZBIN}/ezmlm-reject || \
+       { ${ECHO} "failed to accept good message without dir: $?"; \
+       exit 100; }
+
+#too small
+  ${ECHO} "5000:1000" > "${DIR}/msgsize"
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject too small message"; \
+               exit 100; }
+
+# just right
+  ${ECHO} "500:5" > "${DIR}/msgsize"
+  make_message | ${EZBIN}/ezmlm-reject "${DIR}" || \
+       { ${ECHO} "failed to accept message of ok size"; \
+       exit 100; }
+
+#too large
+  ${ECHO} "20:10" > "${DIR}/msgsize"
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject too large message"; \
+               exit 100; }
+
+# restore
+  ${RM} -f "${DIR}/msgsize"
+
+# without subject
+  SUBJECT=''
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject message without subject"; \
+               exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject message without subject"; \
+               exit 100; }
+
+# with empty subject
+  SUBJECT='(NUll)'
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject null subject"; \
+               exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
+       { ${ECHO} "ezmlm-reject failed to reject null subject"; \
+               exit 100; }
+
+# testing -S
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -S "${DIR}"` || \
+       { ${ECHO} "-S switch failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -S ` || \
+       { ${ECHO} "-S switch failed without dir"; exit 100; }
+
+# with command subject
+  SUBJECT='REmOVE'
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "failed to reject command subject with dir"; \
+               exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \
+       { ${ECHO} "failed to reject command subject without dir"; \
+               exit 100; }
+
+# testing -C
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -C "${DIR}"` || \
+       { ${ECHO} "-C switch failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -C ` || \
+       { ${ECHO} "-C switch failed without dir"; exit 100; }
+
+  SUBJECT='test'
+
+# Test with list name in Cc:
+  CC="$TO"
+  TO="nobody@$HOST"
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \
+       { ${ECHO} "failed to accept good Cc: with dir"; \
+               exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
+       { ${ECHO} "failed to accept good Cc: without dir"; \
+               exit 100; }
+
+# Bad To/Cc
+  CC="$TO"
+  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+               { ${ECHO} "failed to reject bad To/Cc with dir"; \
+               exit 100; }
+  if [ "$?" != "100" ]; then
+       ${ECHO} "failed to exit 100 on error"; exit 100
+  fi
+  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject -q "${DIR}" 2>&1` && \
+               { ${ECHO} "failed to reject bad To/Cc with dir"; \
+               exit 100; }
+  if [ "$?" -ne "99" ]; then
+       ${ECHO} "-q failed"; exit 100
+  fi
+
+# for backwards-compatibility and since we don't know inlocal@inhost without
+# dir, ezmlm-reject doesn't check To/Cc when there is no dir
+  OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject` || \
+               { ${ECHO} "failed to accept bad To/Cc without dir"; \
+               exit 100; }
+
+# testing -T
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -T "${DIR}"` || \
+       { ${ECHO} "-T switch failed with dir"; exit 100; }
+OUT=`make_message | ${EZBIN}/ezmlm-reject -T ` || \
+       { ${ECHO} "-T switch failed without dir"; exit 100; }
+
+# restore good TO
+  TO="$EZTEST-__tstlist@$HOST"
+
+# if part is mimereject message should be rejected
+  touch "${DIR}"/mimeremove
+  ${ECHO} "text/html" > "${DIR}"/mimereject
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "mimereject failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
+       { ${ECHO} "mimereject without dir"; exit 100; }
+
+# if part is removed ezmlm-reject should not reject
+  ${ECHO} "tExt/htMl" > "${DIR}"/mimeremove
+  ${ECHO} "" > "${DIR}"/mimereject 
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \
+       { ${ECHO} "mimeremove failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
+       { ${ECHO} "mimeremove without dir"; exit 100; }
+
+# test content-type with something after boundary=xxx
+  AFTERBOUND=';micalg=pgp-md5'
+  ${ECHO} "text/html" > "${DIR}"/mimereject
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322"
+         ${ECHO} -n "ezmlm-reject.......   "
+         BUG="${BUG} reject_bound"
+       }
+
+# restore
+  ${RM} "${DIR}"/mimereject
+  AFTERBOUND=''
+
+# if entire message is mimeremove type is should be rejected
+  ${ECHO} "multipart/mixed" > "${DIR}"/mimeremove
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \
+       { ${ECHO} "mimereject failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
+       { ${ECHO} "mimereject without dir"; exit 100; }
+
+# restore
+  ${RM} "${DIR}"/mimeremove
+
+# test headerreject
+  ${ECHO} "Content-TYPE" > "${DIR}"/headerreject
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -H "${DIR}"` || \
+       { ${ECHO} "headerreject -H failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -h "${DIR}" 2>&1` && \
+       { ${ECHO} "headerreject failed with dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject` || \
+       { ${ECHO} "headerreject failed without dir"; exit 100; }
+  OUT=`make_message | ${EZBIN}/ezmlm-reject -h 2>&1` && \
+       { ${ECHO} "-h was accepted without dir"; exit 100; }
+
+# Suppress content-type header
+  CONTENT=''
+  OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \
+       { ${ECHO} "headerreject rejected even though header isn't there"; \
+       exit 100; }
+
+  CONTENT='multIpart/mIXed'
+
+  ${ECHO} "OK"
+###############################
+# ezmlm-sub/unsub/list/issubn #
+###############################
+
+  ${ECHO} -n "ezmlm-[un|is]sub[n]:  "
+
+  SENDER="XYZZY@HOst"; export SENDER
+
+# With mysql testing, there may be junk left from earlier testing that
+# gives false positives in testing. Make sure it's detected
+  ${EZBIN}/ezmlm-list "${DIR}" >/dev/null || \
+       { ${ECHO} "ezmlm-list: failed"; exit 100; }
+
+  ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} '@' >/dev/null 2>&1 && \
+       { ${ECHO} "already addresses in table - please remove and start again";
+               exit 100; }
+
+  ${EZBIN}/ezmlm-list "${DIR}/digest" | ${GREP} '@' >/dev/null 2>&1 && \
+       { ${ECHO} "already addresses in table - please remove and start again";
+               exit 100; }
+
+  ${EZBIN}/ezmlm-list "${DIR}/${ALLOW}" | ${GREP} '@' >/dev/null 2>&1 && \
+       { ${ECHO} "already addresses in table - please remove and start again";
+               exit 100; }
+
+# not subscriber. Test default
+  ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" && \
+       { ${ECHO} "ezmlm-issubn: failed: exit 0 on non-subscriber"; exit 100; }
+
+# not subscriber. Test -n
+  ${EZBIN}/ezmlm-issubn -n "${DIR}" "${DIR}/${ALLOW}" || \
+       { ${ECHO} "ezmlm-issubn: -n failed for non-subscriber"; exit 100; }
+
+# add subscriber
+  ${EZBIN}/ezmlm-sub "${DIR}" "xyZZy@hoSt" || \
+       { ${ECHO} "ezmlm-sub: failed to add subscriber"; exit 100; }
+
+# is subscriber. Test default
+  ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" || \
+       { ${ECHO} "ezmlm-issubn: failed: exit false for subscriber"; exit 100; }
+
+# is subscriber. Test -n
+  ${EZBIN}/ezmlm-issubn -n "${DIR}" "${DIR}/${ALLOW}" && \
+       { ${ECHO} "ezmlm-issubn: -n failed for subscriber"; exit 100; }
+
+# add to allow
+  ${EZBIN}/ezmlm-sub "${DIR}/${ALLOW}" "ZZtop@hoSt" || \
+       { ${ECHO} "ezmlm-sub: failed to add address to ${DIR}/${ALLOW}"; exit 100; }
+
+# list subscribers
+  ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} "xyZZy" >"${ERR}" 2>&1 || \
+       { ${ECHO} "ezmlm-list: failed to list subscribers"; exit 100; }
+
+# remove subscriber
+  ${EZBIN}/ezmlm-unsub "${DIR}" "xYzZy@hOst" || \
+       { ${ECHO} "ezmlm-sub: failed to add subscriber"; exit 100; }
+
+# see that it was removed
+  ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} "xyZZy" >"${ERR}" 2>&1 && \
+       { ${ECHO} "ezmlm-unsub: failed to remove subscriber"; exit 100; }
+
+  SENDER="zztop@HOst"; export SENDER
+
+# check for address in allow
+  ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" || \
+       { ${ECHO} "ezmlm-sub/issubn: failed to add/look in 2nd db"; exit 100; }
+
+# remove (multiple) (non)existing addresses from allow
+  ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "xYzZy@hOst" "zZToP@HOSt" || \
+       { ${ECHO} "ezmlm-unsub: failed to remove subscriber"; exit 100; }
+
+# verify removal
+  ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" && \
+       { ${ECHO} "ezmlm-unsub/issubn: failed to remove address"; exit 100; }
+
+# clean up
+  LOCAL=''; export LOCAL
+
+  ${ECHO} "OK"
+##############
+# ezmlm-send #
+##############
+  ${ECHO} -n "ezmlm-send (1/2):     "
+
+  SENDER="${SND}@$HOST"; export SENDER
+  ${EZBIN}/ezmlm-sub "${DIR}" "$SENDER"
+# set up prefix
+  ${ECHO} "[PFX]" > "${DIR}/prefix"
+# set up trailer
+  { ${ECHO} "--- TRAILER ---"; ${ECHO}; } > "${DIR}/text/trailer"
+# test
+  { ${ECHO} "X-num: msg1"; make_message; } | \
+       ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to accept normal message"; exit 100; }
+  if [ `cat "${DIR}/num"` != "1:1" ]; then
+       ${ECHO} "failed to create num for normal message 1"; exit 100; 
+  fi
+  if [ ! -x "${DIR}/archive/0/01" ]; then
+       { ${ECHO} "failed to archive normal message"; exit 100; }
+  fi
+  ${GREP} "1:" "${DIR}/archive/0/index" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to index archive"; exit 100; }
+
+  ${RM} -f "${DIR}/indexed"
+  ${RM} -f "${DIR}/archived"
+
+# test to see that trailer is added to nom-mime messages
+  CONTENT=''
+  { echo "X-num: msg5"; make_message; } | \
+       ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
+       { ${ECHO} "failed to accept non-mime message"; exit 100; }
+
+# test to see that trailer is suppressed for multipart/signed
+  CONTENT='multipart/signed'
+  { echo "X-num: msg6"; make_message; } | \
+       ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
+       { ${ECHO} "failed to accept multipart/signed message"; exit 100; }
+
+# restore
+  CONTENT='multipart/mixed'
+
+# test content-type with something after boundary=xxx
+  AFTERBOUND=';micalg=pgp-md5'
+  ${ECHO} "text/html" > "${DIR}"/mimeremove
+  make_message | ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1  || \
+       { ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322"
+         ${ECHO} -n "ezmlm-send.........   "
+         BUG="${BUG} send_bound"
+       }
+# restore
+  AFTERBOUND=''
+  ${ECHO} "1:1" > "${DIR}/num"
+  ${RM} "${DIR}"/mimeremove
+
+# -r => don't trim received headers
+  { ${ECHO} "X-num: msg2"; make_message; } | \
+       ${EZBIN}/ezmlm-send -r "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to accept normal message 2"; exit 100; }
+
+  ${GREP} "2:" "${DIR}/archive/0/index" >/dev/null 2>&1 && \
+       { ${ECHO} "indexed message with DIR/indexed missing"; exit 100; }
+  ${GREP} "msg2" ${DIR}/archive/0/* >/dev/null 2>&1 && \
+       { ${ECHO} "archived message with DIR/archived missing"; exit 100; }
+
+# -C eliminate SENDER from addressees
+  { ${ECHO} "X-num: msg3"; make_message; } | \
+       ${EZBIN}/ezmlm-send -C "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to accept normal message 3"; exit 100; }
+  ${EZBIN}/ezmlm-unsub "${DIR}" "$SENDER"
+
+# make sure headerremove was done
+  ${GREP} -i 'return-receipt-to' < "${DIR}/archive/0/01" >/dev/null &&
+       { ${ECHO} "failed to remove headerremove"; exit 100; }
+# test mimeremove
+  touch "${DIR}/archived" "${DIR}/indexed"
+  ${ECHO} "teXT/hTml" > "${DIR}/mimeremove"
+  { ${ECHO} "X-num: msg4"; make_message; } | \
+       ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to accept mimeremove message"; exit 100; }
+  ${GREP} -i 'text/html' < "${DIR}/archive/0/04" >/dev/null &&
+       { ${ECHO} "failed to remove mimeremove part"; exit 100; }
+
+  ${ECHO} "OK"
+################
+# ezmlm-tstdig #
+################
+  ${ECHO} -n "ezmlm-tstdig:         "
+
+  ${EZBIN}/ezmlm-tstdig -k2 -m5 -t1 "${DIR}" || \
+       { ${ECHO} "-t1 failed"; exit 100; }
+  ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" && \
+       { ${ECHO} "-t0 failed"; exit 100; }
+
+  LOCAL="$LOC-xx"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='xx'; export DEFAULT
+  fi
+  ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" || \
+       { ${ECHO} "problem with -xx in manager position"; exit 100; }
+  LOCAL="$LOC-dig."; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='dig.'; export DEFAULT
+  fi
+  ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" && \
+       { ${ECHO} "problem with -dig in manager position"; exit 100; }
+  LOCAL="$LOC-digest-"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='digest-'; export DEFAULT
+  fi
+  ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" || \
+       { ${ECHO} "err with -digest- in mgr pos: 0.31 bug fixed in 0.321"
+         ${ECHO} -n "ezmlm-tstdig.......   "
+         BUG="${BUG} digest"
+       }
+  LOCAL=''; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       unset DEFAULT
+  fi
+  ${EZBIN}/ezmlm-tstdig -k2 -m4 -t1 "${DIR}" || \
+       { ${ECHO} "-m failed"; exit 100; }
+  ${EZBIN}/ezmlm-tstdig -k1 -m5 -t0 "${DIR}" || \
+       { ${ECHO} "-k failed"; exit 100; }
+  LOCAL="$LOC"; export LOCAL
+  ${EZBIN}/ezmlm-tstdig -k1 -m5 -t0 "${DIR}" > "${ERR}" 2>&1 || \
+       {
+        ${ECHO} "problem with DEFAULT unset: 0.32 bug, OK in 0.321."
+        ${ECHO} -n "ezmlm-tstdig.......   "
+         BUG="${BUG} tstdig"
+       }
+  ${ECHO} "OK"
+
+##############
+# ezmlm-weed #
+##############
+
+  ${ECHO} -n "ezmlm-weed:           "
+
+  ${ECHO} "Subject: test" | ${EZBIN}/ezmlm-weed || \
+       { ${ECHO} "failed to accept good message"; exit 100; }
+  ${ECHO} "Subject: success notice" | ${EZBIN}/ezmlm-weed >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject bad message"; exit 100; }
+
+  ${ECHO} "OK"
+
+##############
+# ezmlm-make #
+##############
+  ${ECHO} -n "ezmlm-make (2/2):     "
+
+# make sure a few ezmlm-make switches work
+  ${EZBIN}/ezmlm-make -+qkgu -C${EZBIN}/ezmlmrc "${DIR}" || \
+       { ${ECHO} "failed to edit test list to +qkgu"; exit 100; }
+  ${GREP} "${DENY}" "${DIR}/editor" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to implement -k for list"; exit 100; }
+  ${GREP} "ezmlm-request" "${DIR}/manager" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to implement -q for list"; exit 100; }
+  ${GREP} "ezmlm-get -s" "${DIR}/manager" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to implement -g for list"; exit 100; }
+  ${GREP} "${ALLOW}" "${DIR}/editor" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to implement -u for list"; exit 100; }
+
+  ${EZBIN}/ezmlm-make -+QKGU -C${EZBIN}/ezmlmrc "${DIR}" || \
+       { ${ECHO} "failed to edit test list to +QKGU"; exit 100; }
+  ${GREP} "${DENY}" "${DIR}/editor" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to implement -K for list"; exit 100; }
+  ${GREP} "ezmlm-request" "${DIR}/manager" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to implement -Q for list"; exit 100; }
+  ${GREP} "ezmlm-get -s" "${DIR}/manager" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to implement -G for list"; exit 100; }
+  ${GREP} "${ALLOW}" "${DIR}/editor" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to implement -U for list"; exit 100; }
+
+# edit the list (add moderation and remove admin)
+  ${EZBIN}/ezmlm-make -+rsm -C${EZBIN}/ezmlmrc "${DIR}" || \
+       { ${ECHO} "failed to edit test list to +rsm"; exit 100; }
+# edit the list (add text file editing and list/log)
+${EZBIN}/ezmlm-make -+ln -C${EZBIN}/ezmlmrc "${DIR}" || \
+       { ${ECHO} "failed to edit test list to +ln"; exit 100; }
+
+# Now to create our own manager for later tests:
+
+${ECHO} "|${GREP} 'req1' >/dev/null 2>&1 && { ${ECHO} \"\$LOCAL\" >> '${REQ}'; exit 99; }; exit 0" > "${DIR}/manager"
+${ECHO} "|${EZBIN}/ezmlm-manage -le ${SW_FROM} '${DIR}'" >> "${DIR}/manager"
+${ECHO} "OK"
+
+# correct bouncer for our binaries:
+###################################
+  ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/bouncer"
+  ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/digest/bouncer"
+  if [ "$EZVER" = "31" ]; then # autodetecting bouncer for 0.31x
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer"
+    ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer"
+  else                         # split bouncer with args for later versions
+    ${ECHO} "|/${EZBIN}/ezmlm-return -D '${DIR}'" >> "${DIR}/bouncer"
+    ${ECHO} "|/${EZBIN}/ezmlm-return -d '${DIR}'" >> "${DIR}/digest/bouncer"
+  fi
+
+# if testing qmail>=1.02, remove inlocal/inhost - shouldn't be used
+  if [ "$QMVER" = "n" ]; then
+       ${RM} -f "${DIR}/inlocal" "${DIR}/inhost" > /dev/null || \
+         { ${ECHO} "failed to remove inlocal/inhost for testlist"; exit 100; }
+  fi
+
+
+###############
+# ezmlm-clean #
+###############
+
+  ${ECHO} -n "ezmlm-clean (1/2):    "
+
+# clean1 should be silently removed (no -x).
+# clean2 should result in a message
+# clean3 should not since it's time hasn't come
+# clean4 should be removed, but not result in a message since we use -R
+
+  ${ECHO} "Return-Path: <${DIG}@$HOST>" > "${DIR}/mod/pending/1"
+  ${ECHO} "X-num: clean1" >> "${DIR}/mod/pending/1"
+  ${ECHO} "Return-Path: <${DIG}@${HOST}>" > "${DIR}/mod/pending/2"
+  ${ECHO} "X-num: clean2" >> "${DIR}/mod/pending/2"
+  ${ECHO} "Return-Path: <${DIG}@$HOST>" > "${DIR}/mod/pending/999999999"
+  ${ECHO} "X-num: clean3" >> "${DIR}/mod/pending/999999999"
+
+  chmod +x "${DIR}/mod/pending/2" "${DIR}/mod/pending/999999999"
+
+  ${EZBIN}/ezmlm-clean "${DIR}" >"${ERR}" 2>&1 ||
+       { ${ECHO} "failed first invocation"; exit 100; }
+  if [ -r "${DIR}/mod/pending/1" ]; then
+       ${ECHO} "failed to remove non-x moderation queue entry 1"
+       exit 100
+  fi
+  if [ -r "${DIR}/mod/pending/2" ]; then
+       ${ECHO} "failed to remove moderation queue entry 2"
+       exit 100
+  fi
+  if [ ! -r "${DIR}/mod/pending/999999999" ]; then
+       ${ECHO} "removed mod queue entry 3 that wasn't due"
+       exit 100
+  fi
+
+${ECHO} <<EOF > "${DIR}/mod/pending/4"
+Return-Path: <${DIG}@$HOST>
+X-num: clean4
+EOF
+  chmod +x "${DIR}/mod/pending/4"
+  ${EZBIN}/ezmlm-clean -R "${DIR}" >"${ERR}" 2>&1 ||
+       { ${ECHO} "-R failed"; exit 100; }
+  if [ -r  "${DIR}/mod/pending/4" ]; then
+       ${ECHO} "failed to remove moderation queue entry 4"; exit 100
+  fi
+
+  ${ECHO} "OK"
+
+###############
+# ezmlm-store #
+###############
+
+  ${ECHO} -n "ezmlm-store (1/2):    "
+
+  SENDER="${SND}@$HOST"; export SENDER
+  ${EZBIN}/ezmlm-sub "${DIR}/mod" "$SENDER"
+
+# message from mod, normal use -> should queue
+  { ${ECHO} "X-num: mod1"; make_message; } > ${TMP};
+       ${EZBIN}/ezmlm-store "${DIR}" >"${ERR}" 2>&1 < ${TMP} || \
+       { ${ECHO} "failed to process message 1"; exit 100; }
+
+  cat ${DIR}/mod/pending/* | ${GREP} "mod1" > /dev/null || \
+       { ${ECHO} "failed to queue message 1"; exit 100; }
+
+  ${RM} -f "${DIR}/modpost" 
+
+# no modpost - should go directly to list
+  { ${ECHO} "X-num: mod2"; make_message; } > ${TMP};
+       ${EZBIN}/ezmlm-store "${DIR}" >"${ERR}" 2>&1 < ${TMP} || \
+       {
+         ${GREP} -v "child" "${ERR}" > /dev/null 2>&1
+         if [ "$?" != "0" ]; then
+           ${ECHO} "Failed to process message mod2"; exit 100
+         else
+           EZFORK='no'
+         fi
+       }
+
+  cat ${DIR}/mod/pending/* | ${GREP} "mod2" > /dev/null && \
+       { ${ECHO} "queued message 2 despite non-modpost"; exit 100; }
+
+  if [ -z "$EZFORK" ]; then
+       cat ${DIR}/archive/0/* | ${GREP} "mod2" > /dev/null || \
+               { ${ECHO} "failed to archive message 2 (non-modpost)"; exit 100; }
+  fi
+
+  touch "${DIR}/modpost"
+
+# from moderator. Should be queued, even with -P
+  { ${ECHO} "X-num: mod3"; make_message; } > ${TMP};
+       ${EZBIN}/ezmlm-store -P "${DIR}" >"${ERR}" 2>&1 < ${TMP} || \
+       { ${ECHO} "-P failed to accept mods post 3"; exit 100; }
+
+  cat ${DIR}/mod/pending/* | ${GREP} "mod3" > /dev/null || \
+       { ${ECHO} "failed to queue message 3"; exit 100; }
+
+  ${EZBIN}/ezmlm-unsub "${DIR}/mod" "$SENDER"
+
+# not from moderator, should be rejected directly with -P
+  { ${ECHO} "X-num: mod4"; make_message; } > ${TMP};
+       ${EZBIN}/ezmlm-store -P "${DIR}" >"${ERR}" 2>&1 < ${TMP} && \
+       { ${ECHO} "-P failed to reject non-mod message 4"; exit 100; }
+
+  ${ECHO} "OK"
+
+################
+# ezmlm-return #
+################
+  ${ECHO} -n "ezmlm-return:         "
+
+  SENDER="${BNC}@$HOST"; export SENDER
+  HOST="$HOST"; export HOST
+  LOCAL="$LOC-return-1-$BNC=$HOST"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT="1-$BNC=$HOST"; export DEFAULT
+  fi
+# we use 'du' because bounce handling is different in 0.31x and >=0.32
+  BSIZE1=`${DU} "${DIR}/bounce"` || \
+       { ${ECHO} "du doesn't work"; exit 99; } 
+  make_message | ${EZBIN}/ezmlm-return "${DIR}" || \
+    [ "$?" -eq "99" ] || \
+       { ${ECHO} "failed to process normal bounce from non-sub" ; exit 100; }
+  BSIZE2=`${DU} "${DIR}/bounce"`
+  if [ "$BSIZE1" != "$BSIZE2" ]; then
+       ${ECHO} "failed to ignore non-subscriber bounce" ; exit 100
+  fi
+  ${EZBIN}/ezmlm-sub "${DIR}" "${BNC}@$HOST"
+  make_message | ${EZBIN}/ezmlm-return "${DIR}" || \
+    [ "$?" -eq "99" ] || \
+       { ${ECHO} "failed to process normal bounce from sub" ; exit 100; }
+  BSIZE1=`${DU} "${DIR}/bounce"`
+  if [ "$BSIZE1" = "$BSIZE2" ]; then
+       ${ECHO} "failed to note subscriber bounce" ; exit 100
+  fi
+  LOCAL="$LOC-digest-return-1-$BNC=$HOST"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT="1-$BNC=$HOST"; export DEFAULT
+  fi
+  BSIZE1=`${DU} "${DIR}/digest/bounce"`
+  make_message | ${EZBIN}/ezmlm-return $DLC "${DIR}" || \
+    [ "$?" -eq "99" ] || \
+       { ${ECHO} "failed to process normal digest non-sub bounce" ; exit 100; }
+  BSIZE2=`${DU} "${DIR}/digest/bounce"`
+  if [ "$BSIZE1" != "$BSIZE2" ]; then
+       ${ECHO} "failed to ignore non-digest-subscriber bounce" ; exit 100
+  fi
+  ${EZBIN}/ezmlm-unsub "${DIR}" "${BNC}@$HOST"
+  ${EZBIN}/ezmlm-sub "${DIR}/digest" "${BNC}@$HOST"
+  make_message | ${EZBIN}/ezmlm-return $DLC "${DIR}" || \
+    [ "$?" -eq "99" ] || \
+       { ${ECHO} "failed to proc. nl digest-subscriber bounce" ; exit 100; }
+  BSIZE1=`${DU} "${DIR}/digest/bounce"`
+  if [ "$BSIZE1" = "$BSIZE2" ]; then
+       ${ECHO} "failed to note digest-subscriber bounce" ; exit 100
+  fi
+  ${EZBIN}/ezmlm-sub "${DIR}" "${BNC}@$HOST"
+
+  ${ECHO} "OK"
+
+# as we exit, the bounce address is subscribed to both list and digest-list
+# and is the SENDER
+
+##############
+# ezmlm-warn #
+##############
+  ${ECHO} -n "ezmlm-warn (1/3):     "
+
+# should send a warning
+  ${EZBIN}/ezmlm-warn -t0 "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with normal bounce for warning"; exit 100; }
+  ${EZBIN}/ezmlm-issubn "${DIR}" || \
+       { ${ECHO} "script error: SENDER is not a subscriber"; exit 100; }
+
+  ${EZBIN}/ezmlm-warn -d -t0 "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with digest bounce for warning"; exit 100; }
+  ${EZBIN}/ezmlm-issubn "${DIR}/digest" || \
+       { ${ECHO} "script error: SENDER is not a digest subscriber"; exit 100; }
+
+  ${ECHO} "OK"
+
+################
+# ezmlm-manage #
+################
+  ${ECHO} -n "ezmlm-manage (1/4):   "
+
+  LOCAL="$LOC-unsubscribe"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='unsubscribe'; export DEFAULT
+  fi
+  SENDER="${SND}@$HOST"; export SENDER
+
+  ${EZBIN}/ezmlm-sub "${DIR}" "${SND}@$HOST"
+  ${EZBIN}/ezmlm-manage -U "${DIR}" </dev/null >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with -U"; exit 100; }
+  ${EZBIN}/ezmlm-issubn "${DIR}" && \
+       { ${ECHO} "unsubscribe with -U failed"; exit 100; }
+
+  LOCAL="$LOC-digest-subscribe"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='digest-subscribe'; export DEFAULT
+  fi
+  ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${SND}@$HOST"
+
+# test that access to the deny db is restricted to remote admins
+  LOCAL="$LOC-deny-subscribe"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='deny-subscribe'; export DEFAULT
+  fi
+  ${EZBIN}/ezmlm-manage "${DIR}" </dev/null >/dev/null 2>&1 && \
+       {
+        ${ECHO} "Deny open to regular subscribers: 0.31 bug, OK in 0.321."
+        ${ECHO} -n "ezmlm-manage ...      "
+        BUG="${BUG} deny"
+       }
+  SENDER="${MOD}@$HOST"; export SENDER
+  ${EZBIN}/ezmlm-sub "${DIR}/mod" "$SENDER" || exit 100
+  ${EZBIN}/ezmlm-manage "${DIR}" </dev/null > "${ERR}" 2>&1 || \
+       { ${ECHO} "Deny access denied to remote admin!"; exit 100; }
+
+# make non-moderated
+  ${RM} -f "${DIR}/modsub" || \
+       { ${ECHO} "Failed to remove DIR/modsub"; exit 99; }
+
+# make non-remote
+  ${RM} -f "${DIR}/remote" || \
+       { ${ECHO} "Failed to remove DIR/remote"; exit 99; }
+  ${EZBIN}/ezmlm-manage "${DIR}" </dev/null > "${ERR}" 2>&1 && \
+       {
+        ${ECHO} "Deny even without remote/modsub: 0.31 bug, OK in 0.321."
+        ${ECHO} -n "ezmlm-manage ...      "
+        BUG="${BUG} deny"
+       }
+
+# restore remote/SENDER/mod/LOCAL/DEFAULT
+  ${EZBIN}/ezmlm-unsub "${DIR}/mod" "$SENDER" || exit 100
+  SENDER="${SND}@$HOST"; export SENDER # restore order
+  touch "${DIR}/remote" || \
+       { ${ECHO} "Failed to remove DIR/remote"; exit 99; }
+  LOCAL="$LOC-digest-subscribe"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='digest-subscribe'; export DEFAULT
+  fi
+
+  ${EZBIN}/ezmlm-manage -S "${DIR}" </dev/null >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with -S"; exit 100; }
+  ${EZBIN}/ezmlm-issubn "${DIR}/digest" || \
+       { ${ECHO} "digest-subscribe with -S failed"; exit 100; }
+  ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${SND}@$HOST"
+  touch "${DIR}/modsub" || \
+       { ${ECHO} "Failed to restore DIR/modsub"; exit 99; }
+
+  SENDER="${MAN}@$HOST"; export SENDER
+
+  ${ECHO} "X-num: sub1" > "${DIR}/__tmp"
+  ${ECHO} "From: Mr. $EZTEST requests <${MAN}@$HOST>" >> "${DIR}/__tmp"
+  ${ECHO} >> "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-manage ${SW_FROM} "${DIR}" < "${DIR}/__tmp" \
+               >"${ERR}" 2>&1 || \
+       { ${ECHO} "digest-subscribe with request failed"; exit 100; }
+
+  ${EZBIN}/ezmlm-sub "${DIR}" "${MAN}@$HOST"
+  LOCAL="$LOC-unsubscribe"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='unsubscribe'; export DEFAULT
+  fi
+  ${ECHO} "X-num: sub2" > "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "unsubscribe request failed"; exit 100; }
+
+# -get function for backwards compatibility
+  LOCAL="$LOC-get.1"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='get.1'; export DEFAULT
+  fi
+  ${ECHO} "X-num: manget1" > "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "get failed"; exit 100; }
+# -C should disable it
+  ${EZBIN}/ezmlm-manage -C "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 && \
+       { ${ECHO} "-C failed to disable -get"; exit 100; }
+
+  ${ECHO} "OK"
+
+#################
+# ezmlm-request #
+#################
+  ${ECHO} -n "ezmlm-request (1/2):  "
+
+  SENDER="${SND}@$HOST"; export SENDER
+  LOCAL="$LOC-request"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT='request'; export DEFAULT
+  fi
+
+  ${ECHO} "X-num: req1" > "${DIR}/__tmp"
+# use a non-existing command
+  ${ECHO} "Subject: qqqq ${SND}@$HOST" >> "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-request "${DIR}" < "${DIR}/__tmp" > "${ERR}" 2>&1
+  if [ "$?" != "99" ]; then
+       ${ECHO} "qqqq command in subject failed to exit 99"
+       exit 100
+  fi
+
+  ${ECHO} "X-num: req1" > "${DIR}/__tmp"
+# test full ezmlm cmd in subject and command substitution
+  ${ECHO} "Subject: ${LOC}-remove-${SND}=${HOST}@${HOST}" >> "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-request "${DIR}" < "${DIR}/__tmp" > "${ERR}" 2>&1
+  if [ "$?" != "99" ]; then
+       ${ECHO} "full ezmlm command in subject failed to exit 99"
+       exit 100
+  fi
+
+
+
+  ${ECHO} "OK"
+
+###############
+# ezmlm-split #
+###############
+if [ "$QMVER" = "n" ]; then
+  ${ECHO} -n "ezmlm-split (1/2):    "
+# set up split file
+  ${ECHO} "edu:1:26:l1@h1" > "${DIR}/split"
+  ${ECHO} "edu:27:52:l2@h2" >> "${DIR}/split"
+  ${ECHO} "com:::l3@h3" >> "${DIR}/split"
+# most testing with -D
+  ${ECHO} "lindberg@ezmlm.org" | ${EZBIN}/ezmlm-split -D "${DIR}" | \
+       ${GREP} "$LIST@$HOST" >/dev/null || \
+       { ${ECHO} "failed to split correctly on domain"; exit 100; }
+  ${ECHO} "lindberg@id.com" | ${EZBIN}/ezmlm-split -D "${DIR}" | \
+       ${GREP} 'l3' >/dev/null || \
+       { ${ECHO} "failed to split correctly on domain"; exit 100; }
+  ${ECHO} "lindberg@id.wustl.edu" | ${EZBIN}/ezmlm-split -D "${DIR}" | \
+       ${GREP} 'l1' >/dev/null || \
+       { ${ECHO} "failed to split correctly on hash + domain"; exit 100; }
+  ${ECHO} "cfl@id.wustl.edu" | ${EZBIN}/ezmlm-split -D "${DIR}" | \
+       ${GREP} 'l2' >/dev/null || \
+       { ${ECHO} "failed to split correctly on hash + domain"; exit 100; }
+# one test with delivery - redirect to local manager
+# should exit 99 after redirecting
+  ${ECHO} ":::${LOC}@$HOST" > "${DIR}/split"
+  SENDER="${MOD}@$HOST"; export SENDER
+  DTLINE="Delivered-To: ezmlm-split@$HOST"; export DTLINE
+  LOCAL="$LOC-subscribe-${SND}=$HOST"; export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT="subscribe-${SND}=$HOST"; export DEFAULT
+  fi
+  ${ECHO} "X-num: spl1" | ${EZBIN}/ezmlm-split "${DIR}" >"${ERR}" 2>&1
+
+  EC="$?"
+  if [ "$EC" -eq "0" ]; then
+       ${ECHO} "exited 0 after forwarding, rather than 99"; exit 100
+  elif [ "$EC" != "99" ]; then
+       ${ECHO} "failed to process message for forwarding"; exit 100
+  fi
+# if no match, should exit 0
+  ${ECHO} "___:::${LOC}@$HOST" > "${DIR}/split"
+  ${ECHO} "X-num: spl1" | ${EZBIN}/ezmlm-split "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to exit 0 after failing to match"; exit 100; }
+
+  ${ECHO} "OK"
+fi
+
+########################
+# waiting for delivery #
+########################
+  send_test 2
+fi             # end of sect 1
+
+####################################### start of section 2
+
+if [ "$SECT" -le "2" ]; then
+  wait_test 2
+
+#############
+# ezmlm-idx #
+#############
+  ${ECHO} -n "ezmlm-idx:            "
+  ${RM} -f "${DIR}/archive/0/index" "${DIR}/indexed"
+  ${EZBIN}/ezmlm-idx "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to run"; exit 100; }
+  if [ ! -r "${DIR}/indexed" ]; then
+       ${ECHO} "failed to create DIR/indexed"; exit 100
+  fi
+  if [ ! -r "${DIR}/archive/0/index" ]; then
+       ${ECHO} "failed to create index"; exit 100
+  fi 
+  ${ECHO} "OK"
+
+#############
+# ezmlm-get #
+#############
+${ECHO} -n "ezmlm-get (1/2):      "
+
+# blast digest recipient account with all these excerpts.
+${EZBIN}/ezmlm-sub "${DIR}/digest" "${DIG}@$HOST"
+
+# first ezmlm-get in the manager position:
+
+# index1/get1/thread1 should bounce and will not be looked for
+# index2 ... should be in DIG@HOST's inbox
+# get3 - r format to DIG@HST
+# get4 - n
+# get5 - v
+# get6 - x
+
+SENDER="${BNC}@$HOST"; export SENDER
+LOCAL="$LOC-xxxx"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='xxxx'; export DEFAULT
+fi
+${ECHO} "X-num: index1" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} " failed to exit 0 for non-recognized commands"; exit 100; }
+
+# This should not give a digest
+LOCAL="$LOC-"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=''; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} " failed to exit 0 for list-@host"; exit 100; }
+
+LOCAL="$LOC-index"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='index'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "-s failed to reject -index from non-sub"; exit 100; }
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" -ne "99" ]; then
+       ${ECHO} "failed to exit 99 after -index"
+       exit 100
+fi
+
+${ECHO} "X-num: index2" > "${DIR}/__tmp"
+SENDER="${DIG}@$HOST"; export SENDER
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" -ne "99" ]; then
+       ${ECHO} "-s failed to exit 99 after -index"
+       exit 100
+fi
+
+SENDER="${BNC}@$HOST"; export SENDER
+${ECHO} "X-num: get1" > "${DIR}/__tmp"
+LOCAL="$LOC-get.2_4"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='get.2_4'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "-s failed to reject -get from non-sub"; exit 100; }
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -get"
+       exit 100
+fi
+${ECHO} "X-num: get2" > "${DIR}/__tmp"
+SENDER="${DIG}@$HOST"; export SENDER
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "-s failed to exit 99 after -get"
+       exit 100
+fi
+
+# test formats for -get
+${ECHO} "X-num: get3" > "${DIR}/__tmp"
+LOCAL="$LOC-getr.2_4"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='getr.2_4'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -getr"
+       exit 100
+fi
+${ECHO} "X-num: get4" > "${DIR}/__tmp"
+LOCAL="$LOC-getn.2_4"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='getn.2_4'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -getn"
+       exit 100
+fi
+
+${ECHO} "X-num: get5" > "${DIR}/__tmp"
+LOCAL="$LOC-getv.2_4"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='getv.2_4'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -getv"
+       exit 100
+fi
+
+${ECHO} "X-num: get6" > "${DIR}/__tmp"
+LOCAL="$LOC-getx.2_4"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='getx.2_4'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -getx"
+       exit 100
+fi
+
+SENDER="${BNC}@$HOST"; export SENDER
+LOCAL="$LOC-index"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='index'; export DEFAULT
+fi
+${ECHO} "X-num: thread1" > "${DIR}/__tmp"
+LOCAL="$LOC-thread.1"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='thread.1'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "-s failed to reject -thread from non-sub"; exit 100; }
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after -thread"
+       exit 100
+fi
+${ECHO} "X-num: thread2" > "${DIR}/__tmp"
+SENDER="${DIG}@$HOST"; export SENDER
+${EZBIN}/ezmlm-get -s "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "-s failed to exit 99 after -thread"
+       exit 100
+fi
+
+######### digests
+# we use headeradd to label them since trigger headers aren't propagated
+${ECHO} "X-num: not_propagated" > "${DIR}/__tmp"
+
+# dig1 from manager will go to DIG@HOST
+# dig2 from editor
+# dig3 from command line
+# dig4 -fr format check from command line. We check only that they get there.
+# dig5 -fn
+# dig6 -fx
+# dig7 -fv
+# we check that dignum is created and digissue is updated 
+
+# now -dig in the manager position:
+mv -f "${DIR}/headeradd" "${DIR}/headeradd.bak"
+${ECHO} "X-num: dig1" > "${DIR}/headeradd"
+SENDER="${BNC}@$HOST"; export SENDER
+LOCAL="$LOC-dig.code"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT='dig.code'; export DEFAULT
+fi
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject -dig when no digest code was on cmd-line"
+         exit 100
+       }
+if [ -r "${DIR}/dignum" ]; then
+       ${ECHO} "script error: dignum exists"; exit 100
+fi
+${EZBIN}/ezmlm-get "${DIR}" 'code' < "${DIR}/__tmp" >"${ERR}" 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 after digest in manager position"
+       exit 100
+fi
+if [ ! -r "${DIR}/dignum" ]; then
+       ${ECHO} "failed to generate dignum"; exit 100
+fi
+if [ ! -r "${DIR}/digissue" ]; then
+       ${ECHO} "failed to generate digissue"; exit 100
+fi
+${EZBIN}/ezmlm-get "${DIR}" 'code' < "${DIR}/__tmp" >/dev/null 2>&1
+if [ "$?" != "99" ]; then
+       ${ECHO} "failed to exit 99 when nothing to digest in manager position"
+       exit 100
+fi
+
+${EZBIN}/ezmlm-get "${DIR}" 'coden' < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject -dig with bad digest code 'coden'"; exit 100; }
+${EZBIN}/ezmlm-get "${DIR}" 'cod' < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject -dig with bad digest code 'cod'"; exit 100; }
+
+# now in the editor position:
+${RM} -f "${DIR}/dignum"
+LOCAL="$LOC"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       ${UNSET} DEFAULT
+fi
+${ECHO} "X-num: dig2" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to exit 0 after digest in editor"; exit 100; }
+
+# This causes an error on systems where 'unset' doesn't work
+# For these, we skip this test.
+  if [ -z "$BADUNSET" ]; then
+    if [ ! -r "${DIR}/dignum" ]; then
+       ${ECHO} "failed to generate dignum after digest in editor"; exit 100
+    fi
+
+    ${GREP} "2:" "${DIR}/digissue" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to update digissue after digest in editor";
+         exit 100; }
+    ${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to exit 0 when nothing to digest in editor";
+         exit 100; }
+  fi
+
+# now from the command line with formats ...
+${RM} -f "${DIR}/dignum"
+LOCAL=''; export LOCAL
+${ECHO} "X-num: dig3" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to exit 0 after cmd line digest"; exit 100; }
+${GREP} "3:" "${DIR}/digissue" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to update digissue after cmd line digest"; exit 100; }
+${EZBIN}/ezmlm-get "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to exit 0 when nothing to digest from cmd line"
+       exit 100; }
+${RM} -f "${DIR}/dignum"
+${ECHO} "X-num: dig4" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get -fr "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "-fr failed for digest"; exit 100; }
+${RM} -f "${DIR}/dignum"
+${ECHO} "X-num: dig5" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get -fn "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "-fn failed for digest"; exit 100; }
+${RM} -f "${DIR}/dignum"
+${ECHO} "X-num: dig6" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get -fv "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "-fv failed for digest"; exit 100; }
+${RM} -f "${DIR}/dignum"
+${ECHO} "X-num: dig7" > "${DIR}/headeradd"
+${EZBIN}/ezmlm-get -fx "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "-fx failed for digest"; exit 100; }
+
+# restore headeradd
+mv -f "${DIR}/headeradd.bak" "${DIR}/headeradd"
+
+${ECHO} "OK"
+
+##############
+# ezmlm-send #
+##############
+${ECHO} -n "ezmlm-send (2/2):     "
+MSG1=`${GREP} -l "msg1" $SINKDIR/new/*` || \
+       { ${ECHO} "failed to deliver message 1 to subscriber"; \
+       exit 100; }
+# make sure headeradd was done
+  ${GREP} -i 'precedence: bulk' < "$MSG1" >/dev/null 2>&1 ||
+       { ${ECHO} "failed to add headeradd"; exit 100; }
+# check on received: header handling
+${GREP} '#PENULTIMATE#' "$MSG1" >/dev/null && \
+       { ${ECHO} "-r failed to remove received header"; \
+       exit 100; }
+${GREP} '#LAST#' "$MSG1" >/dev/null || \
+       { ${ECHO} "-r failed to leave last received header"; \
+       exit 100; }
+${GREP} 'Subject:' "$MSG1" | ${GREP} 'PFX' >/dev/null 2>&1 || \
+       { ${ECHO} "failed to add subject prefix"; exit 100; }
+       # the trailer should be a MIME part, so not at the very end
+${TAIL} -6 "$MSG1" | ${HEAD} -2 | ${GREP} 'TRAILER' >/dev/null 2>&1 || \
+       { ${ECHO} "failed to add trailer"; exit 100; }
+
+MSG2=`${GREP} -l "msg2" $SINKDIR/new/*` || \
+       { ${ECHO} "failed to deliver message 2 to subscriber"; \
+       exit 100; }
+${GREP}  '#PENULTIMATE#' "$MSG2" >/dev/null || \
+       { ${ECHO} "-R failed to leave received header"; \
+       exit 100; }
+
+${GREP} "msg3" $SINKDIR/new/* >/dev/null 2>&1 && \
+       { ${ECHO} "-C failed to exclude sender (no longer supported)"; \
+         BUG="${BUG}_noself"; \
+         echo -n "ezmlm-send:           "; }
+
+MSG5=`${GREP} -l "msg5" $SINKDIR/new/*` || \
+       { ${ECHO} "failed to deliver message 5 to subscriber"; \
+       exit 100; }
+${GREP} 'TRAILER' "$MSG5" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to add trailer to non-mime message"; \
+       exit 100; }
+
+MSG6=`${GREP} -l "msg6" $SINKDIR/new/*` || \
+       { ${ECHO} "failed to deliver message 6 to subscriber"; \
+       exit 100; }
+
+${GREP} 'TRAILER' "$MSG6" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to suppress trailer for multipart/signed message"; \
+         echo "                      0.31 bug fixed in 0.316/0.323";
+         BUG="${BUG}_signed"; \
+         echo -n "ezmlm-send ......:    "; }
+
+${GREP} "msg3" $SINKDIR/new/* >/dev/null 2>&1 && \
+       { 
+         ${ECHO} "${BUG}" | ${GREP} 'noself' >/dev/null 2>&1 || \
+         {
+           ${ECHO} "-C failed to exclude sender (no longer supported)"
+           BUG="${BUG}_noself"
+           echo -n "ezmlm-send ......:   ${BUG} "
+         }
+       }
+
+${ECHO} "OK"
+###############
+# ezmlm-clean #
+###############
+
+${ECHO} -n "ezmlm-clean (2/2):    "
+
+${GREP} "clean1" ${DIGDIR}/new/* >/dev/null 2>&1 && \
+       { ${ECHO} "removal of non-x mod queue entry 1 wasn't silent"; exit 100; }
+${GREP} "clean2" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "failed to notify sender of mod queue entry 2 time out"
+         exit 100
+       }
+${GREP} "clean3" ${DIGDIR}/new/* >/dev/null 2>&1 && \
+       { ${ECHO} "notified sender about entry 3 even though it wasn't rejected"
+         exit 100
+       }
+${GREP} "clean4" ${DIGDIR}/new/* >/dev/null 2>&1 && \
+       { ${ECHO} "-R failed: notified sender about entry 3 rejection"; exit 100; }
+
+
+# clean1 should be silently removed (no -x).
+# clean2 should result in a message
+# clean3 should not since it's time hasn't come
+# clean4 should be removed, but not result in a message since we use -R
+
+${ECHO} "OK"
+
+###############
+# ezmlm-store #
+###############
+${ECHO} -n "ezmlm-store (2/2):    "
+
+MOD1=`${GREP} -l "mod1" $SINKDIR/new/* 2>/dev/null`
+if [ -z "$MOD1" ]; then
+       ${ECHO} "ezmlm-store: failed to deliver mod request to moderator"
+       exit 100
+fi
+${GREP} "mod2" $SINKDIR/new/* >/dev/null && \
+       { ${ECHO} "ezmlm-store: didn't post directly in absence of DIR/modpost"; \
+       exit 100; }
+MOD3=`${GREP} -l "mod3" $SINKDIR/new/* 2>/dev/null`
+if [ -z "$MOD3" ]; then
+       ${ECHO} "ezmlm-store: -P failed to deliver mod request to moderator"
+       exit 100
+fi
+${GREP} "mod4" $SINKDIR/new/* >/dev/null && \
+       { ${ECHO} "ezmlm-store: -P failed to reject message from non-mod"; \
+       exit 100; }
+
+${ECHO} "OK"
+
+################
+# ezmlm-manage #
+################
+${ECHO} -n "ezmlm-manage (2/4):   "
+
+# check digest-subscribe and list-unsubscribe replies
+SUB1=`${GREP} -l 'sub1' $MANDIR/new/*` || \
+       { ${ECHO} "failed getting digest-subscribe confirm request"; exit 100; }
+
+SUB2=`${GREP} -l 'sub2' $MANDIR/new/*` || \
+       { ${ECHO} "failed getting -unsubscribe confirm request"; exit 100; }
+
+# Check -get.1 reply
+MANGET1=`${GREP} -l 'manget1' $MANDIR/new/*` || \
+       { ${ECHO} "failed getting -get.1 reply"; exit 100; }
+
+${GREP} 'msg1' "$MANGET1" >/dev/null || \
+       { ${ECHO} "get.1 failed to return archived message"; exit 100; }
+
+# Add moderator
+${EZBIN}/ezmlm-sub "${DIR}/mod" "${MOD}@$HOST"
+
+LOCAL=`${GREP} "Reply-To:" "$SUB1" | cut -d' ' -f2 | cut -d'@' -f1` || \
+       { ${ECHO} "failed to find confirm address in -subscribe reply"; exit 100; }
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT
+fi
+${ECHO} "X-num: sub3" > "${DIR}/__tmp"
+${ECHO} "From: Mr. $EZTEST confirms <$SENDER>" >> "${DIR}/__tmp"
+${ECHO} >> "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage ${SW_FROM} "${DIR}" < "${DIR}/__tmp" \
+               >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed to send user conf for sub1"; exit 100; }
+
+LOCAL=`${GREP} "Reply-To:" "$SUB2" | cut -d' ' -f2 | cut -d'@' -f1` || \
+       { ${ECHO} "failed to find confirm address in -unsubscribe reply"
+         exit 100; }
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT
+fi
+${ECHO} "X-num: sub4" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to send conf for sub2"; exit 100; }
+
+# now test remote admin functions
+# add a few addresses to allow
+${EZBIN}/ezmlm-sub "${DIR}/${ALLOW}" "aaa@bbb" "ccc@ddd" "eee@fff"
+
+# test -edit
+${ECHO} "#TEST_TEXT#" > "${DIR}/text/test"
+LOCAL="$LOC-edit.test-$MAN=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="edit.test-$MAN=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: edit1" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -e "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject edit request from non-mod"; exit 100; }
+LOCAL="$LOC-edit.test-$MOD=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="edit.test-$MOD=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: edit2" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 && \
+       { ${ECHO} "-E failed for edit2"; exit 100; }
+${ECHO} "X-num: edit3" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -e "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "-e failed for remote admin for edit3"; exit 100; }
+
+# test list/log
+LOCAL="$LOC-allow-list-$MAN=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="allow-list-$MAN=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: list1" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -l "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject list request from non-mod"; exit 100; }
+
+LOCAL="$LOC-allow-log-$MAN=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="allow-log-$MAN=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: log1" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -l "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "failed to reject log request from non-mod"; exit 100; }
+
+LOCAL="$LOC-allow-list-$MOD=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="allow-list-$MOD=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: list2" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 && \
+       { ${ECHO} "-L failed to reject list request"; exit 100; }
+
+${ECHO} "X-num: list3" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -l "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "-l failed for remote admin for list3"; exit 100; }
+
+LOCAL="$LOC-allow-log-$MOD=$HOST"; export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT="allow-log-$MOD=$HOST"; export DEFAULT
+fi
+${ECHO} "X-num: log2" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 && \
+       { ${ECHO} "-L failed to reject log request"; exit 100; }
+
+${ECHO} "X-num: log3" > "${DIR}/__tmp"
+${EZBIN}/ezmlm-manage -l "${DIR}" < "${DIR}/__tmp" >"${ERR}" 2>&1 || \
+       { ${ECHO} "-l failed for remote admin for log3"; exit 100; }
+
+
+${ECHO} "OK"
+
+##################
+# ezmlm-moderate #
+##################
+
+${ECHO} -n "ezmlm-moderate (1/2): "
+
+# MOD1 and MOD3 are defined from ezmlm-store testing
+
+REJ=`${GREP} "From: $LOC-reject" "$MOD1"| cut -d' ' -f2`
+if [ -z "$REJ" ]; then
+       ${ECHO} "No From: ...-reject header in mod request for mod1"
+       exit 100
+fi
+
+ACC=`${GREP} "Reply-To: $LOC-accept" "$MOD3"| cut -d' ' -f2`
+if [ -z "$ACC" ]; then
+       ${ECHO} "No From: ...-accept header in mod request for mod3"
+       exit 100
+fi
+
+# remove moderation request from sinkdir
+${RM} -f "$MOD1" 2>/dev/null || \
+       { ${ECHO} "failed to remove mod request for mod1"; exit 100; }
+${RM} -f "$MOD3" 2>/dev/null || \
+       { ${ECHO} "failed to remove mod request for mod3"; exit 100; }
+
+# make sure we get the (mis)accepted message(s)
+${EZBIN}/ezmlm-sub "${DIR}" "${SND}@$HOST"
+
+LOCAL=`${ECHO} "$REJ" | cut -d@ -f1`
+export LOCAL
+
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$REJLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+       </dev/null >"${ERR}" 2>&1 || \
+               { ${ECHO} "failed on rejection"; exit 100; }
+
+LOCAL=`${ECHO} "$ACC" | cut -d@ -f1`
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$ACCLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+        </dev/null >"${ERR}" 2>&1 || \
+               { ${ECHO} "failed on acceptance"; exit 100; }
+
+ls -l "${DIR}/mod/rejected/" | ${GREP} '[0-9]' >/dev/null 2>&1 || \
+       { ${ECHO} "failed to write reject stub"; exit 100; }
+ls -l "${DIR}/mod/accepted/" | ${GREP} '[0-9]' >/dev/null 2>&1 || \
+       { ${ECHO} "failed to write accept stub"; exit 100; }
+
+REJ1=`${ECHO} "$REJ" | sed s/reject/accept/`
+LOCAL=`${ECHO} "$REJ1" | cut -d@ -f1`
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$REJLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+       </dev/null >/dev/null 2>&1 && \
+       { ${ECHO} "failed to bounce accept of rejected message"; exit 100; }
+LOCAL=`${ECHO} "$REJ" | cut -d@ -f1`
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$REJLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+       </dev/null >/dev/null 2>&1 || \
+       { ${ECHO} "failed to silently ignore re-rejection"; exit 100; }
+
+ACC1=`${ECHO} "$ACC" | sed s/accept/reject/`
+LOCAL=`${ECHO} "$ACC1" | cut -d@ -f1`
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$REJLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+       </dev/null >/dev/null 2>&1 && \
+       { ${ECHO} "failed to bounce reject of accepted message"; exit 100; }
+LOCAL=`${ECHO} "$ACC" | cut -d@ -f1`
+export LOCAL
+if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$ACCLEN"-`; export DEFAULT
+fi
+${EZBIN}/ezmlm-moderate "${DIR}" "${EZBIN}/ezmlm-send ${DIR}" \
+       </dev/null >/dev/null 2>&1 || \
+       { ${ECHO} "failed to silently ignore re-acceptance"; exit 100; }
+
+${ECHO} "OK"
+
+# cleanup
+${EZBIN}/ezmlm-unsub "${DIR}" "${SND}@$HOST"
+
+##############
+# ezmlm-warn #
+##############
+${ECHO} -n "ezmlm-warn (2/3):     "
+
+${EZBIN}/ezmlm-warn -t0 "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with normal bounce for warning"; exit 100; }
+
+${EZBIN}/ezmlm-warn -d -t0 "${DIR}" >"${ERR}" 2>&1 || \
+       { ${ECHO} "failed with digest bounce for warning"; exit 100; }
+
+${ECHO} "OK"
+
+#################
+# ezmlm-request #
+#################
+
+  ${ECHO} -n "ezmlm-request (2/2):  "
+
+  ${GREP} "$LOC-qqqq-$SND=$HOST" "${REQ}" >/dev/null || \
+       { ${ECHO} "'qqqq' subject query rewriting failed"; exit 100; }
+
+  ${GREP} "$LOC-unsubscribe-$SND=$HOST" "${REQ}" >/dev/null || \
+       { ${ECHO} "ezmlm 'remove' subject query rewriting failed"; exit 100; }
+
+  ${ECHO} "OK"
+
+########################
+# waiting for delivery #
+########################
+  send_test 3
+fi             # end section 2
+
+######################################### start of section 3
+if [ "$SECT" -le "3" ]; then
+  wait_test 3
+
+###############
+# ezmlm-split #
+###############
+if [ "$QMVER" = "n" ]; then
+  ${ECHO} -n "ezmlm-split (2/2):    "
+
+# we know that ezmlm-manage works. A bounce would go to MODDIR, so a
+# message in SINKDIR means that the request was forwarded to ezmlm-manage,
+# which replied with a confirmation request.
+  ${GREP} 'X-num: spl1' $SINKDIR/new/* > /dev/null 2>&1 || \
+       { ${ECHO} "failed to receive sub conf req.";
+         ${ECHO} "this could be a failure of ezmlm-split, but usually,";
+         ${ECHO} "it happens because ezmlm binaries when run by qmail";
+         ${ECHO} "don't have access to shared libraries required for";
+         ${ECHO} "RDBMS access. This happens on systems where RDBMS";
+         ${ECHO} "shared libs are installed in the /usr/local hierarchy.";
+         ${ECHO} "fix: see ld.so man page on how to modify /etc/ld.so.conf";
+         ${ECHO} "or compile statically by adding -static to conf-sqlld.";
+         ${ECHO}
+         exit 100; }
+
+  ${ECHO} "OK"
+fi
+
+##################
+# ezmlm-moderate #
+##################
+
+  ${ECHO} -n "ezmlm-moderate (2/2): "
+
+  MOD1=`${GREP} -l "mod1" $SINKDIR/new/* | head -1` || \
+       { ${ECHO} "failed to send rejection notice for message mod1"; exit 100; }
+
+# ${SND}@$HOST means it was rejected, not send through the list
+  ${GREP} "To: ${SND}@$HOST" "$MOD1" > /dev/null 2>&1 || \
+       { ${ECHO} "failed to reject message mod1"; exit 100; }
+
+  MOD3=`${GREP} -l "mod3" $SINKDIR/new/* | head -1`
+  if [ -z "$MOD3" ]; then
+    ${ECHO} "failed to post message mod3"
+    exit 100
+  fi
+
+# ${LOC}@$HOST means it was not rejected, but sent through the list
+  ${GREP} "To: ${LOC}@$HOST" "$MOD3" > /dev/null 2>&1 || \
+       { ${ECHO} "failed to reject message mod3"; exit 100; }
+
+  ${ECHO} "OK"
+
+################
+# ezmlm-manage #
+################
+  ${ECHO} -n "ezmlm-manage (3/4):   "
+
+  SENDER="${MOD}@$HOST"; export SENDER
+  ${EZBIN}/ezmlm-issubn "${DIR}" && \
+       { ${ECHO} "unsub without mod for moderated list failed"; exit 100; }
+
+  SUB3=`${GREP} -l 'sub3' $MODDIR/new/*` || \
+       { ${ECHO} "failed getting subscribe moderation confirm request"; \
+        exit 100; }
+
+# confirm subscription request
+  LOCAL=`${GREP} "Reply-To:" "$SUB3" | cut -d' ' -f2 | cut -d'@' -f1` || \
+       { ${ECHO} "no confirm address in sub3 mod confirm request"; exit 100; }
+  export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT
+  fi
+  ${ECHO} "X-num: modR1" > "${DIR}/__tmp"
+  ${ECHO} "FROM: moderator agrees <$SENDER>" >> "${DIR}/__tmp"
+  ${ECHO} >> "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-manage ${SW_FROM} "${DIR}" < "${DIR}/__tmp"\
+               >/dev/null 2>&1 || \
+       { ${ECHO} "failed to send digest sub mod accept for sub3"; exit 100; }
+
+# complete edit. SENDER can be any address
+  SENDER="${MAN}@$HOST"; export SENDER
+  EDIT3=`${GREP} -l 'edit3' $MODDIR/new/*` || \
+       { ${ECHO} "failed getting edit reply for edit3"; \
+        exit 100; }
+  ${GREP} "#TEST_TEXT#" "$EDIT3" >/dev/null 2>&1 || \
+       { ${ECHO} "old text missing in edit3 edit reply"; exit 100; }
+  LOCAL=`${GREP} "Reply-To:" "$EDIT3" | cut -d' ' -f2 | cut -d'@' -f1` || \
+       { ${ECHO} "no reply address in edit3 edit reply"; exit 100; }
+  export LOCAL
+  if [ "$QMVER" = "n" ]; then
+       DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT
+  fi
+  ${ECHO} "X-num: edit4" > "${DIR}/__tmp"
+  ${ECHO} >> "${DIR}/__tmp"
+  ${ECHO} "%%% START OF TEXT FILE" >> "${DIR}/__tmp"
+  ${ECHO} "#NEW_TEXT#" >> "${DIR}/__tmp"
+  ${ECHO} "%%% END OF TEXT FILE" >> "${DIR}/__tmp"
+  ${EZBIN}/ezmlm-manage -e "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \
+       { ${ECHO} "failed to send edit4 reply for edit3"; exit 100; }
+
+# check results of log/list
+  LOG3=`${GREP} -l 'log3' $MODDIR/new/*` || \
+       { ${ECHO} "failed getting -log reply to log3"; \
+        exit 100; }
+  ${GREP} "aaa@bbb" "$LOG3" | ${GREP} "+m" > /dev/null 2>&1 || \
+       { ${ECHO} "failed to get log reply to log3"; exit 100; }
+
+  LIST3=`${GREP} -l 'list3' $MODDIR/new/*` || \
+       { ${ECHO} "failed getting -list reply to list3"; \
+        exit 100; }
+  ${GREP} "aaa@bbb" "$LIST3" > /dev/null 2>&1 || \
+       { ${ECHO} "failed to get list reply to list3"; exit 100; }
+
+  ${ECHO} "OK"
+
+#############
+# ezmlm-get #
+#############
+  ${ECHO} -n "ezmlm-get (2/2):      "
+
+# index1/get1/thread1 should bounce and will not be looked for
+# index2 ... should be in DIG@HOST's inbox
+# get3 - r format to DIG@HST
+# get4 - n
+# get5 - v
+# get6 - x
+
+# well - just a consistency check
+  ${GREP} "index1" ${DIGDIR}/new/* >/dev/null 2>&1 && \
+       { ${ECHO} "index1 found in wrong mailbox"; exit 100; }
+
+# now check that they've been delivered. We don't check the formats,
+# as this would be quite involved.
+  ${GREP} "index2" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "index2 failed to return"; exit 100; }
+  ${GREP} "get2" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "get2 failed to return"; exit 100; }
+  ${GREP} "get3" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "get3 format 'r' failed to return"; exit 100; }
+  ${GREP} "get4" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "get3 format 'n' failed to return"; exit 100; }
+  ${GREP} "get5" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "get3 format 'v' failed to return"; exit 100; }
+  ${GREP} "get6" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "get3 format 'x' failed to return"; exit 100; }
+
+  ${GREP} "dig1" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig1 from manager wasn't delivered"; exit 100; }
+  ${GREP} "dig2" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig2 from editor wasn't delivered"; exit 100; }
+  ${GREP} "dig3" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig3 from command line wasn't delivered"; exit 100; }
+  ${GREP} "dig4" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig4 format 'r' wasn't delivered"; exit 100; }
+  ${GREP} "dig5" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig5 format 'n' wasn't delivered"; exit 100; }
+  ${GREP} "dig6" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig6 format 'x' wasn't delivered"; exit 100; }
+  ${GREP} "dig6" ${DIGDIR}/new/* >/dev/null 2>&1 || \
+       { ${ECHO} "dig6 format 'v' wasn't delivered"; exit 100; }
+
+  ${ECHO} "OK"
+
+
+########################
+# waiting for delivery #
+########################
+  send_test 4
+fi                     # end section 3
+
+####################################### start of section 4
+if [ "$SECT" -le "4" ]; then
+  wait_test 4
+
+##############
+# ezmlm-warn #
+##############
+  ${ECHO} -n "ezmlm-warn (3/3):     "
+
+  SENDER="${BNC}@${HOST}"
+  export SENDER
+  ${EZBIN}/ezmlm-issubn -n "${DIR}" || \
+       { ${ECHO} "failed to remove bouncing subscriber"; exit 100; }
+  ${EZBIN}/ezmlm-issubn -n "${DIR}/digest" || \
+       { ${ECHO} "failed to remove bouncing digest subscriber"; exit 100; }
+
+  ${ECHO} "OK"
+
+################
+# ezmlm-manage #
+################
+  ${ECHO} -n "ezmlm-manage (4/4):   "
+
+  ${GREP} "#NEW_TEXT#" "${DIR}/text/test" >/dev/null 2>&1 || \
+       { ${ECHO} "edit4 failed to update text file"; exit 100; }
+
+  ${ECHO} "OK"
+
+fi                     # end section 4
+
+########################## start of section 9 (cleanup)
+if [ "$SECT" -eq "9" -o -z "$DEBUG" ]; then
+
+#####################
+# remove test files #
+#####################
+
+
+# cleanup the mysql sub tables so we can repeat if necessary
+# the Log test will pass due to old data once we access the mysql log,
+# rather than the file, but what the ...
+  if [ $USESQL ]; then
+       ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${MAN}@$HOST" "${DIG}@$HOST" \
+               >/dev/null 2>&1
+       ${EZBIN}/ezmlm-unsub "${DIR}/mod" "${MOD}@$HOST" \
+               >/dev/null 2>&1
+       ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "aaa@bbb" "ccc@ddd" "eee@fff" \
+               >/dev/null 2>&1
+  fi
+  ${RM} -rf "${DIR}" ${DOT}* "${ERR}" >/dev/null 2>&1
+
+fi
+${ECHO}
+if [ ! -z "${BUG}" ]; then
+  ${ECHO} "${BUG}" | ${GREP} "config" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The config bug prevents editing lists created with"
+       ${ECHO} "ezmlm-idx<0.31 or ezmlm-0.53. 'touch DIR/config' is a work-"
+       ${ECHO} "around, and upgrading to >=0.314 corrects it."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "deny" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+    if [ "$EZVER" = '31' ]; then
+       ${ECHO} "The DENY bug allows users to remove themselves"
+       ${ECHO} "from DIR/blacklist which is not intended, but OTOH,"
+       ${ECHO} "DIR/blacklist is not intended for this and as a SENDER check"
+       ${ECHO} "inherently insecure anyway. If you need this feature and the"
+       ${ECHO} "bug is a problem, upgrade to >=0.321."
+    else
+       ${ECHO} "DENY access means that subscribers can remove";
+       ${ECHO} "themselves from DIR/deny. This is a bug, but DENY"
+       ${ECHO} "is easy to circumvent and not intended to keep users from"
+       ${ECHO} "posting, anyway."
+       ${ECHO} "The bug is fixed in >=0.321."
+    fi
+    }
+  ${ECHO} "${BUG}" | ${GREP} "return" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The failure to add the ezmlm-return lines means"
+       ${ECHO} "that old lists will work correctly, but bounce handling"
+       ${ECHO} "won't work in lists created with this version."
+       ${ECHO} "The bug is fixed in >=0.321."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "tstdig" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The ezmlm-tstdig bug means that DIR/inlocal still needs to be"
+       ${ECHO} "adjusted for with digests within virtual domains."
+       ${ECHO} "The bug is fixed in >=0.321."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "digest" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The ezmlm-tstdig -digest- bug means that ezmlm-tstdig when"
+       ${ECHO} "in DIR/manager does not pass on digest subscribe request."
+       ${ECHO} "Upgrade to ezmlm-idx>=0.321 if you use ezmlm-tstdig in"
+       ${ECHO} "DIR/manager (this is NOT used except in custom or very"
+       ${ECHO} "old (ezlm-idx<0.30) digest setups)."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "_bound" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The ezmlm-send/reject mimeremove bug caused erroneous"
+       ${ECHO} "rejection of messages with text after the mime boundary in the"
+       ${ECHO} "Content-type header when DIR/mimeremove was used. This type"
+       ${ECHO} "of message is very rare (mainly Mutt with PGP MIME)."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "_noself" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The ezmlm-send -C switch 'not to sender' is no longer" 
+       ${ECHO} "supported. For backwards compatibility the switch is"
+       ${ECHO} "ignored. Instead, implement this feature in the recipients"
+       ${ECHO} "mailbox by rejecting messages from the list with the"
+       ${ECHO} "recipient's address in the From: header."
+    }
+  ${ECHO} "${BUG}" | ${GREP} "_signed" >/dev/null 2>&1 && \
+    {
+       ${ECHO}
+       ${ECHO} "The trailer is added as a separate MIME part to multipart"
+       ${ECHO} "messages, but should be suppressed not only for multipart"
+       ${ECHO} "alternative, but also for many other multipart types,"
+       ${ECHO} "including multipart/signed."
+    }
+    ${ECHO}
+fi
+
+exit 0
+
+
diff --git a/ezmlm-tstdig.1 b/ezmlm-tstdig.1
new file mode 100644 (file)
index 0000000..3bd3185
--- /dev/null
@@ -0,0 +1,112 @@
+.TH ezmlm-tstdig 1
+.SH NAME
+ezmlm-tstdig \- Tests if a digest should be created
+.SH SYNOPSIS
+.B ezmlm-tstdig
+[
+.B -k
+.I kbytes
+] [
+.B -m
+.I msg
+] [
+.B \-t
+.I time
+]
+.I dir
+
+.B ezmlm-tstdig
+reads files in the list directory
+.I dir
+and determines if any of the criteria specified by the options are met.
+If they are, or if all options specified are 0,
+.B ezmlm-tstdig
+exits with success (0). Otherwise,
+.B ezmlm-tstdig
+exits (99), or in case of errors, (100) for permanent and (111) for temporary
+errors.
+
+The normal use of
+.B ezmlm-tstdig
+is to place it in a script so that
+.B ezmlm-get(1)
+is executed if
+.B ezmlm-tstdig
+exists 0, but skipped otherwise.
+
+.B ezmlm-tstdig
+uses LOCAL to adapt its behavior so that it
+can be used from the command line, a script, or from within
+.IR dir\fB/editor ,
+or
+.IR dir\fB/manager .
+If invoked from
+.IR dir\fB/editor ,
+the
+.B ezmlm-tstdig
+line should end in '|| exit 99'.
+When used here,
+.B ezmlm-tstdig
+if digest generation criteria are met
+tests a
+timestamp in
+.IR dir\fB/tstdig .
+If
+.I dir\fB/tstdig
+is more than 1 hour old or a digest has been successfully created since
+.I dir\fB/tstdig
+was written,
+.B ezmlm-tstdig
+will set the timestamp to the current time and exit 0. Otherwise it will
+exit 99. This is to guard against initiating duplicate digests when messages
+arrive while digesting is in progress.
+.SH OPTIONS
+.TP
+.B \-k
+Success if more than
+.I kbytes
+of message body has accumulated since the latest digest.
+.TP
+.B \-m
+Success if more than
+.I msg
+messages have accumulated since the latest digest.
+.TP
+.B \-t
+Success if more than
+.I time
+hours have passed since the latest digest.
+.SH USAGE
+This is an example script for ezmlm-tstdig usage.
+
+.RS
+.nf
+#!/bin/sh
+#usage: script dir diglist@host
+#digest if > 64 kbytes message bodies,
+#          > 30 messages, or
+#          > 48 hours since last digest.
+
+# ezmlm bin path - modify for your setup
+EZPATH='/usr/local/bin/ezmlm'
+
+EZTST="${EZPATH}/ezmlm-tstdig"
+EZGET="${EZPATH}/ezmlm-get"
+${EZTST} -k64 -m30 -t48 "$1" || exit 0
+${EZGET} -t "'$2'" "'$1'" < /dev/null
+# improve by testing exit status
+.fi
+.RE
+.PP
+.SH BUGS
+Obviously,
+.B ezmlm-tstdig
+should be integrated into the digesting program so that 
+.I dir\fB/tstdig
+will not be not necessary. This may be done in the next version.
+.SH "SEE ALSO"
+ezmlm-get(1),
+ezmlm-make(1),
+ezmlm-manage(1),
+ezmlm-send(1),
+ezmlm(5)
diff --git a/ezmlm-tstdig.c b/ezmlm-tstdig.c
new file mode 100644 (file)
index 0000000..dc073ea
--- /dev/null
@@ -0,0 +1,176 @@
+/*$Id: ezmlm-tstdig.c,v 1.17 1999/03/20 16:43:42 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include "stralloc.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "sig.h"
+#include "getconf.h"
+#include "env.h"
+#include "fmt.h"
+#include "now.h"
+#include "lock.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
+
+#define FATAL "ezmlm-tstdig: fatal: "
+
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-tstdig: usage: ezmlm-tstdig [-k kbytes] [-m messages] [-t hours] dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+stralloc line = {0};
+
+substdio ssnum;
+char numbuf[16];
+
+char strnum[FMT_ULONG];
+
+int flaglocal = 0;
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+  char *dir;
+  char *local;
+  char *def;
+  int opt;
+  unsigned int pos;
+  unsigned long num, digsize, dignum;
+  unsigned long cumsize = 0L;
+  unsigned long deltanum = 0L;
+  unsigned long deltawhen = 0L;
+  unsigned long deltasize = 0L;
+  unsigned long when, tsttime, digwhen;
+  int fd,fdlock;
+
+  (void) umask(022);
+  sig_pipeignore();
+  when = (unsigned long) now();
+
+  while ((opt = getopt(argc,argv,"k:t:m:vV")) != opteof)
+    switch(opt) {
+      case 'k':
+                if (optarg)
+                  scan_ulong(optarg,&deltasize);
+                break;
+      case 't':
+                if (optarg)    /* hours */
+                  scan_ulong(optarg,&deltawhen);
+                break;
+      case 'm':
+                if (optarg)
+                  scan_ulong(optarg,&deltanum);
+                break;
+      case 'v':
+      case 'V': strerr_die2x(0,"ezmlm-tstdig version: ",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+
+
+  dir = argv[optind++];
+  if (!dir) die_usage();
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  if (argv[optind])
+    die_usage();       /* avoid common error of putting options after dir */
+  if (!getconf_line(&line,"num",0,FATAL,dir))
+    _exit(99);         /* no msgs no shirt -> no digest */
+  if(!stralloc_0(&line)) die_nomem();
+  pos = scan_ulong(line.s,&num);
+  if (line.s[pos] == ':')
+    scan_ulong(line.s+pos+1,&cumsize);
+
+  if (getconf_line(&line,"dignum",0,FATAL,dir)) {
+    if(!stralloc_0(&line)) die_nomem();
+    pos = scan_ulong(line.s,&dignum);
+    if (line.s[pos] == ':')
+      pos += 1 + scan_ulong(line.s+pos+1,&digsize);
+    if (line.s[pos] == ':')
+      scan_ulong(line.s+pos+1,&digwhen);
+  } else {
+    dignum = 0L;       /* no file, not done any digest */
+    digsize = 0L;      /* nothing digested */
+    digwhen = 0L;      /* will force a digest, but the last one was eons  */
+                       /* ago. ezmlm-get sends it out only if there are   */
+                       /* messages. This is as it should for new lists.   */
+  }
+  local = env_get("LOCAL");
+  if (local && *local) {                       /* in editor or manager */
+    def = env_get("DEFAULT");
+    if (def && *def) {                         /* qmail>=1.02 and manager */
+      if (!case_starts(def,"dig") || case_starts(def,"digest-"))
+        _exit(0);
+    } else {                           /* older qmail versions or editor */
+      if (!getconf_line(&line,"inlocal",0,FATAL,dir)) {
+       flaglocal = 1;
+      } else {
+       pos = str_len(local);
+       if (pos <= line.len) {          /* maybe qmail>=1.02 and editor */
+         flaglocal = 1;                /* editor and qmail>=1.02. No harm */
+                                       /* if we're wrong */
+       } else {                        /* older qmail */
+         if (case_diffb(local,line.len,line.s))        /* local */
+           flaglocal = 1;              /* minimal harm */
+          else if (pos < line.len +4 ||        /* in manager and non-digest */
+               !case_starts(local+line.len,"-dig"))
+           _exit(0);
+          else if (case_starts(local+line.len,"-digest-"))
+           _exit(0);
+       }
+      }
+    }
+  }
+
+  if (!deltawhen && !deltasize && !deltanum) _exit(0);
+  if ((deltawhen && ((digwhen + deltawhen * 3600L) <= when)) ||
+      (deltasize && ((digsize + (deltasize << 2)) <= cumsize)) ||
+      (deltanum && ((dignum + deltanum) <= num))) {    /* digest! */
+    if (flaglocal) {   /* avoid multiple digests. Of course, ezmlm-tstdig*/
+                       /* belongs in ezmlm-digest, but it's too late ....*/
+      fdlock = open_append("lock");
+      if (fdlock == -1)
+        strerr_die2sys(111,FATAL,ERR_OPEN_LOCK);
+      if (lock_ex(fdlock) == -1) {
+        close(fdlock);
+        strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK);
+      }
+      getconf_line(&line,"tstdig",0,dir,FATAL);
+      if (!stralloc_0(&line)) die_nomem();
+      scan_ulong(line.s,&tsttime);     /* give digest 1 h to complete */
+                                       /* nobody does digests more often */
+      if ((tsttime + 3600L < when) || (tsttime <= digwhen)) {
+        fd = open_trunc("tstdign");
+        if (fd == -1)
+          strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/","tstdign",": ");
+        substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf));
+        if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,when)) == -1)
+          strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
+        if (substdio_puts(&ssnum,"\n") == -1)
+          strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/","tstdign",": ");
+        if (substdio_flush(&ssnum) == -1)
+          strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/","tstdign",": ");
+        if (fsync(fd) == -1)
+          strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/","tstdign",": ");
+        if (close(fd) == -1)
+          strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/","tstdign",": ");
+        if (rename("tstdign","tstdig") == -1)
+          strerr_die4sys(111,FATAL,ERR_MOVE,"tstdign",": ");
+        _exit(0);
+      }
+    } else
+        _exit(0);
+  }
+  _exit(99);
+}
+
index 7223ae9..8fcfd63 100644 (file)
@@ -3,6 +3,11 @@
 ezmlm-unsub \- manually remove addresses from a mailing list
 .SH SYNOPSIS
 .B ezmlm-unsub
 ezmlm-unsub \- manually remove addresses from a mailing list
 .SH SYNOPSIS
 .B ezmlm-unsub
+[
+.B \-mMHvV
+] [
+.B \-h\fBhash
+]
 .I dir
 [
 .I box\fB@\fIdomain ...
 .I dir
 [
 .I box\fB@\fIdomain ...
@@ -14,6 +19,10 @@ removes each address
 from the mailing list stored in
 .IR dir .
 
 from the mailing list stored in
 .IR dir .
 
+If no command line argument is given,
+.B ezmlm-unsub
+will process stdin instead.
+
 If
 .I box\fB@\fIdomain
 is not on the mailing list,
 If
 .I box\fB@\fIdomain
 is not on the mailing list,
@@ -26,10 +35,46 @@ converts
 to lowercase before removing
 .I box\fB@\fIdomain
 from the mailing list.
 to lowercase before removing
 .I box\fB@\fIdomain
 from the mailing list.
+.SH "GENERAL OPTIONS"
+.TP
+.B \-v
+Display
+.B ezmlm-unsub(1)
+version information.
+.TP
+.B \-V
+Display
+.B ezmlm-unsub(1)
+version information.
+.SH "MYSQL OPTIONS"
+These option is silently ignored in the absence of mysql support.
+.TP
+.B \-h \fIhash
+With mysql support the argument is used as the hash. The argument should
+be between 1 and 99. The hash is used in
+in the distribution of addresses between sublists. As the hash is normally
+between 0 and 52, controlling the hash makes it possible to remove addresses
+that cannot be manipulated remotely. A hash of 99 is reserved for sublists,
+and a hash of 98 is reserved for ``receipt'' addresses serviced by
+.B ezmlm-receipt(1).
+.TP
+.B \-H
+(Default.)
+The address can be removed if it has a hash in the normal range (0..52).
+.TP
+.B \-m
+(Default.)
+Use SQL support if available.
+.TP
+.B \-M
+Do not use SQL support even if available.
+This option can be used to manipulate
+a normal local subscriber database even for lists with SQL support.
 .SH "SEE ALSO"
 ezmlm-list(1),
 ezmlm-manage(1),
 ezmlm-make(1),
 .SH "SEE ALSO"
 ezmlm-list(1),
 ezmlm-manage(1),
 ezmlm-make(1),
+ezmlm-receipt(1),
 ezmlm-send(1),
 ezmlm-sub(1),
 ezmlm(5)
 ezmlm-send(1),
 ezmlm-sub(1),
 ezmlm(5)
index 3f53890..89eb450 100644 (file)
@@ -1,9 +1,27 @@
 #include "strerr.h"
 #include "subscribe.h"
 #include "strerr.h"
 #include "subscribe.h"
-#include "log.h"
+#include "sgetopt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "getln.h"
+#include "scan.h"
+#include "errtxt.h"
+#include "idx.h"
 
 #define FATAL "ezmlm-unsub: fatal: "
 
 #define FATAL "ezmlm-unsub: fatal: "
-#define WARNING "ezmlm-unsub: warning: "
+
+void *psql = (void *) 0;
+
+char inbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+
+stralloc line = {0};
+
+void die_usage()
+{
+  strerr_die1x(100,
+   "ezmlm-unsub: usage: ezmlm-unsub [-h hash] [-HmMnNvV] dir box@domain ...");
+}
 
 void main(argc,argv)
 int argc;
 
 void main(argc,argv)
 int argc;
@@ -11,24 +29,69 @@ char **argv;
 {
   char *dir;
   char *addr;
 {
   char *dir;
   char *addr;
+  char *cp;
+  char ch;
+  int match;
+  int flagmysql = 1;           /* if there is mysql support, use it! */
+  int forcehash = -1;
+  int flagname = 0;
+  unsigned int u;
+  int opt;
 
 
-  dir = argv[1];
-  if (!dir)
-    strerr_die1x(100,"ezmlm-unsub: usage: ezmlm-unsub dir box@domain ...");
-  if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
-
-  argv += 2;
-  while (addr = *argv++)
-    switch(subscribe(addr,0)) {
-      case -1:
-       strerr_die1(111,FATAL,&subscribe_err);
-      case -2:
-       strerr_warn4(WARNING,"cannot unsubscribe ",addr,": ",&subscribe_err);
-       break;
-      case 1:
-       log("-manual",addr);
+  (void) umask(022);
+
+  while ((opt = getopt(argc,argv,"h:HmMnNvV")) != opteof)
+    switch(opt) {
+      case 'h': (void) scan_ulong(optarg,&u); forcehash = 0; break;
+      case 'H': forcehash = -1; break;
+      case 'm': flagmysql = 1; break;
+      case 'M': flagmysql = 0; break;
+      case 'n': flagname = 1; break;
+      case 'N': flagname = 0; break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-unsub version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
     }
 
     }
 
+  dir = argv[optind++];
+  if (!dir) die_usage();
+
+  if (dir[0] != '/')
+    strerr_die2x(100,FATAL,ERR_SLASH);
+
+  if (chdir(dir) == -1)
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+  if (forcehash == 0) forcehash = (int) u;
+
+  if (argv[optind]) {
+    while ((addr = argv[optind++]))
+      (void) subscribe(dir,addr,0,"","-manual",flagmysql,
+               forcehash,(char *) 0,FATAL);
+  } else {
+    for (;;) {
+      if (getln(&ssin,&line,&match,'\n') == -1)
+       strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+      if (!match) break;
+      if (line.len == 1 || *line.s == '#') continue;
+      line.s[line.len - 1] = '\0';
+      if (flagname) {
+       cp = line.s;
+       while ((ch = *cp)) {
+         if (ch == '\\') {
+            if (!*(++cp)) break;
+         } else if (ch == ' ' || ch == '\t' || ch == ',') break;
+         cp++;
+       }
+       if (ch)
+         *cp = '\0';
+      }
+      (void) subscribe(dir,line.s,0,"","+manual",flagmysql,
+               forcehash,(char *) 0,FATAL);
+    }
+  }
+  closesql();
   _exit(0);
 }
   _exit(0);
 }
index 06fd0b0..48048a5 100644 (file)
@@ -3,6 +3,15 @@
 ezmlm-warn \- send out bounce warnings
 .SH SYNOPSIS
 .B ezmlm-warn
 ezmlm-warn \- send out bounce warnings
 .SH SYNOPSIS
 .B ezmlm-warn
+[
+.B \-dD
+][
+.B \-t
+.I timeout
+][
+.B \-l
+.I lockout
+]
 .I dir
 .SH DESCRIPTION
 .B ezmlm-warn
 .I dir
 .SH DESCRIPTION
 .B ezmlm-warn
@@ -12,27 +21,91 @@ for the mailing list stored in
 
 .B ezmlm-warn
 scans
 
 .B ezmlm-warn
 scans
-.I dir\fB/bounce
-for bounce messages received by
-.BR ezmlm-return .
-If it sees a distribution bounce for
+.I dir\fB/bounce/d/
+for directories older than
+.I timeout
+days ago (see
+.BR \-t ).
+The directories are created by
+B ezmlm-return
+and contain bounces.
+If
+.B ezmlm-warn
+sees a distribution bounce for
 .I box\fB@\fIdomain
 .I box\fB@\fIdomain
-received more than ten days ago,
+received more than
+.I timeout
+days ago,
 it sends
 .I box\fB@\fIdomain
 a list of all the message numbers missed recently,
 and deletes the bounce.
 If it sees a warning bounce for
 .I box\fB@\fIdomain
 it sends
 .I box\fB@\fIdomain
 a list of all the message numbers missed recently,
 and deletes the bounce.
 If it sees a warning bounce for
 .I box\fB@\fIdomain
-received more than ten days ago,
+received more than
+.I timeout
+days ago,
 it sends
 .I box\fB@\fIdomain
 a probe,
 and deletes the bounce.
 
 .B ezmlm-warn
 it sends
 .I box\fB@\fIdomain
 a probe,
 and deletes the bounce.
 
 .B ezmlm-warn
+uses
+.I dir\fB/bounce/lastd
+to keep track of when it was last run. If insufficient time has
+passed (see
+.BR \-l )
+.B ezmlm-warn
+exits without further action.
+
+.B ezmlm-warn
+keeps files with the bounced message numbers in
+.IR dir\fB/bounce/h .
+Expired files are removed and
+.I dir\fB/bounce/lasth
+keeps track of the last subdirectory scanned.
+
+.B ezmlm-warn
 will not send a warning or probe to an address that is
 not currently a subscriber.
 will not send a warning or probe to an address that is
 not currently a subscriber.
+.SH OPTIONS
+.TP
+.B \-d
+process bounces for the digest list, rather than for the main list.
+Digest list bounces are stored in
+.I dir\fB/digest/bounce/
+rather than in
+.IR dir\fB/bounce/ .
+.TP
+.B \-D
+(Default.)
+Process bounces for the main list.
+.TP
+.B \-l \fIlockout
+.B ezmlm-warn
+will abort execution if it was run less than
+.I lockout
+seconds ago. The default is
+.I timeout /
+50, which with the default
+.I timeout
+is 20,000 seconds (approx. 5.6 hours). There is no reason to use this
+switch, except for testing and possibly in combination with
+.BR \-t.
+.TP
+.B \-t \fItimeout
+Bounces received more than
+.I timeout
+days ago are processed. This overrides the default of 1,000,000
+seconds (approximately 10 days)
+and may possibly be useful for very large busy lists. Also, a
+.I timeout
+of zero can be used to send a warning to all addresses for which
+a bounce has been received and a probe for all addresses for which a
+warning has bounces.
+This is useful to rapidly clear
+out bouncing addresses from a (low quality) address list.
 .SH "SEE ALSO"
 ezmlm-make(1),
 ezmlm-return(1),
 .SH "SEE ALSO"
 ezmlm-make(1),
 ezmlm-return(1),
index 3140976..7d601e3 100644 (file)
@@ -1,3 +1,5 @@
+/*$Id: ezmlm-warn.c,v 1.27 1999/08/07 20:47:26 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "direntry.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "direntry.h"
@@ -6,6 +8,7 @@
 #include "substdio.h"
 #include "stralloc.h"
 #include "slurp.h"
 #include "substdio.h"
 #include "stralloc.h"
 #include "slurp.h"
+#include "sgetopt.h"
 #include "getconf.h"
 #include "byte.h"
 #include "error.h"
 #include "getconf.h"
 #include "byte.h"
 #include "error.h"
 #include "fmt.h"
 #include "cookie.h"
 #include "qmail.h"
 #include "fmt.h"
 #include "cookie.h"
 #include "qmail.h"
+#include "errtxt.h"
+#include "mime.h"
+#include "idx.h"
+#include "subscribe.h"
 
 #define FATAL "ezmlm-warn: fatal: "
 
 #define FATAL "ezmlm-warn: fatal: "
-void die_usage() { strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn dir"); }
-void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
+void die_usage()
+{
+  strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn -dD -l secs -t days dir");
+}
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
 
 stralloc key = {0};
 stralloc outhost = {0};
 stralloc outlocal = {0};
 stralloc mailinglist = {0};
 
 stralloc key = {0};
 stralloc outhost = {0};
 stralloc outlocal = {0};
 stralloc mailinglist = {0};
+stralloc digdir = {0};
+stralloc charset = {0};
+char boundary[COOKIE];
+
+substdio ssout;
+char outbuf[16];
 
 unsigned long when;
 char *dir;
 
 unsigned long when;
 char *dir;
+char *workdir;
+int flagdig = 0;
+char flagcd = '\0';            /* default: don't use transfer encoding */
 stralloc fn = {0};
 stralloc fn = {0};
+stralloc bdname = {0};
+stralloc fnlasth = {0};
+stralloc fnlastd = {0};
+stralloc lasth = {0};
+stralloc lastd = {0};
 struct stat st;
 struct stat st;
+void *psql = (void *) 0;
 
 
-void die_read() { strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fn.s,": "); }
+void die_read() { strerr_die4sys(111,FATAL,ERR_READ,fn.s,": "); }
+
+void makedir(s)
+char *s;
+{
+  if (mkdir(s,0755) == -1)
+    if (errno != error_exist)
+      strerr_die4x(111,FATAL,ERR_CREATE,s,": ");
+}
 
 char inbuf[1024];
 substdio ssin;
 
 char inbuf[1024];
 substdio ssin;
@@ -46,6 +80,7 @@ char hash[COOKIE];
 stralloc fnhash = {0};
 stralloc quoted = {0};
 stralloc line = {0};
 stralloc fnhash = {0};
 stralloc quoted = {0};
 stralloc line = {0};
+stralloc qline = {0};
 
 struct qmail qq;
 int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
 
 struct qmail qq;
 int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
@@ -58,35 +93,29 @@ substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
 struct datetime dt;
 char date[DATE822FMT];
 
 struct datetime dt;
 char date[DATE822FMT];
 
-void copy(fn)
-char *fn;
+void code_qput(s,n)
+char *s;
+unsigned int n;
 {
 {
-  int fd;
-  int match;
-
-  fd = open_read(fn);
-  if (fd == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
-
-  substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
-  for (;;) {
-    if (getln(&sstext,&line,&match,'\n') == -1)
-      strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
-    if (!match)
-      break;
-    qmail_put(&qq,line.s,line.len);
-  }
-
-  close(fd);
+    if (!flagcd)
+      qmail_put(&qq,s,n);
+    else {
+      if (flagcd == 'B')
+        encodeB(s,n,&qline,0,FATAL);
+      else
+        encodeQ(s,n,&qline,FATAL);
+      qmail_put(&qq,qline.s,qline.len);
+    }
 }
 
 void doit(flagw)
 int flagw;
 {
 }
 
 void doit(flagw)
 int flagw;
 {
-  int i;
+  unsigned int i;
   int fd;
   int match;
   int fdhash;
   int fd;
   int match;
   int fdhash;
+  char *err;
   datetime_sec msgwhen;
 
   fd = open_read(fn.s);
   datetime_sec msgwhen;
 
   fd = open_read(fn.s);
@@ -95,29 +124,42 @@ int flagw;
 
   if (getln(&ssin,&addr,&match,'\0') == -1) die_read();
   if (!match) { close(fd); return; }
 
   if (getln(&ssin,&addr,&match,'\0') == -1) die_read();
   if (!match) { close(fd); return; }
-
-  if (!issub(addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; }
-
+  if (!issub(workdir,addr.s,(char *) 0,FATAL)) { close(fd);
+                        /*XXX*/unlink(fn.s); return; }
   cookie(hash,"",0,"",addr.s,"");
   cookie(hash,"",0,"",addr.s,"");
-  if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem();
-  if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem();
+  if (!stralloc_copys(&fnhash,workdir)) die_nomem();
+  if (!stralloc_cats(&fnhash,"/bounce/h/")) die_nomem();
+  if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
+  if (!stralloc_cats(&fnhash,"/h")) die_nomem();
+  if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
   if (!stralloc_0(&fnhash)) die_nomem();
 
   if (!stralloc_0(&fnhash)) die_nomem();
 
-  if (qmail_open(&qq) == -1)
-    strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
+  if (qmail_open(&qq, (stralloc *) 0) == -1)
+    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
 
   msgwhen = now();
   qmail_puts(&qq,"Mailing-List: ");
   qmail_put(&qq,mailinglist.s,mailinglist.len);
 
   msgwhen = now();
   qmail_puts(&qq,"Mailing-List: ");
   qmail_put(&qq,mailinglist.s,mailinglist.len);
+  if (getconf_line(&line,"listid",0,FATAL,dir)) {
+    qmail_puts(&qq,"\nList-ID: ");
+    qmail_put(&qq,line.s,line.len);
+  }
   qmail_puts(&qq,"\nDate: ");
   datetime_tai(&dt,msgwhen);
   qmail_put(&qq,date,date822fmt(date,&dt));
   qmail_puts(&qq,"\nDate: ");
   datetime_tai(&dt,msgwhen);
   qmail_put(&qq,date,date822fmt(date,&dt));
-  qmail_puts(&qq,"Message-ID: <");
-  qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) msgwhen));
-  qmail_puts(&qq,".");
-  qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid()));
-  qmail_puts(&qq,".ezmlm-warn@");
-  qmail_put(&qq,outhost.s,outhost.len);
+  if (!stralloc_copys(&line,"Message-ID: <")) die_nomem();
+  if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,(unsigned long) msgwhen)))
+               die_nomem();
+  if (!stralloc_cats(&line,".")) die_nomem();
+  if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,(unsigned long) getpid())))
+               die_nomem();
+  if (!stralloc_cats(&line,".ezmlm-warn@")) die_nomem();
+  if (!stralloc_catb(&line,outhost.s,outhost.len)) die_nomem();
+  qmail_put(&qq,line.s,line.len);
+  if (flagcd) {
+    if (!stralloc_0(&line)) die_nomem();
+    cookie(boundary,"",0,"",line.s,"");        /* universal MIME boundary */
+  }
   qmail_puts(&qq,">\nFrom: ");
   if (!quote(&quoted,&outlocal)) die_nomem();
   qmail_put(&qq,quoted.s,quoted.len);
   qmail_puts(&qq,">\nFrom: ");
   if (!quote(&quoted,&outlocal)) die_nomem();
   qmail_put(&qq,quoted.s,quoted.len);
@@ -126,34 +168,84 @@ int flagw;
   qmail_puts(&qq,"\nTo: ");
   if (!quote2(&quoted,addr.s)) die_nomem();
   qmail_put(&qq,quoted.s,quoted.len);
   qmail_puts(&qq,"\nTo: ");
   if (!quote2(&quoted,addr.s)) die_nomem();
   qmail_put(&qq,quoted.s,quoted.len);
-  qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n\n" : "\nSubject: ezmlm warning\n\n");
-
-  copy("text/top");
-  copy(flagw ? "text/bounce-probe" : "text/bounce-warn");
+  if (flagcd) {                        /* to accomodate transfer-encoding */
+    qmail_puts(&qq,"\nMIME-Version: 1.0\n");
+    qmail_puts(&qq,"Content-Type: multipart/mixed; boundary=");
+    qmail_put(&qq,boundary,COOKIE);
+  } else {
+    qmail_puts(&qq,"\nContent-type: text/plain; charset=");
+    qmail_puts(&qq,charset.s);
+  }
+  qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n" : "\nSubject: ezmlm warning\n");
+
+  if (flagcd) {                        /* first part for QP/base64 multipart msg */
+    qmail_puts(&qq,"\n\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+    qmail_puts(&qq,charset.s);
+    qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+    if (flagcd == 'Q')
+      qmail_puts(&qq,"Quoted-printable\n\n");
+    else
+      qmail_puts(&qq,"base64\n\n");
+  } else
+    qmail_puts(&qq,"\n");
+
+  copy(&qq,"text/top",flagcd,FATAL);
+  copy(&qq,flagw ? "text/bounce-probe" : "text/bounce-warn",flagcd,FATAL);
 
   if (!flagw) {
 
   if (!flagw) {
-    fdhash = open_read(fnhash.s);
-    if (fdhash == -1) {
-      if (errno != error_noent)
-        strerr_die6sys(111,FATAL,"unable to open ",dir,"/",fnhash.s,": ");
-    }
-    else {
-      copy("text/bounce-num");
-      substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf));
-      if (substdio_copy(&ssqq,&sstext) < 0)
-        strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fnhash.s,": ");
+    if (flagdig)
+      copy(&qq,"text/dig-bounce-num",flagcd,FATAL);
+    else
+      copy(&qq,"text/bounce-num",flagcd,FATAL);
+    if (!flagcd) {
+      fdhash = open_read(fnhash.s);
+      if (fdhash == -1) {
+        if (errno != error_noent)
+          strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
+      } else {
+        substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf));
+        for(;;) {
+          if (getln(&sstext,&line,&match,'\n') == -1)
+            strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
+          if (!match) break;
+          code_qput(line.s,line.len);
+        }
+      }
       close(fdhash);
       close(fdhash);
+    } else {
+      if (!stralloc_copys(&line,"")) die_nomem();      /* slurp adds! */
+      if (slurp(fnhash.s,&line,256) < 0)
+        strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
+      code_qput(line.s,line.len);
     }
   }
 
     }
   }
 
-  copy("text/bounce-bottom");
+  copy(&qq,"text/bounce-bottom",flagcd,FATAL);
+  if (flagcd) {
+    if (flagcd == 'B') {
+      encodeB("",0,&line,2,FATAL);
+      qmail_put(&qq,line.s,line.len);  /* flush */
+    }
+    qmail_puts(&qq,"\n\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n");
+  }
   if (substdio_copy(&ssqq,&ssin) < 0) die_read();
   close(fd);
 
   if (substdio_copy(&ssqq,&ssin) < 0) die_read();
   close(fd);
 
+  if (flagcd) {                                /* end multipart/mixed */
+    qmail_puts(&qq,"\n--");
+    qmail_put(&qq,boundary,COOKIE);
+    qmail_puts(&qq,"--\n");
+  }
+
   strnum[fmt_ulong(strnum,when)] = 0;
   cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W");
   if (!stralloc_copy(&line,&outlocal)) die_nomem();
   strnum[fmt_ulong(strnum,when)] = 0;
   cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W");
   if (!stralloc_copy(&line,&outlocal)) die_nomem();
-  if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-")) die_nomem();
+  if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-"))
+       die_nomem();
   if (!stralloc_cats(&line,strnum)) die_nomem();
   if (!stralloc_cats(&line,".")) die_nomem();
   if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
   if (!stralloc_cats(&line,strnum)) die_nomem();
   if (!stralloc_cats(&line,".")) die_nomem();
   if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
@@ -170,8 +262,8 @@ int flagw;
   qmail_from(&qq,line.s);
 
   qmail_to(&qq,addr.s);
   qmail_from(&qq,line.s);
 
   qmail_to(&qq,addr.s);
-  if (qmail_close(&qq) != 0)
-    strerr_die2x(111,FATAL,"temporary qmail-queue error");
+  if (*(err = qmail_close(&qq)) != '\0')
+    strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE, err + 1);
 
   strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
   strerr_warn2("ezmlm-warn: info: qp ",strnum,0);
 
   strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
   strerr_warn2("ezmlm-warn: info: qp ",strnum,0);
@@ -179,76 +271,252 @@ int flagw;
   if (!flagw) {
     if (unlink(fnhash.s) == -1)
       if (errno != error_noent)
   if (!flagw) {
     if (unlink(fnhash.s) == -1)
       if (errno != error_noent)
-        strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fnhash.s,": ");
+        strerr_die4sys(111,FATAL,ERR_DELETE,fnhash.s,": ");
   }
   if (unlink(fn.s) == -1)
   }
   if (unlink(fn.s) == -1)
-    strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": ");
+    strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
 }
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
 }
 
 void main(argc,argv)
 int argc;
 char **argv;
 {
-  DIR *bouncedir;
-  direntry *d;
+  DIR *bouncedir, *bsdir, *hdir;
+  direntry *d, *ds;
   unsigned long bouncedate;
   unsigned long bouncedate;
-  int fdlock;
-
-  umask(022);
+  unsigned long bouncetimeout = BOUNCE_TIMEOUT;
+  unsigned long lockout = 0L;
+  unsigned long ld;
+  unsigned long ddir,dfile;
+  int fdlock,fd;
+  char *err;
+  int opt;
+  char ch;
+
+  (void) umask(022);
   sig_pipeignore();
   when = (unsigned long) now();
   sig_pipeignore();
   when = (unsigned long) now();
-
-  dir = argv[1];
+  while ((opt = getopt(argc,argv,"dDl:t:vV")) != opteof)
+    switch(opt) {
+      case 'd': flagdig = 1; break;
+      case 'D': flagdig = 0; break;
+      case 'l':
+                if (optarg) {  /* lockout in seconds */
+                  (void) scan_ulong(optarg,&lockout);
+                }
+                break;
+      case 't':
+                if (optarg) {  /* bouncetimeout in days */
+                  (void) scan_ulong(optarg,&bouncetimeout);
+                  bouncetimeout *= 3600L * 24L;
+                }
+                break;
+      case 'v':
+      case 'V': strerr_die2x(0,
+               "ezmlm-warn version: ezmlm-0.53+",EZIDX_VERSION);
+      default:
+       die_usage();
+    }
+  dir = argv[optind];
   if (!dir) die_usage();
   if (!dir) die_usage();
-
   if (chdir(dir) == -1)
   if (chdir(dir) == -1)
-    strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+    strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+  if (flagdig) {
+    if (!stralloc_copys(&digdir,dir)) die_nomem();
+    if (!stralloc_cats(&digdir,"/digest")) die_nomem();
+    if (!stralloc_0(&digdir)) die_nomem();
+    workdir = digdir.s;
+  } else
+    workdir = dir;
+
+  if (!stralloc_copys(&fnlastd,workdir)) die_nomem();
+  if (!stralloc_cats(&fnlastd,"/bounce/lastd")) die_nomem();
+  if (!stralloc_0(&fnlastd)) die_nomem();
+  if (slurp(fnlastd.s,&lastd,16) == -1)                /* last time d was scanned */
+      strerr_die4sys(111,FATAL,ERR_READ,fnlastd.s,": ");
+  if (!stralloc_0(&lastd)) die_nomem();
+  (void) scan_ulong(lastd.s,&ld);
+  if (!lockout)
+    lockout = bouncetimeout / 50;              /* 5.6 h for default timeout */
+  if (ld + lockout > when && ld < when)
+    _exit(0);          /* exit silently. Second check is to prevent lockup */
+                       /* if lastd gets corrupted */
+
+  if (!stralloc_copy(&fnlasth,&fnlastd)) die_nomem();
+  fnlasth.s[fnlasth.len - 2] = 'h';            /* bad, but feels good ... */
 
   switch(slurp("key",&key,32)) {
     case -1:
 
   switch(slurp("key",&key,32)) {
     case -1:
-      strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
     case 0:
     case 0:
-      strerr_die3x(100,FATAL,dir,"/key does not exist");
+      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
   }
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
   }
   getconf_line(&outhost,"outhost",1,FATAL,dir);
   getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+  if (flagdig)
+    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
   getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
   getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+  if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+    if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+      if (charset.s[charset.len - 1] == 'B' ||
+               charset.s[charset.len - 1] == 'Q') {
+        flagcd = charset.s[charset.len - 1];
+        charset.s[charset.len - 2] = '\0';
+      }
+    }
+  } else
+    if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+  if (!stralloc_0(&charset)) die_nomem();
+
+  set_cpoutlocal(&outlocal);   /* for copy */
+  set_cpouthost(&outhost);     /* for copy */
+  ddir = when / 10000;
+  dfile = when - 10000 * ddir;
 
 
-  fdlock = open_append("lockbounce");
+  if (!stralloc_copys(&line,workdir)) die_nomem();
+  if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  fdlock = open_append(line.s);
   if (fdlock == -1)
   if (fdlock == -1)
-    strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
+    strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
   if (lock_ex(fdlock) == -1)
   if (lock_ex(fdlock) == -1)
-    strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: ");
+    strerr_die4sys(111,FATAL,ERR_OBTAIN,line.s,": ");
 
 
-  bouncedir = opendir("bounce");
+  if (!stralloc_copys(&line,workdir)) die_nomem();
+  if (!stralloc_cats(&line,"/bounce/d")) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  bouncedir = opendir(line.s);
   if (!bouncedir)
   if (!bouncedir)
-    strerr_die4sys(111,FATAL,"unable to open ",dir,"/bounce: ");
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+    else
+      _exit(0);                /* no bouncedir - no bounces! */
 
 
-  while (d = readdir(bouncedir)) {
+  while ((d = readdir(bouncedir))) {           /* dxxx/ */
     if (str_equal(d->d_name,".")) continue;
     if (str_equal(d->d_name,"..")) continue;
 
     if (str_equal(d->d_name,".")) continue;
     if (str_equal(d->d_name,"..")) continue;
 
-    if (!stralloc_copys(&fn,"bounce/")) die_nomem();
-    if (!stralloc_cats(&fn,d->d_name)) die_nomem();
-    if (!stralloc_0(&fn)) die_nomem();
-
-    if (stat(fn.s,&st) == -1) {
-      if (errno == error_noent) continue;
-      strerr_die6sys(111,FATAL,"unable to stat ",dir,"/",fn.s,": ");
+    scan_ulong(d->d_name,&bouncedate);
+       /* since we do entire dir, we do files that are not old enough. */
+       /* to not do this and accept a delay of 10000s (2.8h) of the oldest */
+       /* bounce we add to bouncedate. We don't if bouncetimeout=0 so that */
+       /* that setting still processes _all_ bounces. */
+    if (bouncetimeout) ++bouncedate;
+    if (when >= bouncedate * 10000 + bouncetimeout) {
+      if (!stralloc_copys(&bdname,workdir)) die_nomem();
+      if (!stralloc_cats(&bdname,"/bounce/d/")) die_nomem();
+      if (!stralloc_cats(&bdname,d->d_name)) die_nomem();
+      if (!stralloc_0(&bdname)) die_nomem();
+      bsdir = opendir(bdname.s);
+      if (!bsdir) {
+       if (errno != error_notdir)
+         strerr_die4sys(111,FATAL,ERR_OPEN,bdname.s,":y ");
+       else {                          /* leftover nnnnn_dmmmmm file */
+         if (unlink(bdname.s) == -1)
+           strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
+         continue;
+       }
+      }
+      while ((ds = readdir(bsdir))) {                  /* dxxxx/yyyy */
+       if (str_equal(ds->d_name,".")) continue;
+       if (str_equal(ds->d_name,"..")) continue;
+       if (!stralloc_copy(&fn,&bdname)) die_nomem();   /* '\0' at end */
+         fn.s[fn.len - 1] = '/';
+       if (!stralloc_cats(&fn,ds->d_name)) die_nomem();
+       if (!stralloc_0(&fn)) die_nomem();
+       if ((ds->d_name[0] == 'd') || (ds->d_name[0] == 'w'))
+         doit(ds->d_name[0] == 'w');
+        else                           /* other stuff is junk */
+         if (unlink(fn.s) == -1)
+           strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
+      }
+      closedir(bsdir);
+      if (rmdir(bdname.s) == -1)       /* the directory itself */
+      if (errno != error_noent)
+          strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
     }
     }
+  }
+  closedir(bouncedir);
 
 
-    if (when > st.st_mtime + 3000000)
-      if (unlink(fn.s) == -1)
-        strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": ");
-
-    if ((d->d_name[0] == 'd') || (d->d_name[0] == 'w')) {
-      scan_ulong(d->d_name + 1,&bouncedate);
-      if (when > bouncedate + 1000000)
-       doit(d->d_name[0] == 'w');
+  if (!stralloc_copy(&line,&fnlastd)) die_nomem();
+  line.s[line.len - 2] = 'D';
+  fd = open_trunc(line.s);                     /* write lastd. Do safe */
+                                               /* since we read before lock*/
+  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
+  if (substdio_put(&ssout,strnum,fmt_ulong(strnum,when)) == -1)
+    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
+  if (substdio_put(&ssout,"\n",1) == -1)       /* prettier */
+    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
+  if (substdio_flush(&ssout) == -1)
+    strerr_die4sys(111,FATAL,ERR_FLUSH,line.s,": ");
+  if (fsync(fd) == -1)
+    strerr_die4sys(111,FATAL,ERR_SYNC,line.s,": ");
+  if (close(fd) == -1)
+    strerr_die4sys(111,FATAL,ERR_CLOSE,line.s,": ");
+
+  if (rename(line.s,fnlastd.s) == -1)
+    strerr_die4sys(111,FATAL,ERR_MOVE,fnlastd.s,": ");
+
+                               /* no need to do h dir cleaning more than */
+                               /* once per 1-2 days (17-30 days for all) */
+  if (stat(fnlasth.s,&st) == -1) {
+    if (errno != error_noent)
+      strerr_die4sys(111,FATAL,ERR_STAT,fnlasth.s,": ");
+  } else if (when < st.st_mtime + 100000 && when > st.st_mtime)
+    _exit(0);                  /* 2nd comp to guard against corruption */
+
+  if (slurp(fnlasth.s,&lasth,16) == -1)                /* last h cleaned */
+      strerr_die4sys(111,FATAL,ERR_READ,fnlasth.s,": ");
+  if (!stralloc_0(&lasth)) die_nomem();
+  ch = lasth.s[0];                              /* clean h */
+  if (ch >= 'a' && ch <= 'o')
+    ++ch;
+  else
+    ch = 'a';
+  lasth.s[0] = ch;
+  if (!stralloc_copys(&line,workdir)) die_nomem();
+  if (!stralloc_cats(&line,"/bounce/h/")) die_nomem();
+  if (!stralloc_catb(&line,lasth.s,1)) die_nomem();
+  if (!stralloc_0(&line)) die_nomem();
+  hdir = opendir(line.s);              /* clean ./h/xxxxxx */
+
+  if (!hdir) {
+    if (errno != error_noent)
+    strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
+  } else {
+
+    while ((d = readdir(hdir))) {
+      if (str_equal(d->d_name,".")) continue;
+      if (str_equal(d->d_name,"..")) continue;
+      if (!stralloc_copys(&fn,line.s)) die_nomem();
+      if (!stralloc_append(&fn,"/")) die_nomem();
+      if (!stralloc_cats(&fn,d->d_name)) die_nomem();
+      if (!stralloc_0(&fn)) die_nomem();
+      if (stat(fn.s,&st) == -1) {
+       if (errno == error_noent) continue;
+       strerr_die4sys(111,FATAL,ERR_STAT,fn.s,": ");
+      }
+      if (when > st.st_mtime + 3 * bouncetimeout)
+       if (unlink(fn.s) == -1)
+          strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
     }
     }
+    closedir(hdir);
   }
 
   }
 
-  closedir(bouncedir);
-
+  fd = open_trunc(fnlasth.s);                  /* write lasth */
+  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
+  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
+  if (substdio_put(&ssout,lasth.s,1) == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
+  if (substdio_put(&ssout,"\n",1) == -1)       /* prettier */
+    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
+  if (substdio_flush(&ssout) == -1)
+    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
+  (void) close(fd);            /* no big loss. No reason to flush/sync */
+                               /* See check of ld above to guard against */
+                               /* it being corrupted and > when */
+
+  closesql();
   _exit(0);
 }
   _exit(0);
 }
index 5a5911f..4233717 100644 (file)
@@ -7,6 +7,8 @@ ezmlm-weed \- weed out useless messages
 .B ezmlm-weed
 reads a mail message from its standard input.
 If it recognizes the message as an MTA warning message or success message,
 .B ezmlm-weed
 reads a mail message from its standard input.
 If it recognizes the message as an MTA warning message or success message,
+or as a message with precedence ``bulk'' or ``junk'' as generated by
+vacation autoresponders,
 it exits 99;
 this will cause
 .B qmail-alias
 it exits 99;
 this will cause
 .B qmail-alias
@@ -33,6 +35,13 @@ Generic warning message, recommended for all MTAs:
    Subject: deferral notice
 .EE
 
    Subject: deferral notice
 .EE
 
+Delivery-status notification (DSN, rfc1891). All DSN messages with ``Action''
+other than ``failed'':
+
+.EX
+   Content-type: multipart/report
+.EE
+
 Warning message from sendmail, MIME form:
 
 .EX
 Warning message from sendmail, MIME form:
 
 .EX
@@ -104,6 +113,21 @@ Non-MIME form:
 .EX
    THIS IS A WARNING MESSAGE ONLY
 .EE
 .EX
    THIS IS A WARNING MESSAGE ONLY
 .EE
+
+Notification messages from Novell Groupwise:
+
+.EX
+  Subject: Message status - delivered
+.EE
+.br
+.EX
+  Subject: Message status - opened
+.EE
+.br
+.EX
+  Subject: Out of Office AutoReply:
+.EE
+
 .SH "SEE ALSO"
 ezmlm-return(1),
 qmail-command(8)
 .SH "SEE ALSO"
 ezmlm-return(1),
 qmail-command(8)
index 777fa03..4ec3906 100644 (file)
@@ -5,18 +5,24 @@
 #include "substdio.h"
 #include "getln.h"
 #include "strerr.h"
 #include "substdio.h"
 #include "getln.h"
 #include "strerr.h"
+#include "errtxt.h"
 
 char buf0[256];
 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
 
 #define FATAL "ezmlm-weed: fatal: "
 
 
 char buf0[256];
 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
 
 #define FATAL "ezmlm-weed: fatal: "
 
+void die_nomem()
+{
+  strerr_die2x(111,FATAL,ERR_NOMEM);
+}
+
 void get(sa)
 stralloc *sa;
 {
   int match;
   if (getln(&ss0,sa,&match,'\n') == -1)
 void get(sa)
 stralloc *sa;
 {
   int match;
   if (getln(&ss0,sa,&match,'\n') == -1)
-    strerr_die2sys(111,FATAL,"unable to read input: ");
+    strerr_die2sys(111,FATAL,ERR_READ_INPUT);
   if (!match) _exit(0);
 }
 
   if (!match) _exit(0);
 }
 
@@ -30,6 +36,9 @@ stralloc line6 = {0};
 stralloc line7 = {0};
 stralloc line8 = {0};
 
 stralloc line7 = {0};
 stralloc line8 = {0};
 
+stralloc boundary = {0};
+stralloc dsnline = {0};
+
 char warn1[] = "    **********************************************";
 char warn2[] = "    **      THIS IS A WARNING MESSAGE ONLY      **";
 char warn3[] = "    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **";
 char warn1[] = "    **********************************************";
 char warn2[] = "    **      THIS IS A WARNING MESSAGE ONLY      **";
 char warn3[] = "    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **";
@@ -40,19 +49,46 @@ int flagsw = 0;
 int flagsr = 0;
 int flagas = 0;
 int flagbw = 0;
 int flagsr = 0;
 int flagas = 0;
 int flagbw = 0;
+int flagdsn = 0;
+
+int isboundary()
+/* returns 1 if line.len contains the mime bondary, 0 otherwise */
+{
+    if (line.s[0] == '-' && line.s[1] == '-' && line.len >= boundary.len + 3)
+      if (!byte_diff(line.s + 2,boundary.len,boundary.s))      /* boundary */
+        return 1;
+    return 0;
+}
 
 void main()
 {
 
 void main()
 {
-  int match;
+  unsigned int i,j;
 
   for (;;) {
     get(&line);
     if (line.len == 1) break;
 
   for (;;) {
     get(&line);
     if (line.len == 1) break;
-
+    if (line.s[0] == ' ' || line.s[0] == '\t') {       /* continuation */
+      if (flagdsn) {
+       if (!stralloc_catb(&dsnline,line.s,line.len - 1)) die_nomem();
+       continue;
+      }
+    }
+    flagdsn = 0;
     if (stralloc_starts(&line,"Subject: success notice"))
       _exit(99);
     if (stralloc_starts(&line,"Subject: deferral notice"))
       _exit(99);
     if (stralloc_starts(&line,"Subject: success notice"))
       _exit(99);
     if (stralloc_starts(&line,"Subject: deferral notice"))
       _exit(99);
+    if (stralloc_starts(&line,"Precedence: bulk"))
+      _exit(99);
+    if (stralloc_starts(&line,"Precedence: junk"))
+      _exit(99);
+/* for Novell Groupwise */
+    if (stralloc_starts(&line,"Subject: Message status - delivered"))
+      _exit(99);
+    if (stralloc_starts(&line,"Subject: Message status - opened"))
+      _exit(99);
+    if (stralloc_starts(&line,"Subject: Out of Office AutoReply:"))
+      _exit(99);
 
     if (stralloc_starts(&line,"From: Mail Delivery Subsystem <MAILER-DAEMON@"))
       flagmds = 1;
 
     if (stralloc_starts(&line,"From: Mail Delivery Subsystem <MAILER-DAEMON@"))
       flagmds = 1;
@@ -62,6 +98,71 @@ void main()
       flagsr = 1;
     if (stralloc_starts(&line,"Auto-Submitted: auto-generated (warning"))
       flagas = 1;
       flagsr = 1;
     if (stralloc_starts(&line,"Auto-Submitted: auto-generated (warning"))
       flagas = 1;
+    if (case_startb(line.s,line.len,"Content-type: multipart/report"))
+      if (!stralloc_copyb(&dsnline,line.s,line.len - 1)) die_nomem();
+      flagdsn = 1;
+  }                    /* end of header */
+
+  if (flagdsn) {       /* always only one recipient/action */
+    flagdsn = 0;       /* will be set for correct report type */
+    for (i=0; i < dsnline.len; i += 1+byte_chr(dsnline.s+i,dsnline.len-i,';')) {
+      while (dsnline.s[i] == ' ' || dsnline.s[i] == '\t')
+       if (++i >= dsnline.len) break;
+      if (case_startb(dsnline.s + i,dsnline.len - i,"report-type=")) {
+       i += 12;
+       while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t' || dsnline.s[i] =='"')
+         if (++i >= dsnline.len) break;
+       if (case_startb(dsnline.s + i,dsnline.len - i,"delivery-status"))
+         flagdsn = 1;
+      } else if (case_startb(dsnline.s + i,dsnline.len - i,"boundary=")) {
+       i += 9;
+       while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t')
+         if (++i >= dsnline.len) break;
+       if (dsnline.s[i] == '"') {
+         if (++i >= dsnline.len) break;
+         j = i + byte_chr(dsnline.s + i,dsnline.len - i,'"');
+         if (j >= dsnline.len) break;
+       } else {
+         j = i;
+         while (dsnline.s[j] !=' ' && dsnline.s[j] !='\t' &&
+               dsnline.s[j] !=';')
+           if (++j >= dsnline.len) break;
+       }                               /* got boundary */
+       if (!stralloc_copyb(&boundary,dsnline.s+i,j-i)) die_nomem();
+      }
+    }
+  }
+  if (flagdsn && boundary.len) {       /* parse DSN message */
+    get(&line);                        /* if bad format we exit(0) via get() */
+    for (;;) {
+      if (isboundary()) {
+      if (line.len == boundary.len + 5 && line.s[line.len - 1] == '-'
+               && line.s[line.len - 2] == '-')
+        _exit(99);                     /* end: not failure report */
+        get(&line);                    /* Content-type */
+        if (case_startb(line.s,line.len,"content-type:")) {
+         i = 13;
+         while (line.s[i] == ' ' || line.s[i] == '\t')
+               if (++i >= line.len) break;
+         if (case_startb(line.s+i,line.len-i,"message/delivery-status")) {
+           for (;;) {
+             get(&line);
+             if (isboundary()) break;
+             if (case_startb(line.s,line.len,"action:")) {
+               i = 8;
+               while (line.s[i] == ' ' || line.s[i] == '\t')
+                 if (++i >= line.len) break;
+               if (case_startb(line.s + i, line.len - i,"failed"))
+                 _exit(0);     /* failure notice */
+               else
+                 _exit(99);    /* there shouldn't be more than 1 action */
+             }
+            }
+         }
+        }
+      } else
+       get(&line);
+    }
   }
 
   get(&line1);
   }
 
   get(&line1);
diff --git a/ezmlm.5 b/ezmlm.5
index 2866b91..6ac1cc6 100644 (file)
--- a/ezmlm.5
+++ b/ezmlm.5
@@ -21,7 +21,60 @@ manipulate the subscriber list stored under
 handles administrative requests automatically;
 .B ezmlm-send
 sends a message to all subscribers listed in
 handles administrative requests automatically;
 .B ezmlm-send
 sends a message to all subscribers listed in
-.IR dir .
+.I dir
+and also maintains a message archive and message subject index if the list
+is configured to do so.
+.B ezmlm-reject
+rejects messages that have an empty subject, or a subject consisting of
+only a command word;
+.B ezmlm-return
+handles bounces;
+.B ezmlm-warn
+warns users for which messages bounce and eventually removes them from
+the subscriber list.
+.B ezmlm-idx
+can create a subject index from an existing list archive.
+.B ezmlm-get
+manages message, index, and thread retrieval from the archive, as well
+as the generation of message digests;
+.B ezmlm-cron
+provides a restricted interface to cron for the generation of
+digest generation trigger messages;
+.B ezmlm-store
+queues messages of moderated lists and sends a moderation request to
+the moderator(s);
+.B ezmlm-moderate
+processes moderation requests to accept the queued message to the list
+via
+.B ezmlm-send,
+or to return the message to the sender;
+.B ezmlm-clean
+cleans up the moderation queue and returns to the sender
+any messages that have timed-out;
+.B ezmlm-gate
+posts messages that come from a SENDER in an address database, and sends
+remaining messages out for moderation;
+.B ezmlm-check
+is used to diagnose problems with ezmlm mailing list configuration;
+.B ezmlm-issub
+and
+.B ezmlm-issubn
+determine if a SENDER is a subscriber or a member of a
+collection of addresses;
+.B ezmlm-tstdig
+determines if it is time to create a new digest based on the number and
+volume of messages and the amount of time that has passed since the last
+digest was issued;
+.B ezmlm-request
+can be used to answer
+.B ezmlm
+commands in the subject line easing migration from other mailing list
+managers. It can also function as a global interface mimicking
+the interface of other mailing list manager.
+.B ezmlm-glmake
+can set up the global interface, and
+.B ezmlm-glconf
+can create a configuration file for the global interface from your lists.
 .SH SUBSCRIBERS
 .I dir\fB/subscribers
 is a directory containing the subscriber list.
 .SH SUBSCRIBERS
 .I dir\fB/subscribers
 is a directory containing the subscriber list.
@@ -69,12 +122,19 @@ is a directory containing messages previously sent to subscribers.
 .B ezmlm-send
 archives all new messages if
 .I dir\fB/archived
 .B ezmlm-send
 archives all new messages if
 .I dir\fB/archived
-exists.
+exists. If
+.I dir\fB/indexed
+exists,
+.B ezmlm-send
+also maintains a message subject and author index.
 
 Messages sent to the mailing list are numbered from 1 upwards,
 whether or not they are archived.
 .I dir\fB/num
 
 Messages sent to the mailing list are numbered from 1 upwards,
 whether or not they are archived.
 .I dir\fB/num
-is the number of messages sent so far.
+is the number of messages sent so far followed by ':', followed by the
+cumulative amount of message body that has passed
+.B ezmlm-send
+stored as kbytes * 4 (4 corresponds to 1kb).
 
 .I dir\fB/archive
 has subdirectories,
 
 .I dir\fB/archive
 has subdirectories,
@@ -83,11 +143,43 @@ Message number 100m+n, with n between 0 and 99, is stored in
 .IR dir\fB/archive/\fIm\fB/\fIn .
 For example, message number 15307 is stored in
 .IR dir\fB/archive/153/07 .
 .IR dir\fB/archive/\fIm\fB/\fIn .
 For example, message number 15307 is stored in
 .IR dir\fB/archive/153/07 .
+The message index is stored in the file
+.B index
+in the same subdirectory of
+.I dir\fB/archive
+holding the corresponding messages.
+Thus, the subject index contains up to 100 entries.
+
+The subject index contains message subjects that are normalized so that
+the original message and all replies have the same entry. The subject index
+is used for advanced message retrieval functions. For safety, the subject
+index is created under a temporary name
+inside
+.I dir\fB/archive
+and then moved into place.
 
 .B ezmlm-manage
 will ignore message files without the owner-execute bit set.
 .B ezmlm-send
 turns on the owner-execute bit after safely writing the message to disk.
 
 .B ezmlm-manage
 will ignore message files without the owner-execute bit set.
 .B ezmlm-send
 turns on the owner-execute bit after safely writing the message to disk.
+
+.B ezmlm-make
+by default adds
+.B ezmlm-get
+to
+.I dir\fB/manager
+to handle 
+.I \-get, \-index,
+and
+.I \-thread
+requests. If
+.B ezmlm-make
+is invoked with a 
+.I digcode
+command line argument, digest creation
+is enabled by putting this argument on the
+.B ezmlm-get
+command line.
 .SH BOUNCES
 .I dir\fB/bounce
 is a directory containing bounce messages.
 .SH BOUNCES
 .I dir\fB/bounce
 is a directory containing bounce messages.
@@ -127,9 +219,10 @@ handles incoming bounce messages.
 sets up
 .I dir\fB/bouncer
 to invoke
 sets up
 .I dir\fB/bouncer
 to invoke
-.B ezmlm-return
-and then
-.BR ezmlm-warn .
+.BR ezmlm-return .
+.B ezmlm-warn
+is no longer invoked here due to the load it places on systems with many
+large lists with many bounces.
 
 .I dir\fB/manager
 handles incoming administrative requests.
 
 .I dir\fB/manager
 handles incoming administrative requests.
@@ -137,9 +230,266 @@ handles incoming administrative requests.
 sets up
 .I dir\fB/manager
 to invoke
 sets up
 .I dir\fB/manager
 to invoke
-.B ezmlm-manage
+.BR ezmlm-get ,
+.BR ezmlm-manage ,
 and then
 .BR ezmlm-warn .
 and then
 .BR ezmlm-warn .
+
+.I dir\fB/moderator
+handles incoming message
+.I accept
+and
+.I reject
+requests for moderated lists.
+.B ezmlm-make
+sets up
+.I dir\fB/moderator
+to invoke
+.BR ezmlm-moderate ,
+and .BR ezmlm-clean .
+.SH DIGESTS
+.B ezmlm-get
+can create digests if it is invoked from the command line, from
+.IR dir\fB/editor ,
+or from
+.IR dir\fB/manager .
+The program functions in slightly different ways in these 3 settings (see
+.BR ezmlm-get(1) ).
+
+To enable automatic digests for a mailing list, use the
+.B ezmlm-make \-d
+switch. To also enable the generation of digests at specific times dictated
+by mailed trigger messages, a
+.I digcode
+should be specified on the
+.B ezmlm-get
+command line.
+This can be done by specifying
+.I digcode
+as a fifth argument to
+.B ezmlm-make
+when setting up the list.
+.I digcode
+must be alphanumeric and is case-insensitive.
+
+To generate trigger messages, use
+.B ezmlm-cron(1)
+as an interface to
+.B crond(8)
+or use
+.B crond
+directly.
+
+.I dir\fB/num
+contains the number of the last message processed, followed by ':' and a
+number that is increased by 1 for each 256 bytes of message body text
+processed. The latter number is used by
+.B ezmlm-tstdig
+to determine if a new digest is due.
+
+.I dir\fB/dignum
+contains the contents of
+.I dir\fB/num
+at the time of the last regular digest creation, followed by a ':',
+followed by a timestamp.
+It is updated after each regular digest is sent.
+
+.I dir\fB/digissue
+contains the issue number of the last regular digest. It is incremented
+for each regular digest sent.
+
+The following user crontab entry (all on one line)
+generates a digest of the list
+.I list@host.domain
+at 1600 every day:
+
+.EX
+  00 16 * * * /var/qmail/bin/qmail-inject list-dig.digcode
+.EE
+
+Alternatively,
+.B ezmlm-cron
+can be used:
+
+.EX
+  % ezmlm-cron -t 16:00 list@host digcode
+.EE
+
+.B ezmlm-get
+can also be run from the shell: To generate a digest to
+.I list-digest@host
+from the list housed in
+.IR ~joe/list :
+
+.EX
+  % ezmlm-get ~joe/list
+.EE
+
+Like other
+.B ezmlm-get
+replies, digest can be sent in several formats. See
+.B ezmlm-get(1)
+for more info.
+.SH MODERATION
+There are three aspects of moderation: moderation of posts, moderation
+of subscriptions, and "remote administration", i.e. giving the
+moderator the right to (un)subscribe any user.
+.B ezmlm
+handles these three aspects separately. The two first aspects enhance
+security, while the third decreases security, but makes list administration
+considerably easier. By default, the moderator database is the same for all
+three functions. While "remote administration" and subscription moderation
+always use the same database, the moderators for message moderation can
+be different.
+
+Even with subscription moderation, the user has to verify the request. This
+is to ensure that the user initiating the request really controls the address.
+.B ezmlm-manage
+options exist to disable the user handshake, which may be useful in some
+circumstances.
+
+For moderation options, the moderators are by stored in a subscriber
+list in
+.IR moddir\fB/subscribers .
+By default
+.I moddir
+is
+.IR dir\fB/mod .
+
+Moderators can be added and removed with:
+
+.EX
+.B ezmlm-sub
+.I moddir
+.I moderator@host
+.EE
+
+.EX
+.B ezmlm-unsub
+.I moddir
+.I moderator@host
+.EE
+
+For subscription moderation, touch
+.IR dir\fB/modsub
+after adding moderator(s).
+For remote administration, touch
+.IR dir\fB/remote .
+If the contents of these files start with a leading forward slash, it is 
+assumed to be the name of
+.B moddir
+subscription
+moderation. If both files exist and start with a forward slash, the
+.I dir\fB/remote
+contents are ignored. Moderators are stored in a subscriber list in the
+.B subscribers
+subdirectory of
+.BR moddir .
+If no directory names are specified,
+the default,
+.IR dir\fB/mod ,
+is used.
+In all cases, the
+.I subscribers
+subdirectory of the base directory must exists/be created.
+
+Moderation of messages is achieved by
+creating
+.I dir\fB/modpost
+and  modifying
+.IR dir\fB/editor
+to invoke
+.B ezmlm-store.
+.B ezmlm-store
+stores the message in
+.IR dir\fB/mod/pending
+and sends a moderation request to all moderators stored in
+.IR moddir .
+
+If
+.I dir\fB/modpost
+does not exist,
+.B ezmlm-store
+posts messages directly, and
+.B ezmlm-clean
+does nothing.
+
+If
+.I dir\fB/modpost
+contains a directory name starting with a forward slash,
+this directory is used as
+.I moddir
+for message moderation.
+Moderators are stored in a subscriber list in the
+.I subscribers
+subdirectory of
+.IR moddir .
+If no directory names are specified,
+the default,
+.IR dir\fB/mod ,
+is used.
+
+.IR dir\fB/moderator
+is linked to
+.IR dot\fB\-accept-default
+and
+.IR dot\fB\-reject-default .
+It handles replies from the moderators.
+
+In addition to a moderator list, the directories
+.IR dir\fB/mod/pending ,
+.IR dir\fB/mod/accepted ,
+and
+.IR dir\fB/mod/rejected
+must exist. These directories contain the message moderation queue.
+
+If
+.IR dir\fB/mod/modtime
+it determines the minimal time in hours that messages wait in the moderation
+queue, before they are returned to sender with the message in
+.IR dir\fB/text/mod-timeout .
+
+If a
+.I \-help
+command is send for a moderator and
+.IR dir\fB/modsub
+or
+.IR dir\fB/remote
+exist, a more detailed help message stored in
+.I dir\fB/text/mod-help
+will be sent together with the regular help. This text should not contain
+secrets.
+If
+.I dir\fB/text/mod-help
+does not exist,
+.I dir\fB/text/help
+will be sent.
+
+If a
+.I \-list
+command is sent for a moderator and
+.IR dir\fB/modsub
+or
+.IR dir\fB/remote
+exist, and the
+.B ezmlm-manage \-l
+command line switch is specified, a subscriber list will be returned.
+
+If an
+.I \-edit.file
+command is sent for a moderator and
+.IR dir\fB/remote
+exist, and the
+.B ezmlm-manage \-d
+command line switch is specified,
+.B text\fB/file
+is returned together with an
+.B ezmlm
+cookie. The remote administrator may return an edited version of the
+file, which will be stored, provided that the cookie is valid.
+See
+.B ezmlm-manage(1)
+for more info.
 .SH TEXT
 .I dir\fB/text
 is a directory
 .SH TEXT
 .I dir\fB/text
 is a directory
@@ -187,6 +537,27 @@ Rejecting a bad unsubscription confirmation number.
 .B get-bad
 Rejecting a bad archive retrieval request.
 .TP
 .B get-bad
 Rejecting a bad archive retrieval request.
 .TP
+.B digest
+Text copied into the
+.I Administrativia
+section of the digest. Usually, this will contain subscription info
+for the digest, as well as information on how to post to the list.
+.TP
+.B trailer
+If this files exists, it is copied to the end of all messages to the list.
+.TP
+.B faq
+Sent in response to the
+.I faq
+command. Usually contains frequently asked questions and answers specific
+for the mailing list.
+.TP
+.B info
+Sent in response to the
+.I info
+command. Usually contains a descripition, policy, etc, for the list. The
+first line should in itself be a very brief description of the list.
+.TP
 .B bounce-warn
 Pointing out that messages have bounced.
 .TP
 .B bounce-warn
 Pointing out that messages have bounced.
 .TP
@@ -198,9 +569,96 @@ Explaining that
 .B ezmlm-return
 has kept a list of bounced message numbers.
 .TP
 .B ezmlm-return
 has kept a list of bounced message numbers.
 .TP
+.B dig-bounce-num
+Explaining that digest messages have bounced. All other text files are used
+for both the main list and the digest list.
+.TP
 .B bounce-bottom
 Separating the bounce message.
 .B bounce-bottom
 Separating the bounce message.
+.TP
+.B mod-help
+is set to list moderators issuing a
+.I \-help
+command. It contains instructions for moderators, but it is relatively
+trivial for a non-moderator to read it. Don't put secrets here.
+.TP
+.B mod-reject
+is the returned to the sender of a rejected post.
+.TP
+.B mod-timeout
+is returned if the message timed-out without moderator action.
+.TP
+.B mod-sub
+is added to the text confirming subscription and unsubscription
+instead of
+.B bottom
+and the requesting message, for actions that were approved
+by a moderator. Not copying the requesting message
+hides the moderator identity
+from the subscriber.
+.TP
+.B mod-request
+is the text sent to the moderators to request moderator action on
+a posted message.
+.TP
+.B mod-unsub-confirm
+Requesting that the moderator confirm a request to subscribe.
+If this file does not exist,
+.B sub-confirm
+will be used.
+.TP
+.B mod-unsub-confirm
+Requesting that the moderator confirm a request to unsubscribe.
+If this file does not exist,
+.B unsub-confirm
+will be used.
+.TP
+.B edit-do
+Instructions sent to the remote administrator together with a copy
+of a
+.I dir\fB/text
+file and editing instructions.
+.TP
+.B edit-list
+A list of editable files in
+.I dir\fB/text
+with a one-line description send to a remote administrator in response to a
+.I -edit
+command.
+.TP
+.B edit-done
+Sent to the remote administrator after an edited
+.I dir\fB/text
+file has been successfully saved.
 .PP
 .PP
+Several tags in the text files are replaced by ezmlm programs.
+All programs replace the tag
+.B <#l#>
+with the name of the list or the list-digest, as appropriate for the request,
+and
+.B <#h#>
+with the hostname for the list.
+.B ezmlm-send
+and
+.B ezmlm-get
+replace
+.B <#n#>
+with the current message number in added headers from
+.I dir\fB/headeradd
+and text files.
+.B ezmlm-get
+does this for digest messages, where the current message is the number of
+the first message in the digest.
+.B ezmlm-manage
+replaces the tag
+.B <#A#>
+anywhere on a line with the subscription address, and
+.B <#R#>
+anywhere on a line
+with the address the subscriber must reply to. Only the first tag on any
+line is processed.
+.PP
+For backwards compatibility,
 .B ezmlm-manage
 replaces the line
 .B !A
 .B ezmlm-manage
 replaces the line
 .B !A
@@ -213,6 +671,23 @@ in
 and
 .B unsub-confirm
 with the address that the subscriber must reply to.
 and
 .B unsub-confirm
 with the address that the subscriber must reply to.
+.PP
+.B ezmlm-store
+replaces the tag
+.B <#A#>
+anywhere on a line with the address for accepting the message, and
+.B <#R#>
+anywhere on a line
+with the address for rejecting the message.
+Only the first tag on any line is processed.
+.PP
+For backwards compatibility,
+.B ezmlm-store
+also replaces the line
+.B !A
+with the address for accepting the message and the line
+.B !R
+with the address for rejecting the message.
 .SH "OUTGOING MESSAGE EDITING"
 .I dir\fB/headerremove
 is a list of bad header field names,
 .SH "OUTGOING MESSAGE EDITING"
 .I dir\fB/headerremove
 is a list of bad header field names,
@@ -233,10 +708,61 @@ fields.
 is a list of new header fields.
 .B ezmlm-send
 adds these fields to every outgoing message.
 is a list of new header fields.
 .B ezmlm-send
 adds these fields to every outgoing message.
-.B ezmlm-make
+.B ezmlm-send
 sets up
 .I dir\fB/headeradd
 sets up
 .I dir\fB/headeradd
-with no new fields.
+to add
+.B X-No-Archive: yes
+and
+.BR Precedence: bulk .
+
+If
+.I dir\fB/mimeremove
+exists,
+.B ezmlm-send
+removed parts with the corresponding content-types from composite MIME
+messages. If the
+.B ezmlm-reject
+.I dir
+argument is specified,
+simple MIME messages of these content-types are rejected.
+
+If
+.I dir\fB/mimereject
+exists, and the
+.B ezmlm-reject
+.I dir
+argument is specified,
+simple MIME messages of these content-types, or
+composite MIME messages with any body part of these content-types are rejected.
+
+If
+.I dir\fB/sequence
+exists, the first line is added as a header to all outgoing messages, followed
+by a space and the message number. The message number is useful for archive
+retrievals, since some mail systems do not reveal the return-path to the user.
+.B NOTE:
+Sublists have their own message counter. Adding a sequence header from a
+sublists will give you the sublist message number which is different from
+the main list message number.
+
+.I dir\fB/prefix
+is a subject prefix. If this file exists, its contents are prefixed to the
+subject of the post in the outgoing message. The archived message is not
+processed. Attempts are made to not duplicate an existing prefix in replies.
+Think twice before using this option.
+A prefix takes unnecessary space on the subject line and most mail clients
+can easily filter on other headers, such as 'Mailing-List:'. If
+.I dir\fB/prefix contains a single '#', this will be replaced by the message
+number. The use of this feature is inadvisable and violates internet mail
+standards. However, it is very popular in e.g. Japan. If you must use this
+feature, make sure you are aware that you may be causing problems to users,
+sublists, etc.
+
+.I dir\fB/text/trailer
+is a message trailer. If this file exists, it's contents are copied to the 
+end of outgoing messages. Only lines terminated with new-line are copied.
+No trailer is copied to the archived version of the message.
 .SH MISCELLANY
 The first line of
 .I dir\fB/mailinglist
 .SH MISCELLANY
 The first line of
 .I dir\fB/mailinglist
@@ -248,6 +774,27 @@ field, showing the contents of
 .IR dir\fB/mailinglist ,
 in every outgoing message.
 
 .IR dir\fB/mailinglist ,
 in every outgoing message.
 
+If
+.I dir\fB/listid
+exists,
+ezmlm programs create a new
+.B List-ID
+field, showing the contents of the first line of
+.IR dir\fB/listid ,
+in every outgoing message. The list-id should be unique and within name
+space controlled by the owner. It should remain constant even if lists
+move and be of the format
+
+.EX
+List-ID: optional_text <unique_id.domain>
+.EE
+
+This header would result from a
+.I dir\fB/listid
+file containing ``optional_text <unique_id.domain>''. See
+.I http://www.within.com/~chandhok/ietf/listid.shtml
+for more info.
+
 The first lines of
 .I dir\fB/outlocal
 and
 The first lines of
 .I dir\fB/outlocal
 and
@@ -292,6 +839,44 @@ is the name of the parent list.
 This affects the behavior of
 .BR ezmlm-send .
 
 This affects the behavior of
 .BR ezmlm-send .
 
+If
+.I dir\fB/qmqpservers
+exists,
+.B ezmlm-send
+and
+.B ezmlm-get
+will use
+.B qmail-qmqpc(1)
+to send posts and digests. Other mail will use the normal qmail mechanism.
+If
+.B qmail-qmqpc
+is modified correctly, server IP addresses listed one per line in
+.I dir\fB/qmqpsevers
+will be tried in order, rather than the default servers specified in
+.IR /var/qmail/control .
+
+If
+.I dir\fB/msgsize
+exists, it is assumed to contain ``max:min'', where ``max'' is the maximum
+size in bytes of an acceptable message body, and ``min'' the corresponding
+minimal size. Either will be ignored if zero or omitted. If the
+.B ezmlm-reject
+command line specifies the list directory, messages not meeting the size
+criteria are rejected.
+
+If
+.I dir\fB/charset
+exists, the first line is assumed to represent a valid MIME character set,
+which is used for all outgoing MIME messages sent by
+.B ezmlm-get 
+and the message moderation programs. The character set string may be suffixed
+with ':' and 'Q' or 'B' to send all outgoing
+text (ezmlm messages, digest table-of-contents, moderation requests, etc)
+encoded in ``Quoted-Printable'' or ``base64'' encoding. By default, no encoding
+is done, which may result in the transmission of characters with the high
+bit set. When encoding is specified, trigger messages and other parts of the
+reply that should not be encoded are sent as separate MIME parts.
+
 .I dir\fB/lock
 is an empty file.
 Any program that reads or writes the subscriber list,
 .I dir\fB/lock
 is an empty file.
 Any program that reads or writes the subscriber list,
@@ -304,14 +889,54 @@ is an advisory log of subscription and unsubscription actions.
 .B WARNING:
 .B Log
 is not protected against system crashes.
 .B WARNING:
 .B Log
 is not protected against system crashes.
-Log entries may be missing or corrupted if the system goes down.
+Log entries may be missing or corrupted if the system goes down. There is
+Log for each of the accessory address databases as well. Thus, the log
+for digest subscribers is
+.IR dir\fB/digest/Log .
+If enabled, these logs can be retrieved by remote administrators (see
+.BR ezmlm-manage(1) ).
+
+.I dir\fB/digest
+contains items specific for the digest list.
+
+.I dir\fB/digest/subscribers
+contains hash files of digest subscriber addresses.
+
+.IR dir\fB/digest/Log ,
+.IR dir\fB/digest/bounce ,
+.IR dir\fB/digest/lockbounce ,
+and
+.I dir\fB/digest/lock
+have functions for the digest list that mirror that of the corresponding
+files in
+.IR dir .
+
+.I dir\fB/sql
+contains SQL server access information for list that are configured to
+use an SQL database for storage.
+
+.I dir\fB/tstdig
+is a timestamp used temporarily by
+.B ezmlm-tstdig(1)
+to coordinate digesting.
 .SH "SEE ALSO"
 .SH "SEE ALSO"
+ezmlm-check(1),
+ezmlm-clean(1),
+ezmlm-gate(1),
+ezmlm-get(1),
+ezmlm-idx(1),
+ezmlm-issub(1),
+ezmlm-issubn(1),
 ezmlm-list(1),
 ezmlm-make(1),
 ezmlm-manage(1),
 ezmlm-list(1),
 ezmlm-make(1),
 ezmlm-manage(1),
+ezmlm-moderate(1),
+ezmlm-request(1),
 ezmlm-return(1),
 ezmlm-send(1),
 ezmlm-return(1),
 ezmlm-send(1),
+ezmlm-store(1),
 ezmlm-sub(1),
 ezmlm-sub(1),
+ezmlm-tstdig(1),
 ezmlm-unsub(1),
 ezmlm-warn(1),
 dot-qmail(5)
 ezmlm-unsub(1),
 ezmlm-warn(1),
 dot-qmail(5)
diff --git a/ezmlmglrc b/ezmlmglrc
new file mode 100644 (file)
index 0000000..54e3809
--- /dev/null
+++ b/ezmlmglrc
@@ -0,0 +1,97 @@
+# ezmlmglrc file to set up a global "majordomo"-like interface.
+# You also need to create DIR/config.cf, for instance with ezmlm-glconf
+#
+# Usage: ezmlm-make -Cezmlmglrc [-5 owner] dir dot local host
+#
+# dir   - base directory
+# dot   - qmail file. Usually, ~alias/.qmail-majordomo or such.
+# local - local address, e.g. "majordomo"
+# host  - host
+#
+# 
+# These work just like for standard ezmlm-make
+#
+# directories
+</+text/>
+# links - the second for complete command addresses like
+# majordomo-which-me=myhost, as well as for our own bounces
+</:/ezdomo/>
+</:-default/ezdomo/>
+</ezdomo/>
+|<#B#>/ezmlm-request -f ezdomo.cf '<#D#>'
+# standard stuff
+</inlocal/>
+<#L#>
+</outlocal/>
+<#L#>
+</outhost/>
+<#H#>
+# List owner mail
+</:-owner/owner/>
+</owner#5/>
+&<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</headerremove/>
+return-path
+return-receipt-to
+content-length
+# texts
+</text/bottom/>
+
+--- Administrative commands ---
+
+Administrative functions of ezmlm mailing lists are done by
+sending a message to the lists COMMAND address.
+
+Please do not send the requests to the list address. If you do,
+ezmlm will not see them and other subscribers will be annoyed.
+
+To subscribe to any list "listname@hostname" send a message to:
+   <listname-subscribe@hostname>
+
+To get a complete list of commands for the same list, mail to:
+   <listname-help@hostname>
+
+--- Enclosed is a copy of the request I received.
+
+</text/help/>
+ezmlm mailing lists have an address for each command (see below).
+
+I work at this address to make it easier for users used to other
+mailing list managers to use ezmlm lists. I do this by reading the
+first line of your message and doing my best to translate it into
+a command message to the correct list. Usually, it is more efficient
+for you to talk to the list directly.
+
+In general, I accept and translate commands of the form:
+
+command [listname] [username]
+
+for instance:
+
+subscribe listname
+
+I also directly reply to:
+
+lists [username]
+which [username]
+
+If username is omitted, your address will be used and the
+reply will be sent to your address.
+
+If listname does not contain a host name, I will look into my
+list and try to add the correct host name. If I can't find it,
+I will add the name of this computer. If listname contains a host
+name, it must match a listname on my list. If not, I will
+replace the host name with the name of this computer.
+
+</text/top/>
+Hi! This is the ezmlm program. I'm managing the
+<#L#>@<#H#> address to guide
+your request to the appropriate ezmlm mailing list.
+
+</ezdomo/>
+|<#B#>/ezmlm-request -f '<#D#>/config.cf' '<#D#>'
+# that's all folks!
+
diff --git a/ezmlmglrc.5 b/ezmlmglrc.5
new file mode 100644 (file)
index 0000000..a57dafc
--- /dev/null
@@ -0,0 +1,71 @@
+.TH ezmlmglrc 5
+.SH NAME
+ezmlmglrc \- set up the global ezmlm interface
+.SH SYNOPSIS
+.B ezmlm-make
+.B \-C ezmlmglrc
+[
+.B \-5\fI owner
+]
+.I dir dot local host
+.SH DESCRIPTION
+.B ezmlmglrc
+instructs
+.B ezmlm-make(1)
+to create
+.I dir
+and files within it to support the
+.I local\fB@\fIhost
+address as a global ezmlm interface.
+.I dot
+and
+.I dot\fB-default
+are linked to
+.I dir\fB/ezdomo
+which uses
+.B ezmlm-request(1)
+to handle requests as well as 
+bounces and ezmlm-style command addresses for the global interface.
+The configuration file
+.I dir\fB/config.cf
+should be created separately with
+.BR ezmlm-glconf(1) .
+.SH OPTIONS
+.TP
+.B -5\fI owner
+Forward mail addressed to
+.I local\fB-owner@\fIhost
+to
+.I owner
+rather than storing it in a local mailbox.
+.SH USAGE
+Typical use by ``joe'' to set up
+.B joe-\fImajordomo\fB@\fIthis.com:
+
+.EX
+ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo joe-majordomo this.com
+.EE
+
+Typical use by ``alias'' to set up
+.I majordomo\fB@\fIthis.com:
+
+.EX
+ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo majordomo this.com
+.EE
+
+Typical use by ``virt'' controlling the virtual domain
+.I lists.com
+to set up
+.I majordomo\fB@\fIlist.com:
+
+.EX
+ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo majordomo list.com
+
+echo "virt-majordomo" > ~/domo/inlocal
+.EE
+The ``echo'' line is required only if used with qmail<1.02.
+.SH "SEE ALSO"
+ezmlm-glconf(1),
+ezmlm-make(1),
+ezmlm-request(1),
+ezmlm(5)
diff --git a/ezmlmrc.5 b/ezmlmrc.5
new file mode 100644 (file)
index 0000000..6d30610
--- /dev/null
+++ b/ezmlmrc.5
@@ -0,0 +1,746 @@
+.TH ezmlmrc 5
+.UC 4
+.SH NAME
+ezmlmrc \- ezmlm-make configuration file
+.SH SYNOPSIS
+ezmlmrc
+.SH DESCRIPTION
+.LP
+.B .ezmlmrc
+is a file that configures
+.B ezmlm-make(1)
+for setting up new lists.
+.B ezmlmrc
+if a plain text with four types
+of tags. All start in
+the first position of the line.
+No other text is allowed on the same line. For
+security reasons, no periods are allowed anywhere in a tag.
+Any line with a ``#'' in position 1 is ignored,
+as is any text preceding the first tag.
+
+The first line
+in
+.B .ezmlmrc
+is unique. It should start in position 1 with ``x.yz'', where
+``x'' is the major version number, ``y'' a minor version number, and ``z''
+a bugfix version number.
+.B ezmlm-make(1)
+will print a warning message if it is used with an
+.B .ezmlmrc
+file that lacks the version identifier, or
+with an
+.B ezmlmrc
+file that has a version identifier that differs in
+either major or minor version numbers from the
+.B ezmlm-make
+version.
+
+The
+.B .ezmlmrc
+file is processed top down. Text preceding the first tag is ignored.
+Subsequently, one and only one file is open for writing. Any text encountered
+in
+.B \.ezmlmrc
+is copied to that file as is with a few substitutions (see below). Text
+following conditional tags is copied only if the condition is met. A file is
+automatically closed when a new file is opened. Opening a file overwrites
+any preexisting file with that name.
+Tags are:
+
+.TP
+.B </filename#aI/>
+The following text will be copied to
+.IR dir\fB/filename
+if the options specified after the ``#'' are active, in this case
+.I archived
+and not
+.IR indexed .
+Any number of flags can be specified. This
+is used to adapt the files and
+messages to the type of list created. If no flags are
+used, the ``#'' can be omitted. If the file name is the same as the previous
+tag, or if it is omitted, the text will be added to the previous file.
+When a new file is opened the previous file is closed. Attempts to add
+more text to a already closed file overwrites its contents.
+For all letter switches (except
+.BR \-cCvV ),
+upper and lower
+case tags are opposite and mutually exclusive. Thus, if
+.B \-g
+is specified,
+.B \-G
+is not set and
+if
+.B \-G
+is set,
+.B -g
+is not.
+
+The tag
+.B #E
+has special meaning. It is false if the list is being edited, e.g.
+.B ezmlm-make
+.B \-e
+or
+.BR \+ ,
+but true
+if switches
+.B \-ee
+or
+.BR \-++
+are used, or if
+.B ezmlm-make
+.I local
+is specified. Thus, for normal edits with unchanged list name, the files
+tagged with
+.B #E
+are not overwritten (preserving manual customizations), but if the list name
+changes or if explicitly specified by
+.B \-ee
+or
+.BR \-++
+the
+.B #E
+switch is ignored.
+
+.TP
+.B </filename#^5^i/>
+This is an alternative way of specifying ``if switch \-5 is specified and
+the \-i switch is not specified''. ``^'' is used as ``not''.
+.TP
+.B </-filename#eA/>
+.IR dir\fB/filename
+will be erased, if the options after the ``#'' are active, in this case
+.I not archived
+and
+.IR edit .
+An alternative to specify that a flag, e.g. ``4'' should not be active is
+to use ``^4''.
+.TP
+.B </+directory#aI/>
+The directory ``directory'' is created if the flags specified are active, in
+this case
+.I archived
+and not
+.IR indexed .
+If no flags are specified, the ``#'' can be
+omitted.
+.TP
+.B </:link/directory#aI/>
+.B dot\fI\-link
+is symlinked to
+.I dir/directory
+if the flags specified are active, in
+this case
+.I archived
+and not
+.IR indexed .
+If no flags are specified, the ``#'' can be
+omitted.
+.PP
+In addition,
+.I local
+is substituted for
+.BR <#L#> ,
+the part of
+.I dot
+between the first 2 hyphens (if any) for
+.BR <#1#> ,
+the part of
+.I dot
+between the second and third hyphen (if any) for
+.BR <#2#> ,
+.I host
+for
+.BR <#H#> ,
+.I dir
+for
+.BR <#D#> ,
+.I dot
+for
+.BR <#T#> ,
+.I digestcode
+for
+.BR <#C#> ,
+and the path to the
+.B ezmlm
+binaries for
+.BR <#B#>
+anywhere in the text. Other tags of this format are copied to the files as is.
+
+.BR <#l#> ,
+.BR <#h#> ,
+.BR <#A#> ,
+.BR <#R#> ,
+will be substituted on-the-fly where appropriate for the
+.IR local
+or
+.IR local\fB\-digest
+local part of the list address, the
+.IR host ,
+the subscriber address or the moderation accept address,
+and the subscription reply address or moderation reject address, respectively.
+The use of
+.BR <#l#>
+is to allow the same text file to be used for requests pertaining to both
+the main list and the digest list.
+
+Before the template file is processed,
+.B ezmlm-make
+will create the list directory.
+.B ezmlm-make
+will also create
+.IR dir\fB/key .
+.SH "DESCRIPTION OF EZMLMRC"
+The ezmlmrc file is preconfigured to act upon
+.B ezmlm-make(1)
+switches to produce the results as described in the
+.B ezmlm-make(1)
+man page.
+A number of files are created via
+.B ezmlmrc
+independently of any switched. These are
+.I dir\fB/text/info
+with a short description of the list,
+.I dir\fB/text/faq
+with frequently asked questions about the list,
+.I dir\fB/headeradd
+adding ``Precedence: bulk'' and ``X-No-Archive: yes'' to outgoing messages,
+.I dir\fB/headerremove
+removing ``Return-Path'', ``Return-Receipt-To'', ``Content-length'',
+ and ``Precedence'' from list messages, and
+.I dir\fB/text/sub-ok
+with text sent after successful subscription. These files are not overwritten
+when lists are edited.
+
+Also created are the following files within
+.IR dir\fB/text/ :
+.BR bottom ,
+.BR bounce-bottom ,
+.BR bounce-num ,
+.BR dig-bounce-num ,
+.BR bounce-probe
+.BR bounce-warn ,
+.BR get-bad ,
+.BR help ,
+.BR mod-help ,
+.BR mod-request ,
+.BR mod-reject ,
+.BR mod-timeout ,
+.BR mod-sub-confirm ,
+.BR mod-unsub-confirm ,
+.BR sub-bad ,
+.BR sub-confirm ,
+.BR sub-nop
+.BR unsub-bad ,
+.BR unsub-confirm ,
+.BR unsub-nop ,
+.BR unsub-ok ,
+.BR top .
+
+.I dir\fB/bouncer
+is set up to invoke
+.B ezmlm-weed(1)
+and
+.B ezmlm-return(1)
+to handle bounces.
+In addition to switch-dependent lines, an invocation of
+.B ezmlm-warn(1)
+is placed at the end of
+.IR dir\fB/editor ,
+.IR dir\fB/manager ,
+and
+.I dir\fB/owner
+to process the contents of the bounce directory.
+.BR ezmlm-reject(1)
+is placed first in
+.I dir\fB/editor
+ (unless the
+.B \-0\ mainlist@mainhost
+switch is used) to reject undesirable messages.
+ Below is a description of the switches and the consequences
+the have for list creation with the standard
+.B ezlmrc
+file.
+.B emzlm-make(1)
+by default sets the
+.BR \-a ,
+and
+.B \-p
+switches.
+.TP
+.B \-a
+.I dir\fB/archived
+and
+.I dir\fB/indexed
+are created.
+.I dir\fB/text/bottom
+is adjusted to mention archive access.
+.B \-A
+.I dir\fB/archived
+and
+.I dir\fB/indexed
+are removed.
+.TP
+.B \-b
+Block archive. The list set up with
+.B ezmlm-get -P
+to allow only moderators archive access.
+.TP
+.B \-B
+The
+.B ezmlm-get -P
+switch is not used.
+.TP
+.B \-d
+.I dir\fB/digest/
+is created.
+.I dir\fB/digest/lock
+is created.
+.I dir\fB/digest/lockbounce
+is created.
+.I dir\fB/digest/bounce/
+is created.
+.I dir\fB/digest/subscribers/
+is created.
+.I dot\fB-digest-owner
+is linked to
+.IR dir\fB/owner .
+.I dot\fB-digest-return-default
+is linked to
+.IR dir\fB/bouncer .
+An invocation of
+.B ezmlm-warn(1) -d
+is added to
+.I dir\fB/editor
+and
+.IR dir\fB/manager .
+Invocations of
+.B ezmlm-tstdig(1)
+and
+.B ezmlm-get(1)
+are added with default arguments to
+.IR dir\fB/editor .
+A note on digest (un)subscription is added to
+.I dir\fB/text/bottom
+and to
+.IR dir\fB/text/mod-help .
+.I dir\fB/text/digest
+is created for the ``Administrivia'' section of the digest.
+.TP
+.B \-D
+The items mentioned under switch
+.B \-d
+are not done. The result is that the references to the digest
+in the text files is removed.
+.TP
+.B \-f
+The text ``[\fIlocal\fR]'' is placed in
+.I dir\fB/prefix
+resulting in the text being used as the list's subject index.
+.TP
+.B \-F
+.I dir\fB/prefix
+is removed.
+.TP
+.B \-g
+The -s switch is added to the
+.B ezmlm-get(1)
+line in
+.I dir\fB/manager
+so that only subscribers can access the archive.
+.TP
+.B \-G
+The -s switch for
+.B ezmlm-get(1)
+is not used. Anyone can access the archive if archive (access) in general
+is enabled (see
+.B \-p
+for ``public'',
+.B \-a
+for ``archived'', and
+.B \-i
+for ``indexed''.
+.TP
+.B \-i
+.I dir\fB/editor
+(for normal lists)
+or
+.I dir\fB/moderator
+(for moderated lists)
+are set up to run
+.B ezmlm-archive(1)
+after messages are posted. This sets up the cross-reference for
+.B ezmlm-cgi(1)
+WWW access.
+.TP
+.B \-I
+.B ezmlm-archive(1)
+is not configured.
+.TP
+.B \-j
+.I dir\fB/manager
+uses
+.B ezmlm-manage -U
+to allow unconfirmed unsubscribe.
+.B \-J
+The
+.B ezmlm-manage -U
+switch is not used.
+.TP
+.B \-k
+Blacklist. A
+.B ezmlm-issubn(1)
+line that tests the envelope sender against the address database in
+.I dir\fB/deny
+is inserted into
+.IR dir\fB/editor .
+As a consequence, posts from such senders are rejected. This switch is ignored
+for sublists (i.e. if the
+.B \-0\ mainlist@mainhost
+switch is used).
+.TP
+.B \-K
+The
+.B ezmlm-issubn(1)
+line testing the envelope sender against the ``blacklist'' in
+.I dir\fB/deny
+is not used.
+.TP
+.B \-l
+The -l switch is added to the
+.B ezmlm-manage(1)
+command line in
+.I dir\fB/manager
+to allow retrieval of subscriber list and list log by remote administrators.
+.BR NOTE :
+This is pointless, unless the list is also set up for remote administration
+with the
+.B \-r
+switch.
+.I dir\fB/text/mod-help
+is adjusted.
+.TP
+.B \-L
+Do not allow access to the subscriber list under any circumstances. The
+.B ezmlm-manage(1)
+\-l switch is not specified.
+.TP
+.B \-m
+Message moderation.
+.I dir\fB/modpost
+is created.
+.I dir\fB/editor
+is set up with
+.B ezmlm-store(1)
+instead of
+.BR ezmlm-send(1) .a
+.I dir\fB/moderator
+is set up with
+.BR ezmlm-moderate(1) ,
+and
+.BR ezmlm-clean(1) .
+.I dot\fB/\-accept-default
+and
+.I dot\fB/-reject-default
+are linked to
+.IR dir\fB/moderator .
+.I dir\fB/text/mod-help
+is adjusted.
+Special action is taken when the
+.B \-m
+switch is combined with
+.BR \-u .
+In this case, the setup is as for the
+.B \-m
+switch alone, but
+.I dir\fB/editor
+is set up with
+.B ezmlm-gate(1)
+which will fork
+.B ezmlm-send(1)
+for posts with an envelope sender that is a subscriber or a moderator, and
+for
+.B ezmlm-store(1)
+for posts with other envelope senders. The consequence is that posts from
+subscribers (with the usual caveats for SENDER checks) are posted directly,
+whereas other posts are sent for moderation.
+.TP
+.B \-M
+No message moderation.
+.I dir\fB/editor
+is set up with
+.B ezmlm-send(1)
+as usual.
+.I dir\fB/moderator
+is removed.
+.TP
+.B \-n
+Allow text file editing.
+.ezmlm-manage(1)
+in
+.I dir\fB/manager
+is set up with the \-e switch to allow remote admins to via E-mail edit
+the files in
+.IR dir\fB/text/ .
+.BR NOTE :
+This is pointless, unless the list is also set up for remote administration
+with the
+.B \-r
+switch.
+.I dir\fB/text/mod-help
+is adjusted.
+.TP
+.B \-N
+Remote editing of files in
+.I dir\fB/text
+is not allowed.
+The -e switch for
+.B ezmlm-manage
+will not be used. 
+.TP
+.B \-o
+For moderated lists, the
+.B ezmlm-store -P
+switch is used so that posts from non-moderators are rejected rather than
+sent for moderation. This is for some announcement lists.
+.TP
+.B \-O
+The
+.B ezmlm-store -P
+switch is not used.
+.TP
+.B \-p
+Public.
+.I dir\fB/public
+is created.
+.TP
+.B \-P
+Not public.
+.I dir\fB/public
+is removed.
+.TP
+.B \-q
+A line with
+.B ezmlm-request(1)
+is added to
+.I dir\manager
+to service commands in the ``Subject'' line of messages sent to the
+``list-request'' address.
+.TP
+.B \-Q
+.B ezmlm-request(1)
+is not used.
+.TP
+.B \-r
+Remote admin.
+.I dir\fB/remote
+is created.
+.I dir\fB/text/mod-help
+is adjusted.
+.TP
+.B \-R
+.I dir\fB/remote
+is removed.
+.TP
+.B \-s
+Subscription moderation.
+.I dir\fB/modsub
+is created.
+.I dir\fB/text/mod-help
+is adjusted.
+.I dir\fB/text/sub-confirm
+is adjusted.
+.TP
+.B \-S
+.I dir\fB/modsub
+is removed.
+.TP
+.B \-t
+.I dir\fB/text/trailer
+is created with instructions on how to unsubscribe.
+.TP
+.B \-T
+.I dir\fB/text/trailer
+is removed.
+.TP
+.B \-u
+User-only posts.
+.I dir\fB/editor
+is set up with an
+.B ezmlm-issubn(1)
+line to check the envelope sender against the subscriber address databases.
+If the sender is not found, the post is rejected. This results in
+subscriber-only posts, with the usual caveats for SENDER checks.
+Special action is taken when the
+.B \-u
+switch is combined with
+.BR \-m .
+In this case, the setup is as for the
+.B \-m
+switch alone, but
+.I dir\fB/editor
+is set up with
+.B ezmlm-gate(1)
+which will fork
+.B ezmlm-send(1)
+for posts with an envelope sender that is a subscriber or a moderator, and
+for
+.B ezmlm-store(1)
+for posts with other envelope senders.
+.B ezmlm-clean(1)
+is set up with the \-R switch.
+The consequence is that posts from
+subscribers (with the usual caveats for SENDER checks) are posted directly,
+whereas other posts are sent for moderation.
+.B ezmlm-clean(1)
+is set up with the \-R switch.
+Thus, ignored posts are silently
+removed rather than returned to sender.
+.TP
+.B \-U
+The
+.B ezmlm-issubn(1)
+line
+restricting posts by envelope sender is not used.
+.TP
+.B \-w
+The
+Remove the
+.B ezmlm-warn(1)
+invocations from the list setup. It is assumed that
+.B ezmlm-warn(1)
+for both
+.I local@host
+and
+.I local-digest@host
+will be run by other means, such as crond.
+If the
+.B \-6
+switch is used with this switch, the local list name will be added to the
+SQL config info for
+.I dir\fB/sql
+and
+.I dir\fB/digest/sql .
+This is to support building the main list for a distributed list using
+a SQL address database. In addition,
+.B ezmlm-receipt(1)
+will be set up for bounce handling in
+.I dir\fB/bouncer
+instead of
+.BR ezmlm-return(1).
+.TP
+.B \-W
+No action taken.
+.TP
+.B \-xyzXYZ
+User configurable. By default, if the
+.B \-x
+switch is specified,
+.I dir\fB/mimeremove 
+is created. This file contains many MIME types not routinely supported.
+MIME types in
+.I dir\fB/mimeremove are stripped from multipart posts before archiving
+and distribution.
+To view the list of
+MIME types, see
+.B ezmlmrc
+or create a list and list
+.IR dir\fB/mimeremove .
+In addition
+.I dir\fB/msgsize
+is created containing ``40000:2'' causing
+.B ezmlm-reject(1)
+to reject all posts that have a body of less than 2 bytes (empty) or
+more than 40000 bytes (too large).
+.TP
+.B \-0\fI\ mainlist@mainhost
+.I dir\fB/sublist
+is created with ``mainlist@mainhost''.
+.B dir\fB/ezmlm-reject
+is not used in
+.I dir\fB/editor
+to avoid rejecting messages that the main list has accepted.
+.TP
+.B \-3\fI\ fromarg
+The list is set up to add ``from'' to
+.I dir/fB/headerremove
+and
+.B From:\fI fromarg
+to
+.IR dir\fB/headeradd .
+This replaces the incoming ``From:'' header as desirable for some announcement
+lists.
+.TP
+.B \-4\fI\ tstdigopts
+.I tstdigopts
+will be used as the arguments for
+.ezmlm-tstdig(1)
+in
+.IR dir\fB/editor .
+This must be both switches and their arguments for
+.BR ezmlm-tstdig(1) .
+.BR NOTE :
+This is pointless, unless the list is also set up for digests
+with the
+.B \-d
+switch.
+.TP
+.B \-5\fI\ owner@ownerhost
+.I owner@ownerhost is placed in
+.I dir\fB/owner
+so that mail to ``list-owner'' is forwarded to that address, rather than
+being stored in
+.IR dir\fB/Mailbox .
+If the address does not start with an underscore or alphanumeric character,
+the argument must start with an ampersand.
+.TP
+.B \-6\fI\ host:port:user:password:datab:table
+.TP
+The string, followed by the list name is placed in
+.IR dir\fB/sql .
+The same string with ``table'' suffixed with ``_digest'' and ``_allow''
+is placed in
+.I dir\fB/digest/sql
+and
+.IR dir\fB/allow/sql ,
+respectively.
+.B \-7\fI\ /msgmodPath
+.I msgmodPath
+is placed in
+.IR dir\fB/modpost
+is the list is set up for message moderation with the
+.B \-m
+switch.
+.TP
+.B \-8\fI\ /submodPath
+.I submodPath
+is placed in
+.IR dir\fB/modsub
+is the list is set up for subscription moderation with the
+.B \-s
+switch.
+.TP
+.B \-9\fI\ /remoteAdminPath
+.I remoteAdminPath
+is placed in
+.IR dir\fB/remote
+is the list is set up for remote administration with the
+.B \-r
+switch.
+.SH "SEE ALSO"
+ezmlm(5),
+ezmlm-clean(1),
+ezmlm-gate(1),
+ezmlm-get(1),
+ezmlm-issubn(1),
+ezmlm-make(1),
+ezmlm-manage(1),
+ezmlm-moderate(1),
+ezmlm-request(1),
+ezmlm-return(1),
+ezmlm-send(1),
+ezmlm-store(1),
+ezmlm-tstdig(1),
+ezmlm-warn(1),
diff --git a/ezmlmrc.ch_GB b/ezmlmrc.ch_GB
new file mode 100644 (file)
index 0000000..61afeb3
--- /dev/null
@@ -0,0 +1,966 @@
+0.324 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.ch_GB,v 1.2 1999/12/23 23:08:19 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+To
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+list-help: <mailto:<#l#>-help@<#h#>>
+list-unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+list-post: <mailto:<#L#>@<#H#>>
+To:##L@##H
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+È¡Ïû×¢²á£¬½«µç×ÓÓʼþ·¢Ë͵½£º<#L#>-unsubscribe@<#H#>£¬Èç¹ûÐèÒª¸ü¶àµÄ°ïÖú£¬½«
+µç×ÓÓʼþ·¢Ë͵½£º<#L#>-help@<#H#>¡£
+</text/bottom/>
+
+---<#l#> ÓʼþÁбíµÄ¹ÜÀíÃüÁî---
+
+ϵͳÄܹ»×Ô¶¯´¦Àí¶ÔÓʼþÁбíµÄ¹ÜÀíÇëÇó¡£½«ÐèÒª´¦ÀíµÄÃüÁî·¢Ë͵½ÒÔϵĵç×ÓÓʼþ
+µØÖ·£º
+
+×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-subscribe@<#H#>>
+
+È¡Ïû×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-unsubscribe@<#H#>>
+
+½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·Äܹ»»ñµÃÓʼþÁбíµÄ½éÉÜÐÅÏ¢£º
+   <<#L#>-info@<#H#>>
+
+½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·Äܹ»»ñµÃÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð£¨FAQ£©£º
+   <<#L#>-faq@<#H#>>
+
+</#d/>
+×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-digest-subscribe@<#H#>>
+
+È¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢
+Ë͵½£º
+   <<#L#>-get.123_145@<#H#>>
+
+</text/bottom#aI/>
+»ñµÃÓʼþÁбíµÚ12ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-get.12@<#H#>>
+
+</text/bottom#i/>
+»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-index.123_456@<#H#>>
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+»ñµÃÓëÀúÊ·Óʼþ12345ÏàͬÖ÷ÌâµÄÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-thread.12345@<#H#>>
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+
+Äã¿ÉÒÔͨ¹ýµç×ÓÓʼþµÄ·½Ê½×¢²áÒ»¸öÆäËüµÄµØÖ·£¬¾ÙÀýÀ´½²£¬ÄãÏ£Íûͨ¹ýµç×ÓÓʼþµÄ·½Ê½×¢
+²á¡°john@host.domain¡±£¬Ö»ÒªÔÚÃüÁîºó£¨subscribe£©Ìí¼Ó¡°-¡±²¢ÇÒÓá°=¡±´úÌæ¡°@¡±£º
+<<#L#>-subscribe-john=host.domain@<#H#>>
+
+È¡Ïû×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+<<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+ʹÓÃÕâÖÖ·½Ê½×¢²á¡¢È¡Ïû×¢²áÓʼþÁбíʱ£¬ÏµÍ³½«Ïò¸ÃµØÖ··¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬µ±¸ÃµØÖ·
+ÊÕµ½µç×ÓÓʼþʱ£¬Ö»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄܹ»Íê³É×¢²áºÍÈ¡Ïû×¢²á¡£
+
+</text/bottom/>
+Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκÎÎÊÌ⣬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß<#L#>-owner@<#H#>¡£
+Èç¹û²»Äܽâ¾öÎÊÌ⣬ÇëÓëϵͳµÄ¹ÜÀíÔ±ÁªÏµ¡£
+</text/bottom/>
+
+--- ËæП½ÉϵÄÊÇϵͳÊÕµ½µÄÄã·¢Ë͵ÄÓʼþ¡£
+
+</text/bounce-bottom/>
+
+--- ËæП½ÉϵÄÊÇϵͳÊÕµ½µÄϵͳµ¯»Ø£¨bounce£©µÄÓʼþ¡£
+
+</text/bounce-num/>
+
+ϵͳÒѾ­±£´æÁËÒ»·Ý´Ó<#L#>ÓʼþÁÐ±í·¢Ë͵½ÄãµÄµç×ÓÓʼþµØÖ·±»µ¯»Ø£¨bounce£©µç×ÓÓʼþ¡£
+
+</#a/>
+ÕâЩµç×ÓÓʼþµÄ¿½±´¿ÉÄÜÒѾ­±£´æÔÚÀúÊ·ÎĵµÖС£
+</#aI/>
+»ñµÃÓʼþÁбíµÚ12345ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-get.123_145@<#H#>>
+
+»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-index.123-456@<#H#>>
+
+<//>
+ÏÂÃæÊǵç×ÓÓʼþµÄ±àºÅ£º
+
+</text/dig-bounce-num/>
+
+ϵͳÒѾ­±£´æÁËÒ»·Ý´Ó<#L#>ÓʼþÁÐ±í·¢Ë͵½ÄãµÄµç×ÓÓʼþµØÖ·±»µ¯»Ø£¨bounce£©µÄÕªÒªÓʼþ¡£
+¶ÔÓÚÄã´í¹ýµÄÿ·ÝÕªÒª£¬ÏµÍ³ÒѾ­°üº¬ÔÚ·¢Ë͸øÄãµÄÕªÒªÓʼþÖеĵÚÒ»¸öÓʼþ¡£ÏµÍ³Ã»Óн«Äã
+´í¹ýµÄÕªÒªÓʼþ·¢Ë͸øÄ㣬µ«ÊÇÄã¿ÉÒÔͨ¹ýÓʼþÁбíµÄÀúÊ·ÎĵµÖлñµÃ¡£
+
+</#aI/>
+»ñµÃÓʼþÁбíµÚ12345ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-get.123_145@<#H#>>
+
+»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-index@<#H#>>
+
+<//>
+ÏÂÃæÊÇÕªÒªÓʼþµÄ±àºÅ£º
+
+</text/bounce-probe/>
+
+´Ó<#l#>ÓʼþÁÐ±í·¢Ë͸øÄãµÄµç×ÓÓʼþÒѾ­±»µ¯»Ø£¨bounce£©¡£ÏµÍ³ÒѾ­ÏòÄã·¢ËÍÁËÒ»¸ö¾¯¸æµÄ
+Óʼþ£¬µ«ÊÇÕâ¸öÓʼþͬÑù±»µ¯»Ø£¨bounce£©¡£ÏµÍ³½«¸½Éϵ¯»Ø£¨bounce£©µÄÓʼþ¡£
+
+Õâ¸öÓʼþÊÇϵͳΪ¼ì²âÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñÄܹ»µ½´ï¶ø·¢Ë͵ġ£Èç¹ûÕâ·âÓÃÓÚ¼ì²âµÄµç×ÓÓʼþ
+Ò²±»µ¯»Ø£¨bounce£©£¬ÏµÍ³½«°ÑÄãµÄµç×ÓÓʼþµØÖ·´Ó<#l#>@<#H#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á²¢²»ÔÚͨ
+ÖªÄ㡣ͬÑùÄãÒ²¿ÉÒÔͨ¹ýÏòÏÂÃæµÄµØÖ··¢Ë͵ç×ÓÓʼþµÄ·½Ê½ÖØÐÂ×¢²áÓʼþÁÐ±í£º
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+´Ó<#l#>ÓʼþÁÐ±í·¢Ë͸øÄãµÄµç×ÓÓʼþÒѾ­±»µ¯»Ø£¨bounce£©¡£ÏµÍ³ÒѾ­½«±»µ¯»Ø£¨bounce£©µÄ
+µÚÒ»¸öµç×ÓÓʼþ¸½ÉÏ¡£
+
+Èç¹ûÕâ¸öµç×ÓÓʼþͬÑù±»µ¯»Ø£¬ÏµÍ³½«ÏòÄãµÄµç×ÓÓʼþµØÖ··¢ËÍÒ»¸ö¼ì²âÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñ
+ÕýÈ·µÄµç×ÓÓʼþ£¬Èç¹ûÕâ¸öµç×ÓÓʼþͬÑù±»µ¯»Ø£¬ÏµÍ³½«°ÑÄãµÄµç×ÓÓʼþµØÖ·´Ó<#l#>ÓʼþÁбí
+È¡Ïû×¢²á²¢²»ÔÚ֪ͨÄã¡£
+
+</text/digest#d/>
+×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+       <#L#>-digest-subscribe@<#H#>
+
+È¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+       <#L#>-digest-unsubscribe@<#H#>
+
+ÏòÓʼþÁÐ±í·¢Ë͵ç×ÓÓʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+       <#L#>@<#H#>
+
+</text/get-bad/>
+ÔÚÓʼþÁбíµÄÀúÊ·ÎĵµÖв»ÄÜ·¢ÏÖÕâÌõÓʼþ¡£
+
+</text/help/>
+ϵͳÊÕµ½µÄµç×ÓÓʼþÖÐûÓаüÀ¨ÏµÍ³Äܹ»´¦ÀíµÄÃüÁî¡£
+
+</text/mod-help/>
+ÄãÏÖÔÚÒѾ­³ÉΪ<#L#>@<#H#>ÓʼþÁбíµÄ¹ÜÀíÕߣ¨moderator£©£¬ÏÂÃ潫½éÉÜ×÷Ϊһ¸öÓʼþÁбí
+µÄËùÓÐÕß»ò¹ÜÀíÕߣ¨moderator£©Äã¿ÉÒÔͨ¹ýÏÂÃæµÄ·½Ê½¶ÔÓʼþÁбíµÄ¸÷¸ö·½Ãæ½øÐйÜÀí¡£
+
+
+Óû§×¢²áºÍÈ¡Ïû×¢²áµÄ¹ÜÀí
+----------------------
+×÷ΪÓʼþÁбíµÄ¹ÜÀíÕߣ¬ÄãÄܹ»×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÈκÎÓû§¡£ÄãÏ£Íûͨ¹ýµç×ÓÓʼþµÄ·½
+ʽע²á¡°john@host.domain¡±£¬Ö»ÒªÔÚÃüÁîºó£¨subscribe£©Ìí¼Ó¡°-¡±²¢ÇÒÓá°=¡±´úÌæ¡°@¡±£¬¾Ù
+ÀýÀ´½²£¬×¢²áÉÏÃæËù½²µÄµØÖ·£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+ͬÑù£¬È¡Ïû×¢²áÉÏÃæµÄµç×ÓÓʼþµØÖ·£¬½«µç×ÓÓʼþ·¢Ë͵½£º
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#d/>
+ͬÑù¶ÔÓÚ×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£º
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+<//>
+ËùÓеÄ×¢²áºÍÈ¡Ïû×¢²á¶¼²»ÐèÒªÓÐÓʼþÖ÷ÌâºÍÓʼþÄÚÈÝ!
+
+</#r/>
+ϵͳ½«ÏòÄã·¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬È·ÈÏÊÇÄã·¢Ë͵ÄÇëÇó¡£ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉËùÓеÄÇëÇó¡£
+</#R/>
+ϵͳ½«ÏòÓû§·¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬ÈçÉÏÃæËù˵µÄµç×ÓÓʼþµØÖ·<john@host.domain>¡£Óû§±ØÐë
+»Ø¸´µç×ÓÓʼþ²ÅÄÜÍê³ÉËùÓеÄÇëÇó¡£
+<//>
+
+È·Èϵķ½Ê½·ÀÖ¹ÁËÆäËûÈËËæÒâµÄÏòÓʼþÁбíÌí¼ÓºÍɾ³ýÓû§¡£
+
+ϵͳ½«Í¨ÖªÓû§Ëû/ËýµÄ×¢²á״̬ÒѾ­¸Ä±ä¡£
+
+×¢²áºÍÈ¡Ïû×¢²á
+-------------
+
+ÈκÎÓû§¿ÉÒÔͨ¹ýÏòÏÂÃæµÄµØÖ··¢Ë͵ç×ÓÓʼþ½øÐÐ×¢²á»òÈ¡Ïû×¢²á£º
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+ͬÑù¶ÔÓÚ×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£º
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+<//>
+Óû§½«´ÓϵͳÊÕµ½È·ÈÏÐÅËû/Ëýµç×ÓÓʼþµØÖ·µÄÈ·ÈÏÐÅ¡£Ò»µ©µç×ÓÓʼþµØÖ·±»È·ÈÏ£¬×¢²á»òÈ¡Ïû×¢²á½«Íê³É¡£
+
+</#s/>
+ÒòΪÓʼþÁбí¶ÔÓÚÓû§×¢²áÊÇÐèÒª¾­¹ý¹ÜÀíÕߣ¨moderator£©µÄÅú×¼ºó²ÅÄÜÍê³É£¬ËùÒÔϵͳÔÚÍê³É¶ÔÓû§
+µç×ÓÓʼþµØÖ·µÄÑéÖ¤ºó½«ÏòÓʼþÁбíµÄ¹ÜÀíÕߣ¨moderator£©·¢ËÍÇëÇó¹ÜÀíÕßÈ·ÈϵØÖ·×¢²áÓʼþÁбí
+µÄÇëÇó¡£Èç¹ûÄãÏ£ÍûÓû§×¢²áÓʼþÁÐ±í£¬Ö»Òª»Ø¸´µç×ÓÓʼþ½øÐÐÍê³ÉÈ·ÈÏ¡£Èç¹ûÄ㲻ϣÍûÓû§×¢²á
+ÓʼþÁÐ±í£¬Äã¿ÉÒÔɾ³ýÕâ·âµç×ÓÓʼþ¡£
+</#S/>
+×¢²áÒ²ÊÇͬÑùµÄ·½Ê½
+<//>
+
+ͬÑùÓû§Ò²¿ÉÒÔʹÓÃÏÂÃæµÄ·½·¨È¡Ïû×¢²á£º
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+"mary@host.domain"½«ÊÕµ½ÏµÍ³·¢Ë͵ÄÈ·ÈÏÈ¡Ïû×¢²áµÄµç×ÓÓʼþ.ÔÚÑéÖ¤Íê³Éºó¾ÍÄÜÈ¡Ïû×¢²á¡£
+
+</#rl/>
+ͨ¹ýµç×ÓÓʼþµÄ·½Ê½»ñµÃ<#L#>@<#H#>ÓʼþÁбíµÄ×¢²áÓû§£¬½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·:
+   <<#L#>-list@<#H#>>
+
+ͨ¹ýµç×ÓÓʼþµÄ·½Ê½»ñµÃ<#L#>@<#H#>ÓʼþÁбíµÄÈÕÖ¾£¨Log£©Îļþ, ½«µç×ÓÓʼþ·¢Ë͵½ÏÂ
+ÃæµÄµØÖ·:
+   <<#L#>-log@<#H#>>
+
+</#rld/>
+ͬÑù£¬Í¨¹ýµç×ÓÓʼþ»ñµÃÓʼþÁбíÕªÒªµÄ×¢²áÓû§£º
+   <<#L#>-digest-list@<#H#>>
+ͬÑù£¬Í¨¹ýµç×ÓÓʼþ»ñµÃÓʼþÁбíÕªÒªµÄÈÕÖ¾Îļþ£º
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Äã¿ÉÒÔͨ¹ý¶ÔһЩÎļþµÄ±à¼­À´¶¨ÖÆÓʼþÁбíµÄ»ØÓ¦Óʼþ¡£µÃµ½ÐèÒª±à¼­µÄÎļþ¼°ÈçºÎ±à¼­£¬½«µç×ÓÓʼþ·¢ËÍ
+µ½ÏÂÃæµÄµØÖ·£º
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+ÓйÜÀíµÄͶµÝ
+-----------
+µ±Ò»¸öÓʼþÁбíÉèÖóÉËùÓз¢Ë͵½ÓʼþÁбíµÄÓʼþ¶¼Òª¾­¹ý¹ÜÀíÕßµÄÉóºËºó²ÅÄÜ·¢ËÍʱ£¬ÏµÍ³½«±£´æͶµÝµ½
+ÓʼþÁбíµÄÓʼþ²¢½«ÓʼþµÄ¿½±´·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß¡£Õâ·âÓʼþµÄÌØÕ÷ÊÇÔÚÓʼþµÄÖ÷ÌâÖÐÓÐ
+¡°MODERATE for ...¡±¡£
+
+Èç¹ûÄãÏ£ÍûÔÚÓʼþÁбíÖÐת·¢Óʼþ£¬ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¡£
+
+Èç¹ûÄ㲻ϣÍûת·¢Óʼþ²¢ÒªÉ¾³ý´ËÓʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½¡¯·¢¼þÈË£º¡®µÄµç×ÓÓʼþµØÖ·¡£Í¨³£ÄãÖ»Òªµã»÷
+¡°È«²¿»Ø¸´¡±£¬È»ºóɾ³ý³ý¡®reject¡¯ÒÔÍâµÄËùÓеç×ÓÓʼþµØÖ·¡£Í¬Ê±ÄãÒ²¿ÉÒÔÔÚ'%'¼äÌí¼ÓΪʲôûÓÐת
+·¢µÄµÄÆÀÂÛ£¬ÏµÍ³½«ÕâЩÆÀÂÛ×Ô¶¯µÄ·¢Ë͵½ÓʼþµÄ·¢¼þÈË¡£
+
+ϵͳ½«¶Ô¸ù¾ÝÓʼþÁбí¹ÜÀíÕ߶ÔÓʼþ»Ø¸´µÄÏȺó˳Ðò¶ÔÓʼþ½øÐд¦Àí£¨ÏµÍ³×ÜÊÇ°´ÕÕ×îÏȻظ´µÄ½øÐд¦Àí£©¡£
+Èç¹ûÄãÇëÇó´¦ÀíµÄµç×ÓÓʼþϵͳÒѾ­½øÐÐÁË´¦Àí£¨·¢ËÍ»òɾ³ý£©£¬ÏµÍ³»áÓõç×ÓÓʼþµÄ·½Ê½Í¨ÖªÄã¡£
+
+Èç¹ûϵͳÔÚÒ»¶Îʱ¼äÄÚ£¨Í¨³£ÊÇ5Ì죩ûÓÐÊÕµ½Èκδ¦ÀíµÄ·½Ê½£¬ÏµÍ³½«Óʼþ×Ô¶¯µÄÍ˻ص½·¢¼þÈ˲¢½âÊÍΪʲ
+ôûÓнøÐд¦Àí¡£Í¬ÑùÄãÒ²¿ÉÒÔÉèÖá°¡±µÄÐÅϢ֪ͨ·¢¼þÈËΪʲôûÓд¦Àí¡£
+<//>
+
+Íâ³ö
+----
+Èç¹ûÄãÖ»ÊÇÁÙʱµÄ¸ü»»µç×ÓÓʼþµØÖ·£¬Ö»Òª½«ÓÐÕýÈ·µÄÓʼþÁбíÍ·(»òÕßÓʼþµÄÖ÷ÌâÊÇÒÔ
+'MODERATE for <#L#>@<#H#>'»ò'CONFIRM subscribe to <#L#>@<#H#>'¿ªÍ·µÄµç×ÓÓʼþ) ×ª·¢µ½ÐµÄ
+µç×ÓÓʼþµØÖ·¾Í¿ÉÒÔÁË¡£Äã¿ÉÒÔͨ¹ýеĵØÖ·¶ÔÓʼþÁбí½øÐйÜÀí¡£Í¬Ñù£¬ÄãÒ²¿ÉÒÔ½«µç×ÓÓʼþת·¢µ½Äã
+µÄÅóÓѵĵç×ÓÓʼþÐÅÏ䣬ίÍÐËû/ËýÌæÄãÁÙʱ¹ÜÀíÓʼþÁÐ±í¡£
+
+µ±ÄãÍâ³öʱ£¬Èç¹ûÄãÏ£Íûϵͳ×Ô¶¯ÑéÖ¤ËùÓеÄÇëÇó£¬ÔÚÄãµÄµç×ÓÓʼþ¿Í»§¶ËÉèÖóÉ×Ô¶¯»Ø¸´·ûºÏÉÏÊöÌõ¼þµÄ
+µç×ÓÓʼþ¡£
+
+</#r/>
+Èç¹ûÄãÊÔͼͨ¹ýÒ»¸ö²¢²»ÊÇÄãµÄµç×ÓÓʼþµØÖ·¹ÜÀíÄãµÄÓʼþÁÐ±í£¬ÏµÍ³½«ÏòÓû§·¢ËÍÈ·ÈϵÄÓʼþ£¬ÔÚÓʼþÈ·
+ÈϺó£¬Ò»·âÒªÇóÓʼþÁбí¹ÜÀíÕß½øÐÐÈ·Èϵĵç×ÓÓʼþ½«·¢Ë͵½ÓʼþÁбíµÄËùÓйÜÀíÕß¡£ÏµÍ³ÕâÑù´¦ÀíÊÇÒòΪ
+ϵͳ²»ÄÜÈ·ÈÏÊÇË­·¢Ë͵ÄÇëÇó¡£
+
+<//>
+
+×¢Ò⣺Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκεÄÎÊÌ⣬ÇëÄãÓëÓʼþÁбíµÄËùÓÐÕß(<#L#>-owner@<#H#>)ÁªÏµ¡£
+
+</text/mod-reject/>
+¶Ô²»Æð£¬Äã·¢Ë͵½ÓʼþÁбíµÄÓʼþûÓб»ÓʼþÁбíµÄ¹ÜÀíÕßÅú×¼¡£Èç¹ûÓʼþÁбíµÄ¹ÜÀíÕ߶ÔÄãµÄÓʼþ
+×öÁËÆÀÂÛ£¬Ò²¸½ÔÚÕâ·âÓʼþÖС£
+</text/mod-request/>
+Õâ·âÓʼþÊÇijÈË·¢Ë͵½<#L#>@<#H#>ÓʼþÁбíÖеġ£Èç¹ûÄãÏ£ÍûÓʼþÁбíµÄ×¢²áÓû§¶¼ÊÕµ½Õâ·âÓʼþ£¬Çë
+½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!A
+
+ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄܽ«µç×ÓÓʼþ·¢Ë͵½ÓʼþÁÐ±í¡£µØÖ·µÄ¸ñʽÊÇ"<#L#>-accept"¡£»òÕß
+½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#A#>
+<//>
+
+ɾ³ýÕâ·âÓʼþ²¢½«Õâ·âÓʼþÖ±½ÓÍ˻ط¢ÐÅÈË£¬Ç뽫Õâ·âÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ͨ³££¬ÄãÖ»Òªµã»÷¡±È«²¿»Ø¸´¡°£¬²¢½«³ýÁË"<#L#>-reject"µÄµØÖ·È«²¿É¾³ý¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+Èç¹ûÄãÏ£Íû¶ÔÓÚÍ˻صÄÓʼþ¼ÓÉÏÄãµÄÆÀÂÛ£¬ÇëÄ㽫ÄãµÄÆÀÂÛÌí¼ÓÔÚ¡±%%% Start comment¡°
+ºÍ¡±%%% End comment¡°Ö®¼ä£º
+
+%%% Start comment
+%%% End comment
+
+ллÄãµÄ°ïÖú£¡
+
+--- ËæП½ÉϵÄÊÇͶµÝµ½ÓʼþÁбíµÄµç×ÓÓʼþ¡£
+
+</text/mod-sub#E/>
+--- ÓÉÓÚ<#l#>@<#H#>¹ÜÀíÕßµÄÇëÇó£¬ÏµÍ³ÒѾ­½«Äã×¢²á»òÈ¡Ïû×¢²áÓʼþÁÐ±í¡£
+
+Èç¹û×¢²á»òÈ¡Ïû×¢²á²¢²»·ûºÏÄãµÄÏë·¨£¬ÇëÄãÖ±½Ó½«µç×ÓÓʼþ·¢Ë͵½ÓʼþÁбíµÄËùÓÐÕß(<#l#>-owner@<#H#>)¡£
+
+Èç¹ûÄãÏ£ÍûµÃµ½¸ü¶àµÄ°ïÖú£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½<#L#>-help@<#H#>¡£
+
+</text/mod-timeout/>
+¶Ô²»Æð£¬<#L#>ÓʼþÁбíµÄ¹ÜÀíÕß²»Äܹ»´¦ÀíÄãͶµÝµÄÓʼþ¡£ÏµÍ³½«ÓʼþÍ˻ظøÄ㣬ÇëÄãÖØÐÂͶµÝÓʼþ»òÓëÓÊ
+¼þÁбíµÄ¹ÜÀíÕßÁªÏµ¡£
+
+--- ËæП½ÉϵÄÊÇͶµÝµ½ÓʼþÁбíµÄµç×ÓÓʼþ¡£
+
+</text/mod-sub-confirm/>
+Óû§!AÇëÇó×¢²á<#l#>ÓʼþÁÐ±í£¬
+ËûµÄÇëÇó±ØÐëµÃµ½ÄãµÄÈ·ÈϺó²ÅÄÜÍê³É£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+Èç¹ûÄã²»ÏëÈÃÓû§×¢²áÓʼþÁÐ±í£¬ÄãÖ»ÒªºöÂÔÕâ·âÓʼþ¾Í¿ÉÒÔÁË¡£
+
+ллÄãµÄ°ïÖú£¡
+
+</text/mod-unsub-confirm/>
+Óû§!AÇëÇóÈ¡Ïû×¢²á<#l#>ÓʼþÁÐ±í£¬
+ËûµÄÇëÇó±ØÐëµÃµ½ÄãµÄÈ·ÈϺó²ÅÄÜÍê³É£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+Èç¹ûÄã²»ÏëÈÃÓû§´ÓÓʼþÁбíÖÐÈ¡Ïû×¢²á£¬ÄãÖ»ÒªºöÂÔÕâ·âÓʼþ¾Í¿ÉÒÔÁË¡£
+
+ллÄãµÄ°ïÖú£¡
+
+</text/sub-bad/>
+ÓÃÓÚÈ·Èϵıê¼ÇÊÇ·Ç·¨µÄ¡£
+
+×î´óµÄ¿ÉÄÜÐÔÊÇÒòΪ±ê¼ÇÒѾ­¹ýÆÚ¡£ÓÃÓÚÈ·Èϵıê¼ÇÔÚ10ÌìÄÚÊÇÓÐЧµÄ¡£»¹ÓÐÒ»ÖÖ¿ÉÄÜÊÇÒòΪÓÃÓÚ
+È·ÈϵĻظ´Óʼþ²¢Ã»ÓаüÀ¨ËùÓеÄÈ·ÈÏÐÅÏ¢¡£
+
+ϵͳÒѾ­Éú³ÉÁËÒ»¸öеÄÈ·Èϱê¼Ç¡£Íê³ÉÈ·ÈÏ
+
+!A
+
+¼ÓÈë<#l#>ÓʼþÁÐ±í£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+×¢Ò⣬ÔÚÄãÈ·ÈÏÄãµÄ×¢²áÒÔÇ°ÇëºË¶Ô»Ø¸´µØÖ·¡£
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm/>
+ΪÁËÍê³É×¢²á<#l#>ÓʼþÁÐ±í£¬ÄãÐèҪȷÈÏÏÂÃæµÄµØÖ·ÊÇ·ñÕýÈ·
+
+!A
+
+ΪÁËÍê³ÉÈ·ÈÏ£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+ͨ¹ýÈ·ÈÏ£¬ÏµÍ³¿ÉÒÔ£º
+1.È·ÈÏÊÇ·ñÄܹ»´ÓÄãµÄµç×ÓÓʼþµØÖ·ÊÕµ½Óʼþ¡£
+2.ËüÄܹ»·ÀֹijЩÈËðÓÃÄãµÄÃûÒå½øÐÐ×¢²á¡£
+
+</#q/>
+ÓÐЩµç×ÓÓʼþµÄ¿Í»§¶Ë³ÌÐò²»Äܹ»½âÎöºÜ³¤µÄµØÖ·¡£Èç¹ûÄã²»Äܹ»Ö±½Ó»Ø¸´Õâ·âµç×ÓÓʼþ£¬Äã¿É
+ÒÔÏò<<#L#>-request@<#H#>>·¢ËÍÓʼþ²¢½«ÉÏÃæµÄµØÖ··ÅÔÚÓʼþµÄÖ÷ÌâÖС£
+
+</text/sub-confirm#s/>
+Õâ¸öÓʼþÁбíµÄ×¢²áÊÇÐèÒª¾­¹ýÓʼþÁбíµÄ¹ÜÀíÕßÅú×¼µÄ¡£Ò»µ©Äã»Ø¸´ÁËÈ·ÈÏÐÅ£¬×¢²áÇëÇó½«Ö±
+½Ó·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß¡£ÏµÍ³½«Í¨ÖªÄãµ±ÓʼþÁбíµÄ¹ÜÀíÕßͬÒâÄã¼ÓÈëÓʼþÁÐ±í¡£
+
+</text/sub-nop/>
+ÏÂÃæµÄµç×ÓÓʼþµØÖ·
+
+!A
+
+ÒѾ­ÊÇ<#l#>ÓʼþÁбíµÄ×¢²áÓû§¡£Äã²»ÄÜÖظ´×¢²áÒ»¸öÓʼþÁÐ±í¡£
+
+</text/sub-ok#E/>
+ÏÂÃæµÄµç×ÓÓʼþµØÖ·
+
+!A
+
+ÒѾ­³É¹¦µÄ×¢²á<#l#>ÓʼþÁÐ±í¡£
+
+»¶Ó­¼ÓÈë<#l#>@<#H#>ÓʼþÁбí!
+
+ÇëÄã±£´æÕâ·âµç×ÓÓʼþ£¬ÒÔ±ãÒÔºóÈ¡Ïû×¢²á»ò¸Ä±ä×¢²áµÄµç×ÓÓʼþµØÖ·¡£
+
+</text/top/>
+ÓʼþÁбíµÄÃû³ÆÊÇ£º<#l#>@<#H#>
+
+</#x/>
+ÓʼþÁбíËùÓÐÕߵĵç×ÓÓʼþµØÖ·£º<#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+ÓÃÓÚÈ·Èϵıê¼ÇÊÇ·Ç·¨µÄ¡£
+
+×î´óµÄ¿ÉÄÜÐÔÊÇÒòΪ±ê¼ÇÒѾ­¹ýÆÚ¡£ÓÃÓÚÈ·Èϵıê¼ÇÔÚ10ÌìÄÚÊÇÓÐЧµÄ¡£»¹ÓÐÒ»ÖÖ¿ÉÄÜÊÇÒòΪÓÃÓÚ
+È·ÈϵĻظ´Óʼþ²¢Ã»ÓаüÀ¨ËùÓеÄÈ·Èϱê¼Ç¡£
+
+ϵͳÒѾ­Éú³ÉÁËÒ»¸öеÄÈ·Èϱê¼Ç¡£Íê³ÉÈ·ÈÏ
+
+!A
+
+´Ó<#l#>ÓʼþÁбíÖÐɾ³ý£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+×¢Ò⣬ÔÚÄãÈ·ÈÏÈ¡ÏûÄãµÄ×¢²áÒÔÇ°ÇëºË¶Ô»Ø¸´µØÖ·¡£
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm/>
+ΪÁËÍê³É´Ó<#l#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á£¬ÄãÐèҪȷÈÏÏÂÃæµÄµØÖ·ÊÇ·ñÕýÈ·
+
+!A
+
+ΪÁËÍê³ÉÈ·ÈÏ£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£
+</#x/>
+
+ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º
+       mailto:<#R#>
+<//>
+
+ϵͳ²»ÄÜÈ·ÈÏÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñÊÇÓʼþÁбíµÄ×¢²áÓû§¡£Äã¿ÉÒÔʹÓÃÏÂÃæµÄ·½·¨»ñµÃÄãʹÓÃʲô
+µØÖ·×¢²áÓʼþÁÐ±í£ºÔÚÄãÊÕµ½µÄ´ÓÓʼþÁÐ±í·¢Ë͵ĵç×ÓÓʼþÖУ¬Ã¿¸öµç×ÓÓʼþµÄÍ˻ط¾¶
+£¨Return path£©ÖаüÀ¨ÁËÄã×¢²áÓõĵç×ÓÓʼþµØÖ·£¬ÀýÈ磬mary@xdd.ff.comÊÕµ½µÄµç×ÓÓʼþÖаü
+À¨µÄÍ˻ط¾¶£¨Return path£©ÊÇ<<#l#>-return-<number>-mary=xdd.ff.com@<#H#>¡£
+
+</#q/>
+ÓÐЩµç×ÓÓʼþµÄ¿Í»§¶Ë³ÌÐò²»Äܹ»½âÎöºÜ³¤µÄµØÖ·¡£Èç¹ûÄã²»Äܹ»Ö±½Ó»Ø¸´Õâ·âµç×ÓÓʼþ£¬Äã¿ÉÒÔÏò
+<<#L#>-request@<#H#>>·¢ËÍÓʼþ²¢½«ÉÏÃæµÄµØÖ··ÅÔÚÓʼþµÄÖ÷ÌâÖС£
+
+</text/unsub-nop/>
+ÏÂÃæµÄµç×ÓÓʼþµØÖ·
+
+!A
+
+²¢Ã»ÓÐ×¢²á<#l#>ÓʼþÁÐ±í¡£
+
+Èç¹ûÄãÒѾ­È¡Ïû×¢²á£¬µ«ÊÇÄ㻹ÊÇÊÕµ½´ÓÓʼþÁÐ±í·¢ËÍÀ´µÃµÄµç×ÓÓʼþ£¬ÇëÄãºË¶ÔÕâ·âÓʼþµÄ£º
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+ÄãÖ»Òª½«µç×ÓÓʼþ·¢Ë͵½£º
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+¾ÍÄܹ»È¡Ïû×¢²á£¬¡®user=host.dom¡¯ÊÇÄãµÄµç×ÓÓʼþµØÖ·£¬ÔÚÕâ·âÓʼþ·¢³öºó£¬Ä㽫ÊÕµ½ÏµÍ³·¢
+Ë͵ÄÓйØÈ¡Ïû×¢²áµÄÈ·ÈÏÐÅ£¬ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ¡Ïû×¢²á£¬×îºóϵͳ½«ÏòÄã·¢ËÍÈ¡Ïû
+×¢²á³É¹¦µÄµç×ÓÓʼþ¡£
+
+Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκÎÎÊÌ⣬Ç뽫µç×ÓÓʼþ·¢Ë͵½£º
+
+    <#l#>-owner@<#H#>
+
+Ëû¸ºÔð¹ÜÀíÕâ¸öÓʼþÁÐ±í¡£
+
+</text/unsub-ok/>
+ÏÂÃæµÄµØÖ·
+
+!A
+
+ÒѾ­³É¹¦µÄ´Ó<#l#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á¡£
+
+</text/edit-do#n/>
+ÇëÄã±à¼­ÏÂÃæµÄÎļþ²¢½«ËûÃÇ·¢Ë͵½ÏÂÃæµÄµØÖ·£º
+
+!R
+
+ÒÔ'%%%'¿ªÊ¼µÄÎÄ×ÖÊDz»Äܹ»±à¼­µÄ¡£
+
+
+</text/edit-list#n/>
+<#L#>-edit.file ÕßÌõÃüÁî¿ÉÒÔÓÃÓÚÔ¶³ÌµÄ±à¼­<#L#>@<#H#>ÓʼþÁбíµÄ¸÷ÖÖ¿ØÖÆ
+Îļþ¡£
+
+ÏÂÃæÊÇÄã¿ÉÒÔͨ¹ýµç×ÓÓʼþµÄ·½Ê½±à¼­µÄÎļþµÄÃû³Æ¡£ÄãÖ»Òª½«ÐèÒª±à¼­µÄÎļþ·¢Ë͵½<#L#>-edit.file
+¾ÍÄÜÍê³É±à¼­¡£
+
+ÎļþÃû              ÓÃ;
+
+bottom              Ìí¼ÓÔÚϵͳ×Ô¶¯·´À¡Óʼþβ²¿µÄÐÅÏ¢¡£
+digest              ÕªÒª´¦ÀíµÄÐÅÏ¢¡£
+faq                 ÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð¡£
+get_bad             ÔÚÓʼþÁбíµÄÀúÊ·ÎĵµÖÐûÓз¢ÏÖÎĵµµÄÐÅÏ¢¡£
+help                ÓʼþÁбíµÄ°ïÖúÎļþ¡£
+info                ÓʼþÁбíµÄÐÅÏ¢Îļþ£¬ÓÃÓÚ½éÉÜÕâ¸öÓʼþÁбíµÄÖ÷ÒªÓÃ;¡£
+mod_help            ÓʼþÁбí¹ÜÀíÕߵİïÖúÎļþ¡£
+mod_reject          ·¢Ë͸ø·¢ÐÅÈ˾ܾøͶµÝµÄÐÅÏ¢¡£
+mod_request         ·¢Ë͸øÓʼþÁбíÕßµÄÇëÇóÐÅÏ¢¡£
+mod_sub             ÔÚÓʼþÁбí¹ÜÀíÕßͬÒâÄãµÄ×¢²áºó·¢Ë͸øÓû§µÄÐÅÏ¢¡£
+mod_sub_confirm     ·¢Ë͸øÓʼþÁбí¹ÜÀíÕßÒªÇóÈ·ÈÏijÓû§×¢²áµÄÐÅÏ¢¡£
+mod_timeout         ·¢Ë͸ø·¢ÐÅÈ˳¬Ê±Í¶µÝµÄÐÅÏ¢¡£
+mod_unsub_confirm   ·¢Ë͸øÓʼþÁбí¹ÜÀíÕßÒªÇóÈ·ÈÏijÓû§È¡Ïû×¢²áµÄÐÅÏ¢¡£
+sub_bad             Èç¹û×¢²áµÄÈ·ÈÏÐÅÏ¢Ë𻵣¬·¢Ë͸øÓû§µÄÐÅÏ¢¡£
+sub_confirm         ÐèÒªÓû§È·ÈϵÄ×¢²áÐÅÏ¢¡£
+sub_nop             ·¢Ë͸øÖظ´×¢²áÓû§×¢²áÁбíµÄÐÅÏ¢¡£
+sub_ok              ×¢²á³É¹¦ºóµÄ·¢Ë͸øÓû§µÄÐÅÏ¢¡£
+top                 Ìí¼ÓÔÚϵͳ×Ô¶¯·´À¡Óʼþ¶¥²¿µÄÐÅÏ¢¡£
+</#tn/>
+trailer             Ìí¼ÓÔÚÓʼþÁбíת·¢Óʼþβ²¿µÄÐÅÏ¢¡£
+</#n/>
+unsub_bad           Èç¹ûÈ¡Ïû×¢²áµÄÈ·ÈÏÐÅÏ¢Ë𻵣¬·¢Ë͸øÓû§µÄÐÅÏ¢¡£
+unsub_confirm       ÐèÒªÓû§È·ÈϵÄÈ¡Ïû×¢²áÐÅÏ¢¡£
+unsub_nop           ·¢Ë͸ø²»ÊÇÓʼþÁбí×¢²áÓû§ÒªÇóÈ¡Ïû×¢²áÓʼþÁбíµÄÐÅÏ¢¡£
+unsub_ok            È¡Ïû×¢²á³É¹¦ºó·¢Ë͸øÓû§µÄÐÅÏ¢¡£
+
+</text/edit-done#n/>
+ÒѾ­³É¹¦µÄ¸üÐÂÅäÖÃÎļþ¡£
+</text/info#E/>
+ÓʼþÁбíµÄ½éÉÜÎļþ²»´æÔÚ¡£
+</text/faq#E/>
+FAQ - ÓйØ<#l#>ÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð¡£
+
diff --git a/ezmlmrc.cs b/ezmlmrc.cs
new file mode 100644 (file)
index 0000000..7620bec
--- /dev/null
@@ -0,0 +1,1097 @@
+#$Id: ezmlmrc.cs,v 1.8 1999/05/11 03:28:11 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+# Use Quoted-Printable to make averyone happy.
+iso-8859-2:Q
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Omlovám se, ale mám pøíkaz odmítnout pøíspìvky od vás. Kontaktujte <#L#>-owner@<#H#>, máte-li dotazy k tomuto faktu (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Omlouvám se, ale do tohoto listu smìjí pøispívat pouze pøihlá¹ení u¾ivatelé. Jste-li pøihlá¹eným u¾ivatelem, pøepo¹lete tuto zprávu na adresu <#L#>-owner@<#H#>, aby akceptoval va¹i novou adresu (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+List-Post: <mailto:<#L#>@<#H#>>
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+Pro odhlá¹ení, po¹lete mail na <#L#>-unsubscribe@<#H#>
+Dal¹í pøíkazy vypí¹e e-mail: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Administrativní pøíkazy pro list <#l#> ---
+
+Umím automaticky obsluhovat administrativní pøíkazy. Neposílejte
+je prosím do listu! Po¹lete zprávu na adresu pøíslu¹ného pøíkazu:
+
+Pro pøihlá¹ení do listu, po¹lete e-mail na adresu:
+   <<#L#>-subscribe@<#H#>>
+
+Pro odhlá¹ení se z listu pou¾ijte adresu
+   <<#L#>-unsubscribe@<#H#>>
+
+Informace o listu a FAQ (èasto kladené dotazy) získáte zasláním dopisu
+na následující adresy:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#d/>
+Podobné adresy existují i pro list digestù:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+Zprávy èíslo 123 a¾ 145 z archívu (maximálnì 100 zpráv na jeden mail)
+získáte zasláním zprávy na následující adresu:
+   <<#L#>-get.123_145@<#H#>>
+
+</text/bottom#aI/>
+Zprávu èíslo 12 získáte pomocí následující adresy:
+   <<#L#>-get.12@<#H#>>
+
+</text/bottom#i/>
+Seznam zpráv se subjectem a autorem zpráv 123-456 - e-mail:
+   <<#L#>-index.123_456@<#H#>>
+
+Tyto adresy v¾dy vrací seznam 100 zpráv, maximálnì 2000 na jeden po¾adavek.
+Tak¾e ve vý¹e uvedeném pøíkladì ve skuteènosti dostanete seznam zpráv 100-499.
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+Pro získání zpráv se stejným subjectem jako zpráva 12345 po¹lete
+prázdný mail na adresu:
+   <<#L#>-thread.12345@<#H#>>
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+Zprávy ve skuteènosti nemusí být prázdné - budu jejich obsah ignorovat.
+Jediná dùle¾itá vìc je ADRESA na kterou mail posíláte.
+
+Mù¾ete se také do listu pøihlásit pod jinou adresou - napøíklad
+"pepa@domena.cz". Staèí pøidat pomlèku a novou adresu s rovnítkem (=)
+namísto zavináèe:
+<<#L#>-subscribe-pepa=domena.cz@<#H#>>
+
+Odhlásit tuto adresu lze pomocí mailu na adresu
+<<#L#>-unsubscribe-pepa=domena.cz@<#H#>>
+
+V obou pøípadech po¹lu ¾ádost o souhlas na tuto adresu. Kdy¾ ji dostanete,
+jednodu¹e na ni odpovìzte a va¹e pøihlá¹ení/odhlá¹ení se dokonèí.
+
+</text/bottom/>
+Pokud nedosáhnete po¾adovaných výsledkù, kontaktujte mého správce
+na adrese <#L#>-owner@<#H#>. Prosím o trpìlivost, mùj správce je
+podstatnì pomalej¹í ne¾ já ;-)
+</text/bottom/>
+
+--- Pøipojuji kopii po¾adavku, který jsem dostal.
+
+</text/bounce-bottom/>
+
+--- Pøipojuji kopii zprávy, která se mi vrátila.
+
+</text/bounce-num/>
+
+Uschoval jsem si seznam zpráv z listu <#L#>, které se z va¹í adresy
+vrátily.
+
+</#a/>
+Kopie tìchto zpráv mù¾ete získat v archívu.
+</#aI/>
+Pro získání zprávy 12345 z archívu, po¹lete prázdný mail na adresu
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Zprávy èíslo 123 a¾ 145 získáte z archívu (maximálnì 100 zpráv na jeden mail)
+získáte zasláním zprávy na následující adresu:
+   <<#L#>-get.123_145@<#H#>>
+
+Seznam zpráv se subjectem a autorem zpráv 123-456 - e-mail:
+   <<#L#>-index@<#H#>>
+
+<//>
+Následují èísla zpráv:
+
+</text/dig-bounce-num/>
+
+Uschoval jsem èísla digestù z listu <#L#>-digest, které se vrátily
+z va¹í adresy. Pro ka¾dý takový digest jsem si zapamatoval èíslo
+první zprávy v digestu. Nearchivuji si digesty samotné, ale
+mù¾ete si vy¾ádat jednotlivé zprávy z archívu hlavního listu.
+
+</#aI/>
+
+Pro získání zprávy 12345 z archívu, po¹lete prázdný mail na adresu
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Zprávy èíslo 123 a¾ 145 získáte z archívu (maximálnì 100 zpráv na jeden mail)
+získáte zasláním zprávy na následující adresu:
+   <<#L#>-get.123_145@<#H#>>
+
+Seznam zpráv se subjectem a autorem zpráv 123-456 - e-mail:
+   <<#L#>-index@<#H#>>
+
+<//>
+Následují èísla prvních zpráv v digestech:
+
+</text/bounce-probe/>
+
+Vracejí se mi zprávy pro vás z listu <#l#>.
+Poslal jsem vám varovnou zprávu, ale ta se také vrátila.
+Pøipojuji kopii varovné zprávy.
+
+Toto je testovací zpráva pro ovìøení, jestli je va¹e adresa dosa¾itelná.
+Pokud se tato zpráva vrátí, zru¹ím va¹i adresu z listu <#l#>@<#H#>
+bez dal¹ího upozornìní. Mù¾ete se pøihlásit znovu posláním prázdné zprávy
+na adresu
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+Vracejí se mi zprávy pro vás z listu <#l#>.
+Pøipojuji kopii první vrácené zprávy, kterou jsem dostal.
+
+Pokud se tato zpráva také vrátí, po¹lu testovací zprávu.
+Pokud se vrátí i testovací zpráva, zru¹ím va¹i adresu z listu <#l#>
+bez dal¹ího upozornìní.
+
+</text/digest#d/>
+Pro pøihlá¹ení do digestu po¹lete mail na adresu
+       <#L#>-digest-subscribe@<#H#>
+
+Pro odhlá¹ení z digestu pou¾ijte adresu
+       <#L#>-digest-unsubscribe@<#H#>
+
+Chcete-li poslat zprávu do listu, pi¹te na adresu
+       <#L#>@<#H#>
+
+</text/get-bad/>
+Promiòte, ale tato zpráva v archívu není.
+
+</text/help/>
+Toto je zpráva se v¹eobecnou nápovìdou. Zpráva, kterou jsem dostal,
+nebyla poslána na ¾ádnou z adres platných pro zasílání pøíkazù.
+
+</text/mod-help/>
+Dìkuji, ¾e jste se uvoli moderovat nebo spravovat list <#L#>@<#H#>.
+
+Moje pøíkazy jsou ponìkud odli¹nìj¹í od jiných listù, ale myslím,
+¾e je seznáte intuitivními a pøíjemnými k pou¾ití.
+
+Tady jsou instrukce pro èinnosti, které pøípadnì mù¾ete vykonávat
+jako správce listu nebo moderátor.
+
+Vzdálené pøihlá¹ení
+-------------------
+
+Jako moderátor mù¾ete pøihla¹ovat a odhla¹ovat libovolnou adresu
+do svého listu. Pro pøihlá¹ení u¾ivatele "pepa@domena.cz" jednodu¹e
+doplòte pomlèku za název pøíkazu a pak tuto adres s rovnítkem
+místo zavináèe. Napøíklad pro pøihlá¹ení vý¹e uvedené adresy
+po¹lete mail na adresu
+   <<#L#>-subscribe-pepa=domena.cz@<#H#>>
+
+Podobnì mù¾ete odhla¹ovat u¾ivatele pomocí mailu na adresu
+   <<#L#>-unsubscribe-pepa=domena.cz@<#H#>>
+
+</#d/>
+Pro digestový list:
+   <<#L#>-digest-subscribe-pepa=domena.cz@<#H#>>
+   <<#L#>-digest-unsubscribe-pepa=domena.cz@<#H#>>
+
+<//>
+To je v¹echno. ®ádný speciální subject ani obsah zprávy není potøeba!
+
+</#r/>
+Po¹lu vám ¾ádost o potvrzení, abych se ujistil, ¾e po¾adavek
+opravdu pochází od vás. Jednodu¹e odpovìzte na mail,
+který obdr¾íte a vá¹ pøíkaz se vykoná.
+</#R/>
+Po¹lu ¾ádost o potvrzení, v tomto pøípadì na adresu <pepa@domena.cz>.
+V¹echno co bude muset udìlat u¾ivatel je odpovìdìt na tuto
+¾ádost.
+<//>
+
+Potvrzení jsou nezbytná, aby se tøetím stranám co nejvíce
+ztí¾ila mo¾nost pøidávat a ru¹it cizí adresu do/z listu.
+
+Uvìdomuji u¾ivatele, kdy¾ se stav jeho pøihlá¹ení zmìní.
+
+Pøihlá¹ení
+----------
+
+Libovolný u¾ivatel se smí pøihla¹ovat a odhla¹ovat do/z listu
+zasláním zprávy na adresu
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+Pro digestový list:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+U¾ivatel obdr¾í ¾ádost o potvrzení, abych se ujistil,
+¾e mu skuteènì daná adresa patøí. Jakmile se toto ovìøí,
+u¾ivatel je odhlá¹en.
+
+</#s/>
+Proto¾e toto je list s moderovaným pøihlá¹ením, po¹lu dal¹í
+¾ádost o potvrzení moderátorovi. Proto¾e u¾ivatel ji¾ potvrdil
+pøání být na listu, mù¾ete si jako moderátor být dostateènì jist,
+¾e adresa pøihla¹ovaného je skuteèná. Pokud chcete pøijmout
+u¾ivatelovu ¾ádost, jednodu¹e po¹lete odpovìï na tuto zprávu.
+Pokud ne, sma¾te tuto zprávu a pøípadnì kontaktujte u¾ivatele
+pro dal¹í informace.
+</#S/>
+Pøihlíá¹ení funguje stejnì.
+<//>
+
+U¾ivatel také mù¾e pou¾ít adresu
+
+   <<#L#>-subscribe-jana=domena.cz@<#H#>>
+   <<#L#>-unsubscribe-jana=domena.cz@<#H#>>
+
+pro zaslání mailu pro "jana@domena.cz". Pokud tato skuteènì má
+vý¹e uvedenou adresu, obdr¾í ¾ádost o potvrzení a mù¾e ji
+potvrdit.
+
+Va¹e adresa a identita není otevøena pøihlá¹enému, pokud mu sám
+nepo¹lete mail.
+
+</#rl/>
+Pro získání seznamu pøihlá¹ených pro list <#L#>@<#H#>, po¹lete
+zprávu na adresu
+   <<#L#>-list@<#H#>>
+
+Seznam provedených transakcí listu <#L#>@<#H#> získáte z adresy
+   <<#L#>-list@<#H#>>
+
+</#rld/>
+Pro pøihlá¹ené do digestu:
+   <<#L#>-digest-list@<#H#>>
+a
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Mù¾ete vzdálenì editovat textové soubory, ze kterých se sestavují
+odpovìdi, které posílám. Chcete-li získat seznam editovatelných souborù
+a pokyny pro editaci, napi¹te na adresu
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+Moderované pøíspìvky
+--------------------
+
+Pokud je list moderovaný, ulo¾ím si zprávy, které obdr¾ím a po¹lu vám
+kopii a instrukce. Zpráva pro vás bude mít subject "MODERATE for ...".
+
+Chcete-li zprávu pøijmout, staèí poslat odpovìï (na adresu v "Reply-To:"),
+kterou nastavím na pøíkaz pro pøijetí zprávy do listu. Nemusíte 
+posílat obsah pùvodní zprávy. Ve skuteènosti ignoruji cokoli, co mi
+po¹lete, pokud bude adresa, na kterou to po¹lete, korektní.
+
+Pokud chcete zprávu odmítnout, po¹lete odpovìï na adresu ve "From:",
+kterou nastavím na pøíkaz pro odmítnutí zprávy. Toto se obvykle udìlá
+pøíkazem "Odpovìz v¹em" ve va¹em po¹tovním klientovi, pøièem¾
+sma¾ete v¹echny ostatní adresy kromì adresy pro odmítnutí (reject).
+Mù¾ete pøidat komentáø odesílateli - napi¹te jej mezi dva øádky,
+zaèínající tøema znaky "%". Po¹lu autorovi pouze tento komentáø,
+co¾ neprozradí va¹i identitu.
+
+Se zprávou nalo¾ím podle první odpovìdi, kterou dostanu.
+Uvìdomím vás, pokud mi po¹lete po¾adavek na potvrzení ji¾
+odmítnuté zprávy a naopak,
+
+Pokud nedostanu odpovìï od moderátora do urèité doby (implicitnì 5 dní),
+vrátím zprávu odesílateli s vysvìtlením, ¾e byla odmítnuta.
+Jako administrátor mù¾ete také list nastavit tak, ¾e ignorované
+zprávy jsou jednodu¹e smazány bez upozornìní odesílateli.
+<//>
+
+Dovolená
+--------
+Pokud jste doèasnì na jiné adrese, staèí si pøeposlat v¹echny zprávy,
+které mají správnou hlavièku "Mailing-List:" (nebo v¹echny se subjectem
+"MODERATE for <#L#>@<#H#>" (nebo "CONFIRM subscribe to <#L#>@<#H#>")
+na novou adresu. Mù¾ete také pøeposílat tyto zprávy pøíteli, který
+bude moderovat za vás. Prosím uvìdomte o tomto také správce listserveru.
+
+Pokud chcete automaticky potvrdit v¹echny po¾adavky bìhem své nepøítomnosti,
+nastavte si po¹tovního klienta na posílání automatických odpovìdí na zprávy,
+které splòují vý¹e uvedená kritéria.
+
+</#r/>
+Pokud zkusíte dìlat vzdálenou administraci z adresy, která není
+va¹e vlastní, bude o potvrzení po¾ádán u¾ivatel, nikoli vy.
+Po schválení u¾ivatelem po¹lu ¾ádost o potvrzení v¹em moderátorùm.
+Toto dìlám proto, ¾e nemám zpùsob, jak zjistit, ¾e jste to skuteènì vy,
+kdo poslal pùvodní po¾adavek.
+
+Berte také na vìdomí, ¾e v tomto pøípadì je vá¹ pùvodní po¾adavek
+(vèetnì va¹í adresy!) zaslán u¾ivateli s ¾ádostí o potvrzení.
+<//>
+
+Mnoho ¹tìstí!
+
+PS: Prosím kontaktujte správce listu (<#L#>-owner@<#H#>),
+budete-li mít dotazy nebo problémy.
+
+</text/mod-reject/>
+Je mi líto, ale va¹e ní¾e citované zpráva nebyla potvrzena moderátorem.
+Pokud moderátor pøipojil nìjaký komentáø, uvádím jej ní¾e.
+</text/mod-request/>
+Ní¾e citovaná zpráva byla zaslána na adresu listu <#L#>@<#H#>.
+Pokud souhlasíte s distribucí této zprávy v¹em pøihlá¹eným, po¹lete
+mail na adresu
+
+!A
+
+Toho obvykle dosáhnete pomocí tlaèítka "Odpovìï/Reply". Mù¾ete zkontrolovat
+adresu, zaèíná-li øetìzcem "<#L#>-accept". Pokud toto nefunguje, staèí
+zkopírovat adresu a ulo¾it ji do políèka "To:" nové zprávy.
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#A#>
+<//>
+
+Chcete-li zprávu odmítnout a zpùsobit její vrácení odesílateli,
+po¹lete zprávu na adresu
+
+!R
+
+Toto se bvykle nejsnáze udìlá pomocí tlaèítka "Odpovìz v¹em/Reply to all"
+a následného vymazání v¹ech adres kromì té, která zaèíná "<#L#>-reject".
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Není tøeba kopírovat zprávu ve svém potvrzení nebo odmítnutí této zprávy.
+Chcete-li poslat komentáø odesílateli odmítnuté zprávy, doplòte jej
+mezi následující øádky zaèínající tøemi znaky "%":
+
+%%% Zaèátek komentáøe
+%%% Konec komentáøe
+
+Dìkuji za spolupráci.
+
+--- Dále uvádím zaslanou zprávu.
+
+</text/mod-sub#E/>
+--- Pøihlásil nebo odhlásil jsem vás na ¾ádost moderátora
+listu <#l#>@<#H#>.
+
+Pokud to není akce, se kterou souhlasíte, po¹lete co nejdøíve
+stí¾nost nebo dal¹í komentáøe správci listu (<#l#>-owner@<#H#>).
+
+Chcete-li získat podrobnìj¹í návod pro práci s listem <#L#>, po¹lete
+prázdnou zprávu na adresu
+<#L#>-help@<#H#>.
+
+</text/mod-timeout/>
+Je mi líto, ale moderátor listu <#L#> nezareagoval na vá¹ pøíspìvek.
+Tento tedy pova¾uji za odmítnutý a vracím vám jej. Pokud máte pocit,
+¾e do¹lo k chybì, obra»te se pøímo na moderátora listu.
+
+--- Dále uvádím vámi zaslanou zprávu.
+
+</text/mod-sub-confirm/>
+®ádám zdvoøile oprávnìní pøidat adresu
+
+!A
+
+do seznamu ètenáøù listu <#l#>. Po¾adavek vze¹el buïto od vás,
+nebo ji¾ byl ovìøen u potenciálního ètenáøe.
+
+Souhlasíte-li, po¹lete prázdný mail na adresu
+
+!R
+
+Toho obvykle dosáhnete pomocí tlaèítka "Odpovìï/Reply". Mù¾ete zkontrolovat
+adresu, zaèíná-li øetìzcem "<#L#>-sc". Pokud toto nefunguje, staèí
+zkopírovat adresu a ulo¾it ji do políèka "To:" nové zprávy.
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Nesouhlasíte-li, ignorujte tuto zprávu.
+
+Díky za spolupráci!
+
+</text/mod-unsub-confirm/>
+Obdr¾el jsem po¾adavek na zru¹ení adresy
+
+!A
+
+z listu <#l#>. Souhlasíte-li, po¹lete prázdnou odpovìï
+na tuto adresu:
+
+!R
+
+Toho obvykle dosáhnete pomocí tlaèítka "Odpovìï/Reply". Mù¾ete zkontrolovat
+adresu, zaèíná-li øetìzcem "<#L#>-sc". Pokud toto nefunguje, staèí
+zkopírovat adresu a ulo¾it ji do políèka "To:" nové zprávy.
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Nesouhlasíte-li, ignorujte tuto zprávu.
+
+Dìkuji za spolupráci!
+
+</text/sub-bad/>
+Hmmm, tohle èíslo potvrzení nevypadá platnì.
+
+Nejèastìj¹ím dùvodem výskytu neplatných èísel je vypr¹ení èasu.
+Musím dostat odpovìï na ka¾dý po¾adavek nejpozdìji do deseti dnù.
+Ujistìte se také, ¾e v odpovìdi, kterou jsem obdr¾el, bylo _celé_
+èíslo potvrzení. Nìkteré e-mailové programy mohou oøíznout èást
+adresy pro odpovìï, která mù¾e být i dosti dlouhá.
+
+Posílám novou ¾ádost o potvrzení. Pro potvrzení, ¾e chcete pøidat adresu
+
+!A
+
+do listu <#l#>, po¹lete prázdnou odpovìï na adresu
+
+!R
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Je¹tì jednou: ujistìte se, ¾e adresa pro odpovìï je skuteènì v poøádku
+pøedtím, ne¾ potvrdíte tuto ¾ádost.
+
+Omlouvám se za potí¾e.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm/>
+Chcete-li opravdu pøidat adresu
+
+!A
+
+do listu <#l#>, po¹lete prázdnou zprávu na adresu
+
+!R
+
+Toho obvykle dosáhnete pomocí tlaèítka "Odpovìï/Reply". Mù¾ete zkontrolovat
+adresu, zaèíná-li øetìzcem "<#L#>-sc". Pokud toto nefunguje, staèí
+zkopírovat adresu a ulo¾it ji do políèka "To:" nové zprávy.
+
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Vy¾adování tohoto potvrzení má dva dùvody. Za prvé ovìuje, ¾e jsem
+schopen zasílat mail na va¹i adresu. A za druhé, chrání vás v pøípadì,
+¾e nìkdo zfal¹uje ¾ádost o pøihlá¹ení s va¹ím jménem.
+
+</#q/>
+Nìkteré po¹tovní programy jsou chybné a nemohou zpracovávat dlouhé
+adresy. Pokud nemù¾ete odpovìdìt na tuto adresu, po¹lete
+zprávu na adresu <<#L#>-request@<#H#>>
+a vlo¾te celou vý¹e uvedenou adresu do subjectu.
+
+</text/sub-confirm#s/>
+Tento list je moderovaný. Jakmile po¹lete potvrzení, po¾adavek
+bude poslán moderátorovi tohoto listu. Uvìdomím vás, jakmile
+bude pøihlá¹ení hotovo.
+
+</text/sub-nop/>
+Potvrzení: Adresa
+
+!A
+
+byla v ji¾ v listu <#l#>, kdy¾ jsem obdr¾el va¹i ¾ádost,
+a zùstává pøihlá¹ena.
+
+</text/sub-ok#E/>
+Potvrzení: Pøidal jsem adresu
+
+!A
+
+do listu <#l#>.
+
+Vítejte v listu <#l#>@<#H#>!
+
+Prosím uschovejte si tuto zprávu pro informaci, z jaké adresy
+bylo pøihlá¹ení do listu provedeno. Budete ji potøebovat v pøípadì,
+¾e se budete chtít odhlásit nebo zmìnit svoji adresu.
+
+</text/top/>
+Zdravím, tady je program ezmlm. Spravuji diskusní list
+<#l#>@<#H#>.
+
+</#x/>
+Pracuji pro svého správce, který mù¾e být zasti¾en na adrese
+at <#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+Hmmm, tohle èíslo potvrzení nevypadá platnì.
+
+Nejèastìj¹ím dùvodem výskytu neplatných èísel je vypr¹ení èasu.
+Musím dostat odpovìï na ka¾dý po¾adavek nejpozdìji do deseti dnù.
+Ujistìte se také, ¾e v odpovìdi, kterou jsem obdr¾el, bylo _celé_
+èíslo potvrzení. Nìkteré e-mailové programy mohou oøíznout èást
+adresy pro odpovìï, která mù¾e být i dosti dlouhá.
+
+Posílám novou ¾ádost o potvrzení. Pro potvrzení, ¾e chcete zru¹it adresu
+
+!A
+
+do listu <#l#>, po¹lete prázdnou odpovìï na adresu
+
+!R
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+        mailto:<#R#>
+<//>
+
+Je¹tì jednou: ujistìte se, ¾e adresa pro odpovìï je skuteènì v poøádku
+pøedtím, ne¾ potvrdíte tuto ¾ádost.
+
+Omlouvám se za potí¾e.
+
+        <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm/>
+Potvrzujete-li, ¾e chcete adresu
+
+!A
+
+zru¹it z listu <#l#>, po¹lete prázdnou odpovìï na adresu
+
+!R
+
+Toho obvykle dosáhnete pomocí tlaèítka "Odpovìï/Reply". Mù¾ete zkontrolovat
+adresu, zaèíná-li øetìzcem "<#L#>-sc". Pokud toto nefunguje, staèí
+zkopírovat adresu a ulo¾it ji do políèka "To:" nové zprávy.
+</#x/>
+
+Mù¾ete také zkusit kliknout zde:
+       mailto:<#R#>
+<//>
+
+Nekontroloval jsem, je-li va¹e adresa v souèasné dobì na listu.
+Chcete-li zjistit, ze které adresy bylo provedeno pøihlá¹ení,
+podívejte se do zpráv, které dostáváte z listu. Ka¾dá zpráva
+má adresu v návratové cestì:
+<<#l#>-return-<number>-jana=domena.cz@<#H#>.
+
+</#q/>
+Nìkteré po¹tovní programy jsou chybné a nemohou zpracovávat dlouhé
+adresy. Pokud nemù¾ete odpovìdìt na tuto adresu, po¹lete
+zprávu na adresu <<#L#>-request@<#H#>>
+a vlo¾te celou vý¹e uvedenou adresu do subjectu.
+
+</text/unsub-nop/>
+Potvrzení: Adresa
+
+!A
+
+nebyla na listu <#l#> v dobì, kdy jsem obdr¾el
+vá¹ po¾adavek a není na nìm ani teï.
+
+Pokud se odhlásíte, ale stále vám budou chodit dopisy, je pøihlá¹ení
+provedeno pod jinou adresou, ne¾ kterou v souèasné dobì pou¾íváte.
+Podívejte se prosím do hlavièek zpráv na text
+
+"Return-Path: <<#l#>-return-1234-pepa=domena.cz@<#H#>>'
+
+Odhla¹ovací adresa pro tohoto u¾ivatele pak bude
+"<#l#>-unsubscribe-pepa=domena.cz@<#H#>".
+Staèí poslat mail na tuto adresu s tím, ¾e pepa=domena.cz nahradíte
+skuteènými hodnotami. Pak odpovíte na ¾ádost o potvrzení a mìla
+by vám dojít zpráva o odhlá¹ení z listu.
+
+V nìkterých po¹tovních programech si musíte zprávu zobrazit vèetnì
+hlavièek, jinak není hlavièka "Return-Path" viditelná.
+
+Pokud toto stále nefunguje, pak je mi líto, ale nemohu vám pomoci.
+Prosím PREPO©LETE (forward) zprávu z listu spolu s poznámkou o tom,
+èeho se sna¾íte dosáhnout a seznamem adres, ze kterých potenciálnì
+mù¾ete být pøihlá¹en[a] mému správci:
+
+    <#l#>-owner@<#H#>
+
+Tento se bude sna¾it vá¹ problém øe¹it. Mùj správce je tro¹ku pomalej¹í
+ne¾ já, tak¾e prosím o trochu trpìlivosti.
+
+</text/unsub-ok/>
+Potvrzení: Zru¹il jsem adresu
+
+!A
+
+z listu <#l#>. Tato adresa ji¾ dále není v seznamu
+pøihlá¹ených.
+
+</text/edit-do#n/>
+Prosím editujte následující soubor a po¹lete jej na adresu
+
+!R
+
+Vá¹ po¹tovní program by mìl mít tlaèítko "Odpovìï/Reply",
+který tuto adresu pou¾ije automaticky.
+
+Umím dokonce sám smazat citovací znaèky, které vá¹ po¹tovní program
+pøidá pøed text, pokud ov¹em ponecháte znaèkovací øádky samotné.
+
+Tyto øádky zaèínají tøemi znaky procento. Nesmí být modifikovány
+(s výjimkou pøípadných znakù pøed nimi, pøidaných pøipadnì va¹ím
+po¹tovním klientem).
+
+</text/edit-list#n/>
+Pøíkaz <#L#>-edit.soubor mù¾e být pou¾it vzdáleným správcem k editaci
+textových souborù, ze kterých se skládají odpovìdi pro list <#L#>@<#H#>.
+
+Následuje seznam pøíslu¹ných souborù a krátký popis toho, kdy je
+jejich obsah vyu¾íván. Chcete-li editovat soubor, staèí poslat
+mail na adresu <#L#>-edit.soubor, pøièem¾ je nutno "soubor"
+nahradit skuteèným jménem souboru. Obdr¾íte soubor spolu s instrukcemi,
+jak tento soubor editovat.
+
+Soubor              Pou¾ití
+
+bottom              pøidává se za ka¾dou odpovìï. V¹eobecné informace.
+digest              "administrativní" èást digestù.
+faq                 èasto kladené dotazy, specifické pro tento list.
+get_bad             neni-li zpráva nalezena v archívu.
+help                v¹eobecná nápovìda (mezi "top" a "bottom").
+info                informace o listu. První øádek by mìl dávat smysl sám o sobì.
+mod_help            nápovìda pro moderátory.
+mod_reject          odesílateli odmítnuté zprávy.
+mod_request         moderátorovi spolu s pøíspìvkem.
+mod_sub             pøihla¹ovanému, jakmile jeho pøihlá¹ení potvrdí moderátor.
+mod_sub_confirm     moderátorovi s ¾ádostí o potvrzení pøihlá¹ení.
+mod_timeout         odesílateli, nestihne-li moderátor potvrdit zprávu.
+mod_unsub_confirm   administrátorovi s ¾ádostí o potvrzení odhlá¹ení.
+sub_bad             odesílateli, bylo-li pøihlá¹ení neplatné.
+sub_confirm         odesílateli - ¾ádost potvrzení pøihlá¹ení.
+sub_nop             odesílateli - pøi pokusu o opìtovné pøihlá¹ení
+sub_ok              odesílateli - oznamuje pøihlá¹ení.
+top                 zaèátek v¹ech odpovìdí.
+</#tn/>
+trailer             pøidá se za ka¾dý pøíspìvek do listu.
+</#n/>
+unsub_bad           odesílateli, byla li ¾ádost o odhlá¹ení neplatná.
+unsub_confirm       odesílateli - ¾ádost o potvrzení odhlá¹ení.
+unsub_nop           odesílateli - nebyl-li pøihlá¹en a sna¾il-li se odhlásit.
+unsub_ok            odesílateli po úspì¹ném odhlá¹ení.
+
+</text/edit-done#n/>
+Textový soubor byl úspì¹nì upraven.
+</text/info#E/>
+®ádná informace nebyla k tomuto listu poskytnuta.
+</text/faq#E/>
+FAQ - Èasto kladené dotazy v listu <#l#>@<#H#>.
+
+[ ®ádné zatím nejsou dostupné ]
+
+
diff --git a/ezmlmrc.da b/ezmlmrc.da
new file mode 100644 (file)
index 0000000..8733272
--- /dev/null
@@ -0,0 +1,1097 @@
+0.324 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.da,v 1.17 1999/12/23 23:08:19 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+# Use Quoted-Printable to make averyone happy.
+iso-8859-1:Q
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Desværre. Jeg har fået instruktion om at afvise post fra dig. Kontakt <#L#>-owner@<#H#> hvis du mener der må være sket en fejl (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Beklager, kun tilmeldte må poste. Hvis du er tilmeldt under et andet navn, videresend venligst dette brev til <#L#>-owner@<#H#> så din nye adresse kan blive tilmeldt (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+list-help: <mailto:<#l#>-help@<#h#>>
+list-unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+list-post: <mailto:<#L#>@<#H#>>
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+Vil du fjernes fra listen, så skriv til: <#L#>-unsubscribe@<#H#>
+Vil du have en kommandooversigt, skriv til: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Kommandooversigt:
+
+Jeg kan håndtere administrative forespørgsler automatisk.
+De må IKKE sendes til <#L#>, da de så kommer ud til
+alle tilmeldte på listen (og det virker ikke).
+Send blot et brev uden indhold til en af adresserne som eksemplerne
+viser:
+
+Tilmelding: send et tomt brev til:
+   <<#L#>-subscribe@<#H#>>
+
+Framelding: send et tomt brev til:
+   <<#L#>-unsubscribe@<#H#>>
+
+Send email til følgende for at få info eller FAQ for denne liste:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+  
+
+</#d/>
+Lignende adresser findes for udtræks listen:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+Hent alle brevene i intervallet 123 til 145 (max. 100 ad gangen),
+send et tomt brev til:
+   <<#L#>-get.123_145@<#H#>>
+
+</text/bottom#aI/>
+Hent brev nummer 12, send et tomt brev til:
+   <<#L#>-get.12@<#H#>>
+
+</text/bottom#i/>
+Hent en oversigt over breve i intervallet 123 til 456, send et
+tomt brev til:
+   <<#L#>-index.123_456@<#H#>>
+
+Resultatet kommer i breve med hundrede titler pr. brev,
+max. 2000 i alt, så eksemplet vil vise dig brev 100 til 499.
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+Hent alle breve med samme emne som brev 123:
+   <<#L#>-thread.123@<#H#>>
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+Dine administrative breve behøver ikke at være tomme, men deres
+indhold vil blive ignoreret. Kommandoen ligger alene i
+modtageradressen 
+
+Hvis du vil tilmelde dig med en anden adresse end den du skriver
+fra, f.eks. jens@ferieby.dk, skal du skrive til:
+<<#L#>-subscribe-jens=ferieby.dk@<#H#>>
+Bemærk -jens og at @ i adressen er lavet om til et =.
+
+Du kan framelde din alternative adresse ved at skrive til:
+<<#L#>-unsubscribe-jens=ferieby.dk@<#H#>>
+
+jens@ferieby.dk vil i begge tilfælde få et brev som skal
+bekræftes for at få udført til/fra meldingen.
+
+</text/bottom/>
+Hvis disse instruktioner ikke er tilstrækkelige, og du ikke
+har held med dine kommandoer, kan du skrive til min ejer
+<#L#>-owner@<#H#>, som er et menneske
+(og som derfor ikke svarer så hurtigt som jeg gør).
+
+Uanset hvor håbløst det ser ud, så forsøg IKKE at skrive
+til selve mailing listen, f.eks. for at blive frameldt.
+</text/bottom/>
+
+--- Vedlagt: En kopi af det kommando brev du sendte til mig.
+
+</text/bounce-bottom/>
+
+--- Vedlagt: En kopi af det brev som ikke kunne afleveres.
+
+</text/bounce-num/>
+
+Jeg har hold øje med hvilke breve fra <#L> listen der er
+kommet retur fordi de ikke kunne afleveres til dig.
+
+</#a/>
+Kopier af disse brev er muligvis i arkivet.
+</#aI/>
+Du kan f.eks. hente brev 123 fra arkivet ved at send et tomt
+brev til:
+   <<#L#>-get.123@<#H#>>
+
+</#ia/>
+Du kan f.eks. hente brev 123-145 (max. 100 ad gangen), ved at
+sende et tomt brev til:
+   <<#L#>-get.123_145@<#H#>>
+
+Du kan få en oversigt over emne og afsender for de sidste 100
+breve ved at sende et tomt brev til:
+   <<#L#>-index@<#H#>>
+
+<//>
+Her er brevnumrene:
+
+</text/dig-bounce-num/>
+
+Jeg har gemt en liste over hvilke udtræk fra <#L#> listen som er
+kommet retur fordi de ikke kunne afleveres. Kopier af disse breve
+kan hentes i arkivet. For hvert udtræk du mangler, kender jeg
+nummeret på det første brev i udtrækket.
+Jeg gemmer ikke selve udtrækkene, men hvis brevene er der endnu,
+kan du f.eks. få brev 12345 ved at sende et tomt brev til:
+<#L#>-get.12345@<#H#>.
+
+</#ia/>
+Du kan hente en oversigt over brevene 123-145 (max. 100 ad gangen)
+ved at sende et tomt brev til:
+   <<#L#>-get.123_145@<#H#>>
+
+Du kan hente en oversigt over emne og afsender i de nyeste 100
+breve ved at sende et tomt brev til:
+   <<#L#>-index@<#H#>>
+
+<//>
+Her er en liste over brevnumre i udtrækket:
+
+</text/bounce-probe/>
+
+<#L#> listen har haft svigtende held med at aflevere breve til dig.
+Jeg har sendt dig en advarsel, men den kom retur. Fejlmeddelse vedlagt.
+
+Dette er en test for at se om post kan afleveres til dig. Hvis
+det ikke lykkes, bliver du automatisk fjernet fra <#L#>listen.
+Du kan melde dig til igen ved at sende et tomt brev til:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+Mine breve til dig fra <#l#> er kommet retur uden at kunne afleveres.
+Kopi af fejlmeddelsen er vedlagt.
+
+Hvis dette brev også kommer retur uden at kunne afleveres, sender
+jeg et test brev. Hvis det heller ikke kan afleveres, fjerner jeg
+din adresse fra modtagerlisten uden at give yderligere besked.
+
+</text/digest#d/>
+Du kan abonnere på listeudtræk ved at sende et tomt brev til:
+       <#L#>-digest-subscribe@<#H#>
+
+Du kan ophæve listeudtræk abonnementet ved at sende et tomt
+brev til:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Du kan sende et brev ud til alle liste modtagerne ved at skrive til:
+       <#L#>@<#H#>
+
+</text/get-bad/>
+Ikke godt. Det brev findes ikke i arkivet.
+
+</text/help/>
+Dette er en generel hjælpetekst. Det brev jeg modtog fra dig var
+ikke sendt til nogen af mine kommandoadresser.
+
+</text/mod-help/>
+Tak fordi du vil moderere <#L#>@<#H#> listen.
+
+Mine kommandoer er lidt anderledes end i andre postlister,
+men jeg tror du bliver glad for mig når du lærer mig at kende.
+
+Her er en oversigt over hvordan du gør:
+
+Fjernadministration
+--------------------
+Som moderator kan du til- og framelde hvem som helst,
+f.eks. jens@ferieby.dk, ved at sende et tomt brev til:
+   <<#L#>-subscribe-jens=ferieby.dk@<#H#>> eller
+   <<#L#>-unsubscribe-jens=ferieby.dk@<#H#>>
+Bemærk at det ene @ er lavet om til =.
+
+</#d/>
+For udtrækslisterne (digest):
+   <<#L#>-digest-subscribe-jens=ferieby.dk@<#H#>>
+   <<#L#>-digest-unsubscribe-jens=ferieby.dk@<#H#>>
+
+<//>
+Så simpelt er det. Der behøver hverken være emne eller
+indhold i dine kommandobreve.
+
+</#r/>
+Jeg sender dig så et brev som du skal kvittere for ved at
+sende et tomt svar på tilbage.
+</#R/>
+Jeg sender et brev til brugeren som vedkommende skal bekræfte,
+for at abonnementet kan træde i kraft.
+<//>
+
+Disse dialoger er nødvendige for at sikre at den person jeg har
+kontakt med er den han/hun giver sig ud for at være. Ellers
+kunne en fremmed tilmelde et uvidende offer til en masse
+postlister.
+
+Jeg sender en bekræftelse til brugeren når abonnementsstatus
+er ændret.
+
+Tilmelding
+----------
+
+Enhver kan til- eller framelde sig ved at sende et tomt
+brev til:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+For udtrækslisterne:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+Brugeren vil modtage et brev som skal bekræftes med et tomt
+svar for at sikre at vedkommende råder over den pågældende
+postadresse.
+
+</#s/>
+Eftersom denne liste er tilmeldingsmodereret, skal en moderator
+godkende tilmeldingen. Du kan godkende tilmeldingen ved at
+leve et tomt svar på CONFIRM brevet. (Eller du kan lade være).
+</#S/>
+Tilmelding sker på samme måde.
+<//>
+
+Brugeren kan også skrive til:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+for at tilmelde "mary@host.domain". Kun hvis hun modtager post
+på den adresse, vil hun modtage bekræftelses forespørgslen og
+være i stand til at svare på den.
+
+Din adresse og identitet er skjult for abonnenten medmindre
+du skriver direkte til vedkommende.
+
+</#rl/>
+En liste over tilmeldte fås ved at sende et tomt brev til:
+  <<#L#>-list@<#H#>>
+
+En transaksjonslog fås ved at sende et tomt brev til:
+  <<#L#>-list@<#H#>>
+
+</#rld/>
+Over digest tilmeldte:
+   <<#L#>-digest-list@<#H#>>
+og:
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Du kan fjernrette de tekstsvar som listen udsender. En liste
+over filer samt instruktioner fås ved at sende et tomt brev til:
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+Modererede lister
+-----------------
+Når listen er modereret, gemmer jeg det indsendte brev og sender
+dig en kopi sammen med en instruktion. Brevet du modtager vil
+have teksten "MODERATE for ..." i emne linjen.
+
+Du godkender at brevet bliver sendt til listen ved blot at
+svare på "MODERATE for ..." brevet. Du behøver ikke inkludere
+selve brevets indhold i dit svar.
+
+Hvis du vil afvise det indsendte brev, svarer du til brevets
+'From:' adresse istedetfor som normalt, dets 'Reply-To:" adresse.
+Du kan skrive en kommentar til indsenderen, om hvorfor du afviser
+brevet, imellem de to linjer som begynder med %%%. Din identitet
+forbliver anonym.
+
+Det første svar jeg får fra en moderator afgør det videre
+forløb. Hvis en anden moderator har svaret før dig, får du
+besked.
+
+Hvis jeg ikke får svar fra en moderator inden for en bestemt
+tid (normalt 5 dage), returnerer jeg brevet til afsender med
+en forklaring. Din administrator kan evt. konfigurere listen
+så ignorerede "MODERATE for ..." breve bliver slettet uden
+at brevskriveren informeres.
+<//>
+
+Ferie
+-----
+Hvis du midlertidigt har en anden adresse, kan du videresende alle
+breve som har en korrekt 'Mailing-List:' linje i brevhovedet, eller
+med andre ord, har titlen 'MODERATE for <#L#>@<#H#>'
+eller 'CONFIRM subscribe to <#L#>@<#H#>' til din nye adresse eller en
+anden som passer moderator hvervet mens du er væk. Sørg for at listens
+ejer er indforstået med dette.
+
+Hvis du hellere vil lave automatisk godkendelse af alle breve
+mens du er væk, kan du bede dit post program om at lave auto-svar
+på alle breve som har et emne der svarer til de ovennævnte kriterier.
+
+</#r/>
+Hvis du forsøger at fjernadministrere fra en adresse som ikke er
+din, bliver abonnenten spurgt om bekræftelse, derefter moderator(erne).
+Jeg er nødt til at gøre det på den måde når jeg ikke kan verificere
+din identitet.
+
+Bemærk at din originale forespørgsel (og din adresse) bliver sendt
+til abonnenten i dette filfælde!
+<//>
+
+Held og lykke!
+
+PS: Kontakt venligst liste ejeren (<#L#>-owner@<#H#>)
+hvis du har spørgsmål eller problemer.
+
+</text/mod-reject/>
+Jeg må desværre meddele at dit brev (vedlagt) ikke er blevet godkendt
+af moderator. Hvis moderatoren har skrevet en kommentar, ses den
+nedenfor.
+</text/mod-request/>
+Det vedlagte brev er blevet postet til <#L#>@<#H#> listen.
+Hvis du vil godkende at det kommer ud til alle abonnenterne,
+skriver du til:
+
+!A
+
+Bekræftelse sker normalt blot ved at svare på dette brev. Svar adressen
+skulle gerne starte med "<#L#>-accept". Hvis det ikke er tilfældet, må
+den korrekte svar adresse overføres manuelt til modtagerfeltet, evt.
+med klippe/klistre.
+Mulighederne afhænger af at du har et fornuftigt postprogram.
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#A#>
+<//>
+
+Hvis du istedet vil afvise at brevet postes til listen, svar til:
+
+!R
+
+Normalt er det nemmest at lave et "svar-til-alle", og fjerne alle
+adresserne undtagen den der starter med
+"<#L#>-reject".
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Du behøver ikke inkludere brevet i dit svar for at acceptere eller
+afvise det. Hvis du vil sende en besked til afsenderen af et
+afvist brev, kan du skrive beskeden mellem de to linjer der
+begynder med %%%.
+
+%%% Kommentar start
+%%% Kommentar slut
+
+Tak for hjælpen!
+
+--- Her er det indsendte brev.
+
+</text/mod-sub#E/>
+--- Jeg har til- eller afmeldt dig fra <#l#>@<#H#> på begæring
+af moderator.
+
+Hvis du ikke er indforstået med dette, skriv snarest til liste
+ejeren på (<#l#>-owner@<#H#>).
+
+Hvis du ønsker oplysninger om hvordan man bruger <#L#> arkivet,
+send et tomt brev til <#L#>-help@<#H#>.
+
+</text/mod-timeout/>
+Moderator fra <#L#> listen har desværre ikke reageret på dit brev.
+Derfor sender jeg det hermed retur til dig. Hvis du mener det er
+en fejl, send brevet igen eller kontakt en moderator direkte.
+
+--- Enclosed, please find the message you sent.
+
+</text/mod-sub-confirm/>
+Jeg beder hermed om din tilladelse til at tilføje
+
+!A
+
+som abonnent på <#l#> listen. Denne forespørgsel kom enten fra
+dig, eller den er allerede blevet godkendt af den potentielle
+abonnent.
+
+Bekræft ved at sende et tomt svar til denne adresse:
+
+!R
+
+Dit post program burde have en svarfunktion som automatisk bruger
+den adresse. (Ellers må man klippe/klistre).
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Hvis du ikke vil godkende, kan du bare glemme dette brev.
+
+Tak for hjælpen!
+
+</text/mod-unsub-confirm/>
+Nogen har bedt om at få fjernet
+
+!A
+
+fra <#l#> listen. Du kan godkende ved at lave et tomt svar
+til denne adresse:
+
+!R
+
+Normalt sker dette ved at du svarer på dette brev. Der behøver ikke
+være noget indhold. Hvis det ikke virker, må svaradressen kopieres
+over i modtagerfeltet på dit svarbrev, f.eks. med en mus.
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Hvis du ikke vil godkende, kan du bare ignorere dette brev.
+
+Tak for hjælpen!
+
+</text/sub-bad/>
+Ups, bekræftelsesnummeret er ikke gyldigt.
+
+Den mest almindelige grund til ugyldige numre er at deres levetid
+er udløbet. De gælder kun i 10 dage.
+Det kan også være at noget af nummeret mangler i det brev du har
+sendt til mig. Nogle post programmer kan ikke finde ud af lange
+adresser.
+
+Hermed et nyt bekræftelsesnummer. For at bekræfte at du vil have
+
+!A
+
+tilføjet til <#l#> listen, send et tomt svar til denne adresse:
+
+!R
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Kontroller hellere adressen igen, for at være sikker på det hele
+er der, inden du svarer.
+
+Undskyld besværet.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm/>
+Hvis du vil bekræfte at du vil have
+
+!A
+
+tilføjet til <#l#> listen, send et tomt svar til denne adresse:
+
+!R
+
+Normalt kan det simpelthen gøres ved at besvare dette brev.
+Der behøver ikke være noget indhold i brevet.
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Denne bekræftelse tjener to formål. For det firste konstateres om
+jeg er i stand til at sende post til dig. For det andet sikrer det
+dig imod at andre melder sig til med din adresse.
+
+</#q/>
+Nogle post programmer er for dårlige og kan ikke håndtere lange
+adresser. Hvis du er ramt af et sådant, kan du istedet skrive
+til <<#L#>-request@<#H#>> og indsætte
+hele adressen ovenfor i emne linjen.
+
+</text/sub-confirm#s/>
+Denne liste er modereret. Når du har sendt denne bekræftelse,
+vil moderator få besked om af godkende. Du får besked når
+din tilmelding er blevet aktiv.
+
+</text/sub-nop/>
+Anerkendelse: Adressen
+
+!A
+
+var allerede tilmeldt <#l#> listen da jeg fik din tilmelding,
+og er fortsæt tilmeldt.
+
+</text/sub-ok#E/>
+Anerkendelse: Jeg har tilføjet adressen
+
+!A
+
+til <#l#> listen.
+
+Velkommen til <#l#>@<#H#>!
+
+Gem dette brev så du ved hvilken adresse du er tilmeldt med, da
+du skal bruge denne adresse hvis du senere vil frameldes eller
+ændre din tilmeldingsadresse.
+
+</text/top/>
+Hej! Dette er ezmlm programmet. Jeg håndterer <#l#>@<#H#> listen.
+
+</#x/>
+Jeg arbejder for min ejer som kan nås på
+<#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+Ups! Bekræftelsesnummeret er ikke gyldigt.
+
+Den mest almindelige grund til ugyldige numre er at deres levetid
+er udløbet. De gælder kun i 10 dage.
+Det kan også være at noget af nummeret mangler i det brev du har
+sendt til mig. Nogle post programmer kan ikke finde ud af lange
+adresser.
+
+Hermed et nyt bekræftelsesnummer. For at bekræfte at du vil have
+
+!A
+
+fjernet fra <#l#> listen, send et tomt svar til denne adresse:
+
+!R
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Check hellere adressen igen, for at være sikker på det hele er der,
+inden du svarer.
+
+Undskyld besværet.
+
+        <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm/>
+Hvis du vil bekræfte at du vil have
+
+!A
+
+fjernet fra <#l#> listen, send et tomt svar til denne adresse:
+
+!R
+
+Normalt kan det simpelthen gøres ved at besvare dette brev.
+Der behøver ikke være noget indhold i brevet.
+</#x/>
+
+Måske virker det at klikke med musen på næste linje:
+        mailto:<#R#>
+<//>
+
+Jeg har ikke undersøgt om din adresse er tilmeldt i øjeblikket.
+Du kan se hvilken adresse du har brugt i din tilmelding ved
+at kigge på de breve du modtager fra listen. Hvert brev har
+din abonnementsadresse gemt i sin retur sti, f.eks. modtager
+mary@xdd.ff.com breve med retur stien
+<<#l#>-return-<number>-mary=xdd.ff.com@<#H#>.
+
+</#q/>
+Nogle post programmer er meget syge og kan ikke håndtere lange
+adresser. Hvis du er ramt af et sådant, kan du istedet skrive
+til <<#L#>-request@<#H#>> og putte hele adressen ovenfor i emne
+linjen.
+
+</text/unsub-nop/>
+Anerkendelse: Adressen
+
+!A
+
+var ikke tilmeldt <#l#> listen da jeg fik din tilmelding, og
+er det stadig ikke.
+
+Hvis du afmelder, men stadig får post, er du tilmeldt med en
+andren adresse end den du bruger i øjeblikket. Kig i brevhoved
+efter noget der ser sådan ud:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+Afmeldingsadressen for denne bruger ville blive:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+
+Send nu post til denne adresse, erstat user=host.dom med rigtige
+værdier, og du burde modtage et brev om at du er frameldt listen.
+
+I nogle post programmer, skal man gøre brevhovedet synligt for
+at se retur stien:
+
+I Eudora 4.0, klik på (øh, hvem kender Eudora?) knappen.
+I PMMail, klik på "Window->Show entire message/header"
+   hvis du har en engelsk udgave ;-)
+
+Hvis dette stadig ikke virker, kan jeg nok ikke hjælpe dig mere.
+Så videresend din liste kommando til liste ejeren sammen med en
+besked om hvad det er du prøver at opnå, samt en liste over de
+andresser du evt. kan være tilmeldt under. Ejeren,
+
+    <#l#>-owner@<#H#>
+
+Vil tage sig af det. Min ejer er ikke så hurtig som mig, så hav
+venligst lidt tålmodighed.
+
+</text/unsub-ok/>
+Anderkendelse: Jeg har fjernet adressen
+
+!A
+
+fra <#l#> listen. Adressen er ikke længere tilmeldt.
+
+</text/edit-do#n/>
+Ret den følgende tekst og send den til denne adresse:
+
+!R
+
+Dit post program har en svar facilitet som bruger denne adresse
+automatisk.
+
+Jeg kan fjerne de de gåseøjne dit post program tilføjer i
+teksten, bare du ikke retter i selve markeringslinjerne.
+
+Markeringslinjerne er de linjer der starter med %%%. De må ikke
+ændres.
+
+</text/edit-list#n/>
+<#L#>-edit.file kommandoen kan bruges af en fjernadministrator,
+til at rette teksterne i de fleste af svarteksterne i
+svar-tekst filerne .
+
+Her følger en list en liste over svar-tekst filer samt en
+kort beskrivelse af hvornår deres indhold bliver brugt.
+For at rette en fil, skriv til <#L#>-edit.file, erstat
+"file" delen med filnavnet. Editeringsinstruktioner følger
+med tekst filen.
+
+filnavn             Anvendelse
+
+bottom              Afslutning på alle breve. Generel kommando information.
+digest              'administrationsdelen' af et udtræk.
+faq                 De mest spurgte spørgsmål om denne postliste.
+get_bad             Istedetfor breve som ikke kan findes i arkivet.
+help                generel hjælp (mellem 'top' og 'bottom').
+info                liste information. Første linje skal give mening i sig selv
+mod_help            specifik hjælp til liste moderatorer.
+mod_reject          til afsender af afvist post.
+mod_request         til post moderatorer sammen med brevet.
+mod_sub             til abonnent når moderator har bekræftet tilmelding.
+mod_sub_confirm     til tilmeldingsmoderator for at bekræfte tilmelding.
+mod_timeout         til afsender af brev som moderator ikke har reageret på.
+mod_unsub_confirm   til fjernadministrator om at framelde.
+sub_bad             til afsender hvis manglende bekræftelse.
+sub_confirm         til afsender for at bekræfte tilmelding.
+sub_nop             til afsender efter gentilmelding.
+sub_ok              til afsender efter vellykket tilmelding.
+top                 Begynnelse på alle breve.
+</#tn/>
+trailer             tilføjes til alle breve som udsendes fra listen.
+</#n/>
+unsub_bad           til afsender hvis frameldingsbekræftelse ikke var korrekt.
+unsub_confirm       til afsender for at bekræfte frameldingsbekræftelse.
+unsub_nop           til ikke-tilmeldte efter framelding.
+unsub_ok            til ex-tilmeldte efter vellykket framelding.
+
+</text/edit-done#n/>
+Denne text er med held blevet opdateret
+</text/info#E/>
+Der findes pt. ingen information om denne liste.
+</text/faq#E/>
+FAQ - Ofte stillede spørgsmål om <#l#>@<#H#> listen.
+
+Der ikke lavet nogen endnu.
+
diff --git a/ezmlmrc.de b/ezmlmrc.de
new file mode 100644 (file)
index 0000000..cd8f44f
--- /dev/null
@@ -0,0 +1,1412 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.de,v 1.22 1999/12/23 02:43:12 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# Deutsche Übersetzung: Frank Tegtmeyer <fte@pobox.com>
+#                       Anmerkungen zur Übersetzung bitte direkt
+#                       an mich
+# translation to German: Frank Tegtmeyer <fte@pobox.com>
+#                       comments regarding the translation
+#                       directly to me please
+#
+# Changes:
+# 1999-11-23     Update for version 0.40, most help texts are moved to
+#                the answer of the -help command.
+#                The sample address ich@irgendwo.de was replaced by
+#                ich@lightwerk.de because I this address is under
+#                my control.
+# 1999-02-17     some refinements, sql support by Fred,
+#                mod-help with -log command
+# 1998-11-26     added -list command to mod-help
+#                more verbose explanation for ezmlm-issubn
+# 1998-08-14     one spelling error, added faq/info commands to 'bottom'
+#                instead of mod-help, Fred corrected one a-switch
+#                added a pointer to my web page "Mailinglisten und ihre
+#                Benutzung"
+# 1998-06-29     update for ezmlm-idx-0.31
+#                added faq/info, correction of some switches (archive, digest)
+#                again use of mailto:, additional hint to prevent the use
+#                of the sample address ich@irgendwo.de, some spelling errors
+#                corrected, only ASCII in qmail bounces
+#
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+# Use Quoted-Printable to make averyone happy.
+iso-8859-1:Q
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean state.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Tut mir leid, ich wurde angewiesen, Ihre Nachrichten nicht anzunehmen. Diesbezuegliche Fragen richten Sie bitte an <#L#>-owner@<#H#> (#5.7.2)."; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Hier werden nur Nachrichten von Abonnenten der Liste akzeptiert. Falls Sie die Liste beziehen aber trotzdem nicht schreiben duerfen, schicken Sie bitte diese Nachricht an <#L#>-owner@<#H#> weiter, damit Ihre neue Adresse aufgenommen werden kann. Der Listeneigentuemer kann Sie ebenso gezielt fuer das Schreiben von Nachrichten freischalten, auch wenn Sie die Liste nicht beziehen (#5.7.2)."; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+Um die Liste abzubestellen, schicken Sie eine Mail an:
+    <#L#>-unsubscribe@<#H#>
+Um eine Liste aller verfügbaren Kommandos zu bekommen, schicken
+Sie eine Mail an:
+    <#L#>-help@<#H#>
+</text/bottom#E/>
+
+Wenn Sie weiterführende Informationen zu Mailinglisten haben möchten,
+schauen Sie sich doch im World Wide Web einmal das Dokument
+"Mailinglisten und ihre Benutzung"  unter folgender Adresse an:
+http://www.pobox.com/~fte/ml.html
+
+--- Hier eine Aufstellung der wichtigsten Kommandos zur Steuerung des
+    Mailinglistenmanagers ezmlm für diese Liste:
+
+Ich kann alle Ihre Anforderungen bezüglich der Liste
+automatisch bearbeiten. Schicken Sie einfach eine leere Mail
+an die jeweilige Adresse.
+SENDEN SIE KEINE KOMMANDOS AN DIE MAILINGLISTE SELBST.
+In dem Fall kann ich nicht darauf reagieren und viele Empfänger
+der Mailingliste werden sich bei Ihnen oder über Sie beschweren.
+
+   <<#L#>-help@<#H#>>
+   Beschreibung der Steuerungsmöglichkeiten für diese
+   Mailingliste
+
+   <<#L#>-subscribe@<#H#>>
+   wenn Sie die Mailingliste in Zukunft beziehen möchten
+
+   Wenn Sie keine Nachrichten der Mailingliste <#L#>
+   mehr empfangen möchten, benutzen Sie bitte die Adresse, die
+   im Header "List-Unsubscribe:" angegeben ist. Wenn Sie Ihre
+   Email-Adresse nach der Listenbestellung nicht geändert haben,
+   geht auch:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+   Für die Digest-Liste existieren die entsprechenden Adressen:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+</#HJE/>
+Beim Löschen oder Eintragen von Abonnenten verschicke ich eine
+zusätzliche Kontrollnachricht. Diese muß zur Bestätigung einfach
+nur beantwortet werden.
+
+</#E/>
+Falls Sie menschliche Hilfe brauchen, wenden Sie sich bitte an
+den Listeneigentümer:
+
+   <<#L#>-owner@<#H#>>
+
+Bitte schicken Sie eine Listenmail inklusive ALLER Header mit -
+dadurch wird es sehr viel leichter, Ihnen schnell zu helfen.
+
+--- Anbei eine Kopie der Anforderung die ich erhalten habe:
+
+</text/bounce-bottom#E/>
+
+--- Anbei eine Kopie der Fehlermeldung (bounce), die ich
+    erhalten habe:
+
+</text/bounce-num#E/>
+
+Ich habe mir gemerkt, welche Nachrichten der Mailingliste
+   <<#L#>@<#H#>>
+nicht an Sie zugestellt werden konnten.
+</#aE/>
+Eventuell befinden sich noch Kopien dieser Nachrichten
+im Archiv.
+
+</#aE/>
+Um beispielsweise eine Kopie der Nachricht 123
+anzufordern, schicken Sie eine Nachricht an
+   <#L#>-get.123@<#H#>
+
+Um die Nachrichten 123 bis 145 (maximal einhundert Nachrichten pro
+Anforderung) zu bekommen, benutzen Sie die folgende Adresse:
+   <#L#>-get.123_145@<#H#>
+
+Um eine Liste (Verfasser und Betreff) der letzen einhundert
+Nachrichten zu bekommen, schicken Sie eine leere Mail an die
+folgende Adresse:
+   <#L#>-index@<#H#>
+
+</#E/>
+Hier die Nummern der Nachrichten:
+
+</text/dig-bounce-num#E/>
+
+Ich habe mir gemerkt, welche Nachrichten der Mailingliste
+<#L#>-digest nicht an Sie zugestellt werden konnten.
+Pro nicht zugestelltem Digest wird jeweils die Nummer der
+ersten Nachricht vermerkt.
+
+</#aE/>
+Unter Umständen befinden sich noch Kopien der Nachrichten
+im Archiv. Ich habe mir jeweils die Nummer der ersten
+Nachricht pro Digest gemerkt. Sie können sich die Nachrichten
+vom Archiv schicken lassen. Eine Anforderung der Digests
+selber ist nicht möglich, da diese nicht archiviert werden.
+
+Um beispielsweise eine Kopie der Nachricht 123
+anzufordern, schicken Sie eine Nachricht an
+   <#L#>-get.123@<#H#>
+
+Um die Nachrichten 123 bis 145 (maximal einhundert Nachrichten pro
+Anforderung) zu bekommen, benutzen Sie die folgende Adresse:
+   <#L#>-get.123_145@<#H#>
+
+Um eine Liste (Verfasser und Betreff) der letzen einhundert
+Nachrichten zu bekommen, schicken Sie eine leere Mail an die
+folgende Adresse:
+   <#L#>-index@<#H#>
+
+</#E/>
+Hier die Nummern der ersten Nachricht pro Digest:
+
+</text/bounce-probe#E/>
+
+Es scheint, daß einige Nachrichten der Mailingliste
+<#l#> an Sie nicht zustellbar waren.
+Ich habe Ihnen eine Warnung geschickt, aber auch diese konnte
+nicht zugestellt werden. Eine Kopie der Fehlernachricht
+ist angehängt.
+
+Diese Nachricht ist ein weiterer Versuch zu prüfen, ob Ihre Adresse
+erreichbar ist. Wenn auch dieser letzte Versuch scheitert Ihnen
+Mail zuzustellen, dann wird Ihre Adresse ohne weitere Hinweise
+von der Mailingliste
+   <#l#>@<#H#>
+entfernt.
+
+Durch eine leere Mail an die Adresse
+   <<#l#>-subscribe@<#H#>>
+können Sie sich wieder in die Mailingliste eintragen.
+
+</text/bounce-warn#E/>
+
+Es scheint, daß einige Nachrichten der Mailingliste
+<#l#> an Sie nicht zustellbar waren.
+Ich habe eine Kopie der ersten Fehlernachricht mitgeschickt.
+
+Falls diese Nachricht auch nicht zustellbar ist, werde ich eine
+weitere Versuchsnachricht schicken. Ist auch diese ohne Erfolg, wird
+Ihre Adresse von der Mailingliste <#l#> gestrichen.
+
+</text/digest#dE/>
+Um sich in die Digest-Liste einzutragen, schicken Sie eine Mail an:
+   <#L#>-digest-subscribe@<#H#>
+
+Um sich abzumelden, schicken Sie eine Mail an:
+   <#L#>-digest-unsubscribe@<#H#>
+
+Nachrichten, die Sie in der Liste veröffentlichen wollen,
+schicken Sie bitte an:
+   <#L#>@<#H#>
+
+</text/get-bad#E/>
+Diese Nachricht ist im Archiv nicht vorhanden.
+
+</text/help#E/>
+Dies ist eine allgemeine Hilfsnachricht. Entweder haben Sie die Hilfe
+direkt angefordert oder die Mail, die ich empfangen habe, ist nicht an
+eine meiner korrekten Steuerungsadressen geschickt worden.
+
+Hier eine Aufstellung der Kommandos zur Steuerung des
+Mailinglistenmanagers ezmlm für diese Liste:
+
+<<#L#>-info@<#H#>>
+<<#L#>-faq@<#H#>>
+Die beiden Adressen sind zur Anforderung eines
+Informationstextes zur Mailingliste bzw. zur Anforderung der
+FAQ (Frequently Asked Questions - oft gestellte Fragen und
+die Antworten darauf) vorgesehen.
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+<<#L#>-get.12@<#H#>>
+Auf diese Weise fordern Sie eine Kopie der Nachricht 12
+vom Archiv an.
+
+<<#L#>-get.123_145@<#H#>>
+Fordern Sie auf diese Weise eine Kopie der Nachrichten
+123 bis 145 vom Archiv an. Sie können mit einer Anforderung
+maximal einhundert Nachrichten bekommen.
+
+<<#L#>-index.123_456@<#H#>>
+Fordern Sie auf diese Weise die Betreff-Zeilen (Subjects)
+der Nachrichten von 123 bis 456 (inklusive) vom Archiv an.
+Pro Anforderung werden maximal 2000 Betreff-Zeilen zugestellt. 
+Die Zustellung erfolgt in Gruppen zu je einhundert Betreff-Zeilen,
+so daß Sie mit dieser Anforderung real die Betreff-Zeilen
+der Nachrichten 100 bis 499 erhalten.
+Zusätzlich zu den Betreffzeilen wird der jeweilige Autor
+übermittelt.
+
+<<#L#>-thread.123@<#H#>>
+Anforderung aller Nachrichten, die den gleichen Betreff wie
+die Nachricht 123 haben.
+
+</#E/>
+Der Inhalt der Nachrichten muß nicht unbedingt leer sein, Sie
+können auch etwas in die Betreff-Zeilen schreiben. Ich werde
+jedoch beide Angaben ignorieren - nur die angeschriebene Adresse
+ist für meine Steuerung maßgebend.
+
+------------------------------------------------------------
+ACHTUNG: bitte probieren Sie nicht die im folgenden genannte
+Adresse ich@lightwerk.de aus, sondern ersetzen Sie
+diese durch Ihre eigene Adresse, unter der Sie
+Abonnent der Liste werden möchten!
+------------------------------------------------------------
+
+Sie können direkt die Adresse vorgeben, unter der Sie als
+Empfänger der Liste eingetragen werden möchten. Dazu bauen Sie
+die gewünschte Adresse in meine Steuerungsadresse ein, indem Sie
+das at-Zeichen (@) durch ein Gleichheitszeichen (=) ersetzen.
+Um zum Beispiel als Adresse ich@lightwerk.de anzugeben, senden
+Sie eine Mail an die Adresse
+   <<#L#>-subscribe-ich=lightwerk.de@<#H#>>.
+Die entsprechende Adresse zum abmelden des Abonnements ist
+   <<#L#>-unsubscribe-ich=lightwerk.de@<#H#>>.
+In beiden Fällen werde ich eine Bestätigung an ich@lightwerk.de
+schicken, die Sie nach Empfang einfach nur beantworten müssen,
+um den An- oder Abmeldevorgang abzuschließen.
+
+Auch wenn diese Erklärungen zu kompliziert für Sie sein sollten
+oder Sie Probleme mit der Steuerung der Liste haben, schreiben
+Sie bitte keine Hilfemails an die Liste selbst. Wenden Sie sich
+stattdessen an den Listeneigentümer:
+   <#L#>-owner@<#H#>
+Bitte haben Sie Geduld, da es sich dabei um ein eventuell
+überlastetes menschliches Wesen handelt, das nie so schnell
+reagieren kann wie ich :)
+
+</text/mod-help#E/>
+Vielen Dank, daß Sie bereit sind, die Moderation der Liste
+   <#L#>@<#H#>
+zu übernehmen.
+
+Die Kommandos, die ich benutze, sind sehr verschieden von denen
+anderer Mailinglistenmanager. Sie werden Ihnen anfangs sehr
+ungewohnt vorkommen, wenn Sie sich aber erst einmal daran gewöhnt
+haben werden Sie die Einfachheit und Geschwindigkeit des Systems
+schätzen lernen.
+
+Hier einige Hinweise, wie die Moderation funktioniert.
+Generelle Hinweise zur Listenbedienung folgen am Ende dieser
+Mail.
+
+Eintragen von Nutzern per Mail
+------------------------------
+Als Moderator sind Sie in der Lage, per Mail beliebige Adressen 
+in die Liste aufzunehmen oder sie daraus zu streichen. Sie
+bauen einfach die Adresse, um die es geht in meine Kommando-Adresse
+ein und ersetzen dabei das at-Zeichen (@) durch ein
+Gleichheitszeichen (=).
+Für die Adresse ich@lightwerk.de geht das zum Beispiel
+über die folgenden Steueradressen:
+
+Eintragen:
+   <#L#>-subscribe-ich=lightwerk.de@<#H#>
+Löschen:
+   <#L#>-unsubscribe-ich=lightwerk.de@<#H#>
+
+</#dE/>
+Entsprechend für die Digest-Liste:
+   <#L#>-digest-subscribe-ich=lightwerk.de@<#H#>
+   <#L#>-digest-unsubscribe-ich=lightwerk.de@<#H#>
+
+</#E/>
+So einfach ist das :) Sie brauchen nicht einmal einen
+Betreff oder irgendeinen Nachrichtentext schreiben.
+
+</#rE/>
+Ich werde Ihnen eine Rückfrage schicken, um sicherzugehen daß
+wirklich Sie das Kommando geschickt haben.
+Sie brauchen dann einfach nur noch antworten und der Vorgang
+ist damit abgeschlossen.
+</#RE/>
+Ich werde zur Sicherheit an die angegebene Adresse (in diesem
+Fall ich@lightwerk.de) eine Rückfrage schicken.
+Alles was der Nutzer tun muß, ist auf diese Anfrage zu antworten.
+</#E/>
+
+Die Bestätigungsnachrichten sind erforderlich um es Dritten
+schwerer zu machen, beliebige Mailadressen in die Liste
+aufzunehmen.
+
+Der Nutzer wird darüber informiert, wenn er in die Liste
+aufgenommen oder aus ihr gelöscht wird.
+
+
+Abonnement durch die User
+-------------------------
+
+Jeder kann die Liste abonnieren oder abbestellen indem eine
+Mail an die entsprechende Adresse geschickt wird:
+
+Bestellen der Liste:
+   <#L#>-subscribe@<#H#>
+
+Abbestellen der Liste:
+   <#L#>-unsubscribe@<#H#>
+
+</#dE/>
+Entsprechend für die Digest-Liste:
+
+   <#L#>-digest-subscribe@<#H#>
+   <#L#>-digest-unsubscribe@<#H#>
+
+</#E/>
+In beiden Fällen bekommt der Nutzer eine Rückfrage, um
+Fälschungen vorzubeugen. Nach Bestätigung wird der Nutzer
+Abonnent der Liste oder aus ihr gelöscht.
+
+</#sE/>
+Da diese Liste mit moderierten Abonnements arbeitet, wird
+bei einem Abonnement eine zweite Rückfrage an den oder die
+Moderatoren geschickt.
+Da die Bestätigung durch den Nutzer schon erfolgte, können Sie
+relativ sicher sein, daß die angegebene Adresse nicht gefälscht
+ist. Wenn Sie dem Abonnement durch den User zustimmen,
+beantworten Sie die Bestätigungsanforderung einfach.
+Falls nicht, können Sie die Anforderung einfach löschen.
+Eventuell können Sie auch mehr Informationen vom Nutzer einholen
+oder ihm Ihre Gründe für die Nicht-Bestätigung mitteilen.
+Beachten Sie, daß dadurch Ihre Email-Adresse bekannt wird.
+
+</#E/>
+Die Nutzer können auch die folgende Adressen benutzen:
+
+   <#L#>-subscribe-ich=lightwerk.de@<#H#>
+   <#L#>-unsubscribe-ich=lightwerk.de@<#H#>
+
+</#dE/>
+Für Digests:
+   <#L#>-digest-subscribe-ich=lightwerk.de@<#H#>
+   <#L#>-digest-unsubscribe-ich=lightwerk.de@<#H#>
+
+</#E/>
+Damit können sie eine andere als die aktuell benutzte
+Email-Adresse in die Mailingliste einzutragen bzw. sie daraus
+löschen (in diesem Beispiel die Adresse ich@lightwerk.de).
+Nur wenn die Rückfrage an diese Adresse dann auch beantwortet
+wird, kann die Aktion ausgeführt werden.
+
+All diese Rückfragen werden durchgeführt um sicherzustellen
+daß keine gefälschten Kommandos vorliegen und daß es sich
+wirklich um den Wunsch der Person handelt, die Mails über
+diese Adresse empfängt.
+
+Ihre Adresse und Identität wird keiner weiteren Person
+offengelegt, es sei denn Sie nehmen direkt Kontakt auf.
+
+</#rlE/>
+Information über den Listenzustand
+----------------------------------
+
+Um eine Liste der Abonnenten von <#L#>@<#H#>
+zu bekommen, senden Sie eine Mail an:
+   <<#L#>-list@<#H#>>
+
+Um ein Transaktionslog (Liste der Abonnenten-Zu- und
+Abgaenge) für <#L#>@<#H#>
+zu bekommen, senden Sie eine Mail an:
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+Die Liste der Digest-Abonnenten erhalten Sie über:
+   <<#L#>-digest-list@<#H#>>
+
+Das Logfile für die <#L#>-digest@<#H#> Liste über:
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+
+Textänderungen
+--------------
+
+Sie können die erläuternden Texte, die ich verschicke auch per Mail
+verändern. Um eine Datei- und Kommandoliste dafür zu erhalten schreiben
+Sie an:
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+
+Moderierte Nachrichten
+----------------------
+
+Moderierte Nachrichten werden von mir zunächst in eine
+Warteschlange eingereiht, daraufhin wird eine Bestätigungs-
+anforderung an Sie geschickt. In der Betreffzeile steht
+in diesem Fall "MODERATE for ...".
+
+Falls Sie die Nachricht genehmigen, müssen Sie einfach nur
+auf diese Anforderung antworten. Dazu benutzen Sie bitte
+die Adresse im Reply-To:-Header (sollte automatisch von
+Ihrem Mailprogramm angeboten werden). In einigen Programmen
+wird die Adresse auch als Hyperlink im Mailtext angezeigt, den
+Sie dann nur noch per Mausklick öffnen müssen (zum Beispiel in
+Pegasus Mail).
+Die Nachricht des Nutzers müssen Sie nicht mitschicken, da ich
+noch eine Kopie davon besitze und diese verwende.
+
+Wenn Sie die Nachricht ablehnen möchten, senden Sie an die
+Adresse, die im From:-Header angegeben ist. Auch hier können
+Sie die Möglichkeit des Hyperlinks verwenden, wenn Ihr Mailprogramm
+das unterstützt.
+Sie können eine Begründung oder einen Kommentar mitgeben, indem Sie
+Ihren Text in zwei Zeilen einschließen, die jeweils mit drei
+Prozentzeichen beginnen. Der Nutzer erhält nur diesen
+Kommentar, ohne daß Ihre Identität dabei preisgegeben wird.
+
+Ich werde die Nachricht anhand der ersten Moderatoren-Antwort
+behandeln. Sollten Sie eine Bestätigung oder Ablehnung schicken
+und die Nachricht wurde aufgrund der Entscheidung eines
+weiteren Moderators schon anderweitig verarbeitet, werde
+ich Sie darüber informieren.
+
+Sollte kein Moderator innerhalb einer festgelegten Zeit
+(normalerweise 5 Tage) reagieren, schicke ich die Nachricht
+zusammen mit einer Erklärung an den Absender zurück.
+Die Liste kann auch so konfiguriert werden, daß solche
+Nachrichten nicht an den Nutzer zurückgeschickt, sondern
+kommentarlos gelöscht werden.
+
+</#E/>
+
+Urlaub und andere Abwesenheit
+-----------------------------
+
+Wenn Sie zeitweilig über eine andere Adresse erreichbar sind, schicken
+Sie alle Mails, die den richtigen 'Mailing-List:' Header haben an diese
+Adresse weiter. Behandeln Sie alle Mails, die einen Betreff der Form:
+'MODERATE for <#L#>@<#H#>' oder
+'CONFIRM subscribe to <#L#>@<#H#>'
+haben auf die gleiche Weise.
+Ihre Moderationstätigkeit können Sie dann auch von der neuen Adresse
+aus fortsetzen.
+Es ist ebenfalls möglich, einen Vertreter damit zu beauftragen. Bitte
+klären Sie aber Vertretungen vorher mit dem Listeneigentümer ab.
+
+Wenn Sie für eine Weile alle Anforderungsmails automatisch
+bestätigen wollen, lassen Sie einfach Ihr Mailsystem die Nachrichten
+automatisch beantworten, die die obengenannten Bedingungen erfüllen.
+
+</#rE/>
+Wenn Sie die Liste von einer Fremdadresse aus administrieren wollen,
+werden nicht Sie, sondern der Nutzer nach einer Bestätigung gefragt.
+Danach wird die Bestätigungsanforderung an alle Moderatoren verschickt.
+Diese Verfahrensweise ist notwendig, da ich in diesem Fall nicht wissen kann,
+ob Sie zur Administration berechtigt sind.
+
+Bitte beachten Sie, daß in diesem Fall auch Ihre Administrationsmail
+(und Ihre Mailadresse) an den Nutzer übermittelt werden.
+
+</#E/>
+Viel Erfolg!
+
+PS: Bitte wenden Sie sich an den Listeneigentümer
+   <#L#>-owner@<#H#>
+wenn Sie Probleme irgendwelcher Art mit der Listenadministration
+haben.
+
+</text/mod-reject#E/>
+Tut mir leid, Ihre (angehängte) Nachricht wurde von einem Moderator
+abgewiesen. Falls der Moderator einen Kommentar dazu abgegeben hat,
+können Sie diesen weiter unten finden.
+</text/mod-request#E/>
+Bitte entscheiden Sie als Moderator, ob diese Nachricht an die
+Mailingliste
+   <#L#>@<#H#>
+weitergeleitet werden soll.
+
+Um die Nachricht zuzulassen und sofort an alle Listenabonnenten
+weiterzuleiten, senden Sie bitte eine Mail an:
+
+!A
+
+Normalerweise sollte das über die "Beantworten"-Funktion Ihres
+Mailprogramms funktionieren. Bitte prüfen Sie aber noch einmal,
+ob die Adresse mit "<#L#>-accept" beginnt und am Ende nicht
+abgeschnitten ist. Manche Programme haben leider Probleme mit langen
+Adressen. Falls "Beantworten" nicht funktioniert, kopieren Sie
+die oben genannte Adresse einfach in die Zieladresse einer neuen
+Nachricht. Beachten Sie dabei aber einen eventuell von Ihrem
+Mailprogramm vorgenommenen Zeilenumbruch, falls die Adresse nicht
+in eine Zeile paßt.
+</#xE/>
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#A#>
+Kontrollieren Sie aber bitte auch in diesem Fall, daß die Adresse
+nicht durch Zeilenumbruch verstümmelt wurde!
+</#E/>
+
+
+Um die Nachricht abzuweisen und an den Absender zurückzuschicken,
+senden Sie bitte eine Mail an:
+
+!R
+
+Falls Ihr Programm das unterstützt, können Sie auch an die im
+From: Header angegebene Adresse antworten (das sollte die oben
+angegebene sein).
+
+</#xE/>
+Wenn Ihr Programm Hyperlinks unterstützt, können Sie auch
+hier klicken:
+   mailto:<#R#>
+
+</#E/>
+
+Sie müssen keine Kopie der Originalnachricht mitschicken.
+Wenn Sie dem Absender bei einer Ablehnung einen Kommentar zukommen
+lassen wollen, schließen Sie diesen zwischen zwei Zeilen ein, die
+jeweils mit drei Prozentzeichen beginnen.
+
+%%% Beginn Kommentar
+%%% Ende Kommentar
+
+Auch bei Ablehnung einer Nachricht kontrollieren Sie bitte, daß
+die Adresse nicht von Ihrem Mailprogramm verstümmelt wird.
+
+Vielen Dank für Ihre Mithilfe!
+
+--- Anbei finden Sie die Nachricht, um die es geht.
+
+</text/mod-sub#E/>
+Ich habe Sie auf Anforderung eines Moderators in die folgende
+Mailingliste aufgenommen bzw. Sie aus dieser gelöscht:
+   <#l#>@<#H#>
+
+Falls das nicht Ihren Wünschen entspricht oder ein Irrtum vorliegt,
+wenden Sie sich mit Ihrer Reklamation so schnell wie möglich an
+den Listeneigentümer:
+   <#l#>-owner@<#H#>
+
+Falls Sie Informationen über die Steuerung der Liste benötigen,
+senden Sie einfach eine leere Mail an 
+   <#l#>-help@<#H#>
+
+</text/mod-timeout#E/>
+Leider hat keiner der Moderatoren Ihre Nachricht bearbeitet. Deswegen
+schicke ich sie Ihnen zurück. Falls Sie dennoch versuchen wollen, die
+Nachricht zu veröffentlichen, schicken Sie sie bitte erneut oder
+nehmen Sie direkt Kontakt mit einem Moderator auf.
+
+--- Anbei finden Sie die Nachricht, die ich von Ihnen empfangen habe.
+
+</text/mod-sub-confirm#E/>
+Bitte entscheiden Sie, ob
+
+!A
+
+die Mailingliste
+   <#l#>@<#H#>
+abonnieren darf. Falls die Anforderung nicht von Ihnen selbst kam
+(die Originalanforderung habe ich angehängt), habe ich schon geprüft,
+daß die Anforderung wirklich von der angegebenen Adresse kam.
+
+Um zuzustimmen, senden Sie einfach eine leere Mail an die
+folgende Adresse:
+
+!R
+
+Die Funktion "Beantworten" in Ihrem Mailprogramm sollte diese Adresse
+automatisch benutzen.
+Beachten Sie dabei aber einen eventuell von Ihrem Mailprogramm
+vorgenommenen Zeilenumbruch, falls die Adresse nicht in eine Zeile paßt.
+Sie können die Adresse auch kopieren und in einer neuen Mail
+als Empfänger einsetzen.
+</#xE/>
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#R#>
+</#E/>
+
+
+Falls Sie nicht zustimmen, ignorieren Sie diese Nachricht einfach.
+Sie können Dem Nutzer natürlich auch eine Begründung Ihrer Ablehnung
+schicken, damit wird diesem allerdings Ihre Email-Adresse bekannt.
+
+Vielen Dank für Ihre Mithilfe!
+
+</text/mod-unsub-confirm#E/>
+Bitte entscheiden Sie, ob
+
+!A
+
+von der Mailingliste
+   <#l#>@<#H#>
+gestrichen werden soll.
+Um zuzustimmen, senden Sie einfach eine leere Mail an die
+folgende Adresse:
+
+!R
+
+Die Funktion "Beantworten" in Ihrem Mailprogramm sollte diese Adresse
+automatisch benutzen.
+Beachten Sie dabei aber einen eventuell von Ihrem Mailprogramm
+vorgenommenen Zeilenumbruch, falls die Adresse nicht in eine Zeile paßt.
+Sie können die Adresse auch kopieren und in einer neuen Mail
+als Empfänger einsetzen.
+</#xE/>
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#R#>
+</#E/>
+
+Falls Sie nicht zustimmen, ignorieren Sie diese Nachricht einfach.
+Sie können Dem Nutzer natürlich auch eine Begründung Ihrer Ablehnung
+schicken, damit wird diesem allerdings Ihre Email-Adresse bekannt.
+
+Vielen Dank für Ihre Mithilfe!
+
+</text/sub-bad#E/>
+Es scheint, daß diese Bestätigungsnummer nicht gültig ist.
+
+Der Grund dafür ist in den meisten Fällen eine Zeitüberschreitung.
+Bestätigungen muß ich innerhalb von zehn Tagen bekommen, sonst gelten
+Anforderungen als abgelehnt.
+Stellen Sie auch sicher, daß Sie die Antwortadresse komplett
+übernommen haben - da diese Kontrolladressen recht lang sind, haben
+einige Mailprogramme die Eigenschaft, diese kommentarlos zu kürzen.
+
+Ich habe eine neue Bestätigungsnummer generiert. Um zuzustimmen, daß
+die Adresse
+
+!A
+
+in die Mailingliste
+   <#l#>@<#H#>
+aufgenommen wird, senden Sie eine leere Mail an die Adresse
+
+!R
+</#xE/>
+
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#R#>
+</#E/>
+
+Prüfen Sie noch einmal genau, daß Sie an die richtige Adresse
+schreiben und diese nicht von Ihrem Mailprogramm verstümmelt wurde.
+
+Bitte entschuldigen Sie den Aufwand.
+
+   <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+Um zu bestätigen, daß Sie unter der Adresse
+
+!A
+
+die Mailingliste <#l#>@<#H#>
+abonnieren möchten, senden Sie eine leere Mail an 
+
+!R
+
+Die Funktion "Beantworten" in Ihrem Mailprogramm sollte diese Adresse
+automatisch benutzen.
+Beachten Sie dabei aber einen eventuell von Ihrem Mailprogramm
+vorgenommenen Zeilenumbruch, falls die Adresse nicht in eine Zeile paßt.
+Sie können die Adresse auch kopieren und in einer neuen Mail
+als Empfänger einsetzen.
+</#xE/>
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#R#>
+</#qE/>
+
+Manche Mailprogramme sind nicht in der Lage, lange Adressen zu
+verarbeiten. Falls Sie die angegebene Adresse nicht anschreiben
+können, benutzen Sie bitte die Adresse
+<<#L#>-request@<#H#>> und tragen die
+obengenannte Adresse in die Betreff-Zeile (Subject:) ein.
+</#E/>
+
+Diese Bestätigung dient zwei Zwecken. Zum einen wird dadurch sicher-
+gestellt, daß ich Mails an Ihre Adresse zustellen kann.
+Zum anderen dient die Bestätigung als Schutz gegen gefälschte
+Mailinglisten-Abonnements.
+
+</#sE/>
+Diese Mailingliste ist moderiert. Sobald Sie die Bestätigung
+abgeschickt haben, wird eine weitere Bestätigung von den Moderatoren
+eingeholt. Sie erhalten einen Hinweis, wenn der Vorgang abgeschlossen
+wurde. Falls nach etwa zehn Tagen keine Reaktion kam, hat keiner der
+Moderatoren zugestimmt, Sie in die Liste aufzunehmen.
+
+</#E/>
+Wenn Sie diese Nachricht nicht beantworten, erhalten Sie die
+Mailingliste nicht. Wenden Sie sich an Ihren Mail-Administrator, wenn
+Sie der Meinung sind, daß jemand unter Ihrem Namen ein gefälschtes
+Abonnement vorgenommen hat.
+
+</text/sub-nop#E/>
+Hm. Die Adresse
+
+!A
+
+ist schon Abonnent der Mailingliste
+<#l#>@<#H#>.
+Diese Adresse war schon als Abonnent eingetragen, bevor Ihre
+Anforderung empfangen wurde. Daher habe ich keinerlei
+Änderungen ausgeführt.
+
+</text/sub-ok#E/>
+Bestätigung: Ich habe Ihre Adresse
+
+!A
+
+als Abonnenten in die Mailingliste <#l#>
+aufgenommen.
+
+Willkommen bei <#l#>@<#H#>!
+
+Bitte heben Sie diese Nachricht gut auf, damit Sie auch später
+noch wissen, unter welcher Adresse Sie die Mailingliste empfangen.
+Damit vermeiden Sie Probleme, falls sie später Ihre Adresse ändern
+oder die Mailingliste wieder abbestellen wollen.
+
+Um die Liste wieder abzubestellen, senden Sie eine leere Mail an
+die Adresse
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Hallo, hier ist das ezmlm Programm. Ich verwalte die Mailingliste
+   <#l#>@<#H#>
+
+Ich nehme dem Eigentümer der Liste die meiste Arbeit ab. Er selbst
+ist erreichbar unter der Adresse
+   <#l#>-owner@<#H#>
+
+</text/unsub-bad#E/>
+Es scheint, daß diese Bestätigungsnummer nicht gültig ist.
+
+Der Grund dafür ist in den meisten Fällen eine Zeitüberschreitung.
+Bestätigungen muß ich innerhalb von zehn Tagen bekommen, sonst gelten
+Anforderungen als abgelehnt.
+Stellen Sie auch sicher, daß Sie die Antwortadresse komplett
+übernommen haben - da diese Kontrolladressen recht lang sind, haben
+einige Mailprogramme die Eigenschaft, sie kommentarlos zu kürzen.
+
+Ich habe eine neue Bestätigungsnummer generiert. Um zuzustimmen, daß
+Ihre Adresse
+
+!A
+
+von der Mailingliste <#l#>@<#H#>
+gestrichen werden soll, senden Sie bitte eine leere Mail an
+folgende Adresse:
+
+!R
+</#xE/>
+
+oder klicken Sie hier, wenn Ihr Programm Hyperlinks unterstützt:
+   mailto:<#R#>
+</#E/>
+
+Bitte prüfen Sie noch einmal genau, daß Sie an die richtige Adresse
+schreiben und diese nicht von Ihrem Mailprogramm verstümmelt wurde.
+
+Bitte entschuldigen Sie den Aufwand.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+Um zuzustimmen, daß Ihre Adresse
+
+!A
+
+von der Mailingliste <#l#>@<#H#>
+gestrichen werden soll, senden Sie bitte eine leere Mail an
+folgende Adresse:
+
+!R
+
+Die Funktion "Beantworten" in Ihrem Mailprogramm sollte diese Adresse
+automatisch benutzen.
+Beachten Sie dabei aber einen eventuell von Ihrem Mailprogramm
+vorgenommenen Zeilenumbruch, falls die Adresse nicht in eine Zeile paßt.
+Sie können die Adresse auch kopieren und in einer neuen Mail
+als Empfänger einsetzen.
+</#xE/>
+Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier:
+   mailto:<#R#>
+</#qE/>
+
+Manche Mailprogramme sind nicht in der Lage, lange Adressen zu
+verarbeiten. Falls Sie die angegebene Adresse nicht anschreiben
+können, benutzen Sie bitte die Adresse
+<<#L#>-request@<#H#>> und tragen die
+obengenannte Adresse in die Betreff-Zeile (Subject:) ein.
+</#E/>
+
+Ich habe nicht überprüft, ob Ihre Adresse wirklich die Mailingliste
+bezieht. Sollte die Adresse nicht zu den Abonnenten der Mailingliste
+gehören erhalten Sie erst nach Ihrer Bestätigung eine Fehlermeldung.
+
+</text/unsub-nop#E/>
+Hm. Die Adresse
+
+!A
+
+ist kein Abonnent der Mailingliste
+   <#l#>@<#H#>
+und konnte deshalb auch nicht von ihr abgemeldet werden.
+
+Wenn Sie die Liste abbestellen aber trotzdem weiterhin Nachrichten
+aus der Mailingliste empfangen, sind sie wahrscheinlich mit einer
+anderen Adresse eingetragen, als diejenige die sie momentan
+benutzen.
+
+Um festzustellen, unter welcher Adresse Sie die Mailingliste
+empfangen, sehen Sie sich die Header der empfangenen Nachrichten an.
+Jede Nachricht hat Ihre Empfängeradresse in ihrem Return-Path: kodiert.
+Zum Beispiel empfängt die Adresse ich@lightwerk.de alle Listennachrichten
+mit folgendem Return-Path:
+Return-Path: <<#l#>-return-<nummer>-ich=lightwerk.de@<#H#>
+Die Nummer wechselt natürlich, also sieht das zum Beispiel so aus:
+'Return-Path: <<#l#>-return-1234-ich=lightwerk.de@<#H#>>'
+
+Das zeigt, daß die Adresse, über die die Nachrichten bezogen werden,
+ich@lightwerk.de ist. Die Adresse zum Abbestellen der Liste wäre in
+diesem Fall 
+   <#l#>-unsubscribe-ich=lightwerk.de@<#H#>
+Benutzen Sie einfach die so ermittelte Adresse.
+
+Wenn Ihre Listen-Nachrichten einen Header "List-Unsubscribe"
+enthalten, dann können sie die dort angegebene Adresse benutzen. Diese
+hat Ihre Bezugsadresse schon mit in die Abmeldeadresse einbezogen.
+
+Wie Sie die Anzeige aller Header in Ihrem Mailprogramm einschalten,
+ist leider bei jedem Programm anders. Einige Beispiele:
+- Pegasus-Mail: Strg-P (deutsche Version) oder Strg-H (engl. Version)
+- Elm und Mutt: Anzeige der Nachricht nicht mit <Enter> sondern mit 'h'
+- Microsoft Outlook 98: sehen Sie unter Ansicht/Optionen nach. Dort
+                        finden Sie die Internet-Header Ihrer Mail
+- Eudora Pro (Mac): klicken Sie auf die mit "Blah" markierte Stelle
+- ...
+
+Falls all das nicht funktioniert, ist es wahrscheinlich, daß jemand
+die Nachrichten der Mailingliste an sie kopiert. Bitte fragen Sie
+ihren lokalen Mailadministrator um Hilfe. Kann auch dieser Ihnen nicht
+helfen, schicken Sie eine Listen-Nachricht inklusive ALLER HEADER
+zusammen mit einer Erklärung, was sie versucht haben an den Eigentümer
+dieser Liste:
+
+  <#l#>-owner@<#H#>
+
+Dieser wird sich dann mit Ihnen in Verbindung setzen und sich um das
+Problem kümmern. Aber haben Sie bitte Geduld - es handelt sich um
+ein menschliches Wesen, das eventuell vielbeschäftigt ist :)
+
+</text/unsub-ok#E/>
+Bestätigung: die Adresse
+
+!A
+
+wurde von der Mailingliste
+   <#l#>@<#H#>
+abgemeldet.
+
+</text/edit-do#nE/>
+Bitte bearbeiten Sie den folgenden Text und senden Sie ihn an:
+
+!R
+
+Die Funktion "Beantworten" in Ihrem Mailprogramm sollte diese Adresse
+automatisch benutzen.
+
+Solange Sie die Markierungszeilen nicht verändern, kann ich
+Quote-Zeichen (Zitat-Markierungen, in der Regel '> '), die Ihr
+Mail-Programm vor dem Text einfügt, selbständig wieder entfernen.
+
+Markierungszeilen sind Zeilen, die mit '%%%' beginnen. Sie dürfen
+nicht geändert werden (vom Mailprogramm eingefügte Zitat-Markierungen
+sind akzeptabel).
+
+
+</text/edit-list#nE/>
+Durch Remote-Administratoren kann das <#L#>-edit.file
+Kommando benutzt werden, um die Textdateien zu verändern, die die
+Hauptmenge der Antworten von der Liste
+    <#L#>@<#H#>
+ausmachen.
+
+Hier finden Sie eine Aufstellung der Dateinamen und eine kurze
+Beschreibung ihres Inhalts bzw. ihrer Funktion.
+Um den Inhalt einer Datei zu ändern, senden Sie einfach eine
+Mail an
+   <#L#>-edit.file@<#H#>
+wobei Sie 'file' durch den konkreten Dateinamen ersetzen.
+Die Instruktionen zur Bearbeitung erhalten Sie zusammen mit dem
+Text.
+
+Datei               Inhalt / Funktion
+
+bottom              an alle Antworten angehängt, allgemeine
+                    Information zu Kommandos
+digest              Steuerungsinformationen für Digests
+faq                 oft gestellte Fragen und die Antworten zur Liste
+get_bad             anstelle nicht im Archiv vorhandener Nachrichten
+help                allg. Hilfe (zwischen 'top' und 'bottom').
+info                Listenbeschreibung. Die erste Zeile ist Kurzbeschreibung.
+mod_help            Hilfe für Listenmoderatoren
+mod_reject          an den Absender abgewiesener Nachrichten
+mod_request         an Moderatoren, zusammen mit der Nachricht
+mod_sub             an Neu-Abonnenten, nach Moderator-Bestätigung
+mod_sub_confirm     Abonnement-Anforderung, an Moderatoren
+mod_timeout         Zeitüberschreitung, an Absender
+mod_unsub_confirm   Abbestellung, an Remote-Administrator
+sub_bad             Abonnement-Ablehnung, an Abonnent
+sub_confirm         an Neu-Abonnenten, zur Bestätigung des Abonnements
+sub_nop             an Abonnenten, falls er schon Abonnent ist
+sub_ok              an Abonnenten, wenn Abonnement erfolgreich
+top                 Anfang von allen Antworten
+</#tnE/>
+trailer             an alle Listennachrichten angehängt
+</#nE/>
+unsub_bad           an Abonnenten, wenn Abmeldung abgelehnt
+unsub_confirm       an Abonnenten, Anforderung Abmeldebestätigung
+unsub_nop           an Nicht-Abonnenten, wenn Abmeldung angefordert
+unsub_ok            an abgemeldeten Abonnenten, Abmeldung erfolgreich
+
+</text/edit-done#nE/>
+Der Text wurde erfolgreich abgeändert.
+
+</text/info#E/>
+Für diese Liste wurde noch keine Beschreibung bereitgestellt.
+
+</text/faq#E/>
+Oft gestellte Fragen+Antworten für die Mailingliste
+   <#l#>@<#H#>
+
+Leider hat sich noch niemand die Mühe gemacht, ein entsprechendes
+Dokument zu erstellen.
diff --git a/ezmlmrc.en_US b/ezmlmrc.en_US
new file mode 100644 (file)
index 0000000..bf51c12
--- /dev/null
@@ -0,0 +1,1152 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.en_US,v 1.17 1999/12/11 03:30:16 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean state.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#>
+For additional commands, e-mail: <#L#>-help@<#H#>
+</text/bottom#E/>
+
+--- Administrative commands for the <#l#> list ---
+
+I can handle administrative requests automatically. Please
+do not send them to the list address! Instead, send
+your message to the correct command address:
+
+For help and a description of available commands, send a message to:
+   <<#L#>-help@<#H#>>
+
+To subscribe to the list, send a message to:
+   <<#L#>-subscribe@<#H#>>
+
+To remove your address from the list, just send a message to
+the address in the ``List-Unsubscribe'' header of any list
+message. If you haven't changed addresses since subscribing,
+you can also send a message to:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+or for the digest to:
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+</#HEJ/>
+For addition or removal of addresses, I'll send a confirmation
+message to that address. When you receive it, simply reply to it
+to complete the transaction.
+
+</#E/>
+If you need to get in touch with the human owner of this list,
+please send a message to:
+
+    <<#L#>-owner@<#H#>>
+
+Please include a FORWARDED list message with ALL HEADERS intact
+to make it easier to help you.
+
+--- Enclosed is a copy of the request I received.
+
+</text/bounce-bottom#E/>
+
+--- Enclosed is a copy of the bounce message I received.
+
+</text/bounce-num#E/>
+
+I've kept a list of which messages from the <#L#> mailing list have 
+bounced from your address.
+
+</#aE/>
+Copies of these messages may be in the archive.
+
+</#aE/>
+To retrieve a set of messages 123-145 (a maximum of 100 per request),
+send an empty message to:
+   <<#L#>-get.123_145@<#H#>>
+
+To receive a subject and author list for the last 100 or so messages,
+send an empty message to:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Here are the message numbers:
+
+</text/dig-bounce-num#E/>
+
+I've kept a list of which digests from the <#L#>-digest mailing list
+have bounced from your address. For each digest you missed, I have
+noted the number of the first message in the digest.
+
+</#aE/>
+I do not archive the digests themselves, but you may be able to
+get the messages from the main list archive.
+
+To retrieve a set of messages 123-145 (a maximum of 100 per request),
+send an empty message to:
+   <<#L#>-get.123_145@<#H#>>
+
+To receive a subject and author list for the last 100 or so messages,
+send an empty message to:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Here are the digest message numbers:
+
+</text/bounce-probe#E/>
+
+Messages to you from the <#l#> mailing list seem to
+have been bouncing. I sent you a warning message, but it bounced.
+I've attached a copy of the bounce message.
+
+This is a probe to check whether your address is reachable. If this
+probe bounces, I will remove your address from the
+<#l#>@<#H#> mailing list, without further notice.
+
+You can re-subscribe by sending a message to this address:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+Messages to you from the <#l#> mailing list seem to
+have been bouncing. I've attached a copy of the first bounce
+message I received.
+
+If this message bounces too, I will send you a probe. If the probe bounces,
+I will remove your address from the <#l#> mailing list,
+without further notice.
+
+</text/digest#dE/>
+To subscribe to the digest, e-mail:
+       <<#L#>-digest-subscribe@<#H#>>
+
+To unsubscribe from the digest, e-mail:
+       <<#L#>-digest-unsubscribe@<#H#>>
+
+To post to the list, e-mail:
+       <<#L#>@<#H#>>
+
+</text/get-bad#E/>
+Sorry, that message is not in the archive.
+
+</text/help#E/>
+This is a generic help message. The message I received wasn't sent to
+any of my command addresses.
+
+Here is a list of the command addresses supported:
+
+Send mail to the following for info and FAQ for this list:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Similar addresses exist for the digest list:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+To get messages 123 through 145 (a maximum of 100 per request), mail:
+   <<#L#>-get.123_145@<#H#>>
+
+To get an index with subject and author for messages 123-456, mail:
+   <<#L#>-index.123_456@<#H#>>
+
+To receive all messages with the same subject as message 12345,
+send an empty message to:
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+The messages do not really need to be empty, but I will ignore
+their content. Only the ADDRESS you send to is important.
+
+You can start a subscription for an alternate address,
+for example "john@host.domain", just add a hyphen and your
+address (with '=' instead of '@') after the command word:
+    <<#L#>-subscribe-john=host.domain@<#H#>>
+
+To stop subscription for this address, mail:
+    <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</text/mod-help#E/>
+Thank you for agreeing to moderate the <#L#>@<#H#>
+mailing list.
+
+My commands are a little different from other mailing lists,
+but I think you will find them intuitive and easy to use.
+
+Here are some instructions for the tasks you may have to perform
+as a list-owner and/or moderator.
+
+General list instructions follow at the end of this message.
+
+Remote subscription
+-------------------
+As a moderator, you can subscribe and unsubscribe any address to
+the mailing list. To subscribe "john@host.domain", simply put
+a hyphen after the command word, then his address with '=' instead
+of the '@'. For instance, to subscribe that address, send mail to:
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+You can similarly remove the address by sending a message to:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#dE/>
+For the digest list:
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+</#E/>
+That's all. No subject and no message body needed!
+
+</#rE/>
+I will send you a confirmation request, to make sure
+that you really sent the request. Simply reply to the
+message, and your wish has been granted.
+</#RE/>
+I will send a confirmation request to the user address, in this
+case <john@host.domain>. All the user has to do is to reply to 
+this confirmation request message.
+</#E/>
+
+The confirmations are necessary to make it extremely hard
+for a third party to add or remove an address to the list.
+
+I will notify the user when his/her subscriber status
+has changed.
+
+Subscription
+------------
+
+Any user can subscribe or unsubscribe by sending mail to:
+
+    <<#L#>-subscribe@<#H#>>
+    <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+For the digest list:
+
+    <<#L#>-digest-subscribe@<#H#>>
+    <<#L#>-digest-unsubscribe@<#H#>>
+
+</#E/>
+The user will receive a confirmation request to make
+sure s/he controls the subscription address. Once this
+is verified the user is unsubscribed.
+
+</#sE/>
+Since this list is moderated for subscriptions, I will send a
+second confirmation request to the moderator(s). Since the user
+has already confirmed the desire to be on the list, you as the
+moderator can be highly confident that the subscriber address is
+real. If you want to approve the users request, simply reply to
+my CONFIRM message. If not, you can simply delete my message or
+possibly contact the potential subscriber for more information.
+</#SE/>
+Subscriptions work the same way.
+</#E/>
+
+The user can also use:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+to have mail sent to "mary@host.domain". Only if she receives mail
+at this address will she receive the confirmation request and be
+able to reply to it.
+
+Your address and identity will not be revealed to the subscriber,
+unless you send mail directly to the user.
+
+</#rlE/>
+To get a subscriber list for <#L#>@<#H#>, send a message to:
+   <<#L#>-list@<#H#>>
+
+To get a list transaction log <#L#>@<#H#>, send a message to:
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+For digest subscribers:
+   <<#L#>-digest-list@<#H#>>
+and:
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+You can remotely edit the text files that make up the responses the
+list sends out. To get a list of files and editing instructions, mail:
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+Moderated posts
+---------------
+When posts are moderated, I will save the posted message and send
+you a copy together with instructions. The message to you will
+have "MODERATE for ..." as the subject.
+
+To accept the post, just reply to the 'Reply-To:', which I have
+configured with the correct "accept" address address. You do not need
+to include the post itself. In fact, I will ignore anything you send
+me as long as the address you send to is correct.
+
+If you want to reject it, send mail to the 'From:' address, which
+I have configured with the correct "reject" address. This can
+usually be done by 'reply-to-all', then deleting any address other
+than the "reject" address. You may add a comment to the sender between
+two lines starting with three '%'. I will send only this comment to the
+sender with the rejected post. Again, I will not reveal your identity.
+
+I will process the message according to the first reply I receive.
+If you send me a request to accept a message that has already been
+rejected or vice versa, I will let you know.
+
+If I receive no moderator replies within a certain period of
+time (normally 5 days), I will return the message to the sender
+with an explanation of what happened. Your administrator can also
+set up the list so that such "ignored" messages are simply deleted
+without notification, rather than returned to sender.
+</#E/>
+
+Vacations
+---------
+If you are temporarily at a different address, just forward all messages
+that have the correct 'Mailing-List:' header (or all that have subjects
+starting with 'MODERATE for <#L#>@<#H#>'
+or 'CONFIRM subscribe to <#L#>@<#H#>') to the
+new address. You can then moderate from the new address. Alternatively,
+you can forward the messages to a friend so that s/he can moderate
+for you. Please OK this with the list owner first.
+
+If you would like to automatically approve all requests while you
+are gone, set up you mail client to auto-reply to messages that
+have subjects meeting the above criteria.
+
+</#rE/>
+If you try to do remote administration from an address that is not
+your own, the subscriber, not you, will be asked to confirm. After
+that, a moderator confirm request is sent to all moderators.
+I'm doing this because I have no way of knowing that it is you that
+sent the original request.
+
+Please note that your original request (and your address) are sent to
+the subscriber in this case!
+</#E/>
+
+Good luck!
+
+PS: Please contact the list owner (<#L#>-owner@<#H#>) if you
+have any questions or problems.
+
+</text/mod-reject#E/>
+I'm sorry, your message (enclosed) was not accepted by the moderator.
+If the moderator has made any comments, they are shown below.
+</text/mod-request#E/>
+The enclosed message was submitted to the <#L#>@<#H#>
+mailing list. If you'd like to approve it for distribution to all
+the subscribers, please e-mail:
+
+!A
+
+Usually, this happens when you just hit the "reply" button. You can
+check the address to make sure that it starts with
+"<#L#>-accept". If this does not work, simply copy the
+address and paste it into the "To:" field of a new message.
+</#xE/>
+
+Alternatively, click here:
+       mailto:<#A#>
+</#E/>
+
+To reject the post and cause it to be returned to the
+sender, please send a message to:
+
+!R
+
+Usually, it is easiest to hit the "reply-to-all" button, and then
+remove all the addresses except the one starting with
+"<#L#>-reject".
+</#xE/>
+
+Alternatively, click here:
+       mailto:<#R#>
+</#E/>
+
+You do not need to copy the post in your response to accept or 
+reject it. If you wish to send a comment to the sender of a rejected
+post, please include it between two marker lines starting with three
+percent signs ('%'):
+
+%%% Start comment
+%%% End comment
+
+Thank you for your help!
+
+--- Enclosed, please find the posted message.
+
+</text/mod-sub#E/>
+--- I have subscribed or unsubscribed you at the request of
+a moderator of the <#l#>@<#H#> mailing list.
+
+If this is not an action you desire, please send a complaint 
+or other comments to the list owner (<#l#>-owner@<#H#>) as soon 
+as possible.
+
+</text/mod-timeout#E/>
+I'm sorry, the list moderators for the <#L#> list
+have failed to act on your post. Thus, I'm returning it to you.
+If you feel that this is in error, please repost the message
+or contact a list moderator directly.
+
+--- Enclosed, please find the message you sent.
+
+</text/mod-sub-confirm#E/>
+I respectfully request your permission to add
+
+!A
+
+to the subscribers of the <#l#> mailing list. This request
+either came from you, or it has already been verified by
+the potential subscriber.
+
+To confirm, please send an empty reply to this address:
+
+!R
+
+Usually, this happens when you just hit the "reply" button.
+If this does not work, simply copy the address and paste it into
+the "To:" field of a new message.
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+If you don't approve, simply ignore this message.
+
+Thank you for your help!
+
+</text/mod-unsub-confirm#E/>
+A request has been made to remove
+
+!A
+
+from the <#l#> mailing list. If you agree, please send
+an empty reply to this address:
+
+!R
+
+Usually, this happens when you just hit the "reply" button.
+If this does not work, simply copy the address and paste it into
+the "To:" field of a new message.
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+If you don't approve, simply ignore this message.
+
+Thank you for your help!
+
+</text/sub-bad#E/>
+Oops, that confirmation number appears to be invalid.
+
+The most common reason for invalid numbers is expiration. I have to
+receive confirmation of each request within ten days. Also, make sure
+the entire confirmation number was in the reply you sent me. Some 
+e-mail programs have a habit of cutting off some of the reply address,
+which can be quite long.
+
+I've set up a new confirmation number. To confirm that you would like
+
+!A
+
+added to the <#l#> mailing list, please send
+an empty reply to this address:
+
+!R
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+Again, check the reply address carefully to make sure it is all included 
+before you confirm your subscription.
+
+Sorry for the trouble.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+To confirm that you would like
+
+!A
+
+added to the <#l#> mailing list, please send
+an empty reply to this address:
+
+!R
+
+Usually, this happens when you just hit the "reply" button.
+If this does not work, simply copy the address and paste it into
+the "To:" field of a new message.
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+This confirmation serves two purposes. First, it verifies that I am able
+to get mail through to you. Second, it protects you in case someone
+forges a subscription request in your name.
+
+</#qE/>
+Some mail programs are broken and cannot handle long addresses. If you
+cannot reply to this request, instead send a message to
+<<#L#>-request@<#H#>> and put the
+entire address listed above into the "Subject:" line.
+
+</#sE/>
+This list is moderated. Once you have sent this confirmation, the
+request will be sent to the moderator(s) of this list. I will notify
+you when your subscription has been activated.
+
+</text/sub-nop#E/>
+I've been unable to carrry out your request: The address
+
+!A
+
+was already on the <#l#> mailing list when I received
+your request, and remains a subscriber.
+
+</text/sub-ok#E/>
+Acknowledgment: I have added the address
+
+!A
+
+to the <#l#> mailing list.
+
+Welcome to <#l#>@<#H#>!
+
+Please save this message so that you know the address you are
+subscribed under, in case you later want to unsubscribe or change your
+subscription address.
+
+To unsubscribe, send a message to:
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Hi! This is the ezmlm program. I'm managing the
+<#l#>@<#H#> mailing list.
+
+I'm working for my owner, who can be reached
+at <#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+Oops, that confirmation number appears to be invalid.
+
+The most common reason for invalid numbers is expiration. I have to
+receive confirmation of each request within ten days. Also, make sure
+the entire confirmation number was in the reply you sent me. Some 
+e-mail programs have a habit of cutting off some of the reply address,
+which can be quite long.
+
+I've set up a new confirmation number. To confirm that you would like
+
+!A
+
+removed from the <#l#> mailing list, please send an empty reply 
+to this address:
+
+!R
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+Again, check the reply address carefully to make sure it is all included 
+before you confirm this action.
+
+Sorry for the trouble.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+To confirm that you would like
+
+!A
+
+removed from the <#l#> mailing list, please send an empty reply 
+to this address:
+
+!R
+
+Usually, this happens when you just hit the "reply" button.
+If this does not work, simply copy the address and paste it into
+the "To:" field of a new message.
+</#xE/>
+
+or click here:
+       mailto:<#R#>
+</#E/>
+
+I haven't checked whether your address is currently on the mailing list.
+To see what address you used to subscribe, look at the messages you are
+receiving from the mailing list. Each message has your address hidden
+inside its return path; for example, mary@xdd.ff.com receives messages
+with return path: <<#l#>-return-<number>-mary=xdd.ff.com@<#H#>.
+
+</#qE/>
+Some mail programs are broken and cannot handle long addresses. If you
+cannot reply to this request, instead send a message to
+<<#L#>-request@<#H#>> and put the entire address listed above
+into the "Subject:" line.
+
+</text/unsub-nop#E/>
+I'm sorry, I've been unable to carry out your request,
+since the address
+
+!A
+
+was not on the <#l#> mailing list when I received
+your request and is not a subscriber of this list.
+
+If you unsubscribe, but continue to receive mail, you're subscribed
+under a different address than the one you currently use.
+Please look at the header for:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+This shows that the subscription address is ``user@host.dom''.
+The unsubscribe address for this user would be:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+
+Just mail to that address, adjusted for the real subscription address.
+
+If the message has a ``List-Unsubscribe:'' header, you can send
+a message to the address in that header. It contains the subscription
+already coded into it.
+
+For some mail programs, you need to make the headers visible to
+see the return path:
+
+For Eudora 4.0, click on the "Blah blah ..." button.
+For PMMail, click on "Window->Show entire message/header". 
+
+If this still doesn't work, I'm sorry to say that I can't help you.
+Please FORWARD a list message together with a note about what you're
+trying to achieve and a list of addresses that you might be subscribed
+under to my owner:
+
+    <<#l#>-owner@<#H#>>
+
+who will take care of it. My owner is a little bit slower than I am, 
+so please be patient.
+
+</text/unsub-ok#E/>
+Acknowledgment: I have removed the address
+
+!A
+
+from the <#l#> mailing list. This address
+is no longer a subscriber.
+
+</text/edit-do#nE/>
+Please edit the following text file and send it to this address:
+
+!R
+
+Your mailer should have a Reply feature that uses this address automatically.
+
+I can remove the quote marks that your mailer adds to the text,
+as long as you do not edit the marker lines themselves.
+
+The marker lines are the lines starting with '%%%'. They must not
+be modified (extra characters added by your mailer at the beginning
+of the line are acceptable).
+
+
+</text/edit-list#nE/>
+The <#L#>-edit.file command can be used by a remote
+administrator to edit the text files than make up the bulk
+of the responses from the <#L#>@<#H#> list.
+
+What follows is a list of the response file name and a short
+description of when their contents are used.  To edit a file,
+simply send mail to <#L#>-edit.file, substituting the file name
+for 'file'. Editing instructions are mailed with the text file.
+
+File                Use
+
+bottom              bottom of all responses. General command info.
+digest              'administrivia' section of digests.
+faq                 frequently asked questions specific to this list.
+get_bad             in place of messages not found in the archive.
+help                general help (between 'top' and 'bottom').
+info                list info. First line should be meaningful on its own.
+mod_help            specific help for list moderators.
+mod_reject          to sender of rejected post.
+mod_request         to message moderators together with post.
+mod_sub             to subscriber after moderator confirmed subscribe.
+mod_sub_confirm     to subscription mod to request subscribe confirm.
+mod_timeout         to sender of timed-out post.
+mod_unsub_confirm   to remote admin to request unsubscribe confirm.
+sub_bad             to subscriber if confirm was bad.
+sub_confirm         to subscriber to request subscribe confirm.
+sub_nop             to subscriber after re-subscription.
+sub_ok              to subscriber after successful subscription.
+top                 top of all responses.
+</#tnE/>
+trailer             added to all posts sent out from the list.
+</#nE/>
+unsub_bad           to subscriber if unsubscribe confirm was bad.
+unsub_confirm       to subscriber to request unsubscribe confirm.
+unsub_nop           to non-subscriber after unsubscribe.
+unsub_ok            to ex-subscriber after successful unsubscribe.
+
+</text/edit-done#nE/>
+The text file was successfully updated.
+</text/info#E/>
+No information has been provided for this list.
+</text/faq#E/>
+FAQ - Frequently asked questions of the <#l#>@<#H#> list.
+
+None available yet.
+
diff --git a/ezmlmrc.es b/ezmlmrc.es
new file mode 100644 (file)
index 0000000..5b5cf00
--- /dev/null
@@ -0,0 +1,1264 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.es,v 1.4 1999/12/22 04:06:38 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc- Traducción de: Vicent Mas, Francesc Alted, Sonia Lorente, Cyndy DePoy
+# #######   Servicom2000
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+Para dar de baja la suscripción, mande un mensaje a:
+
+   <#L#>-unsubscribe@<#H#>
+
+Para obtener el resto de direcciones-comando, mande un mensaje a:
+
+   <#L#>-help@<#H#>
+
+</text/bottom#E/>
+
+--- Comandos administrativos para la lista <#l#> ---
+
+Puedo gestionar automáticamente peticiones administrativas. Por
+favor, no envíe este tipo de peticiones a la lista. Envíelas a la
+dirección-comando adecuada:
+
+Para obtener ayuda y una descripción de los comandos disponibles,
+mande un mensaje a:
+
+   <<#L#>-help@<#H#>>
+
+Para suscribirse a la lista, mande un mensaje a:
+
+   <<#L#>-subscribe@<#H#>>
+
+Para eliminar su dirección de la lista, simplemente mande un
+mensaje a la dirección que hay en la cabecera
+``List-Unsubscribe'' de cualquier mensaje de la lista. Si usted
+no ha cambiado su dirección desde que se suscribió, también puede
+enviar un mensaje a:
+
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+o, para los resúmenes, a:
+
+   <<#L#>-unsubscribe@<#H#>>
+
+</#E/>
+
+Para añadir o eliminar direcciones, le enviaré un mensaje de
+confirmación a esa dirección. Cuando lo reciba, pulse el botón
+'Responder' para completar la transacción.
+
+Si necesita contactar con el propietario de la lista, por favor,
+mande un mensaje a:
+
+    <<#L#>-owner@<#H#>>
+
+Por favor, incluya una lista de mensajes REENVIADOS con TODAS LAS
+CABECERAS intactas para que sea más fácil ayudarle.
+
+--- Le adjunto una copia de la petición que he recibido.
+
+</text/bounce-bottom#E/>
+
+--- Le adjunto una copia del mensaje devuelto que he recibido.
+
+</text/bounce-num#E/>
+
+He guardado una lista de todos los mensajes de la lista de correo
+<#L#> que han sido devueltos procedentes de su dirección.
+
+</#aE/>
+
+Una copia de estos mensajes puede estar en el archivo.
+
+</#aE/>
+
+Para recibir los mensajes desde el número 123 al 145 (con un
+máximo de 100 por petición), escriba a:
+
+   <<#L#>-get.123_145@<#H#>>
+
+Para recibir una lista por "Asunto" y "Autor" de los últimos 100
+mensajes, envíe un mensaje en blanco a:
+
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Aquí están los números de los mensajes:
+
+</text/dig-bounce-num#E/>
+
+He guardado una lista de los resúmenes de la lista de correo
+<#L#> que han sido devueltos desde su dirección. Por cada uno de
+los resúmenes perdidos, he anotado el número del primer mensaje
+en el resumén.
+
+</#aE/>
+
+No archivo los resúmenes propiamente dichos, pero puede conseguir
+los mensajes del archivo principal de la lista.
+
+Para recuperar el grupo de mensajes del 123 al 145 (máximo 100
+por petición), envíe un mensaje en blanco a:
+
+   <<#L#>-get.123_145@<#H#>>
+
+Para recibir una lista por "Asunto" y "Autor" de los últimos 100
+mensajes, envíe un mensaje en blanco a:
+
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Estos son los números de mensaje de los resúmenes:
+
+</text/bounce-probe#E/>
+
+Parece que han sido devueltos algunos mensajes dirigidos a usted
+de la lista de correo <#l#>. Le he enviado un mensaje de aviso,
+pero también ha sido devuelto. Le adjunto una copia del mensaje
+devuelto.
+
+Esta es una prueba para comprobar si su dirección es accesible.
+Si esta prueba me es devuelta, eliminaré su dirección de la lista
+de correo <#l#>@<#H#>, sin más avisos. En ese caso, puede usted
+volver a suscribirse mandando un mensaje a esta dirección:
+
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+Han sido devueltos algunos mensajes para usted de la lista de
+correo <#l#>. Le adjunto una copia del primer mensaje devuelto
+que recibí. Si también se devuelve este mensaje, le mandaré una
+prueba. Si se devuelve la prueba, eliminaré su dirección de la
+lista de correo <#l#> sin más avisos.
+
+</text/digest#dE/>
+Para suscribirse al resumen escriba a:
+
+       <#L#>-digest-subscribe@<#H#>
+
+Para cancelar su suscripción al resumen, escriba a:
+
+       <#L#>-digest-unsubscribe@<#H#>
+
+Para mandar un mensaje a la lista, escriba a:
+
+       <#L#>@<#H#>
+
+</text/get-bad#E/>
+Lo siento, ese mensaje no está en el archivo.
+
+</text/help#E/>
+
+Este es un mensaje genérico de ayuda. El mensaje que recibí no
+fue mandado a ninguna de mis direcciones-comando.
+
+Aquí hay una lista de las direcciones comando disponibles:
+
+Mande un correo a las siguientes direcciones-comando para obtener
+información y FAQ de esta lista:
+
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Para la lista de resúmenes existen direcciones-comando análogas:
+
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+
+Para recibir los mensajes desde el número 123 al 145 (con un
+máximo de 100 por petición), escriba a:
+
+   <<#L#>-get.123_145@<#H#>>
+
+Para obtener un índice con los campos "Asunto" y "Autor" para los
+mensajes del 123 al 456, debe escribir a:
+
+   <<#L#>-index.123_456@<#H#>>
+
+Para recibir todos los mensajes con el mismo "Asunto" que el
+mensaje 12345, mande un mensaje en blanco a:
+
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+
+En realidad no es necesario que los mensajes estén en blanco,
+pero si no lo están ignoraré su contenido. Sólo es importante la
+DIRECCIÓN a la que se envía.
+
+Usted puede suscribir una dirección alternativa, por ejemplo,
+para "david@ordenador.dominio", simplemente añada un guión y su
+dirección (con '=' en lugar de '@') después del comando:
+
+   <<#L#>-subscribe-david=ordenador.dominio@<#H#>>
+
+Para cancelar la suscripción de esta dirección, escriba a:
+
+<<#L#>-unsubscribe-david=ordenador.dominio@<#H#>>
+
+</text/mod-help#E/>
+Gracias por acceder a moderar la lista <#L#>@<#H#>.
+
+Mis comandos son algo distintos a los de otras listas de correo,
+pero creo que los encontrará intuitivos y fáciles de utilizar.
+
+Estas son algunas instrucciones para las tareas que debe realizar
+como propietario y/o moderador de una lista de correo.
+
+Al final del mensaje se incluyen algunas instrucciones generales
+para la lista.
+
+Suscripción remota
+-------------------
+
+Como moderador, puede añadir o quitar cualquier dirección de la
+lista. Para suscribir "david@ordenador.dominio", basta con poner
+un guión después del comando, y después su dirección con '=' en
+lugar de '@'. Por ejemplo, para suscribir esa dirección, mande
+correo a:
+
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+De la misma manera puede eliminar la dirección de la lista
+mandando un mensaje a:
+
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#dE/>
+Para suscribirse o darse de baja de la lista de resúmenes:
+
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+</#E/>
+
+Eso es todo. No es necesario poner "Asunto" o cuerpo principal en
+el mensaje.
+
+</#rE/>
+
+Le mandaré una petición de confirmación, para asegurarme que
+usted me envió la petición. Simplemente responda al mensaje, y se
+cursará su petición. </#RE/> Mandaré una petición de confirmación
+a la dirección del usuario, en este caso a
+<david@ordenador.dominio>. El usuario simplemente debe responder
+a este mensaje de confirmación. </#E/>
+
+Las confirmaciones son necesarias para impedir, en la medida de
+lo posible, que un tercero añada o quite una dirección de la
+lista.
+
+Notificaré al usuario cualquier cambio en el estado de su
+suscripción.
+
+Suscripción
+------------
+
+Cualquier usuario puede suscribirse o darse de baja mandando un
+correo a:
+
+   <#L#>-subscribe@<#H#>
+   <#L#>-unsubscribe@<#H#>
+
+</#dE/>
+Para la lista de resúmenes:
+
+   <#L#>-digest-subscribe@<#H#>
+   <#L#>-digest-unsubscribe@<#H#>
+
+</#E/>
+
+El usuario recibirá una petición de confirmación para asegurarse
+que él/ella posee la dirección de suscripción. Una vez
+verificada, se procederá a dar de baja al usuario.
+
+</#sE/>
+
+Como esta lista está moderada para suscripciones, mandaré una
+segunda petición de confirmación al moderador. Como el usuario ya
+ha confirmado su deseo de estar en la lista, usted, como
+moderador, puede estar seguro de que la dirección del suscriptor
+es real. Si quiere aprobar la petición del usuario, simplemente
+responda a mi mensaje de confirmación. En caso contrario, puede
+simplemente borrar mi mensaje o contactar con el suscriptor para
+pedir más información.
+
+</#SE/>
+Las suscripciones funcionan del mismo modo.
+</#E/>
+
+El usuario también puede utilizar:
+
+   <<#L#>-subscribe-maria=ordenador.dominio@<#H#>>
+   <<#L#>-unsubscribe-maria=ordenador.dominio@<#H#>>
+
+para que le manden correo a: "maria@ordenador.dominio". Solo si
+ella recibe correo en esta dirección, podrá recibir la petición
+de confirmación y mandar una contestación.
+
+Su dirección e identidad no serán reveladas al suscriptor, a no
+ser que le mande correo directamente al usuario.
+
+</#rlE/>
+
+Para conseguir una lista de suscriptores para <#L#>@<#H#> envíe
+un mensaje a:
+
+   <<#L#>-list@<#H#>>
+
+Para conseguir un log de la lista de transacciones para
+<#L#>@<#H#> mande un mensaje a:
+
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+Para suscriptores al resumen:
+
+   <<#L#>-digest-list@<#H#>>
+
+y:
+
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+
+Usted puede modificar remotamente los ficheros de texto que
+componen las respuestas mandadas por la lista. Para conseguir una
+lista de ficheros e instrucciones de edición, escriba a:
+
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+Mensajes moderados.
+-------------------
+
+Cuando los mensajes están moderados, guardaré el mensaje enviado
+y le mandaré una copia junto con instrucciones. El mensaje para
+usted llevará "MODERATE for ..." como "Asunto".
+
+Para aceptar el mensaje, simplemente responda a la dirección que
+figura en el campo 'Responder a:' , que ya he configurado con la
+dirección correcta de aceptación. No necesita incluir el mensaje
+en sí. De hecho, ignoraré el contenido siempre y cuando la
+dirección a la que escriba sea correcta.
+
+Si quiere rechazar el mensaje, mande un correo a la dirección
+'De:', que ya he configurado con la dirección correcta de
+"rechazo". Eso normalmente se hace con 'Responder a todos', y
+borrando después todas las direcciones salvo la dirección
+"rechazada". Puede añadir un comentario al remitente insertando
+dicho comentario entre dos líneas que empiecen con tres '%'. Solo
+mandaré este comentario al remitente con el mensaje rechazado.
+Una vez más, no revelaré su identidad.
+
+Procesaré el mensaje en función de la primera respuesta que
+recibo. Le avisaré si me manda una petición para aceptar un
+mensaje que, Previamente, había sido rechazado o viceversa.
+
+Si no recibo respuestas del moderador dentro de un cierto periodo
+de tiempo (normalmente 5 días), devolveré el mensaje al remitente
+con una explicación de lo que ha pasado. Su administrador también
+puede configurar la lista para que estos mensajes "ignorados"
+simplemente sean borrados sin notificación, en lugar de ser
+devueltos al remitente.
+
+</#E/>
+
+Vacaciones
+----------
+
+Si está temporalmente en otra dirección, simplemente reenvíe
+todos los mensajes que tienen el encabezamiento 'Mailing-List:'
+(o todos los que tienen "Asunto" empezando con 'MODERATE for
+<#L#>@<#H#>' o con 'CONFIRM subscribe to <#L#>@<#H#>') a la nueva
+dirección. Así podrá leer la lista desde la nueva dirección. Como
+alternativa, puede reenviar los mensajes a un amigo para que él o
+ella los lea en su lugar. Por favor, antes de hacerlo consiga el
+permiso del propietario de la lista.
+
+Si desea aprobar automáticamente todas las peticiones mientras
+esté fuera, configure su programa de correo para responder
+automáticamente a mensajes que tienen un "Asunto" que reúna los
+criterios anteriormente expuestos.
+
+</#rE/>
+
+Si intenta administrar la lista remotamente, desde una dirección
+que no es la suya, el suscriptor cuya dirección está utilizando,
+y no usted, recibirá la petición de confirmación. Entonces, se
+mandará una petición de confirmación a todos los moderadores.
+Hago esto porque no tengo manera de saber que usted realmente ha
+mandado la petición original.
+
+En este caso, ¡Recuerde que se manda su petición original (y su
+dirección) al suscriptor!
+
+</#E/>
+
+¡Buena suerte!
+
+PD: Por favor, póngase en contacto con el propietario de la lista
+(<#L#>-owner@<#H#>) si tiene preguntas o problemas.
+
+</text/mod-reject#E/>
+
+Lo siento, el mensaje que le adjunto no fue aceptado por el
+moderador. Si el moderador ha hecho algún comentario, aparecerá
+en la parte inferior.
+
+</text/mod-request#E/>
+
+El mensaje adjunto fue mandado a la lista de correo <#L#>@<#H#>.
+
+Si desea aprobar su distribucisn a todos los suscriptores, por
+favor, escriba a:
+
+!A
+
+Normalmente esto ocurre al pulsar el botón "responder". Usted
+puede comprobar la dirección para asegurarse de que empieza por
+"<#L#>-accept" . Si esto no funciona, simplemente copie la
+dirección y péguela en el campo "Para:" de un nuevo mensaje.
+</#xE/>
+
+Como alternativa haga clic aquí:
+
+       mailto:<#A#>
+</#E/>
+
+Para rechazar el mensaje y hacer que sea devuelto al remitente,
+por favor, mande un mensaje a:
+
+!R
+
+Normalmente, lo más fácil es hacer clic en el botón "Responder a
+todos" y luego quitar todas las direcciones menos la que empieza
+con "<#L#>-reject".
+</#xE/>
+
+Como alternativa, haga clic aquí:
+       mailto:<#R#>
+</#E/>
+
+No es necesario copiar el mensaje en su respuesta para aceptarlo
+o rechazarlo. Si desea mandar un comentario al remitente de un
+mensaje rechazado, por favor, inclúyalo entre dos líneas que
+empiezan con tres signos de porcentaje ('%'):
+
+%%% Inicio del comentario
+%%% Fin del comentario
+
+¡Gracias por su ayuda!
+
+--- Se adjunta el mensaje enviado.
+
+</text/mod-sub#E/>
+
+--- Le he suscrito o dado de baja por petición del moderador de
+la lista de correo <#l#>@<#H#>.
+
+Si no está de acuerdo con esta acción, por favor, mande una queja
+u otros comentarios al propietario de la lista
+(<#l#>-owner@<#H#>) tan pronto como le sea posible.
+
+</text/mod-timeout#E/>
+
+Lo siento, los moderadores de la lista <#L#> no han procesado su
+mensaje. Por esa razón, se lo devuelvo. Si cree que esto es un
+error, por favor, vuelva a mandar el mensaje o póngase en
+contacto con el moderador de la lista directamente.
+
+--- Le adjunto el mensaje que mandó.
+
+</text/mod-sub-confirm#E/>
+Respetuosamente pido permiso para añadir
+
+!A
+
+a los suscriptores de la lista de correo <#l#>. Esta petición o
+procede de usted o ha sido ya verificada por el suscriptor.
+
+Para confirmar, por favor, envíe un mensaje en blanco a esta
+dirección:
+
+!R
+
+Normalmente esto ocurre al pulsar el botón "Responder". Si esto
+no funciona, simplemente copie la dirección y péguela en el campo
+"Para:" de un nuevo mensaje. </#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+Si no está de acuerdo, simplemente ignore este mensaje. 
+
+¡Gracias por su ayuda!
+
+</text/mod-unsub-confirm#E/>
+Se ha hecho una petición para eliminar
+
+!A
+
+de la lista de correo <#l#>. Si está de acuerdo, por favor, envíe
+un mensaje en blanco a esta dirección:
+
+!R
+
+Normalmente, esto ocurre al pulsar el botón "Responder". Si esto
+no funciona, simplemente copie la dirección y péguela en el campo
+"Para:" de un nuevo mensaje. 
+</#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+Si no está de acuerdo, simplemente ignore este mensaje. 
+
+¡Gracias por su ayuda!
+
+</text/sub-bad#E/>
+¡Vaya!, parece que el número de confirmación no es válido. 
+
+La principal causa por la que los números se invalidan es su
+expiración. Yo tengo que recibir confirmación de cada petición en
+un plazo de diez días. Además, asegúrese de que el número de
+confirmación completo estaba incluido en la respuesta que me
+mandó. Algunos programas de correo tienen la (mala) costumbre de
+cortar parte de la dirección de respuesta, que puede ser muy
+larga.
+
+He configurado un nuevo número de confirmación. Para confirmar
+que le gustaría que
+
+!A
+
+fuese añadida a la lista de correo <#l#>, por favor, mande un
+mensaje en blanco a esta dirección:
+
+!R
+</#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+De nuevo, compruebe cuidadosamente la dirección de la respuesta
+para asegurarse que esté todo incluido antes de confirmar su
+suscripción.
+
+Perdone las molestias.
+
+       <#L#>-Propietario <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+Para confirmar que le gustaría que
+
+!A
+
+fuese añadido a la lista de correo <#l#>, por favor, envíe un
+mensaje en blanco a esta dirección:
+
+!R
+
+Normalmente esto ocurre al pulsar el botón "Responder". Si eso no
+funciona, es suficiente copiar la dirección y pegarla en el campo
+"Para:" de un nuevo mensaje. 
+</#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+Esta confirmación cumple dos propósitos. Primero, verifica que
+puedo mandarle correo. Segundo, le protege en el caso de que
+alguien intente falsificar una petición de suscripción en su
+nombre.
+
+</#qE/>
+
+Algunos programas de correo no pueden manejar direcciones largas.
+Si no puede responder a esta petición, envíe un mensaje a
+<<#L#>-request@<#H#>> y ponga la dirección entera escrita arriba
+en la línea de "Asunto:".
+
+</#sE/>
+
+Esta lista está moderada. Una vez que haya enviado esta
+confirmación, se mandará la petición al moderador de la lista.
+Cuando su suscripción haya sido activada, se lo notificaré.
+
+</text/sub-nop#E/>
+No he conseguido cursar su petición: La dirección
+
+!A
+
+ya estaba en la lista de correo <#l#> cuando recibí su petición,
+y usted sigue siendo suscriptor.
+
+</text/sub-ok#E/>
+Acuse de recibo: He añadido la dirección
+
+!A
+
+A la lista de correo <#l#>.
+
+¡Bienvenido a <#l#>@<#H#>!
+
+Por favor guarde este mensaje para que sepa bajo que dirección
+está suscrito, por si luego quiere cancelar su suscripción o
+cambiar la dirección de la misma.
+
+Para cancelar su suscripción mande un mensaje a:
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+
+¡Hola! Soy el programa ezmlm. Me ocupo de la lista de correo
+<#l#>@<#H#>.
+
+</#x/>
+
+Estoy trabajando para mi propietario, a quien se puede localizar
+en <#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+¡Vaya!, parece que ese número de confirmación es inválido. 
+
+La principal razón por la que los números de confirmación se
+invalidan es la expiración. Debo recibir confirmación de cada
+petición en un plazo de diez días. Además, asegúrese que el
+número completo de confirmación estaba incluido en la respuesta
+que me mandó. Tenga en cuenta que algunos programas de correo
+tienen la (mala) costumbre de cortar parte de la dirección de
+respuesta, que puede ser muy larga.
+
+He configurado un nuevo número de confirmación. Para confirmar
+que le gustaría que
+
+!A
+
+fuese dado de baja en la lista de correo <#l#>, por favor, mande
+un mensaje en blanco a esta dirección:
+
+!R
+</#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+De nuevo, compruebe la dirección de respuesta cuidadosamente para
+asegurarse que esté todo incluido antes de confirmar esta acción.
+
+Perdone las molestias.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+Para confirmar que le gustaría que
+
+!A
+
+sea dado de baja de la lista de correo <#l#>, por favor, mande un
+mensaje en blanco a esta dirección:
+
+!R
+
+Normalmente esto ocurre al pulsar el botón "Responder". Si no
+funciona, simplemente copie la dirección y péguela en el campo
+"Para:" de un nuevo mensaje. 
+</#xE/>
+
+o haga clic aquí:
+
+       mailto:<#R#>
+</#E/>
+
+No he comprobado si su dirección está actualmente en la lista de
+correo. Para ver que dirección utilizó para suscribirse, mire los
+mensajes que está recibiendo de la lista de correo. Cada mensaje
+tiene su dirección oculta dentro de la ruta de retorno; por
+ejemplo, maria@xdd.ff.com recibe mensajes con la ruta de retorno:
+<<#l#>-return-<número>-maria=xdd.ff.com@<#H#>>.
+
+</#qE/>
+
+Algunos programas de correo no pueden manejar direcciones largas.
+Si no puede responder a esta petición, envíe un mensaje a
+<<#L#>-request@<#H#>> y escriba la dirección completa en la línea
+de "Asunto:".
+
+</text/unsub-nop#E/>
+Lo siento, no he podido cursar su petición porque la dirección
+
+!A
+
+no estaba en la lista de correo <#l#> cuando recibí su petición y
+no es suscriptor de esta lista.
+
+Si se da de baja, pero sigue recibiendo correo, es que está
+suscrito con una dirección distinta a la que usa actualmente. Por
+favor, busque en las cabeceras el texto:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+La dirección para dar de baja a este usuario sería:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+
+Simplemente escriba a esa dirección, tras modificarla con la
+verdadera dirección de suscripción.
+
+Si el mensaje tiene una cabecera ``List-Unsubscribe:'' puede
+usted mandar un mensaje a la dirección de esa cabecera. La
+cabecera ya contiene la petición de suscripción.
+
+En algunos programas de correo, necesitará hacer visibles los
+encabezamientos para ver el campo de retorno:
+
+Con Eudora 4.0, haga clic en el botón "Blah blah ...". Con
+PMMail, haga clic en "Window->Show entire message/header".
+
+Si esto tampoco da resultado, siento decirle que no le puedo
+ayudar. Por favor, reenvíe el mensaje junto con una nota sobre lo
+que está intentando hacer y una lista de direcciones bajo las
+cuales puede estar suscrito, a mi propietario:
+
+    <#l#>-owner@<#H#>
+
+que se ocupará de todo. Mi propietario es un poco más lento que
+yo; por favor, tenga paciencia.
+
+</text/unsub-ok#E/>
+Acuse de recibo: He dado de baja la dirección
+
+!A
+
+de la lista de correo <#l#>. Esta dirección ya no está suscrita.
+
+</text/edit-do#nE/>
+
+Por favor edite el siguiente fichero de texto y envíelo a esta
+dirección:
+
+!R
+
+Su programa de correo debería tener la opción "Responder" que
+utiliza esta dirección automáticamente.
+
+Puedo quitar las comillas que su programa añade al texto, siempre
+y cuando usted no modifique las líneas marcadoras (las que
+empiezan con '%%%'). Estas líneas no deben ser modificadas (solo
+son tolerados caracteres añadidos por su programa de correo al
+principio de la línea).
+
+</text/edit-list#nE/>
+
+El comando <#L#>-edit.file puede ser utilizado por un
+administrador remoto para modificar los ficheros de texto que
+componen la mayoría de las respuestas de la lista de correo
+<#L#>@<#H#>.
+
+Lo que sigue es un listado de los ficheros de respuesta y una
+corta indicación de cuando se utilizan sus contenidos. Para
+modificar un fichero, simplemente envíe un correo a
+<#L#>-edit.fichero, sustituyendo 'fichero' por el nombre del
+fichero. Las instrucciones para las modificaciones se envían con
+el fichero.
+
+File                Use
+
+bottom        final de todas las respuestas. Información general
+              sobre comandos.        
+digest        sección administrativa de resúmenes. 
+faq           preguntas frecuentes propias de esta lista.
+get_bad       en lugar de mensajes no encontrados en el archivo.
+help          ayuda general (entre 'top' y 'bottom').
+info          información sobre la lista. La primera línea debe
+              tener significado por sí misma. 
+mod_help      ayuda específica para moderadores.
+mod_reject    al remitente del mensaje rechazado.
+mod_request   a los moderadores de mensajes junto a los mensajes.
+mod_sub       al suscriptor después de que el moderador confirme
+              la suscripción.
+mod_sub_confirm  al moderador para pedir confirmación de 
+                 suscripción.
+mod_timeout   al remitente de correo caducado.  
+mod_unsub_confirm  al administrador remoto para pedir confirmación
+                   de baja.
+sub_bad       al suscriptor si la confirmación no fue correcta.
+sub_confirm   al suscriptor para pedir confirmación de 
+              suscripción.
+sub_nop       al suscriptor después de re-suscribirse.
+sub_ok        al suscriptor después de la suscripción. 
+top           el principio de todas las respuestas.
+</#tnE/>
+trailer       añadido a todos los mensajes enviados de la lista.
+</#nE/>
+unsub_bad     al suscriptor si la confirmación de baja fue 
+              incorrecta.
+unsub_confirm al suscriptor para pedir confirmación de 
+              cancelación.
+unsub_nop     al no suscriptor después de darse de baja.
+unsub_ok      al ex suscriptor después de darse de baja.
+
+</text/edit-done#nE/>
+El fichero de texto fue actualizado correctamente.
+</text/info#E/>
+No se ha proporcionado información para esta lista.
+</text/faq#E/>
+FAQ - Preguntas más comunes para la lista <#l#>@<#H#>.
+
+Ninguno disponible todavía. 
+
+
diff --git a/ezmlmrc.fr b/ezmlmrc.fr
new file mode 100644 (file)
index 0000000..dd04a17
--- /dev/null
@@ -0,0 +1,1226 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.fr,v 1.22 1999/12/22 04:02:15 lindberg Exp $
+#Name:$
+#
+# ezmlmrc.fr - Traduction: Frank DENIS "Jedi/Sector One" <j@4u.net>
+# ##########
+# Controle les actions de ezmlm-make apres le patch ezmlm-idx-0.31 ou suivant.
+#
+# Le repertoire de base 'DIR' est toujours cree par ezmlm-make, comme DIR/key.
+# Tout le reste est genere a partir d'ici.
+#
+# ezmlm-make cherche ce fichier,d'abord en tant que .ezmlmrc dans le repertoire
+# ou les fichiers .qmail seront places (si vous avez utilise l'option -c en
+# ligne de commande), puis dans /etc/ezmlmrc, et enfin ezmlmrc dans le
+# repertoire contenant l'executable de ezmlm-make.
+# Ainsi, vous pouvez personnaliser ezmlm-make au niveau global en placant une
+# copie personnalisee d'ezmlmrc dans /etc et au niveau utilisateur en le
+# copiant dans .ezmlmrc dans le repertoire utilisateur ET en utilisant le
+# commutateur -c d'ezmlm-make.
+#
+# Les reperes sont:
+#      </nomdefichier/>  : ce qui suit sera place dans DIR/nomdefichier.
+#      </-nomdefichier/> : efface DIR/nomdefichier.
+#      </+repertoire/>   : cree le repertoire DIR/repertoire.
+#      </:lien/repertoire>: lien symbolique DIR/.qmail-list-lien -> DIR/repertoire.
+#
+# Le nom a l'interieur d'un repere peut etre suffixe de '#' et de n'importe
+# quel commutateur correspondant a ceux de la ligne de commande. L'objet sera
+# cree/etendu uniquement si tous les commutateurs listes sont positionnes.
+# Les fichiers peuvent etre agrandis tant qu'ils sont les derniers crees, mais
+# pas si un autre fichier a ete ebauche depuis. Les commutateurs inconnus
+# sont ignores sans preavis.
+# 
+# Ainsi, </nomfichier#aP> cree le fichier si et seulement si la liste est
+# archivee (-a) et non publique (-P). Si le repere suitant est
+# </nomfichier#m/> , le fichier est agrandi avec le texte qui suit jusqu'au
+# prochain repere si les messages de la liste sont moderes (-m).
+# Si le repere suivant est </autrechose/>, 'nomfichier' est ferme. Tout autre
+# repere impliquant la reouverture de 'nomfichier' tronquera le fichier au
+# lieu de l'agrandir.
+#
+# Un ensemble de commutateurs pour l'utilisateur (xX, yY, zZ) sont disponibles
+# pour la personalisation.
+# 
+# Les substitutions sont:
+# <#B#> chemin exe d'ezmlm    <#C#> code bulletin       <#D#> repertoire
+# <#H#> machine               <#L#> local               <#F#> commutateurs
+# <#T#> point-qmail           <#0#> arg pour -0. <#3#>..<#9#> arg pour -3..9
+# <#1#> ext1                  <#2#> ext2 [si le point-qmail est /chemin/.qmail-ext1-ext2-nom]
+# Le dernier est utile quand un seul utilisateur controle plusieurs domaines
+# virtuels.
+# Les reperes inconnus sont copies tels quels. ezmlm-manage remplace <#A#> par
+# l'adresse de l'abonne et <#R#> par celle de confirmation. ezmlm-store
+# remplace <#A#> par l'adresse d'acceptation et <#R#> par celle de rejet.
+#-----------------------------ici
+#
+# -0 est utilise pour l'adresse de la liste principale dans le cas de sous-listes.
+# -3 est pour le nouvel en-tete "from" si nous voulons que celui-ci soit remplace
+# -4 pour specifier les commutateurs de ezmlm-tstdig utilises dans dir/editor.
+#    Par defaut, il s'agit de -k64 -m30 -t24
+# -5 pour l'adresse du proprietaire de la liste: liste-owner. Les messages
+# envoyes a liste-owner seront renvoyes vers cette adresse.
+# -6 pour les informations de connexion SQL
+# -7 pour le contenu de DIR/modpost
+# -8 pour le contenu de DIR/modsub
+# -9 pour le contenu de DIR/remote
+#
+# Pour faciliter la tache, le commutateur '-x' produit les actions
+# suivantes non standards :
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Des tentatives de creation de lien ou de repertoires deja existants
+# provoqueront une erreur FATALE. Des tentatives d'ouverture de fichiers deja
+# fermes ou abandonnes causeront leur ecrasement.
+#
+# Un des problemes majeurs avec les listes ezmlm est DIR/inlocal. Pour des
+# utilisateurs normaux, il contient le nom de la liste (genre utilisateur-liste)
+# ce qui est correct. En revanche, pour l'utilisateur 'ezmlm' controlant le
+# domaine virtuel 'machine.domaine.com' le nom de la liste est
+# 'liste@machine.domaine.com' , mais inlocal doit etre 'ezmlm-liste', et non
+# 'liste'. De facon similaire, si ezmlm-domaine1 controle 'machine.domaine.com'
+# liste@machine.domaine.com doit garantir un inlocal contenant
+# 'ezmlm-domaine1-liste'. Pour avoir toujours une liste correcte, placez ce
+# fichier dans le repertoire utilisateur (~ezmlm/.ezmlmrc) et changez le
+# texte du fichier inlocal en 'ezmlm-<#L#>' ou 'ezmlm-<#1#>-<#L#>',
+# respectivement.
+#
+# Configuration pour prevoir l'edition future sans ligne de commande ezmlm-make
+# autre que le repertoire. Utile pour les outils d'edition IHM/WWW.
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# Repertoires opur les bulletins
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# Pour la base de donnees d'adresses supplementaires
+</+allow/>
+</+allow/subscribers/>
+# Pour la liste noire
+</+deny#k/>
+</+deny/subscribers#k/>
+# Base de donnees des moderateurs et repertoires des files d'attente.
+# Requis opur -m, -r -s, c'set pourquoi nous les mettons en place par defaut.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# liens: point -> DIR/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# Uniquement pour les listes moderees
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# On se debarasse des commutateurs de configuration pour le mode d'edition
+# pour pouvoir debuter sur de bonnes bases.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Inutile, si ce n'est pour la moderation des messages.
+</-moderator#eM/>
+# Nous ne nettoyons pas les fichiers de texte pour aider
+# les utilisateurs effectuant leur configuration manuellement,
+# par exemple en modifiant le repertoire DIR/remote.
+</modsub#s/>
+<#8#>
+# Administration distante
+</remote#r/>
+<#9#>
+# Moderation des messages
+</modpost#m/>
+<#7#>
+# Adresse du proprietaire de la liste
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Gestion des inscriptions. Ajoutez des commutateurs si vous desirez des
+# bulletins dans un format personnalise. Les commandes de services sont
+# donnees en tant que sujet de la requete a l'adresse # si le commutateur
+# -q est selectionne. De meme, -l et -d activent l'edition ou le fichier
+# texte des abonnes, pour l'administration distante.
+# -u donne a l'abonne uniquement acces a l'archive.
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Il est possible d'ajouter -l et -d meme pour les listes non
+# moderees, etant donne que ezmlm-manage ne l'acceptera pas a moins
+# qu'il n'y ait des administrateurs distants.
+# Tout d'abord pour les listes avec une confirmation normale :
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... et maintenant sans confirmation d'inscription ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... maintenant aucune confirmation pour se desinscrire ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... et finalement aucune confirmation nulle part ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# Le rejet ne devrait pas etre configure pour les sous-listes.
+</#^0/>
+# Par defaut, on rejete maintenant tout, pour satisfaire les exigences des
+# adresses de listes dans les champs To et Cc.
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => rejette les contributions des adresses en liste noire. Valable aussi
+# pour les listes moderees - permet de filtrer les perturbateurs.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# commutateur -u=> Restriction aux sous-lists et aux bulletins.
+# Sans l'option 'm', le faire avec ezmlm-issubn, si 'm' est active, en
+# revanche, le faire avec ezmlm-gate.
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# Pour la moderation de messages, l'editeur dispose de store et de clean.
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# Pour les listes non moderees, il y a send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive est ici pour les listes normales. A mettre dans moderator pour
+# les listes qui utilisent mess-mod.
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# Toutes les listes peuvent provoquer des avertissements, a moins que
+# l'option -w ne soit activee.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Pour les retours a l'expediteur des bulletins.
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# Retours a l'expediteur pour les listes et bulletins.
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# Le fichier moderator est ajoute uniquement pour les listes dont les messages sont
+# moderes. Toutefois, '-e' ne le retire pas vu qu'il est impossible d'en
+# retirer les liens symboliques (ils sont en dehors du repertoire de la liste).
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# Pour les sous-listes, ce qui suit doit etre preserve
+list-post
+# Retire l'en-tete "from" si -3 est actif.
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+Pour toute requete administrative, contactez <#L#>-help@<#H#>; Liste geree par ezmlm
+# Headeradd doit toujours exister mais les sous-listses sont un cas a part.
+</headeradd#E^0/>
+# Impeccable pour les listes de diffusion (et le programme "vacation").
+Precedence: bulk
+# Pour eviter d'etre indexe par le site findmail.com
+X-No-Archive: yes
+# rfc2369, d'abord ce qui ne concerne que la liste principale, ensuite
+# les en-tetes pour les sous-listes.
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# Ajoute une nouvelle ligne "From: xxx" si l'on a utilise -3 'xxx' .
+</#3E/>
+From: <#3#>
+# Taille maximale et taille minimale de chaque message.
+</msgsize#x/>
+30000:2
+# Retire les parties en mime si l'option -x est utilisee.
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# Ceux qui suivent peuvent aussi etre exclus. Mais pour beaucoup de listes,
+# il est preferable de les accepter. Pour ce faire, retirez leur commentaire.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Traite les informations de connexion SQL
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- Fin de tout ce qui concerne le SQL.
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+Desinscription: envoyez un message a: <#L#>-unsubscribe@<#H#>
+Pour obtenir de l'aide, ecrivez a: <#L#>-help@<#H#>
+</text/bottom#E/>
+
+--- Voici les adresses relatives aux commandes de cette liste:
+
+Je peux prendre en charge les requetes administratives automatiquement.
+Envoyez simplement un petit message a l'une de ces adresses:
+
+Pour recevoir de l'aide et une description des commandes possibles, envoyez
+un message a :
+   <<#L#>-help@<#H#>>
+
+Pour vous inscrire a la liste de diffusion <#L#>, envoyez un message a :
+   <<#L#>-subscribe@<#H#>>
+
+Pour retirer votre adresse de la liste, envoyez simplement un message a
+l'adresse qui se trouve dans l'en-tete ``List-Unsubscribe'' situe dans
+n'importe quel message de la liste. Si votre adresse actuelle est strictement
+identique a celle que vous avez utilisee pour vous inscrire, il vous est aussi
+possible d'envoyer un message quelconque a :
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+ou pour une liste qui vous serait envoyee sous forme de bulletin, a :
+   <<#L#>-unsubscribe@<#H#>>
+
+</#E/>
+Pour l'ajout ou le retrait d'adresses, vous receverez systematiquement un
+message de confirmation. Il vous suffira d'y repondre pour achever la
+transaction.
+
+Si vous desirez contacter le proprietaire de cette liste, veuillez envoyer un
+message a :
+
+    <<#L#>-owner@<#H#>>
+
+S'il vous plait, envoyez un message qui vous a ete adresse avec TOUS SES
+EN-TETES (faite suivre le message : "forward") pour qu'il puisse plus
+aisement vous aider.
+
+--- Ci-dessous se trouve une copie de la requete que j'ai recue.
+
+</text/bounce-bottom#E/>
+
+--- Ci-dessous se trouve une copie du message problematique qui m'est revenu :
+
+</text/bounce-num#E/>
+
+
+J'ai conserve une liste des messages de la liste de diffusion <#L#> qui
+n'ont temporairement pas pu etre delivres a votre adresse.
+
+</#aE/>
+Une copie de ces messages doit se trouver dans l'archive.
+
+</#aE/>
+Pour obtenir l'ensemble des messages depuis le numero 123 jusqu'au numero 145
+(avec un maximum de 100 par requete), envoyez un message vide avec un sujet
+quelconque a :
+   <<#L#>-get.123_145@<#H#>>
+
+Pour recevoir un resume des 100 derniers messages, avec uniquement le nom des
+auteurs et les sujets traites, envoyez un message a :
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Voici les numeros des messages en question :
+
+</text/dig-bounce-num#E/>
+
+J'ai conserve une liste des bulletins de la liste de diffusion <#L#>
+qui n'ont temporairement pas pu etre delivres a votre adresse. Pour chaque
+bulletin que vous n'avez pas pu consulter, j'ai note les numeros du premier
+message qui s'y trouvait.
+
+</#aE/>
+Aucune archive des bulletins eux-memes n'est conservee, mais vous pouvez
+toujours recuperer les messages a partir de la liste principale.
+
+Ainsi, pour obtenir les messages situes entre le numero 123 et le numero 145
+(avec un maximum de 100 par requete), il suffit d'envoyer un message 
+a l'adresse :
+   <<#L#>-get.123_145@<#H#>>
+
+Et pour recevoir un resume des 100 derniers messages (auteur/sujet), envoyez
+un message a :
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Voici le numero du premier message de chaque bulletin :
+
+</text/bounce-probe#E/>
+
+Des messages vous etant adresses en tant qu'abonne a la liste de diffusion
+<#l#> n'ont pas pu atteindre votre compte E-Mail. J'ai tente de vous en
+informer, mais ce message d'information n'a lui aussi pas pu atteindre sa
+cible.
+Voici une copie du message de retour a l'expediteur.
+
+Ceci est en realite un test pour determiner s'il est possible de vous
+contacter a l'adresse de votre inscription. Si ce dernier essai ne s'avere
+pas concluant, je serais contraint de retirer votre adresse de la liste
+<#l#>@<#H#> sans autre avertissement.
+
+Il vous sera toujours possible de vous re-inscrire a l'adresse :
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+Un certain nombre de messages provenant de la liste de diffusion
+<#l> n'ont pas pu vous etre remis correctement. En attachement, vous trouverez
+une copie du premier message de retour a l'envoyeur que j'ai recu.
+
+Si le message que vous lisez actuellement ne parvient pas non plus a
+destination, un dernier message vous sera envoye. Si celui-ci echoue aussi,
+votre adresse sera malheureusement retiree de la liste <#l#>.
+
+</text/digest#dE/>
+Pour vous abonner a la liste sous forme de bulletins, ecrivez a :
+       <#L#>-digest-subscribe@<#H#>
+
+Pour vous desabonner des bulletins, ecrivez a :
+       <#L#>-digest-unsubscribe@<#H#>
+
+Les participations a la liste se font a l'adresse suivante :
+       <#L#>@<#H#>
+
+</text/get-bad#E/>
+Desole, mais ce message est introuvable dans l'archive.
+
+</text/help#E/>
+Ceci est un message d'aide generique. Le message que j'ai recu n'etait pas
+adresse a l'une de mes adresses correspondant aux commandes valides.
+
+Voici donc une liste des commandes supportees, representees par des adresses
+auxquelles ecrire.
+
+Envoyez un message a l'adresse suivant pour obtenir des informations et des
+reponses aux questions courantes sur cette liste de diffusion :
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Des adresses similaires existent pour la liste sous forme de bulletins :
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i necessite l'ajout de la ligne ezmlm-get. Faute de quoi il
+# serait impossible de faire de la saisie multiple !
+</#aE/>
+Pour obtenir tous les messages situes entre le numero 123 et le numero 145
+(avec un maximum de 100 par requete), envoyez un message a :
+   <<#L#>-get.123_145@<#H#>>
+
+Pour obtenir un resume des messages 123 a 456 avec uniquement les sujets et
+le nom des auteurs, envoyez un message a :
+   <<#L#>-index.123_456@<#H#>>
+
+Pour recevoir tous les messages comportant le meme sujet que le message 12345,
+envoyez un message a :
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+En realite, les messages n'ont pas besoin d'etre vides, leur contenu sera
+totalement ignore. Seul l'ADRESSE a laquelle vous ecrivez est determinante.
+
+Il est possible de demander un abonnement a une autre adresse que la votre.
+Par exemple pour abonner "john@machine.domaine", il suffit d'ajouter un tiret
+et l'adresse (avec le signe "=" a la place de "@") apres le nom de la
+commande :
+<<#L#>-subscribe-john=machine.domaine@<#H#>>
+
+Pour desabonner cette derniere adresse :
+<<#L#>-unsubscribe-john=machine.domaine@<#H#>>
+
+</text/mod-help#E/>
+Merci beaucoup d'accepter le role de moderateur pour la liste de diffusion
+<#L#>@<#H#> .
+
+Mes commandes sont legerement differentes des autres listes.
+Elles peuvent d'abord sembler inhabituelles, mais une fois que
+vous les aurez utilisees, vous apprecierez la simplicite du
+systeme, et la vitesse a laquelle je repond a vos souhaits.
+
+Voici quelques informations au sujet du fonctionnement de la
+moderation:
+
+Inscription a distance
+----------------------
+En tant que moderateur, vous pouvez inscrire et desinscrire n'importe quelle
+adresse a la liste de diffusion.
+Ainsi, pour abonner "john@machine.domaine", mettez simplement un tiret apres
+le nom de la commande, puis l'adresse du futur abonne en remplacant le signe
+"@" par "=".
+Par exemple, pour inscrire l'utilisateur ci-dessus, envoyez un message a :
+   <<#L#>-subscribe-john=machine.domaine@<#H#>>
+
+De facon similaire, il est possible de retirer son adresse de la liste en
+ecrivant a :
+   <<#L#>-unsubscribe-john=machine.domaine@<#H#>>
+
+</#dE/>
+Idem pour les listes presentees sous la forme de bulletins :
+   <<#L#>-digest-subscribe-john=machine.domaine@<#H#>>
+   <<#L#>-digest-unsubscribe-john=machine.domaine@<#H#>>
+
+</#E/>
+C'est tout ! Aucun sujet special ni corps de message n'est requis.
+
+</#rE/>
+Je vous enverrai une demande de confirmation, pour etre
+sur que vous etes bien a l'origine de la requete. Repondez
+simplement au message et la transaction sera achevee.
+</#RE/>
+J'enverrai une demande de confirmation a l'adresse de
+l'utilisateur (ici john@machine.domaine).
+Tout ce qu'il aura a faire sera de repondre au message.
+</#E/>
+
+Ces etapes de confirmation sont necessaires pour rendre beaucoup plus ardu
+le fait qu'un tiers puisse ajouter ou retirer une adresse de la liste.
+
+Je previendrai bien entendu l'utilisateur quand son etat d'abonne changera.
+
+Inscription
+-----------
+
+N'importe quel utilisateur peut s'abonner ou se desabonner en envoyant un
+message a :
+
+<#L#>-subscribe@<#H#> pour l'inscription
+<#L#>-unsubscribe@<#H#> pour la desinscription
+
+</#dE/>
+Et pour les listes presentees sous forme de bulletins :
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+</#E/>
+L'utilisateur recevra une demande de confirmation pour etre
+sur qu'il/elle controle l'adresse d'inscription. Une fois
+ceci verifie, l'utilisateur sera desinscrit.
+
+</#sE/>
+Etant donne que cette liste est moderee pour les abonnements,
+j'enverrai une seconde demande de confirmation aux moderateurs.
+Etant donne que l'utilisateur a deja confirme son desir
+d'appartenir a la liste, vous, en tant que moderateur, pouvez
+etre surs que l'adresse de l'abonne est reelle. Si vous desirez
+approuver la requete d'un utilisateur, repondez simplement a mon
+message de confirmation. Dans le cas contraire, vous pouvez
+simplement effacer mon message ou eventuellement contacter l'abonne
+potentiel pour davantage de renseignements.
+
+</#SE/>
+Les inscriptions fonctionnent de facon analogue.
+</#E/>
+
+Il est aussi possible d'utiliser :
+
+   <<#L#>-subscribe-mary=machine.domaine@<#H#>>
+   <<#L#>-unsubscribe-mary=machine.domaine@<#H#>>
+
+pour que les messages soient envoyes a "mary@machine.domaine". Elle
+recevra la demande de confirmation uniquement si elle recoit son
+courrier a cette adresse et si elle est alors en mesure d'y repondre.
+
+Votre adresse et votre identite ne seront pas revelees a l'abonne,
+a moins que vous ne lui ecriviez directement.
+
+</#rlE/>
+Pour obtenir la liste des abonnees a <#L#>@<#H#>, envoyez un
+message a : 
+   <<#L#>-list@<#H#>>
+
+Pour obtenir un historique des transactions de la liste
+<#L#>@<#H#>, envoyez un message a :
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+Pour les abonnes aux bulletins :
+   <<#L#>-digest-list@<#H#>>
+et :
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+Vous pouvez a distance editer les fichiers de texte contenant les
+messages du robot. Pour obtenir la liste des fichiers et les
+instructions pour les editer, ecrivez a :
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+Envoi de messages moderes
+-------------------------
+Lorsque l'envoi de messages est modere, je conserverai chaque
+message en attente et vous en enverrai une copie avec les
+instructions. Ces messages auront pour sujet "MODERATE for ..." .
+
+Pour accepter la contribution, repondez simplement a l'adresse
+specifiee dans le champs "Reply-To:" (ceci doit etre de toutes
+facons pris en charge automatiquement par votre logiciel de
+messagerie) si vous souhaitez accepter le message. Inutile de
+renvoyer le message en question. En fait, le corps du message
+sera ignore du moment que l'adresse est correcte.
+
+Si vous desirez le rejeter, envoyez un message a l'adresse
+precisee de le champ "From" (peut etre habituellement fait a
+l'aide d'un "reply-to-all" suivi d'un effacement de l'adresse
+d'acceptation). Vous pouvez ajouter un commentaire optionnel a
+l'envoyeur entre les deux lignes debutant par '%%%' sans les
+guillemets.
+La encore, votre anonymat sera conserve.
+
+Je traiterai chaque message d'apres la premiere reponse recue.
+Si vous m'envoyez un message pour accepter un message qui a deja
+ete rejete ou l'inverse, je vous tiendrai au courant.
+
+Si je ne recois aucune reponse d'un moderateur apres un certain
+delai (normallement 5 jours), je renverrai le message a
+l'expediteur avec une explication de ce qu'il est arrive.
+L'adminsitrateur peut aussi parametrer la liste de facon a ce que
+ces messages "ignores" soient purement et simplement effaces sans
+avertissement prealable, plutot que retournes a l'envoyeur.
+</#E/>
+
+Absences
+--------
+Si vous etes temporairement a une adresse differente, faites simplement
+suivre tous les messages qui ont un entete "Mailing-List:" correct (ou
+tous les messages qui ont un sujet debutant par
+'MODERATE for <#L#>@<#H#>' ou 'CONFIRM subscribe to <#L#>@<#H#>') a la
+nouvelle addresse. Vous pouvez alors moderer a partir de la nouvelle
+adresse. Alternativement, vous pouvez faire suivre les messages a un
+ami qui moderera pour vous. Pensez a vous mettre d'accord avec le
+proprietaire de la liste avant tout.
+
+Si vous souhaitez que toutes les requetes soient approuvees lorsque
+vous etes absents, configurez votre client de messagerie pour
+repondre automatiquement a tous les messages qui correspondent aux
+criteres ci-dessus.
+
+</#rE/>
+Si vous essayez de faire de l'administration a distance a partir
+d'une adresse qui n'est pas la votre, l'abonne, et non vous, devra
+confirmer. Apres cela, une demande de validation sera envoyee a
+tous les moderateurs.
+Je suis oblige de faire cela car je n'ai aucun moyen de verifier
+que c'est bien vous qui avez emis la requete originale.
+
+A noter que votre requete (et votre adresse) sont transmises a
+l'abonne dans ce cas.
+</#E/>
+
+Bonne chance !
+
+PS: Contactez le proprietaire (<#L#>-owner@<#H#>) si vous avez
+une question ou des difficultes.
+
+</text/mod-reject#E/>
+Je suis desole, votre message n'a pas ete accepte par le
+moderateur. Si le moderateur y a joint des commentaires, ils
+se trouvent ci-dessous.
+</text/mod-request#E/>
+A vous de decider si, en tant que moderateur, vous approuvez
+le message ci-joint pour la liste <#L#>@<#H#>.
+
+Pour accepter le message et l'envoyer immediatement a tous les
+abonnes de la liste, envoyez un message a: 
+
+!A
+
+En regle generale, il suffit de repondre a ce message (Reply) .
+Verifiez simplement que l'adresse debute bien par
+"<#L#>-accept".
+Si cela ne fonctionne pas, copiez simplement l'adresse et
+collez la dans le champs representant le destinataire.
+</#xE/>
+
+Si votre brouteur le permet, vous pouvez aussi cliquer ici :
+       mailto:<#A#>
+</#E/>
+
+Pour rejeter la contribution et le retourner a l'expediteur,
+veuillez envoyer un message a :
+
+!R
+
+En pratique, il est souvent plus simple d'effectuer une reponse
+a tous et de retirer tous les adresses, en dehors de celle qui
+debute par "<#L#>-reject".
+</#xE/>
+
+Si votre brouteur prend en compte les liens hypertexte, vous
+pouvez aussi cliquer ici :
+       mailto:<#R#>
+</#E/>
+
+Vous n'avez pas besoin de recopier le message dans vos reponses pour
+l'accepter ou le rejeter. Si vous souhaitez y ajouter un commentaire
+en cas de rejet, ajoutez-le entre les deux lignes debutant pas '%%%'
+(sans les guillemets).
+
+%%% Debut du commentaire
+%%% Fin du commentaire
+
+Merci de votre aide !
+
+--- Ci-joint, le message envoye:
+
+</text/mod-sub#E/>
+--- Je vous ai inscrit ou desinscrit a la demande d'un moderateur
+de la liste de diffusion <#l#>@<#H#>.
+
+Si ce n'est pas ce que vous souhaitez, envoyez s'il vous plait
+un message au proprietaire <#l>-owner@<#H#> des que possible.
+
+Si vous souhaitez davantage d'informations sur la facon d'acceder
+a l'archive de la liste <#L#>, envoyez simplement un message vide
+a: <#L#>-help@<#H#>.
+
+</text/mod-timeout#E/>
+
+Je suis desole, les moderateurs de la liste n'ont pas reagit a
+votre participation. Donc, je vous la renvoie. Si vous pensez
+qu'il s'agit d'une erreur, faites part de ce message directement
+a un moderateur de la liste <#L#>.
+
+--- Ci-joint, le message que vous avez envoye:
+
+</text/mod-sub-confirm#E/>
+Je vous demande humblement la permission d'ajouter
+
+!A
+
+aux abonnes de la liste de diffusion <#l>. Cette requete
+peut venir de vous-meme ou avoir deja ete supervisee par
+l'abonne potentiel.
+
+Pour confirmer, veuillez envoyer une reponse a cette
+adresse :
+
+!R
+
+Votre logiciel de messagerie devrait avoir une fonction "Reply"
+pour la traiter automatiquement.
+Si cela ne fonctionne pas, effectuez un copier/coller pour y
+ecrire.
+</#xE/>
+
+ou, si votre logiciel de messagerie le permet, cliquer ici :
+       mailto:<#R#>
+</#E/>
+
+Si vous n'approuvez pas cet abonnement, ne tenez pas compte de
+ce message.
+
+Merci de votre aide !
+
+</text/mod-unsub-confirm#E/>
+Je vous demande humblement la permission de retirer
+
+!A
+
+de la liste <#l#>. Si vous acceptez, envoyez un message
+quelconque a cette adresse:
+
+!R
+
+Votre logiciel de messagerie devrait avoir une fonction "Reply"
+pour utiliser automatiquement cette adresse. Sinon, il vous
+reste le copier/coller.
+
+</#xE/>
+
+Le lien suivant pourrait aussi fonctionner :
+       mailto:<#R#>
+</#E/>
+
+En cas de desaccord, ne tenez pas compte de ce message.
+
+Merci de votre aide !
+
+</text/sub-bad#E/>
+
+Oups, ce numero de confirmation semble invalide.
+
+La raison la plus courante des nombres invalides est leur expiration.
+Je dois recevoir la confirmation de chaque requete dans les dix jours.
+De plus, soyez certains que l'integrite du nombre de confirmation
+figurait dans la reponse que vous m'avez envoyee. Certains logiciels de
+messagerie ont la facheuse habitude de tronquer les adresses un peu
+longues.
+
+J'ai mis en place un nouveau nombre de confirmation. Pour confirmer que
+vous souhaitez voir
+
+!A
+
+parmi les abonnes de la liste <#l#>, envoyez s'il vous plait une reponse
+quelconque a cette adresse:
+
+!R
+</#xE/>
+
+ou suivez ce lien :
+       mailto:<#R#>
+</#E/>
+
+Une fois de plus, verifiez soigneusement l'adresse de la reponse pour
+etre sur qu'elle est complete avant de renouveller votre inscription.
+
+Toutes mes excuses pour le derangement.
+
+       Le proprietaire de <#L#> <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+
+Pour confirmer que vous souhaitez voir
+
+!A
+
+parmi les abonnes de la liste <#l#>, veuillez renvoyer un message
+quelconque a l'adresse suivante:
+
+!R
+
+En fait, inutile de la recopier: la fonction "Reply" (repondre a
+l'expediteur) de votre logiciel de messagerie doit s'en charger
+automatiquement. Sinon, il reste le copier/coller.
+</#xE/>
+
+ou suivez ce lien :
+       mailto:<#R#>
+</#E/>
+
+Cette confirmation a deux buts. Tout d'abord, elle verifie que je suis
+capable d'obtenir des messages de vous. Ensuite, elle vous protege au
+cas ou quelqu'un ferait une inscription frauduleuse sous votre nom.
+
+</#qE/>
+Certains logiciels de messageries sont boggues et ne peuvent prendre
+en compte de longues adresses. Si vous ne pouvez pas repondre a cette
+requete, envoyez a la place un message a <<#L#>-request@<#H#>> et
+mettez l'adresse complete presentee ci-dessus dans le champs "Sujet".
+
+</#sE/>
+Cette liste est moderee. Apres avoir recu cette confirmation, la
+requete sera envoyee au(x) moderateur(s) de la liste. Je vous
+previendrai lorsque votre inscription sera effective.
+
+</text/sub-nop#E/>
+Il a ete impossible de satisfaire votre requete : l'adresse
+
+!A
+
+etait deja sur la liste de diffusion <#l#> lorsque
+j'ai recu votre requete, et est toujours abonnee.
+
+</text/sub-ok#E/>
+
+Accuse de reception: j'ai ajoute l'adresse
+
+!A
+
+a la liste de diffusion <#l#>.
+
+Bienvenue dans la liste <#l#>@<#H#> !
+
+Pensez a sauvegarder ce message pour que vous puissiez connaitre
+l'adresse sous laquelle vous vous etes abonnes, au cas ou vous
+souhaiteriez ulterieurement vous desinscrire ou changer votre
+adresse d'abonnement.
+
+Pour vous desinscrire, envoyez un message a :
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Bonjour ! Je suis le programme ezmlm. Je m'occupe de la liste
+de diffusion <#l#>@<#H#>.
+
+</#x/>
+Je travaille pour mon proprietaire, qui peut etre joint a:
+<#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+Oups, ce numero de confirmation semble invalide.
+
+La raison la plus courante des nombres invalides est leur expiration.
+Je dois recevoir la confirmation de chaque requete dans les dix jours.
+De plus, soyez certains que l'integrite du nombre de confirmation
+figurait dans la reponse que vous m'avez envoyee. Certains logiciels de
+messagerie ont la facheuse habitude de tronquer les adresses un peu
+longues.
+
+J'ai mis en place un nouveau nombre de confirmation. Pour confirmer que
+vous souhaitez voir
+
+!A
+
+desabonne de la liste <#l#> , envoyez une reponse quelconque a :
+
+!R
+</#xE/>
+
+ou suivez ce lien :
+       mailto:<#R#>
+</#E/>
+
+A nouveau, verifiez que l'adresse a laquelle vous ecrivez est complete.
+
+Toutes mes excuses pour le derangement.
+
+       Le proprietaire de <#l#> <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+Pour confirmer que vous souhaitez voir
+
+!A
+
+supprime de la liste de diffusion <#l#> , veuillez envoyer un message
+quelconque a l'adresse suivante:
+
+!R
+
+En fait, inutile de la recopier: la fonction "Reply" (repondre a
+l'expediteur) de votre logiciel de messagerie doit s'en charger
+automatiquement. Un copier/coller vers le champs "To:" est aussi
+une possible.
+</#xE/>
+
+Vous pouvez aussi tout aussi bien suivre ce lien :
+       mailto:<#R#>
+</#E/>
+
+Je n'ai pas verifie que votre adresse fait actuellement partie de la
+liste. Pour verifier a quelle adresse vous vous etes abonnes, regardez
+les messages que vous recevez de cette liste. Chaque message a votre
+adresse cachee dans son chemin de retour; par exemple
+dieu@ciel.paradis.com recoit ses messages avec dans le champ
+"return-path": <<#l#>-return-<nombre>-dieu=ciel.paradis.com@<#H#>.
+
+</#qE/>
+Certains logiciels de messagerie mal concus ne peuvent traiter les
+adresses au dela d'une certaine taille. S'il vous est impossible de
+repondre a ce message, envoyez a la place un message a l'adresse
+<<#L#>-request@<#H#>> et mettez l'adresse complete dans le champs
+"Sujet".
+
+</text/unsub-nop#E/>
+Desole, mais il est impossible de satisfaire votre requete, etant
+donne que l'adresse
+
+!A
+
+ne figurait pas sur la liste de diffusion <#l#> lorsque
+j'ai recu votre requete, et n'est toujours pas abonnee.
+
+Si vous annulez votre abonnement, mais continuez pourtant a recevoir
+des messages de la liste, vous avez probablement effectue votre
+inscription sous une adresse differente de celle que vous utilisez
+actuellement.
+Verifiez dans l'en-tete une ligne de la forme :
+
+'Return-Path: <<#l#>-return-1234-utilisateur=machine.domaine@<#H#>>'
+
+Cela reflete une inscription de l'adresse
+"utilisateur@machine.domaine". Dans ce cas, il est possible de
+se desabonner en ecrivant a :
+'<#l#>-unsubscribe-utilisateur=machine.domaine@<#H#>'.
+
+Reprenez cet exemple apres y avoir mis votre adresse d'inscription.
+
+Si vous avez recu des messages disposant dans leur en-tete d'une
+ligne "List-Unsubscribe:", vous pouvez directement ecrire a cette
+adresse. Inutile de preciser quoi que ce soit d'autre : il est
+deja personnalise.
+
+Dans certains programmes, il est necessaires d'activer des options
+pour faire figurer toutes les lignes de l'en-tete des messages.
+
+Si malgre tout cela ne fonctionne toujours pas, je suis au regret
+de vous informer que je ne peut guere vous aider davantage.
+Il vous reste donc a faire suivre (Forward) un message au
+proprietaire de la liste accompagne d'un petit mot doux.
+Voici son adresse :
+
+    <#l#>-owner@<#H#>
+
+N'etant pas un robot, sa reponse ne sera pas immediate.
+
+</text/unsub-ok#E/>
+Accuse de reception : l'adresse
+
+!A
+
+a ete retiree de la liste de diffusion <#l#>.
+Cette adresse ne figure donc plus parmis les abonnes.
+
+</text/edit-do#nE/>
+Veuillez editer le fichier de texte suivant et l'envoyer a
+cette adresse :
+
+!R
+
+
+Votre logiciel de messagerie doit posseder une fonction de reponse (Reply)
+pour y ecrire automatiquement.
+
+A noter que je peux retirer les quotes ajoutes par votre logiciel dans
+la mesure ou vous n'editez pas les lignes concernees.
+
+Les lignes de reperage sont celles qui debutent par '%%%'. Elles ne doivent
+pas etre modifiees (des caracteres supplementaires ajoutes par votre logiciel
+au debut d'une ligne sont tolerables).
+
+
+</text/edit-list#nE/>
+
+La commande <#L#>-edit.file peut etre utilisee par un administrateur
+distant pour editer les fichiers de textes a la base des reponses de la
+liste <#L#>@<#H#>.
+
+Ci-dessous, une liste des fichiers contenant les textes de reponses
+et une breve description de l'utilisation de leur contenu. Pour editer un
+fichier, envoyez simplement un message a <#L#>-edit.fichier, en substituant
+le nom du fichier a 'fichier'. Les instructions d'edition seront envoyees
+avec le fichier de texte.
+
+Fichier             Utilisation
+
+bottom              pied de page de toutes les reponses: infos generales.
+digest              section 'administrative' des bulletins periodiques.
+faq                 reponses aux questions frequentes au sujet de cette liste.
+get_bad             dans le cas de messages absents des archives.
+help                aide generale (entre 'top' et 'bottom').
+info                informations sur la liste. La premiere ligne en est un resume.
+mod_help            aide specifique aux moderateurs de liste.
+mod_reject          a l'expediteur d'envois refuses.
+mod_request         aux moderateurs avec un envoi.
+mod_sub             a l'abonne apres confirmation d'inscription du moderateur.
+mod_sub_confirm     aux moderateurs pour valider une inscription.
+mod_timeout         a l'expediteur d'un message non valide depuis longtemps.
+mod_unsub_confirm   a un administrateur pour demander une desinscription.
+sub_bad             a l'abonne si la confirmation etait mauvaise.
+sub_confirm         a l'abonne pour confirmer sa requete.
+sub_nop             a l'abonne apres une nouvelle inscription.
+sub_ok              a l'abonne apres un abonnement reussi.
+top                 en-tete de chaque reponse.
+</#tnE/>
+trailer             ajoute a la fin de chaque contribution a la liste.
+</#nE/>
+unsub_bad           a l'abonne si la confirmation de desinscription est fausse.
+unsub_confirm       a l'abonne pour demander confirmation de desinscription.
+unsub_nop           a un non-abonne apres une demande de desabonnement.
+unsub_ok            a un ex-abonne apres une desinscription reussie.
+
+</text/edit-done#nE/>
+Le fichier de texte a ete mis a jour avec succes.
+</text/info#E/>
+Aucune information complementaire n'existe pour cette liste.
+</text/faq#E/>
+FAQ - Reponses aux questions courantes sur la liste <#l#>@<#H#> 
+
+Aucune pour le moment.
+
+
diff --git a/ezmlmrc.id b/ezmlmrc.id
new file mode 100644 (file)
index 0000000..506918f
--- /dev/null
@@ -0,0 +1,1155 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.id,v 1.5 1999/12/22 04:02:15 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc.id translated By Aria Prima Novianto.
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Maaf, program ini menolak posting anda. Hubungi <#L#>-owner@<#H#> jika anda mempunyai pertanyaan tentang hal ini (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Maaf, hanya pelanggan boleh mengirim posting. Jika anda seorang pelanggan, forward mail ini ke <#L#>-owner@<#H#> supaya email baru anda juga dimasukkan (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+Untuk berhenti, e-mail: <#L#>-unsubscribe@<#H#>
+Untuk perintah yang lain, e-mail: <#L#>-help@<#H#>
+</text/bottom#E/>
+
+--- Perintah-perintah untuk list <#l#> ---
+
+Program ini bisa menerima permohonan secara otomatis. Tolong jangan 
+kirim permohonan ke alamat list!  Tetapi, kirim permohonan anda ke 
+alamat berikut:
+
+Untuk daftar dan deskripsi perintah yang ada, kirim e-mail ke:
+   <<#L#>-help@<#H#>>
+
+Untuk menjadi pelanggan list, kirim e-mail ke:
+   <<#L#>-subscribe@<#H#>>
+
+Untuk berhenti sebagai pelanggan, kirim e-mail ke alamat yang ada di
+``List-Unsubscribe'' header dari e-mail yang anda terima dari milis.
+Jika anda belum ganti alamat e-mail sejak menjadi pelanggan, bisa juga
+berhenti dengan mengirim e-mail ke:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+atau untuk digest ke:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#E/>
+Untuk penambahan atau penghapusan satu alamat, konfirmasi akan dikirim
+ke alamat tersebut. Jika anda menerimanya, cukup reply e-mail
+konfirmasi tersebut.
+
+Jika anda ingin berhubungan dengan pemilik list ini, silakan kirim
+e-mail ke:
+
+    <<#L#>-owner@<#H#>>
+
+Tolong FORWARD mail dari milis yang anda ikuti lengkap dengan SEMUA HEADER
+untuk mempermudah kami menolong anda.
+
+--- Berikut adalah kopi dari permohonan yang kami terima.
+
+</text/bounce-bottom#E/>
+
+--- Berikut adalah kopi dari e-mail mental yang kami terima.
+
+</text/bounce-num#E/>
+
+Kami menyimpan daftar posting dari milis <#L#> yang mental dari
+alamat anda.
+
+</#aE/>
+Kopi dari posting-posting ini mungkin masih ada di dalam arsip.
+
+</#aE/>
+Untuk mendapatkan posting 123-145 (maksimum 100 posting untuk setiap 
+permohonan), kirim e-mail kosong ke:
+   <<#L#>-get.123_145@<#H#>>
+
+Untuk mendapatkan daftar subjek dan penulis dari 100 posting terakhir,
+kirim e-mail kosong ke:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Berikut adalah nomor-nomor posting:
+
+</text/dig-bounce-num#E/>
+
+Kami telah menyimpan daftar digest dari milis <#L#>-digest yang
+mental dari alamat anda.  Untuk setiap digest yang tidak anda terima,
+kami telah mencatat nomor dari posting pertama dari digest tersebut.
+
+</#aE/>
+Kami sendiri tidak menyimpan digest-digest tersebut, tapi mungkin anda
+dapat mengambilnya dari arsip milis utamanya.
+
+Untuk mendapatkan posting 123-145 (maksimum 100 posting untuk setiap
+permohonan), kirim e-mail kosong ke:
+   <<#L#>-get.123_145@<#H#>>
+
+Untuk mendapatkan daftar subjek dan penulis dari 100 posting terakhir,
+kirim e-mail kosong ke:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Berikut adalah nomor-nomor posting dari digest:
+
+</text/bounce-probe#E/>
+
+Posting-posting untuk anda dari milis <#l#> nampaknya mental.
+Kami telah mengirimkan sebuah mail peringatan, namun mental juga.
+Kami lampirkan kopi dari mail yang mental tersebut.
+
+Ini adalah mail percobaan untuk mencek apakah alamat e-mail anda dapat
+terjangkau.  Jika mail ini mental, kami akan menghapus alamat anda dari
+milis <#l#>@<#H#> tanpa pemberitahuan lebih lanjut.
+
+Anda dapat mendaftar kembali dengan mengirimkan e-mail kosong ke:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+Posting-posting ke anda dari milis <#l#> nampaknya mental.
+Kami lampirkan kopi dari posting mental pertama yang kami
+terima.
+
+Jika posting ini juga mental, kami akan mengirimkan sebuah mail
+percobaan. Jika mail tersebut juga mental, kami akan menghapus alamat
+anda dari milis <#l#> tanpa pemberitahuan lebih lanjut.
+
+</text/digest#dE/>
+Untuk berlangganan digest, e-mail:
+       <#L#>-digest-subscribe@<#H#>
+
+Untuk berhenti berlangganan digest, e-mail:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Untuk mengirim posting ke list, e-mail:
+       <#L#>@<#H#>
+
+</text/get-bad#E/>
+Maaf, posting tersebut tidak ada di arsip kami.
+
+</text/help#E/>
+Ini adalah sebuah panduan umum.  Posting yang kami terima tidak
+terkirim ke salah satu dari alamat-alamat perintah kami.
+
+Berikut ini adalah daftar perintah yang tersedia:
+
+Kirim e-mail ke alamat berikut untuk info dan FAQ list:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Alamat berikut bisa digunakan untuk list digest:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+Untuk mendapatkan posting 123-145 (maksimum 100), kirim e-mail ke:
+   <<#L#>-get.123_145@<#H#>>
+
+Untuk mendapatkan indeks subjek dan penulis posting 123-456, kirim e-mail ke:
+   <<#L#>-index.123_456@<#H#>>
+
+Untuk menerima semua posting dengan subjek yang sama dengan posting 12345,
+kirim e-mail ke:
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+E-mail tidak perlu kosong, tapi program ini tidak akan membaca isi mail. 
+Hanya alamat tujuan e-mail yang penting.
+
+Anda dapat berlangganan menggunakan alamat e-mail anda yang lain,
+misalnya "john@host.domain", dengan menambahkan '-' dan alamat e-mail
+anda (gunakan '=' sebagai pengganti '@') setelah kata perintah:
+<<#L#>-subscribe-john=host.domain@<#H#>>
+
+Untuk berhenti menerima email di alamat ini, kirim e-mail ke:
+<<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</text/mod-help#E/>
+Terima kasih atas kesediaan anda untuk memoderatori
+milis <#L#>@<#H#>.
+
+Perintah-perintah yang kami punya agak sedikit berbeda dari milis-milis 
+yang lain, tapi kami harap anda dapat menggunakannya dengan mudah.
+
+Berikut adalah beberapa perintah untuk tugas-tugas yang mungkin harus
+anda lakukan sebagai list-owner dan/atau moderator.
+
+Perintah-perintah umum akan ada di bagian akhir mail ini.
+
+Pendaftaran jarak jauh
+----------------------
+Sebagai moderator, anda dapat mendaftarkan dan menghapuskan siapa saja ke
+dalam milis. Untuk mendaftarkan "john@host.domain", taruh '-' setelah kata
+perintahnya, kemudian alamat emailnya dengan menggunakan tanda '=' sebagai
+ganti dari '@'. Contoh, untuk mendaftarkan alamat tersebut, kirim mail ke:
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Dengan cara yang sama, untuk menghapus alamat tersebut, kirim mail ke:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#dE/>
+Untuk list digest:
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+</#E/>
+Itu saja. Tidak perlu subjek dan isi dari postingnya!
+
+</#rE/>
+Kami akan mengirimkan sebuah permohonan konfirmasi, untuk memastikan
+bahwa anda benar-benar mengirimkan permohonan tersebut. Yang perlu anda
+lakukan adalah mereply ke mail konfirmasi tersebut.
+</#RE/>
+Kami akan mengirimkan sebuah permohonan konfirmasi ke alamat tersebut,
+dalam hal ini <john@host.domain>. Yang bersangkutan tinggal menjawab
+mail konfirmasi tersebut.
+</#E/>
+
+Konfirmasi-konfirmasi tersebut sangat penting untuk menghindari pihak
+ketiga untuk menambah atau menghapus sebuah alamat e-mail ke dalam list.
+
+Kami akan memberitahu pelanggan tersebut ketika status berlangganannya
+telah berubah.
+
+Berlangganan
+------------
+
+Setiap pemakai dapat berlangganan atau berhenti dengan mengirim e-mail ke:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#dE/>
+Untuk list digest:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+</#E/>
+Si fulan akan menerima sebuah permohonan konfirmasi untuk memastikan
+bahwa dialah pemilik alamat e-mail yang sebenarnya.  Setelah ini telah dapat
+dikonfirmasikan, yang bersangkutan akan dihapus dari list.
+
+</#sE/>
+Karena milis ini telah dimoderatori untuk dapat berlangganan, kami akan
+mengirimkan permohonan konfirmasi kedua kepada moderator. Karena si
+fulan telah berkeinginan untuk masuk ke dalam list, anda sebagai
+moderator dapat percaya bahwa alamat pemakai tersebut adalah benar. Jika
+anda ingin menyetujui permohonan tersebut, reply ke mail CONFIRM kami.
+Jika tidak, anda dapat menghapus mail dari kami ini atau mungkin
+mengkontak calon pelanggan list untuk keterangan lebih lanjut.
+</#SE/>
+Untuk berlangganan adalah sama caranya.
+</#E/>
+
+Si fulan dapat juga mengirim mail ke:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+untuk mendapatkan mailnya terkirim ke "mary@host.domain".  Hanya jika 
+yang bersangkutan menerima mail pada alamat tersebut, dia akan menerima
+permohonan konfirmasi tersebut dan dapat mereplynya.
+
+Alamat dan identitas anda tidak akan tampak pada mail ke si pelanggan,
+kecuali kalau anda mengirim mail secara langsung ke yang bersangkutan.
+
+</#rlE/>
+Untuk mendapatkan daftar pelanggan <#L#>@<#H#>, kirim mail ke:
+   <<#L#>-list@<#H#>>
+
+Untuk mendapatkan daftar log transaksi <#L#>@<#H#>, kirim mail ke:
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+Untuk pelanggan-pelanggan digest:
+   <<#L#>-digest-list@<#H#>>
+dan:
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+Anda dapat dari jarak jauh mengedit file-file yang dikirim oleh list.
+Untuk mendapatkan daftar file dan petunjuk untuk mengeditnya, e-mail ke:
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+Posting-posting termoderatori
+-----------------------------
+Ketika posting-posting dimoderatori, kami akan menyimpan posting yang
+terkirim dan mengirimkan kopinya ke anda berikut petunjuk-petunjuk.
+Posting ke anda akan mempunyai subjek "MODERATE for ..."
+
+Untuk menyetujui posting tersebut, reply ke 'Reply-To:' yang telah kami
+persiapkan dengan alamat "accept" yang benar.  Anda tidak perlu untuk
+memasukkan postingnya sendiri.  Bahkan, kami tidak akan menghiraukan
+apapun yang anda kirim ke kami asalkan alamat yang anda kirim sudah benar.
+
+Jika anda ingin menolak, mail ke alamat 'From:' yang telah kami persiapkan
+dengan alamat "reject" yang benar. Ini dapat dilakukan dengan cara
+'reply-to-all', kemudian menghapus alamat selain alamat 'reject' tersebut.
+Anda dapat memberi komentar ke si pengirim diantara dua baris yang dimulai
+dengan tiga buah '%'. Komentar ini hanya akan dikirim ke si fulan yang
+yang postingnya ditolak. Sekali lagi, identitas anda akan dirahasiakan.
+
+Kami akan memproses posting sesuai dengan reply pertama yang kami terima.
+Jika anda mengirim mail untuk menyetujui posting yang sebelumnya sudah
+ditolak, atau sebaliknya, kami akan memberitahu anda.
+
+Jika kami tidak menerima reply dari moderator dalam waktu tertentu
+(biasanya 5 hari), kami akan mengembalikan posting tersebut ke si pengirim
+dengan penjelasan tentang apa yang telah terjadi. Anda sebagai administrator
+dapat juga mengatur listnya untuk menghapus posting-posting tersebut tanpa
+pemberitahuan, juga tanpa perlu dikembalikan ke si pengirim.
+</#E/>
+
+Vakansi
+-------
+Jika sedang berada pada alamat yang berbeda, forward semua posting yang
+mempunyai header 'Mailing-List:' yang benar (atau semuanya yang mempunyai
+subjek dengan awalan 'MODERATE for <#L#>@<#H#>' atau
+'CONFIRM subscribe to <#L#>@<#H#>') ke alamat yang baru. Anda kemudian dapat
+memoderatorinya dari alamat yang baru. Atau anda dapat memforwardkan
+posting-posting tersebut ke teman anda sehingga dia dapat memoderatorinya
+untuk anda. Mohon untuk meminta persetujuan dari pemilik list terlebih dahulu.
+
+Jika anda ingin secara otomatis menyetujui semua permohonan-permohonan
+ketika anda sedang pergi, atur program mail anda untuk mereply otomatis ke
+semua posting yang mempunyai subjek sesuai keterangan di atas.
+
+</#rE/>
+Jika anda mencoba untuk melakukan administrasi jarak jauh dari sebuah
+alamat yang bukan milik anda, si pemohon, bukan anda, akan dimintakan
+konfirmasinya.  Setelah itu, sebuah permohonan konfirmasi akan
+dikirimkan ke semua moderator.  Kami lakukan itu karena kami tidak dapat
+mengetahui apakah permohonan tersebut benar berasal dari anda.
+
+Tolong perhatikan bahwa permohonan asli anda (dan alamat anda) akan
+dikirimkan ke si pemohon dalam hal ini!
+</#E/>
+
+Semoga sukses!
+
+PS: Silakan kontak si pemilik list (<#L#>-owner@<#H#>) jika anda
+mempunyai pertanyaan-pertanyaan atau masalah-masalah.
+
+</text/mod-reject#E/>
+Maaf, posting anda (terlampir) tidak diterima oleh moderator.  Jika ada
+komentar-komentar dari moderator, mereka akan terlihat di bawah.
+</text/mod-request#E/>
+Posting terlampir telah dikirim ke milis <#L#>@<#H#>.  Jika anda
+ingin menyetujuinya untuk disebarluaskan ke semua pelanggan, kirim
+e-mail ke:
+
+!A
+
+Biasanya, yang perlu anda lakukan adalah dengan menekan tombol "reply".
+Anda dapat mencek untuk memastikan bahwa alamatnya dimulai dengan
+"<#L#>-accept".  Jika ini tidak berhasil, kopi alamatnya dan letakkan
+kembali ke dalam kolom "To:" di posting yang baru.
+</#xE/>
+
+Alternatif lainnya, klik di sini:
+       mailto:<#A#>
+</#E/>
+
+Untuk menolak posting dan mengembalikannya ke si pengirim, kirim sebuah
+posting ke:
+
+!R
+
+Biasanya, cara termudah adalah dengan menekan tombol "reply-to-all", dan
+kemudian menghapus semua alamat kecuali yang dimulai dengan
+"<#L#>-reject".
+</#xE/>
+
+Alternatif lainnya, klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Anda tidak perlu untuk mengkopi isi dari posting ke dalam respon
+persetujuan atau penolakan anda.  Jika anda ingin membuat komentar
+kepada si pengirim yang tertolak postingnya, masukkan komentarnya di 
+antara dua garis penanda yang dimulai dengan tiga tanda persen ('%'):
+
+%%% Start comment
+%%% End comment
+
+Terima kasih atas bantuan anda!
+
+--- Berikut adalah posting yang terkirim.
+
+</text/mod-sub#E/>
+--- Kami telah mendaftarkan atau menghapus e-mail anda sesuai permohonan
+dari moderator milis <#l#>@<#H#>.
+
+Jika hal ini tidak sesuai dengan yang anda harapkan, silakan kirim
+sebuah mail komplain atau komentar-komentar ke pemilik list
+(<#l#>-owner@<#H#>) secepatnya.
+
+</text/mod-timeout#E/>
+Maaf, moderator-moderator dari milis <#L#> sedang sibuk saat ini.  
+Oleh karenanya, kami mengirimkan posting ini kembali ke anda.  Jika anda 
+menyadari bahwa ini adalah sebuah kesalahan, tolong kirimkan ulang posting 
+anda atau kontak seorang moderator list secara langsung.
+
+--- Berikut adalah posting yang anda kirim.
+
+</text/mod-sub-confirm#E/>
+Dengan hormat kami mengharapkan ijin anda untuk menambahkan 
+
+!A
+
+ke dalam daftar pelanggan-pelanggan milis <#l#>.  Permohonan ini datangnya 
+adalah dari anda sendiri, atau dari si calon pelanggan yang sudah 
+memverifikasikannya.
+
+Untuk mengkonfirmasikannya, kirim reply kosong ke alamat berikut:
+
+!R
+
+Biasanya, yang perlu anda lakukan adalah dengan menekan tombol "reply".
+Jika ini tidak berhasil, kopi alamatnya dan letakkan kembali ke dalam 
+kolom "To:" di posting yang baru.
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Jika anda tidak menyetujuinya, jangan hiraukan posting tersebut.
+
+Terima kasih atas bantuan anda!
+
+</text/mod-unsub-confirm#E/>
+Sebuah permohonan telah dibuat untuk menghapus
+
+!A
+
+dari milis <#l#>. Jika anda setuju, kirim mail kosong
+ke alamat ini:
+
+!R
+
+Biasanya, yang perlu anda lakukan adalah dengan menekan tombol "reply".
+Jika ini tidak berhasil, kopi alamatnya dan letakkan kembali ke dalam
+kolom "To:" di posting yang baru.
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Jika anda tidak menyetujuinya, jangan hiraukan posting tersebut.
+
+Terima kasih atas bantuan anda!
+
+</text/sub-bad#E/>
+Oops, nomor konfirmasi tersebut kelihatannya tidak valid.
+
+Sebab yang paling umum untuk nomor yang invalid adalah kadaluarsa. Kami
+harus menerima konfirmasi dari setiap permohonan dalam jangka waktu 10 hari.
+Juga, pastikan bahwa seluruh nomor konfirmasi masuk dalam reply yang anda
+kirimkan ke kami. Beberapa program e-mail mempunyai kebiasaan untuk
+memotong sebagian dari alamat reply, yang kadang sangat panjang.
+
+Kami telah membuat sebuah nomor konfirmasi baru. Kalau anda ingin
+
+!A
+
+masuk ke dalam milis <#l#>,
+kirim mail kosong ke alamat:
+
+!R
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Sekali lagi, cek alamat replynya secara cermat untuk memastikan bahwa
+semuanya telah masuk sebelum anda mengirim konfirmasi anda.
+
+Maaf atas ketidaknyamanan ini.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+Untuk memastikan bahwa anda ingin
+
+!A
+
+masuk ke dalam milis <#l#>, kirim mail kosong
+ke alamat berikut:
+
+!R
+
+Biasanya, yang perlu anda lakukan adalah dengan menekan tombol "reply".
+Jika ini tidak berhasil, kopi alamatnya dan letakkan kembali ke dalam
+kolom "To:" di posting yang baru.
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Mail konfirmasi ini mempunyai dua tujuan.  Pertama, untuk memastikan
+bahwa kami dapat menghubungi anda.  Kedua, untuk mencegah orang lain
+memalsukan permohonan pendaftaran atas nama anda.
+
+</#qE/>
+Beberapa program mail tidak berfungsi sempurna dan tidak dapat menangani
+alamat-alamat panjang.  Jika anda tidak dapat mereply ke permohonan ini,
+kirimkan sebuah mail ke <<#L#>-request@<#H#>> dan taruh
+alamat-alamat yang nampak di atas ke dalam baris "Subject:". 
+
+</#sE/>
+List ini dimoderatori.  Sekali anda telah mengirim konfirmasi ini,
+permohonannya akan dikirimkan ke moderator dari list ini.  Kami akan
+mengabari anda jika e-mail anda telah diaktifkan.
+
+</text/sub-nop#E/>
+Untuk diketahui: Alamat berikut
+
+!A
+
+sudah terdaftar pada milis <#l#> ketika kami menerima permohonan anda,
+dan masih berstatus sebagai pelanggan.
+
+</text/sub-ok#E/>
+Untuk diketahui: Kami telah menambahkan alamat
+
+!A
+
+ke milis <#l#>.
+
+Selamat datang di <#l#>@<#H#>!
+
+Tolong simpan mail ini sehingga anda dapat tahu dengan alamat apa anda
+terdaftar pada milis, jika sewaktu-waktu anda ingin berhenti atau
+mengganti alamat berlangganan anda di kemudian hari.
+
+Untuk berhenti, kirim mail ke:
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Hai! Ini adalah program ezmlm.
+Kami yang mengurus milis <#l#>@<#H#>.
+
+</#x/>
+Kami bekerja untuk pemilik kami, yang dapat dijangkau pada alamat e-mail 
+<#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+Oops, nomor konfirmasi tersebut kelihatannya tidak valid.
+
+Sebab yang paling umum untuk nomor yang invalid adalah kadaluarsa. Kami
+harus menerima konfirmasi dari setiap permohonan dalam jangka waktu 10 hari.
+Juga, pastikan bahwa seluruh nomor konfirmasi masuk dalam reply yang anda
+kirimkan ke kami. Beberapa program e-mail mempunyai kebiasaan untuk
+memotong sebagian dari alamat reply, yang kadang sangat panjang.
+
+Kami telah membuat sebuah nomor konfirmasi baru. Kalau anda ingin
+
+!A
+
+dihapus dari milis <#l#>,
+kirim reply kosong ke alamat:
+
+!R
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Sekali lagi, cek alamat replynya secara cermat untuk memastikan bahwa
+semuanya telah masuk sebelum anda mengirim konfirmasi anda.
+
+Maaf atas ketidaknyamanan ini.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+Untuk memastikan bahwa anda ingin
+
+!A
+
+dihapus dari milis <#l#>,
+kirim mail kosong ke alamat:
+
+!R
+
+Biasanya, yang perlu anda lakukan adalah dengan menekan tombol "reply".
+Jika ini tidak berhasil, kopi alamatnya dan letakkan kembali ke dalam
+kolom "To:" di posting yang baru.
+</#xE/>
+
+atau klik di sini:
+       mailto:<#R#>
+</#E/>
+
+Kami belum mencek apakah alamat anda sudah ada di dalam milis. Untuk
+melihat alamat apa yang anda pakai untuk mendaftar, lihat mail yang anda
+terima dari milis. Setiap mail mempunyai alamat anda yang tersembunyi di
+dalam return-pathnya; sebagai contoh, mary@xdd.ff.com menerima mail
+dengan return-path: <<#l#>-return-<number>-mary=xdd.ff.com@<#H#>.
+
+</#qE/>
+Beberapa program mail tidak berfungsi sempurna dan tidak dapat menangani
+alamat-alamat panjang. Jika anda tidak dapat mereply ke permohonan ini,
+kirimkan sebuah mail ke <<#L#>-request@<#H#>> dan taruh alamat-alamat
+yang nampak di atas ke dalam baris "Subject:".
+
+</text/unsub-nop#E/>
+Permohonan anda tidak dapat kami penuhi, disebabkan
+alamat berikut
+
+!A
+
+tidak terdaftar dalam milis <#l#> ketika kami menerima permohonan anda
+dan bukan pelanggan dari list ini.
+
+Jika anda berhenti, tapi masih menerima mail, anda terdaftar dengan
+alamat lain dari yang anda pakai sekarang.  Tolong lihat header surat
+untuk:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+Ini menunjukkan bahwa alamat pelanggan adalah ``user@host.dom''.
+Alamat berhenti untuk pelanggan ini adalah:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+
+Kirim mail ke alamat tersebut, disesuaikan dengan alamat sebenarnya.
+
+Kalau mail dari milis punya header ``List-Unsubscribe:'', anda dapat
+mengirim mail ke alamat yang ada di dalam header tersebut. Header
+tersebut berisi alamat khusus untuk anda gunakan untuk berhenti.
+
+Untuk beberapa program mail, anda perlu untuk membuat headersnya
+terlihat untuk dapat melihat return path:
+
+Untuk Eudora 4.0, klik pada tombol "Blah blah ...".
+Untuk PMMail, klik pada "Window->Show entire message/header".
+
+Jika itu masih belum berhasil, kami mohon maaf kami tidak dapat membantu
+anda. Tolong FORWARD mail dari list tersebut bersama-sama dengan sedikit
+catatan tentang apa yang ingin anda lakukan dan daftar kemungkinan
+alamat-alamat e-mail yang anda daftarkan pada milis, ke pemilik list:
+
+    <#l#>-owner@<#H#>
+
+yang kemudian akan menanganinya.  Pemilik list ini agak sedikit lambat
+dari kami, harap sabar.
+
+</text/unsub-ok#E/>
+Untuk diketahui: Kami telah menghapus alamat
+
+!A
+
+dari milis <#l#>. Alamat tersebut sudah tidak ada lagi di dalam
+daftar pelanggan.
+
+</text/edit-do#nE/>
+Silakan edit file teks berikut dan kirimkan ke alamat ini:
+
+!R
+
+Program mail anda punya Reply yang menggunakan alamat ini secara otomatis.
+
+Kami dapat menghapus tanda-tanda kutip yang ditambahkan pada teks oleh
+program mail anda, jika anda tidak mengedit baris-baris penanda tersebut.
+
+Baris-baris penanda tersebut dimulai dengan '%%%'.  Jangan merubahnya
+(karakter-karakter ekstra yang ditambahkan oleh program mail anda pada
+baris pertama dapat diterima).
+
+
+</text/edit-list#nE/>
+Perintah <#L#>-edit.file dapat digunakan oleh administrator dari jarak
+jauh untuk mengedit file-file teks untuk kemudian membuat kumpulan dari
+tanggapan-tanggapan dari milis <#L#>@<#H#>.
+
+Berikut adalah daftar dari nama-nama file tanggapan beserta keterangan
+singkat tentang kapan mereka digunakan. Untuk mengedit suatu file,
+kirim mail ke <#L#>-edit.file, dengan menggantikan nama file untuk 'file'.
+Instruksi-instruksi pengeditan juga dikirimkan beserta file teksnya.
+
+File                Kegunaan
+
+bottom              bagian bawah dari semua tanggapan.  Informasi secara umum.
+digest              'administrivia' bagian dari digests.
+faq                 frequently asked questions khusus untuk list tersebut.
+get_bad             pengganti posting-posting yang tidak ditemukan pada arsip.
+help                panduan umum (antara 'top' dan 'bottom').
+info                info list. Baris pertama sangat berarti.
+mod_help            panduan khusus untuk moderator list. 
+mod_reject          untuk pengirim yang postingnya tertolak.
+mod_request         untuk moderator dengan postingnya.
+mod_sub             untuk pelanggan setelah moderator menyetujui.
+mod_sub_confirm     untuk moderator untuk permohonan berlangganan.
+mod_timeout         untuk pengirim yang postingnya kadaluarsa.
+mod_unsub_confirm   untuk admin untuk permohonan berhenti.
+sub_bad             untuk pelanggan jika konfirmasi berlangganan tidak sukses.
+sub_confirm         untuk pelanggan untuk permohonan berlangganan.
+sub_nop             untuk pelanggan setelah mendaftar ulang.
+sub_ok              untuk pelanggan setelah permohonannya sukses.
+top                 bagian atas dari semua tanggapan.
+</#tnE/>
+trailer             ditambahkan ke semua posting yang terkirim.
+</#nE/>
+unsub_bad           untuk pelanggan jika konfirmasi berhenti tidak sukses.
+unsub_confirm       untuk pelanggan untuk permohonan berhenti.
+unsub_nop           untuk bukan-pelanggan setelah berhenti.
+unsub_ok            untuk eks-pelanggan setelah suksesnya permohonan berhenti.
+
+</text/edit-done#nE/>
+Teks filenya sudah diupdate dengan sukses.
+</text/info#E/>
+Tidak ada informasi yang telah disediakan untuk list ini.
+</text/faq#E/>
+FAQ - Frequently asked questions untuk milis <#l#>@<#H#>.
+
+Belum tersedia sampai saat ini.
+
+
diff --git a/ezmlmrc.it b/ezmlmrc.it
new file mode 100644 (file)
index 0000000..3db0eec
--- /dev/null
@@ -0,0 +1,1155 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.it,v 1.3 1999/12/22 04:02:15 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# translation by Roberto De Carlo rodeca@tiscalinet.it
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+Per cancellarsi, scrivi a: <#L#>-unsubscribe@<#H#>
+Se vuoi conoscere altri comandi, scrivi a: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Comandi di gestione per la mailing list <#l#>  ---
+
+Posso elaborare comandi di gestione autonomamente. Per 
+favore non inviarli direttamente all'indirizzo della lista!
+Invece spedisci il tuo messaggio al giusto indirizzo per i comandi:
+
+Per ricevere aiuto e una descrizione dei comandi, scrivi a:
+   <<#L#>-help@<#H#>>
+
+Per iscriversi alla lista, spedisci un messaggio a:
+   <<#L#>-subscribe@<#H#>>
+
+Per cancellare il tuo indirizzo dalla lista, ti basta scrivere 
+all'indirizzo presente nell'intestazione ``List-Unsubscribe'' di
+qualsiasi messaggio della lista. Se non hai cambiato indirizzo da
+quando ti sei iscritto, puoi anche mandare un messaggio a:
+    <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+o per le raccolte a:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#E/>
+
+Per l'aggiunta o la rimozione degli indirizzi di email, ti spedirò
+una conferma. Quando la riceverai, ti basta semplicemente rispondere
+per completare l'operazione.
+
+Se desideri contattare il responsabile in carne ed ossa di questa
+lista perfavore spedisci un messaggio a:
+
+    <<#L#>-owner@<#H#>>
+
+Perfavore inccludi un messaggio della lista con tutte le intestazioni
+complete per farti aiutare più facilmente.
+
+--- Allego una copia della richiesta che ho ricevuto.
+
+</text/bounce-bottom#E/>
+
+--- Allego una copia del messaggio di ritorno che ho ricevuto.
+
+</text/bounce-num#E/>
+
+Ho tenuto una copia dei messaggi della lista <#L#> che sono tornati
+indietro dal tuo indirizzo.
+
+</#aE/>
+Le copie di questi messaggi potrebbero essere nell'archivio.
+
+</#aE/>
+
+Per ricevere l'insieme dei messaggi 123-145 (al massimo
+100 per richiesta) dall'archivio, scrivi un messaggio vuoto a:   
+   <<#L#>-get.123_145@<#H#>>
+
+
+Per ricevere l'elenco dei soggetti e degli autori degli ultimi 100
+messaggi scrivi a:
+
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Ecco i numeri dei messaggi:
+
+</text/dig-bounce-num#E/>
+
+Ho un elenco delle raccolte dalla mailing list <#L#>-digest che sono
+tornate indietro dal tuo indirizzo. Per ogni raccolta che ti sei
+perso ho annotato il numero del primo messaggio della raccolta. 
+
+</#aE/>
+Io non archivio le raccolte stesse, ma sei in grado di prendere i
+messaggi dall'archivio  principale della mailing list.
+
+Per ricevere i messaggi dal numero 123 al numero 145 (massimo 100 per ogni
+richiesta),  scrivi un messaggio vuoto a:
+
+   <<#L#>-get.123_145@<#H#>>
+
+Per ricevere l'elenco dei soggetti e degli autori degli ultimi 100 messaggi
+scrivi a:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Ecco i numeri delle raccolte:
+
+</text/bounce-probe#E/>
+
+I messaggi a te inviati dalla mailing list <#l#> sembrano tornare indietro.
+Ti ho spedito un messaggio di avvertimento, ma anche questo è tornato
+indietro.
+ Allego una copia del primo messaggio che mi è tornato indietro.
+
+Questa è una prova per vedere se il tuo indirizzo è raggiungibile.
+Se anche questo messaggio torna indietro toglierò il tuo indirizzo dalla
+mailing list <#l#>@<#H#> senza ulteriori avvertimenti.
+
+Ti potrai reiscrivere spedendo un messaggio a questo indirizzo:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+I messaggi a te inviati dalla mailing list <#l#> sembrano tornare indietro.
+Ti ho spedito un messaggio di avvertimento, ma anche questo è tornato
+indietro.
+ Allego una copia del primo messaggio che mi è tornato indietro.
+
+Se anche questo messaggio torna indietro ti spedirò un messaggio di
+prova. Se ritorna anche questo messaggio toglierò il tuo indirizzo
+dalla mailing list <#l#> senza ulteriori avvertimenti. 
+
+</text/digest#dE/>
+Per iscriversi alla lista delle raccolte scrivi a:
+       <#L#>-digest-subscribe@<#H#>
+
+Per rimuoverti dalla lista delle raccolte scrivi a:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Per spedire un messaggio alla lista scrivi a:
+       <#L#>@<#H#>
+
+</text/get-bad#E/>
+Spiacente, questo messaggio non è nell'archivio.
+
+</text/help#E/>
+Questo è un messaggio di aiuto generico. Il messaggio che ho ricevuto
+non è stato spedito ad alcuno dei miei indirizzi per i comandi.
+
+Ecco un elenco degli indirizzi per i comandi consentiti:
+
+Scrivi una email ai seguenti indirizzi per le informazioni o le FAQ
+della lista:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Indirizzi analoghi esistono per la lista delle raccolte:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+Per ricevere i messaggi dal numero 123 al numero 145 (massimo 100 per ogni
+richiesta), scrivi a:
+   <<#L#>-get.123_145@<#H#>>
+
+Per ricevere l'indice dei messaggi 123-456 con l'oggetto e l'autore, scrivi a:
+   <<#L#>-index.123_456@<#H#>>
+
+Per ricevere tutti i messaggi con lo stesso oggetto del messaggio
+12345, spedisci un messaggio vuoto a:
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+I messaggi in realtà non é necessario che siano vuoti, ma ignorerò
+il loro contenuto. E' importante solo l'INDIRIZZO dal quale li spedisci.
+
+Puoi iscriverti anche da un altro indirizzo,per esempio se vuoi iscrivere
+"john@host.domain", basta solo aggiungere un trattino e il tuo indirizzo (con
+'=' al posto di '@') dopo i comandi: <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Per cancellare l'iscrizione da questo indirizzo, scrivi a:
+<<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</text/mod-help#E/>
+Grazie per aver accettato di moderare la mailing list <#L#>@<#H#>.
+
+I miei comandi sono leggermente differenti da quelli delle altre
+mailing list, ma credo che li troverai intuitivi e facili da usare.
+
+Ecco alcune istruzioni per i compiti che dovrai assolvere come 
+amministratore della lista e/o moderatore.
+
+Sottoscrizione remota
+-------------------
+Come moderatore, puoi iscrivere e cancellare qualsiasi indirizzo alla
+mailing list. Per iscrivere "john@host.domain" , basta solo
+aggiungere un trattino  dopo il comando, quindi il suo indirizzo con
+'=' invece di '@'. Per esempio, per iscrivere questo indirizzo scrivi
+a:    <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Analogamente puoi rimuovere l'indirizzo scrivendo a:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#dE/>
+Per la lista delle raccolte:
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+</#E/>
+Questo è tutto. Non sono necessari comandi nell' oggetto o nel corpo del 
+messaggio!
+
+</#rE/>
+Ti spedirò una richiesta di conferma, per essere sicuro che tu abbia
+realmente spedito la richiesta. Rispondi semplicemente al messaggio e i 
+tuoi desideri saranno eseguiti.
+</#RE/>
+Spedirò una richiesta di conferma all'indirizzo dell'utente, in questo caso
+a <john@host.domain>. Tutto ciò che l'utente dovrà fare sarà quello di 
+rispondere alla richiesta di conferma.
+</#E/>
+
+I messaggi di conferma sono necessari per rendere estremamente difficile a
+qualcun altro di aggiungere o togliere un indirizzo dalla lista.
+
+Avvertirò l'utente quando cambia la sua iscrizione.
+
+Iscrizione
+-----------
+
+Qualsiasi utente può iscriversi o rimuoversi scrivendo a:
+
+    <<#L#>-subscribe@<#H#>>
+    <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+Per la lista delle raccolte:
+
+    <<#L#>-digest-subscribe@<#H#>>
+    <<#L#>-digest-unsubscribe@<#H#>>
+
+</#E/>
+L'utente riceverà una richiesta di conferma per essere sicuri che
+controlli veramente l'indirizzo di iscrizione. Una volta fatta la
+verifica l'utente viene rimosso.
+
+</#sE/>
+Visto che questa lista è moderata per le iscrizioni, spedirò una seconda
+richiesta di conferma al moderatore. Dato che l'utente ha già confermato 
+il desiderio di essere nella lista, come moderatore puoi essere certo che 
+l'indirizzo sia esistente. Se vuoi approvare la richiesta dell'utente,
+rispondi semplicemente al mio messaggio di CONFERMA. In caso contrario puoi
+cancellare il mio messaggio o il potenziale iscrivente per maggiori 
+informazioni.
+</#SE/>
+Le iscrizioni funzionano allo stesso modo.
+</#E/>
+
+L'utente può anche utilizzare:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+per ricevere le e-mail a: "mary@host.domain". Solo se riceve effettivamente
+le e-mail a questo indirizzo potrà ricevere il messaggio di conferma ed essere 
+in grado di rispondergli.
+
+Il tuo indirizzo e la tua identità non saranno resi noti agli iscritti, a meno
+che tu non decida di scrivergli direttamente.
+
+</#rlE/>
+Per ricevere l'elenco degli iscritti a: <#L#>@<#H#> invia un messaggio a:
+   <<#L#>-list@<#H#>>
+
+Per ricevere il log delle transazioni per <#L#>@<#H#> scrivi a:
+   <<#L#>-log@<#H#>>
+</#rldE/>
+Per gli iscritti alle raccolte:
+   <<#L#>-digest-list@<#H#>>
+e:
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+Puoi modificare a distanza i file di testo che compongono le risposte che 
+la lista spedisce. Per ricevere un elenco dei file e delle istruzioni per
+modificarli, scrivi a:
+   <<#L#>-edit@<#H#>>
+
+
+</#mE/>
+Moderazione dei messaggi
+------------------------
+Quando i messaggi sono moderati, archivierò il messaggio spedito e te ne
+invierò una copia con le istruzioni. Il messaggio che riceverai avrà
+"MODERATE for ..." come oggetto.
+
+Per accettare il messaggio, basta solo rispondere all'indirizzo 'Rispondi a:' 
+che ho già configurato con il corretto indirizzo di accettazione. Non è 
+necessario allegare il messaggio stesso. Difatti ignorerò tutto ciò che mi
+invierai se l'indirizzo dal quale scrivi è corretto.
+.
+Se vuoi rifutarlo, scrivi una e-mail allindirizzo 'Da:', che avrò già 
+configurato con il corretto indirizzo di "rifuto". Questo di solito può essere
+fatto con il 'Rispondi a tutti:' e cancellando tutti i destinatari escluso 
+quello di "rifiuto". Puoi aggiungere un commento al mittente tra due linee che 
+iniziano con tre '%'. Io spedirò solo questo commento con il messaggio 
+rifiutato. E ancora, non rivelerò la tua identità.
+
+Processerò il messaggio secondo la prima risposta che mi arriverà.
+Se mi spedisci una richiesta di accettare un messaggio che è stato già
+rifiutato o vice versa, te lo farò sapere.
+
+Se non ricevo risposte dal moderatore entro un certo numero di giorni
+(di solito 5), spedirò un messaggio al mittente con la spiegazione di ciò
+che è successo. Il tuo amministratore può anche configurare la lista in modo
+tale che questi messaggi "ignorati" vengano cancellati senza avviso, invece
+che rispediti al mittente. 
+</#E/>
+
+Assenze
+---------
+Se hai momentaneamente un indirizzo diverso, ti basta forwardare tutti i
+messaggi che hanno l'intestazione 'Mailing-List:' (o tutti i messaggi che
+iniziano con 'MODERATE for <#L#>@<#H#>' o con 'CONFIRM subscribe to
+<#L#>@<#H#>') al nuovo indirizzo.
+Puoi perciò moderare la mailing-list dal nuovo indirizzo. In alternativa, puoi
+forwardare i messaggi a un amico in modo tale che li possa moderare lui per te.
+Però assicurati di essere d'accordo con il proprietario della mailing list.
+
+Se vuoi approvare in automatico tutte le richieste mentre sei via, allora
+configura il tuo programma di posta in modo tale da risondere in automatico ai
+messaggi che hanno gli oggetti conformi ai criteri sopracitati.
+
+</#rE/>
+Se vuoi amministrare la lista da un indirizzo che non è il tuo ti verrà
+chiesta una conferma. Fatto ciò, verrà inviata una richiesta di conferma a
+tutti i moderatori. Faccio così perchè non c'è modo di conoscere che sia stato
+davvero tu a mandarmi la richiesta originale. 
+
+Ricorda che la tua richiesta originale ( e il tuo indirizzo) sono spediti a
+tutti gli iscritti in questo caso! 
+</#E/>
+
+Buona fortuna!
+
+PS: Per favore contatta l'amministratore della lista (<#L#>-owner@<#H#>) se
+hai domande o problemi.
+</text/mod-reject#E/>
+Spiacente, ma il tuo messaggio (allegato) non è stato accettato dal moderatore.
+Se il moderatore ha scritto qualche commento, essi sono riportati qui sotto.
+</text/mod-request#E/>
+Il messaggio allegato è stato inviato alla mailing list <#L#>@<#H#>
+Se vuoi approvarlo affinchè venga spedito a tutti gli iscritti, scrivi a:
+
+
+!A
+
+In genere ciò accade non appena schiacci il bottone "Rispondi". Puoi
+controllare l'indirizzo per assicurarti che inizi con "<#L#>-accept".
+Se non funziona, allora ti basta copiare l'indirizzo e incollarlo nel campo
+"A:" di un nuovo messaggio.
+</#xE/>
+
+Oppure clicca qui:
+       mailto:<#A#>
+</#E/>
+
+Per rifiutare il messaggio e fare in modo che esso venga rispedito al
+mittente, per favore spedisci un messaggio a:
+
+!R
+
+Di solito è più facile cliccare sul bottone "Rispondi a tutti:", e poi
+togliere tutti gli indirizzi tranne quello che inizia con "<#L#>-reject".
+</#xE/>
+
+Oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Non è necessario copiare il messaggio nella risposta per accettarlo o
+rifiutarlo. Se desideri spedire un commento al mittente del messaggio
+rifiutato, per favore includilo tra due segnalatori di linea che iniziano
+con tre segni di percentuale ('%'):
+
+%%% Start comment
+%%% End comment
+
+Grazie per il tuo aiuto!
+
+--- In allegato, per favore verifica il messaggio inviato.
+
+</text/mod-sub#E/>
+--- Ti ho iscritto o cancellato dietro richiesta del moderatore della mailing
+list  <#l#>@<#H#>.
+
+Se non approvi quello che è stato fatto, per favore invia una lamentela o
+altri commenti al responsabile della lista (<#l#>-owner@<#H#>) non appena
+possibile.
+
+</text/mod-timeout#E/>
+Sono spiacente, ma il moderatore della lista <#L#> non ha ancora vagliato il
+tuo messaggio, perciò te lo rimando indietro. Se credi che ci sia un errore,
+per favore rispediscilo o contatta il moderatore della lista direttamente.
+
+--- In allegato, per favore, verifica il messaggio che hai spedito.
+
+</text/mod-sub-confirm#E/>
+Chiedo rispettosamente il tuo permesso di aggiungere
+
+!A
+
+agli iscritti della mailing list <#l#>. Questa richiesta o viene da
+te, o è già stata verificata dal potenziale iscritto. 
+
+Per confermare spedisci una risposta vuota a questo indirizzo:
+
+!R
+
+
+In genere ciò accade non appena schiacci il bottone "Rispondi". 
+Se non funziona, allora ti basta copiare l'indirizzo e incollarlo nel campo
+"A:" di un nuovo messaggio.
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Se non sei d'accordo ti basta ignorare questo messaggio.
+
+Grazie per il tuo aiuto!
+
+</text/mod-unsub-confirm#E/>
+E' stato richiesto di cancellare
+
+!A
+
+dalla miling list <#l#>. Se sei d'accordo, per favore spedisci una 
+risposta vuota a questo indirizzo: 
+
+!R
+
+In genere ciò accade non appena schiacci il bottone "Rispondi". 
+Se non funziona, allora ti basta copiare l'indirizzo e incollarlo nel campo
+"A:" di un nuovo messaggio.
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Se non sei d'accordo ti basta ignorare questo messaggio.
+
+Grazie per il tuo aiuto!
+
+</text/sub-bad#E/>
+Spiacente, il tuo numero di conferma sembra essere non valido.
+
+La ragione più comune per i numeri non validi è la scadenza. Devo 
+ricevere conferma di ogni richiesta entro 10 giorni. Oppure
+assicurati che era incluso tutto il numero di conferma nella
+risposta che mi hai inviato.  Alcuni programmi di posta elettronica
+hanno l'abitudine di eliminare  qualcosa nell'indirizzo di risposta
+che può essere abbastanza lungo.
+
+Ho predisposto un altro numero di conferma. Per confermare che vuoi
+che
+
+!A
+
+venga aggiunto alla mailing list <#l#>, per favore spedisci una
+risposta vuota a questo indirizzo:
+
+!R
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Di nuovo, controlla l'indirizzo di risposta per assicurarti che sia tutto
+incluso prima di confermare la tua iscrizione.
+
+Spiacente per l'inconveniente.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+Per confermare che vuoi che
+
+!A
+
+venga iscritto alla mailing list <#l#>, per favore invia una risposta vuota a
+questo indirizzo:
+
+!R
+
+In genere ciò accade non appena schiacci il bottone "Rispondi". 
+Se non funziona, allora ti basta copiare l'indirizzo e incollarlo nel campo
+"A:" di un nuovo messaggio.
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Questa conferma è necessaria per due motivi. Il primo è che verifica che io
+sia in grado  di ricevere la posta da te. Il secondo motivo è che ti protegge 
+nel caso qualcuno stia tentando di fare un'iscrizione a nome tuo.
+
+</#qE/>
+Alcuni programmi di posta sono difettosi e non sono in grado di gestire
+indirizzi molto lunghi. Se non riesci a rispondere a questa richiesta
+spedisci un messaggio a <<#L#>-request@<#H#>> e metti l'indirizzo
+intero indicato sopra nel campo "Oggetto:".
+
+</#sE/>
+Questa mailing list è moderata. Una volta spedita questa conferma la richiesta
+verrà spedita al/i moderatore/i della lista. Ti farò sapere quando la tua
+iscrizione sarà accettata.
+
+</text/sub-nop#E/>
+Ho delle difficoltà a soddisfare la tua richiesta: l'indirizzo
+
+!A
+
+è già iscritto nella mailing list <#l#> quando ho ricevuto la tua
+richiesta e rimane iscritto.
+
+</text/sub-ok#E/>
+Conferma: ho aggiunto l'indirizzo
+
+!A
+
+alla mailing list <#l#> .
+
+Benvenuto su <#l#>@<#H#>!
+
+Per favore salva questo messaggio in modo tale da sapere con quale
+indirizzo ti sei iscritto nel caso tu voglia successivamente cancellarti o
+modificare il tuo indirizzo di iscrizione.
+
+Per cancellare l'scrizione scrivi a:
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Ciao! Sono il programma ezmlm. Mi occupo della 
+mailing list <#l#>@<#H#> .
+
+Sto lavorando per il mio responsabile, che può essere contattato presso
+at <#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+Spiacente, ma questo numero di conferma sembra essere non
+valido.
+
+La ragione più comune per i numeri non validi è la scadenza. Devo ricevere
+conferma di ogni richiesta entro 10 giorni. Oppure assicurati che era incluso
+tutto il numero di conferma nella risposta che mi hai inviato. 
+Alcuni programmi di posta elettronica hanno l'abitudine di eliminare qualcosa
+nell'indirizzo di risposta che può essere abbastanza lungo.
+
+Ho predisposto un altro numero di conferma. Per confermare che vuoi che
+
+!A
+
+venga rimosso dalla mailing list <#l#>, per favore manda una risposta vuota
+all'indirizzo:
+
+!R
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Di nuovo, controlla l'indirizzo di risposta per assicurarti che sia tutto
+incluso prima di confermare la tua iscrizione.
+
+Spiacente per l'inconveniente.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+Per confermare che vuoi che
+
+!A
+
+venga rimosso dalla mailing list <#l#>, per favore invia una risposta vuota a
+questo indirizzo:
+
+!R
+
+In genere ciò accade non appena schiacci il bottone "Rispondi". 
+Se non funziona, allora ti basta copiare l'indirizzo e incollarlo nel campo
+"A:" di un nuovo messaggio.
+</#xE/>
+
+oppure clicca qui:
+       mailto:<#R#>
+</#E/>
+
+Non ho controllato che il tuo indirizzo sia al momento nella mailing list.
+Per vedere quale indirizzo hai usato per iscriverti, guarda ai messaggi che
+stai ricevendo dalla mailing list. Ciascun messaggio ha il tuo indirizzo
+nascosto nel campo di ritorno; per esempio, mary@xdd.ff.com riceve i messaggi
+con il campo di ritorno:<<#l#>-return-<numero>-mary=xdd.ff.com@<#H#>.
+
+</#qE/>
+Alcuni programmi di posta sono difettosi e non sono in grado di gestire
+indirizzi molto lunghi. Se non riesci a rispondere a questa richiesta
+spedisci un messaggio a <<#L#>-request@<#H#>> e metti l'indirizzo
+intero indicato sopra nel campo "Oggetto:".
+
+</text/unsub-nop#E/>
+Mi dispiace, ma non sono in grado di soddisfare la tua richiesta,
+visto che l'indirizzo
+
+!A
+
+non è nella mailing list <#l#> quando ho ricevuto la tua
+richiesta e non è iscritto a questa mailing list.
+
+Se ti sei cancellato, ma continui a ricevere i messaggi, allora ti sei
+iscritto con un altro indirizzo diverso da quello che usi al momento. per
+favore cerca nell'intestazione:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+Ciò indica che l'indirizzo usato per l'iscrizione è``user@host.dom''.
+L'indirizzo per cancellarsi per questo utente sarà:
+'<#l#>-unsubscribe-utente=host.dominnio@<#H#>'.
+Basta scrivere a questo indirizzo, sostituendo ai valori utente=host.dominio
+quelli corretti.
+
+Se il messaggio ha un'intestazione con ``List-Unsubscribe:'' puoi
+spedire un messaggio all'indirizzo in quell'intestazione. Esso
+contiene l'indirizzo di iscrizione già codificato al suo interno.
+
+Per alcuni programmi di posta devi rendere le intestazioni visibili per
+leggere il percorso di ritorno:
+
+Con Eudora 4.0, clicca sul bottone "Blah blah ..." .
+Con PMMail, clicca su "Finestra->Mostra l'intero messaggio/intestazione". 
+
+Se tutto ciò ancora non funziona, mi dispiace dirti che non posso aiutarti.
+Per favore INOLTRA un messaggio della lista con una nota nella quale spieghi
+cosa stai cercando di ottenere insieme a un elenco di indirizzi dai quali ti
+potresti essere iscritto al mio responsabile: 
+    <#l#>-owner@<#H#>
+
+che se ne occuperà lui. Il mio responsabile è un po' più lento di quello che
+sono io, così per favore sii paziente.
+</text/unsub-ok#E/>
+Conferma: ho cancellato l'indirizzo
+
+!A
+
+dalla mailing list <#l#> . Questo indirizzo non è più iscritto.
+
+</text/edit-do#nE/>
+Per favore modifica i seguenti file di testo e inviali all'indirizzo:
+
+!R
+
+Il tuo programma di posta dovrebbe avere un'opzione di Rispondi che utilizzi
+questo indirizzo automaticamente.
+
+Posso rimouvere i segni di citazione che il tuo programma aggiunge al testo, a
+meno che tu non modifichi le linee citate stesse.
+
+Le linee segnate sono quelle che iniziano con '%%%'. Esse non devono essere
+modificate (caratteri aggiuntivi aggiunti dal tuo programma di posta
+all'inizio della linea sono tollerati).
+
+
+</text/edit-list#nE/>
+Il comando <#L#>-edit.file può essere usato da un amministratore remoto per
+modificare il file di testo che costituiscono il corpo delle risposte dalla
+mailing list <#L#>@<#H#> .
+
+Quello che segue è una lista dei nomi dei file delle risposte e una breve
+descrizione di quando è utilizzato il loro contenuto. Per modificare un file,
+spedisci semplicemente una e-mail a <#L#>-edit.file, sostituendo 'file' con il
+nome del file. Le istruzioni di modifica sono inviate con il file.
+
+File                Utilizzo
+
+bottom        la fine di tutte le risposte. informazioni generali sui comandi
+digest        sezione "amministrativa" per le raccolte. 
+faq           domande più frequenti relative alla lista.
+get_bad       al posto dei messaggi non trovati nell'archivio.
+help          aiuto generico (tra l'inizio e la fine).
+info          informazioni sulla lista.
+mod_help      aiuto specifico per i moderatori.
+mod_reject    al mittente dei messaggi rifiutati.
+mod_request   ai moderatori insieme con il messaggio.
+mod_sub       agli iscritti dopo che il moderatore ha confermato l'iscrizione.
+mod_sub_confirm  ai moderatori per avere conferma delle iscrizioni.
+mod_timeout   al mittente del messaggio scaduto. 
+mod_unsub_confirm  all'amministratore remoto per chiedere conferma di cancellazione
+sub_bad        all'iscritto se la richiesta di iscrizione è sbagliata.
+sub_confirm   all'iscritto per chiedere conferma dell'iscrizione.
+sub_nop       all'iscritto dopo una re-iscrizione.
+sub_ok        all'iscritto dopo che è stata accettata l'iscrizione.
+top           l'inizio di tutte le risposte.
+</#tnE/>
+trailer       aggiunto ai messaggi spediti fuori dalla lista
+</#nE/>
+unsub_bad     all'iscritto se la conferma di cancellazione è sbagliata.
+unsub_confirm all'iscritto per chiedere conferma di cancellazione.
+unsub_nop     al non-iscritto dopo la cancellazione.
+unsub_ok      all'ex iscritto dopo l'avvenuta cancellazione.
+
+</text/edit-done#nE/>
+Il file di testo è stato aggiornato correttamente.
+</text/info#E/>
+Non sono state fornite informazioni per questa lista.
+</text/faq#E/>
+FAQ - Frequently asked questions per la lista <#l#>@<#H#> .
+
+Non ancora disponibili.
diff --git a/ezmlmrc.jp b/ezmlmrc.jp
new file mode 100644 (file)
index 0000000..a275392
--- /dev/null
@@ -0,0 +1,1334 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.jp,v 1.28 1999/12/22 04:02:15 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc.jp - Translated: Masashi Fujita <objectx@bandit.co.jp>
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#       </filename/>       : put succeeding text lines in DIR/filename
+#       </-filename/>      : erase DIR/filename.
+#       </+dirname/>       : create directory DIR/dirname
+#       </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#>
+For additional commands, e-mail: <#L#>-help@<#H#>
+</text/bottom#E/>
+
+--- mailing list <#l#> \e$B$GMxMQ2DG=$J\e(B command \e$B0lMw$G$9\e(B ---
+
+ezmlm \e$B$O0J2<$N\e(B command \e$B$r<+F0$G<B9T$7$^$9!#\e(B
+
+[[[ \e$B@dBP$K\e(B mailing list \e$BK\BN$K\e(B command \e$B$rAw$i$J$$$G2<$5$$\e(B ]]]
+
+command \e$B$O0J2<$N\e(B address \e$B08$K6u$N\e(B message \e$B$rAw$k$3$H$G<B9T$5$l$^$9!#\e(B
+
+   * \e$BMxMQ2DG=$J\e(B command \e$B0lMw$r<h$j=P$9\e(B
+     <<#L#>-help@<#H#>>
+     (Get help and commands)
+
+   * \e$B9XFI$r3+;O$9$k\e(B
+     <<#L#>-subscribe@<#H#>>
+     (Start subscription) 
+
+\e$B9XFI$rCf;_$9$k$K$O\e(B mailing list <#L#> \e$B$+$i$N\e(B message \e$B$N\e(B header \e$B$K\e(B
+\e$B4^$^$l$F$$$k\e(B ``List-Unsubscribe'' \e$B9T$,<($9\e(B address \e$B$K6u\e(B message
+\e$B$rAw$C$F$/$@$5$$!#$^$?$O0J2<$N\e(B address \e$B08$F$K6u\e(B message \e$B$rAw$C$F\e(B
+\e$B2<$5$$!#\e(B
+     <<#L#>-unsubscribe@<#H#>>
+     (Stop subscription)
+
+</#dE/>
+digest \e$B$N9XFI$rCf;_$9$k$K$O0J2<$N\e(B address \e$B08$F$K6u$N\e(B message \e$B$r\e(B
+\e$BAw$C$F2<$5$$!#\e(B
+     <<#L#>-digest-unsubscribe@<#H#>>
+     (Stop digest subscription)
+
+</#E/>
+\e$B9XFI$N3+;O$*$h$SCf;_$N:]$K$O\e(B ezmlm \e$B$O3NG'$N0Y$N\e(B message \e$B$r\e(B
+\e$B;XDj$5$l$?\e(B address \e$B08$F$KAw?.$7$^$9!#$=$N3NG'$N0Y$N\e(B message
+\e$B$KBP$7$F!"\e(Breply \e$B$rJV$9$3$H$G3NG'$N<jB3$-$O=*N;$7$^$9!#\e(B
+
+\e$B0J>e$N;X<($K=>$C$F$b!"K>$s$@7k2L$K$J$i$J$$>l9gEy$O!"\e(B
+mailing list <#L#> \e$B$N<g:K<T$N\e(B
+<#L#>-owner@<#H#> \e$BKxO"Mm$7$F2<$5$$!#\e(B
+\e$B!JJV;v$,CY$l$k$+$b$7$l$^$;$s!#$4N;>52<$5$$!K\e(B
+
+\e$BLdBj$N2r@O$r?J$a$d$9$/$9$k0Y$K\e(B ezmlm \e$B$+$iAw$i$l$F$-$?\e(B message \e$B$r\e(B
+\e$B!XA4$F$N\e(B header \e$B$r4^$a$F!YE:IU$7$F$/$@$5$$!#\e(B
+
+--- \e$B0J2<$KAw$i$l$F$-$?\e(B message \e$B$rE:IU$7$F$*$-$^$9\e(B ---
+
+</text/bounce-bottom#E/>
+
+--- \e$B0J2<$KJVAw$5$l$F$-$?\e(B message \e$B$rE:IU$7$F$*$-$^$9\e(B ---
+
+</text/bounce-num#E/>
+
+mailing list <#L#> \e$B$,5.J}08$KAw$C$?\e(B message \e$B$NFb\e(B
+\e$BG[Aw$K<:GT$7$?$b$N$NHV9f$rE:IU$7$F$*$-$^$9!#\e(B
+
+</#aE/>
+message \e$B$O\e(B archive \e$BCf$KJ]B8$5$l$F$$$^$9!#\e(B
+
+</#aE/>
+\e$B6u$N\e(B message \e$B$r0J2<$N\e(B command address \e$B$KAw$k$3$H$G!"5.J}$,<u$1<h$l\e(B
+\e$B$J$+$C$?\e(B message \e$B$r\e(B archive \e$BFb$+$i<h$j=P$9$3$H$,=PMh$^$9!#\e(B
+
+\e$BNc!K\e(B
+   * 123 \e$BHV$+$i\e(B 145 \e$BHVKx$N\e(B message \e$B$r<h$j=P$9\e(B
+     <<#L#>-get.123_145@<#H#>>
+     \e$B!J0lEY$K<h$j=P$;$k$N$O:GBg$G\e(B 100\e$BDL$G$9!K\e(B
+
+   * \e$B:G?7\e(B 100\e$BDL$NEj9F<T$H\e(B Subject: \e$B9T$r<h$j=P$9\e(B
+     <<#L#>-index@<#H#>>
+
+</#E/>
+\e$BG[Aw$K<:GT$7$?\e(B message \e$B$NHV9f$O0J2<$NDL$j$G$9\e(B:
+
+</text/dig-bounce-num#E/>
+
+\e$BG[Aw$K<:GT$7$?\e(B mailing list <#L#> \e$B$N\e(B digest \e$BHG$K\e(B
+\e$B4^$^$l$F$$$?:G=i$N\e(B message \e$BHV9f$rE:IU$7$F$*$-$^$9!#\e(B
+
+</#aE/>
+ezmlm \e$B$O\e(B digest \e$B<+BN$OJ]B8$7$F$$$^$;$s!#\e(B
+\e$B$G$9$,!"0J2<$N\e(B command address \e$B$K6u$N\e(B message \e$B$rAw$k;v$G\e(B
+mailing list <#L#> \e$BK\BN$N\e(B
+archive \e$B$+$i!"5.J}$,<u$1<h$l$J$+$C$?\e(B message \e$B72$r<h$j=P$9\e(B
+\e$B$3$H$,$G$-$^$9!#\e(B
+
+\e$BNc!K\e(B
+   * 123 \e$BHV$+$i\e(B 145 \e$BHVKx$N\e(B message \e$B$r<h$j=P$9\e(B
+     <<#L#>-get.123_145@<#H#>>
+     \e$B!J0lEY$K<h$j=P$;$k$N$O:GBg$G\e(B 100\e$BDL$G$9!K\e(B
+
+   * \e$B:G?7\e(B 100\e$BDL$NEj9F<T$H\e(B Subject: \e$B9T$r<h$j=P$9\e(B
+     <<#L#>-index@<#H#>>
+
+</#E/>
+--- \e$B0J2<$O\e(B digest \e$BHG$N3+;O\e(B message \e$BHV9f0lMw$G$9\e(B ---
+
+</text/bounce-probe#E/>
+
+\e$B5.J}08$K\e(B mailing list <#L#> \e$B$,Aw$C$?\e(B
+message \e$B$N4v$D$+$,G[Aw=PMh$:!"3NG'$N0Y$K\e(B ezmlm \e$B$,Aw?.$7$?\e(B
+message \e$B$bG[Aw$K<:GT$7$F$7$^$$$^$7$?!#\e(B
+
+\e$BG[Aw$K<:GT$7$FJVAw$5$l$F$-$?\e(B message \e$B$rE:IU$7$F$*$-$^$9!#\e(B
+
+\e$B$3$N\e(B message \e$B$O!"5.J}08$KG[Aw$,2DG=$+H]$+$rD4$Y$k$?$a$N$b$N$G$9!#\e(B
+\e$B$3$N\e(B message \e$B$bG[Aw$K<:GT$7$?>l9g$O!"\e(Bezmlm \e$B$O5.J}$N\e(B address \e$B$r\e(B
+mailing list <#L#>@<#H#> \e$B$+$i\e(B
+\e$B<+F0E*$K:o=|$7$^$9!#\e(B
+
+\e$B$b$&0lEY9XFI$r$7$?$$>l9g$O!"0J2<$N\e(B address
+
+        <<#L#>-subscribe@<#H#>>
+
+\e$B08$K6u$N\e(B message \e$B$rAw$C$F!"?75,$K9XFI$r$7$J$*$7$F2<$5$$!#\e(B
+
+</text/bounce-warn#E/>
+
+\e$B5.J}08$K\e(B mailing list <#L#> \e$B$,Aw$C$?\e(B message \e$B$N4v$D$+$G\e(B
+\e$BG[Aw$K<:GT$7$^$7$?!#\e(B
+
+\e$BG[Aw$K<:GT$7$?\e(B message \e$B$N:G=i$N0lDL$rE:IU$7$F$*$-$^$9!#\e(B
+
+\e$B$b$7$b$3$N\e(B message \e$B<+BN$bG[Aw$K<:GT$7$?>l9g$K$O\e(B
+ezmlm \e$B$O3NG'$N\e(B message \e$B$rAw$j$^$9!#$=$N\e(B message \e$B$bG[Aw$K<:GT$7$?>l9g\e(B
+\e$B5.J}$N\e(B address \e$B$O\e(B mailing list <#L#> \e$B$+$i\e(B
+\e$BL5>r7o$K:o=|$5$l$^$9!#\e(B
+
+</text/digest#dE/>
+digest \e$B$N9XFI$r4uK>$9$k>l9g$O!"6u$N\e(B message \e$B$r\e(B
+
+        <<#L#>-digest-subscribe@<#H#>>
+        (To subscribe to the digest)
+
+\e$B08$KAw$C$F2<$5$$!#\e(B
+
+digest \e$B$N9XFI$r$d$a$k>l9g$O!"6u$N\e(B message \e$B$r\e(B
+
+        <<#L#>-digest-unsubscribe@<#H#>>
+        (To unsubscribe from the digest)
+
+\e$B08$KAw$C$F2<$5$$!#\e(B
+
+mailing list <#L#> \e$B$X$N\e(B post \e$B$O\e(B
+
+        <<#L#>@<#H#>>
+        (To post to the list)
+
+\e$B08$K$*4j$$$7$^$9!#\e(B
+
+</text/get-bad#E/>
+\e$B?=$7LuM-$j$^$;$s$,!";XDj$5$l$?\e(B message \e$B$O\e(B archive \e$BCf$K\e(B
+\e$B$"$j$^$;$s$G$7$?!#\e(B
+
+</text/help#E/>
+\e$B$3$l$OHFMQ$N\e(B help message \e$B$G$9!#\e(B
+\e$B5.J}$N\e(B message \e$B$O\e(B ezmlm \e$B$N\e(B command \e$B$H$7$F$OG'<1$5$l$^$;$s$G$7$?!#\e(B
+
+\e$B0J2<$KMxMQ2DG=$J\e(B command address \e$B0J2<$NDL$j$G$9!'\e(B
+\e$B!J6u\e(B message \e$B$r;XDj$5$l$?\e(B command address \e$B$KAw?.$9$k$3$H$G<B9T$5$l$^$9!K\e(B
+
+   * mailing list <#l#> \e$B$N@bL@$r<h$j=P$7$^$9!#\e(B
+     <<#L#>-info@<#H#>>
+     (Get information) 
+   * mailing list <#l#> \e$B$N!X$h$/?R$M$i$l$k<ALd$H$=$NEz$(!Y$r<h$j=P$7$^$9!#\e(B
+     <<#L#>-faq@<#H#>>
+     (Get FAQ) 
+
+</#dE/>
+   * digest list <#L#>-digest \e$B$N9XFI$r3+;O$9$k\e(B
+     <<#L#>-digest-subscribe@<#H#>>
+     (Start digest subscription) 
+
+   * digest list <#L#>-digest \e$B$N9XFI$rCf;_$9$k\e(B
+     <<#L#>-digest-unsubscribe@<#H#>>
+     (Stop digest subscription) 
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+   * 123 \e$BHV$+$i\e(B 145 \e$BHVKx$N\e(B message \e$B$r<h$j=P$9\e(B
+     <<#L#>-get.123_145@<#H#>>
+     \e$B!J0lEY$K<h$j=P$;$k$N$O:GBg$G\e(B 100\e$BDL$G$9!K\e(B
+
+   * 123 \e$BHV$+$i\e(B 145 \e$BHVKx$N\e(B message \e$B$NAw?.<T$H\e(B Subject: \e$B$r<h$j=P$9\e(B
+     <<#L#>-index.123_456@<#H#>>
+
+   * message 12345 \e$BHV$N\e(B Subject: \e$B$HF1$8\e(B Subject: \e$B$r;}$D\e(B message \e$B$r\e(B
+     \e$B<h$j=P$9\e(B
+     <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+command address \e$B08$F$N\e(B message \e$B$O\e(B address \e$B$N$_$,I,MW$G$9!#Cf?H$O\e(B
+\e$B2?$,$"$C$F$bL5;k$5$l$^$9!#\e(B
+
+\e$BI,MW$G$"$l$PDL>o$H$O0[$J$k\e(B address \e$B$G\e(B mailing list <#L#> \e$B$+$i$N\e(B
+message \e$B$r<u$1<h$k$h$&$K=PMh$^$9!#\e(B
+
+\e$BNc!K\e(Bjohn@host.domain \e$B$G<u$1<h$kMM$K$9$k\e(B
+
+    \e$B<u$1<h$j\e(B address \e$B$r0J2<$NMM$KJQ49$7$F\e(B
+
+        john@host.domain
+                \e$B"-\e(B      \e$B!J\e(B'@' --> '='\e$B!K\e(B
+        john=host.domain
+                \e$B"-\e(B
+        <<#L#>-subscribe-john=host.domain@<#H#>>
+
+<#L#>-subscribe-john=host.domain@<#H#> \e$B08$F$K6u\e(B message \e$B$rAw$k$3$H$G\e(B
+john@host.domain \e$B$G$N9XFI$r3+;O$G$-$^$9!#\e(B
+
+\e$B$3$N>l9g!"9XFI$rCf;_$9$k$K$O\e(B <#L#>-unsubscribe-john=host.domain@<#H#>
+\e$B08$F$K6u\e(B message \e$B$rAw$C$F$/$@$5$$!#\e(B
+
+</text/mod-help#E/>
+--- \e$B4IM}<T$N3'MM$X\e(B ---
+
+mailing list <#L#>@<#H#> \e$B$N4IM}$K\e(B
+\e$B6(NO$7$F$$$?$@$-46<U$7$^$9!#\e(B
+
+ezmlm \e$B$N\e(B command \e$B$O!"B>$N\e(B mailing list program \e$B$H$O<c430[$J$C$F\e(B
+\e$B8+$($k$+$b$7$l$^$s$,!"\e(Bcommand \e$B$,D>46E*$G$"$j!";HMQ$,4JC1$@$H\e(B
+\e$B;W$($k$G$7$g$&!#\e(B
+
+\e$B0J2<$O\e(B mailing list \e$B$N4IM}<T$H$7$F$N:n6H$N$?$a$N<j0z$-$G$9!#\e(B
+
+Remote subscription
+-------------------
+\e$B4IM}<T$OG$0U$N\e(B address \e$B$r9XFI<T$K2C$($?$j30$7$?$j$9$k;v$,=PMh$^$9!#\e(B
+\e$BNc$($P\e(B "john@host.domain" \e$B$r9XFI<T$K2C$($k>l9g$O!"\e(B
+
+                john@host.domain
+                        \e$B"-\e(B
+                john=host.domain
+                        \e$B"-\e(B
+        <<#L#>-subscribe-john=host.domain@<#H#>>
+
+\e$B$NMM$K$7$F\e(B command address \e$B$r@8@.$7!"$=$N\e(B address \e$B$X\e(B
+\e$B6u$N\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+
+\e$B$^$?!"\e(Bjohn@host.domain \e$B$r9XFI<T$+$i30$9>l9g$O\e(B
+
+        <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+\e$B$X6u$N\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+
+</#dE/>
+digest list \e$B$K2C$($?$j!&30$7$?$j$9$k>l9g$bF1MM$K$7$F\e(B
+
+        <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+        <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+\e$B$NMM$K$J$j$^$9!#\e(B
+
+</#E/>
+message \e$B$NCf?H$OI,MW$"$j$^$;$s!#\e(Baddress \e$B$@$1$,=EMW$G$9!#\e(B
+
+</#rE/>
+ezmlm \e$B$O5.J}$K3NG'$N\e(B message \e$B$rAw$j$^$9!#$3$l$O\e(B request \e$B$,\e(B
+\e$BK\Ev$K5.J}$+$i$N$b$N$+$r3NG'$9$k$?$a$G$9!#Aw$i$l$?\e(B message \e$B$K\e(B
+reply \e$B$9$k;v$G<jB3$-$O40N;$7$^$9!#\e(B
+
+</#RE/>
+ezmlm \e$B$O\e(B user \e$B$KBP$7$F3NG'$N\e(B message \e$B$rAw$j$^$9!#\e(B
+\e$B>e5-$N>l9g$O\e(B <john@host.domain> \e$B08$K3NG'$N\e(B message \e$B$,Aw$i$l$k\e(B
+\e$B$3$H$K$J$j$^$9!#3NG'$N\e(B message \e$B$r<u$1<h$C$?\e(B user \e$B$O\e(B reply \e$B$r\e(B
+\e$B$9$k$3$H$G3NG'$,=*N;$7$^$9!#\e(B
+</#E/>
+
+\e$B$3$N3NG'$K$h$C$F!"Bh;0<T$K$h$k967b$r:$Fq$J$b$N$K$7$F$$$^$9!#\e(B
+
+\e$B$^$?!"\e(Bezmlm \e$B$O9XFI$N>uBV$,JQ2=$7$?$3$H$r\e(B user \e$B$KDLCN$7$^$9!#\e(B
+
+
+Subscription
+------------
+\e$B4IM}<T$K8B$i$:!"C/$G$b0J2<$N\e(B address \e$B08$K6u$N\e(B message \e$B$r\e(B
+\e$BAw$k;v$G9XFI$r3+;O$7$?$j!&=*N;$5$;$?$j=PMh$^$9!#\e(B
+
+        <<#L#>-subscribe@<#H#>>
+       (Start subscription)
+
+       <<#L#>-unsubscribe@<#H#>>
+       (Stop subscription)
+
+</#dE/>
+digest list \e$B$N9XFI3+;O!&=*N;$O0J2<$N\e(B command address \e$B$G$9!#\e(B
+
+        <<#L#>-digest-subscribe@<#H#>>
+       (Start digest subscription)
+
+       <<#L#>-digest-unsubscribe@<#H#>>
+       (Stop digest subscription)
+
+</#E/>
+\e$BH/?.<T$K$O3NG'$N\e(B message \e$B$,\e(B ezmlm \e$B$+$iAw$i$l$^$9!#\e(B
+
+</#sE/>
+\e$B$3$N\e(B mailing list \e$B$N9XFI3+;O!&C&B`$O4IM}<T$N4FFD2<$G9T$o$l$kMM\e(B
+\e$B@_Dj$5$l$F$$$^$9!#4IM}<T08$K3NG'$r=P$9A0$K\e(B ezmlm \e$B$O\e(B request \e$B$r\e(B
+\e$B=P$7$?H/?.<T$X3NG'$N\e(B message \e$B$rAw$j!"\e(Brequest \e$B$,K\J*$+H]$+$r3NG'\e(B
+\e$B$7$F$$$k$N$G!"$=$N\e(B request \e$B$,K\J*$G$"$k$H9M$($F$bBg>fIW$G$9!#\e(B
+
+request \e$B$,@5Ev$J$b$N$H;W$&$N$G$"$l$P!"\e(Bezmlm \e$B$+$iFO$$$?3NG'$N\e(B
+message \e$B$KBP$7$F\e(B reply \e$B$7$F2<$5$$!#@5Ev$G$J$$$H;W$&$N$G$"$l$P\e(B
+ezmlm \e$B$+$i$N\e(B message \e$B$rC1=c$KL5;k$7$F2<$5$$!#$=$7$F!"I,MW$J$i\e(B
+request \e$B$NH/?.<T$KO"Mm$7$F$_$F2<$5$$!#\e(B
+</#SE/>
+\e$B9XFI3+;O!&C&B`$O<+F0$G=hM}$5$l$^$9!#\e(B
+</#E/>
+
+\e$B$^$?!"\e(B
+
+        <<#L#>-subscribe-mary=host.domain@<#H#>>
+       (Start subscription as mary@host.domain)
+
+       <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+       (Stop subscription as mary@host.domain)
+
+\e$B$NMM$K$9$k;v$G!"H/?.85$H$O0[$J$k\e(B address\e$B!J$3$N>l9g$O\e(B mary@host.domain\e$B!K\e(B
+\e$B$G\e(B mailing list \e$B$+$i$N\e(B message \e$B$r<u$1<h$kMM$K$9$k;v$b=PMh$^$9!#\e(B
+\e$B3NG'$O\e(B mary@host.domain \e$B08$KH/9T$5$l!"$=$N\e(B message \e$B$KBP$7$F\e(B
+\e$B@5$7$$\e(B reply \e$B$,5"$C$F$-$?>l9g$N$_9XFI!&C&B`$OM-8z$K$J$j$^$9!#\e(B
+
+\e$B4IM}<T$N\e(B address \e$B$=$NB>$N>pJs$O9XFI<T$K$O0l@ZO"Mm$5$l$^$;$s!#\e(B
+\e$B!JL^O@!"5.J}$,D>@\\e(B mail \e$B$rAw$C$?>l9g$OJL$G$9!K\e(B
+
+</#rlE/>
+mailing list <#L#>@<#H#> \e$B$N9VFI<T0lMw$O\e(B
+\e$B0J2<$N\e(B address \e$B$+$iF@$i$l$^$9!#\e(B
+        <<#L#>-list@<#H#>>
+ezmlm \e$B$N\e(B log \e$B$O0J2<$N\e(B address \e$B$+$iF@$i$l$^$9!#\e(B
+        <<#L#>-log@<#H#>>
+
+</#rldE/>
+mailing list <#L#>@<#H#> \e$B$N\e(B digest \e$BHG$N9VFI<T0lMw$O\e(B
+\e$B0J2<$N\e(B address \e$B$+$iF@$i$l$^$9!#\e(B
+        <<#L#>-digest-list@<#H#>>
+digest \e$BHG$K4X$9$k\e(B log \e$B$O0J2<$N\e(B address \e$B$G$9!#\e(B
+        <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+ezmlm \e$B$,Aw$j=P$9\e(B message text \e$B$rJT=8$9$k$K$O!"0J2<$N\e(B command address:
+
+        <<#L#>-edit@<#H#>>
+
+\e$B08$K6u$N\e(B e-mail \e$B$rAw$C$F2<$5$$!#\e(B
+\e$B!JJT=82DG=$J\e(B message \e$B0lMw5Z$S!"JT=8J}K!$OJV?.$K4^$^$l$F$$$^$9!K\e(B
+
+</#mE/>
+Moderated posts
+---------------
+message \e$B$r?3::$9$kMM$K@_Dj$5$l$F$$$k>l9g$O!"\e(Bezmlm \e$B$O\e(B post \e$B$5$l$?\e(B
+message \e$B$r0lC6J]B8$7!"?3::<jB3$-$N@bL@$rIU$1$?$b$N$r4IM}<T08$K\e(B
+\e$BAw$j$^$9!#$=$N\e(B message \e$B$O\e(B "Subject: MODERATE for ..." \e$B$H$J$C$F\e(B
+\e$B$$$^$9!#\e(B
+
+post \e$B$rG'$a$k>l9g$O!"\e(Bezmlm \e$B$,\e(B "Reply-To:" \e$B$K@_Dj$7$?\e(B address
+\e$B08$K\e(B reply \e$B$r$7$F2<$5$$!#K\J8$N\e(B copy \e$B$OI,MW$"$j$^$;$s!#\e(B
+\e$B!J\e(Bezmlm \e$B$O\e(B reply \e$B$NCf?H$O0l@Z8+$F$$$^$;$s!K\e(B
+
+post \e$B$r5qH]$9$k>l9g$O!"\e(Bezmlm \e$B$,\e(B "From:" \e$B$K@_Dj$7$?\e(B address \e$B08$K\e(B
+reply \e$B$r$7$F2<$5$$!#DL>o\e(B Mail User Agent (MUA) \e$B$N\e(B 'reply-to-all'
+\e$B$N5!G=$r;H$C$F\e(B message \e$B$N=`Hw$r$7$?8e$K!"ITMW$J\e(B address \e$B$r:o$k\e(B
+\e$B$@$1$@$H;W$$$^$9!#5qH]$9$kM}M3Ey$r#38D$N\e(B'%'\e$B$G;O$^$k9T$N8e$KIU$1\e(B
+\e$B#38D$N\e(B'%' \e$B$GJD$8$k$3$H$GF1:-$9$k;v$,=PMh$^$9!#\e(B
+
+\e$B7+$jJV$7$^$9$,!"4IM}<T$N\e(B address \e$B$=$NB>$N>pJs$O\e(B ezmlm \e$B7PM3$G$O\e(B
+\e$BL@$i$+$K$5$l$^$;$s!#\e(B
+
+\e$BJ#?t$N4IM}<T$,$$$k>l9g!"\e(Bezmlm \e$B$O:G=i$K4IM}<T$+$iFO$$$?\e(B message
+\e$B$N$_$KH?1~$7$^$9!#5.J}$,\e(B post \e$B$rG'$a$k\e(B reply \e$B$r$7$?;~$K!"4{$K\e(B
+\e$BB>$N4IM}<T$,5qH]$r$7$F$$$?>l9g!"5Z$S$=$N5U$N>l9g$O\e(B ezmlm \e$B$O\e(B
+\e$B5.J}08$K\e(B message \e$B$rAw$j$^$9!#\e(B
+
+ezmlm \e$B$ODj$a$i$l$?4|8B!JDL>o$O\e(B 5\e$BF|!K0JFb$K?3::$N7k2L$r<u$1\e(B
+\e$B<h$l$J$$>l9g$K$O!"H/?.<T08$KM}M3$rF1:-$7$F\e(B message \e$B$rJVAw$7$^$9!#\e(B
+\e$B!JI,MW$H$"$l$P!"4|8B@Z$l$N\e(B message \e$B$rC1=c$K:o=|$9$kMM$K$b\e(B
+  \e$B@_Dj=PMh$^$9!K\e(B
+</#E/>
+
+Vacations
+---------
+\e$B0l;~E*$K0[$J$k\e(B address \e$B$G4IM}$N:n6H$r$7$?$$>l9g$O!"\e(B
+"Mailing-List: contact <#L#>-help@<#H#>; run by ezmlm" \e$B$d\e(B
+"Subject: MODERATE for <#L#>@<#H#>" \e$B$d\e(B
+"Subject: CONFIRM subscribe to <#L#>@<#H#>" \e$BEy$N\e(B
+\e$B4IM}$N0Y$N\e(B message \e$B$,K>$s$@\e(B address \e$B08$KFO$/MM$K@_Dj$9$l$P\e(B
+\e$B2DG=$G$9!#\e(B
+
+\e$B$^$?$OCN?M08$KAw$jD>$9MM$K$9$k$H$$$&<j$b$"$j$^$9!#\e(B
+\e$B!J$3$N>l9g$O;vA0$K<g:K<T$K3NG'$r$H$C$F2<$5$$!K\e(B
+
+\e$B5.J}$,4IM}$N:n6H$r<B9T=PMh$J$$4V$O!"<+F0$G>5G'$r9T$&$H$$$&$N$G\e(B
+\e$B$"$l$P!">e5-$N4IM}MQ\e(B message \e$B$KBP$7$FE,@Z$J1~Ez$r<+F0@8@.$9$k\e(B
+\e$BMM$K@_Dj$7$F2<$5$$!#\e(B
+
+</#rE/>
+\e$B9XFI3+;O!&=*N;$N:n6H$r4IM}<T$G$"$k5.J}$N$b$N$G$J$$\e(B address \e$B$+$i\e(B
+\e$B9T$C$?>l9g!"9XFI3+;O!&=*N;$NBP>]$K$J$C$?\e(B address \e$B08$K3NG'$N\e(B message
+\e$B$,FO$-$^$9!#$=$N8e$KA44IM}<T08$K3NG'$N\e(B message \e$B$,FO$-$^$9!#$3$l$O\e(B
+request \e$B$rH/9T$7$?$N$,5.J}<+?H$+H]$+$r\e(B ezmlm \e$B$,H=CG$9$k<jCJ$r;}$C$F\e(B
+\e$B$$$J$$0Y$G$9!#\e(B
+
+\e$B$3$N>l9g$O!"5.J}$NAw?.$7$?\e(B message \e$B$d\e(B address \e$B$,BP>]$H$J$C$?\e(B user
+\e$B08$KAw$i$l$k;v$r3P$($F$*$$$F2<$5$$!#\e(B
+
+</#E/>
+\e$B$*<j?t$r$*$+$1$7$^$9!#\e(B
+
+PS: \e$B2?$+ITL@$JE@Ey$,$"$j$^$7$?$i!"<g:K<T$N\e(B
+
+        <#L#>-owner@<#H#>
+
+    \e$B$KO"Mm$7$F2<$5$$!#\e(B
+
+</text/mod-reject#E/>
+\e$B?=$7LuM-$j$^$;$s$,!"5.J}$N\e(B post \e$B$7$?\e(B message \e$B$O4IM}<T$K$h$C$F\e(B
+\e$B5qH]$5$l$^$7$?!#4IM}<T$,2?$+\e(B comment \e$B$rIU$1$F$$$k>l9g$O\e(B
+\e$B0J2<$KE:IU$5$l$F$$$^$9!#\e(B
+</text/mod-request#E/>
+mailing list <#L#> \e$B$K\e(B
+\e$B0J2<$KE:IU$5$l$?\e(B message \e$B$,\e(B post \e$B$5$l$^$7$?!#\e(B
+post \e$B$rG'$a$k>l9g$O!"0J2<$N\e(B address
+
+!A
+
+\e$B$X\e(B reply \e$B$7$F2<$5$$!#\e(B
+
+\e$BDL>o$O\e(B Mail User Agent (MUA) \e$B$N\e(B reply \e$B$N5!G=$@$1$G==J,$JH&$G$9!#\e(B
+
+\e$B$&$^$/$$$+$J$$>l9g$O!"<jF0$G\e(B
+
+        To: <#A#>
+
+\e$B$rIU$1$F\e(B reply message \e$B$r:n@.$7$F2<$5$$!#\e(B
+
+</#xE/>
+
+MUA \e$B$K$h$C$F$O\e(B
+
+        mailto:<#A#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G=`Hw$,=PMh$k>l9g$b$"$k$G$7$g$&!#\e(B
+</#E/>
+
+post \e$B$rG'$a$J$$>l9g$O!"0J2<$N\e(B address
+
+!R
+
+\e$B08$K\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+
+MUA \e$B$K\e(B "reply-to-all" \e$B$N5!G=$,$"$k$N$J$i\e(B <#L#>-reject \e$B0J30$G\e(B
+\e$B;O$^$kB>$N\e(B address \e$B$r:o=|$9$k$N$,4JC1$G$7$g$&!#\e(B
+</#xE/>
+
+MUA \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G=`Hw$,=PMh$k>l9g$b$"$k$G$7$g$&!#\e(B
+</#E/>
+
+*** post \e$B$5$l$?\e(B message \e$BK\BN$O\e(B copy \e$B$9$kI,MW$O$"$j$^$;$s\e(B ***
+
+post \e$B$rG'$a$J$$>l9g$K!"2?$+\e(B comment \e$B$rIU$1$?$$$N$G$"$l$P\e(B
+\e$B0J2<$NMM$J\e(B marker line
+
+%%% Start comment
+%%% End comment
+
+\e$B$N4V$K\e(B comment \e$B$r=q$$$F2<$5$$!#\e(B
+
+--- \e$B0J2<$KAw$i$F$-$?\e(B message \e$B$rE:IU$7$F$*$-$^$9\e(B
+
+</text/mod-sub#E/>
+--- \e$B4IM}<T$,5.J}$N\e(B
+    mailing list <#L#>@<#H#> \e$B$G$N\e(B
+    \e$B9XFI$N>uBV$rJQ99$7$^$7$?!#\e(B
+
+\e$B$3$NJQ99$,K>$s$@$b$N$G$J$$>l9gEy$O!"$9$0$K\e(B
+
+        <#L#>-owner@<#H#>
+
+\e$BKxO"Mm$r2<$5$$!#\e(B
+
+mailing list <#L#> \e$B$N\e(B archive \e$B$K\e(B access \e$B$7$?$$>l9g$O\e(B
+
+        <#L#>-help@<#H#>
+
+\e$BKx!"6u$N\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+
+</text/mod-timeout#E/>
+\e$B?=$7LuM-$j$^$;$s!#\e(B
+mailing list <#L#> \e$B$N4IM}<T$,\e(B
+\e$B5.J}$N\e(B message \e$B$r?3::$9$kA0$K;~4V@Z$l$K$J$j$^$7$?!#\e(B
+
+\e$B$3$l$,\e(B error \e$B$@$H;W$&$N$G$"$l$P!"$b$&0lEY\e(B post \e$B$9$k$+\e(B
+\e$B4IM}<T$KD>@\AjCL$7$F$_$F2<$5$$!#\e(B
+
+--- \e$B5.J}$+$iAw$i$l$?\e(B message \e$B$rE:IU$7$F$*$-$^$9\e(B ---
+
+</text/mod-sub-confirm#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$N\e(B
+\e$B9XFI<T$H$7$F2C$($FM_$7$$;]$N\e(B request \e$B$,FO$-$^$7$?!#\e(B
+\e$B!J$3$N\e(B request \e$B$,9XFI4uK><TK\?M$+$i$N\e(B request \e$B$N>l9g$O!"\e(B
+  \e$BI,MW$J3NG'$O:Q$s$G$$$^$9!K\e(B
+
+\e$B9XFI$rG'$a$k>l9g$O!"6u$N\e(B message \e$B$r0J2<$N\e(B address
+
+!R
+
+\e$B$K\e(B reply \e$B$7$F2<$5$$!#\e(B
+
+\e$BDL>o$O\e(B Mail User Agent (MUA) \e$B$N\e(B reply \e$B$N5!G=$@$1$G==J,$JH&$G$9!#\e(B
+\e$B$=$l$,$&$^$/9T$+$J$$>l9g$O!"\e(B
+
+        To: <#R#>
+
+\e$B$r<jF0$G@_Dj$7$F\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+</#xE/>
+
+MUA \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G=`Hw$,=PMh$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$B9XFI$rG'$a$J$$>l9g$O!"$3$N\e(B message \e$B$rL5;k$7$F$/$@$5$$!#\e(B
+
+</text/mod-unsub-confirm#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$+$i\e(B
+\e$B30$9$N$G$"$l$P!"0J2<$N\e(B address
+
+!R
+
+\e$B08$K\e(B reply \e$B$7$F2<$5$$!#\e(B
+
+\e$BDL>o$O\e(B Mail User Agent (MUA) \e$B$N\e(B reply \e$B$N5!G=$@$1$G==J,$JH&$G$9!#\e(B
+\e$B$=$l$,$&$^$/9T$+$J$$>l9g$O!"\e(B
+
+        To: <#R#>
+
+\e$B$r<jF0$G@_Dj$7$F\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+</#xE/>
+
+MUA \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G=`Hw$,=PMh$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$BC&B`$rG'$a$J$$>l9g$O!"$3$N\e(B message \e$B$rL5;k$7$F2<$5$$!#\e(B
+
+</text/sub-bad#E/>
+\e$B3NG'$N0Y$N\e(B key \e$B$,IT@5$G$9!#\e(B
+
+\e$B4v$D$+$NM}M3$,9M$($i$l$^$9$,!"$b$C$H$bB?$$$N$,4|8B@Z$l$K\e(B
+\e$B$h$k$b$N$G$9!#3NG'$OLs\e(B 10\e$BF|0JFb$K9T$o$l$J$1$l$P$J$j$^$;$s!#\e(B
+\e$B$^$?!"\e(Be-mail \e$B$r07$&4D6-$K$h$C$F$O\e(B ezmlm \e$B$,;H$C$F$$$kD9$$\e(B
+address \e$B$r@Z$j5M$a$F$7$^$&;v$,$"$k$N$G!"A4$F$N\e(B address \e$B$,\e(B
+\e$B@5$7$/EA$o$C$F$$$k$+$I$&$+3NG'$7$F$_$F2<$5$$!#\e(B
+
+\e$B?7$7$$\e(B key \e$B$rMQ0U$7$^$7$?!"0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$K\e(B
+\e$B2C$($?$$>l9g$O!"6u$N\e(B message \e$B$r0J2<$N\e(B address
+
+!R
+
+\e$B$KAw$C$F2<$5$$!#\e(B
+</#xE/>
+
+Mail User Agent (MUA) \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G3NG'$N\e(B message \e$B$rAw$k=`Hw$b=PMh$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$B7+$jJV$9MM$G$9$,!"\e(Breply \e$B$N\e(B address \e$BA4$F$,@5$7$/<h$j9~$^$l$F\e(B
+\e$B$$$k$+!"Aw?.A0$K3NG'$7$F2<$5$$!#\e(B
+
+\e$B$b$7$&$^$/9T$+$J$$MM$J$i\e(B
+
+        <#L#>-Owner <<#L#>-owner@<#H#>>
+
+\e$B$KO"Mm$r2<$5$$!#\e(B
+
+</text/sub-confirm#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#>
+\e$B$K2C$($k;v$rG'$a$k>l9g$O!"6u$N\e(B message \e$B$r\e(B
+
+!R
+
+\e$B$KJV?.$7$F2<$5$$!#\e(B
+
+\e$BDL>o$O\e(B Mail User Agent (MUA) \e$B$N\e(B reply \e$B$N5!G=$r;H$&$@$1$G$7$g$&!#\e(B
+
+\e$B$=$l$G$&$^$/9T$+$J$$>l9g$O\e(B
+
+        To:<#R#>
+
+\e$B$H$7$F\e(B message \e$B$r:n@.$7$F2<$5$$!#\e(B
+</#xE/>
+
+MUA \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1=`Hw$,=PMh$k$b$N$b$"$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$B$3$N3NG'$K$O0J2<$NFs$D$N0UL#$,$"$j$^$9!#\e(B
+
+        * \e$B;XDj$5$l$?\e(B address \e$B$G\e(B message \e$B$,Aw?.=PMh$k$+H]$+\e(B
+        * \e$B5.J}$N\e(B address \e$B$r56$C$?\e(B request \e$B$rGS=|$9$k\e(B
+
+</#qE/>
+e-mail \e$B$r07$&4D6-$K$h$C$F$O!"\e(Bezmlm \e$B$,;H$&D9$$\e(B address \e$B$r\e(B
+\e$B$&$^$/07$($J$$;v$,$"$j$^$9!#$=$NMM$J>l9g$O0J2<$N\e(B address
+
+        <<#L#>-request@<#H#>>
+
+\e$B$K\e(B "Subject: <#R#>" \e$B$H$7$F\e(B
+message \e$B$rAw$C$F2<$5$$!#\e(B
+
+</#sE/>
+mailing list <#L#> \e$B$O\e(B moderated \e$B$J\e(B mailing list \e$B$G$9!#\e(B
+\e$B5.J}$,$3$N3NG'$rAw?.$9$k$H!"A4$F$N4IM}<T08$F$K5.J}$N9XFI$rG'$a$k$+H]$+\e(B
+\e$B$N3NG'$,FO$-$^$9!#4IM}<T$,9XFI$r>5G'$7$?8e!"5.J}08$F$K$=$N;]$NDLCN$,\e(B
+\e$BFO$/$O$:$G$9!#\e(B
+
+</text/sub-nop#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$O4{$K\e(B mailing list <#L#> \e$B$N\e(B
+\e$B9XFI<T$K$J$C$F$$$^$9!#\e(B
+
+</text/sub-ok#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$K2C$($^$7$?!#\e(B
+
+        -       -       -       -       -       -       -       -       -
+
+[[[ Welcome to <#L#>@<#H#>! ]]]
+
+\e$B8e$G3NG'$N$?$a$KI,MW$K$J$k;v$,$"$j$^$9$N$G!"$3$N\e(B message \e$B$O\e(B
+\e$BK:$l$:J]B8$7$F$*$$$F2<$5$$!#\e(B
+
+\e$B9XFI$rCf;_$9$k>l9g$O!"0J2<$N\e(B address \e$B08$F$K6u$N\e(B message \e$B$rAw$C$F2<$5$$\e(B
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+\e$B$3$s$K$A$O!#;d$O\e(B ezmlm
+
+mailing list <#L#>@<#H#> \e$B$r4IM}$7$F$$$^$9!#\e(B
+
+</#x/>
+\e$B$3$N\e(B mailing list \e$B$N<g:K<T$K$O\e(B
+
+        <#L#>-owner@<#H#>
+
+\e$B$GO"Mm$9$k$3$H$,=PMh$^$9!#\e(B
+
+</text/unsub-bad#E/>
+\e$BAw$i$l$F$-$?3NG'$N0Y$N\e(B key \e$B$,@5$7$/$"$j$^$;$s!#\e(B
+
+\e$B4v$D$+$NM}M3$,9M$($i$l$^$9$,!"$b$C$H$bB?$$$N$,4|8B@Z$l$K\e(B
+\e$B$h$k$b$N$G$9!#3NG'$OLs\e(B 10\e$BF|0JFb$K9T$o$l$J$1$l$P$J$j$^$;$s!#\e(B
+\e$B$^$?!"\e(Be-mail \e$B$r07$&4D6-$K$h$C$F$O\e(B ezmlm \e$B$,;H$C$F$$$kD9$$\e(B
+address \e$B$r@Z$j5M$a$F$7$^$&;v$,$"$k$N$G!"A4$F$N\e(B address \e$B$,\e(B
+\e$B@5$7$/EA$o$C$F$$$k$+$I$&$+3NG'$7$F$_$F2<$5$$!#\e(B
+
+\e$B?7$7$$\e(B key \e$B$rMQ0U$7$^$7$?!"0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$+$i\e(B
+\e$B30$7$?$$>l9g$O!"6u$N\e(B message \e$B$r0J2<$N\e(B address
+
+!R
+
+\e$B$KAw$C$F2<$5$$!#\e(B
+</#xE/>
+
+Mail User Agent (MUA) \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$9$k$@$1$G3NG'$N\e(B message \e$B$rAw$k=`Hw$b=PMh$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$B7+$jJV$9MM$G$9$,!"\e(Breply \e$B$N\e(B address \e$BA4$F$,@5$7$/<h$j9~$^$l$F\e(B
+\e$B$$$k$+!"Aw?.A0$K3NG'$7$F2<$5$$!#\e(B
+
+\e$B$b$7$&$^$/9T$+$J$$MM$J$i\e(B
+
+        <#L#>-Owner <<#L#>-owner@<#H#>>
+
+\e$B$KO"Mm$r2<$5$$!#\e(B
+
+</text/unsub-confirm#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$N\e(B
+\e$B9XFI<T$+$i30$7$?$$>l9g$O!"6u$N\e(B message \e$B$r0J2<$N\e(B address
+
+!R
+
+\e$BKxAw$C$F2<$5$$!#\e(B
+
+\e$BDL>o$O\e(B Mail User Agent (MUA) \e$B$N\e(B reply \e$B$N5!G=$r;H$($PBg>fIW$G$9!#\e(B
+
+\e$B$b$7!"$=$l$G$&$^$/9T$+$J$$>l9g$O!"\e(B
+
+        To: <#R#>
+
+\e$B$H$7$F\e(B message \e$B$r:n@.$7$F2<$5$$!#\e(B
+</#xE/>
+
+\e$B$^$?!"\e(BMail User Agent (MUA) \e$B$K$h$C$F$O\e(B
+
+        mailto:<#R#>
+
+\e$B$r\e(B click \e$B$7$F\e(B message \e$B$r:n@.$9$k;v$b=PMh$k$G$7$g$&!#\e(B
+</#E/>
+
+\e$B5.J}$N\e(B address \e$B$,9XFI<T$+H]$+$O\e(B check \e$B$7$F$$$^$;$s!#\e(B
+\e$B$I$N\e(B address \e$B$G9XFI$r$7$F$$$k$N$+$O!"\e(Bmailing list \e$B$+$i\e(B
+\e$BAw$i$l$F$/$k\e(B message \e$B$N\e(B "Return-Path:" \e$B$N=j$KKd$a9~$^$l$F\e(B
+\e$B$$$^$9!#Nc$($P!"\e(Bmary@xdd.ff.com \e$B$,9XFI$N\e(B address \e$B$J$i\e(B
+
+        Return-Path: <<#L#>-return-<number>-mary=xdd.ff.com@<#H#>>
+
+\e$B$H$$$&6q9g$$$G$9!#\e(B
+
+</#qE/>
+\e$B4D6-$K$h$C$F$O!"D9$$\e(B address \e$B$r$&$^$/07$($J$$>l9g$,M-$j$^$9!#\e(B
+\e$B$3$N\e(B message \e$B$K\e(B reply \e$B$r$&$^$/JV$;$J$$MM$J$i!"0J2<$N\e(B address
+
+        <<#L#>-request@<#H#>>
+
+\e$B$K\e(B "Subject: <#R#>" \e$B$rIU$1$FAw$C$F2<$5$$!#\e(B
+
+</text/unsub-nop#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$O\e(B mailing list <#L#> \e$B$N\e(B
+\e$B9XFI<T$G$O$"$j$^$;$s!#\e(B
+
+        -       -       -       -       -       -       -       -
+
+\e$B9XFI$r;_$a$?$K$b4X$o$i$:!"\e(Bmailing list <#L#>
+\e$B$+$i$N\e(B mail \e$B$,FO$/>l9g$O!"5.J}$,8=:_;H$C$F$$$k\e(B e-mail address \e$B$H$O\e(B
+\e$B0c$&\e(B address \e$B$G\e(B mailing list <#L#> \e$B$r\e(B
+\e$B9XFI$7$F$$$k$N$+$b$7$l$^$;$s!#\e(B
+
+hearder \e$B$N0J2<$NItJ,$K\e(B
+
+'Return-Path: <<#L#>-return-1234-user=host.dom@<#H#>>'
+
+\e$B5.J}$,$I$N\e(B address \e$B$G9XFI$r$7$F$$$k$N$+$,8=$l$F$$$^$9!#\e(B
+\e$B!J$3$N>l9g!"\e(Buser@host.dom \e$B$G9XFI$r$7$F$$$k$3$H$K$J$j$^$9!K\e(B
+
+address \e$B$rL@<($7$F9XFICf;_$N\e(B request \e$B$r=P$9>l9g$O!"0J2<$NMM$K\e(B
+
+        <<#L#>-unsubscribe-user=host.dom@<#H#>>
+
+'<#L#>-unsubscribe-' \e$B$N8e$m$K!"\e(Buser@host.dom \e$B$r\e(B user=host.dom \e$B$K\e(B
+\e$B=q$-49$($?J*$r7R$$$G2<$5$$!#\e(B
+
+\e$B4v$D$+$N\e(B Mail User Agent (MUA) \e$B$O!"\e(BReturn-Path \e$B$r8+$k$?$a$K$O\e(B
+\e$BFCJL$JA`:n$rI,MW$K$J$j$^$9!#\e(B
+
+        * Eudora 4.0 \e$B$@$H!X\e(BBlah blah ...\e$B!Y%\%?%s$r\e(B click \e$B$9$k\e(B
+        * PMMail \e$B$@$H\e(B Window menu \e$B$N!X\e(BShow entire message/header\e$B!Y\e(B
+          \e$B%\%?%s$r\e(B click \e$B$9$k\e(B
+
+        -       -       -       -       -       -       -       -
+
+address \e$B$rL@<($7$?9XFICf;_$b$&$^$/$$$+$J$$>l9g$O!"?=$7Lu$"$j$^$;$s$,\e(B
+
+        * \e$B5.J}$,2?$r$7$h$&$H$7$F<:GT$7$?$N$+\e(B
+        * ezmlm \e$B$+$i$N\e(B message
+        * \e$B9XFICf;_$r4uK>$9$k\e(B address
+
+\e$B$rE:IU$7$F!"\e(Bmailing list <#L#> \e$B$N\e(B owner \e$B$N\e(B
+
+    <#L#>-owner@<#H#>
+
+\e$BKxAw$C$F2<$5$$!#!JJV;v$K;~4V$,$+$+$k$+$b$7$l$^$;$s$,$4N;>52<$5$$!K\e(B
+
+</text/unsub-ok#E/>
+\e$B0J2<$N\e(B address
+
+!A
+
+\e$B$r\e(B mailing list <#L#> \e$B$N9XFI<T$+$i30$7$^$7$?!#\e(B
+
+</text/edit-do#nE/>
+\e$BE:IU$5$l$?\e(B message text \e$B$rJT=8$7$F!"0J2<$N\e(B address
+
+!R
+
+\e$B08$KJVAw$7$F2<$5$$!#\e(B
+
+\e$B!X\e(B%%%\e$B!Y$G;O$^$k9T$,\e(B message text \e$B3+;O$N\e(B marker line \e$B$K\e(B
+\e$B$J$C$F$$$^$9!#\e(B
+
+\e$B!J$3$N9T$K5.J}$N;H$C$F$$$k\e(B Mail User Agent (MUA) \e$B$G$N\e(B
+  \e$B0zMQ$N0u\e(B (ex. foo>%%%) \e$B$,IU2C$5$l$F$$$k>l9g$O!"\e(Bmessage text
+  \e$BK\BN$NItJ,$KIU$$$?0zMQ$N0u$O<+F0=|5n$5$l$^$9!K\e(B
+
+</text/edit-list#nE/>
+\e$B4IM}<T$O\e(B <#L#>-edit.FILE command \e$B$r;H$&$3$H$G\e(B ezmlm \e$B$,=PNO$9$k\e(B
+mailing list <#L#> \e$B$N0Y$N\e(B message text \e$B$rJT=8$9$k$3$H$,=PMh$^$9!#\e(B
+
+\e$B0J2<$OJT=82DG=$J\e(B FILE \e$B$H!"$=$NL\E*$G$9!#\e(Bfile FOO \e$B$rJT=8$7$?$$\e(B
+\e$B>l9g$O\e(B <#L#>-edit.FOO \e$B08$K6u$N\e(B message \e$B$rAw$C$F2<$5$$!#\e(B
+\e$BJT=8$N;EJ}$OAw?.$5$l$k\e(B message \e$B$K4^$^$l$F$$$^$9!#\e(B
+
+File                Use
+
+bottom              ezmlm \e$B$N\e(B command \e$B0lMw$G$9!#\e(B
+                    ezmlm \e$B$,JVAw$9$kA4$F$N\e(B message \e$B$KIU2C$5$l$^$9!#\e(B
+digest              digest \e$BHG$N0Y$N\e(B command \e$B$N@bL@$G$9!#\e(B
+faq                 mailing list <#L#> \e$B$G$N\e(B FAQ \e$B$G$9!#\e(B
+get_bad             archive \e$BCf$K;XDj$5$l$?\e(B message \e$B$r8+IU$1$i$l$J$+$C$?>l9g$K\e(B
+                    \e$BAw$i$l$^$9!#\e(B
+help                help message \e$B$G$9!J\e(B'top' \e$B$H\e(B 'bottom' \e$B$N4V$KF~$j$^$9!K\e(B
+info                mailing list <#L#> \e$B$N>pJs$G$9!#\e(B
+mod_help            \e$B4IM}<T8~$1$N\e(B help message \e$B$G$9!#\e(B
+mod_reject          \e$B4IM}<T$,<uM}$7$J$+$C$?\e(B post \e$B$NAw$j<g$KBP$7$FAw$i$l$^$9!#\e(B
+mod_request         moderated \e$B$J\e(B mailing list \e$B$KBP$7$F\e(B post \e$B$,$"$C$?>l9g\e(B
+                    \e$B4IM}<T$KAw$i$l$^$9!#\e(B
+mod_sub             \e$B9XFI4uK><T$KBP$7$F!"4IM}<T$,9XFI\e(B request \e$B$r<uM}$7$?;~$KAw$i$l$^$9!#\e(B
+mod_sub_confirm     \e$B4IM}<T$KBP$7$F9XFI\e(B request \e$B$N3NG'$N$?$aAw$i$l$^$9!#\e(B
+mod_timeout         \e$B4IM}<T$,<uM}$;$:;~4V@Z$l$K$J$C$?\e(B post \e$B$NAw?.<T$KAw$i$l$^$9!#\e(B
+mod_unsub_confirm   \e$B4IM}<T$KBP$7$F9XFICf;_$N3NG'$r<h$k>l9g$KAw$i$l$^$9!#\e(B
+sub_bad             \e$B9XFI4uK><T$+$i$N9XFI3NG'$N0Y$N1~Ez$,IT@5$J>l9g$KAw$i$l$^$9!#\e(B
+sub_confirm         \e$B9XFI4uK><T$KBP$7$F!"3NG'$N$?$a$KAw$i$l$^$9!#\e(B
+sub_nop             \e$B4{$K9XFI<T$K$J$C$F$$$k?M$,:F$S9XFI\e(B request \e$B$r=P$7$?>l9g$K\e(B
+                    \e$BAw$i$l$^$9!#\e(B
+sub_ok              \e$B9XFI$N<jB3$-$,=*N;$7$?8e$KAw$i$l$^$9!#\e(B
+top                 ezmlm \e$B$,Aw?.$9$kA4$F$N1~Ez$NF,$KIU$-$^$9!#\e(B
+</#tnE/>
+trailer             \e$B$3$N\e(B mailing list \e$B$KBP$9$kA4$F$N\e(B post \e$B$NKvHx$K\e(B
+                    \e$BIU$1B-$5$l$FAw$i$l$^$9!#\e(B
+</#nE/>
+unsub_bad           \e$B9XFI<T$+$i$N9XFICf;_3NG'$,IT@5$J>l9g$KAw$i$l$^$9!#\e(B
+unsub_confirm       \e$B9XFI<T$+$i$N9XFICf;_$N\e(B request \e$B$N3NG'$N$?$a$KAw$i$l$^$9!#\e(B
+unsub_nop           \e$B9XFI<T0J30$,9XFI$rCf;_$7$h$&$H$7$?;~$KAw$i$l$^$9!#\e(B
+unsub_ok            \e$B9XFI<T$+$i$N9XFICf;_$N\e(B request \e$B$,<uM}$5$l$?;~$KAw$i$l$^$9!#\e(B
+
+</text/edit-done#nE/>
+message text \e$B$N99?7$K@.8y$7$^$7$?!#\e(B
+
+</text/info#E/>
+--- mailing list <#L#>@<#H#> \e$B$K$D$$$F\e(B ---
+\e$B!J8=:_9);vCf$G$9!K\e(B
+</text/faq#E/>
+--- mailing list <#L#>@<#H#> \e$B$K4X$7$F!"$h$/?R$M$i$l$k<ALd$H$=$NEz$(\e(B ---
+\e$B!J8=:_9);vCf$G$9!K\e(B
+
diff --git a/ezmlmrc.pl b/ezmlmrc.pl
new file mode 100644 (file)
index 0000000..58df48a
--- /dev/null
@@ -0,0 +1,1106 @@
+#$Id: ezmlmrc.pl,v 1.19 1999/05/11 03:28:11 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# English ---> polish translation by Sergiusz Paw³owicz, 1998.
+# Translation (C) to Free Software Foundation, 1998.
+# Wszelkie uwagi dotycz±ce t³umaczenia proszê przesy³aæ na adres
+#                                        cheeze@hyperreal.art.pl
+# Troche opisow po polsku znajdziecie pod adresem
+#                        http://www.arch.pwr.wroc.pl/~ser/lists/
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+ISO-8859-2
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Przykro mi, ale nakazano mi odrzucaæ Twoje listy... Skontaktuj siê, proszê, z opiekunem listy, osi±galnym pod adresem: <#L#>-owner@<#H#>, je¿eli masz jakiekolwiek w±tpliwo¶ci co do tego stanu rzeczy (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Przykro mi, ale tylko prenumeratorzy mog± wysy³aæ pocztê na listê... Jesli jeste¶ pewna/pewien prenumerowania tej w³a¶nie listy, prze¶lij, proszê, kopiê tego listu opiekunowi: <#L#>-owner@<#H#>, aby dopisa³ on Twój nowy adres pocztowy (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+List-Post: <mailto:<#L#>@<#H#>>
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+Wypisanie?     wy¶lij list: <#L#>-unsubscribe@<#H#>
+Wiêcej pomocy? wy¶lij list: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Poni¿ej znajduj± siê komendy menad¿era list dyskusyjnych "ezmlm".
+
+Spe³niam komendy administracyjne automatycznie.
+Wy¶lij jedynie pusty list pod którykolwiek z tych adresów:
+
+   <<#L#>-subscribe@<#H#>>:
+   Zapisanie siê na listê o nazwie <#L#>.
+
+   <<#L#>-unsubscribe@<#H#>>:
+   Wypisanie siê z listy o nazwie <#L#>.
+
+Wy¶lij list pod nastêpuj±ce adresy, je¶li chcesz uzykaæ krótk± notkê
+informacyjn± o li¶cie dyskusyjnej lub jej FAQ (czyli 'najczê¶ciej
+zadawana pytania na temat listy wraz z odpowiedziami'):
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#d/>
+I odpowiadaj±ce powy¿szemu adresy, je¶li chodzi ci o przegl±d listy:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+   <<#L#>-get.12_45@<#H#>>:
+   Chêæ otrzymania kopii listów od nr 12 do 45 z archiwum.
+   Jednym listem mo¿esz otrzymaæ maksymalnie 100 listów.
+
+</text/bottom#aI/>
+   <<#L#>-get.12@<#H#>>:
+   Chêæ otrzymania kopii listu nr 12 z archiwum.
+</text/bottom#i/>
+   <<#L#>-index.123_456@<#H#>>:
+   Chêæ otrzymania tytu³ów listów od nr 123 do 456 z archiwum.
+   Tytu³y s± wysy³ane do Ciebie w paczkach po sto na jeden list.
+   Mo¿esz maksymalnie zamówiæ 2000 tytu³ów na jeden raz.
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+   <<#L#>-thread.12345@<#H#>>:
+   Chêæ otrzymania wszystkich kopii listów z tym samym tytu³em
+   jaki posiada list o numerze 12345.
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+
+NIE WYSY£AJ POLECEÑ ADMINISTRACYJNYCH NA LISTÊ DYSKUSYJN¡!
+Jesli to zrobisz, administrator listy ich nie zobaczy, natomiast
+wszyscy prenumeratorzy nie¼le siê na Ciebie wkurz± i zostaniesz
+uznany(a) za internetowego ¿ó³todzioba, z którym nie warto gadaæ.
+
+Aby okresliæ adres Bóg@niebo.prezydent.pl jako swój adres subskrybcyjny,
+wy¶lij list na adres:
+<<#L#>-subscribe-Bóg=niebo.prezydent.pl@<#H#>>.
+Wy¶lê Ci wtedy potwierdzenie na ten w³asnie adres; kiedy je otrzymasz,
+po prostu odpowiedz na nie, aby staæ siê prenumeratorem.
+
+</text/bottom#x/>
+Je¿eli instrukcje, których Ci udzieli³em, s± zbyt trudne, albo
+nie jeste¶ zadowolony z ich efektów, skontaktuj siê z opiekunem listy
+pod adresem <#L#>-owner@<#H#>. 
+Proszê byæ cierpliwym, opiekun listy jest o wiele wolniejszy
+od komputera, którym ja jestem ;-)
+</text/bottom/>
+
+--- Za³±cznik jest kopi± polecenia, które otrzyma³em.
+
+</text/bounce-bottom/>
+
+--- Za³±cznik jest kopi± odrzuconego listu, który dosta³em.
+
+</text/bounce-num/>
+
+Na wszelki wypadek przechowujê odrzucone listy z twojego adresu,
+wys³ane na listê o nazwie <#L#>. Aby dostaæ kopiê tych listów
+z archiuwm, np. listu o numerze 12345, wyslij pust± wiadomosæ
+na adres: <#L#>-get.12345@<#H#>.
+
+</#ia/>
+Aby zamówiæ listê tytu³ów i autorów stu ostatnich wiadomo¶ci,
+wy¶lij pusty list na adres: <#L#>-index@<#H#>.
+
+Aby dostaæ pêczek listów od 123 do 131 (maksymalnie 100 na jeden raz),
+wy¶lij pust± wiadomosæ na adres:
+<#L#>-get.123_145@<#H#>.
+
+<//>
+Poni¿ej znajduj± sie numery listów:
+
+</text/dig-bounce-num/>
+
+Trzymam indeks przesy³ek, które nie zosta³y prawid³owo dorêczone
+pod Twój adres z listy <#L#>-digest. Mam zachowany numer pierwszego
+listu ka¿dego przegl±du, z którym mia³e¶ k³opoty. Mo¿esz wiêc
+spróbowaæ dostaæ listy z archiwum g³ównego.
+
+Aby dostaæ list nr 12345 z archiwum, wy¶lij pusty list na
+adres: <#L#>-get.12345@<#H#>.
+
+</#ia/>
+Aby dostaæ listê tytu³ów i autorów ostatnich stu listów, wy¶lij
+pust± wiadomosc na adres: <#L#>-index@<#H#>.
+
+Aby dostaæ pêczek listów od numeru 123 do 145 (maksymalnie sto naraz)
+wy¶lij pust± wiadomosæ pod adres: <#L#>-get.123_145@<#H#>.
+
+<//>
+Poni¿ej znajdziesz numery przegl±dów listy:
+
+</text/bounce-probe/>
+
+Jeste¶ zapisany(a) na listê dyskusyjn± o nazwie <#l#>,
+niestety listy z niej nie mog± do Ciebie dotrzeæ, gdy¿ s± odrzucane
+przez twój serwer. Wys³a³em Ci ostrze¿enie o tym fakcie,
+ale i ono przepad³o... Nie miej wiêc do mnie ¿alu, je¶li
+zmuszony bêdê wykresliæ Ciê z listy prenumeratorów, a nast±pi
+to w przypadku, je¶li i ten list nie zostanie przyjêty przez Twój
+serwer pocztowy.
+
+</text/bounce-warn/>
+
+Poczta kierowana do Ciebie z listy <#l#> jest odrzucana przez Twój serwer.
+Za³±czam kopiê pierwszej przesy³ki, z dostarczeniem której mia³em k³opoty.
+
+Je¿eli niniejszy list ostrzegawczy równie¿ przepadnie, wy¶lê Ci
+przesy³kê testow±, której odbicie siê od Twojego adresu spowoduje
+trwa³e wypisanie z pocztowej listy dyskusyjnej.
+
+</text/digest#ia/>
+Aby zaprenumerowaæ przegl±d listy, napisz pod adres:
+       <#L#>-digest-subscribe@<#H#>
+
+Aby wykre¶liæ swoój adres pocztowy z listy subskrybentów, napisz pod adres:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Aby wys³aæ cokolwiek na listê, pisz pod adres:
+       <#L#>@<#H#>
+
+</#iax/>
+       Opiekun listy pocztowej - 
+        - <<#L#>-owner@<#H#>>
+
+</text/get-bad/>
+Przykro mi, tego listu nie ma w archiwum.
+
+</text/help/>
+Niestety nie poda³e¶ prawid³owego adresu prenumeraty.
+List, który otrzyma³e¶, jest niczym innym, jak standardow± instrukcj±
+obs³ugi menad¿era list dyskusyjnych zainstalowanego na naszym serwerze.
+Mam nadziejê, ¿e teraz ju¿ sobie poradzisz.
+
+</text/mod-help/>
+Dziêkujê za zgodê na zostanie moderatorem listy o adresie:
+<#L#>@<#H#>.
+
+Moje komendy s± nieco inne, ni¿ bywaj± w programach obs³uguj±cych
+pocztowe listy dyskusyjne. Mo¿esz nawet na pocz±tku stwierdziæ, ¿e s±
+niezwyk³e, ale jak tylko zaczniesz ich u¿ywaæ, docenisz prostotê systemu
+oraz szybko¶æ, z jak± obs³ugujê twoje ¿yczenia.
+
+Poni¿ej kilka s³ów o tym, jak dzia³a moderowanie: 
+
+Zdalne wpisanie na listê prenumeratorów
+---------------------------------------
+Bêd±c moderatorem, mo¿esz zapisaæ lub wypisaæ internautê
+o adresie janek@komputer-janka.domena poprzez wys³anie listu na adres:
+
+<#L#>-subscribe-janek=komputer-janka.domena@<#H#>
+<#L#>-unsubscribe-janek=komputer-janka.domena@<#H#>
+
+</#g/>
+Odpowiednio dla przegl±du listy:
+
+<#L#>-digest-subscribe-janek=komputer-janka.domena@<#H#>
+<#L#>-digest-unsubscribe-janek=komputer-janka.domena@<#H#>
+
+<//>
+To wszystko. Nie musisz nadawaæ listowi tytu³u, nie musisz
+równie¿ pisaæ nic w jego tre¶ci!
+
+</#r/>
+Wy¶lê Ci pro¶bê o potwierdzenie 
+Co zrobiæ z moim listem?
+Po prostu odpowiedz na niego i gotowe.
+</#R/>
+Wy¶lê pro¶bê o potwierdzenie chêci uczestnictwa na adres
+autora listu.
+Wystarczy, ze na te pro¶be odpowie, a bedzie zapisany.
+<//>
+
+Zawiadomiê subskrybenta, je¿eli jego/jej dane dotyczace
+jego subskrybcji zostan± zmienione.
+
+Prenumerata
+-----------
+
+Ka¿dy mo¿e zapisaæ siê na listê, albo z niej wypisaæ, poprzez
+wys³anie listu na adres:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#g/>
+Obs³uga przegl±du listy:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+Chêtny otrzyma pro¶be o potwierdzenie ¿yczenia wypisania siê z listy,
+aby siê upewniæ czy ¿yczenie to zosta³o rzeczywiscie przez niego
+wys³ane. Je¿eli zostanie to potwierdzone, zostanie usuniêty 
+z listy prenumeratorów.
+Podobna procedura obowi±zuje podczas zapisywania siê na listê.
+
+</#s/>
+Podczas procedury zapisywania siê na listê, pro¶ba
+o potwierdzenie zapisu jest wysy³ana równie¿ do moderatora listy.
+Pozytywna odpowied¼ moderatora dope³ni zapisu na listê.
+</#S/>
+Zapisy funkcjonuj± w ten sam sposób.
+<//>
+
+U¿ytkownik mo¿e równie¿ u¿ywaæ adresów:
+
+<#L#>-subscribe-janek=komputer-janka.domena@<#H#>
+<#L#>-unsubscribe-janek=komputer-janka.domena@<#H#>
+
+aby poczta z listy wêdrowa³a na inny adres bed±cy jego w³asno¶ci±.
+Tylko wówczas, kiedy u¿ytkownik dostaje listy na adres
+janek@komputer-janka.domena, bêdzie w stanie odpowiedzieæ
+na ¿yczenie potwierdzenia skierowanego od menad¿era listy.
+
+Wszystkie powy¿sze kroki s± przedsiêbrane po to, by unikaæ
+z³o¶liwo¶ci typu zapisanie kogo¶ wbrew jego woli na listê
+oraz aby moderator móg³ byæ pewnym, ¿e adres prenumeratora
+rzeczywi¶cie istnieje.
+
+Twój rzeczywisty adres pocztowy nie bêdzie ujawniony prenumaratorowi.
+Pozwoli to zachowaæ Ci anonimowo¶æ.
+
+</#rl/>
+Aby uzyskaæ listê prenumeratorów <#L#>@<#H#>, 
+wy¶lij list na adres:
+   <<#L#>-list@<#H#>>
+
+Chc±c uzyskaæ dziennik pok³adowy listy <#L#>@<#H#>,
+wy¶lij list na adres:
+   <<#L#>-list@<#H#>>
+
+</#rld/>
+Adresy w³a¶ciwe dla przegl±du listy:
+   <<#L#>-digest-list@<#H#>>
+i:
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Mo¿esz zdalnie zmieniaæ pliki tekstowe, którymi pos³uguje siê automat
+podczas obs³ugi listy dyskusyjnej. Aby uzyskaæ zbiór plików oraz
+instrukcje, jak je zmieniaæ, napisz pod adres:
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+Przesy³ki moderowane
+--------------------
+Je¿eli przesy³ki podlegaj± moderowaniu, umieszczam wys³ane listy
+w kolejce pocztowej i wysy³am ¿yczenie przyjrzenia sie listowi do
+moderatora.
+
+Wystarczy, aby¶ odpowiedzia³ na adres zwrotny tego listu, u¿ywaj±c
+funkcji "odpowiedz (reply)", aby zaakceptowaæ tre¶æ listu. 
+
+Je¿eli natomiast chcesz odmówiæ zgody na wys³anie listu, wy¶lij
+pocztê na adres wziêty z nag³ówka "From:" (mo¿na zwykle tego
+dokonaæ poprzez u¿ycie opcji "reply-to-all/odpowiedz-na-wszystkie-
+-adresy" i skasowanie z tej listy w³asnego adresu oraz adresu 
+akceptuj±cego). Mo¿esz równie¿ dodaæ jak±¶ notkê do wysy³aj±cego
+odrzucony przez Ciebie list, aby wyt³umaczyæ mu, dlaczego to
+uczyni³e¶. Notkê dodajesz umieszczaj±c j± w tre¶ci powy¿szego listu
+odrzucaj±cego, wstawiaj±c j± pomiêdzy dwie linie, zawieraj±ce
+trzy znaki '%'.
+
+Wezmê pod uwagê pierwszy list, który od Ciebie dostanê.
+Je¿eli wy¶lesz najpierw potwierdzenie akceptacji listu, który
+wcze¶niej odrzuci³e¶, lub odwrotnie, oczywi¶cie Ci o tym powiem.
+
+Je¿eli nie dostanê odpowiedzi od moderatora przez okre¶lony czas,
+zwykle jest to piêæ dni, zwrócê list nadawcy z opisem zaistnia³ej
+sytuacji.
+<//>
+
+Wakacje
+-------
+Je¿eli korzystasz tymczasowo z innego adresu, po prostu przekieruj
+wszystkie listy z nag³ówkiem 'Mailing-List:',
+albo te, których tematy zaczynaj± siê s³owami
+"MODERATE for <#L#>@<#H#>",
+lub
+"CONFIRM subscribe to <#L#>@<#H#>",
+na nowy adres.
+Mo¿esz wtedy moderowaæ z nowego adresu. Innym sposobem jest
+przekierowanie tych listów do przyjaciela, który mo¿e Ciê zast±piæ.
+Musisz oczywi¶cie uzgodniæ przedtem wszystko z opiekunem listy.
+
+Je¿eli chcesz automatycznie aprobowaæ wszelkie przesy³ki kierowane
+na listê, skonfiguruj swój program pocztowy tak, aby automatycznie
+odpowiada³ na listy maj±ce tematy zgodne z powy¿szymi kryteriami.
+
+</#r/>
+Uwa¿aj, je¿eli bêdziesz próbowa³ zdalnie zarz±dzaæ list± z adresu,
+który nie jest wpisany jako adres administratora, prenumerator,
+a nie Ty, zostanie poproszony o potwierdzenie, które zostanie
+potem przekazane do moderatorów.
+Robiê tak, gdy¿ nie ma sposobu upewniæ siê czy to rzeczywi¶cie Ty
+kryjesz siê za poczt± przychodz±c± z nieznanego adresu.
+
+Pamiêtaj, ¿e w powy¿szym wypadku Twoje ¿ycznie skierowane do serwera
+i równie¿ Twój adres s± przesy³ane do prenumeratora! Przestajesz byæ
+wówczas anonimowy.
+<//>
+
+Powodzenia!
+
+PS: Skontaktuj siê, proszê, z opiekunem listy pod adresem
+<#L#>-owner@<#H#>
+je¿eli masz jakie¶ pytania, lub napotkasz na problemy.
+
+</text/mod-reject/>
+Przykro mi, ale Twój list nie zosta³ zaakceptowany przez moderatora.
+Je¿eli moderator uczyni³ jakie¶ uwagi, zamieszczam je poni¿ej.
+</text/mod-request/>
+Proszê o decyzjê czy b±d±c moderatorem zgadzasz siê na wys³anie
+za³±czonej przesy³ki na listê o nazwie <#L#>.
+
+Aby zgodziæ siê na natychmiastowe wys³anie listu do wszystkich
+prenumeratorów, wy¶lij, proszê, list na adres:
+
+# This does the default !A for normal setups, but puts in a 'mailto:address'
+# for lists created with the -x switch.
+!A
+</#x/>
+
+mailto:<#A#>
+# Below is a minimalist tag. It just means that succeeding lines should be
+# added to the currently open file in all cases.
+<//>
+
+Aby odmówiæ wys³ania listu, i zwróciæ go nadawcy, proszê
+przes³aæ wiadomosæ na adres: 
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Nie musisz za³±czaæ kopii listu, który akceptujesz (lub nie) do
+wys³ania na listê. Je¿eli chcesz przes³aæ jak±¶ notkê do nadawcy
+odrzuconego listu, zawrzyj j± pomiêdzy dwie linie zaczynaj±ce siê
+trzema znakami procentu ("%").
+
+%%% Pocz±tek notki
+%%% Koniec notki
+
+Dziêkujê za pomoc!
+
+--- W za³±czniu mo¿esz znale¼æ wys³any list.
+
+</text/mod-sub#E/>
+--- zapisa³em Ciê (lub wypisa³em) z listy
+<#l#>@<#H#>
+na ¿yczenie jej moderatora.
+
+Je¶li nie jest to dzia³anie, którego pragn±³e¶, mo¿esz
+przes³aæ swoje w±tpliwo¶ci do opiekuna listy:
+<#l#>-owner@<#H#>
+
+Je¿eli potrzebujesz informacji o tym, jak dostaæ siê do archiwum
+listy <#L#>, prze¶lij pusty list na adres:
+<#L#>-help@<#H#>
+
+</text/mod-timeout/>
+Przykro mi, ale moderatorzy nie zareagowali na Twój list.
+Dlatego zwracam go Tobie, je¿eli uwa¿asz, ¿e kryje siê za tym
+jaki¶ b³±d maszyny, wy¶lij list ponownie, albo skontaktuj siê
+bezpo¶rednio z moderatorem listy.
+
+--- W za³±czeniu Twoja oryginalna przesy³ka na listê.
+
+</text/mod-sub-confirm/>
+Bardzo proszê o zgodê na dodanie internauty o adresie:
+
+<#A#>
+
+jako prenumeratora listy dyskusyjnej <#l#>.
+Poniewa¿ powy¿sze ¿yczenie mog³o nie pochodziæ od Ciebie (patrz
+koniec listu), ju¿ zd±¿y³em potwierdziæ, ¿e internauta o adresie:
+<#A#>
+rzeczywiscie podobne ¿yczenie wys³a³.
+
+Aby udzieliæ zgody, proszê wys³aæ pust± odpowiedz na adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Twój program pocztowy powienien automatycznie prawid³owo zaadresowaæ
+list, je¿eli u¿yjesz opcji "Odpowiedz/Reply".
+
+Je¿eli natomiast siê nie zgadzasz, po prostu zignoruj ten list.
+
+Dziekujê za pomoc!
+
+</text/mod-unsub-confirm/>
+Bardzo proszê o Twoj± zgodê na usuniêcie internauty o adresie:
+
+!A
+
+z listy prenumeratorów listy <#l#>. 
+Je¿eli siê zgadzasz, wyslij, proszê, pust± odpowiedz na adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Twój program pocztowy powienien automatycznie prawid³owo zaadresowaæ
+list, je¿eli u¿yjesz opcji "Odpowiedz/Reply".
+
+Dziekujê za pomoc!
+
+</text/sub-bad/>
+Hmmm, numer potwierdzenia wydaje mi siê nieprawid³owy.
+
+Najczêstsz± przyczyn± nieprawid³owo¶ci jest jego przeterminowanie.
+Muszê dostaæ potwierdzenie ka¿dego ¿ycznia w ci±gu dziesiêciu dni.
+Mo¿esz równie¿ upewniæ siê czy za³±czy³e¶(a¶) ca³y numer potwierdzenia
+w poprzednim liscie, niektóre programy pocztowe maj± z³y nawyk
+ucinania adresów, które wydaj± im siê zbyt d³ugie.
+
+Przygotowa³em nowy numer potwierdzenia. Aby ponownie potwierdziæ
+chêæ zapisania siê z adresu:
+
+!A
+
+na listê dyskusyjn± <#L#>, wy¶lij pust± odpowied¼
+pod adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Pamiêtaj, sprawd¼ dok³adnie czy zalaczy³e¶(a¶) pe³ny numer, oczywi¶cie
+uczyñ to przed wys³aniem listu ;-)
+
+Przepraszam za k³opoty.
+Opiekun listy -
+</#x/>
+<#L#>-owner@<#H#>
+<//>
+
+</text/sub-confirm/>
+Aby potwierdziæ chêæ zapisania siê z adresu:
+
+!A
+
+na listê dyskusyjn± o nazwie <#L#>,
+wy¶lij, proszê, pust± odpowied¼ pod adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Twój program pocztowy powienien automatycznie zaadresowaæ przesy³kê,
+je¿eli u¿yjesz opcji "odpowiedz/reply".
+
+Potwierdzenie ma na celu
+a) sprawdzenie siê czy potrafiê wysy³aæ listy na adres przez Ciebie podany,
+b) upewnienie siê czy ktos nie zrobi³ Ci g³upiego dowcipu, zapisuj±c Ciê
+   bez twojej wiedzy na nasz± listê.
+
+</text/sub-confirm#s/>
+Lista jest moderowana. Kiedy wys³a³e¶ ju¿ potwierdzenie, chêæ prenumeraty
+zosta³a przes³ana moderatorowi. Zawiadomiê Ciê odrêbnym listem, je¶li
+zostaniesz wpisany(a) na listê prenumeratorów.
+
+</text/sub-nop/>
+
+Potwierdzenie: Adres poczty elektronicznej:
+
+!A
+
+jest ju¿ na li¶cie prenumeratorów <#L#>. By³ on ju¿ na li¶cie
+przed wys³aniem ponownej pro¶by, a wiêc j± zignorujê.
+
+</text/sub-ok#E/>
+Potwierdzenie: Doda³em adres
+
+!A
+
+do listy prenumeratorów <#L#>.
+
+**** WITAJ NA LI¦CIE <#L#>@<#H#>!
+
+Proszê o zachowanie tej przesy³ki, bêdziesz dziêki niej pamiêta³,
+z którego dok³adnie adresu jestes zapisany(a), informacja ta bêdzie
+niezbêdna, je¶li chcia³(a)by¶ kiedy¶ z listy siê wypisaæ lub zmieniæ
+adres korespondencyjny.
+
+</text/top/>
+Czesæ! Nazywam siê "ezmlm" i zarz±dzam serwerem pocztowych
+list dyskusyjnych, miêdzy innymi list± o nazwie:
+<#L#>@<#H#>
+
+</#x/>
+Jestem komputerem, bezdusznym s³ug± opiekuna listy, cz³owieka :-),
+którego mo¿na znale¼æ pod adresem:
+<#L#>-owner@<#H#>.
+
+</text/unsub-bad/>
+Hmmm, numer potwierdzenia wydaje mi siê nieprawid³owy.
+
+Najczêstsz± przyczyn± nieprawid³owo¶ci jest przeterminowanie,
+muszê dostaæ potwierdzenie ka¿dego ¿ycznia w ci±gu dziesiêciu dni.
+Mo¿esz równie¿ upewniæ siê czy za³±czy³e¶(a¶) ca³y numer potwierdzenia
+w poprzednim li¶cie, niektóre programy pocztowe maj± z³y nawyk
+ucinania adresów, które wydaj± im siê zbyt d³ugie.
+
+Przygotowa³em nowy numer potwierdzenia. Aby ponownie potwierdziæ
+¿e mam usun±æ adres
+
+!A
+
+z listy prenumeratorów <#l#>, wy¶lij pust± odpowiedz na adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Pamiêtaj, sprawd¼ dokladnie czy za³aczy³e¶(a¶) pe³ny numer potwierdzenia,
+uczyñ to oczywi¶cie przed wys³aniem listu ;-)
+
+Przepraszam za k³opoty.
+Opiekun -
+<#L#>-owner@<#H#>
+
+</text/unsub-confirm/>
+Aby potwierdziæ, ¿e chcesz usunac adres
+
+!A
+
+z listy prenumaratorów <#L#>, prze¶lij, proszê, pust±
+odpowied¼ na ten list pod adres:
+
+!R
+</#x/>
+
+mailto:<#R#>
+<//>
+
+Twój program pocztowy powienien automatycznie zaadresowaæ przesy³kê,
+je¿eli u¿yjesz opcji "odpowiedz/reply".
+
+Nie sprawdzi³em jednak czy twój adres znajduje siê na li¶cie
+prenumeratorów. Aby sprawdziæ, którego adresu u¿ywasz jako koresponde-
+cyjnego, spojrzyj na jak±kolwiek wiadomosæ z listy dyskusyjnej.
+Ka¿dy list ma schowany Twój adres w scie¿ce zwrotnej; np.
+Bóg@niebo.prezydent.pl dostaje listy ze scie¿k± zwrotn±:
+<<#l#>-return-<number>-Bóg=niebo.prezydent.pl@<#H#>.
+
+</text/unsub-nop/>
+Powiadomienie: Adresu pocztowego
+
+!A
+
+nie ma na li¶cie prenumeratorów <#l#>. Nie by³o go równie¿
+przed dosteniem Twojego ¿yczenia wykre¶lenia z listy.. 
+
+Je¿eli wypisa³e¶(a¶) siê, lecz nadal dostajesz listy, jeste¶ po prostu
+zapisany(a) z innego adresu, ni¿ ten, którego w³a¶nie u¿ywasz.
+Spojrzyj, proszê, ma nag³ówki któregokolwiek listu z prenumeraty,
+znajdziesz tam frazê:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+W³a¶ciwy adres, na który powinno wiêc trafiæ twoje ¿yczenie wypisania to:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+Po prostu napisz na powy¿szy adres, zamieniaj±c user=host.dom na twoje
+prawdziwe dane, odpowiedz po¼niej na pro¶bê potwierdzenia, 
+powieniene¶(a¶) wówczas dostaæ list, ¿e jeste¶ wykre¶lony(a)
+z listy prenumeratorów.
+
+Je¿eli moje rady nie skutkuj±, niestety nie mogê Ci ju¿ wiêcej pomóc.
+Prze¶lij, proszê, jak±kolwiek przesy³kê z listy wraz z krótk± informacj±,
+co chcesz osi±gn±æ, do opiekuna listy, pod adres:
+
+</#x/>
+mailto:<#L#>-owner@<#H#>
+</#X/>
+    <#l#>-owner@<#H#>
+<//>
+
+który to opiekun siê tym zajmie. We¼ pod uwagê, ¿e cz³owiek jest nieco
+wolniejszy od komputera :-), wiêc b±d¼ cierpliwy(a).
+
+</text/unsub-ok/>
+Zawiadomienie: usun±³em adres pocztowy
+
+!A
+
+z listy prenumeratorów <#l#>.
+Na adres ten nie bêd± ju¿ przychodzi³y przesy³ki z listy.
+
+</text/edit-do#n/>
+Przerób, proszê, za³±czony tekst i wy¶lij go na adres:
+
+!R
+
+Twój program powienien uczyniæ to automatycznie, je¿eli u¿yjesz
+funkcji "reply/odpowiedz".
+
+Mogê bez k³opotu usun±æ dodatki jakie mo¿e dodawaæ do tekstów
+Twój program pocztowy, je¿eli zachowasz linie znaczników.
+
+Linie znaczników s± to linie rozpoczynaj±ce siê "%%%".
+Nie mog± one byæ zmienione, dodatkowe znaki dodane przez program
+pocztowy na pocz±tku linii s± dozwolone.
+
+
+</text/edit-list#n/>
+Pliki <#L#>-edit.nazwa_pliku mog± byæ stosowane przez zdalnego
+administratora do edycji tekstów zarz±dczych listy dyskusyjnej.
+
+Tabela pod spodem jest list± plików wraz z krótkim opisem
+ich dzia³ania. Aby zamieniæ okre¶lony plik, po prostu wy¶lij
+pusty list na adres <#L#>-edit.nazwa_pliku ,
+zamieniaj±c wyra¿enie 'nazwa_pliku' nazw± zamienianego pliku.
+Instrukcja sposobu zamiany pliku zostanie dostarczona wraz ze
+starym plikiem poczt± zwrotn±.
+
+File                Use
+
+bottom              spód ka¿dej odpowiedzi administracyjnej. G³ówne komendy.
+digest              administracyjna czê¶æ przegl±du listy.
+faq                 najczê¶ciej zadawane pytania na naszej li¶cie.
+get_bad             tekst w miejsce listu nie znalezionego w archiwum.
+help                g³ówna tre¶æ pomocy.
+info                informacje o naszej li¶cie.
+mod_help            pomoc dla moderatorów list.
+mod_reject          list przesy³any nadawcy przesy³ki nie zaakceptowanej.
+mod_request         tekst przesy³any razem z pro¶b± moderowania.
+mod_sub             tekst przesy³any prenumeratorowi po zaakceptowaniu.
+mod_sub_confirm     tekst do moderatora z pro¶b± o wpisanie na listê.
+mod_timeout         do nadawcy przterminowanego listu.
+mod_unsub_confirm   do zdalnego opiekuna z pro¶b± o potwierdzenie wypisu.
+sub_bad             do prenumaratora, je¿eli potwierdzenie by³o z³e.
+sub_confirm         do prenumeratora z pro¶b± dokonania potwierdzenia.
+sub_nop             tre¶æ listu powitalnego dla ponownie subskrybuj±cego.
+sub_ok              tre¶æ listu powitalnego dla nowozapisanego.
+top                 pocz±tek ka¿dego listu, ostro¿nie!
+</#tn/>
+trailer             tekst dodawany do ka¿dego listu, ostro¿nie!
+</#n/>
+unsub_bad           do prenumeratora, je¶li jego potwierdzenie jest z³e.
+unsub_confirm       tre¶æ potwierdzenia po ¿yczeniu wypisania siê z listy.
+unsub_nop           do osoby nie bêd±cej prenumeratorem, wypisuj±cej siê.
+unsub_ok            list po¿egnalny do rezygnuj±cego z prenumeraty.
+
+</text/edit-done#n/>
+Plik tekstowy zosta³ szczê¶liwie zamieniony.
+
+</text/info#E/>
+Nie mam ¿adnych informacji na temat listy :-(
+</text/faq#E/>
+FAQ - najczê¶ciej zadawane pytania na li¶cie
+<#l#>@<#H#>.
+
+Jeszcze nic tu nie ma :-(, przepraszamy!
+
+
diff --git a/ezmlmrc.pt b/ezmlmrc.pt
new file mode 100644 (file)
index 0000000..a8532a5
--- /dev/null
@@ -0,0 +1,1133 @@
+0.324 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.pt_BR,v 1.15 1999/05/06 09:26:00 lindberg Exp $
+#$Name:$
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+ISO-8859-1:Q
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sinto muito, eu estou rejeitando as suas mensagens. Contacte <#L#>-owner@<#H#> se você tem questões sobre isto (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sinto muito, somente assinantes podem enviar mensagens. Se você é um assinante, por favor repasse esta mensagem para <#L#>-owner@<#H#> para ter o seu novo endereço incluído (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contacte <#L#>-help@<#H#>; gerenciado pelo ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+list-help: <mailto:<#l#>-help@<#h#>>
+list-unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+list-post: <mailto:<#L#>@<#H#>>
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+Para cancelar a subscrição, envie mensagem para: <#L#>-unsubscribe@<#H#>
+Para comandos adicionais, envie mensagem para: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Aqui estão os endereços de comando do ezmlm.
+
+Eu posso tratar as requisições administrativas automaticamente.
+Basta enviar uma mensagem vazia para qualquer destes endereços:
+
+   <<#L#>-subscribe@<#H#>>:
+   Receber as futuras mensagens enviadas para a lista <#L#>.
+
+   <<#L#>-unsubscribe@<#H#>>:
+   Parar de receber as mensagens da lista <#L#>.
+
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+   Para receber mais informações ou o FAQ desta lista,
+   se disponíveis.
+
+</#d/>
+Existem também estes endereços similares para a lista "digest":
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+   <<#L#>-get.12_45@<#H#>>:
+   Recupera uma cópia das mensagens 12 a 45 do arquivo.
+   No máximo 100 mensagens serão retornadas por requisição.
+
+</text/bottom#aI/>
+   <<#L#>-get.12@<#H#>>:
+   Recupera uma cópia da mensagem 12 do arquivo.
+
+</text/bottom#i/>
+   <<#L#>-index.123_456@<#H#>>:
+   Recupera os assuntos das mensagens número 123 a 456.
+   Assuntos são retornados em grupos de 100, ou seja você receberá
+   os assuntos das mensagens 100 a 499.
+   Um máximo de 2000 assuntos são retornados por requisição.
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+   <<#L#>-thread.12345@<#H#>>:
+   Recupera uma cópia de todas as mensagens com o mesmo assunto
+   da mensagem 12345.
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+Na verdade as mensagens não precisam ser vazias, mas eu irei
+ignorar o seu conteúdo. Somente o ENDEREÇO é importante.
+
+Você pode iniciar a assinatura para um endereço alternativo,
+por exemplo "john@host.domain", bastando adicionar um traço
+e o seu endereço (com '=' no lugar de '@'), ou seja:
+<<#L#>-subscribe-john=host.domain@<#H#>>
+
+Para cancelar a subscrição para este endereço, envie mensagem
+para: <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+Em ambos os casos, eu enviarei uma mensagem de confirmação para
+esse endereço; quando você receber esta mensagem, simplesmente
+responda para completar sua subscrição (ou cancelamento).
+
+</text/bottom/>
+Se estas instruções são muito complicadas ou você não teve os
+resultados que esperava, por favor contacte o meu dono em 
+<#L#>-owner@<#H#>. Mas tenha paciência, o meu dono é
+muito mais lento do que eu ;-)
+</text/bottom/>
+
+--- Abaixo está uma cópia da requisição que eu recebi.
+
+</text/bounce-bottom/>
+
+--- Abaixo está uma cópia da mensagem devolvida que eu recebi.
+
+</text/bounce-num/>
+
+Eu mantenho um controle das mensagens da lista <#L> que não
+foram entregues para o seu endereço.
+</#a/>
+Cópias destas mensagens podem estar no arquivo.
+</#aI/>
+Para pegar a mensagem 12345 do arquivo, envie uma mensagem vazia para
+  <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Para recuperar uma lista de assuntos e autores das últimas 100
+mensagens, envie uma mensagem vazia para:
+   <<#L#>-index@<#H#>>
+
+Para recuperar as mensagens 123 a 145 (no máximo 100 por requisição),
+envie uma mensagem vazia para:
+   <<#L#>-get.123_145@<#H#>>
+
+<//>
+Aqui estão os números das mensagens:
+
+</text/dig-bounce-num/>
+
+Eu mantenho um controle de quais mensagens da lista <#L#>-digest
+não foram entregues para o seu endereço. Para cada "digest" que você
+não recebeu, eu tenho anotado o número da primeira mensagem do "digest".
+Então você pode pegar as mensagens do arquivo da lista principal.
+
+</#aI/>
+Para recuperar a mensagem 12345 do arquivo, envie uma mensagem vazia para:
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Para recuperar as mensagens 123 a 145 (no máximo 100 por requisição),
+envie uma mensagem vazia para:
+   <<#L#>-get.123_145@<#H#>>
+
+Para recuperar uma lista de assuntos e autores das últimas 100
+mensagens, envie uma mensagem vazia para:
+   <<#L#>-index@<#H#>>
+
+<//>
+Aqui estão os números dos "digests":
+
+</text/bounce-probe/>
+
+Mensagens da lista <#l#> para você estão sendo devolvidas.
+Eu enviei um aviso para você, que também foi devolvido.
+Eu anexei uma cópia da mensagem devolvida.
+
+Esta é uma verificação para o seu endereço. Se esta verificação
+for devolvida, eu removerei o seu endereço da lista
+<#l#>@<#H#>, sem mais avisos. Você pode assinar novamente a
+lista enviando uma mensagem vazia para o endereço:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+Mensagens da lista <#l#> para você não foram entregues.
+Eu anexei uma cópia da primeira mensagem que eu recebi de volta.
+
+Se esta mensagem também não for entregue, eu enviarei uma última
+verificação. Se a verificação também for devolvida, eu removerei o seu
+endereço da lista <#l#>, sem mais avisos.
+
+</text/digest#d/>
+Para subscrever-se à lista "digest", envie mensagem para:
+       <#L#>-digest-subscribe@<#H#>
+
+Para cancelar a subscrição da lista "digest", envie mensagem para:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Para enviar mensagens para a lista, use o endereço:
+       <#L#>@<#H#>
+
+</text/get-bad/>
+Sinto muito, esta mensagem não está arquivada.
+
+</text/help/>
+Esta é uma mensagem de ajuda genérica. A mensagem que eu recebi 
+não era para os meus endereços de comando.
+
+</text/mod-help/>
+Obrigado por concordar em moderar a lista
+<#L#>@<#H#>.
+
+Meus comandos são um pouco diferentes de outros gerenciadores de
+listas. À primeira vista eles parecem não usuais, mas à medida que
+você os for usando, vai apreciar a simplicidade do sistema e
+a rapidez com que eu trato suas requisições.
+
+Aqui estão algumas observações sobre como atuar como dono da
+lista e/ou moderador:
+
+Subscrição Remota
+-----------------
+Como um moderador, você pode subscrever e cancelar a subscrição
+de qualquer endereço da lista. Para cadastrar john@johnhost.johndomain,
+simplesmente coloque um traço depois do comando, e depois o endereço
+com '=' no lugar de '@'. Por exemplo, para cadastrar este endereço,
+envie uma mensagem para:
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Você pode analogamente remover esse endereço, enviando mensagem para:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#d/>
+Para a lista "digest":
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+<//>
+Isto é tudo. Nem assunto nem corpo de mensagem são necessários!
+
+</#r/>
+Eu enviarei para você um pedido de confirmação, para ter certeza
+que é realmente você quem enviou a requisição. Simplesmente
+retorne a mensagem, e a requisição será completada.
+</#R/>
+Eu enviarei um pedido de confirmação para o endereço do usuário,
+neste caso <john@host.domain>. Tudo que o usuário tem que fazer é
+retornar este pedido de confirmação.
+<//>
+
+As confirmações são necessárias para evitar que pessoas
+não autorizadas possam cadastrar ou remover endereços
+da lista.
+
+Eu notificarei o usuário quando a situação de sua subscrição
+for alterada.
+
+Subscrição
+----------
+
+Qualquer usuário pode subscrever-se ou cancelar a subscrição
+enviando mensagem para:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+Para a lista "digest":
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+<//>
+O usuário receberá um pedido de confirmação para eu ter 
+certeza que ele controla o endereço de subscrição. Quando este
+endereço for verificado, ele será descadastrado.
+
+</#s/>
+Sendo esta lista moderada para subscrição, eu enviarei um segundo
+pedido de confirmação para o(s) moderador(es). Se o usuário
+já tiver confirmado o desejo de ficar na lista, você como
+moderador pode confiar que o endereço do assinante é verdadeiro.
+Se você deseja aprovar os pedidos do usuário, simplesmente
+retorne a mensagem de CONFIRMAÇÃO. Caso contrário, simplesmente
+ignore a minha mensagem ou possivelmente contacte o potencial
+assinante para obter mais informações.
+</#S/>
+Subscrições funcionam da mesma forma.
+<//>
+
+O usuário também pode usar estas formas:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+para que as mensagens sejam enviadas para "mary@host.domain".
+Somente se ela receber mensagens neste endereço, ela será
+capaz de responder a confirmação.
+
+Seu endereço e identidade não serão revelados para o assinante,
+a não ser que você envie mensagens diretamente para o usuário.
+
+</#rl/>
+Para obter o cadastro de assinantes da lista <#L#>@<#H#>,
+envie uma mensagem para:
+   <<#L#>-list@<#H#>>
+
+Para um registro de transações da lista,
+envie uma mensagem para:
+   <<#L#>-log@<#H#>>
+
+</#rld/>
+Para o cadastro de assinantes da lista digest:
+   <<#L#>-digest-list@<#H#>>
+e:
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Você pode editar remotamente os arquivos-texto de resposta que a lista
+envia. Para obter uma lista dos arquivos e instruções de edição, envie
+mensagem para:
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+Postagens Moderadas
+-------------------
+Quando as postagens são moderadas, eu colocarei as mensagens em 
+uma fila, e enviarei a você uma cópia junto com instruções. A
+mensagem terá "MODERATE for ..." como assunto.
+
+Se você aceita a mensagem, basta responder para o endereço 'Reply-To:',
+o qual já deixei configurado como o endereço de "aceitação".
+Não é necessário incluir a mensagem; na verdade, eu ignorarei qualquer
+coisa que você envie, desde que o endereço para o qual você enviou
+esteja correto.
+
+Se você quiser rejeitá-la, envie a mensagem para o endereço 'From:',
+que por sua vez, está configurado com o endereço de "rejeição".
+Você pode usualmente fazer um 'reply-to-all' - resposta para todos,
+e então remover o seu endereço e o endereço de "aceitação").
+Você pode adicionar um comentário opcional para o remetente entre
+duas linhas começando com três '%'. Eu enviarei este comentário somente
+para o remetente, sem revelar sua identidade.
+
+Eu irei processar a mensagem de acordo com o primeiro retorno que eu
+receber. Se você me enviar uma requisição para aceitar uma mensagem
+que já foi rejeitada ou vice-versa, eu o avisarei.
+
+Se eu não receber nenhuma resposta do moderador dentro de um certo
+período de tempo (normalmente 5 dias), eu retornarei uma mensagem
+para o remetente com uma explicação do ocorrido. O administrador
+também pode configurar a lista para que as mensagens "ignoradas"
+sejam simplesmente removidas, ao invés de retornar para o remetente.
+<//>
+
+Férias
+------
+Se você está temporariamente em um endereço diferente, basta repassar 
+todas as mensagens que têm o cabeçalho correto 'Mailing-List:' (ou todas
+as mensagens que têm assuntos começando com 'MODERATE for <#L#>@<#H#>'
+ou 'CONFIRM subscribe to <#L#>@<#H#>') para o novo endereço.
+Você pode então moderar a partir do novo endereço. Alternativamente,
+você pode repassar as mensagens para um amigo, assim ele pode moderar 
+para você. Por favor, avise e confirme este procedimento com o dono da lista.
+
+Se você quiser aprovar automaticamente todas as mensagens enquanto
+está fora, configure o seu programa de correio eletrônico para responder 
+automaticamente as mensagens que têm os assuntos com os critérios acima.
+
+</#r/>
+Se você tentar administrar remotamente a partir de um endereço que
+não é seu, o assinante, não você, será questionado para confirmar.
+Depois disto, um pedido de confirmação é enviado para todos os
+moderadores. Estou fazendo isto, porque eu não tenho como saber que
+foi você quem enviou o pedido original. 
+
+Por favor note que o seu pedido original (e seu endereço) é enviado
+para o assinante neste caso!
+<//>
+
+Boa sorte!
+
+PS: Por favor, contacte o dono da lista (<#L#>-owner@<#H#>) se você
+tiver qualquer dúvida ou problema.
+
+</text/mod-reject/>
+Sinto muito, sua mensagem (incluída) não foi aceita pelo moderador.
+Se o moderador fez algum comentário, este será mostrado abaixo.
+</text/mod-request/>
+Esta mensagem foi submetida à lista <#L#>@<#H#>.
+Se você aprova a mensagem para distribuição a todos
+os assinantes, por favor envie mensagem para:
+
+!A
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Você pode confirmar se o endereço começa com
+"<#L#>-accept". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+Alternativamente, clique aqui:
+       mailto:<#A#>
+
+<//>
+
+Para rejeitar esta mensagem, retornando-a para o remetente,
+por favor envie uma mensagem para:
+
+!R
+
+Na prática, é fácil usar o botão "reply-to-all" ou "responder
+para todos", e então remover todos os endereços, exceto o que
+começar com
+"<#L#>-reject".
+</#x/>
+
+Alternativamente, clique aqui:
+       mailto:<#R#>
+<//>
+
+Você não precisa copiar esta mensagem na sua resposta para
+aceitá-la ou rejeitá-la. Se você quiser enviar um comentário para
+o remetente de uma mensagem rejeitada, por favor inclua o comentário
+entre duas linhas começando com três sinais de porcentagem ('%').
+
+%%% Início do comentário
+%%% Fim do comentário
+
+Obrigado pela sua ajuda!
+
+--- Inclusão, por favor encontre a mensagem postada.
+
+</text/mod-sub#E/>
+--- Eu subscrevi você ou cancelei sua subscrição através
+da requisição de um moderador da lista <#l#>@<#H#>.
+
+Se esta é uma ação que você não deseja, por favor envie uma
+reclamação ou outros comentários para o dono da lista
+(<#l#>-owner@<#H#>) assim que possível.
+
+Se você quer alguma informação em como acessar o arquivo
+da lista <#L#>, basta enviar uma mensagem vazia para 
+<#L#>-help@<#H#>.
+
+</text/mod-timeout/>
+Sinto muito, os moderadores não tomaram nenhuma ação com a sua
+mensagem. Eu a estou retornado para você. Se você acha que isto
+é um erro, por favor reenvie sua mensagem ou contacte um moderador
+da lista diretamente.
+
+--- Inclusão, por favor encontre a mensagem que você enviou.
+
+</text/mod-sub-confirm/>
+Respeitosamente eu solicito sua permissão para incluir
+
+!A
+
+como assinante da lista <#l#>. Este pedido ou vem de você
+ou já foi verificado pelo potencial assinante.
+
+Para confirmar, por favor envie uma resposta vazia para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Se você não aprovar, simplesmente ignore esta mensagem.
+
+Obrigado pela sua ajuda!
+
+</text/mod-unsub-confirm/>
+Foi feito um pedido para remover
+
+!A
+
+da lista <#l#>. Se você concordar, por favor envie
+uma resposta vazia para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Se você não aprova, simplesmente ignore esta mensagem.
+
+Obrigado pela sua ajuda!
+
+</text/sub-bad/>
+Este número de confirmação perece ser inválido.
+
+A maioria dos casos de números inválidos é devida a expiração. Eu 
+tenho que receber uma confirmação de cada requisição dentro de 10 dias. 
+Certifique-se também que o número de confirmação está inteiro na
+resposta que você me enviou. Alguns programas de correio eletrônico têm
+o hábito de cortar parte do endereço de retorno, o qual pode ser
+bastante longo.
+
+Eu configurei um novo número. Para confirmar que você deseja que
+
+!A
+
+seja incluído na lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Novamente verifique o endereço de resposta cuidadosamente, para ter
+certeza que está completo antes que você confirme a sua subscrição.
+
+Sinto muito pelo problema.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm/>
+Para confirmar que você deseja que
+
+!A
+
+seja incluído na lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Esta confirmação tem dois propósitos. Primeiro, ela verifica que eu
+sou consigo receber mensagens de você. Segundo, ela protege você no caso
+de alguém estar forjando um pedido de subscrição em seu nome.
+
+</#q/>
+Alguns programas de correio eletrônico não conseguem manipular endereços
+muito longos. Se você não está conseguindo responder esta requisição por
+causa disto, envie uma mensagem para <<#L#>-request@<#H#>> 
+e coloque o endereço inteiro listado abaixo na linha "Subject:" ou
+"Assunto:".
+
+</text/sub-confirm#s/>
+Esta lista é moderada. Depois que você enviar esta confirmação,
+o pedido será enviado para o(s) moderador(es) desta lista. Eu notificarei
+você quando sua subscrição for ativada.
+
+</text/sub-nop/>
+Confirmação: o endereço
+
+!A
+
+está na lista <#l#>. Este endereço já estava
+cadastrado antes do seu pedido ser recebido.
+
+</text/sub-ok#E/>
+Confirmação: eu incluí o endereço
+
+!A
+
+para a lista <#l#>.
+
+Bem-vindo à <#l#>@<#H#>!
+
+Por favor salve esta mensagem para que você saiba o endereço sob o
+qual está inscrito; se mais tarde você quiser cancelar ou alterar
+o seu endereço de subscrição, esta mensagem poderá ser útil.
+
+</text/top/>
+Oi! Este é o programa ezmlm. Eu estou gerenciando
+a lista <#l#>@<#H#>.
+
+</#x/>
+Eu estou trabalhando para o meu dono, que pode ser
+contactado pelo endereço <#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+O número de confirmação perece ser inválido.
+
+A maioria dos casos de números inválidos é devida a expiração. Eu 
+tenho que receber uma confirmação de cada requisição dentro de 10 dias. 
+Certifique-se também que o número de confirmação está inteiro na
+resposta que você me enviou. Alguns programas de correio eletrônico têm
+o hábito de cortar parte do endereço de retorno, o qual pode ser
+bastante longo.
+
+Eu configurei um novo número. Para confirmar que você deseja que
+
+!A
+
+seja removido da lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Novamente verifique o endereço de resposta cuidadosamente, para ter
+certeza que está completo antes que você confirme esta ação.
+
+Sinto muito pelo problema.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm/>
+Para confirmar que você deseja que
+
+!A
+
+seja removido da lista <#l#>, por favor envie uma resposta vazia
+para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Eu não verifiquei se o seu endereço está atualmente na lista.
+Para ver qual endereço você usou ao se subscrever, olhe as mensagens
+que você está recebendo da lista. Cada mensagem tem seu endereço 
+oculto dentro do caminho de retorno; por exemplo, mary@xdd.ff.com 
+recebe mensagens com caminho de retorno:
+<<#l#>-return-<number>-mary=xdd.ff.com@<#H#>.
+
+</#q/>
+Alguns programas de correio eletrônico não conseguem manipular endereços
+muito longos. Se você não está conseguindo responder esta requisição por
+causa disto, envie uma mensagem para <<#L#>-request@<#H#>> 
+e coloque o endereço inteiro listado abaixo na linha "Subject:" ou
+"Assunto:".
+
+</text/unsub-nop/>
+Confirmação: o endereço
+
+!A
+
+não está na lista <#l#>. Ele não foi encontrado quando
+o seu pedido foi recebido.
+
+Se você cancelou a subscrição, mas continua recebendo mensagens,
+você está incluído com um endereço diferente do que está usando 
+agora. Por favor, olhe o cabeçalho da mensagem, procurando por:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+O endereço de cancelamento para este endereço deve ser:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+Basta enviar uma mensagem para este endereço, substituindo
+user=host.dom pelos valores corretos, responda ao pedido de confirmação
+e você deverá receber um aviso que está fora da lista.
+
+Para alguns programas de correio, você precisará tornar os cabeçalhos
+visíveis para ver o caminho de retorno (return-path):
+
+Para o Eudora 4.0, clique no botão "Blah blah ...".
+Para o PMMail, clique em "Window->Show entire message/header". 
+
+Se isto ainda não funcionar, eu sinto muito em dizer que eu não posso
+ajudar você. Por favor, REPASSE uma mensagem da lista junto com uma
+observação sobre o que você está tentando fazer para o meu dono:
+
+    <#l#>-owner@<#H#>
+
+que cuidará disto. Meu dono é um pouco mais lento do que eu,
+por favor tenha paciência.
+
+</text/unsub-ok/>
+Confirmação: Eu removi o endereço
+
+!A
+
+da lista <#l#>. Este endereço não está
+mais na lista.
+
+</text/edit-do#n/>
+Por favor edite o arquivo texto seguinte e envie-o para este endereço: 
+
+!R
+
+O seu programa de correio eletrônico deve ser capaz de enviar uma resposta
+para este endereço automaticamente.
+
+Eu posso remover as aspas que o seu programa de correio adiciona
+ao texto, desde que você não edite as próprias linhas marcadoras.
+
+As linhas marcadoras são as linhas começando com '%%%'. Elas não 
+devem ser modificadas (caracteres extras adicionados pelo seu programa
+de correio eletrônico no início da linha são aceitos).
+
+
+</text/edit-list#n/>
+O comando <#L#>-edit.file pode ser usado por um administrador
+remoto para editar os arquivos texto que são usados para as
+respostas da lista <#L#>@<#H#>.
+
+O que segue é uma lista dos nomes dos arquivos de resposta
+e uma breve descrição de quando os seus conteúdos são usados.
+Para editar um arquivo, simplesmente envie uma mensagem para
+<#L#>-edit.file, substituindo 'file' pelo nome do arquivo.
+Instruções para edição serão enviadas com o arquivo texto.
+
+Arquivo             Uso
+
+bottom              rodapé de todas as respostas. Informação geral dos comandos.
+digest              seção 'administrativa' das listas "digest".
+faq                 perguntas frequentes específicas desta lista.
+get_bad             no lugar de mensagem não encontradas no arquivo.
+help                ajuda geral (entre 'top' e 'bottom').
+info                lista informações.
+mod_help            ajuda específica para moderadores.
+mod_reject          para o remetente de uma mensagem rejeitada.
+mod_request         para os moderadores junto com a mensagem.
+mod_sub             para o assinante depois que o moderador confirma a 
+                    sua subscrição.
+mod_sub_confirm     para o moderador de subscrição requerendo a confirmação.
+mod_timeout         para o remetente de uma mensagem expirada.
+mod_unsub_confirm   para o administrador remoto confirmar o cancelamento
+                    de subscrição.
+sub_bad             para o assinante, se confirmado que a msg era inválida.
+sub_confirm         para o assinante solicitando confirmação de subscrição.
+sub_nop             para o assinante depois de re-subscrição.
+sub_ok              para o assinante depois de subscrição com sucesso.
+top                 topo de todas as respostas.
+</#tn/>
+trailer             incluído em todas as mensagens enviadas pela lista.
+</#n/>
+unsub_bad           para o assinante, se a confirmação de cancelamento
+                    é inválida.
+unsub_confirm       para assinante pedindo confirmação para o cancelamento.
+unsub_nop           para não-assinante depois de pedido de cancelamento.
+unsub_ok            para ex-assinante depois do cancelamento com sucesso.
+
+</text/edit-done#n/>
+O arquivo texto foi atualizado com sucesso.
+
+</text/info#E/>
+Ainda não há informações para esta lista.
+</text/faq#E/>
+FAQ - Questões mais freqüentes na lista <#l#>@<#H#>.
+
+Ainda não disponível.
+  
+
diff --git a/ezmlmrc.pt_BR b/ezmlmrc.pt_BR
new file mode 100644 (file)
index 0000000..81aadbf
--- /dev/null
@@ -0,0 +1,1134 @@
+0.324 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.pt_BR,v 1.16 1999/12/23 23:08:19 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Explicitly specify character-set, when this ezmlmrc was used.
+ISO-8859-1:Q
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sinto muito, eu estou rejeitando as suas mensagens. Contacte <#L#>-owner@<#H#> se você tem questões sobre isto (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sinto muito, somente assinantes podem enviar mensagens. Se você é um assinante, por favor repasse esta mensagem para <#L#>-owner@<#H#> para ter o seu novo endereço incluído (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contacte <#L#>-help@<#H#>; gerenciado pelo ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+List-Post: <mailto:<#L#>@<#H#>>
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+---------------------------------------------------------------------
+Para cancelar a subscrição, envie mensagem para: <#L#>-unsubscribe@<#H#>
+Para comandos adicionais, envie mensagem para: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- Aqui estão os endereços de comando do ezmlm.
+
+Eu posso tratar as requisições administrativas automaticamente.
+Basta enviar uma mensagem vazia para qualquer destes endereços:
+
+   <<#L#>-subscribe@<#H#>>:
+   Receber as futuras mensagens enviadas para a lista <#L#>.
+
+   <<#L#>-unsubscribe@<#H#>>:
+   Parar de receber as mensagens da lista <#L#>.
+
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+   Para receber mais informações ou o FAQ desta lista,
+   se disponíveis.
+
+</#d/>
+Existem também estes endereços similares para a lista "digest":
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+   <<#L#>-get.12_45@<#H#>>:
+   Recupera uma cópia das mensagens 12 a 45 do arquivo.
+   No máximo 100 mensagens serão retornadas por requisição.
+
+</text/bottom#aI/>
+   <<#L#>-get.12@<#H#>>:
+   Recupera uma cópia da mensagem 12 do arquivo.
+
+</text/bottom#i/>
+   <<#L#>-index.123_456@<#H#>>:
+   Recupera os assuntos das mensagens número 123 a 456.
+   Assuntos são retornados em grupos de 100, ou seja você receberá
+   os assuntos das mensagens 100 a 499.
+   Um máximo de 2000 assuntos são retornados por requisição.
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+   <<#L#>-thread.12345@<#H#>>:
+   Recupera uma cópia de todas as mensagens com o mesmo assunto
+   da mensagem 12345.
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+Na verdade as mensagens não precisam ser vazias, mas eu irei
+ignorar o seu conteúdo. Somente o ENDEREÇO é importante.
+
+Você pode iniciar a assinatura para um endereço alternativo,
+por exemplo "john@host.domain", bastando adicionar um traço
+e o seu endereço (com '=' no lugar de '@'), ou seja:
+<<#L#>-subscribe-john=host.domain@<#H#>>
+
+Para cancelar a subscrição para este endereço, envie mensagem
+para: <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+Em ambos os casos, eu enviarei uma mensagem de confirmação para
+esse endereço; quando você receber esta mensagem, simplesmente
+responda para completar sua subscrição (ou cancelamento).
+
+</text/bottom/>
+Se estas instruções são muito complicadas ou você não teve os
+resultados que esperava, por favor contacte o meu dono em 
+<#L#>-owner@<#H#>. Mas tenha paciência, o meu dono é
+muito mais lento do que eu ;-)
+</text/bottom/>
+
+--- Abaixo está uma cópia da requisição que eu recebi.
+
+</text/bounce-bottom/>
+
+--- Abaixo está uma cópia da mensagem devolvida que eu recebi.
+
+</text/bounce-num/>
+
+Eu mantenho um controle das mensagens da lista <#L> que não
+foram entregues para o seu endereço.
+</#a/>
+Cópias destas mensagens podem estar no arquivo.
+</#aI/>
+Para pegar a mensagem 12345 do arquivo, envie uma mensagem vazia para
+  <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Para recuperar uma lista de assuntos e autores das últimas 100
+mensagens, envie uma mensagem vazia para:
+   <<#L#>-index@<#H#>>
+
+Para recuperar as mensagens 123 a 145 (no máximo 100 por requisição),
+envie uma mensagem vazia para:
+   <<#L#>-get.123_145@<#H#>>
+
+<//>
+Aqui estão os números das mensagens:
+
+</text/dig-bounce-num/>
+
+Eu mantenho um controle de quais mensagens da lista <#L#>-digest
+não foram entregues para o seu endereço. Para cada "digest" que você
+não recebeu, eu tenho anotado o número da primeira mensagem do "digest".
+Então você pode pegar as mensagens do arquivo da lista principal.
+
+</#aI/>
+Para recuperar a mensagem 12345 do arquivo, envie uma mensagem vazia para:
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+Para recuperar as mensagens 123 a 145 (no máximo 100 por requisição),
+envie uma mensagem vazia para:
+   <<#L#>-get.123_145@<#H#>>
+
+Para recuperar uma lista de assuntos e autores das últimas 100
+mensagens, envie uma mensagem vazia para:
+   <<#L#>-index@<#H#>>
+
+<//>
+Aqui estão os números dos "digests":
+
+</text/bounce-probe/>
+
+Mensagens da lista <#l#> para você estão sendo devolvidas.
+Eu enviei um aviso para você, que também foi devolvido.
+Eu anexei uma cópia da mensagem devolvida.
+
+Esta é uma verificação para o seu endereço. Se esta verificação
+for devolvida, eu removerei o seu endereço da lista
+<#l#>@<#H#>, sem mais avisos. Você pode assinar novamente a
+lista enviando uma mensagem vazia para o endereço:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+Mensagens da lista <#l#> para você não foram entregues.
+Eu anexei uma cópia da primeira mensagem que eu recebi de volta.
+
+Se esta mensagem também não for entregue, eu enviarei uma última
+verificação. Se a verificação também for devolvida, eu removerei o seu
+endereço da lista <#l#>, sem mais avisos.
+
+</text/digest#d/>
+Para subscrever-se à lista "digest", envie mensagem para:
+       <#L#>-digest-subscribe@<#H#>
+
+Para cancelar a subscrição da lista "digest", envie mensagem para:
+       <#L#>-digest-unsubscribe@<#H#>
+
+Para enviar mensagens para a lista, use o endereço:
+       <#L#>@<#H#>
+
+</text/get-bad/>
+Sinto muito, esta mensagem não está arquivada.
+
+</text/help/>
+Esta é uma mensagem de ajuda genérica. A mensagem que eu recebi 
+não era para os meus endereços de comando.
+
+</text/mod-help/>
+Obrigado por concordar em moderar a lista
+<#L#>@<#H#>.
+
+Meus comandos são um pouco diferentes de outros gerenciadores de
+listas. À primeira vista eles parecem não usuais, mas à medida que
+você os for usando, vai apreciar a simplicidade do sistema e
+a rapidez com que eu trato suas requisições.
+
+Aqui estão algumas observações sobre como atuar como dono da
+lista e/ou moderador:
+
+Subscrição Remota
+-----------------
+Como um moderador, você pode subscrever e cancelar a subscrição
+de qualquer endereço da lista. Para cadastrar john@johnhost.johndomain,
+simplesmente coloque um traço depois do comando, e depois o endereço
+com '=' no lugar de '@'. Por exemplo, para cadastrar este endereço,
+envie uma mensagem para:
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Você pode analogamente remover esse endereço, enviando mensagem para:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#d/>
+Para a lista "digest":
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+<//>
+Isto é tudo. Nem assunto nem corpo de mensagem são necessários!
+
+</#r/>
+Eu enviarei para você um pedido de confirmação, para ter certeza
+que é realmente você quem enviou a requisição. Simplesmente
+retorne a mensagem, e a requisição será completada.
+</#R/>
+Eu enviarei um pedido de confirmação para o endereço do usuário,
+neste caso <john@host.domain>. Tudo que o usuário tem que fazer é
+retornar este pedido de confirmação.
+<//>
+
+As confirmações são necessárias para evitar que pessoas
+não autorizadas possam cadastrar ou remover endereços
+da lista.
+
+Eu notificarei o usuário quando a situação de sua subscrição
+for alterada.
+
+Subscrição
+----------
+
+Qualquer usuário pode subscrever-se ou cancelar a subscrição
+enviando mensagem para:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+Para a lista "digest":
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+<//>
+O usuário receberá um pedido de confirmação para eu ter 
+certeza que ele controla o endereço de subscrição. Quando este
+endereço for verificado, ele será descadastrado.
+
+</#s/>
+Sendo esta lista moderada para subscrição, eu enviarei um segundo
+pedido de confirmação para o(s) moderador(es). Se o usuário
+já tiver confirmado o desejo de ficar na lista, você como
+moderador pode confiar que o endereço do assinante é verdadeiro.
+Se você deseja aprovar os pedidos do usuário, simplesmente
+retorne a mensagem de CONFIRMAÇÃO. Caso contrário, simplesmente
+ignore a minha mensagem ou possivelmente contacte o potencial
+assinante para obter mais informações.
+</#S/>
+Subscrições funcionam da mesma forma.
+<//>
+
+O usuário também pode usar estas formas:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+para que as mensagens sejam enviadas para "mary@host.domain".
+Somente se ela receber mensagens neste endereço, ela será
+capaz de responder a confirmação.
+
+Seu endereço e identidade não serão revelados para o assinante,
+a não ser que você envie mensagens diretamente para o usuário.
+
+</#rl/>
+Para obter o cadastro de assinantes da lista <#L#>@<#H#>,
+envie uma mensagem para:
+   <<#L#>-list@<#H#>>
+
+Para um registro de transações da lista,
+envie uma mensagem para:
+   <<#L#>-log@<#H#>>
+
+</#rld/>
+Para o cadastro de assinantes da lista digest:
+   <<#L#>-digest-list@<#H#>>
+e:
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+Você pode editar remotamente os arquivos-texto de resposta que a lista
+envia. Para obter uma lista dos arquivos e instruções de edição, envie
+mensagem para:
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+Postagens Moderadas
+-------------------
+Quando as postagens são moderadas, eu colocarei as mensagens em 
+uma fila, e enviarei a você uma cópia junto com instruções. A
+mensagem terá "MODERATE for ..." como assunto.
+
+Se você aceita a mensagem, basta responder para o endereço 'Reply-To:',
+o qual já deixei configurado como o endereço de "aceitação".
+Não é necessário incluir a mensagem; na verdade, eu ignorarei qualquer
+coisa que você envie, desde que o endereço para o qual você enviou
+esteja correto.
+
+Se você quiser rejeitá-la, envie a mensagem para o endereço 'From:',
+que por sua vez, está configurado com o endereço de "rejeição".
+Você pode usualmente fazer um 'reply-to-all' - resposta para todos,
+e então remover o seu endereço e o endereço de "aceitação").
+Você pode adicionar um comentário opcional para o remetente entre
+duas linhas começando com três '%'. Eu enviarei este comentário somente
+para o remetente, sem revelar sua identidade.
+
+Eu irei processar a mensagem de acordo com o primeiro retorno que eu
+receber. Se você me enviar uma requisição para aceitar uma mensagem
+que já foi rejeitada ou vice-versa, eu o avisarei.
+
+Se eu não receber nenhuma resposta do moderador dentro de um certo
+período de tempo (normalmente 5 dias), eu retornarei uma mensagem
+para o remetente com uma explicação do ocorrido. O administrador
+também pode configurar a lista para que as mensagens "ignoradas"
+sejam simplesmente removidas, ao invés de retornar para o remetente.
+<//>
+
+Férias
+------
+Se você está temporariamente em um endereço diferente, basta repassar 
+todas as mensagens que têm o cabeçalho correto 'Mailing-List:' (ou todas
+as mensagens que têm assuntos começando com 'MODERATE for <#L#>@<#H#>'
+ou 'CONFIRM subscribe to <#L#>@<#H#>') para o novo endereço.
+Você pode então moderar a partir do novo endereço. Alternativamente,
+você pode repassar as mensagens para um amigo, assim ele pode moderar 
+para você. Por favor, avise e confirme este procedimento com o dono da lista.
+
+Se você quiser aprovar automaticamente todas as mensagens enquanto
+está fora, configure o seu programa de correio eletrônico para responder 
+automaticamente as mensagens que têm os assuntos com os critérios acima.
+
+</#r/>
+Se você tentar administrar remotamente a partir de um endereço que
+não é seu, o assinante, não você, será questionado para confirmar.
+Depois disto, um pedido de confirmação é enviado para todos os
+moderadores. Estou fazendo isto, porque eu não tenho como saber que
+foi você quem enviou o pedido original. 
+
+Por favor note que o seu pedido original (e seu endereço) é enviado
+para o assinante neste caso!
+<//>
+
+Boa sorte!
+
+PS: Por favor, contacte o dono da lista (<#L#>-owner@<#H#>) se você
+tiver qualquer dúvida ou problema.
+
+</text/mod-reject/>
+Sinto muito, sua mensagem (incluída) não foi aceita pelo moderador.
+Se o moderador fez algum comentário, este será mostrado abaixo.
+</text/mod-request/>
+Esta mensagem foi submetida à lista <#L#>@<#H#>.
+Se você aprova a mensagem para distribuição a todos
+os assinantes, por favor envie mensagem para:
+
+!A
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Você pode confirmar se o endereço começa com
+"<#L#>-accept". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+Alternativamente, clique aqui:
+       mailto:<#A#>
+
+<//>
+
+Para rejeitar esta mensagem, retornando-a para o remetente,
+por favor envie uma mensagem para:
+
+!R
+
+Na prática, é fácil usar o botão "reply-to-all" ou "responder
+para todos", e então remover todos os endereços, exceto o que
+começar com
+"<#L#>-reject".
+</#x/>
+
+Alternativamente, clique aqui:
+       mailto:<#R#>
+<//>
+
+Você não precisa copiar esta mensagem na sua resposta para
+aceitá-la ou rejeitá-la. Se você quiser enviar um comentário para
+o remetente de uma mensagem rejeitada, por favor inclua o comentário
+entre duas linhas começando com três sinais de porcentagem ('%').
+
+%%% Início do comentário
+%%% Fim do comentário
+
+Obrigado pela sua ajuda!
+
+--- Inclusão, por favor encontre a mensagem postada.
+
+</text/mod-sub#E/>
+--- Eu subscrevi você ou cancelei sua subscrição através
+da requisição de um moderador da lista <#l#>@<#H#>.
+
+Se esta é uma ação que você não deseja, por favor envie uma
+reclamação ou outros comentários para o dono da lista
+(<#l#>-owner@<#H#>) assim que possível.
+
+Se você quer alguma informação em como acessar o arquivo
+da lista <#L#>, basta enviar uma mensagem vazia para 
+<#L#>-help@<#H#>.
+
+</text/mod-timeout/>
+Sinto muito, os moderadores não tomaram nenhuma ação com a sua
+mensagem. Eu a estou retornado para você. Se você acha que isto
+é um erro, por favor reenvie sua mensagem ou contacte um moderador
+da lista diretamente.
+
+--- Inclusão, por favor encontre a mensagem que você enviou.
+
+</text/mod-sub-confirm/>
+Respeitosamente eu solicito sua permissão para incluir
+
+!A
+
+como assinante da lista <#l#>. Este pedido ou vem de você
+ou já foi verificado pelo potencial assinante.
+
+Para confirmar, por favor envie uma resposta vazia para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Se você não aprovar, simplesmente ignore esta mensagem.
+
+Obrigado pela sua ajuda!
+
+</text/mod-unsub-confirm/>
+Foi feito um pedido para remover
+
+!A
+
+da lista <#l#>. Se você concordar, por favor envie
+uma resposta vazia para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Se você não aprova, simplesmente ignore esta mensagem.
+
+Obrigado pela sua ajuda!
+
+</text/sub-bad/>
+Este número de confirmação perece ser inválido.
+
+A maioria dos casos de números inválidos é devida a expiração. Eu 
+tenho que receber uma confirmação de cada requisição dentro de 10 dias. 
+Certifique-se também que o número de confirmação está inteiro na
+resposta que você me enviou. Alguns programas de correio eletrônico têm
+o hábito de cortar parte do endereço de retorno, o qual pode ser
+bastante longo.
+
+Eu configurei um novo número. Para confirmar que você deseja que
+
+!A
+
+seja incluído na lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Novamente verifique o endereço de resposta cuidadosamente, para ter
+certeza que está completo antes que você confirme a sua subscrição.
+
+Sinto muito pelo problema.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm/>
+Para confirmar que você deseja que
+
+!A
+
+seja incluído na lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Esta confirmação tem dois propósitos. Primeiro, ela verifica que eu
+sou consigo receber mensagens de você. Segundo, ela protege você no caso
+de alguém estar forjando um pedido de subscrição em seu nome.
+
+</#q/>
+Alguns programas de correio eletrônico não conseguem manipular endereços
+muito longos. Se você não está conseguindo responder esta requisição por
+causa disto, envie uma mensagem para <<#L#>-request@<#H#>> 
+e coloque o endereço inteiro listado abaixo na linha "Subject:" ou
+"Assunto:".
+
+</text/sub-confirm#s/>
+Esta lista é moderada. Depois que você enviar esta confirmação,
+o pedido será enviado para o(s) moderador(es) desta lista. Eu notificarei
+você quando sua subscrição for ativada.
+
+</text/sub-nop/>
+Confirmação: o endereço
+
+!A
+
+está na lista <#l#>. Este endereço já estava
+cadastrado antes do seu pedido ser recebido.
+
+</text/sub-ok#E/>
+Confirmação: eu incluí o endereço
+
+!A
+
+para a lista <#l#>.
+
+Bem-vindo à <#l#>@<#H#>!
+
+Por favor salve esta mensagem para que você saiba o endereço sob o
+qual está inscrito; se mais tarde você quiser cancelar ou alterar
+o seu endereço de subscrição, esta mensagem poderá ser útil.
+
+</text/top/>
+Oi! Este é o programa ezmlm. Eu estou gerenciando
+a lista <#l#>@<#H#>.
+
+</#x/>
+Eu estou trabalhando para o meu dono, que pode ser
+contactado pelo endereço <#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+O número de confirmação perece ser inválido.
+
+A maioria dos casos de números inválidos é devida a expiração. Eu 
+tenho que receber uma confirmação de cada requisição dentro de 10 dias. 
+Certifique-se também que o número de confirmação está inteiro na
+resposta que você me enviou. Alguns programas de correio eletrônico têm
+o hábito de cortar parte do endereço de retorno, o qual pode ser
+bastante longo.
+
+Eu configurei um novo número. Para confirmar que você deseja que
+
+!A
+
+seja removido da lista <#l#>, por favor envie uma resposta vazia
+para o endereço:
+
+!R
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Novamente verifique o endereço de resposta cuidadosamente, para ter
+certeza que está completo antes que você confirme esta ação.
+
+Sinto muito pelo problema.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm/>
+Para confirmar que você deseja que
+
+!A
+
+seja removido da lista <#l#>, por favor envie uma resposta vazia
+para este endereço:
+
+!R
+
+Na prática, você estará enviado para este endereço quando pressionar o
+botão "reply" ou "responder". Se isto não funcionar, simplesmente copie
+o endereço e cole-o para o campo "To:" de uma nova mensagem.
+</#x/>
+
+ou clique aqui:
+       mailto:<#R#>
+<//>
+
+Eu não verifiquei se o seu endereço está atualmente na lista.
+Para ver qual endereço você usou ao se subscrever, olhe as mensagens
+que você está recebendo da lista. Cada mensagem tem seu endereço 
+oculto dentro do caminho de retorno; por exemplo, mary@xdd.ff.com 
+recebe mensagens com caminho de retorno:
+<<#l#>-return-<number>-mary=xdd.ff.com@<#H#>.
+
+</#q/>
+Alguns programas de correio eletrônico não conseguem manipular endereços
+muito longos. Se você não está conseguindo responder esta requisição por
+causa disto, envie uma mensagem para <<#L#>-request@<#H#>> 
+e coloque o endereço inteiro listado abaixo na linha "Subject:" ou
+"Assunto:".
+
+</text/unsub-nop/>
+Confirmação: o endereço
+
+!A
+
+não está na lista <#l#>. Ele não foi encontrado quando
+o seu pedido foi recebido.
+
+Se você cancelou a subscrição, mas continua recebendo mensagens,
+você está incluído com um endereço diferente do que está usando 
+agora. Por favor, olhe o cabeçalho da mensagem, procurando por:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+O endereço de cancelamento para este endereço deve ser:
+'<#l#>-unsubscribe-user=host.dom@<#H#>'.
+Basta enviar uma mensagem para este endereço, substituindo
+user=host.dom pelos valores corretos, responda ao pedido de confirmação
+e você deverá receber um aviso que está fora da lista.
+
+Para alguns programas de correio, você precisará tornar os cabeçalhos
+visíveis para ver o caminho de retorno (return-path):
+
+Para o Eudora 4.0, clique no botão "Blah blah ...".
+Para o PMMail, clique em "Window->Show entire message/header". 
+
+Se isto ainda não funcionar, eu sinto muito em dizer que eu não posso
+ajudar você. Por favor, REPASSE uma mensagem da lista junto com uma
+observação sobre o que você está tentando fazer para o meu dono:
+
+    <#l#>-owner@<#H#>
+
+que cuidará disto. Meu dono é um pouco mais lento do que eu,
+por favor tenha paciência.
+
+</text/unsub-ok/>
+Confirmação: Eu removi o endereço
+
+!A
+
+da lista <#l#>. Este endereço não está
+mais na lista.
+
+</text/edit-do#n/>
+Por favor edite o arquivo texto seguinte e envie-o para este endereço: 
+
+!R
+
+O seu programa de correio eletrônico deve ser capaz de enviar uma resposta
+para este endereço automaticamente.
+
+Eu posso remover as aspas que o seu programa de correio adiciona
+ao texto, desde que você não edite as próprias linhas marcadoras.
+
+As linhas marcadoras são as linhas começando com '%%%'. Elas não 
+devem ser modificadas (caracteres extras adicionados pelo seu programa
+de correio eletrônico no início da linha são aceitos).
+
+
+</text/edit-list#n/>
+O comando <#L#>-edit.file pode ser usado por um administrador
+remoto para editar os arquivos texto que são usados para as
+respostas da lista <#L#>@<#H#>.
+
+O que segue é uma lista dos nomes dos arquivos de resposta
+e uma breve descrição de quando os seus conteúdos são usados.
+Para editar um arquivo, simplesmente envie uma mensagem para
+<#L#>-edit.file, substituindo 'file' pelo nome do arquivo.
+Instruções para edição serão enviadas com o arquivo texto.
+
+Arquivo             Uso
+
+bottom              rodapé de todas as respostas. Informação geral dos comandos.
+digest              seção 'administrativa' das listas "digest".
+faq                 perguntas frequentes específicas desta lista.
+get_bad             no lugar de mensagem não encontradas no arquivo.
+help                ajuda geral (entre 'top' e 'bottom').
+info                lista informações.
+mod_help            ajuda específica para moderadores.
+mod_reject          para o remetente de uma mensagem rejeitada.
+mod_request         para os moderadores junto com a mensagem.
+mod_sub             para o assinante depois que o moderador confirma a 
+                    sua subscrição.
+mod_sub_confirm     para o moderador de subscrição requerendo a confirmação.
+mod_timeout         para o remetente de uma mensagem expirada.
+mod_unsub_confirm   para o administrador remoto confirmar o cancelamento
+                    de subscrição.
+sub_bad             para o assinante, se confirmado que a msg era inválida.
+sub_confirm         para o assinante solicitando confirmação de subscrição.
+sub_nop             para o assinante depois de re-subscrição.
+sub_ok              para o assinante depois de subscrição com sucesso.
+top                 topo de todas as respostas.
+</#tn/>
+trailer             incluído em todas as mensagens enviadas pela lista.
+</#n/>
+unsub_bad           para o assinante, se a confirmação de cancelamento
+                    é inválida.
+unsub_confirm       para assinante pedindo confirmação para o cancelamento.
+unsub_nop           para não-assinante depois de pedido de cancelamento.
+unsub_ok            para ex-assinante depois do cancelamento com sucesso.
+
+</text/edit-done#n/>
+O arquivo texto foi atualizado com sucesso.
+
+</text/info#E/>
+Ainda não há informações para esta lista.
+</text/faq#E/>
+FAQ - Questões mais freqüentes na lista <#l#>@<#H#>.
+
+Ainda não disponível.
+  
+
diff --git a/ezmlmrc.ru b/ezmlmrc.ru
new file mode 100644 (file)
index 0000000..49e6d34
--- /dev/null
@@ -0,0 +1,1015 @@
+0.324 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.ru,v 1.4 1999/12/23 23:08:19 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</charset/>
+# Charset file is a must for russian mailing lists
+koi8-r
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eI/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#iG/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#ig/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins.
+</manager#LN/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lN/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#Ln/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#ln/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Sorry, I've been told to reject your posts. Contact <#L#>-owner@<#H#> if you have questions about this (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Sorry, only subscribers may post. If you are a subscriber, please forward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mU/>
+|<#B#>/ezmlm-store '<#D#>'
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer is complicated. We use ezmlm-receipt if -6 AND -w, but ezmlm-return
+# if (-6 and -W) OR (not -6 and -w). Since there is no or, we need 2 lines.
+</bouncer/>
+|<#B#>/ezmlm-weed
+</#^6/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6W/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</#6w/>
+|<#B#>/ezmlm-receipt -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+</#^6d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6Wd/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</#6wd/>
+|<#B#>/ezmlm-receipt -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+# Only one allowed
+list-help
+list-unsubscribe
+list-post
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#i/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#L#>-help@<#H#>; run by ezmlm
+# Headeradd needs to always exist
+</headeradd#E/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+List-Post: <mailto:<#L#>@<#H#>>
+X-Comment: <#l#> mailing list (Russian, KOI8-R)
+# max & min message size
+</msgsize#x/>
+40000:2
+# remove mime parts if -x
+</mimeremove#x/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#f/>
+[<#L#>]
+</text/trailer#t/>
+-- 
+To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#>
+For additional commands, e-mail: <#L#>-help@<#H#>
+</text/bottom/>
+
+--- ëÏÍÁÎÄÙ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ---
+
+÷ÓÅ ËÏÍÁÎÄÙ ÏÂÒÁÂÁÔÙ×ÁÀÔÓÑ Á×ÔÏÍÁÔÉÞÅÓËÉ. ðÏÖÁÌÕÊÓÔÁ,
+ÎÅ ÐÏÓÙÌÁÊÔÅ ÉÈ ÎÁ ÁÄÒÅÓ ÓÁÍÏÇÏ ÓÐÉÓËÁ, ÔÁÍ ÏÎÉ ÏÂÒÁÂÏÔÁÎÙ
+ÎÅ ÂÕÄÕÔ, Á ×ÁÓ ÏÂÒÕÇÁÀÔ ÐÏÄÐÉÓÞÉËÉ. ëÏÍÁÎÄÏÊ Ñ×ÌÑÅÔÓÑ
+ÐÉÓØÍÏ (ÎÅÚÁ×ÉÓÉÍÏ ÏÔ ÅÇÏ ÓÏÄÅÒÖÁÎÉÑ), ÐÏÓÌÁÎÎÏÅ ÎÁ
+ÏÄÉΠÉÚ ÁÄÍÉÎÉÓÔÒÁÔÉ×ÎÙÈ ÁÄÒÅÓÏ×:
+
+áÄÒÅÓ ÄÌÑ ÐÏÄÐÉÓËÉ:
+   <<#L#>-subscribe@<#H#>>
+
+áÄÒÅÓ ÄÌÑ ÏÔËÁÚÁ ÏÔ ÒÁÓÓÙÌËÉ:
+   <<#L#>-unsubscribe@<#H#>>
+
+äÌÑ ÐÏÌÕÞÅÎÉÑ ÐÒÁ×ÉÌ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ É FAQ:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#d/>
+ôÁË ÖÅ ÐÏÄÄÅÒÖÉ×ÁÀÔÓÑ É ÄÁÊÄÖÅÓÔÙ:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</text/bottom#ai/>
+þÔÏÂÙ ÐÏÌÕÞÉÔØ ÓÏÏÂÝÅÎÉÑ Ó 123 ÐÏ 145 (max 100 ÎÁ ÐÉÓØÍÏ), ÐÉÛÉÔÅ ÓÀÄÁ:
+   <<#L#>-get.123_145@<#H#>>
+
+</text/bottom#aI/>
+äÌÑ ÐÏÌÕÞÅÎÉÑ ÐÉÓØÍÁ #12 ÉÚ ÁÒÈÉ×Á ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+   <<#L#>-get.12@<#H#>>
+
+</text/bottom#i/>
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÉÎÄÅËÓÁ Ó subject É Á×ÔÏÒÁÍÉ ÐÉÓÅÍ 123-456:
+   <<#L#>-index.123_456@<#H#>>
+
+# Lists need to be both archived and indexed for -thread to work
+</text/bottom#ai/>
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ×ÓÅ ÐÉÓÅÍ, Ó×ÑÚÁÎÎÙÈ Ó ÐÉÓØÍÏÍ #12345:
+   <<#L#>-thread.12345@<#H#>>
+
+# The '#' in the tag below is optional, since no flags follow.
+# The name is optional as well, since the file will always be open
+# at this point.
+</text/bottom#/>
+óÏÄÅÒÖÉÍÏÅ ÐÉÓÅÍ ÒÏÌÉ ÎÅ ÉÇÒÁÅÔ, ×ÁÖÅΠÌÉÛØ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ
+×Ù ÐÏÓÙÌÁÅÔÅ ÐÉÓØÍÏ.
+
+</text/bottom/>
+åÓÌÉ ÎÉÞÅÇÏ ÎÅ ÐÏÍÏÇÁÅÔ, ×Ù ÍÏÖÅÔÅ Ó×ÑÚÁÔØÓÑ Ó ×ÌÁÄÅÌØÃÅÍ
+ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ ÐÏ ÁÄÒÅÓÕ <#L#>-owner@<#H#>. 
+</text/bottom/>
+
+--- îÉÖÅ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÚÁÐÒÏÓÁ
+
+</text/bounce-bottom/>
+
+--- îÉÖÅ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ
+
+</text/bounce-num/>
+
+óÉÓÔÅÍÏÊ ÓÏÈÒÁÎÅΠÓÐÉÓÏË ÐÉÓÅÍ ÉÚ <#L#>, ËÏÔÏÒÙÅ ÎÅ ÄÏÛÌÉ ÄÏ
+×ÁÛÅÇÏ ÁÄÒÅÓÁ (Ô.Å. ÎÁ ÎÉÈ ÂÙÌÏ ÐÏÌÕÞÅÎÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ)
+
+</#a/>
+ëÏÐÉÉ ÜÔÉÈ ÐÉÓÅÍ ÎÁÈÏÄÑÔÓÑ × ÁÒÈÉ×Å.
+</#aI/>
+þÔÏÂÙ ÐÏÌÕÞÉÔØ ÐÉÓØÍÏ 12345 ÉÚ ÁÒÈÉ×Á, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÏÏÂÝÅÎÉÊ 123-145 (max 100 ÎÁ ÚÁÐÒÏÓ):
+   <<#L#>-get.123_145@<#H#>>
+
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÐÏÓÌÅÄÎÉÈ 100 ÓÏÏÂÝÅÎÉÊ Ó subject É Á×ÔÏÒÏÍ:
+   <<#L#>-index@<#H#>>
+
+<//>
+HÏÍÅÒÁ ÓÏÏÂÝÅÎÉÊ:
+
+</text/dig-bounce-num/>
+
+óÉÓÔÅÍÏÊ ÓÏÈÒÁÎÅÎÙ ÓÐÉÓÏË ÄÁÊÄÖÅÓÔÏ× <#L#>, ËÏÔÏÒÙÅ ÎÅ ÄÏÛÌÉ ÄÏ ×ÁÛÅÇÏ
+ÁÄÒÅÓÁ (Ô.Å. ÎÁ ÎÉÈ ÂÙÌÉ ÐÏÌÕÞÅÎÙ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ). óÁÍÉ ÄÁÊÄÖÅÓÔÙ
+ÎÅ ÈÒÁÎÑÔÓÑ, ÎÏ ÉÚ×ÅÓÔÎÙ ÎÏÍÅÒÁ ÐÉÓÅÍ × ÄÁÊÄÖÅÓÔÁÈ. ôÁËÉÍ ÏÂÒÁÚÏÍ
+ÍÏÖÎÏ ÚÁÐÒÏÓÉÔØ ÐÒÏÐÕÝÅÎÎÙÅ ÐÉÓØÍÁ ÉÚ ÁÒÈÉ×Á.
+
+</#aI/>
+þÔÏÂÙ ÐÏÌÕÞÉÔØ ÐÉÓØÍÏ 12345 ÉÚ ÁÒÈÉ×Á, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+   <<#L#>-get.12345@<#H#>>
+
+</#ia/>
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÏÏÂÝÅÎÉÊ 123-145 (max 100 ÎÁ ÚÁÐÒÏÓ):
+   <<#L#>-get.123_145@<#H#>>
+
+áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÐÏÓÌÅÄÎÉÈ 100 ÓÏÏÂÝÅÎÉÊ Ó subject É Á×ÔÏÒÏÍ:
+   <<#L#>-index@<#H#>>
+
+<//>
+ðÏÓÌÅÄÎÉÅ ÎÏÍÅÒÁ ÐÉÓÅÍ × ÄÁÊÄÖÅÓÔÁÈ:
+
+</text/bounce-probe/>
+
+óÏÏÂÝÅÎÉÑ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÎÁ ×ÁÛ ÁÄÒÅÓ
+ÐÒÉ×ÏÄÑÔ Ë ÏÛÉÂËÁÍ ÄÏÓÔÁ×ËÉ (bounce). ÷ÁÍ ÂÙÌÏ ÐÏÓÌÁÎÏ ÐÉÓØÍÏ Ó
+ÐÒÅÄÕÐÒÅÖÄÅÎÉÅÍ, ÎÏ ÏÎÏ ÔÏÖÅ ÎÅ ÂÙÌÏ ÄÏÓÔÁ×ÌÅÎÏ. ÷ ËÏÎÃÅ ÐÉÓØÍÁ
+ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ.
+
+üÔÏ ÐÉÓØÍÏ Ñ×ÌÑÅÔÓÑ ÔÅÓÔÏÍ ÎÁ ÓÕÝÅÓÔ×Ï×ÁÎÉÅ É ÁËÔÉ×ÎÏÓÔØ ×ÁÛÅÇÏ 
+ÁÄÒÅÓÁ. åÓÌÉ ÐÏÐÙÔËÁ ÄÏÓÔÁ×ÉÔØ ×ÁÍ ÜÔÏ ÐÉÓØÍÏ ÔÁË ÖÅ ÂÕÄÅÔ ÎÅÕÄÁÞÎÁ,
+×ÁÛ ÁÄÒÅÓ ÂÕÄÅÔ ÕÄÁÌÅΠÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÂÅÚ ÄÁÌØÛÅÊÛÉÈ
+ÐÒÅÄÕÐÒÅÖÄÅÎÉÊ. ðÏÄÐÉÓÁÔØÓÑ ÚÁÎÏ×Ï ÍÏÖÎÏ ÐÏ ÁÄÒÅÓÕ:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn/>
+
+óÏÏÂÝÅÎÉÑ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÎÁ ×ÁÛ ÁÄÒÅÓ
+ÐÒÉ×ÏÄÑÔ Ë ÏÛÉÂËÁÍ ÄÏÓÔÁ×ËÉ (bounce). ÷ ËÏÎÃÅ ÐÉÓØÍÁ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ
+ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ.
+
+åÓÌÉ ÜÔÏ ÐÉÓØÍÏ ÔÁË ÖÅ ÐÒÉ×ÅÄÅÔ Ë ÏÛÉÂËÅ, ×ÁÍ ÂÕÄÅÔ ×ÙÓÌÁΠÔÅÓÔ. åÓÌÉ
+ÔÅÓÔ ÔÏÖÅ ÐÒÉ×ÅÄÅÔ Ë ÏÛÉÂËÅ, ×ÁÛ ÁÄÒÅÓ ÂÕÄÅÔ ÕÄÁÌÅΠÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ
+<#l#>@<#H#> ÂÅÚ ÄÁÌØÎÅÊÛÉÈ ÐÒÅÄÕÐÒÅÖÄÅÎÉÊ.
+
+</text/digest#d/>
+áÄÒÅÓ ÄÌÑ ÐÏÄÐÉÓËÉ ÎÁ ÄÁÊÄÖÅÓÔ:
+       <#L#>-digest-subscribe@<#H#>
+
+áÄÒÅÓ ÄÌÑ ÏÔÐÉÓËÉ ÏÔ ÄÁÊÄÖÅÓÔÁ:
+       <#L#>-digest-unsubscribe@<#H#>
+
+áÄÒÅÓ ÄÌÑ ÏÔÐÒÁ×ËÉ ÐÉÓÅÍ × ÓÐÉÓÏË ÒÁÓÓÙÌËÉ:
+       <#L#>@<#H#>
+
+</text/get-bad/>
+éÚ×ÉÎÉÔÅ, ÎÏ ÔÁËÏÇÏ ÐÉÓØÍÁ × ÁÒÈÉ×Å ÎÅÔ.
+
+</text/help/>
+üÔÏ ÐÉÓØÍÏ Ñ×ÌÑÅÔÓÑ ÏÂÝÉÍ ÏÐÉÓÁÎÉÅÍ ÒÁÂÏÔÙ ezmlm.
+
+</text/mod-help/>
+óÐÁÓÉÂÏ, ÞÔÏ ×Ù ÓÏÇÌÁÓÉÌÉÓØ ÍÏÄÅÒÉÒÏ×ÁÔØ <#L#>@<#H#>.
+
+ëÏÍÁÎÄÙ ezmlm ÎÅÍÎÏÇÏ ÏÔÌÉÞÁÀÔÓÑ ÏÔ ÄÒÕÇÉÈ ÓÉÓÔÅÍ ÓÐÉÓËÏ×
+ÒÁÓÓÙÌËÉ ËÁË majordomo, listserver, etc, ÎÏ ÏÎÉ ÌÅÇËÏ
+ÚÁÐÏÍÉÎÁÀÔÓÑ É ÉÈ ÌÅÇËÏ ÉÓÐÏÌØÚÏ×ÁÔØ.
+
+HÉÖÅ ÐÒÉ×ÅÄÅÎÙ ÉÎÓÔÕËÃÉÉ ÐÏ ×ÙÐÏÌÎÅÎÉÀ ÚÁÄÁÞ, ÎÅÏÂÈÏÄÉÍÙÈ 
+×ÌÁÄÅÌØÃÕ ÓÐÉÓËÁ É/ÉÌÉ ÍÏÄÅÒÁÔÏÒÕ.
+
+õÄÁÌÅÎÎÁÑ ÐÏÄÐÉÓËÁ
+------------------
+ëÁË ÍÏÄÅÒÁÔÏÒ, ×Ù ÍÏÖÅÔÅ ÐÏÄÐÉÓÁÔØ ÉÌÉ ÏÔÐÉÓÁÔØ ÌÀÂÏÊ ÁÄÒÅÓ
+× ÓÐÉÓËÅ. äÌÑ ÐÏÄÐÉÓËÉ ÁÄÒÅÓÁ john@host.domain ÄÏÂÁ×ØÔÅ
+ÐÅÒÅÎÏÓ ÐÏÓÌÅ ËÏÍÁÎÄÙ, ÐÏÔÏÍ ÁÄÒÅÓ Ó = ×ÍÅÓÔÏ @. HÁÐÒÉÍÅÒ,
+ÄÌÑ ÐÏÄÐÉÓËÉ ×ÙÛÅÕËÁÚÁÎÎÏÇÏ ÁÄÒÅÓÁ, ÓÌÅÄÕÅÔ ÐÏÓÌÁÔØ ÐÉÓØÍÏ
+ÐÏ ÁÄÒÅÓÕ
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+ôÏÞÎÏ ÔÁË ÖÅ ÍÏÖÎÏ ÕÄÁÌÉÔØ ÁÄÒÅÓ ÉÚ ÓÐÉÓËÁ:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#d/>
+ôÏ ÖÅ ÓÁÍÏÅ ÄÌÑ ÄÁÊÄÖÅÓÔÏ×:
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+<//>
+÷ÏÔ É ×ÓÅ. HÅ ÔÒÅÂÕÅÔÓÑ ÎÉÞÅÇÏ ÚÁÐÏÌÎÑÔØ ÎÉ × subject, ÎÉ × ÔÅÌÅ ÐÉÓØÍÁ.
+
+</#r/>
+÷ÁÍ ÂÕÄÅÔ ×ÙÓÌÁΠÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÌÉ ×Ù ÈÏÔÅÌÉ
+×ÙÐÏÌÎÉÔØ ÐÏÄÐÉÓËÕ/ÏÔÐÉÓËÕ. HÁÄÏ ÐÒÏÓÔÏ ÏÔ×ÅÔÉÔØ ÎÁ ÎÅÇÏ.
+</#R/>
+âÕÄÅÔ ×ÙÓÌÁΠÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÐÏÄÐÉÓËÉ ÐÏ ÁÄÒÅÓÕ <john@host.domain>.
+ðÏÌØÚÏ×ÁÔÅÌÀ ÄÏÓÔÁÔÏÞÎÏ ÂÕÄÅÔ ÏÔ×ÅÔÉÔØ ÎÁ ÚÁÐÒÏÓ.
+<//>
+
+óÉÓÔÅÍÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÁÂÓÏÌÀÔÎÁ ÎÅÏÂÈÏÄÉÍÁ, ÞÔÏÂÙ ÎÅ ÄÁÔØ ÎÅÄÏÂÒÏÖÅÌÁÔÅÌÀ
+×ÏÚÍÏÖÎÏÓÔÉ ÄÏÂÁ×ÉÔØ ÉÌÉ ÕÄÁÌÉÔØ ÁÄÒÅÓ × ÓÐÉÓËÅ ÂÅÚ ÖÅÌÁÎÉÑ ×ÌÁÄÅÌØÃÁ
+ÁÄÒÅÓÁ.
+
+ðÏÄÐÉÓËÁ
+--------
+
+ìÀÂÏÊ ÐÏÌØÚÏ×ÁÔÅÌØ ÍÏÖÅÔ ÐÏÄÐÉÓÁÔØÓÑ ÉÌÉ ÏÔÐÉÓÁÔØÓÑ,
+ÐÏÓÌÁ× ÐÉÓØÍÏ ÎÁ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÁÄÒÅÓ:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#d/>
+äÌÑ ÄÁÊÄÖÅÓÔÏ×:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+<//>
+ðÏÌØÚÏ×ÁÔÅÌØ ÐÏÌÕÞÉÔ ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÞÔÏÂÙ ÕÂÅÄÉÔØÓÑ
+× ÔÏÍ, ÞÔÏ ÚÁÐÒÏÓ ÂÙÌ ÓÄÅÌÁΠÉÍÅÎÎÏ ÉÍ. 
+
+</#s/>
+ðÏÓËÏÌØËÕ × ÄÁÎÎÏÍ ÓÐÉÓËÅ ËÏÎÔÒÏÌÉÒÕÅÔÓÑ ÐÏÄÐÉÓËÁ/ÏÔÐÉÓËÁ,
+ÂÕÄÅÔ ×ÙÓÌÁΠÄÏÐÏÌÎÉÔÅÌØÎÙÊ ÚÁÐÒÏÓ ÍÏÄÅÒÁÔÏÒÕ. ðÏÓËÏÌØËÕ
+ÐÏÌØÚÏ×ÁÔÅÌØ ÕÖÅ ÐÏÄÔ×ÅÒÄÉÌ Ó×ÏÅ ÖÅÌÁÎÉÅ, ×Ù, ËÁË ÍÏÄÅÒÁÔÏÒ,
+ÍÏÖÅÔÅ ÂÙÔØ Õ×ÅÒÅÎÙ, ÞÔÏ ÜÔÏ ÉÍÅÎÎÏ ÅÇÏ ÖÅÌÁÎÉÅ, Á ÁÄÒÅÓ
+ÒÁÂÏÔÁÀÝÉÊ. åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ Ó ÐÏÄÐÉÓËÏÊ ÄÁÎÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÑ,
+ÐÒÏÓÔÏ ÐÏÛÌÉÔÅ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ. åÓÌÉ ÎÅÔ, ÔÏ ÓÏÔÒÉÔÅ
+ÅÇÏ É ×ÓÅ.
+
+</#S/>
+ïÔÐÉÓËÁ ÒÁÂÏÔÁÅÔ ÔÁËÉÍ ÖÅ ÏÂÒÁÚÏÍ.
+<//>
+
+ðÏÌØÚÏ×ÁÔÅÌØ ÔÁË ÖÅ ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÁÄÒÅÓÁ:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+ÄÌÑ ÐÏÄÐÉÓËÉ mary@host.domain. óÐÉÓÏË ÂÕÄÅÔ ÉÚÍÅÎÅΠÔÏÌØËÏ ÅÓÌÉ
+ËÔÏ-ÔÏ ÎÁ ÜÔÏÍ ÁÄÒÅÓÅ ÏÔ×ÅÔÉÔ ÎÁ ÚÁÐÒÏÓ.
+
+÷ÁÛ ÁÄÒÅÓ É ÐÒÏÞÁÑ ÉÎÆÏÒÍÁÃÉÑ ÎÅ ÂÕÄÕÔ ÄÏÓÔÕÐÎÙ ÐÏÄÐÉÓÞÉËÕ, ÒÁÚ×Å
+ÞÔÏ ×Ù ÐÏÛÌÅÔÅ ÏÔÄÅÌØÎÏÅ ÐÉÓØÍÏ ÅÍÕ ÎÁÐÒÑÍÕÀ.
+
+</#rl/>
+þÔÏÂÙ ÐÏÌÕÞÉÔØ ÓÐÉÓÏË ÐÏÄÐÉÓÞÉËÏ× <#L#>@<#H#>, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÓÀÄÁ:
+   <<#L#>-list@<#H#>>
+
+þÔÏÂÙ ÐÏÌÕÞÉÔØ ÌÏÇ ÔÒÁÎÚÁËÃÉÊ <#L#>@<#H#>, ÐÉÛÉÔÅ ÓÀÄÁ:
+   <<#L#>-log@<#H#>>
+
+</#rld/>
+äÌÑ ÄÁÊÄÖÅÓÔÏ×:
+   <<#L#>-digest-list@<#H#>>
+É:
+   <<#L#>-digest-log@<#H#>>
+
+</#rn/>
+÷Ù ÍÏÖÅÔÅ ÒÅÄÁËÔÉÒÏ×ÁÔØ ÐÏ ÐÏÞÔÅ ÔÅËÓÔÏ×ÙÅ ÆÁÊÌÙ ËÏÎÆÉÇÕÒÁÃÉÉ
+ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ. äÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÆÁÊÌÏ× É ÉÎÓÔÒÕËÃÉÊ ÐÏ
+ÒÅÄÁËÔÉÒÏ×ÁÎÉÀ, ÐÉÛÉÔÅ ÓÀÄÁ:
+   <<#L#>-edit@<#H#>>
+
+</#m/>
+íÏÄÅÒÉÒÏ×ÁÎÉÅ
+-------------
+ëÏÇÄÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ ÍÏÄÅÒÉÒÕÅÔÓÑ, ÐÉÓØÍÁ ÓÏÈÒÁÎÑÀÔÓÑ É ×ÓÅÍ
+ÍÏÄÅÒÁÔÏÒÁÍ ÐÏÓÙÌÁÅÔÓÑ ËÏÐÉÑ ÐÉÓØÍÁ Ó ÉÎÓÔÒÕËÃÉÅÊ. Subject ÓÏÄÅÒÖÉÔ
+ÓÔÒÏËÕ "MODERATE for ...".
+
+ðÉÓØÍÏ ÓÏÄÅÒÖÉÔ Ä×Á ÚÁÇÏÌÏ×ËÁ: "From:" É "Reply-To:". ôÁËÉÍ ÏÂÒÁÚÏÍ,
+ËÏÇÄÁ ×Ù ÎÁ ÎÅÇÏ ÏÔ×ÅÞÁÅÔÅ, ×ÁÛÁ ÐÏÞÔÏ×ÁÑ ÐÒÏÇÒÁÍÍÁ ÄÏÌÖÎÁ ÓÐÒÏÓÉÔØ,
+ÎÁ ËÁËÏÊ ÉÚ ÁÄÒÅÓÏ× ÏÔ×ÅÞÁÔØ. ïÔ×ÅÔ ÎÁ ÁÄÒÅÓ × Reply-To: ÐÒÉ×ÅÄÅÔ
+Ë ÔÏÍÕ, ÞÔÏ ÉÓÈÏÄÎÏÅ ÐÉÓØÍÏ ÂÕÄÅÔ ÐÒÏÐÕÝÅÎÏ × ÓÐÉÓÏË ÒÁÓÓÙÌËÉ. 
+ïÔ×ÅÔ ÎÁ "From:" ÐÒÉ×ÅÄÅÔ Ë ÏÔËÁÚÕ. ïÂÙÞÎÏ ÐÒÏÇÒÁÍÍÙ ÓÐÒÁÛÉ×ÁÀÔ
+"äÁ/ÎÅÔ", Ô.Å. ×Ù ÐÒÏÓÔÏ ÒÅÛÁÅÔÅ, ÐÒÏÐÕÓËÁÔØ ÉÌÉ ÎÅÔ, ÎÁÖÉÍÁÅÔÅ
+ÏÔ×ÅÔ É ×ÙÂÉÒÁÅÔÅ "ÄÁ" ÉÌÉ "ÎÅÔ". óÏÄÅÒÖÉÍÏÅ ×ÁÛÅÇÏ ÐÉÓØÍÁ
+ÐÒÁËÔÉÞÅÓËÉ ÉÇÎÏÒÉÒÕÅÔÓÑ -- ÚÎÁÞÅÎÉÅ ÉÍÅÀÔ ÔÏÌØËÏ ÁÄÒÅÓÁ, ÏÄÎÁËÏ
+ÐÒÉ ÏÔËÁÚÅ ÍÏÖÎÏ ×ÓÔÁ×ÉÔØ × ÔÅÌÏ ÐÉÓØÍÁ ÔÅËÓÔ ÍÅÖÄÕ Ä×ÕÍÑ ÓÔÒÏËÁÍÉ,
+ÎÁÞÉÎÁÀÝÉÍÉÓÑ Ó ÓÉÍ×ÏÌÏ× %. üÔÏÔ ÔÅËÓÔ ÂÕÄÅÔ ÐÏÓÌÁΠÏÔÐÒÁ×ÉÔÅÌÀ 
+ÐÉÓØÍÁ, ÎÅ ÏÔËÒÙ×ÁÑ ËÔÏ ÉÚ ÍÏÄÅÒÁÔÏÒÏ× ÅÇÏ ÐÏÓÌÁÌ. HÁÐÒÉÍÅÒ:
+
+%%% Start comment
+×ÁÛÅ ÐÉÓØÍÏ ÓÏÄÅÒÖÉÔ ÍÁÔ
+%%% End comment
+
+åÓÌÉ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ ÐÒÏÇÒÁÍÍÁ ÕÍÅÅÔ ÒÁÂÏÔÁÔØ Ó ÔÅÍÐÌÅÊÔÁÍÉ (ÎÁÐÒÉÍÅÒ,
+The Bat!), ÔÏ ÜÔÉ ÓÔÒÏËÉ ÓÔÏÉÔ ÄÏÂÁ×ÉÔØ × ÔÅÍÐÌÅÊÔ ÏÔ×ÅÔÁ.
+
+úÁÐÒÏÓÙ ÎÁ ÍÏÄÅÒÉÒÏ×ÁÎÉÅ ÏÂÒÁÂÁÔÙ×ÁÀÔÓÑ ÐÏ ÐÅÒ×ÏÍÕ ÐÉÓØÍÕ ÏÔ ÍÏÄÅÒÁÔÏÒÁ,
+ÓÒÅÁÇÉÒÏ×Á×ÛÅÇÏ ÒÁÎØÛÅ. åÓÌÉ ËÔÏ-ÔÏ ÉÚ ÍÏÄÅÒÁÔÏÒÏ× ÐÏÚÖÅ ÐÏÛÌÅÔ ÏÔ×ÅÔ
+Ó ÐÒÏÔÉ×ÏÐÏÌÏÖÎÙÍ ÒÅÛÅÎÉÅÍ, ÅÍÕ ÂÕÄÅÔ ÓÏÏÂÝÅÎÏ Ï ÔÏÍ, ÞÔÏ ÕÖÅ ÐÒÏÉÚÏÛÌÏ
+Ó ÄÁÎÎÙÍ ÐÉÓØÍÏÍ.
+
+åÓÌÉ × ÔÅÞÅÎÉÉ ÎÅÓËÏÌØËÉÈ ÄÎÅÊ ÎÅ ÂÕÄÅÔ ÐÏÌÕÞÅÎÏ ÏÔ×ÅÔÁ ÎÉ ÏÔ ÏÄÎÏÇÏ
+ÍÏÄÅÒÁÔÏÒÁ, ÏÔÐÒÁ×ÉÔÅÌÀ ÂÕÄÅÔ ÐÏÓÌÁÎÏ Õ×ÅÄÏÍÌÅÎÉÅ Ï ÚÁÄÅÒÖËÅ. ôÁË ÖÅ,
+ÁÄÍÉÎÉÓÔÒÁÔÏÒ ÓÐÉÓËÁ ÍÏÖÅÔ ÚÁÐÒÅÔÉÔØ ÏÔÓÙÌËÕ ÐÏÄÏÂÎÙÈ Õ×ÅÄÏÍÌÅÎÉÊ.
+<//>
+
+ëÁÎÉËÕÌÙ
+--------
+åÓÌÉ ×Ù ÄÏÌÖÎÙ ÓÒÏÞÎÏ ÐÏËÉÎÕÔØ Ó×ÏÊ ÌÀÂÉÍÙÊ ÇÏÒÏÄ, Á ÔÁÍ, ËÕÄÁ
+×Ù ÓÏÂÒÁÌÉÓØ, ÉÎÔÅÒÎÅÔÁ ÎÅÔ É ÎÅ ÐÒÅÄ×ÉÄÉÔÓÑ, ×Ù ÍÏÖÅÔÅ ÎÁ ×ÒÅÍÑ
+×ËÌÀÞÉÔØ Á×ÔÏÍÁÔÉÞÅÓËÉÊ ÐÒÏÐÕÓË ÐÉÓÅÍ × ÓÐÉÓÏË. ïÄÎÁËÏ ×Ï ÍÎÏÇÉÈ
+ÓÐÉÓËÁÈ ÐÏÄÏÂÎÙÅ ÄÅÊÓÔ×ÉÑ ÍÏÇÕÔ ÐÒÉ×ÅÓÔÉ Ë ÂÁÒÄÁËÕ.
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÐÏÓÔÁ×ÉÔØ Á×ÔÏÏÔ×ÅÔÞÉË ÎÁ ×ÁÛÅÍ ÁÄÒÅÓÅ,
+ÏÔÐÒÁ×ÌÑÀÝÉÊ ×ÓÅ ÐÉÓØÍÁ Ó subject "MODERATE for .." ÎÁ ÁÄÒÅÓ × 
+ÚÁÇÏÌÏ×ËÅ "Reply-To:". Hå òåëïíåHäõåôóñ. 
+
+</#r/>
+åÓÌÉ ×Ù ÐÏÐÒÏÂÕÅÔÅ ÐÏÓÌÁÔØ ÁÄÍÉÎÓÔÒÁÔÉ×ÎÙÊ ÚÁÐÒÏÓ ÎÅ Ó Ó×ÏÅÇÏ ÁÄÒÅÓÁ,
+ÔÏ ÐÏÄÐÉÓÞÉË, Á ÎÅ ×Ù ÂÕÄÅÔ ÓÐÒÏÛÅÎ, ÐÏÄÐÉÓÙ×ÁÔØ ÉÌÉ ÎÅÔ. üÔÏ ÓÄÅÌÁÎÏ
+ÄÌÑ ÔÏÇÏ, ÞÔÏÂÙ ÎÉËÔÏ ÎÅ ÐÏÓÌÁÌ ÐÏÄÄÅÌØÎÙÊ ÚÁÐÒÏÓ ÎÁ ÐÏÄÐÉÓËÕ 
+ÏÔ ×ÁÛÅÇÏ ÁÄÒÅÓÁ, ÐÏÄÐÉÓÁ× Ó×ÏÅÇÏ ×ÒÁÇÁ ÎÁ ×ÙÓÏËÏÔÒÁææÉËÏ×ÙÊ ÓÐÉÓÏË
+ÒÁÓÓÙÌËÉ.
+
+<//>
+
+õÄÁÞÉ!
+
+PS: ÷ ÓÌÕÞÁÅ ÐÒÏÂÌÅÍ Ó×ÑÚÙ×ÁÊÔÅÓØ Ó ×ÌÁÄÅÌØÃÅÍ ÓÐÉÓËÁ 
+ÒÁÓÓÙÌËÉ (<#L#>-owner@<#H#>).
+
+</text/mod-reject/>
+éÚ×ÉÎÉÔÅ, ÎÏ ×ÁÛÅ ÐÉÓØÍÏ (ÎÉÖÅ ÐÒÉ×ÅÄÅÎÎÏÅ) ÎÅ ÂÙÌÏ ÐÒÏÐÕÝÅÎÏ ×
+ÓÐÉÓÏË ÍÏÄÅÒÁÔÏÒÏÍ. åÓÌÉ ÍÏÄÅÒÁÔÏÒ ÈÏÔÅÌ(Á) ÓÏÏÂÝÉÔØ ÞÔÏ-ÌÉÂÏ ×ÁÍ
+ÐÏ ÐÏ×ÏÄÕ ×ÁÛÅÇÏ ÐÉÓØÍÁ, ËÏÍÍÅÎÔÁÒÉÉ ÂÕÄÕÔ ÐÒÉ×ÅÄÅÎÙ ÎÉÖÅ.
+</text/mod-request/>
+HÉÖÅÐÒÉ×ÅÄÅÎÎÏÅ ÐÉÓØÍÏ ÂÙÌÏ ÏÔÐÒÁ×ÌÅÎÏ × ÓÐÉÓÏË <#L#>@<#H#>
+åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ ÅÇÏ ÐÒÏÐÕÓÔÉÔØ, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!A
+
+ïÂÙÞÎÏ ÄÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ" ÄÌÑ
+ÄÁÎÎÏÇÏ ÐÉÓØÍÁ. ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ, ÞÔÏÂÙ × ÐÏÌÅ "To:" ÂÙÌ ÔÏÌØËÏ
+ÏÄÉΠÁÄÒÅÓ. åÓÌÉ ÜÔÏ ÎÅ ÓÒÁÂÏÔÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÁÄÒÅÓ × clipboard É
+×ÓÔÁ×ØÔÅ ÅÇÏ × ÐÏÌÅ "To:". 
+</#x/>
+<//>
+
+äÌÑ ÏÔËÁÚÁ ÏÔ ÐÒÏÐÕÓËÁ ÐÉÓØÍÁ É ÓÏÏÂÝÅÎÉÑ Ï ÜÔÏÍ ÐÉÛÕÝÅÍÕ ÐÏÛÌÉÔÅ
+ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ
+
+!R
+</#x/>
+<//>
+
+÷ÁÍ ÎÅ ÎÕÖÎÏ ËÏÐÉÒÏ×ÁÔØ ÔÅÌÏ ÉÓÈÏÄÎÏÇÏ ÐÉÓØÍÁ. äÌÑ ÔÏÇÏ, ÞÔÏÂÙ ÐÏÓÌÁÔØ
+×ÁÛ ËÏÍÍÅÎÔÁÒÉÊ ÐÏ ÐÏ×ÏÄÕ ÔÏÇÏ, ÐÏÞÅÍÕ ÐÉÓØÍÏ ÎÅ ÂÙÌÏ ÐÒÏÐÕÝÅÎÏ,
+×ÓÔÁ×ØÔÅ ×ÁÛ ÔÅËÓÔ ÍÅÖÄÕ Ä×ÕÍÑ ÓÔÒÏËÁÍÉ Ó %%%.
+
+%%% Start comment
+%%% End comment
+
+ëÏÍÍÅÎÔÁÒÉÉ ÄÏÌÖÎÙ ÎÁÞÉÎÁÔØÓÑ Ó ÎÁÞÁÌÁ ÓÔÒÏËÉ.
+
+--- éÓÈÏÄÎÏÅ ÐÉÓØÍÏ × ÓÐÉÓÏË.
+
+</text/mod-sub#E/>
+--- ÷ÁÓ ÐÏÄÐÉÓÁÌÉ ÉÌÉ ÏÔÐÉÓÁÌÉ ÐÏ ÚÁÐÒÏÓÕ ÍÏÄÅÒÁÔÏÒÁ 
+ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>.
+
+åÓÌÉ ×Ù ÜÔÏÇÏ ÎÅ ÈÏÔÅÌÉ, ×Ù ÍÏÖÅÔÅ ÎÁÐÉÓÁÔØ ÖÁÌÏÂÕ
+×ÌÁÄÅÌØÃÕ ÓÐÉÓËÁ ÐÏ ÁÄÒÅÓÕ <#l#>-owner@<#H#>.
+
+åÓÌÉ ×ÁÓ ÉÎÔÅÒÅÓÕÅÔ ÉÎÆÏÒÍÁÃÉÑ Ï ÓÐÉÓËÅ ÒÁÓÓÙÌËÉ <#L#>,
+ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ <#l#>-help@<#H#>.
+
+</text/mod-timeout/>
+éÚ×ÉÎÉÔÅ, ÎÏ ÍÏÄÅÒÁÔÏÒ(Ù) ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#L#>@<#H#>
+ÎÅ ÐÒÅÄÐÒÉÎÉÍÁÀÔ ÄÅÊÓÔ×ÉÊ ÄÌÑ ÐÒÏÐÕÓËÁ ÉÌÉ ÏÔËÁÚÁ ÐÏ ÐÏ×ÏÄÕ 
+×ÁÛÅÇÏ ÐÉÓØÍÁ × ÓÐÉÓÏË.
+
+--- éÓÈÏÄÎÏÅ ÐÉÓØÍÏ.
+
+</text/mod-sub-confirm/>
+üÔÏ ÚÁÐÒÏÓ ×ÁÛÅÇÏ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÄÏÂÁ×ÌÅÎÉÅ ÁÄÒÅÓÁ
+
+!A
+
+× ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>. 
+úÁÐÒÏÓ ÐÒÏÉÚÏÛÅÌ ÐÏÔÏÍÕ, ÞÔÏ ×Ù (ÉÌÉ ÎÅ ×Ù) ÐÏÐÙÔÁÌÉÓØ 
+ÐÏÄÐÉÓÁÔØ ×ÁÛ ÁÄÒÅÓ ÎÁ ×ÙÛÅÕÐÏÍÑÎÕÔÙÊ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ.
+
+äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÐÏÄÐÉÓËÉ, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ".
+åÓÌÉ ÜÔÏ ÎÅ ÓÒÁÂÏÔÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÁÄÒÅÓ × clipboard É 
+×ÓÔÁ×ØÔÅ ÅÇÏ × ÐÏÌÅ "To:".
+</#x/>
+<//>
+
+åÓÌÉ ×Ù ÎÅ ÈÏÔÉÔÅ ÐÏÄÐÉÓÙ×ÁÔØÓÑ, ÐÒÏÓÔÏ ÎÅ ÏÔ×ÅÞÁÊÔÅ ÎÁ ÜÔÏ ÐÉÓØÍÏ.
+
+</text/mod-unsub-confirm/>
+úÁÐÒÏÓ ÎÁ ÒÁÚÒÅÛÅÎÉÅ ÕÄÁÌÅÎÉÑ
+
+!A
+
+ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>. åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ, 
+ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ".
+åÓÌÉ ÜÔÏ ÎÅ ÐÏÍÏÇÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÔÅËÓÔ É ×ÓÔÁ×ØÔÅ ÅÇÏ × 
+ÐÏÌÅ "To:" ÎÏ×ÏÇÏ ÐÉÓØÍÁ.
+</#x/>
+<//>
+
+åÓÌÉ ×Ù ÎÅ ÓÏÇÌÁÓÎÙ, ÉÇÎÏÒÉÒÕÊÔÅ ÜÔÏ ÐÉÓØÍÏ.
+
+</text/sub-bad/>
+ïÊ. ëÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÎÅËÏÒÒÅËÔÅÎ.
+
+óËÏÒÅÅ ×ÓÅÇÏ ÐÒÏÛÌÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅ ÐÏÌÕÞÅÎÉÑ ×ÁÍÉ
+ÚÁÐÒÏÓÁ. íÁËÓÉÍÕÍ 10 ÄÎÅÊ. ôÁË ÖÅ ×ÏÚÍÏÖÎÏ, ÞÔÏ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ
+ÐÒÏÇÒÁÍÍÁ ÓßÅÌÁ ÞÁÓÔØ ÁÄÒÅÓÁ, ËÏÔÏÒÙÊ É ÓÏÄÅÒÖÉÔ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ.
+
+äÌÑ ×ÁÓ ÓÏÚÄÁΠÎÏ×ÙÊ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. þÔÏÂÙ ÏÄÏÂÒÉÔØ ÐÏÄÐÉÓËÕ
+
+!A
+
+ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ
+ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+</#x/>
+<//>
+
+ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ ×Ù ÐÏÓÙÌÁÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ.
+
+</text/sub-confirm/>
+äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÐÏÄÐÉÓËÉ ÁÄÒÅÓÁ
+
+!A
+
+ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ".
+</#x/>
+<//>
+
+üÔÏ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÎÅÏÂÈÏÄÉÍÏ ÐÏ Ä×ÕÍ ÐÒÉÞÉÎÁÍ. ÷Ï-ÐÅÒ×ÙÈ, ÐÒÏ×ÅÒÑÅÔÓÑ,
+ÄÏÈÏÄÉÔ ÌÉ ÐÏÞÔÁ ÄÏ ×ÁÛÅÇÏ ÁÄÒÅÓÁ. ÷Ï-×ÔÏÒÙÈ, ÜÔÏ ÚÁÝÉÝÁÅÔ ×ÁÓ ÏÔ
+ÐÏÄÐÉÓËÉ, ÅÓÌÉ ËÔÏ-ÔÏ ÐÏÛÌÅÔ ÐÉÓØÍÏ Ó ÐÏÄÄÅÌÁÎÎÙÍ ×ÁÛÉÍ ÉÓÈÏÄÎÙÍ ÁÄÒÅÓÏÍ.
+
+</#q/>
+HÅËÏÔÏÒÙÅ ÓÔÁÒÙÅ ÐÏÞÔÏ×ÙÅ ÐÒÏÇÒÁÍÍÙ ÎÅ ÍÏÇÕÔ ÓÐÒÁ×ÉÔÓÑ Ó ÄÌÉÎÎÙÍÉ
+ÁÄÒÅÓÁÍÉ. åÓÌÉ ×Ù ÎÅ ÍÏÖÅÔÅ ÐÏÓÌÁÔØ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ, ÐÏÛÌÉÔÅ
+ÏÔ×ÅÔ ÎÁ <<#L#>-request@<#H#>> É ×ÓÔÁ×ØÔÅ 
+×ÅÓØ ÁÄÒÅÓ × ÐÏÌÅ subject.
+
+</text/sub-confirm#s/>
+üÔÏÔ ÓÐÉÓÏË ÍÏÄÅÒÉÒÕÅÍÙÊ. ëÏÇÄÁ ×Ù ÐÏÛÌÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÍÏÄÅÒÁÔÏÒ(Ù)
+ÂÕÄÕÔ ÉÚ×ÅÝÅÎÙ Ï ÜÔÏÍ. ÷ ÓÌÕÞÁÅ ÏÄÏÂÒÅÎÉÑ ×ÁÛÅÊ ÐÏÄÐÉÓËÉ ÍÏÄÅÒÁÔÏÒÁÍ
+×ÁÍ ÂÕÄÅÔ ÓÏÏÂÝÅÎÏ.
+
+</text/sub-nop/>
+ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ
+
+!A
+
+ÕÖÅ ÐÏÄÐÉÓÁΠÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>.
+
+</text/sub-ok#E/>
+ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ
+
+!A
+
+ÐÏÄÐÉÓÁΠÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>.
+
+äÏÂÒÏ ÐÏÖÁÌÏ×ÁÔØ!
+
+ðÏÖÁÌÕÊÓÔÁ, ÓÏÈÒÁÎÉÔÅ ÜÔÏ ÐÉÓØÍÏ, ÞÔÏÂÙ ÎÅ ÚÁÂÙÔØ ÁÄÒÅÓ, ËÏÔÏÒÙÊ
+×Ù ÐÏÄÐÉÓÁÌÉ ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ. þÅÒÅÚ ÐÏÌÇÏÄÁ ×Ù ÅÇÏ ÏÂÑÚÁÔÅÌØÎÏ
+ÚÁÂÕÄÅÔÅ, Á ÏÔËÁÚÁÔØÓÑ ÏÔ ÐÏÄÐÉÓËÉ, ÎÅ ÚÎÁÑ ÉÓÈÏÄÎÙÊ ÁÄÒÅÓ, ÂÕÄÅÔ
+ÏÞÅÎØ ÔÒÕÄÎÏ.
+
+</text/top/>
+äÏÂÒÙÊ ÄÅÎØ/ÕÔÒÏ/×ÅÞÅÒ! üÔÏ ÓÏÏÂÝÅÎÉÅ ÏÔ ÐÒÏÇÒÁÍÍÙ ezmlm,
+ÚÁ×ÅÄÕÀÝÅÊ ÓÐÉÓËÏÍ ÒÁÓÓÙÌËÉ <#l#>@<#H#>.
+
+</#x/>
+ó×ÑÚÁÔØÓÑ Ó ×ÌÁÄÅÌØÃÅÍ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ ÍÏÖÎÏ ÐÏ ÁÄÒÅÓÕ
+<#l#>-owner@<#H#>.
+
+</text/unsub-bad/>
+ïÊ. ëÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÎÅËÏÒÒÅËÔÅÎ.
+
+óËÏÒÅÅ ×ÓÅÇÏ ÐÒÏÛÌÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅ ÐÏÌÕÞÅÎÉÑ ×ÁÍÉ
+ÚÁÐÒÏÓÁ. íÁËÓÉÍÕÍ 10 ÄÎÅÊ. ôÁË ÖÅ ×ÏÚÍÏÖÎÏ, ÞÔÏ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ
+ÐÒÏÇÒÁÍÍÁ ÓßÅÌÁ ÞÁÓÔØ ÁÄÒÅÓÁ, ËÏÔÏÒÙÊ É ÓÏÄÅÒÖÉÔ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ.
+
+äÌÑ ×ÁÓ ÓÏÚÄÁΠÎÏ×ÙÊ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. þÔÏÂÙ ÏÄÏÂÒÉÔØ ÕÄÁÌÅÎÉÅ
+ÁÄÒÅÓÁ
+
+!A
+
+ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+</#x/>
+<//>
+
+ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ ×Ù ÐÏÓÙÌÁÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ.
+
+</text/unsub-confirm/>
+äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÕÄÁÌÅÎÉÑ ÁÄÒÅÓÁ
+
+!A
+
+ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ:
+
+!R
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ".
+</#x/>
+<//>
+
+÷ÎÉÍÁÎÉÅ! þÔÏÂÙ ÕÚÎÁÔØ, ÐÏÄ ËÁËÉÍ ÁÄÒÅÓÏÍ ×Ù ÐÏÄÐÉÓÁÎÙ ÎÁ ÓÐÉÓÏË
+ÒÁÓÓÙÌËÉ, ÚÁÇÌÑÎÉÔÅ × ÚÁÇÏÌÏ×ËÉ ÏÄÎÏÇÏ ÉÚ ÐÉÓÅÍ ÉÚ ÓÐÉÓËÁ. ÷
+ËÁÖÄÏÍ ÐÉÓØÍÅ ÅÓÔØ ÚÁÇÏÌÏ×ÏË "Return-Path:", ×ÎÕÔÒÉ ËÏÔÏÒÇÏ
+ÎÁÈÏÄÉÔÓÑ ÁÄÒÅÓ ÐÏÌÕÞÁÔÅÌÑ. HÁÐÒÉÍÅÒ, ÐÒÉ ÁÄÒÅÓÅ vassily.pupkin@usa.net
+ÚÁÇÏÌÏ×ÏË ÂÕÄÅÔ ×ÙÇÌÑÄÅÔØ ÔÁË:
+Return-Path: <<#l#>-return-<ÞÉÓÌÏ>-vassily.pupkin=usa.net@<#H#>
+
+</#q/>
+HÅËÏÔÏÒÙÅ ÓÔÁÒÙÅ ÐÏÞÔÏ×ÙÅ ÐÒÏÇÒÁÍÍÙ ÎÅ ÍÏÇÕÔ ÓÐÒÁ×ÌÑÔØÓÑ Ó ÄÌÉÎÎÙÍÉ
+ÁÄÒÅÓÁÍÉ. åÓÌÉ ×Ù ÎÅ ÍÏÖÅÔÅ ÐÏÓÌÁÔØ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ, ÐÏÛÌÉÔÅ
+ÏÔ×ÅÔ ÎÁ <<#L#>-request@<#H#>> É ×ÓÔÁ×ØÔÅ 
+×ÅÓØ ÁÄÒÅÓ × ÐÏÌÅ subject.
+
+</text/unsub-nop/>
+÷ÎÉÍÁÎÉÅ: ÁÄÒÅÓ
+
+!A
+
+ÎÅ ÐÏÄÐÉÓÁΠÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>!
+
+åÓÌÉ ×Ù ÏÔÐÉÓÙ×ÁÅÔÅÓØ ÏÔ ÓÐÉÓËÁ, ÎÏ ÐÒÏÄÏÌÖÁÅÔÅ ÐÏÌÕÞÁÔØ ÓÏÏÂÝÅÎÉÑ,
+ÚÎÁÞÉÔ ×Ù ÐÏÄÐÉÓÁÎÙ ÐÏÄ ÄÒÕÇÉÍ ÁÄÒÅÓÏÍ. HÁÊÄÉÔÅ ÚÁÇÏÌÏ×ÏË ×ÉÄÁ
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+× ÏÄÎÏÍ ÉÚ ÔÁËÉÈ ÐÉÓÅÍ. äÌÑ ÏÔÐÉÓËÉ ÎÁÄÏ ÂÕÄÅÔ ÐÏÓÌÁÔØ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ
+'<#l#>-unsubscribe-user=host.dom@<#H#>'. ðÒÏÓÔÏ ÓÆÏÒÍÉÒÕÊÔÅ ÔÁËÏÊ
+ÁÄÒÅÓ, ÚÁÍÅÎÉ× user=host.dom ÎÁ ×ÁÛÉ ÒÅÁÌØÎÙÅ ÄÁÎÎÙÅ (ÐÏÄÓÔÁ×É× ÓÉÍ×ÏÌ
+= ×ÍÅÓÔÏ @) É ÏÔ×ÅÔØÔÅ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ.
+
+</text/unsub-ok/>
+ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ
+
+!A
+
+ÕÄÁÌÅΠÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>.
+
+</text/edit-do#n/>
+ðÏÖÁÌÕÊÓÔÁ, ÏÔÒÅÄÁËÔÉÒÕÊÔÅ ÎÉÖÅÐÒÉ×ÅÄÅÎÎÙÊ ÆÁÊÌ É ÏÔÐÒÁ×ØÔÅ ÅÇÏ
+ÐÏ ÁÄÒÅÓÕ:
+
+!R
+
+äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ".
+
+óÉÍ×ÏÌÙ Ë×ÏÔÉÎÇÁ ÂÕÄÕÔ ÕÄÁÌÅÎÙ ÉÚ ÐÉÓØÍÁ Á×ÔÏÍÁÔÉÞÅÓËÉ, ÅÓÌÉ
+×Ù ÎÅ ÂÕÄÅÔÅ ÔÒÏÇÁÔØ ÓÔÒÏËÉ Ó ÍÁÒËÅÒÁÍÉ. íÁÒËÅÒÙ -- ÓÔÒÏËÉ,
+ÎÁÞÉÎÁÀÝÉÅÓÑ Ó %%%. 
+
+</text/edit-list#n/>
+áÄÒÅÓ <#L#>-edit.file ÐÒÅÄÎÁÚÎÁÞÅΠÄÌÑ ÕÄÁÌÅÎÎÏÇÏ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ
+ÔÅËÓÔÏ×ÙÈ ÆÁÊÌÏ×, ËÏÔÏÒÙÅ Ñ×ÌÑÀÔÓÑ ÛÁÂÌÏÎÁÍÉ ÏÔ×ÅÔÏ× ÓÐÉÓËÁ
+ÒÁÓÓÙÌËÉ <#L#>@<#H#>.
+
+îÉÖÅ ÐÒÉ×ÅÄÅΠÓÐÉÓÏË ÉÍÅΠÆÁÊÌÏ× É ËÏÒÏÔËÏÅ ÏÐÉÓÁÎÉÅ ÆÕÎËÃÉÊ
+ËÁÖÄÏÇÏ ÉÚ ÎÉÈ. äÌÑ ÒÅÄÁËÔÉÒÏ×ÁÎÉÑ ËÁËÏÇÏ-ÌÉÂÏ ÉÚ ÜÔÉÈ ÆÁÊÌÏ×
+ÐÒÏÓÔÏ ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ #L#>-edit.ÉÍÑÆÁÊÌÁ. ÷ÁÍ ÂÕÄÅÔ
+×ÙÓÌÁÎÏ ÔÅËÕÝÅÅ ÓÏÄÅÒÖÉÍÏÅ ÆÁÊÌÁ É ÄÁÌØÎÅÊÛÉÅ ÉÎÓÔÒÕËÃÉÉ ÐÏ 
+ÒÅÄÁËÔÉÒÏ×ÁÎÉÀ.
+
+æÁÊÌ                îÁÚÎÁÞÅÎÉÅ
+
+bottom              ÎÉÖÎÑÑ ÞÁÓÔØ ÏÔ×ÅÔÁ, ÏÂÝÁÑ ÉÎÆÏÒÍÁÃÉÑ.
+digest              'ÁÄÍÉÎÉÓÔÒÁÔÉ×ÎÁÑ' ÞÁÓÔØ ÄÌÑ ÄÁÊÄÖÅÓÔÏ×.
+faq                 ÞÁÓÔÏ ÚÁÄÁ×ÁÅÍÙÅ ×ÏÐÒÏÓÙ É ÏÔ×ÅÔÙ ÄÌÑ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ.
+get_bad             ÓÏÏÂÝÅÎÉÅ Ï ÏÔÓÕÔÓÔ×ÉÉ ÐÉÓØÍÁ × ÁÒÈÉ×Å.
+help                ÏÂÝÉÊ ÔÅËÓÔ (ÍÅÖÄÕ 'top' É 'bottom').
+info                ÉÎÆÏÒÍÁÃÉÑ Ï ÓÐÉÓËÅ. ðÅÒ×ÁÑ ÓÔÒÏËÁ Ñ×ÌÑÅÔÓÑ ÚÁÇÏÌÏ×ËÏÍ.
+mod_help            ×ÓÅ ÐÒÏ ÍÏÄÅÒÉÒÏ×ÁÎÉÅ ÄÁÎÎÏÇÏ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ.
+mod_reject          ÔÅËÓÔ ÏÔËÁÚÁ × ÐÏÓÔÉÎÇÅ ÓÏÏÂÝÅÎÉÑ.
+mod_request         ÔÅËÓÔ ÚÁÐÒÏÓÁ ÎÁ ÍÏÄÅÒÁÃÉÀ ÐÉÓØÍÁ.
+mod_sub             ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÍÏÄÅÒÉÒÕÅÍÏÊ ÐÏÄÐÉÓËÉ.
+mod_sub_confirm     ÚÁÐÒÏÓ ÍÏÄÅÒÁÔÏÒÕ Ï ÐÏÄÐÉÓËÅ ÐÏÌØÚÏ×ÁÔÅÌÑ.
+mod_timeout         ÓÏÏÂÝÅÎÉÅ Ï "ÐÒÏÔÕÈÛÅÍ" ÐÉÓØÍÅ × ÏÞÅÒÅÄÉ ÎÁ ÏÄÏÂÒÅÎÉÅ.
+mod_unsub_confirm   ÚÁÐÒÏÓ ÎÁ ÏÄÏÂÒÅÎÉÅ ÏÔÐÉÓËÉ ÐÏÌØÚÏ×ÁÔÅÌÑ ÍÏÄÅÒÁÔÏÒÕ.
+sub_bad             ÐÏÄÐÉÓÞÉËÕ, ÐÒÉ ÎÅËÏÒÒÅËÔÎÏÍ ÐÉÓØÍÅ-ÐÏÄÔ×ÅÒÖÄÅÎÉÉ.
+sub_confirm         ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÐÏÄÐÉÓËÉ ÐÏÌØÚÏ×ÁÔÅÌÀ.
+sub_nop             ÅÓÌÉ ÐÏÌØÚÏ×ÁÔÅÌØ ÕÖÅ ÐÏÄÐÉÓÁÎ.
+sub_ok              ÐÒÉ ÕÓÐÅÛÎÏÊ ÐÏÄÐÉÓËÅ.
+top                 ×ÅÒÈÎÑÑ ÞÁÓÔØ ×ÓÅÈ ÏÔ×ÅÔÏ×.
+</#tn/>
+trailer             ÔÅËÓÔ, ÄÏÂÁ×ÌÑÅÍÙÊ × ËÏÎÅàËÁÖÄÏÇÏ ÐÉÓØÍÁ × ÓÐÉÓÏË.
+</#n/>
+unsub_bad           ÐÏÄÐÉÓÞÉËÕ ÐÒÉ ÎÅÕÄÁÞÎÏÊ ÏÔÐÉÓËÅ.
+unsub_confirm       ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÏÔÐÉÓËÉ ÐÏÌØÚÏ×ÁÔÅÌÀ.
+unsub_nop           ÎÅ-ÐÏÄÐÉÓÞÉËÕ Ï ÔÏÍ, ÞÔÏ ÅÇÏ ÁÄÒÅÓÁ × ÓÐÉÓËÅ ÎÅÔ.
+unsub_ok            ÐÒÉ ÕÓÐÅÛÎÏÊ ÏÔÐÉÓËÅ.
+
+</text/edit-done#n/>
+ôÅËÓÔÏ×ÙÊ ÆÁÊÌ ÂÙÌ ÕÓÐÅÛÎÏ ÏÂÎÏ×ÌÅΠÎÁ ÓÅÒ×ÅÒÅ.
+</text/info#E/>
+ðÎÉÔÅ ÁÄÍÉÎÉÓÔÒÁÔÏÒÁ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ, ÐÕÓÔÏ ÔÕÔ.
+</text/faq#E/>
+FAQ, ÉÌÉ þÁ÷ï -- þÁÓÔÏ ÚÁÄÁ×ÁÅÍÙÅ ÷ÏÐÒÏÓÙ É ïÔ×ÅÔÙ.
+
+úÄÅÓØ ÐÏËÁ ÐÕÓÔÏ. íÏÖÅÔ ËÔÏ-ÎÉÂÕÄØ ÎÁÐÉÛÅÔ?
+
diff --git a/ezmlmrc.sv b/ezmlmrc.sv
new file mode 100644 (file)
index 0000000..4f6c6b5
--- /dev/null
@@ -0,0 +1,1174 @@
+0.40 - This version identifier must be on line 1 and start in pos 1.
+#
+#$Id: ezmlmrc.sv,v 1.23 1999/12/23 23:08:19 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+#
+# ezmlmrc 
+# #######
+# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later.
+#
+# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key.
+# Everything else is done from here.
+#
+# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the
+# lists .qmail files will be placed in (if you've used the -c command line
+# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory.
+# Thus, you can customize ezmlm-make on a global level by placing a customized
+# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in
+# the user's home directory AND use the ezmlm-make -c switch.
+#
+# Tags are:
+#      </filename/>       : put succeeding text lines in DIR/filename
+#      </-filename/>      : erase DIR/filename.
+#      </+dirname/>       : create directory DIR/dirname
+#      </:lname/dirname>  : symlink DIR/.qmail-list-lname -> DIR/dirname
+#
+# The name in the tag can be suffixed with '#' and any number of flags,
+# corresponding to command line switches. The item will be created/extended
+# only if all the flags listed are set. Files can be extended as long as they
+# were the last one created, but not if another file has been started since
+# then. Flags that are not recognized are silently ignored.
+# 
+# Thus, </filename#aP/> creates the file if and only if the list is archived
+# (-a) and not public (-P). If the next tag is </filename#m/>, the file is
+# extended with the lines up to the next tag if the list is message moderated
+# (-m). If the next tag is </another/>, 'filename' is closed. Any further
+# tags leading to the reopenining of 'filename' will overwrite the file, not
+# extend it.
+#
+# A set of user-defined command line switches (xX, yY, zZ) are available for
+# customization.
+#
+# Within the text, certain tags are substituted. Other tags are copied as
+# is. <#A#> and <#R#> are substituted by ezmlm-manage and -store (see man pages)
+# and <#l#> (lower case L) is replaced dynamically by the list name for
+# programs handling both 'list' and 'list-digest'.
+#
+# Substitutions are:
+# <#B#> ezmlm binaries path   <#C#> digest code         <#D#> dir
+# <#H#> host                  <#L#> local               <#F#> flags
+# <#T#> dot                   <#0#> arg for -0. <#3#>...<#9#> arg for -3..9
+# <#1#> ext1                  <#2#> ext2 [if dot is /path/.qmail-ext1-ext2-name]
+# The latter useful when a single user is controlling several virtual domains.
+#
+# -0 is used for the main list address when setting up sublists
+# -3 is for the new from header if we want that header replaced
+# -4 for specifying the ezmlm-tstdig switches used in dir/editor. Default
+#    -k64 -m30 -t24. Only used if -g is used.
+# -5 for list-owner address. Mail to list-owner will be forwarded to this addr.
+# -6 for sql connection info
+# -7 for contents of DIR/modpost
+# -8 for contents of DIR/modsub
+# -9 for contents of DIR/remote
+#
+# For demonstration purposes, the '-x' switch results in the following
+# non-standard actions:
+# - Removal of many non-text MIME parts from messages.
+# - Limit posts to 2 bytes <= msg body size <= 40000
+#
+# Attempts to create links or directories that already exist, will result
+# in a FATAL error. Attempts to open files that have already been closed
+# or already exits, will cause the old file to be overwritten.
+#
+# One of the major problems with ezmlm-lists is DIR/inlocal. For normal
+# users, it is set up to the list name (user-list or so), which is correct.
+# However, for user 'ezmlm' in control of virtual domain 'host.dom.com'
+# the list name is 'list@host.dom.com', but inlocal should be 'ezmlm-list',
+# not 'list'. Similarly, if ezmlm-domain1 is in control of 'host.dom.com,
+# list@host.dom.com, should yield an inlocal of 'ezmlm-domain1-list'. To
+# always get the lists correct, place this file as '.ezmlmrc' in the 
+# users home directory (~ezmlm/.ezmlmrc) and change the inlocal text below
+# to 'ezmlm-<#L#>' or 'ezmlm-<#1#>-<#L#>, respectively.
+# config to support future editing without giving ezmlm-make command line
+# arguments other than dir. Useful for GUI/WWW editing tools
+</config/>
+F:<#F#>
+X:<#X#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+</inlocal/>
+<#L#>
+</sublist#0/>
+<#0#>
+</+archive/>
+</+subscribers/>
+</+bounce/>
+</+text/>
+# dirs for digests
+</+digest#d/>
+</+digest/subscribers#d/>
+</+digest/bounce#d/>
+# for extra address db
+</+allow/>
+</+allow/subscribers/>
+# for blacklist
+</+deny#k/>
+</+deny/subscribers#k/>
+# moderator db & mod queue dirs. Needed for -m, -r -s, so we just
+# make them by default.
+</+mod/>
+</+mod/subscribers/>
+</+mod/pending/>
+</+mod/accepted/>
+</+mod/rejected/>
+# links: dot -> dir/editor
+</:/editor/>
+</:-owner/owner/>
+</:-digest-owner/owner#d/>
+</:-return-default/bouncer/>
+</:-digest-return-default/digest/bouncer#d/>
+</:-default/manager/>
+# for message moderation only
+</:-accept-default/moderator#m/>
+</:-reject-default/moderator#m/>
+# Get rid of configuration flags for editing mode so we can start with a
+# clean slate.
+</-modpost#eM/>
+</-modsub#eS/>
+</-remote#eR/>
+</-public#eP/>
+</-indexed#eA/>
+</-archived#eA/>
+</-prefix#eF/>
+</-text/trailer#eT/>
+</-sublist#e^0/>
+</-mimeremove#eX/>
+# Not needed, except for message moderation.
+</-moderator#eM/>
+# We don't clean out text files to make it easier for users
+# doing manual config by e.g. touching dir/remote.
+# subscription moderation
+</modsub#s/>
+<#8#>
+# remote admin
+</remote#r/>
+<#9#>
+# message moderation
+</modpost#m/>
+<#7#>
+# List owner mail
+</owner#5/>
+<#5#>
+</owner#^5/>
+<#D#>/Mailbox
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# Handles subscription. Add flags if you want a non-default digest format.
+# Service subject commands to the # request address if the -q switch is given.
+# Also -l and -d enable subscriber listing/text file editing, for remote adms.
+# -u gives subscriber only archive access
+</manager#ab/>
+|<#B#>/ezmlm-get -P '<#D#>' <#C#>
+</manager#aGB/>
+|<#B#>/ezmlm-get '<#D#>' <#C#>
+</manager#agB/>
+|<#B#>/ezmlm-get -s '<#D#>' <#C#>
+</manager#q/>
+|<#B#>/ezmlm-request '<#D#>'
+# Ok to add -l/-d even for non-mod lists, since ezmlm-manage
+# won't allow it unless there are remote admins. The lack of logic other than
+# AND makes this very tedious ...
+# first lists with normal confirmation:
+</manager#LNHJ/>
+|<#B#>/ezmlm-manage '<#D#>'
+</manager#lNHJ/>
+|<#B#>/ezmlm-manage -l '<#D#>'
+</manager#LnHJ/>
+|<#B#>/ezmlm-manage -e '<#D#>'
+</manager#lnHJ/>
+|<#B#>/ezmlm-manage -le '<#D#>'
+# ... now no confirmation for subscribe ...
+</manager#LNhJ/>
+|<#B#>/ezmlm-manage -S '<#D#>'
+</manager#lNhJ/>
+|<#B#>/ezmlm-manage -lS '<#D#>'
+</manager#LnhJ/>
+|<#B#>/ezmlm-manage -eS '<#D#>'
+</manager#lnhJ/>
+|<#B#>/ezmlm-manage -leS '<#D#>'
+# ... now no confirmation for unsubscribe ...
+</manager#LNHj/>
+|<#B#>/ezmlm-manage -U '<#D#>'
+</manager#lNHj/>
+|<#B#>/ezmlm-manage -lU '<#D#>'
+</manager#LnHj/>
+|<#B#>/ezmlm-manage -eU '<#D#>'
+</manager#lnHj/>
+|<#B#>/ezmlm-manage -leU '<#D#>'
+# ... and finally no confirmation at all ...
+</manager#LNhj/>
+|<#B#>/ezmlm-manage -US '<#D#>'
+</manager#lNhj/>
+|<#B#>/ezmlm-manage -lUS '<#D#>'
+</manager#Lnhj/>
+|<#B#>/ezmlm-manage -eUS '<#D#>'
+</manager#lnhj/>
+|<#B#>/ezmlm-manage -leUS '<#D#>'
+</manager#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</editor/>
+# reject shouldn't be configured for sublist.
+</#^0/>
+# full reject is now default, to get To/Cc: listaddress requirement
+|<#B#>/ezmlm-reject '<#D#>'
+# -k => reject posts from blacklisted addresses. Done for moderated
+# lists as well - allows removal of unwanted noise.
+</#k^0/>
+|<#B#>/ezmlm-issubn -n '<#D#>/deny' || { echo "Jag tillåter inte dina meddelanden. Kontakta <#L#>-owner@<#H#> ifall du har några frågor angående det (#5.7.2)"; exit 100 ; }
+# switch -u=> restrict to subs of list & digest. If not m
+# do it with ezmlm-issubn, if 'm' do it with ezmlm-gate
+</#uM/>
+|<#B#>/ezmlm-issubn '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' || { echo "Tyvärr, endast prenumeranter får posta. Ifall du är en prenumerant, orward this message to <#L#>-owner@<#H#> to get your new address included (#5.7.2)"; exit 100 ; }
+</#um/>
+|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod'
+# For message moderation, editor has store/clean
+</#mUO/>
+|<#B#>/ezmlm-store '<#D#>'
+</#mUo/>
+|<#B#>/ezmlm-store -P '<#D#>'
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+# for non-message moderated lists, it has send
+</#M/>
+|<#B#>/ezmlm-send '<#D#>'
+# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists
+</#Mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+# all lists have warn unless -w.
+</#W/>
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+# for digest bounces
+</#dW/>
+|<#B#>/ezmlm-warn -d '<#D#>' || exit 0
+</#d^4/>
+|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99
+</#d4/>
+|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99
+</#d/>
+|<#B#>/ezmlm-get '<#D#>' || exit 0
+# bouncer for list and digest
+</bouncer/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -D '<#D#>'
+</digest/bouncer#d/>
+|<#B#>/ezmlm-weed
+|<#B#>/ezmlm-return -d '<#D#>'
+# moderator is set up only for message moderated lists. However, '-e' does
+# not remove it since we can't remove the symlinks to it (they're outside
+# of the list dir.
+</moderator#m/>
+|<#B#>/ezmlm-moderate '<#D#>'
+</#mi/>
+|<#B#>/ezmlm-archive '<#D#>' || exit 0
+</#mU/>
+|<#B#>/ezmlm-clean '<#D#>' || exit 0
+</#mu/>
+|<#B#>/ezmlm-clean -R '<#D#>' || exit 0
+</headerremove#E/>
+return-path
+return-receipt-to
+content-length
+precedence
+x-confirm-reading-to
+x-pmrqc
+list-subscribe
+list-unsubscribe
+list-help
+</headerremove#E^0/>
+# For sublists, these should be left in
+list-post
+# remove from header if -3 'new_from_line'
+</#3E/>
+from
+</lock/>
+</lockbounce/>
+</digest/lockbounce#d/>
+</digest/lock#d/>
+</public#p/>
+</archived#a/>
+</indexed#a/>
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+kontakta <#L#>-help@<#H#>; körs med ezmlm
+# Headeradd needs to always exist but leave out stuff for sublists
+</headeradd#E^0/>
+# Good for mailing list stuff (and vacation program)
+Precedence: bulk
+# To prevent indexing by findmail.com
+X-No-Archive: yes
+# rfc2369, first from main list only, others from sublist only
+List-Post: <mailto:<#L#>@<#H#>>
+</headeradd#E/>
+List-Help: <mailto:<#l#>-help@<#h#>>
+List-Unsubscribe: <mailto:<#l#>-unsubscribe@<#h#>>
+List-Subscribe: <mailto:<#l#>-subscribe@<#h#>>
+# add new from line "From: arg" if -3 'arg'
+</#3E/>
+From: <#3#>
+# max & min message size
+</msgsize#x/>
+30000:2
+# remove mime parts if -x
+</mimeremove#xE/>
+application/excel
+application/rtf
+application/msword
+application/ms-tnef
+text/html
+text/rtf
+text/enriched
+text/x-vcard
+application/activemessage
+application/andrew-inset
+application/applefile
+application/atomicmail
+application/dca-rft
+application/dec-dx
+application/mac-binhex40
+application/mac-compactpro
+application/macwriteii
+application/news-message-id
+application/news-transmission
+application/octet-stream
+application/oda
+application/pdf
+application/postscript
+application/powerpoint
+application/remote-printing
+application/slate
+application/wita
+application/wordperfect5.1
+application/x-bcpio
+application/x-cdlink
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-dvi
+application/x-hdf
+application/x-httpd-cgi
+application/x-koan
+application/x-latex
+application/x-mif
+application/x-netcdf
+application/x-stuffit
+application/x-sv4cpio
+application/x-sv4crc
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-ustar
+application/x-wais-source
+audio/basic
+audio/mpeg
+audio/x-aiff
+audio/x-pn-realaudio
+audio/x-pn-realaudio
+audio/x-pn-realaudio-plugin
+audio/x-realaudio
+audio/x-wav
+image/gif
+image/ief
+image/jpeg
+image/png
+image/tiff
+image/x-cmu-raster
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-xbitmap
+image/x-xpixmap
+image/x-xwindowdump
+text/x-sgml
+video/mpeg
+video/quicktime
+video/x-msvideo
+video/x-sgi-movie
+x-conference/x-cooltalk
+x-world/x-vrml
+# These can also be excluded, but for many lists it is desirable
+# to allow them. Uncomment to add to mimeremove.
+# application/zip
+# application/x-gtar
+# application/x-gzip
+# application/x-sh
+# application/x-shar
+# chemical/x-pdb
+# --------------------- Handle SQL connect info
+</-sql#^6e/>
+</-digest/sql#^6e/>
+</-allow/sql#^6e/>
+</sql#6W/>
+<#6#>
+</sql#6w/>
+<#6#>:<#L#>@<#H#>
+</digest/sql#6dW/>
+<#6#>_digest
+</digest/sql#6dw/>
+<#6#>_digest:<#L#>_digest@<#H#>
+</allow/sql#6/>
+<#6#>_allow
+# -------------------- End sql stuff
+</prefix#fE/>
+[<#L#>]
+</text/trailer#tE/>
+---------------------------------------------------------------------
+För att avsluta prenumerationen skicka e-mail till:
+<#L#>-unsubscribe@<#H#>
+För ytterligare kommandon, skicka e-mail till:
+<#L#>-help@<#H#>
+</text/bottom#E/>
+
+--- Administrativa kommandon för <#l#> listan ---
+
+Administrativa förfrågningar kan hanteras automatiskt. Skicka
+dem inte till listans adress! Skicka istället ditt meddelande
+till rätt "kommando adress":
+
+För hjälp och en beskrivning över tillgängliga kommandon,
+skicka ett brev till:
+   <<#L#>-help@<#H#>>
+
+För att prenumerera på listan, skicka ett brev till:
+   <<#L#>-subscribe@<#H#>>
+
+För att avsluta din prenumeration, skicka ett meddelande till
+adressen som står i "List-Unsubscribe" raden i brevhuvudet
+från ett brev som kom från listan. Ifall du inte bytt adress
+sen du påbörjade din prenumeration, skicka ett brev till:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#dE/>
+eller för "digest" versionen:
+   <<#L#>-unsubscribe@<#H#>>
+
+</#E/>
+För nya/avslutade prenumerationer, skickar jag ett bekräftelse
+brev till adressen. När du får brevet, svara bara på det för
+att genomföra prenumerationsförändringen.
+
+Ifall du behöver komma i kontakt med en människa angående
+listan, skicka ett brev till:
+
+    <<#L#>-owner@<#H#>>
+
+Var vänlig och VIDARESKICKA (forward) ett meddelande från listan
+inklusive HELA brevhuvudet så vi lättare kan hjälpa dig.
+
+--- Nedan finner du en kopia på förfrågan jag fick.
+
+</text/bounce-bottom#E/>
+
+--- Nedan finner du en kopia på det "studsade" meddelandet jag fick.
+
+</text/bounce-num#E/>
+
+Jag har skapat en lista på de meddelanden från <#L#> listan som
+har "studsat" på väg till dig.
+
+</#aE/>
+Kopior av dessa meddelanden kan du finna i arkivet.
+
+</#aE/>
+För att hämta meddelande 123-145 (max 100 per förfrågan), skicka
+ett brev till:
+   <<#L#>-get.123_145@<#H#>>
+
+För att få en lista på titlar och författare för de senaste 100
+meddelandena, skicka ett brev till:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Detta är meddelande nummren:
+
+</text/dig-bounce-num#E/>
+
+Jag har skapat en lista på "digest" meddelanden från <#L#>-digest
+listan, som har "studsat" till din adress. För varje "digest" brev
+som du missat, har jag skrivit upp första meddelandenummret i det
+brevet.
+
+</#aE/>
+"Digest" meddelanden arkiveras inte, men du kanske kan finna dem
+i akrivet för huvudlistan.
+
+För att ta emot brev 123-145 (max 100 per förfrågan),
+skicka ett brev till:
+   <<#L#>-get.123_145@<#H#>>
+
+För en lista över författare och titlar på de senaste 100
+meddelandena, skicka ett brev till:
+   <<#L#>-index@<#H#>>
+
+</#E/>
+Här är "digest" meddelande nummren:
+
+</text/bounce-probe#E/>
+
+Meddelanden till dig från <#l#> listan, verkar ha "studsat".
+Jag skickade ett varningsbrev till dig om det, men det "studsade".
+Nedan följer en kopia på det meddelandet.
+
+Detta testbrev kontrollerar om din adress är nåbar. Ifall detta
+brev också studsar, plockas din adress bort från
+<#l#>@<#H#> listan, utan ytterligare varningar.
+
+Du kan prenumerera på nytt genom att skicka ett brev
+till denna adressen:
+   <<#l#>-subscribe@<#H#>>
+
+</text/bounce-warn#E/>
+
+Meddelanden till dig från <#l#> listan har "studsat".
+Jag bifogar en kopia på det första brevet till dig där
+det inträffade.
+
+Ifall detta meddelande också "studsar", kommer ett testbrev skickas
+till dig. Ifall det brevet också studsar, plockas din adress bort
+från <#l#> listan utan ytterligare varning.
+
+</text/digest#dE/>
+För prenumeration på "digest" versionen, skicka ett brev till:
+       <#L#>-digest-subscribe@<#H#>
+
+För att avsluta prenumerationen på "digest" versionen,
+skicka ett brev till:
+       <#L#>-digest-unsubscribe@<#H#>
+
+För att skicka ett brev till listan, skicka brevet till:
+       <#L#>@<#H#>
+
+</text/get-bad#E/>
+Tyvärr, det meddelandet finns inte i arkivet.
+
+</text/help#E/>
+Detta är ett almänt hjälp meddelande. Brevet som kom var inte
+skickat till någon av kommando adresserna.
+
+Detta är en lista på de kommando adresser som stöds:
+
+Skicka brev till något av följande adresser för information
+och "FAQn" för listan:
+   <<#L#>-info@<#H#>>
+   <<#L#>-faq@<#H#>>
+
+</#dE/>
+Liknande adresser finns för "digest" versionen av listan:
+   <<#L#>-digest-subscribe@<#H#>>
+   <<#L#>-digest-unsubscribe@<#H#>>
+
+# ezmlm-make -i needed to add ezmlm-get line. If not, we can't do
+# multi-get!
+</#aE/>
+För att få meddelande 123 till 145 (max 100 per förfrågan),
+skicka ett brev till:
+   <<#L#>-get.123_145@<#H#>>
+
+För att få ett index med författare och titel för meddelande
+123-456, skicka ett brev till:
+   <<#L#>-index.123_456@<#H#>>
+
+För att få alla meddelanden med samma titel som meddelande 12345,
+skicka ett brev till:
+   <<#L#>-thread.12345@<#H#>>
+
+</#E/>
+Meddelandena behöver inte innehålla något särskilt, det är
+bara adressen som är viktig.
+
+Du kan starta en prenumeration till en alternativ adress,
+t ex "john@host.domain", addera bara ett bindesträck
+och din adress (med '=', istället för '@') efter kommando
+ordet. Dvs:
+<<#L#>-subscribe-john=host.domain@<#H#>>
+
+För att avsluta prenumerationen till denna adressen,
+skicka ett brev till:
+<<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</text/mod-help#E/>
+Tack för att du vill moderera <#L#>@<#H#> listan.
+
+Kommandona är lite anorlunda mot andra listor,
+men de är lätta att lära och använda.
+
+Här är lite instruktioner angående de saker du kan behöva
+göra som listägare/moderator.
+
+Allmäna kommandon följer efter detta meddelande.
+
+Fjärr prenumeration.
+--------------------
+Som moderator kan du prenumerera och avprenumerera vilken adress
+som helst på listan. För att prenumerera "john@host.domain",
+skriv bara ett bindesträck efter "kommando ordet", därefter
+adressen med ett '=' tecken istället för '@'. I detta fallet skulle
+du skickat ett brev till:
+   <<#L#>-subscribe-john=host.domain@<#H#>>
+
+Du kan på samma sätt ta bort en adress med ett meddelande till:
+   <<#L#>-unsubscribe-john=host.domain@<#H#>>
+
+</#dE/>
+För "digest" versionen av listan:
+   <<#L#>-digest-subscribe-john=host.domain@<#H#>>
+   <<#L#>-digest-unsubscribe-john=host.domain@<#H#>>
+
+</#E/>
+Det är allt. Titel och innehåll spelar ingen roll!
+
+</#rE/>
+Ett bekräftelse brev kommer skickas för att vara säker
+på att det verkligen var du som skickade brevet.
+Svara bara på det brevet och det hela är klart.
+</#RE/>
+Jag kommer skicka ett bekräftelsebrev till prenumerantens adress,
+i detta fallet <john@host.domain>. Allt prenumeranten behöver
+göra är att svara på brevet.
+</#E/>
+
+Bekräftelserna är nödvändiga för att göra det svårt för
+en tredje part till att lägga till/ta bort adresser till
+listan.
+
+Jag kommer underrätta prenumeranten när dennes status
+har ändrats.
+
+Prenumeration
+--------------
+
+Alla kan prenumerera/sluta prenumerera på listan genom
+att skicka ett brev till:
+
+<#L#>-subscribe@<#H#>
+<#L#>-unsubscribe@<#H#>
+
+</#dE/>
+För "digest" versionen av listan:
+
+<#L#>-digest-subscribe@<#H#>
+<#L#>-digest-unsubscribe@<#H#>
+
+</#E/>
+Prenumeranten kommer få ett bekräftelse brev för
+att vara säker på att personen har den adressen.
+När det är klart blir personen borttagen ur listan.
+
+</#sE/>
+Eftersom denna listan är sluten, kommer jag skicka en andra
+förfrågan till moderatorerna. Eftersom prenumeranten redan har
+bekräftat att den vill vara med på listan, kan du som
+moderator vara säker på att det är rätt adress. Ifall du vill
+ha med personen på listan, svara på bekräftelse (CONFIRM)
+meddelandet. Ifall du inte vill ha med personen, radera bara
+meddelandet istället (eller kontakta personen för ytterligare
+information).
+</#SE/>
+Prenumeration fungerar på samma sätt.
+</#E/>
+
+Användaren kan också:
+
+   <<#L#>-subscribe-mary=host.domain@<#H#>>
+   <<#L#>-unsubscribe-mary=host.domain@<#H#>>
+
+för att få brev skickad till "mary@host.domain". Bara om hon kan
+ta emot brev på den adressen, får hon bekräftelse meddelandet
+och kan svara på det.
+
+Din adress och identitet kommer att vara hemlig för prenumeranten
+om du inte skickar brev direkt till denne.
+
+</#rlE/>
+För att få en lista på prenumeranter på <#L#>@<#H#>,
+skicka ett brev till:
+   <<#L#>-list@<#H#>>
+
+För att få en "transaktionslog" för <#L#>@<#H#>,
+skicka ett brev till:
+   <<#L#>-log@<#H#>>
+
+</#rldE/>
+För "digest" prenumeranter:
+   <<#L#>-digest-list@<#H#>>
+och:
+   <<#L#>-digest-log@<#H#>>
+
+</#rnE/>
+Du kan ändra textfilerna, som listan använder, på distans. För att
+få en lista på filerna och instruktioner om hur du ändrar dem,
+skicka ett e-mail till:
+   <<#L#>-edit@<#H#>>
+
+</#mE/>
+Modererade utskick
+------------------
+När utskick är modererade, kommer ett brev att skickas till dig
+med en kopia på utskick och instruktioner som berättar hur
+utskicket skall godkännas för att komma med på listan. Det
+brevet kommer att ha "MODERATE for ..." som titel.
+
+För att acceptera ett utskick, skicka bara ett svar till 'Reply-To:'
+adressen (sker vanligtvis med "svara" knappen). Du behöver inte
+skicka med brevet du fick skickat till dig, det är bara adressen
+som är viktig.
+
+Ifall du vill avvisa utskicket, skicka ett brev till avsändar-
+adressen ("From:" fältet), där rätt avvisningsadress är inskrivning.
+"Svara alla" brukar använda den adressen. Om du vill skriva ett
+meddelande till författaren, skriv den mellan två rader som börjar
+med tre '%' tecken. Detta kommer att ske anonymt och bara skickas
+till författaren.
+
+Utskicket kommer att behandlas beroende på vilket svar som kommer
+in först. Om en moderator redan har avvisat ett brev som du godkänner
+så kommer brevet ändå att vara avvisat och vice versa.
+
+Ifall ingen moderator svarar inom en viss tid (vanligtvis 5 dagar),
+kommer brevet att returneras till författaren med en förklaring
+om vad som hände.
+</#E/>
+
+Semestrar
+---------
+Ifall du temporärt har en annan adress, vidareskicka alla brev som
+har korrekt "Mailing-List:" fält i brevhuvudet (eller alla brev som
+har titeln "MODERATE for <#L#>@<#H#>"
+eller "CONFIRM subscribe to <#L#>@<#H#>")
+till den nya adressen. Du kan därefter moderera listan från den
+adressen. Alternativt kan du vidareskicka brevet till någon annan
+som modererar listan åt dig. Fråga listägaren först om det är OK.
+
+Ifall du vill att allt skall godkännas automatiskt medan du är
+borta, ställ iordning ditt e-mail system så den gör ett autosvar
+på brev med ovan nämnda titlar.
+
+</#rE/>
+Ifall du försöker administrera listan från en adress som inte är din
+egen, prenumeranten, inte du, kommer frågas efter en bekräftelse.
+Därefter kommer en bekräftelseförfrågan skickas till moderatorerna.
+Detta görs eftersom det är omöjligt att veta ifall det var du som
+skickade originalfrågan.
+
+Observera att originalförfrågan, inklusive din adress, skickas till
+prenumeranten i detta fallet.
+</#E/>
+
+Lycka till!
+
+PS. Kontakta listägaren (<#L#>-owner@<#H#>) ifall du
+har några frågor eller stöter på några problem.
+
+</text/mod-reject#E/>
+Tyvärr, meddelandet (bifogat) accepterades inte av moderatorn.
+Ifall moderatorn har bifogat några kommentarer, står de här nedan.
+</text/mod-request#E/>
+Det bifogade meddelandet skickades till <#L#>@<#H#> listan.
+Ifall du vill godkänna den för vidare distribution skicka e-mail till:
+
+!A
+
+Vanligtvis händer detta automatiskt om du trycker på "svara" (reply)
+knappen. Du kan kontrollera adressen att den börjar med:
+"<#L#>-accept". Ifall det inte fungerar, kopiera adressen och
+klistra in den i "Till" ("To:") fältet i ett nytt brev.
+</#xE/>
+
+Alternativt, tryck här:
+       <mailto:<#A#>>
+</#E/>
+
+Föra att skicka tillbaka brevet till avsändaren, skicka ett
+meddelande till:
+
+!R
+
+Vanligtvis är det enklare att trycka på "svara alla" ("reply-to-all")
+knappen och ta bort alla adresser som inte börjar med:
+"<#L#>-reject".
+</#xE/>
+
+Alternativt, tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+Du behöver inte kopiera brevet i ditt svar. Ifall du vill skicka
+med en kommentar till författaren till ett brev du inte accepterat,
+inkludera kommentaren, i svarsbrevet, mellan två rader som börjar
+med tre procenttecken ('%').
+
+%%% Start kommenter
+%%% Slut kommentar.
+
+Tack för din hjälp!
+
+--- Nedan finner du utskicket.
+
+</text/mod-sub#E/>
+--- Du har blivit (av-)prenumererad av en moderator för
+<#l#>@<#H#> listan.
+
+Ifall du inte tycker om det, skicka ett klagomål, eller annan
+kommentar, till listägaren (<#l#>-owner@<#H#>) så snart som
+möjligt.
+
+</text/mod-timeout#E/>
+Tyvärr har <#L#> listans moderatorer inte
+hanterat din postning, därför skickas den nu tillbaka till dig.
+Ifall detta är fel, skicka om ditt meddelande till listan
+eller kontakta listägaren (<#L#>-owner@<#H#>).
+
+--- Bifogat är brevet du skickade.
+
+</text/mod-sub-confirm#E/>
+Vill du lägga till
+
+!A
+
+till <#l#> listan? Antingen kom detta brevet som svar på
+att du vill lägga till prenumeranten till listan eller
+så har prenumeranten redan bekräftat sin prenumeration.
+
+För att bekräfta, skicka ett tomt brev till denna adress:
+
+!R
+
+Vanligtvis görs det genom "svara" ("reply") knappen.
+Ifall det inte fungerar, kopiera adressen och klistra in den i
+"To:" fältet i ett nytt meddelande.
+</#xE/>
+
+eller tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+Ifall du inte godkänner detta, ignorera detta meddelande.
+
+Tack för din hjälp!
+
+</text/mod-unsub-confirm#E/>
+Någon önskar ta bort:
+
+!A
+
+från <#l#> listan. Ifall du håller med, skicka ett brev
+till denna adress:
+
+!R
+
+Enklast gör du det genom att trycka på "svara" ("reply") knappen.
+Ifall det inte fungerar, kopiera adressen och klistra in den i
+"Till" ("To:") fältet i det nya meddelandet.
+</#xE/>
+
+eller tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+Ifall du inte håller med, ignorera detta brev.
+
+Tack för din hjälp!
+
+</text/sub-bad#E/>
+Oops, det bekräftelsenummret verkar vara felaktigt.
+
+Den vanligaste orsaken till felaktiga bekräftelsenummer är
+att de blivit för gamla. De gäller i max 10 dagar. Var också
+säker på att du använde hela bekräftelsenummret i ditt svar,
+vissa program kan i vissa fel ta bort slutet på adresser när
+de är långa.
+
+Ett nytt bekräftelsenummer har skapats, för att bekräfta att
+du vill ha med
+
+!A
+
+på <#l#> listan, skicka ett brev till denna adress:
+
+!R
+</#xE/>
+
+eller tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+Var noga med att svarsadresser är riktig när du bekräftar
+prenumerationen.
+
+Ursäkta detta extra besvär.
+
+       <#L#>-Owner <<#l#>-owner@<#H#>>
+
+</text/sub-confirm#E/>
+För att bekräfta att du vill ha
+
+!A
+
+adderad till <#l#> listan, skicka ett brev till denna adress:
+
+!R
+
+Enklast görs det genom att trycka på "svara" ("reply") knappen.
+Ifall det inte fungerar, kopiera adressen och klistra in den i
+"Till" ("To:") fältet i ett nytt brev.
+</#xE/>
+
+eller tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+Denna bekräftelse tjänar två syften. Dels säkerställer den att det går
+att skicka brev till dig och dels skyddar den dig mot att andra försöker
+prenumerera någon mot dess vilja.
+
+</#qE/>
+Det är fel på vissa e-mail program vilket gör att de inte kan hantera
+långa adresser. Ifall du inte kan svara på denna förfrågan, skicka
+istället ett meddelande till <<#L#>-request@<#H#>>
+och skriva hela ovan nämnda adress i titel ("Subject:") raden.
+
+</#sE/>
+Denna lista är modererad. Så fort du har svarat på denna bekräftelse
+kommer din förfrågan att skickas till moderatorerna för listan.
+Du kommer att underrättas när din prenumeration är aktiverad.
+
+</text/sub-nop#E/>
+Jag kunde inte utföra din förfrågan.
+
+!A
+
+prenumererar redan på <#l#> listan när jag fick din förfrågan.
+Adressen kommer vara kvar på listan.
+
+</text/sub-ok#E/>
+Uppmärksamma: Adressen
+
+!A
+
+har adderats till <#l#> listan.
+
+Välkommen till <#l#>@<#H#>!
+
+Var vänlig och spara detta meddelande så du minns vilken adress
+som prenumererar på listan, ifall du senare vill avsluta din
+prenumeration.
+
+För att avsluta prenumerationen, skicka ett brev till:
+
+    <<#l#>-unsubscribe-<#t#>@<#H#>>
+
+</text/top/>
+Detta är ett meddelande från ezmlm programmet som har hand om
+<#l#>@<#H#> listan.
+
+</#x/>
+Ägaren till listan kan nås på:
+<#l#>-owner@<#H#>.
+
+</text/unsub-bad#E/>
+Oops, det bekräftelsenummret verkar vara felaktigt.
+
+Den vanligaste orsaken till felaktiga bekräftelsenummer är
+att de blivit för gamla. De gäller i max 10 dagar. Var också
+säker på att du använde hela bekräftelsenummret i ditt svar,
+vissa program kan i vissa fel ta bort slutet på adresser när
+de är långa.
+
+Ett nytt bekräftelsenummer har skapats, för att bekräfta att
+du vill ta bort
+
+!A
+
+från <#l#> listan, skicka ett brev till denna adress:
+
+!R
+</#xE/>
+
+eller klicka här:
+       <mailto:<#R#>>
+</#E/>
+
+Var vänligt att kontrollera svarsadressen noggrant så att den är
+riktig innan du svarar på detta brev.
+
+Ursäkta allt besvär.
+
+       <#l#>-Owner <<#l#>-owner@<#H#>>
+
+</text/unsub-confirm#E/>
+För att bekräfta att du vill ta bort
+
+!A
+
+från <#l#> listan, skicka ett brev till denna adress:
+
+!R
+
+Vanligtvis gör man det med "Svara" ("Reply") knappen.
+Ifall det inte fungerar, kopiera adressen nedan och klistra
+in den i "Till" ("To:") fältet i ett nytt brev.
+</#xE/>
+
+eller tryck här:
+       <mailto:<#R#>>
+</#E/>
+
+För att se vilken adress din prenumeration går till, undersök ett
+meddelande från listan. Varje meddelande har din adress dold i
+dess "return path", t ex mary@xdd.ff.com har får meddelanden
+med "return-path" satt till:
+<<#l#>-return-<nummer>-mary=xdd.ff.com@<#H#>>.
+
+</#qE/>
+Vissa email program är felaktiga och kan inte hantera långa adresser.
+Ifall du inte kan svara på detta meddelande, skicka istället ett
+meddelande till <<#L#>-request@<#H#>> och skriv hela ovan nämnda
+adress i titel ("Subject:") raden.
+
+</text/unsub-nop#E/>
+Tyvärr kan inte din förfrågan utföras eftersom adressen:
+
+!A
+
+var inte med på <#l#> listan.
+
+Ifall du har avslutat din prenumeration, men fortfarande får brev,
+är du prenumererad under en annan adress än den du för närvarande
+använder. Titta i brevhuvudet (header) efter:
+
+'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>'
+
+Det visar din prenumerationsadress som "user@host.dom".
+För att avsluta din prenumeration med den adressen, skicka
+ett brev till:
+<#l#>-unsubscribe-user=host.dom@<#H#>
+
+Glöm inte att anpassa user=host.dom till din egen adress.
+
+Ifall meddelandet har en "List-Unsubscribe:" fält i brevhuvudet,
+kan du skicka ett meddelande till adressen i det fältet.
+Det är redan anpassat för din adress.
+
+I vissa email program måste du göra vissa inställningar för att
+se "return path" fältet i brevhuvudet:
+
+I Eudora 4.0, klicka på "Blah blah ..." knappen.
+I PMMail, klicka på "Window->Show entire message/header". 
+
+Ifall det inte fungerar kan vi tyvärr inte göra mer.
+Vidaresänd ett brev från listan, tillsammans med ett meddelande
+om vad du vill ha gjort och en lista som du tror att du kan ha
+prenumererat under till listägaren:
+
+    <<#l#>-owner@<#H#>>
+
+som kan ta hand om det. Det kan dock dröja en liten stund innan du får
+ett svar.
+
+</text/unsub-ok#E/>
+Observera: Jag har tagit bort adressen
+
+!A
+
+från <#l#> listan. Den adressen är inte längre en prenumerant.
+
+</text/edit-do#nE/>
+Var vänlig och editera följande textfil och skicka den till
+denna address:
+
+!R
+
+Ditt mailprogram borde ha en svarsfunktiuon som använder
+denna address automatiskt. Ifall det inte fungerar, kan du
+kopiera addressen och klistra in den i "To:"/"Till:" fältet
+på ett nytt medelande.
+</#xE/>
+
+eller klicka här:
+        mailto:<#R#>
+</#E/>
+
+Jag kan ta bort citeringsmarkeringar (t ex "> ") som din
+mailprogramvara lägger till texten så länge som du inte
+ändrar start och slutraderna.
+
+Start och slutraderna är rader som börjar med %%%. De får inte
+ändras. Ifall ditt mailprogram lägger in tecken före dem så skall
+de stå kvar.
+
+
+</text/edit-list#En/>
+<#L#>-edit.fil kommandot kan användas av en fjärradministratör
+för att editera de textfiler som skapar de svaren jag skickar för
+<#L#>@<#H#> listan.
+
+Här följer en lista på de filer som kan ändras samt en
+kort beskrivning om hur dess innehåll används. För att
+ändra en fil, skicka ett brev till <#L#>-edit.filnamn där
+du byter ut filnamn mot filens namn. Editeringsinstruktioner
+skickas till dig ihop med textfilen.
+
+Fil                 Användninsområde.
+
+bottom              slutet på alla svar. Generell kommando information.
+digest              'administrationsbiten' av en 'digest'.
+faq                 Vanligt förekommande frågor på denna lista.
+get_bad             i stället för medelanden som inte hittas i arkivet.
+help                generell hjälp (mellan top och bottom).
+info                list info. Första raden skall kunna visas separat.
+mod_help            specifik hjälp för listmoderatorer.
+mod_reject          sänds till avsändaren av avvisade medelanden.
+mod_request         till medelandemoderatorerna tillsammans med medelandet.
+mod_sub             till prenumeranter efter att en moderator bekräftat prenumerationen.
+mod_sub_confirm     till prenumerationsmoderatorn för att bekräfta prenumerationer.
+mod_timeout         till sändaren av ett medelande som ingen accepterat/avvisat.
+mod_unsub_confirm   till en administratör för att bekräfta avprenumerationer.
+sub_bad             till prenumeranten ifall bekräftelsen var felaktig.
+sub_confirm         till prenumeranten för att bekräfta prenumerationer.
+sub_nop             till prenumeranten efter en dubbel prenumeration.
+sub_ok              till prenumeranten efter en lyckad prenumeration.
+</#tnE/>
+trailer             adderas till alla utskick innan de kommer till listan.
+</#nE/>
+top                 starten på alla svar. Generell kommando information.
+unsub_bad           till prenumeranten ifall avprenumerationen misslyckades.
+unsub_confirm       till prenumeranten för att bekräfta avprenumeration.
+unsub_nop           till icke-prenumerant efter avprenumeration.
+unsub_ok            till tidigare prenumeration efter avslutad prenumeration.
+
+</text/edit-done#nE/>
+Textfilen uppdaterades korrekt.
+</text/info#E/>
+Ingen information har antecknats om listan.
+</text/faq#E/>
+FAQ - vanligt förekommande frågor på <#l#>@<#H#> listan.
+
+Inga har nedtecknats ännu.
+
diff --git a/ezmlmsubrc b/ezmlmsubrc
new file mode 100644 (file)
index 0000000..e8309f7
--- /dev/null
@@ -0,0 +1,162 @@
+#$Id: ezmlmsubrc,v 1.8 1999/05/11 02:32:40 lindberg Exp $
+#$Name: ezmlm-idx-040 $
+# ezmlm-make -C ezmlmsubrc dir dot local host
+# Options:
+#      -3 mainlist local       (required)
+#      -4 mainlist host        (required) 
+#      -6 sql connect info. Format: 'host:port:user:pw:db:table'
+#      -A main list not archived (affects only bounce texts)
+#      -I main list not indexed  (affects only bounce texts)
+#      -d this sublist is for a digest list
+#
+# NOTE: For sublists of a digest list use the list local name for -3, _not_
+# the digest list. Thus, to set up a sublist for list-digest@host, use
+# -d -3 list -4 host. This is needed to make the texts refer correctly.
+# Also, the "table" in the SQL connect info
+# Should be root, where "root" is the table name used for the main list.
+# A digest sublist is just like any other sublist, but the parent is
+# list-digest, rather than list. You need separate sublists for each and they
+# are independent. However, it's convenient to set them up in parallel, and
+# they will not interfere with one another.
+#
+# NOTE: The list address is always added to the SQL connect info to restrict
+# addresses to those serviced by this sublist.
+#
+# For memory
+</config/>
+F:<#F#>
+D:<#D#>
+T:<#T#>
+L:<#L#>
+H:<#H#>
+C:<#C#>
+0:<#0#>
+3:<#3#>
+4:<#4#>
+5:<#5#>
+6:<#6#>
+7:<#7#>
+8:<#8#>
+9:<#9#>
+########## real stuff starts here
+</sublist/>
+<#3#>@<#4#>
+</+subscribers/>
+</+bounce/>
+</+text/>
+</lock/>
+</lockbounce/>
+</-sql/>
+</sql#6D/>
+<#6#>:<#L#>@<#H#>
+</sql#6d/>
+<#6#>_digest:<#L#>_digest@<#H#>
+# links: dot -> dir/editor
+</:/editor/>
+</:-return-default/bouncer/>
+</editor/>
+|<#B#>/ezmlm-send '<#D#>'
+|<#B#>/ezmlm-warn '<#D#>' || exit 0
+</bouncer/>
+|<#B#>/ezmlm-weed
+</bouncer#D/>
+|<#B#>/ezmlm-return -D '<#D#>'
+</bouncer#d/>
+|<#B#>/ezmlm-return -d '<#D#>'
+</inhost/>
+<#H#>
+</outhost/>
+<#H#>
+</inlocal/>
+<#L#>
+</outlocal/>
+<#L#>
+</mailinglist/>
+contact <#3#>-help@<#4#>; run by ezmlm
+</headeradd/>
+Precedence: bulk
+</headerremove/>
+return-path
+return-receipt-to
+content-length
+precedence
+</text/top/>
+Hi! This is the ezmlm program.
+I'm managing the <#3#>@<#4#>
+</#D/>
+and <#3#>-digest@<#4#>
+mailing lists.
+
+</#d/>
+mailing list.
+</text/bounce-bottom/>
+
+--- Enclosed is a copy of the bounce message I received.
+
+</text/bounce-num/>
+
+</#D/>
+I've kept a list of which messages from the <#3#>@<#4#>
+mailing list have bounced from your address.
+
+</#d/>
+I've kept a list of which messages from
+the <#3#>-digest@<#4#>
+digest list have bounced from your address. In each case, the number
+is the number of the first message in the digest.
+
+</#a/>
+Copies of the messages may be in the archive.
+
+To get message 12345 from the archive, send an empty message to:
+   <<#3#>-get.12345@<#4#>>
+
+To retrieve a set of messages 123-145 (a maximum of 100 per request),
+send an empty message to:
+   <<#3#>-get.123_145@<#4#>>
+
+To receive a subject and author list for the last 100 or so messages,
+send an empty message to:
+   <<#3#>-index@<#4#>>
+
+To receive the thread of messages including message 123,
+send an empty message to:
+   <<#3#>-thread.123@<#4#>>
+
+<//>
+Here are the message numbers:
+
+</text/bounce-probe/>
+
+</#D/>
+Messages to you from the <#3#>@<#4#> mailing list
+</#d/>
+Messages to you from the <#3#>-digest@<#4#> list
+<//>
+seem to have been bouncing. I sent you a warning message, but it bounced.
+I've attached a copy of the bounce message.
+
+This is a probe to check whether your address is reachable. If this
+probe bounces, I will remove your address from the list
+without further notice. You can re-subscribe
+by sending an empty message to the following address:
+</#D/>
+   <<#3#>-subscribe@<#4#>>
+
+</#d/>
+   <<#3#>-digest-subscribe@<#4#>>
+
+</text/bounce-warn/>
+
+Messages to you from the
+</#D/>
+<#3#>@<#4#> mailing list seem to
+</#d/>
+<#3#>-digest@<#4#> digest list seem to
+<//>
+have been bouncing. I've attached a copy of the first bounce
+message I received.
+
+If this message bounces too, I will send you a probe. If the probe bounces,
+I will remove your address from the mailing list, without further notice.
+# End of minimal sublist setup.
diff --git a/ezmlmsubrc.5 b/ezmlmsubrc.5
new file mode 100644 (file)
index 0000000..c32ad33
--- /dev/null
@@ -0,0 +1,79 @@
+.TH ezmlmsubrc 5
+.SH NAME
+ezmlmsubrc \- set up a minimal sublist
+.SH SYNOPSIS
+.B ezmlm-make
+.B \-C ezmlmsubrc
+.B -options
+.I dir dot local host
+.SH DESCRIPTION
+.B ezmlmglrc
+instructs
+.B ezmlm-make(1)
+to create
+.I dir
+and files within it to support the
+.I local\fB@\fIhost
+sublist. The sublist handles bounces, but not subscriptions. It is intended
+for creation of sublists that are part of an SQL database supported distributed
+ezmlm list. For creation of regular sublists, use
+.B ezmlm-make(1)
+with
+.BR ezmlmrc(5) .
+.SH "REQUIRED SWITCHES"
+While these switches can be omitted, the list will not function unless they
+are specified.
+.TP
+.B \-3\fI mainlocal
+Local name of the main list for which this list is a sublist. If the sublist
+is a sublist for digests,
+.I mainlocal
+should refer to the mail list, i.e. stripped of ``-digest''. This is required
+in order for the bounce texts to refer to the correct archive. Use the
+.B \-d
+switch!
+.TP
+.B \-4\fI mainhost
+Host name of the main list for which this list is a sublist.
+.TP
+.B \-6\fI host:port:user:pass:db:table
+SQL connect info. Specifies the host and port to connect to, the user/password
+to use, the database name, and the root table name.
+The host defaults to ``localhost'', the database and table to ``ezmlm''. The
+port default is the default for the particular SQL server type used. For
+sublists disseminating a digest, ``table'' will end in ``_digest''.
+.SH OPTIONS
+.TP
+.B \-d
+This sublist is a sublist of a digest list.
+The
+.B \-3
+argment used should be the local name of the main list, rather than
+the digest list, i.e. the terminal ``-digest'' should be stripped.
+.TP
+.B \-5\fI owner
+The address to which to redirect mail send to
+.IR local-\fBowner@\fIhost .
+The default is the owner address for the main list.
+.SH USAGE
+A common task is to create both a sublist for the main list and a sublist
+for the corresponding digest. Note that the local list names are given
+as is, whereas the main list name always refers to the main list itself
+(and not its digest). The main list is  ``mainloc@mainhost'', the local
+sublist is ``me-sub1@myhost''; the main digest is ``mainloc-digest@mainhost''
+and the local digest sublist is ``me-sub1-digest@myhost''.
+
+.EX
+ezmlm-make -Cezmlmsubrc -3 mainloc -4 mainhost -6 mainhost::user:pw:db:tab
+~/DIR ~me/.qmail-sub1 me-sub1 myhost
+.EE
+
+.EX
+ezmlm-make -Cezmlmsubrc -d -3 mainloc -4 mainhost -6 mainhost::user:pw:db:tab
+\-d ~/DIR ~me/.qmail-sub1-digest me-sub1-digest myhost
+.EE
+.SH "SEE ALSO"
+ezmlm-make(1),
+ezmlm(5),
+ezmlmrc(5)
+
diff --git a/idx.h b/idx.h
new file mode 100644 (file)
index 0000000..59f7867
--- /dev/null
+++ b/idx.h
@@ -0,0 +1,354 @@
+/*$Id: idx.h,v 1.57 1999/11/29 04:54:01 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#ifndef IDX_H
+#define IDX_H
+
+/* Version of this release */
+#define EZIDX_VERSION "ezmlm-idx-0.40\n"
+
+/* Range for '-thread' to protect large archives. A '-thread' search */
+/* will start at most THREAD_BEFORE messages before the action argument */
+/* and go to at most THREAD_AFTER messages after the action argument. */
+#define THREAD_BEFORE 2000
+#define THREAD_AFTER 2000
+
+/* Maximum number of messages returned by get */
+/* You also have to update /text/bottom in ezmlmrc if you change this */
+#define MAXGET 100
+
+/* Number of messages before latest digest to return for list-get.99999_x */
+/* This is still subject to the MAXGET restriction */
+#define HISTGET 30
+
+/* Maximum subject index entries returned by index */
+/* Must be multiple of 100 */
+/* You also have to update /text/bottom in ezmlmrc if you change this */
+#define MAXINDEX 2000
+
+/* Max dir/text file size allowed by -edit */
+#define MAXEDIT 10240
+
+/* Timeout in seconds before a bounce warning is sent. Default is  */
+/* 1000000, i.e. 11.57 days. Setting it lower reduces the number of */
+/* messages in the bouce dir, but makes it more likely that an address */
+/* is unsubscribed due to a temporary error. This compile-time default */
+/* should rarely need changing, as it can be overridden with the ezmlm-warn */
+/* -t switch */
+#define BOUNCE_TIMEOUT 1000000L
+
+/* ezmlm-limit defaults. Convert to moderation or defer if more than  */
+/* LIMMSG messages arrive within LIMSECS */
+#define LIMMSG 30L
+#define LIMSECS 3600L
+
+/* Command names and alternative command names */
+/* all alternates must be defined! */
+/* The language-specific blocks need to undefine and redefine commands */
+
+#define ALT_LIST "list"
+#define ALT_LISTN "listn"
+#define ALT_EDIT "edit"
+#define ALT_FAQ "faq"
+#define ALT_GET "get"
+#define ALT_HELP "help"
+#define ALT_INDEX "index"
+#define ALT_INFO "info"
+#define ALT_LOG "log"
+#define ALT_REQUEST "request"
+#define ALT_SUBSCRIBE "subscribe"
+#define ALT_THREAD "thread"
+#define ALT_UNSUBSCRIBE "unsubscribe"
+#define ALT_QUERY "query"
+
+/* to get alternative command names, you need to undefine and redefine */
+/* them. Do this within a language block and send it to the author for */
+/* inclusing in future versions. If it's here already, just uncomment the */
+/* define for the appropriate language. */
+/* #define LANG_FR 1 */
+
+/* French Version */
+#ifdef LANG_FR
+#undef ALT_SUBSCRIBE
+#define ALT_SUBSCRIBE "-inscription"
+#undef ALT_UNSUBSCRIBE
+#define ALT_UNSUBSCRIBE "-desinscription"
+#endif
+/* end French Version */
+
+/* Text that is used in the outgoing messages (there is some other text, but */
+/* it needs to stay constant in order to comply with rfc1153 */
+
+/* Topics (messages nnn through mmm):\n */
+#define TXT_TOP_TOPICS "Topics"
+#define TXT_TOP_MESSAGES " (messages "
+#define TXT_TOP_THROUGH " through "
+#define TXT_TOP_LAST "):\n"
+
+/* in digest */
+#define TXT_ADMINISTRIVIA "\nAdministrivia:\n\n"
+#define TXT_SUPPRESSED "\n<suppressed>\n\n"
+
+/* for the message author line: 000 by */
+/* keep this short! */
+#define TXT_BY " by: "
+
+/* Since this is now run-time configurable, we'll go with the lowest */
+/* common denominator (per rfc2046). -> ISO-8859-1 if you don't like that */
+#define TXT_DEF_CHARSET "us-ascii"
+
+/* should start with 20 'a' [in place of hash] */
+#define TXT_NOINDEX "aaaaaaaaaaaaaaaaaaaa <- subject index not available for message(s) ->\n"
+
+/* When copy of the message is suppressed (is this really used?)*/
+#define TXT_SUPPRESSED "\n<suppressed>\n\n"
+
+/* Subject: MODERATE for inlocal@inhost */
+#define TXT_MODERATE "MODERATE for "
+
+/* Subject: Returned post for inlocal@inhost */
+/* (used both for rejected and timed-out posts) */
+#define TXT_RETURNED_POST "Returned post for "
+
+/* Subject: CONFIRM subscribe to | unsubscribe from */
+#define TXT_USRCONFIRM "confirm "
+#define TXT_MODCONFIRM "CONFIRM "
+#define TXT_SUBSCRIBE_TO "subscribe to "
+#define TXT_UNSUBSCRIBE_FROM "unsubscribe from "
+
+/* Subject: WELCOME to */
+#define TXT_WELCOME "Subject: WELCOME to "
+
+/* Subject: GOODBYE from */
+#define TXT_GOODBYE "Subject: GOODBYE from "
+
+/* Subject: ezmlm response\n */
+#define TXT_EZMLM_RESPONSE "Subject: ezmlm response\n"
+
+/* Subject: majordomo results\n\n [where "majordomo" is outlocal] */
+#define TXT_RESULTS " results\n\n"
+
+/* Subject: Edit file xxx for list@host */
+#define TXT_EDIT_RESPONSE "Subject: EDIT "
+#define TXT_EDIT_FOR " for "
+
+/* Subject: Editable text files\n */
+#define TXT_EDIT_LIST "Subject: List of editable text files\n"
+
+/* markers for ezmlm-manage text file edit */
+/* MUST start with '%' */
+#define TXT_EDIT_START "%%% START OF TEXT FILE"
+#define TXT_EDIT_END "%%% END OF TEXT FILE"
+
+#define TXT_EDIT_SUCCESS "Subject: Success editing "
+
+/* Text for '-list' command */
+#define TXT_LISTMEMBERS "\nSubscribers to this list are:\n\n"
+
+/* Output formats - letter used to override default */
+#define FORMATS "mrvnx"
+#define MIME 'm'
+#define RFC1153 'r'
+/* ---------------- virgin = MIME without header processing */
+#define VIRGIN 'v'
+/* NATIVE 'n' = VIRGIN without threading */
+#define NATIVE 'n'
+/* MIXED => multipart/mixed MIME instead of multipart/digest. Needed to bypass*/
+/* pine bug when content-transfer-encoding is used (pine fails to show the */
+/* initial encoded text/plain part of mulpart/digest, but not of ../mixed) */
+#define MIXED 'x'
+/* default output format. */
+#define DEFAULT_FORMAT MIME
+
+/* Use MIME enclosure for message to moderate by default (1) or not (0) */
+/* ezmlm-store switches -m/-M override */
+#define MOD_MIME 1
+
+/* Used to add "filname=listname.msgno" to digest part content-type line.
+   This confuses the heck out of Outlook Express 5.0. To circumvent this
+   bug the addition has been removed. Uncomment the next line to get it
+   anyway. */
+/* #define DIGEST_PART_FILENAME */
+
+/* Mode of messages in archive. For ezmlm-0.53 this is 0744, but for  */
+/* "secret" lists it may make more sense to make it 0700.             */
+#define MODE_ARCHIVE 0744
+
+/* ezmlm-get actions  (ACTION_GET also for -get in ezmlm-manage) */
+#define ACTION_GET "get"
+#define ACTION_INDEX "index"
+#define ACTION_THREAD "thread"
+
+/* ezmlm-request actions */
+#define ACTION_REQUEST "request"
+
+/* actions for post acceptance/rejection */
+#define ACTION_ACCEPT "accept-"
+#define ACTION_REJECT "reject-"
+
+/* ezmlm-manage actions */
+#define ACTION_LIST "list"
+#define ACTION_LISTN "listn"
+#define ACTION_HELP "help"
+#define ACTION_INFO "info"
+#define ACTION_FAQ "faq"
+#define ACTION_LOG "log"
+#define ACTION_SUBSCRIBE "subscribe"
+#define ACTION_UNSUBSCRIBE "unsubscribe"
+#define ACTION_QUERY "query"
+#define ACTION_EDIT "edit"
+/* if you change this, you MUST ADJUST LENGTH_ED as well! */
+#define ACTION_ED "ed."
+#define LENGTH_ED 3
+
+/* ACTION_XC has to be a string "-xc." where x is any letter. All commands */
+/* should have different letters. They no longer have to match the first    */
+/* letter of subscribe/unsubscribe. */
+/* The third char of ACTION_SC/TC/UV/VC has to be 'c' */
+
+/* user subscription confirm */
+#define ACTION_SC "sc."
+/* moderator subscription confirm */
+#define ACTION_TC "tc."
+/* user unsubscribe confirm */
+#define ACTION_UC "uc."
+/* moderator unsubscribe confirm */
+#define ACTION_VC "vc."
+
+/* name addition for digest, i.e. list-"digest" Don't change! */
+#define ACTION_DIGEST "digest"
+
+/* name addition for dir/extra db, i.e. list-"allow" */
+#define ACTION_ALLOW "allow"
+/* name addition for dir/blacklist db, i.e. list-"deny" */
+#define ACTION_DENY "deny"
+
+/* defaults for message time out in moderation queue. If modsub is 0 */
+/* or empty, DELAY_DEFAULT is used. If it is set, it is made to be  */
+/* within DELAY_MIN .. DELAY_MAX. All in hours. */
+#define DELAY_MIN 24
+#define DELAY_DEFAULT 120
+#define DELAY_MAX 240
+
+/* Mode of messages in moderation queue. The owner mode is |'d with 7.*/
+/* The group/world mode can be set to anything, but it really doesn't */
+/* make sense to make these messages visible to anyone else.          */
+#define MODE_MOD_MSG 0700
+
+/* name and location of system-wide customized ezmlmrc. This is where */
+/* ezmlm-make looks first (unless the -c switch is specified) before  */
+/* falling back to the (usually unchanged) version in the ezmlm bin   */
+/* directory. */
+#define TXT_ETC_EZMLMRC "/etc/ezmlm/ezmlmrc"
+
+/* same name added to auto_bin. Note leading slash! */
+#define TXT_EZMLMRC "/ezmlmrc"
+
+/* same in dot dir for local config (-c) */
+#define TXT_DOTEZMLMRC ".ezmlmrc"
+
+/* name of config file for ezmlm-cron */
+#define TXT_EZCRONRC "ezcronrc"
+
+/* default timestamp for ezmlm-limit */
+#define TXT_LOOPNUM "loopnum"
+
+/* ezmlm-cgi config file for normal SUID root install */
+#define EZ_CGIRC "/etc/ezmlm/ezcgirc"
+
+/* ezmlm-cgi config file for local install we expect to find the file in PWD */
+#define EZ_CGIRC_LOC ".ezcgirc"
+
+/* default charset for ezmlm-cgi [config file overrides per list] */
+#define EZ_CHARSET "iso-8859-1"
+
+/*------------ Specific to SQL version ------------------------------*/
+/* cookie tag for SQL version of sublisting */
+/* NOTE: Need to include terminal space! */
+#define TXT_TAG "X-Ezauth: "
+
+/* max no of bounces that ezmlm-receipt stores */
+#define MAX_MAIN_BOUNCES 50
+
+/* Length of domain field for SQL version. It does only the text after */
+/* the last '.' in the address, so there is no reason to set it to */
+/* anything other than '3'. We truncate it rather than relying on the */
+/* SQL Server since we can't be sure that the SQL Server doesn't have */
+/* buffer overrun holes and the address is user-controlled */
+#define DOMAIN_LENGTH 3
+
+/* programs used for outgoing mail. Normally, qmail-queue is used. Replace */
+/* with qmail-qmqpc to use only qmqp for outgoing mail. QMQPC is for */
+/* large lists when DIR/qmqpservers is present. Only posts and digests will */
+/* use QMQP. If the normal qmail-qmqpc is used the contents of */
+/* DIR/qmqpcservers are ignored. With a patch, qmail-qmqpc will use the */
+/* servers on it's command line. In this case, the IP addresses listed one */
+/* per line in DIR/qmqpservers will be tried until a working one is found. */
+/* the option is mainly to allow large list clusters on a single host to use */
+/* different QMQPC hosts as exploders.*/
+#define PROG_QMAIL_QUEUE "bin/qmail-queue"
+#define PROG_QMAIL_QMQPC "bin/qmail-qmqpc"
+
+/*---------- Things below this line are not configurable -----------*/
+/* file in DIR that has the qmqpc servers (if any) */
+#define QMQPSERVERS "qmqpservers"
+/* database types */
+#define FLD_DIGEST 1
+#define FLD_ALLOW 2
+#define FLD_DENY 3
+/* Action types */
+#define AC_NONE 0
+#define AC_GET 1
+#define AC_DIGEST 2
+#define AC_THREAD 3
+#define AC_INDEX 4
+#define AC_LIST 5
+#define AC_HELP 6
+#define AC_EDIT 7
+#define AC_DENY 8
+#define AC_LOG 9
+#define AC_SUBSCRIBE 10
+#define AC_UNSUBSCRIBE 11
+#define AC_SC 12
+#define AC_LISTN 13
+
+typedef struct msgentry {      /* one per message in range */
+  unsigned long subnum;                /* subject number */
+  unsigned long authnum;       /* message author number */
+  unsigned int date;           /* yyyymm as number */
+} msgentry;
+
+typedef struct subentry {      /* one per unique subject in message range */
+  void *higher;
+  void *lower;
+  char *sub;                   /* string with terminating '\0' */
+                               /* when building, higher/lower=0 marks end */
+                               /* of branch. When printing, start at the  */
+                               /* beginning of the table and go up until  */
+                               /* sub = 0. */
+  unsigned int sublen;
+  unsigned long firstmsg;      /* the first message with this subject*/
+  unsigned long lastmsg;       /* the last message with this subject*/
+  unsigned char msginthread;   /* number of messages seen in this thread */
+} subentry;
+
+typedef struct authentry {     /* one per unique author in message range */
+  void *higher;
+  void *lower;
+  char *auth;                  /* string with terminating '\0' */
+                               /* when building, higher/lower=0 marks end */
+                               /* of branch. When printing, start at the  */
+                               /* beginning of the table and go up until  */
+                               /* auth = 0. */
+  unsigned long authlen;
+  unsigned long firstmsg;      /* the first message with this author */
+                               /* lastmsg not very useful as author are less */
+                               /* clustered than threads */
+} authentry;
+
+typedef struct dateentry {     /* date yyyymm and 1st message of that date */
+  unsigned int date;
+  unsigned int msg;
+} dateentry;
+
+#endif
+
diff --git a/idx.patch b/idx.patch
new file mode 100644 (file)
index 0000000..7fd82fa
--- /dev/null
+++ b/idx.patch
@@ -0,0 +1,3038 @@
+--- ezmlm-warn.1       1998/02/17 00:32:45     1.1
++++ ezmlm-warn.1       1998/12/21 04:35:16     1.5
+@@ -3,6 +3,15 @@
+ ezmlm-warn \- send out bounce warnings
+ .SH SYNOPSIS
+ .B ezmlm-warn
++[
++.B \-dD
++][
++.B \-t
++.I timeout
++][
++.B \-l
++.I lockout
++]
+ .I dir
+ .SH DESCRIPTION
+ .B ezmlm-warn
+@@ -12,27 +21,91 @@
+ .B ezmlm-warn
+ scans
+-.I dir\fB/bounce
+-for bounce messages received by
+-.BR ezmlm-return .
+-If it sees a distribution bounce for
++.I dir\fB/bounce/d/
++for directories older than
++.I timeout
++days ago (see
++.BR \-t ).
++The directories are created by
++B ezmlm-return
++and contain bounces.
++If
++.B ezmlm-warn
++sees a distribution bounce for
+ .I box\fB@\fIdomain
+-received more than ten days ago,
++received more than
++.I timeout
++days ago,
+ it sends
+ .I box\fB@\fIdomain
+ a list of all the message numbers missed recently,
+ and deletes the bounce.
+ If it sees a warning bounce for
+ .I box\fB@\fIdomain
+-received more than ten days ago,
++received more than
++.I timeout
++days ago,
+ it sends
+ .I box\fB@\fIdomain
+ a probe,
+ and deletes the bounce.
+ .B ezmlm-warn
++uses
++.I dir\fB/bounce/lastd
++to keep track of when it was last run. If insufficient time has
++passed (see
++.BR \-l )
++.B ezmlm-warn
++exits without further action.
++
++.B ezmlm-warn
++keeps files with the bounced message numbers in
++.IR dir\fB/bounce/h .
++Expired files are removed and
++.I dir\fB/bounce/lasth
++keeps track of the last subdirectory scanned.
++
++.B ezmlm-warn
+ will not send a warning or probe to an address that is
+ not currently a subscriber.
++.SH OPTIONS
++.TP
++.B \-d
++process bounces for the digest list, rather than for the main list.
++Digest list bounces are stored in
++.I dir\fB/digest/bounce/
++rather than in
++.IR dir\fB/bounce/ .
++.TP
++.B \-D
++(Default.)
++Process bounces for the main list.
++.TP
++.B \-l \fIlockout
++.B ezmlm-warn
++will abort execution if it was run less than
++.I lockout
++seconds ago. The default is
++.I timeout /
++50, which with the default
++.I timeout
++is 20,000 seconds (approx. 5.6 hours). There is no reason to use this
++switch, except for testing and possibly in combination with
++.BR \-t.
++.TP
++.B \-t \fItimeout
++Bounces received more than
++.I timeout
++days ago are processed. This overrides the default of 1,000,000
++seconds (approximately 10 days)
++and may possibly be useful for very large busy lists. Also, a
++.I timeout
++of zero can be used to send a warning to all addresses for which
++a bounce has been received and a probe for all addresses for which a
++warning has bounces.
++This is useful to rapidly clear
++out bouncing addresses from a (low quality) address list.
+ .SH "SEE ALSO"
+ ezmlm-make(1),
+ ezmlm-return(1),
+--- ezmlm-return.1     1998/02/17 00:33:15     1.1
++++ ezmlm-return.1     1999/08/19 03:57:54     1.6
+@@ -3,12 +3,16 @@
+ ezmlm-return \- handle mailing list bounces
+ .SH SYNOPSIS
+ .B ezmlm-return
++[
++.B \-dD
++]
+ .I dir
+ .SH DESCRIPTION
+ .B ezmlm-return
+ handles bounces for the mailing list
+ stored in
+-.IR dir .
++.I dir
++and, if it exists, the associated digest list.
+ .B ezmlm-return
+ is normally invoked from a
+@@ -21,6 +25,30 @@
+ and
+ .BR HOST
+ environment variables.
++
++.B ezmlm-return
++exits 99, not 0, upon success.
++.SH OPTIONS
++.TP
++.B \-d
++.B ezmlm-return
++will assume the bounce is for a digest list.
++Normally,
++.B ezmlm-return
++will autodetect this from the bounce address. Autodetection makes
++.B ezmlm-return
++less flexible and will be removed in future versions.
++.TP
++.B \-D
++.B ezmlm-return
++will assume that the bounce is for a normal (non-digest) list.
++Normally,
++.B ezmlm-return
++will autodetect this from the bounce address. Autodetection makes
++.B ezmlm-return
++less flexible and will be removed in future versions.
++.B \-D
++will become the default.
+ .SH ADDRESSES
+ .B ezmlm-return
+ handles mail sent to any of the following addresses:
+@@ -59,6 +87,21 @@
+ will remove
+ .I box\fB@\fIdomain
+ from the mailing list.
++.TP
++.I local\fB\-return\-receipt\-\fIcookie\-fImsg\-
++A receipt from the list. This is logged. For SQL supporting lists,
++.I cookie
++is verified and receipt logged only if the cookie is correct. The arrival
++of the receipt shows that qmail at the sending host is running.
++
++For all the above addresses if,
++.I local
++is followed by
++.IR \-digest ,
++bounces are assumed to be from the digest list, and are stored in
++.I dir\fB/digest/bounce
++rather than in
++.I dir \fB/bounce .
+ .SH "SEE ALSO"
+ ezmlm-manage(1),
+ ezmlm-make(1),
+--- ezmlm-send.1       1997/07/23 18:55:45     1.1
++++ ezmlm-send.1       1999/08/19 03:13:36     1.27
+@@ -3,6 +3,11 @@
+ ezmlm-send \- distribute a message to a mailing list
+ .SH SYNOPSIS
+ .B ezmlm-send
++[
++.B \-cCrRvV
++] [
++.B \-h\fI header
++]
+ .I dir
+ .SH DESCRIPTION
+ .B ezmlm-send
+@@ -14,9 +19,34 @@
+ exists,
+ .B ezmlm-send
+ records a copy of the message in the
+-.I dir\fB/archive
++.I dir\fB/archive/
+ directory.
++If
++.I dir\fB/indexed
++exists,
++.B ezmlm-send
++adds the subject, author and time stamp of the message to the index, kept with
++the message in a subdirectory of
++.IR dir\fB/archive/ .
++The subject is processed to make reply-subject entries identical to
++original
++message subject entries.
++The subject index is used for the archive retrieval functions of
++.BR ezmlm-get(1) .  
++Use
++.B ezmlm-idx(1)
++to create a subject index from a preexisting archive.
++
++Subject and author lines are decoded if they are encoded per rfc2047. When
++split lines are unfolded, the number of escape sequences for
++iso-2022-* character sets is minimized. For instance, two
++consequtive toascii sequences are reduced.
++This processing is done for the character set specified in
++.IR dir\fB/charset .
++The result of this process is the same for a given subject, irrespective
++of encoding.
++
+ At the beginning of the message,
+ .B ezmlm-send
+ prints a new
+@@ -27,10 +57,24 @@
+ .B Mailing-List
+ field.
++If
++.I dir\fB/listid
++exists,
++.B ezmlm-send
++will assume that the format is correct and
++create a ``List-ID:'' header by placing the contents after the
++text ``List-ID: ''. 
++
++Next,
++.B ezmlm-send
++prints all the new fields listed in
++.IR dir\fB/headeradd .
++Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in these headers
++are replaced by the list host name, list local name, and message number,
++respectively.
++
+ .B ezmlm-send
+-then prints all the new fields listed in
+-.IR dir\fB/headeradd ,
+-followed by an appropriate
++then prints an appropriate
+ .B Delivered-To
+ line.
+@@ -39,6 +83,63 @@
+ .IR dir\fB/headerremove .
+ .B ezmlm-send
++removes MIME parts specified in
++.I dir\fB/mimeremove
++before archiving and distribution of the message.
++
++If
++.I dir\fB/text/trailer
++exists,
++.B ezmlm-send
++adds the trailer to simple text/plain messages in the same encoding as used for
++the the message. However, if the encoding is ``base64'' it is not safe
++to do this and the header is suppressed.
++For composite MIME messages, the trailer is added as a separate
++part, with the character set and encoding specified in
++.IR dir\fB/charset .
++The trailer is not added to multipart/alternative messages.
++Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in
++.I dir\fB/text/trailer
++are replaced by the list host name, list local name, and message number,
++respectively.
++
++If
++.I dir\fB/prefix
++exists,
++.B ezmlm-send
++will prefix the subject line with the first line of this
++file. A space will be added to separate
++.B prefix
++from the subject text.
++.B prefix
++is ignored for sublists. If
++.I dir\fB/prefix
++contains a ``#'', the last ``#'' will be replaced by the message number.
++Any prefix starting with text of a
++reply indicator (``Re:'', ``Re[n]:'', etc) will cause problems.
++The prefix may be
++rfc2047 encoded. Rfc2047 Iso-2022-* encoded prefixes
++.I must
++end in ascii.
++
++The prefix feature and especially the message number feature
++modify the message in violation
++with Internet mail standards. The features have been implemented by popular
++demand. Use at your own peril.
++
++.I dir\fB/sequence
++is ignored as of ezmlm-idx-0.32. Use
++.I dir\fB/headeradd
++with substitution to achieve the same goal.
++
++If
++.I dir\fB/qmqpservers
++exists,
++.B ezmlm-send will use
++.B qmail-qmqp(1)
++to send messages.
++
++.B ezmlm-send
+ does not distribute bounce messages:
+ if the environment variable
+ .B SENDER
+@@ -46,6 +147,60 @@
+ .BR #@[] ,
+ .B ezmlm-send
+ rejects the message.
++.SH OPTIONS
++.TP
++.B \-c
++No longer supported. Ignored for backwards compatibility.
++.TP
++.B \-C
++No longer supported. Ignored for backwards compatibility.
++.B ezmlm-send
++has to parse the subscriber database.
++.TP
++.B \-h\fI header
++If the list is a sublist, i.e.
++.I dir\fB/sublist
++exists,
++.I header
++is required in all messages to the list. This option is used
++when ezmlm is used to run a sublist of a lists run by a different
++mailing list
++manager that uses
++.I header
++rather than ``Mailing-List'' to identify messages from the list.
++Anything after the first colon (if present) in
++.I header
++is ignored.
++.TP
++.B \-r
++Copy incoming ``Received:'' headers to the outgoing message.
++.TP
++.B \-R
++(Default.)
++Do not copy incoming ``Received:'' headers, except the one added by
++the (last) listhost, to the outgoing message.
++In some
++cases, especially for sublists,
++the messages can have a large number of ``Received:''
++headers. This may lead to bounces for some users due to
++sendmail ``hopcounts'' set too low somewhere in the mail path. These users can
++subscribe and receive warning and probe messages, but no list messages, unless
++the number of ``Received:'' headers is reduced.
++
++Pre-list ``Received:'' headers are of little interest to normal list
++subscribers. ``Received:'' headers are
++still copied to the archive and available
++to anyone from there for message tracking purposes.
++.TP
++.B \-v
++Display
++.B ezmlm-send
++version information.
++.TP
++.B \-V
++Display
++.B ezmlm-send
++version information.
+ .SH "SUBLISTS"
+ If
+ .I dir\fB/sublist
+@@ -77,10 +232,71 @@
+ does not add its own
+ .B Mailing-List
+ field.
++
++Fourth,
++.B ezmlm-send
++uses the incoming message number for the outgoing message, if the list
++is not archived and the incoming SENDER has the correct format.
++This allows you to refer bounce warning recipients to the main list for
++archive retrieval of the missed messages. If the sublist archives
++message, it is assumed that missed messages will be retrieved from the sublist
++archive.
++
++The list
++still increments
++.I dir\fB/num
++for each message. If the sublist is archived, use of incoming message number
++for archive storage would be a security risk. In this case, the local sublist
++message number is used.
++.SH "OPTION USAGE"
++In general, the use of a prefix is discouraged. It wastes subject line space,
++creates trouble when MUAs add non-standard reply indicators. However, many
++users expect it not because it is useful, but because they are used to it.
++
++The
++.B \-C
++switch prevents posts from being set to SENDER. Rather than just copying
++out subscriber address files,
++.B ezmlm-send
++has to parse them to look for SENDER. This makes it less efficient. Also,
++it is useful for the SENDER to see the post to know that it has made it
++to the list, and it's context to other subscribers, i.e. where it came
++within the traffic of messages on the list.
++
++Avoiding SENDER as a recipient is useful in small lists, such as small
++teams with varying members, where ezmlm serves mainly as an efficient tool
++to keep the team connected without administrator intervention. Here the
++overhead of subscriber list parsing is negligible.
++.SH "CHARACTER SETS"
++If the list is indexed,
++.B ezmlm-send
++will keep a message index. rfc2047-encoded subject and from lines will be
++decoded.
++If
++.I dir\fB/charset
++exists,
++.B ezmlm-send
++will eliminate redundant escape sequences from the headers according to
++the character set specified in this file.
++Only character sets using escape sequences need this support. Currently,
++supported are iso-2022-jp*, iso-2022-kr, and iso-2022-cn*. Only iso-2022-jp
++has been tested extensively.
++
++The character set can be suffixed
++by ``:'' followed by a code. Recognized codes are ``Q'' 
++for ``Quoted-Printable'', and ``B'' for ``base64''.
++
++For
++.BR ezmlm-send ,
++this affects the format of the trailer, if a trailer is specified and if the
++message is a multipart mime message
+ .SH "SEE ALSO"
++ezmlm-get(1),
++ezmlm-idx(1),
+ ezmlm-manage(1),
+ ezmlm-make(1),
+ ezmlm-sub(1),
+ ezmlm-unsub(1),
+ ezmlm-reject(1),
+-ezmlm(5)
++ezmlm(5),
++qmail-qmqp(1)
+--- ezmlm-sub.1        1998/12/06 16:48:14     1.1
++++ ezmlm-sub.1        1999/08/19 03:22:14     1.5
+@@ -3,9 +3,20 @@
+ ezmlm-sub \- manually add addresses to a mailing list
+ .SH SYNOPSIS
+ .B ezmlm-sub
++[
++.B \-HmMnNsSvV
++][
++.B \-h
++.I hash
++]
++.B 
+ .I dir
+ [
+-.I box\fB@\fIdomain ...
++.I box\fB@\fIdomain 
++[
++.I name
++]
++.I ...
+ ]
+ .SH DESCRIPTION
+ .B ezmlm-sub
+@@ -13,12 +24,20 @@
+ .I box\fB@\fIdomain
+ to the mailing list stored in
+ .IR dir .
++.I name
++is added as a comment to the subscription log, if the
++.B \-n
++switch is used.
++
++If no argument is given on the command line,
++.B ezmlm-sub
++processes stdin.
+ If
+ .I box\fB@\fIdomain
+ is already on the mailing list,
+ .B ezmlm-sub
+-leaves it there.
++leaves it there and does not modify the subscription log.
+ .B ezmlm-sub
+ converts
+@@ -28,11 +47,61 @@
+ to the mailing list.
+ .I box\fB@\fIdomain
+-cannot be longer than 400 characters.
++cannot be longer than 400 characters (255 characters with mysql support).
++.SH "GENERAL OPTIONS"
++.TP
++.B \-n
++Assume arguments are pairs of
++.I box\fB@\fIdomain
++and
++.IR name
++(or other subscriber info)
++rather than addresses alone.
++.B ezmlm-sub(1)
++will add the first argument in each pair to the subscriber list. If it is
++a new address,
++.I name
++will be added to the subscription log.
++.TP
++.B \-N
++(Default.)
++Arguments are all addresses of the type
++.IR box\fB@\fIdomain .
++.TP
++.B \-v
++Display
++.B ezmlm-sub(1)
++version information.
++.TP
++.B \-V
++Display
++.B ezmlm-sub(1)
++version information.
++.SH "MYSQL OPTIONS"
++These option is silently ignored in the absence of mysql support.
++.TP
++.B \-h \fIhash
++With mysql support the argument is used as the hash. The argument should
++be between 1 and 99. The hash is used in
++in the distribution of addresses between sublists. As the hash is normally
++between 0 and 52, controlling the hash makes it possible to add addresses
++that cannot be manipulated remotely.
++.TP
++.B \-m
++(Default.)
++Use SQL support if available.
++.TP
++.B \-M
++Do not use SQL support even if available. This option can be used to build
++a normal local subscriber database even for lists with SQL support. Use
++in combination with
++.B ezmlm-list(1)
++to convert an SQL address db to a ezmlm standard address database.
+ .SH "SEE ALSO"
+ ezmlm-list(1),
+ ezmlm-manage(1),
+ ezmlm-make(1),
++ezmlm-receipt(1),
+ ezmlm-send(1),
+ ezmlm-unsub(1),
+ ezmlm(5)
+--- ezmlm-unsub.1      1998/12/06 16:48:14     1.1
++++ ezmlm-unsub.1      1999/08/19 03:22:14     1.5
+@@ -3,6 +3,11 @@
+ ezmlm-unsub \- manually remove addresses from a mailing list
+ .SH SYNOPSIS
+ .B ezmlm-unsub
++[
++.B \-mMHvV
++] [
++.B \-h\fBhash
++]
+ .I dir
+ [
+ .I box\fB@\fIdomain ...
+@@ -14,6 +19,10 @@
+ from the mailing list stored in
+ .IR dir .
++If no command line argument is given,
++.B ezmlm-unsub
++will process stdin instead.
++
+ If
+ .I box\fB@\fIdomain
+ is not on the mailing list,
+@@ -26,10 +35,46 @@
+ to lowercase before removing
+ .I box\fB@\fIdomain
+ from the mailing list.
++.SH "GENERAL OPTIONS"
++.TP
++.B \-v
++Display
++.B ezmlm-unsub(1)
++version information.
++.TP
++.B \-V
++Display
++.B ezmlm-unsub(1)
++version information.
++.SH "MYSQL OPTIONS"
++These option is silently ignored in the absence of mysql support.
++.TP
++.B \-h \fIhash
++With mysql support the argument is used as the hash. The argument should
++be between 1 and 99. The hash is used in
++in the distribution of addresses between sublists. As the hash is normally
++between 0 and 52, controlling the hash makes it possible to remove addresses
++that cannot be manipulated remotely. A hash of 99 is reserved for sublists,
++and a hash of 98 is reserved for ``receipt'' addresses serviced by
++.B ezmlm-receipt(1).
++.TP
++.B \-H
++(Default.)
++The address can be removed if it has a hash in the normal range (0..52).
++.TP
++.B \-m
++(Default.)
++Use SQL support if available.
++.TP
++.B \-M
++Do not use SQL support even if available.
++This option can be used to manipulate
++a normal local subscriber database even for lists with SQL support.
+ .SH "SEE ALSO"
+ ezmlm-list(1),
+ ezmlm-manage(1),
+ ezmlm-make(1),
++ezmlm-receipt(1),
+ ezmlm-send(1),
+ ezmlm-sub(1),
+ ezmlm(5)
+--- ezmlm-list.1       1998/12/06 16:48:14     1.1
++++ ezmlm-list.1       1999/08/19 03:40:27     1.5
+@@ -3,6 +3,11 @@
+ ezmlm-list \- show the addresses on a mailing list
+ .SH SYNOPSIS
+ .B ezmlm-list
++[
++.B \-n\fI msgnum
++] [
++.B \-aAmMnNvV
++]
+ .I dir
+ .SH DESCRIPTION
+ .B ezmlm-list
+@@ -16,6 +21,40 @@
+ of a possibly malicious remote user.
+ .B ezmlm-list
+ does not strip control characters.
++.SH "GENERAL OPTIONS"
++.TP
++.B \-m
++(Default.)
++Use SQL support if available.
++.TP
++.B \-M
++Do not use SQL support even if available.
++This option can be used to manipulate
++a normal local subscriber database even for lists with SQL support.
++.TP
++.B \-n
++Print only the number of subscribers.
++.TP
++.B \-N
++(Default.)
++List subscriber addresses, one per line.
++.TP
++.B \-v
++Display
++.B ezmlm-list(1)
++version information.
++.TP
++.B \-V
++Display
++.B ezmlm-list(1)
++version information.
++.SH "SEE ALSO"
++ezmlm-list(1),
++ezmlm-manage(1),
++ezmlm-make(1),
++ezmlm-send(1),
++ezmlm-sub(1),
++ezmlm(5)
+ .SH "SEE ALSO"
+ ezmlm-sub(1),
+ ezmlm-unsub(1),
+--- ezmlm.5    1997/07/13 22:01:50     1.1
++++ ezmlm.5    1999/05/12 22:41:46     1.24
+@@ -21,7 +21,60 @@
+ handles administrative requests automatically;
+ .B ezmlm-send
+ sends a message to all subscribers listed in
+-.IR dir .
++.I dir
++and also maintains a message archive and message subject index if the list
++is configured to do so.
++.B ezmlm-reject
++rejects messages that have an empty subject, or a subject consisting of
++only a command word;
++.B ezmlm-return
++handles bounces;
++.B ezmlm-warn
++warns users for which messages bounce and eventually removes them from
++the subscriber list.
++.B ezmlm-idx
++can create a subject index from an existing list archive.
++.B ezmlm-get
++manages message, index, and thread retrieval from the archive, as well
++as the generation of message digests;
++.B ezmlm-cron
++provides a restricted interface to cron for the generation of
++digest generation trigger messages;
++.B ezmlm-store
++queues messages of moderated lists and sends a moderation request to
++the moderator(s);
++.B ezmlm-moderate
++processes moderation requests to accept the queued message to the list
++via
++.B ezmlm-send,
++or to return the message to the sender;
++.B ezmlm-clean
++cleans up the moderation queue and returns to the sender
++any messages that have timed-out;
++.B ezmlm-gate
++posts messages that come from a SENDER in an address database, and sends
++remaining messages out for moderation;
++.B ezmlm-check
++is used to diagnose problems with ezmlm mailing list configuration;
++.B ezmlm-issub
++and
++.B ezmlm-issubn
++determine if a SENDER is a subscriber or a member of a
++collection of addresses;
++.B ezmlm-tstdig
++determines if it is time to create a new digest based on the number and
++volume of messages and the amount of time that has passed since the last
++digest was issued;
++.B ezmlm-request
++can be used to answer
++.B ezmlm
++commands in the subject line easing migration from other mailing list
++managers. It can also function as a global interface mimicking
++the interface of other mailing list manager.
++.B ezmlm-glmake
++can set up the global interface, and
++.B ezmlm-glconf
++can create a configuration file for the global interface from your lists.
+ .SH SUBSCRIBERS
+ .I dir\fB/subscribers
+ is a directory containing the subscriber list.
+@@ -69,12 +122,19 @@
+ .B ezmlm-send
+ archives all new messages if
+ .I dir\fB/archived
+-exists.
++exists. If
++.I dir\fB/indexed
++exists,
++.B ezmlm-send
++also maintains a message subject and author index.
+ Messages sent to the mailing list are numbered from 1 upwards,
+ whether or not they are archived.
+ .I dir\fB/num
+-is the number of messages sent so far.
++is the number of messages sent so far followed by ':', followed by the
++cumulative amount of message body that has passed
++.B ezmlm-send
++stored as kbytes * 4 (4 corresponds to 1kb).
+ .I dir\fB/archive
+ has subdirectories,
+@@ -83,11 +143,43 @@
+ .IR dir\fB/archive/\fIm\fB/\fIn .
+ For example, message number 15307 is stored in
+ .IR dir\fB/archive/153/07 .
++The message index is stored in the file
++.B index
++in the same subdirectory of
++.I dir\fB/archive
++holding the corresponding messages.
++Thus, the subject index contains up to 100 entries.
++
++The subject index contains message subjects that are normalized so that
++the original message and all replies have the same entry. The subject index
++is used for advanced message retrieval functions. For safety, the subject
++index is created under a temporary name
++inside
++.I dir\fB/archive
++and then moved into place.
+ .B ezmlm-manage
+ will ignore message files without the owner-execute bit set.
+ .B ezmlm-send
+ turns on the owner-execute bit after safely writing the message to disk.
++
++.B ezmlm-make
++by default adds
++.B ezmlm-get
++to
++.I dir\fB/manager
++to handle 
++.I \-get, \-index,
++and
++.I \-thread
++requests. If
++.B ezmlm-make
++is invoked with a 
++.I digcode
++command line argument, digest creation
++is enabled by putting this argument on the
++.B ezmlm-get
++command line.
+ .SH BOUNCES
+ .I dir\fB/bounce
+ is a directory containing bounce messages.
+@@ -127,9 +219,10 @@
+ sets up
+ .I dir\fB/bouncer
+ to invoke
+-.B ezmlm-return
+-and then
+-.BR ezmlm-warn .
++.BR ezmlm-return .
++.B ezmlm-warn
++is no longer invoked here due to the load it places on systems with many
++large lists with many bounces.
+ .I dir\fB/manager
+ handles incoming administrative requests.
+@@ -137,9 +230,266 @@
+ sets up
+ .I dir\fB/manager
+ to invoke
+-.B ezmlm-manage
++.BR ezmlm-get ,
++.BR ezmlm-manage ,
+ and then
+ .BR ezmlm-warn .
++
++.I dir\fB/moderator
++handles incoming message
++.I accept
++and
++.I reject
++requests for moderated lists.
++.B ezmlm-make
++sets up
++.I dir\fB/moderator
++to invoke
++.BR ezmlm-moderate ,
++and .BR ezmlm-clean .
++.SH DIGESTS
++.B ezmlm-get
++can create digests if it is invoked from the command line, from
++.IR dir\fB/editor ,
++or from
++.IR dir\fB/manager .
++The program functions in slightly different ways in these 3 settings (see
++.BR ezmlm-get(1) ).
++
++To enable automatic digests for a mailing list, use the
++.B ezmlm-make \-d
++switch. To also enable the generation of digests at specific times dictated
++by mailed trigger messages, a
++.I digcode
++should be specified on the
++.B ezmlm-get
++command line.
++This can be done by specifying
++.I digcode
++as a fifth argument to
++.B ezmlm-make
++when setting up the list.
++.I digcode
++must be alphanumeric and is case-insensitive.
++
++To generate trigger messages, use
++.B ezmlm-cron(1)
++as an interface to
++.B crond(8)
++or use
++.B crond
++directly.
++
++.I dir\fB/num
++contains the number of the last message processed, followed by ':' and a
++number that is increased by 1 for each 256 bytes of message body text
++processed. The latter number is used by
++.B ezmlm-tstdig
++to determine if a new digest is due.
++
++.I dir\fB/dignum
++contains the contents of
++.I dir\fB/num
++at the time of the last regular digest creation, followed by a ':',
++followed by a timestamp.
++It is updated after each regular digest is sent.
++
++.I dir\fB/digissue
++contains the issue number of the last regular digest. It is incremented
++for each regular digest sent.
++
++The following user crontab entry (all on one line)
++generates a digest of the list
++.I list@host.domain
++at 1600 every day:
++
++.EX
++  00 16 * * * /var/qmail/bin/qmail-inject list-dig.digcode
++.EE
++
++Alternatively,
++.B ezmlm-cron
++can be used:
++
++.EX
++  % ezmlm-cron -t 16:00 list@host digcode
++.EE
++
++.B ezmlm-get
++can also be run from the shell: To generate a digest to
++.I list-digest@host
++from the list housed in
++.IR ~joe/list :
++
++.EX
++  % ezmlm-get ~joe/list
++.EE
++
++Like other
++.B ezmlm-get
++replies, digest can be sent in several formats. See
++.B ezmlm-get(1)
++for more info.
++.SH MODERATION
++There are three aspects of moderation: moderation of posts, moderation
++of subscriptions, and "remote administration", i.e. giving the
++moderator the right to (un)subscribe any user.
++.B ezmlm
++handles these three aspects separately. The two first aspects enhance
++security, while the third decreases security, but makes list administration
++considerably easier. By default, the moderator database is the same for all
++three functions. While "remote administration" and subscription moderation
++always use the same database, the moderators for message moderation can
++be different.
++
++Even with subscription moderation, the user has to verify the request. This
++is to ensure that the user initiating the request really controls the address.
++.B ezmlm-manage
++options exist to disable the user handshake, which may be useful in some
++circumstances.
++
++For moderation options, the moderators are by stored in a subscriber
++list in
++.IR moddir\fB/subscribers .
++By default
++.I moddir
++is
++.IR dir\fB/mod .
++
++Moderators can be added and removed with:
++
++.EX
++.B ezmlm-sub
++.I moddir
++.I moderator@host
++.EE
++
++.EX
++.B ezmlm-unsub
++.I moddir
++.I moderator@host
++.EE
++
++For subscription moderation, touch
++.IR dir\fB/modsub
++after adding moderator(s).
++For remote administration, touch
++.IR dir\fB/remote .
++If the contents of these files start with a leading forward slash, it is 
++assumed to be the name of
++.B moddir
++subscription
++moderation. If both files exist and start with a forward slash, the
++.I dir\fB/remote
++contents are ignored. Moderators are stored in a subscriber list in the
++.B subscribers
++subdirectory of
++.BR moddir .
++If no directory names are specified,
++the default,
++.IR dir\fB/mod ,
++is used.
++In all cases, the
++.I subscribers
++subdirectory of the base directory must exists/be created.
++
++Moderation of messages is achieved by
++creating
++.I dir\fB/modpost
++and  modifying
++.IR dir\fB/editor
++to invoke
++.B ezmlm-store.
++.B ezmlm-store
++stores the message in
++.IR dir\fB/mod/pending
++and sends a moderation request to all moderators stored in
++.IR moddir .
++
++If
++.I dir\fB/modpost
++does not exist,
++.B ezmlm-store
++posts messages directly, and
++.B ezmlm-clean
++does nothing.
++
++If
++.I dir\fB/modpost
++contains a directory name starting with a forward slash,
++this directory is used as
++.I moddir
++for message moderation.
++Moderators are stored in a subscriber list in the
++.I subscribers
++subdirectory of
++.IR moddir .
++If no directory names are specified,
++the default,
++.IR dir\fB/mod ,
++is used.
++
++.IR dir\fB/moderator
++is linked to
++.IR dot\fB\-accept-default
++and
++.IR dot\fB\-reject-default .
++It handles replies from the moderators.
++
++In addition to a moderator list, the directories
++.IR dir\fB/mod/pending ,
++.IR dir\fB/mod/accepted ,
++and
++.IR dir\fB/mod/rejected
++must exist. These directories contain the message moderation queue.
++
++If
++.IR dir\fB/mod/modtime
++it determines the minimal time in hours that messages wait in the moderation
++queue, before they are returned to sender with the message in
++.IR dir\fB/text/mod-timeout .
++
++If a
++.I \-help
++command is send for a moderator and
++.IR dir\fB/modsub
++or
++.IR dir\fB/remote
++exist, a more detailed help message stored in
++.I dir\fB/text/mod-help
++will be sent together with the regular help. This text should not contain
++secrets.
++If
++.I dir\fB/text/mod-help
++does not exist,
++.I dir\fB/text/help
++will be sent.
++
++If a
++.I \-list
++command is sent for a moderator and
++.IR dir\fB/modsub
++or
++.IR dir\fB/remote
++exist, and the
++.B ezmlm-manage \-l
++command line switch is specified, a subscriber list will be returned.
++
++If an
++.I \-edit.file
++command is sent for a moderator and
++.IR dir\fB/remote
++exist, and the
++.B ezmlm-manage \-d
++command line switch is specified,
++.B text\fB/file
++is returned together with an
++.B ezmlm
++cookie. The remote administrator may return an edited version of the
++file, which will be stored, provided that the cookie is valid.
++See
++.B ezmlm-manage(1)
++for more info.
+ .SH TEXT
+ .I dir\fB/text
+ is a directory
+@@ -187,6 +537,27 @@
+ .B get-bad
+ Rejecting a bad archive retrieval request.
+ .TP
++.B digest
++Text copied into the
++.I Administrativia
++section of the digest. Usually, this will contain subscription info
++for the digest, as well as information on how to post to the list.
++.TP
++.B trailer
++If this files exists, it is copied to the end of all messages to the list.
++.TP
++.B faq
++Sent in response to the
++.I faq
++command. Usually contains frequently asked questions and answers specific
++for the mailing list.
++.TP
++.B info
++Sent in response to the
++.I info
++command. Usually contains a descripition, policy, etc, for the list. The
++first line should in itself be a very brief description of the list.
++.TP
+ .B bounce-warn
+ Pointing out that messages have bounced.
+ .TP
+@@ -198,9 +569,96 @@
+ .B ezmlm-return
+ has kept a list of bounced message numbers.
+ .TP
++.B dig-bounce-num
++Explaining that digest messages have bounced. All other text files are used
++for both the main list and the digest list.
++.TP
+ .B bounce-bottom
+ Separating the bounce message.
++.TP
++.B mod-help
++is set to list moderators issuing a
++.I \-help
++command. It contains instructions for moderators, but it is relatively
++trivial for a non-moderator to read it. Don't put secrets here.
++.TP
++.B mod-reject
++is the returned to the sender of a rejected post.
++.TP
++.B mod-timeout
++is returned if the message timed-out without moderator action.
++.TP
++.B mod-sub
++is added to the text confirming subscription and unsubscription
++instead of
++.B bottom
++and the requesting message, for actions that were approved
++by a moderator. Not copying the requesting message
++hides the moderator identity
++from the subscriber.
++.TP
++.B mod-request
++is the text sent to the moderators to request moderator action on
++a posted message.
++.TP
++.B mod-unsub-confirm
++Requesting that the moderator confirm a request to subscribe.
++If this file does not exist,
++.B sub-confirm
++will be used.
++.TP
++.B mod-unsub-confirm
++Requesting that the moderator confirm a request to unsubscribe.
++If this file does not exist,
++.B unsub-confirm
++will be used.
++.TP
++.B edit-do
++Instructions sent to the remote administrator together with a copy
++of a
++.I dir\fB/text
++file and editing instructions.
++.TP
++.B edit-list
++A list of editable files in
++.I dir\fB/text
++with a one-line description send to a remote administrator in response to a
++.I -edit
++command.
++.TP
++.B edit-done
++Sent to the remote administrator after an edited
++.I dir\fB/text
++file has been successfully saved.
++.PP
++Several tags in the text files are replaced by ezmlm programs.
++All programs replace the tag
++.B <#l#>
++with the name of the list or the list-digest, as appropriate for the request,
++and
++.B <#h#>
++with the hostname for the list.
++.B ezmlm-send
++and
++.B ezmlm-get
++replace
++.B <#n#>
++with the current message number in added headers from
++.I dir\fB/headeradd
++and text files.
++.B ezmlm-get
++does this for digest messages, where the current message is the number of
++the first message in the digest.
++.B ezmlm-manage
++replaces the tag
++.B <#A#>
++anywhere on a line with the subscription address, and
++.B <#R#>
++anywhere on a line
++with the address the subscriber must reply to. Only the first tag on any
++line is processed.
+ .PP
++For backwards compatibility,
+ .B ezmlm-manage
+ replaces the line
+ .B !A
+@@ -213,6 +671,23 @@
+ and
+ .B unsub-confirm
+ with the address that the subscriber must reply to.
++.PP
++.B ezmlm-store
++replaces the tag
++.B <#A#>
++anywhere on a line with the address for accepting the message, and
++.B <#R#>
++anywhere on a line
++with the address for rejecting the message.
++Only the first tag on any line is processed.
++.PP
++For backwards compatibility,
++.B ezmlm-store
++also replaces the line
++.B !A
++with the address for accepting the message and the line
++.B !R
++with the address for rejecting the message.
+ .SH "OUTGOING MESSAGE EDITING"
+ .I dir\fB/headerremove
+ is a list of bad header field names,
+@@ -233,10 +708,61 @@
+ is a list of new header fields.
+ .B ezmlm-send
+ adds these fields to every outgoing message.
+-.B ezmlm-make
++.B ezmlm-send
+ sets up
+ .I dir\fB/headeradd
+-with no new fields.
++to add
++.B X-No-Archive: yes
++and
++.BR Precedence: bulk .
++
++If
++.I dir\fB/mimeremove
++exists,
++.B ezmlm-send
++removed parts with the corresponding content-types from composite MIME
++messages. If the
++.B ezmlm-reject
++.I dir
++argument is specified,
++simple MIME messages of these content-types are rejected.
++
++If
++.I dir\fB/mimereject
++exists, and the
++.B ezmlm-reject
++.I dir
++argument is specified,
++simple MIME messages of these content-types, or
++composite MIME messages with any body part of these content-types are rejected.
++
++If
++.I dir\fB/sequence
++exists, the first line is added as a header to all outgoing messages, followed
++by a space and the message number. The message number is useful for archive
++retrievals, since some mail systems do not reveal the return-path to the user.
++.B NOTE:
++Sublists have their own message counter. Adding a sequence header from a
++sublists will give you the sublist message number which is different from
++the main list message number.
++
++.I dir\fB/prefix
++is a subject prefix. If this file exists, its contents are prefixed to the
++subject of the post in the outgoing message. The archived message is not
++processed. Attempts are made to not duplicate an existing prefix in replies.
++Think twice before using this option.
++A prefix takes unnecessary space on the subject line and most mail clients
++can easily filter on other headers, such as 'Mailing-List:'. If
++.I dir\fB/prefix contains a single '#', this will be replaced by the message
++number. The use of this feature is inadvisable and violates internet mail
++standards. However, it is very popular in e.g. Japan. If you must use this
++feature, make sure you are aware that you may be causing problems to users,
++sublists, etc.
++
++.I dir\fB/text/trailer
++is a message trailer. If this file exists, it's contents are copied to the 
++end of outgoing messages. Only lines terminated with new-line are copied.
++No trailer is copied to the archived version of the message.
+ .SH MISCELLANY
+ The first line of
+ .I dir\fB/mailinglist
+@@ -248,6 +774,27 @@
+ .IR dir\fB/mailinglist ,
+ in every outgoing message.
++If
++.I dir\fB/listid
++exists,
++ezmlm programs create a new
++.B List-ID
++field, showing the contents of the first line of
++.IR dir\fB/listid ,
++in every outgoing message. The list-id should be unique and within name
++space controlled by the owner. It should remain constant even if lists
++move and be of the format
++
++.EX
++List-ID: optional_text <unique_id.domain>
++.EE
++
++This header would result from a
++.I dir\fB/listid
++file containing ``optional_text <unique_id.domain>''. See
++.I http://www.within.com/~chandhok/ietf/listid.shtml
++for more info.
++
+ The first lines of
+ .I dir\fB/outlocal
+ and
+@@ -292,6 +839,44 @@
+ This affects the behavior of
+ .BR ezmlm-send .
++If
++.I dir\fB/qmqpservers
++exists,
++.B ezmlm-send
++and
++.B ezmlm-get
++will use
++.B qmail-qmqpc(1)
++to send posts and digests. Other mail will use the normal qmail mechanism.
++If
++.B qmail-qmqpc
++is modified correctly, server IP addresses listed one per line in
++.I dir\fB/qmqpsevers
++will be tried in order, rather than the default servers specified in
++.IR /var/qmail/control .
++
++If
++.I dir\fB/msgsize
++exists, it is assumed to contain ``max:min'', where ``max'' is the maximum
++size in bytes of an acceptable message body, and ``min'' the corresponding
++minimal size. Either will be ignored if zero or omitted. If the
++.B ezmlm-reject
++command line specifies the list directory, messages not meeting the size
++criteria are rejected.
++
++If
++.I dir\fB/charset
++exists, the first line is assumed to represent a valid MIME character set,
++which is used for all outgoing MIME messages sent by
++.B ezmlm-get 
++and the message moderation programs. The character set string may be suffixed
++with ':' and 'Q' or 'B' to send all outgoing
++text (ezmlm messages, digest table-of-contents, moderation requests, etc)
++encoded in ``Quoted-Printable'' or ``base64'' encoding. By default, no encoding
++is done, which may result in the transmission of characters with the high
++bit set. When encoding is specified, trigger messages and other parts of the
++reply that should not be encoded are sent as separate MIME parts.
++
+ .I dir\fB/lock
+ is an empty file.
+ Any program that reads or writes the subscriber list,
+@@ -304,14 +889,54 @@
+ .B WARNING:
+ .B Log
+ is not protected against system crashes.
+-Log entries may be missing or corrupted if the system goes down.
++Log entries may be missing or corrupted if the system goes down. There is
++Log for each of the accessory address databases as well. Thus, the log
++for digest subscribers is
++.IR dir\fB/digest/Log .
++If enabled, these logs can be retrieved by remote administrators (see
++.BR ezmlm-manage(1) ).
++
++.I dir\fB/digest
++contains items specific for the digest list.
++
++.I dir\fB/digest/subscribers
++contains hash files of digest subscriber addresses.
++
++.IR dir\fB/digest/Log ,
++.IR dir\fB/digest/bounce ,
++.IR dir\fB/digest/lockbounce ,
++and
++.I dir\fB/digest/lock
++have functions for the digest list that mirror that of the corresponding
++files in
++.IR dir .
++
++.I dir\fB/sql
++contains SQL server access information for list that are configured to
++use an SQL database for storage.
++
++.I dir\fB/tstdig
++is a timestamp used temporarily by
++.B ezmlm-tstdig(1)
++to coordinate digesting.
+ .SH "SEE ALSO"
++ezmlm-check(1),
++ezmlm-clean(1),
++ezmlm-gate(1),
++ezmlm-get(1),
++ezmlm-idx(1),
++ezmlm-issub(1),
++ezmlm-issubn(1),
+ ezmlm-list(1),
+ ezmlm-make(1),
+ ezmlm-manage(1),
++ezmlm-moderate(1),
++ezmlm-request(1),
+ ezmlm-return(1),
+ ezmlm-send(1),
++ezmlm-store(1),
+ ezmlm-sub(1),
++ezmlm-tstdig(1),
+ ezmlm-unsub(1),
+ ezmlm-warn(1),
+ dot-qmail(5)
+--- log.c      1998/02/16 04:49:24     1.1
++++ log.c      1998/11/22 22:24:22     1.3
+@@ -6,14 +6,21 @@
+ #include "fmt.h"
+ #include "open.h"
++/* appends (not crash-proof) a line to "Log". The format is: */
++/* "timestamp event address[ comment]\n". address is free of ' ' */
++/* Unprintable chars are changed to '?'. Comment may have spaces */
++
+ static substdio ss;
+ static char buf[1];
+ static char num[FMT_ULONG];
+ static stralloc line = {0};
++static stralloc fn = {0};
+-void log(event,addr)
++void log(dir,event,addr,comment)
++char *dir;
+ char *event;
+ char *addr;
++char *comment;
+ {
+   char ch;
+   int fd;
+@@ -26,9 +33,22 @@
+     if ((ch < 33) || (ch > 126)) ch = '?';
+     if (!stralloc_append(&line,&ch)) return;
+   }
++  if (comment && *comment) {
++    if (!stralloc_cats(&line," ")) return;
++    while (ch = *comment++) {
++      if (ch == '\t')
++        ch = ' ';
++      else 
++        if ((ch < 32) || (ch > 126)) ch = '?';
++      if (!stralloc_append(&line,&ch)) return;
++    }
++  }
+   if (!stralloc_cats(&line,"\n")) return;
+-  fd = open_append("Log");
++  if (!stralloc_copys(&fn,dir)) return;
++  if (!stralloc_cats(&fn,"/Log")) return;
++  if (!stralloc_0(&fn)) return;
++  fd = open_append(fn.s);
+   if (fd == -1) return;
+   substdio_fdbuf(&ss,write,fd,buf,sizeof(buf));
+   substdio_putflush(&ss,line.s,line.len);
+--- MAN        1997/07/02 23:11:57     1.1
++++ MAN        1999/10/10 03:41:20     1.26
+@@ -1,27 +1,67 @@
+ d:::755:::
+ d:::755:/man1::
+ d:::755:/man5::
++c:::644:/man1/:ezmlm-accept.1:
++c:::644:/man1/:ezmlm-archive.1:
++c:::644:/man1/:ezmlm-issubn.1:
+ c:::644:/man5/:ezmlm.5:
++c:::644:/man5/:ezmlmrc.5:
++c:::644:/man5/:ezmlmglrc.5:
++c:::644:/man5/:ezmlmsubrc.5:
+ c:::644:/man1/:ezmlm-list.1:
++c:::644:/man1/:ezmlm-glconf.1:
+ c:::644:/man1/:ezmlm-make.1:
++c:::644:/man1/:ezmlm-mktab.1:
+ c:::644:/man1/:ezmlm-manage.1:
++c:::644:/man1/:ezmlm-moderate.1:
+ c:::644:/man1/:ezmlm-reject.1:
++c:::644:/man1/:ezmlm-request.1:
+ c:::644:/man1/:ezmlm-return.1:
+ c:::644:/man1/:ezmlm-send.1:
++c:::644:/man1/:ezmlm-split.1:
++c:::644:/man1/:ezmlm-store.1:
+ c:::644:/man1/:ezmlm-sub.1:
+ c:::644:/man1/:ezmlm-unsub.1:
+ c:::644:/man1/:ezmlm-warn.1:
+ c:::644:/man1/:ezmlm-weed.1:
++c:::644:/man1/:ezmlm-idx.1:
++c:::644:/man1/:ezmlm-gate.1:
++c:::644:/man1/:ezmlm-tstdig.1:
++c:::644:/man1/:ezmlm-get.1:
++c:::644:/man1/:ezmlm-check.1:
++c:::644:/man1/:ezmlm-clean.1:
++c:::644:/man1/:ezmlm-limit.1:
++c:::644:/man1/:ezmlm-cron.1:
+ d:::755:/cat1::
+ d:::755:/cat5::
+ c:::644:/cat5/:ezmlm.0:
++c:::644:/cat5/:ezmlmrc.0:
++c:::644:/cat5/:ezmlmglrc.0:
++c:::644:/cat5/:ezmlmsubrc.0:
+ c:::644:/cat1/:ezmlm-list.0:
++c:::644:/cat1/:ezmlm-glconf.0:
+ c:::644:/cat1/:ezmlm-make.0:
++c:::644:/cat1/:ezmlm-mktab.0:
+ c:::644:/cat1/:ezmlm-manage.0:
++c:::644:/cat1/:ezmlm-moderate.0:
++c:::644:/cat1/:ezmlm-request.0:
+ c:::644:/cat1/:ezmlm-reject.0:
+ c:::644:/cat1/:ezmlm-return.0:
+ c:::644:/cat1/:ezmlm-send.0:
++c:::644:/cat1/:ezmlm-store.0:
++c:::644:/cat1/:ezmlm-split.0:
+ c:::644:/cat1/:ezmlm-sub.0:
+ c:::644:/cat1/:ezmlm-unsub.0:
+ c:::644:/cat1/:ezmlm-warn.0:
+ c:::644:/cat1/:ezmlm-weed.0:
++c:::644:/cat1/:ezmlm-idx.0:
++c:::644:/cat1/:ezmlm-gate.0:
++c:::644:/cat1/:ezmlm-tstdig.0:
++c:::644:/cat1/:ezmlm-get.0:
++c:::644:/cat1/:ezmlm-check.0:
++c:::644:/cat1/:ezmlm-clean.0:
++c:::644:/cat1/:ezmlm-limit.0:
++c:::644:/cat1/:ezmlm-cron.0:
++c:::644:/cat1/:ezmlm-accept.0:
++c:::644:/cat1/:ezmlm-archive.0:
++c:::644:/cat1/:ezmlm-issubn.0:
+--- BIN        1997/07/02 23:10:49     1.1
++++ BIN        1999/10/10 03:41:20     1.23
+@@ -1,11 +1,31 @@
+ d:::755:::
++c:::755:/:ezmlm-accept:
++c:::755:/:ezmlm-archive:
++c:::755:/:ezmlm-issubn:
++c:::755:/:ezmlm-glconf:
+ c:::755:/:ezmlm-make:
++c:::755:/:ezmlm-mktab:
+ c:::755:/:ezmlm-manage:
+ c:::755:/:ezmlm-send:
++c:::755:/:ezmlm-request:
+ c:::755:/:ezmlm-reject:
+ c:::755:/:ezmlm-return:
+ c:::755:/:ezmlm-warn:
+ c:::755:/:ezmlm-weed:
+ c:::755:/:ezmlm-list:
++c:::755:/:ezmlm-clean:
++c:::755:/:ezmlm-cron:
++c:::755:/:ezmlm-limit:
++c:::755:/:ezmlm-store:
++c:::755:/:ezmlm-split:
++c:::755:/:ezmlm-moderate:
+ c:::755:/:ezmlm-sub:
+ c:::755:/:ezmlm-unsub:
++c:::644:/:ezmlmrc:
++c:::644:/:ezmlmglrc:
++c:::644:/:ezmlmsubrc:
++c:::755:/:ezmlm-idx:
++c:::755:/:ezmlm-check:
++c:::755:/:ezmlm-gate:
++c:::755:/:ezmlm-tstdig:
++c:::755:/:ezmlm-get:
+--- VERSION    1997/10/12 19:29:59     1.1
++++ VERSION    1997/11/08 04:19:44     1.3
+@@ -1 +1,2 @@
+ ezmlm 0.53
++$Name: ezmlm-idx-040 $
+--- Makefile   1997/07/02 22:17:50     1.1
++++ Makefile   1999/12/23 02:42:12     1.117
+@@ -1,7 +1,14 @@
++#$Id: Makefile,v 1.117 1999/12/23 02:42:12 lindberg Exp $
++#$Name: ezmlm-idx-040 $
+ SHELL=/bin/sh
+-
++SQLCC=`head -1 conf-sqlcc`
++SQLLD=`head -1 conf-sqlld`
+ default: it
++clean: \
++TARGETS
++      rm -f `cat TARGETS`
++
+ alloc.0: \
+ alloc.3
+       nroff -man alloc.3 > alloc.0
+@@ -18,6 +25,10 @@
+ compile alloc_re.c alloc.h alloc_re.c byte.h alloc_re.c
+       ./compile alloc_re.c
++author.o: \
++compile author.c mime.h
++      ./compile author.c
++
+ auto-ccld.sh: \
+ conf-cc conf-ld warn-auto.sh
+       ( cat warn-auto.sh; \
+@@ -34,6 +45,14 @@
+ exit.h auto-str.c
+       ./compile auto-str.c
++auto_cron.c: \
++auto-str conf-cron
++      ./auto-str auto_cron `head -1 conf-cron` > auto_cron.c
++
++auto_cron.o: \
++compile auto_cron.c
++      ./compile auto_cron.c
++
+ auto_bin.c: \
+ auto-str conf-bin
+       ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c
+@@ -79,13 +98,18 @@
+       nroff -man case.3 > case.0
+ case.a: \
+-makelib case_diffb.o case_lowerb.o case_startb.o
+-      ./makelib case.a case_diffb.o case_lowerb.o case_startb.o
++makelib case_diffb.o case_diffs.o case_starts.o case_lowerb.o case_startb.o
++      ./makelib case.a case_diffb.o case_lowerb.o case_startb.o \
++      case_diffs.o case_starts.o
+ case_diffb.o: \
+ compile case_diffb.c case.h case_diffb.c
+       ./compile case_diffb.c
++case_diffs.o: \
++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
+@@ -94,6 +118,15 @@
+ compile case_startb.c case.h case_startb.c
+       ./compile case_startb.c
++checktag.o: \
++compile checktag.c stralloc.h scan.h fmt.h strerr.h cookie.h \
++      errtxt.h subscribe.h conf-sqlcc
++      ./compile checktag.c ${SQLCC}
++
++case_starts.o: \
++compile case_starts.c case.h
++      ./compile case_starts.c
++
+ compile: \
+ make-compile warn-auto.sh systype
+       ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
+@@ -110,6 +143,19 @@
+ surfpcs.h uint32.h surfpcs.h cookie.c
+       ./compile cookie.c
++copy.o: \
++compile copy.c copy.h stralloc.h substdio.h str.h readwrite.h open.h qmail.h \
++strerr.h getln.h case.h errtxt.h mime.h error.h quote.h
++      ./compile copy.c
++
++date2yyyymm.o:\
++compile date2yyyymm.c yyyymm.h
++      ./compile date2yyyymm.c
++
++dateline.o:\
++compile dateline.c yyyymm.h stralloc.h fmt.h
++      ./compile dateline.c
++
+ date822fmt.o: \
+ compile date822fmt.c datetime.h date822fmt.c fmt.h date822fmt.c \
+ date822fmt.h date822fmt.c
+@@ -133,13 +179,46 @@
+       && cat direntry.h2 || cat direntry.h1 ) > direntry.h
+       rm -f trydrent.o
++concatHDR.o: \
++compile concatHDR.c mime.h stralloc.h strerr.h byte.h errtxt.h
++      ./compile concatHDR.c
++
++decodeB.o: \
++compile decodeB.c mime.h uint32.h stralloc.h strerr.h errtxt.h
++      ./compile decodeB.c
++
++decodeHDR.o: \
++compile decodeHDR.c mime.h stralloc.h strerr.h error.h case.h byte.h \
++uint32.h errtxt.h
++      ./compile decodeHDR.c
++
++decodeQ.o: \
++compile decodeQ.c mime.h stralloc.h strerr.h errtxt.h
++      ./compile decodeQ.c
++
++encodeB.o: \
++compile encodeB.c mime.h uint32.h stralloc.h strerr.h errtxt.h
++      ./compile encodeB.c
++
++encodeQ.o: \
++compile encodeQ.c mime.h stralloc.h strerr.h errtxt.h
++      ./compile encodeQ.c
++
++unfoldHDR.o: \
++compile unfoldHDR.c mime.h stralloc.h strerr.h errtxt.h
++      ./compile unfoldHDR.c
++
+ env.0: \
+ env.3
+       nroff -man env.3 > env.0
+ env.a: \
+-makelib envread.o
+-      ./makelib env.a envread.o
++makelib env.o envread.o
++      ./makelib env.a env.o envread.o
++
++env.o: \
++compile env.c env.h str.h
++      ./compile env.c
+ envread.o: \
+ compile envread.c env.h envread.c str.h envread.c
+@@ -169,28 +248,281 @@
+ error_temp.3
+       nroff -man error_temp.3 > error_temp.0
++ezmlm-accept: \
++ezmlm-accept.sh warn-auto.sh conf-bin
++      (cat warn-auto.sh; \
++      echo EZPATH=\'`head -1 conf-bin`\'; \
++      cat ezmlm-accept.sh ) > ezmlm-accept
++
++ezmlm-accept.0: \
++ezmlm-accept.1
++      nroff -man ezmlm-accept.1 > ezmlm-accept.0
++
++ezmlm-archive: \
++load ezmlm-archive.o getconf.o slurpclose.o slurp.o getln.a sig.a \
++strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
++lock.a fd.a getopt.a idxthread.o yyyymm.a
++      ./load ezmlm-archive getconf.o slurpclose.o slurp.o getln.a sig.a \
++      idxthread.o yyyymm.a strerr.a substdio.a stralloc.a alloc.a \
++      error.a str.a fs.a open.a lock.a fd.a getopt.a
++
++ezmlm-archive.0: \
++ezmlm-archive.1
++      nroff -man ezmlm-archive.1 > ezmlm-archive.0
++
++ezmlm-archive.o: \
++compile ezmlm-archive.c alloc.h error.h stralloc.h gen_alloc.h str.h \
++sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h \
++makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h sgetopt.h subgetopt.h
++      ./compile ezmlm-archive.c
++
++ezmlm-cgi: \
++load ezmlm-cgi.o getconf.o slurpclose.o slurp.o constmap.o getln.a sig.a \
++mime.a strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
++lock.a fd.a getopt.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a
++      ./load ezmlm-cgi getconf.o slurpclose.o slurp.o constmap.o getln.a \
++      mime.a sig.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a \
++      strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \
++      lock.a fd.a getopt.a
++
++ezmlm-cgi.0: \
++ezmlm-cgi.1
++      nroff -man ezmlm-cgi.1 > ezmlm-cgi.0
++
++ezmlm-cgi.o: \
++compile ezmlm-cgi.c alloc.h error.h stralloc.h gen_alloc.h str.h \
++sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h env.h \
++makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h mime.h \
++constmap.h sgetopt.h subgetopt.h datetime.h now.h fork.h wait.h
++      ./compile ezmlm-cgi.c
++
++ezmlm-check: \
++ezmlm-check.sh warn-auto.sh conf-bin
++      (cat warn-auto.sh; \
++      echo EZPATH=\'`head -1 conf-bin`\'; \
++      echo QMPATH=\'`head -1 conf-qmail`\'; \
++      cat ezmlm-check.sh ) > ezmlm-check
++
++ezmlm-check.0: \
++ezmlm-check.1
++      nroff -man ezmlm-check.1 > ezmlm-check.0
++
++ezmlm-clean: \
++load ezmlm-clean.o auto_qmail.o getconf.o copy.o mime.a \
++now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
++getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a surf.a \
++error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a cookie.o getopt.a
++      ./load ezmlm-clean auto_qmail.o getconf.o copy.o mime.a \
++      now.o datetime.o date822fmt.o slurpclose.o \
++      slurp.o qmail.o quote.o getln.a env.a sig.a strerr.a \
++      substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
++      open.a seek.a wait.a lock.a fd.a cookie.o getopt.a surf.a
++
++ezmlm-clean.0: \
++ezmlm-clean.1
++      nroff -man ezmlm-clean.1 > ezmlm-clean.0
++
++ezmlm-clean.o: \
++compile ezmlm-clean.c error.h stralloc.h gen_alloc.h str.h \
++env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h copy.h mime.h \
++qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h cookie.h \
++date822fmt.h direntry.h fmt.h strerr.h errtxt.h idx.h sgetopt.h subgetopt.h
++      ./compile ezmlm-clean.c
++
++ezmlm-cron: \
++load ezmlm-cron.o strerr.a stralloc.a alloc.a error.a open.a auto_qmail.o \
++getopt.a getln.a str.a substdio.a sig.a fs.a open.a fd.a lock.a wait.a \
++case.a auto_cron.o
++      ./load ezmlm-cron getopt.a getln.a strerr.a substdio.a \
++      stralloc.a alloc.a sig.a fs.a open.a fd.a lock.a error.a \
++      wait.a case.a str.a auto_qmail.o auto_cron.o
++
++ezmlm-cron.0: \
++ezmlm-cron.1
++      nroff -man ezmlm-cron.1 > ezmlm-cron.0
++
++ezmlm-cron.o: \
++compile ezmlm-cron.c strerr.h substdio.h stralloc.h error.h str.h \
++fork.h readwrite.h wait.h errtxt.h idx.h sgetopt.h auto_qmail.h \
++fmt.h auto_cron.h
++      ./compile ezmlm-cron.c
++
++ezmlm-gate: \
++load ezmlm-gate.o subdb.a auto_bin.o getopt.a getln.a env.a sig.a strerr.a \
++stralloc.a alloc.a error.a str.a case.a wait.a substdio.a open.a lock.a \
++fs.a getconf.o slurpclose.o slurp.o seek.a conf-sqlld
++      ./load ezmlm-gate subdb.a getconf.o slurpclose.o slurp.o \
++      getopt.a getln.a auto_bin.o env.a sig.a fs.a \
++      strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a wait.a \
++      open.a lock.a seek.a ${SQLLD}
++
++ezmlm-gate.0: \
++ezmlm-gate.1
++      nroff -man ezmlm-gate.1 > ezmlm-gate.0
++
++ezmlm-gate.o: \
++compile ezmlm-gate.c idx.h errtxt.h subscribe.h auto_bin.h \
++sgetopt.h subgetopt.h substdio.h getconf.h \
++env.h sig.h strerr.h stralloc.h alloc.h error.h str.h case.h \
++fork.h wait.h exit.h getln.h open.h
++      ./compile ezmlm-gate.c
++
++ezmlm-get: \
++load ezmlm-get.o idxthread.o subdb.a auto_qmail.o getopt.a now.o getconf.o \
++datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o makehash.o \
++cookie.o surf.a yyyymm.a \
++constmap.o getln.a env.a sig.a strerr.a substdio.a mime.a stralloc.a alloc.a \
++error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a copy.o conf-sqlld
++      ./load ezmlm-get idxthread.o subdb.a auto_qmail.o getopt.a getconf.o \
++      now.o datetime.o date822fmt.o cookie.o makehash.o slurpclose.o slurp.o \
++      yyyymm.a \
++      constmap.o substdio.a copy.o mime.a strerr.a stralloc.a alloc.a \
++      qmail.o quote.o surf.a getln.a env.a sig.a \
++      error.a str.a fs.a case.a \
++      open.a seek.a wait.a lock.a fd.a ${SQLLD}
++
++ezmlm-get.o: \
++compile ezmlm-get.c idx.h errtxt.h error.h getconf.h stralloc.h gen_alloc.h \
++str.h cookie.h env.h sig.h slurp.h strerr.h byte.h getln.h case.h qmail.h \
++substdio.h readwrite.h seek.h quote.h sgetopt.h subgetopt.h datetime.h now.h \
++date822fmt.h fmt.h strerr.h copy.h errtxt.h idx.h idxthread.h mime.h \
++constmap.h makehash.h
++      ./compile ezmlm-get.c
++
++ezmlm-get.0: \
++ezmlm-get.1
++      nroff -man ezmlm-get.1 > ezmlm-get.0
++
++ezmlm-greturn: \
++load ezmlm-greturn.o quote.o getconf.o subdb.a log.o \
++slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \
++strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \
++case.a open.a conf-sqlld
++      ./load ezmlm-greturn quote.o getconf.o subdb.a \
++      log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \
++      env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \
++      error.a str.a fs.a case.a open.a ${SQLLD}
++
++ezmlm-greturn.0: \
++ezmlm-greturn.1
++      nroff -man ezmlm-greturn.1 > ezmlm-greturn.0
++
++ezmlm-greturn.o: \
++compile ezmlm-greturn.c stralloc.h gen_alloc.h stralloc.h str.h env.h sig.h \
++slurp.h getconf.h strerr.h byte.h case.h getln.h substdio.h error.h \
++quote.h readwrite.h fmt.h datetime.h now.h cookie.h \
++strerr.h subscribe.h
++      ./compile ezmlm-greturn.c
++
++ezmlm-gwarn: \
++load ezmlm-gwarn.o auto_qmail.o getconf.o mime.a cookie.o subdb.a now.o \
++slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \
++case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \
++open.a lock.a str.a fs.a fd.a wait.a copy.o getopt.a conf-sqlld
++      ./load ezmlm-gwarn auto_qmail.o getconf.o mime.a \
++      cookie.o subdb.a getopt.a \
++      now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \
++      qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \
++      stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \
++      wait.a copy.o ${SQLLD}
++
++ezmlm-gwarn.0: \
++ezmlm-gwarn.1
++      nroff -man ezmlm-gwarn.1 > ezmlm-gwarn.0
++
++ezmlm-gwarn.o: \
++compile ezmlm-gwarn.c direntry.h readwrite.h getln.h \
++substdio.h stralloc.h gen_alloc.h slurp.h getconf.h byte.h error.h str.h \
++sig.h now.h datetime.h  date822fmt.h fmt.h cookie.h qmail.h substdio.h \
++qmail.h copy.h mime.h idx.h errtxt.h sgetopt.h subgetopt.h
++      ./compile ezmlm-gwarn.c
++
++ezmlm-idx: \
++load ezmlm-idx.o slurp.o slurpclose.o mime.a wait.a getopt.a \
++getln.a strerr.a sig.h sig.a open.a lock.a substdio.a stralloc.a \
++alloc.a error.a str.a fd.a case.a fs.a getconf.o makehash.o surf.o mime.a
++      ./load ezmlm-idx \
++      mime.a slurp.o slurpclose.o wait.a getln.a strerr.a sig.a open.a \
++      lock.a mime.a substdio.a stralloc.a alloc.a error.a str.a fd.a \
++      getopt.a case.a fs.a getconf.o makehash.o surf.o
++
++ezmlm-idx.o: \
++compile ezmlm-idx.c stralloc.h getconf.h \
++substdio.h subfd.h strerr.h error.h sgetopt.h \
++lock.h sig.h slurp.h open.h getln.h case.h \
++str.h fmt.h readwrite.h exit.h idx.h mime.h errtxt.h uint32.h
++      ./compile ezmlm-idx.c
++
++ezmlm-idx.0: \
++ezmlm-idx.1
++      nroff -man ezmlm-idx.1 > ezmlm-idx.0
++
++ezmlm-glconf: \
++ezmlm-glconf.sh warn-auto.sh conf-bin
++      (cat warn-auto.sh; \
++      echo EZPATH=\'`head -1 conf-bin`\'; \
++      cat ezmlm-glconf.sh ) > ezmlm-glconf
++
++ezmlm-glconf.0: \
++ezmlm-glconf.1
++      nroff -man ezmlm-glconf.1 > ezmlm-glconf.0
++
++ezmlm-issubn: \
++load ezmlm-issubn.o subdb.a getconf.o slurpclose.o slurp.o \
++env.a fs.a strerr.a getln.a getopt.a conf-sqlld \
++substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
++      ./load ezmlm-issubn subdb.a getconf.o slurpclose.o slurp.o \
++      getopt.a env.a fs.a strerr.a \
++      getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
++      open.a lock.a ${SQLLD}
++
++ezmlm-issubn.0: \
++ezmlm-issubn.1
++      nroff -man ezmlm-issubn.1 > ezmlm-issubn.0
++
++ezmlm-issubn.o: \
++compile ezmlm-issubn.c strerr.h subscribe.h env.h errtxt.h sgetopt.h idx.h
++      ./compile ezmlm-issubn.c
++
++ezmlm-limit: \
++load ezmlm-limit.o getconf.o slurpclose.o slurp.o substdio.a stralloc.a \
++alloc.a error.a str.a case.a open.a lock.a getopt.a fs.a sig.a now.o
++      ./load ezmlm-limit getconf.o slurpclose.o slurp.o getopt.a \
++      strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a \
++      open.a lock.a fs.a sig.a now.o
++
++ezmlm-limit.0: \
++ezmlm-limit.1
++      nroff -man ezmlm-limit.1 > ezmlm-limit.0
++
++ezmlm-limit.o: \
++compile ezmlm-limit.c stralloc.h strerr.h substdio.h readwrite.h sig.h lock.h \
++getconf.h fmt.h now.h sgetopt.h error.h errtxt.h idx.h datetime.h
++      ./compile ezmlm-limit.c
++
+ ezmlm-list: \
+-load ezmlm-list.o strerr.a getln.a substdio.a stralloc.a alloc.a \
+-error.a open.a str.a
+-      ./load ezmlm-list strerr.a getln.a substdio.a stralloc.a \
+-      alloc.a error.a open.a str.a 
++load ezmlm-list.o subdb.a fs.a getconf.o slurpclose.o slurp.o \
++strerr.a getln.a substdio.a stralloc.a alloc.a \
++error.a open.a str.a case.a getopt.a conf-sqlld
++      ./load ezmlm-list subdb.a fs.a getconf.o slurpclose.o slurp.o \
++      strerr.a getln.a getopt.a substdio.a stralloc.a \
++      alloc.a error.a open.a str.a case.a ${SQLLD}
+ ezmlm-list.0: \
+ ezmlm-list.1
+       nroff -man ezmlm-list.1 > ezmlm-list.0
+ ezmlm-list.o: \
+-compile ezmlm-list.c stralloc.h gen_alloc.h stralloc.h ezmlm-list.c \
+-substdio.h ezmlm-list.c getln.h ezmlm-list.c strerr.h ezmlm-list.c \
+-error.h ezmlm-list.c readwrite.h ezmlm-list.c exit.h ezmlm-list.c \
+-open.h ezmlm-list.c
++compile ezmlm-list.c stralloc.h gen_alloc.h substdio.h getln.h strerr.h \
++error.h readwrite.h exit.h open.h errtxt.h subscribe.h exit.h sgetopt.h \
++idx.h fmt.h
+       ./compile ezmlm-list.c
+ ezmlm-make: \
+-load ezmlm-make.o auto_bin.o open.a getopt.a substdio.a strerr.a \
+-stralloc.a alloc.a error.a str.a
+-      ./load ezmlm-make auto_bin.o open.a getopt.a substdio.a \
+-      strerr.a stralloc.a alloc.a error.a str.a 
++load ezmlm-make.o auto_bin.o open.a getln.a getopt.a substdio.a strerr.a \
++stralloc.a alloc.a error.a lock.a str.a
++      ./load ezmlm-make auto_bin.o open.a getln.a getopt.a substdio.a \
++      strerr.a stralloc.a alloc.a error.a lock.a str.a
+ ezmlm-make.0: \
+ ezmlm-make.1
+@@ -202,19 +534,20 @@
+ strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \
+ open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \
+ auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \
+-ezmlm-make.c
++errtxt.h idx.h getln.h lock.h
+       ./compile ezmlm-make.c
+ ezmlm-manage: \
+-load ezmlm-manage.o auto_qmail.o getconf.o subscribe.o log.o cookie.o \
++load ezmlm-manage.o auto_qmail.o getconf.o subdb.a log.o cookie.o \
+ now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
+ surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
+-error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a
+-      ./load ezmlm-manage auto_qmail.o getconf.o subscribe.o \
+-      log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
++error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a \
++mime.a copy.o conf-sqlld
++      ./load ezmlm-manage subdb.a auto_qmail.o getconf.o copy.o \
++      mime.a log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
+       slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
+       substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
+-      open.a seek.a wait.a lock.a fd.a 
++      open.a seek.a wait.a lock.a fd.a getopt.a ${SQLLD}
+ ezmlm-manage.0: \
+ ezmlm-manage.1
+@@ -231,35 +564,84 @@
+ quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \
+ datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \
+ ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \
+-ezmlm-manage.c cookie.h ezmlm-manage.c
++sgetopt.h subgetopt.h cookie.h idx.h errtxt.h copy.h
+       ./compile ezmlm-manage.c
++ezmlm-mktab.0: \
++ezmlm-mktab.1
++      nroff -man ezmlm-mktab.1 > ezmlm-mktab.0
++
++ezmlm-moderate: \
++load ezmlm-moderate.o auto_qmail.o getconf.o auto_bin.o copy.o mime.a \
++cookie.o now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
++surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
++error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a
++      ./load ezmlm-moderate auto_qmail.o getconf.o copy.o mime.a \
++      cookie.o now.o datetime.o date822fmt.o slurpclose.o \
++      slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
++      substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
++      auto_bin.o open.a seek.a wait.a lock.a fd.a getopt.a
++
++ezmlm-moderate.0: \
++ezmlm-moderate.1
++      nroff -man ezmlm-moderate.1 > ezmlm-moderate.0
++
++ezmlm-moderate.o: \
++compile ezmlm-moderate.c error.h stralloc.h gen_alloc.h str.h \
++env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h \
++qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h \
++date822fmt.h fmt.h strerr.h cookie.h errtxt.h idx.h copy.h mime.h \
++subgetopt.h sgetopt.h auto_bin.h fork.h wait.h
++      ./compile ezmlm-moderate.c
++
++ezmlm-request: \
++load ezmlm-request.o subdb.a getconf.o constmap.o getln.a auto_qmail.o qmail.o \
++strerr.a slurpclose.o slurp.o getopt.a env.a open.a fd.a sig.a case.a \
++substdio.a error.a stralloc.a alloc.a str.a case.a fs.a wait.a seek.a \
++date822fmt.o now.o datetime.o quote.o copy.o mime.a conf-sqlld
++      ./load ezmlm-request subdb.a getconf.o constmap.o getln.a auto_qmail.o \
++      qmail.o date822fmt.o datetime.o now.o quote.o \
++      slurpclose.o slurp.o env.a open.a sig.a wait.a getopt.a \
++      strerr.a substdio.a error.a copy.o stralloc.a alloc.a substdio.a \
++      str.a case.a fs.a fd.a sig.a wait.a seek.a mime.a ${SQLLD}
++
++ezmlm-request.0:
++      nroff -man ezmlm-request.1 > ezmlm-request.0
++
++ezmlm-request.o: \
++compile ezmlm-request.c stralloc.h subfd.h strerr.h error.h qmail.h env.h \
++sig.h open.h getln.h case.h str.h readwrite.h exit.h substdio.h quote.h \
++getconf.h constmap.h fmt.h byte.h errtxt.h idx.h datetime.h date822fmt.h \
++subscribe.h now.h copy.h
++      ./compile ezmlm-request.c
++
+ ezmlm-reject: \
+-load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a \
+-alloc.a str.a getopt.a case.a
+-      ./load ezmlm-reject getln.a strerr.a substdio.a error.a \
+-      stralloc.a alloc.a str.a getopt.a case.a 
++load ezmlm-reject.o getln.a strerr.a substdio.a error.a stralloc.a open.a \
++qmail.o env.a seek.a fd.a wait.a auto_qmail.o \
++alloc.a getconf.o slurp.o slurpclose.o str.a getopt.a case.a constmap.o fs.a
++      ./load ezmlm-reject qmail.o getln.a strerr.a substdio.a error.a fs.a \
++      env.a constmap.o getconf.o slurp.o slurpclose.o stralloc.a alloc.a \
++      seek.a str.a getopt.a case.a open.a fd.a wait.a auto_qmail.o
+ ezmlm-reject.0: \
+ ezmlm-reject.1
+       nroff -man ezmlm-reject.1 > ezmlm-reject.0
+ ezmlm-reject.o: \
+-compile ezmlm-reject.c strerr.h ezmlm-reject.c substdio.h \
+-ezmlm-reject.c readwrite.h ezmlm-reject.c stralloc.h gen_alloc.h \
+-stralloc.h ezmlm-reject.c getln.h ezmlm-reject.c sgetopt.h \
+-subgetopt.h sgetopt.h ezmlm-reject.c
++compile ezmlm-reject.c strerr.h substdio.h readwrite.h stralloc.h gen_alloc.h \
++stralloc.h getln.h sgetopt.h subgetopt.h constmap.h getconf.h errtxt.h \
++scan.h fmt.h idx.h qmail.h env.h seek.h
+       ./compile ezmlm-reject.c
+ ezmlm-return: \
+-load ezmlm-return.o quote.o getconf.o issub.o subscribe.o log.o \
++load ezmlm-return.o quote.o getconf.o subdb.a log.o \
+ slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \
+ strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \
+-case.a open.a
+-      ./load ezmlm-return quote.o getconf.o issub.o subscribe.o \
++case.a open.a conf-sqlld
++      ./load ezmlm-return quote.o getconf.o subdb.a \
+       log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \
+       env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \
+-      error.a str.a fs.a case.a open.a 
++      error.a str.a fs.a case.a open.a ${SQLLD}
+ ezmlm-return.0: \
+ ezmlm-return.1
+@@ -270,43 +652,134 @@
+ ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \
+ ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \
+ strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \
+-getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h \
++getln.h ezmlm-return.c substdio.h ezmlm-return.c error.h direntry.h \
+ ezmlm-return.c quote.h ezmlm-return.c readwrite.h ezmlm-return.c \
+ fmt.h ezmlm-return.c now.h datetime.h now.h ezmlm-return.c cookie.h \
+ ezmlm-return.c subscribe.h strerr.h strerr.h subscribe.h \
+-ezmlm-return.c issub.h strerr.h strerr.h issub.h ezmlm-return.c
++strerr.h strerr.h
+       ./compile ezmlm-return.c
+ ezmlm-send: \
+ load ezmlm-send.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
+-slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a \
+-substdio.a stralloc.a alloc.a error.a str.a fd.a case.a fs.a
+-      ./load ezmlm-send auto_qmail.o getconf.o qmail.o \
+-      constmap.o slurp.o slurpclose.o wait.a getln.a strerr.a \
+-      sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a \
+-      error.a str.a fd.a case.a fs.a 
++slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
++substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a \
++getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
++      ./load ezmlm-send subdb.a cookie.o surf.a auto_qmail.o getconf.o \
++      getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
++      wait.a getln.a strerr.a \
++      sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
++      fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
+ ezmlm-send.0: \
+ ezmlm-send.1
+       nroff -man ezmlm-send.1 > ezmlm-send.0
+ ezmlm-send.o: \
+-compile ezmlm-send.c stralloc.h gen_alloc.h stralloc.h ezmlm-send.c \
+-subfd.h substdio.h subfd.h ezmlm-send.c strerr.h ezmlm-send.c error.h \
+-ezmlm-send.c qmail.h substdio.h substdio.h qmail.h ezmlm-send.c env.h \
+-ezmlm-send.c lock.h ezmlm-send.c sig.h ezmlm-send.c open.h \
+-ezmlm-send.c getln.h ezmlm-send.c case.h ezmlm-send.c scan.h \
+-ezmlm-send.c str.h ezmlm-send.c fmt.h ezmlm-send.c readwrite.h \
+-ezmlm-send.c exit.h ezmlm-send.c substdio.h substdio.h ezmlm-send.c \
+-getconf.h ezmlm-send.c constmap.h ezmlm-send.c
++compile ezmlm-send.c stralloc.h gen_alloc.h copy.h \
++subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
++lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
++exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
++uint32.h
+       ./compile ezmlm-send.c
++ezmlm-master: \
++load ezmlm-master.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
++slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
++substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a\
++getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
++      ./load ezmlm-master subdb.a cookie.o surf.a auto_qmail.o getconf.o \
++      getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
++      wait.a getln.a strerr.a \
++      sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
++      fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
++
++ezmlm-master.0: \
++ezmlm-master.1
++      nroff -man ezmlm-master.1 > ezmlm-master.0
++
++ezmlm-master.o: \
++compile ezmlm-master.c stralloc.h gen_alloc.h copy.h \
++subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
++lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
++exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
++uint32.h
++      ./compile ezmlm-master.c
++
++ezmlm-slave: \
++load ezmlm-slave.o auto_qmail.o getconf.o qmail.o constmap.o slurp.o \
++slurpclose.o wait.a getln.a strerr.a sig.a env.a open.a lock.a conf-sqlld \
++substdio.a cookie.o stralloc.a alloc.a error.a str.a fd.a case.a fs.a surf.a \
++getopt.a copy.o mime.a subdb.a makehash.o surf.o makehash.o str.a quote.o
++      ./load ezmlm-slave subdb.a cookie.o surf.a auto_qmail.o getconf.o \
++      getopt.a qmail.o quote.o constmap.o slurp.o slurpclose.o \
++      wait.a getln.a strerr.a \
++      sig.a env.a open.a lock.a substdio.a stralloc.a alloc.a error.a \
++      fd.a case.a fs.a getopt.a copy.o mime.a makehash.o str.a ${SQLLD}
++
++ezmlm-slave.0: \
++ezmlm-slave.1
++      nroff -man ezmlm-slave.1 > ezmlm-slave.0
++
++ezmlm-slave.o: \
++compile ezmlm-slave.c stralloc.h gen_alloc.h copy.h \
++subfd.h substdio.h strerr.h error.h qmail.h env.h makehash.h sgetopt.h \
++lock.h sig.h open.h getln.h case.h scan.h str.h fmt.h readwrite.h quote.h \
++exit.h getconf.h constmap.h byte.h errtxt.h idx.h mime.h subscribe.h \
++uint32.h
++      ./compile ezmlm-slave.c
++
++ezmlm-split: \
++load ezmlm-split.o auto_qmail.o getconf.o \
++slurpclose.o slurp.o qmail.o quote.o wait.a \
++getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a \
++error.a str.a fs.a case.a open.a fd.a
++      ./load ezmlm-split auto_qmail.o getconf.o slurpclose.o \
++      slurp.o qmail.o quote.o getln.a env.a sig.a strerr.a \
++      substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
++      open.a fd.a wait.a
++
++ezmlm-split.0: \
++ezmlm-split.1
++      nroff -man ezmlm-split.1 > ezmlm-split.0
++
++ezmlm-split.o: \
++compile ezmlm-split.c error.h stralloc.h gen_alloc.h str.h \
++env.h sig.h getconf.h strerr.h byte.h getln.h case.h \
++qmail.h substdio.h  readwrite.h quote.h \
++fmt.h errtxt.h idx.h uint32.h
++      ./compile ezmlm-split.c
++
++ezmlm-store: \
++load ezmlm-store.o auto_qmail.o getconf.o subdb.a log.o auto_bin.o mime.a \
++cookie.o now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \
++surf.a getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a conf-sqlld \
++error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a getopt.a copy.o
++      ./load ezmlm-store auto_qmail.o getconf.o subdb.a copy.o mime.a \
++      log.o cookie.o now.o datetime.o date822fmt.o slurpclose.o \
++      slurp.o qmail.o quote.o surf.a getln.a env.a sig.a strerr.a \
++      substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \
++      open.a seek.a wait.a lock.a fd.a getopt.a auto_bin.o ${SQLLD}
++
++ezmlm-store.0: \
++ezmlm-store.1
++      nroff -man ezmlm-store.1 > ezmlm-store.0
++
++ezmlm-store.o: \
++compile ezmlm-store.c error.h stralloc.h gen_alloc.h str.h \
++sgetopt.h subgetopt.h fork.h wait.h auto_bin.h lock.h mime.h \
++env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h \
++qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h \
++date822fmt.h fmt.h subscribe.h strerr.h cookie.h errtxt.h idx.h copy.h
++      ./compile ezmlm-store.c
++
+ ezmlm-sub: \
+-load ezmlm-sub.o subscribe.o log.o now.o fs.a strerr.a getln.a \
++load ezmlm-sub.o subdb.a getconf.o slurpclose.o slurp.o \
++log.o now.o fs.a strerr.a getln.a getopt.a fs.a conf-sqlld \
+ substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
+-      ./load ezmlm-sub subscribe.o log.o now.o fs.a strerr.a \
++      ./load ezmlm-sub subdb.a getconf.o slurpclose.o slurp.o \
++      log.o now.o fs.a strerr.a getopt.a fs.a \
+       getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
+-      open.a lock.a 
++      open.a lock.a ${SQLLD}
+ ezmlm-sub.0: \
+ ezmlm-sub.1
+@@ -314,57 +787,86 @@
+ ezmlm-sub.o: \
+ compile ezmlm-sub.c strerr.h ezmlm-sub.c subscribe.h strerr.h \
+-strerr.h subscribe.h ezmlm-sub.c log.h ezmlm-sub.c
++getln.h substdio.h stralloc.h readwrite.h \
++strerr.h subscribe.h log.h errtxt.h sgetopt.h scan.h idx.h
+       ./compile ezmlm-sub.c
++ezmlm-test: \
++ezmlm-test.sh warn-auto.sh conf-bin
++      (cat warn-auto.sh; \
++      echo QMPATH=\'`head -1 conf-qmail`\'; \
++      cat ezmlm-test.sh ) > ezmlm-test; \
++      chmod 755 ezmlm-test
++
++ezmlm-test.0: \
++ezmlm-test.1
++      nroff -man ezmlm-test.1 > ezmlm-test.0
++
++ezmlm-tstdig: \
++load ezmlm-tstdig.o getopt.a getconf.o now.o fs.a strerr.a getln.a \
++lock.a \
++substdio.a stralloc.a alloc.a error.a str.a case.a sig.a \
++open.a slurpclose.o slurp.o env.a
++      ./load ezmlm-tstdig getopt.a getconf.o env.a now.o fs.a strerr.a \
++      lock.a getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
++      sig.a slurpclose.o slurp.o open.a 
++
++ezmlm-tstdig.0: \
++ezmlm-tstdig.1
++      nroff -man ezmlm-tstdig.1 > ezmlm-tstdig.0
++
++ezmlm-tstdig.o: \
++compile ezmlm-tstdig.c strerr.h sgetopt.h getconf.h \
++sig.h now.h errtxt.h stralloc.h sig.h env.h fmt.h substdio.h readwrite.h \
++now.h idx.h
++      ./compile ezmlm-tstdig.c
++
+ ezmlm-unsub: \
+-load ezmlm-unsub.o subscribe.o log.o now.o fs.a strerr.a getln.a \
++load ezmlm-unsub.o subdb.a getconf.o slurpclose.o slurp.o \
++log.o now.o fs.a strerr.a getln.a getopt.a fs.a conf-sqlld \
+ substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a
+-      ./load ezmlm-unsub subscribe.o log.o now.o fs.a strerr.a \
++      ./load ezmlm-unsub subdb.a getopt.a getconf.o slurpclose.o slurp.o \
++      log.o now.o fs.a strerr.a fs.a \
+       getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \
+-      open.a lock.a 
++      open.a lock.a ${SQLLD}
+ ezmlm-unsub.0: \
+ ezmlm-unsub.1
+       nroff -man ezmlm-unsub.1 > ezmlm-unsub.0
+ ezmlm-unsub.o: \
+-compile ezmlm-unsub.c strerr.h ezmlm-unsub.c subscribe.h strerr.h \
+-strerr.h subscribe.h ezmlm-unsub.c log.h ezmlm-unsub.c
++compile ezmlm-unsub.c strerr.h subscribe.h \
++log.h errtxt.h sgetopt.h scan.h idx.h readwrite.h stralloc.h substdio.h 
+       ./compile ezmlm-unsub.c
+ ezmlm-warn: \
+-load ezmlm-warn.o auto_qmail.o getconf.o cookie.o issub.o now.o \
++load ezmlm-warn.o auto_qmail.o getconf.o mime.a cookie.o subdb.a now.o \
+ slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \
+ case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \
+-open.a lock.a str.a fs.a fd.a wait.a
+-      ./load ezmlm-warn auto_qmail.o getconf.o cookie.o issub.o \
++open.a lock.a str.a fs.a fd.a wait.a copy.o getopt.a conf-sqlld
++      ./load ezmlm-warn auto_qmail.o getconf.o mime.a \
++      cookie.o subdb.a getopt.a \
+       now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \
+       qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \
+       stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \
+-      wait.a 
++      wait.a copy.o ${SQLLD}
+ ezmlm-warn.0: \
+ ezmlm-warn.1
+       nroff -man ezmlm-warn.1 > ezmlm-warn.0
+ ezmlm-warn.o: \
+-compile ezmlm-warn.c ezmlm-warn.c ezmlm-warn.c direntry.h direntry.h \
+-direntry.h ezmlm-warn.c readwrite.h ezmlm-warn.c getln.h ezmlm-warn.c \
+-substdio.h ezmlm-warn.c stralloc.h gen_alloc.h stralloc.h \
+-ezmlm-warn.c slurp.h ezmlm-warn.c getconf.h ezmlm-warn.c byte.h \
+-ezmlm-warn.c error.h ezmlm-warn.c str.h ezmlm-warn.c strerr.h \
+-ezmlm-warn.c sig.h ezmlm-warn.c now.h datetime.h now.h ezmlm-warn.c \
+-datetime.h datetime.h ezmlm-warn.c date822fmt.h ezmlm-warn.c fmt.h \
+-ezmlm-warn.c cookie.h ezmlm-warn.c qmail.h substdio.h substdio.h \
+-qmail.h ezmlm-warn.c
++compile ezmlm-warn.c direntry.h readwrite.h getln.h \
++substdio.h stralloc.h gen_alloc.h slurp.h getconf.h byte.h error.h str.h \
++sig.h now.h datetime.h  date822fmt.h fmt.h cookie.h qmail.h substdio.h \
++qmail.h copy.h mime.h idx.h errtxt.h sgetopt.h subgetopt.h
+       ./compile ezmlm-warn.c
+ ezmlm-weed: \
+-load ezmlm-weed.o getln.a strerr.a substdio.a error.a stralloc.a \
++load ezmlm-weed.o getln.a strerr.a substdio.a error.a case.a stralloc.a \
+ alloc.a str.a
+       ./load ezmlm-weed getln.a strerr.a substdio.a error.a \
+-      stralloc.a alloc.a str.a 
++      case.a stralloc.a alloc.a str.a 
+ ezmlm-weed.0: \
+ ezmlm-weed.1
+@@ -380,6 +882,18 @@
+ ezmlm.5
+       nroff -man ezmlm.5 > ezmlm.0
++ezmlmglrc.0: \
++ezmlmglrc.5
++      nroff -man ezmlmglrc.5 > ezmlmglrc.0
++
++ezmlmrc.0: \
++ezmlmrc.5
++      nroff -man ezmlmrc.5 > ezmlmrc.0
++
++ezmlmsubrc.0: \
++ezmlmsubrc.5
++      nroff -man ezmlmsubrc.5 > ezmlmsubrc.0
++
+ fd.a: \
+ makelib fd_copy.o fd_move.o
+       ./makelib fd.a fd_copy.o fd_move.o
+@@ -496,16 +1010,23 @@
+ byte.h install.c
+       ./compile install.c
++idxthread.o: \
++compile idxthread.c idxthread.h alloc.h error.h stralloc.h str.h lock.h idx.h \
++substdio.h fmt.h readwrite.h idx.h errtxt.h substdio.h byte.h yyyymm.h
++      ./compile idxthread.c
++
+ issub.o: \
+-compile issub.c stralloc.h gen_alloc.h stralloc.h issub.c getln.h \
+-issub.c readwrite.h issub.c substdio.h issub.c open.h issub.c byte.h \
+-issub.c case.h issub.c lock.h issub.c error.h issub.c issub.h \
+-strerr.h issub.h issub.c uint32.h issub.c
+-      ./compile issub.c
++compile issub.c stralloc.h gen_alloc.h getln.h readwrite.h substdio.h \
++open.h byte.h case.h lock.h error.h subscribe.h strerr.h uint32.h fmt.h \
++conf-sqlcc
++      ./compile issub.c ${SQLCC}
+ it: \
++ezmlm-idx ezmlm-accept ezmlm-archive ezmlm-check ezmlm-gate ezmlm-get \
++ezmlm-clean ezmlm-glconf ezmlm-moderate ezmlm-store ezmlm-tstdig \
+ ezmlm-make ezmlm-manage ezmlm-send ezmlm-reject ezmlm-return \
+-ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub
++ezmlm-warn ezmlm-weed ezmlm-list ezmlm-sub ezmlm-unsub ezmlm-cgi ezmlm-limit \
++ezmlm-issubn ezmlm-cron ezmlm-request ezmlm-test ezmlm-split ezmlmrc
+ load: \
+ make-load warn-auto.sh systype
+@@ -527,6 +1048,10 @@
+ fmt.h log.c open.h log.c
+       ./compile log.c
++logmsg.o: \
++compile logmsg.c stralloc.h fmt.h conf-sqlcc
++      ./compile logmsg.c ${SQLCC}
++
+ make-compile: \
+ make-compile.sh auto-ccld.sh
+       cat auto-ccld.sh make-compile.sh > make-compile
+@@ -542,6 +1067,10 @@
+       cat auto-ccld.sh make-makelib.sh > make-makelib
+       chmod 755 make-makelib
++makehash.o: \
++makehash.c makehash.h surf.h uint32.h stralloc.h
++      ./compile makehash.c
++
+ makelib: \
+ make-makelib warn-auto.sh systype
+       ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \
+@@ -549,12 +1078,23 @@
+       chmod 755 makelib
+ man: \
+-ezmlm.0 ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 \
++ezmlm.0 ezmlm-gate.0 ezmlm-idx.0 ezmlm-get.0 ezmlm-check.0 ezmlm-tstdig.0 \
++ezmlm-make.0 ezmlm-manage.0 ezmlm-send.0 ezmlm-reject.0 ezmlm-accept.0 \
+ ezmlm-return.0 ezmlm-warn.0 ezmlm-weed.0 ezmlm-list.0 ezmlm-sub.0 \
+ ezmlm-unsub.0 alloc.0 case.0 datetime.0 direntry.0 env.0 error.0 \
+ error_str.0 error_temp.0 ezmlm.0 fd_copy.0 fd_move.0 getln.0 getln2.0 \
++ezmlm-issubn.0 ezmlm-cron.0 ezmlm-glconf.0 ezmlmglrc.0 ezmlm-test.0 \
++ezmlmsubrc.0 ezmlm-mktab.0 ezmlm-split.0 ezmlm-archive.0 ezmlm-cgi.0 \
+ getopt.0 now.0 sgetopt.0 stralloc.0 subfd.0 subgetopt.0 substdio.0 \
+-substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0
++substdio_copy.0 substdio_in.0 substdio_out.0 surf.0 surfpcs.0 wait.0 \
++ezmlm-clean.0 ezmlm-moderate.0 ezmlm-store.0 ezmlm-request.0 ezmlmrc.0 \
++ezmlm-limit.0
++
++mime.a: \
++makelib concatHDR.o decodeHDR.o unfoldHDR.o \
++decodeQ.o encodeQ.o decodeB.o encodeB.o author.o
++      ./makelib mime.a concatHDR.o decodeHDR.o decodeQ.o encodeQ.o \
++      decodeB.o encodeB.o unfoldHDR.o author.o
+ now.0: \
+ now.3
+@@ -582,6 +1122,16 @@
+ compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c
+       ./compile open_trunc.c
++opensql.o: \
++compile opensql.c error.h strerr.h errtxt.h \
++      str.h case.h stralloc.h subscribe.h conf-sqlcc
++      ./compile opensql.c ${SQLCC}
++
++putsubs.o: \
++compile putsubs.c error.h substdio.h strerr.h readwrite.h \
++str.h open.h case.h errtxt.h stralloc.h subscribe.h qmail.h fmt.h conf-sqlcc
++      ./compile putsubs.c ${SQLCC}
++
+ 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 \
+@@ -601,6 +1151,12 @@
+ compile scan_ulong.c scan.h scan_ulong.c
+       ./compile scan_ulong.c
++searchlog.o: \
++compile searchlog.c case.h stralloc.h scan.h open.h datetime.h errtxt.h str.h \
++      datetime.h date822fmt.h substdio.h readwrite.h strerr.h error.h \
++      subscribe.h conf-sqlcc
++      ./compile searchlog.c ${SQLCC}
++
+ seek.a: \
+ makelib seek_set.o
+       ./makelib seek.a seek_set.o
+@@ -800,6 +1356,12 @@
+ compile strerr_sys.c error.h strerr_sys.c strerr.h strerr_sys.c
+       ./compile strerr_sys.c
++subdb.a: \
++makelib checktag.o issub.o logmsg.o subscribe.o opensql.o putsubs.o \
++      tagmsg.o searchlog.o
++      ./makelib subdb.a checktag.o issub.o logmsg.o subscribe.o \
++      opensql.o putsubs.o tagmsg.o searchlog.o
++
+ subfd.0: \
+ subfd.3
+       nroff -man subfd.3 > subfd.0
+@@ -818,12 +1380,10 @@
+       ./compile subgetopt.c
+ subscribe.o: \
+-compile subscribe.c stralloc.h gen_alloc.h stralloc.h subscribe.c \
+-getln.h subscribe.c readwrite.h subscribe.c substdio.h subscribe.c \
+-strerr.h subscribe.c open.h subscribe.c byte.h subscribe.c case.h \
+-subscribe.c lock.h subscribe.c error.h subscribe.c uint32.h \
+-subscribe.c subscribe.h strerr.h strerr.h subscribe.h subscribe.c
+-      ./compile subscribe.c
++compile subscribe.c stralloc.h gen_alloc.h stralloc.h \
++getln.h readwrite.h substdio.h strerr.h open.h byte.h case.h \
++lock.h error.h uint32.h subscribe.h idx.h fmt.h conf-sqlcc
++      ./compile subscribe.c ${SQLCC}
+ substdi.o: \
+ compile substdi.c substdio.h substdi.c byte.h substdi.c error.h \
+@@ -889,6 +1449,10 @@
+ find-systype trycpp.c
+       ./find-systype > systype
++tagmsg.o: \
++compile tagmsg.c stralloc.h slurp.h scan.h fmt.h strerr.h cookie.h conf-sqlcc
++      ./compile tagmsg.c ${SQLCC}
++
+ uint32.h: \
+ tryulong32.c compile load uint32.h1 uint32.h2
+       ( ( ./compile tryulong32.c && ./load tryulong32 && \
+@@ -907,3 +1471,124 @@
+ wait_pid.o: \
+ compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c
+       ./compile wait_pid.c
++
++yyyymm.a: \
++makelib date2yyyymm.o dateline.o
++      ./makelib yyyymm.a date2yyyymm.o dateline.o
++
++ch: \
++ezmlmrc.ch
++      cp -f ezmlmrc.ch_GB ezmlmrc
++
++ch_GB: \
++ezmlmrc.ch_GB
++      cp -f ezmlmrc.ch_GB ezmlmrc
++
++cs: \
++ezmlmrc.cs
++      cp -f ezmlmrc.cs ezmlmrc
++
++da: \
++ezmlmrc.da
++      cp -f ezmlmrc.da ezmlmrc
++
++de: \
++ezmlmrc.de
++      cp -f ezmlmrc.de ezmlmrc
++
++en_US: \
++ezmlmrc.en_US
++      cp -f ezmlmrc.en_US ezmlmrc
++
++en: \
++ezmlmrc.en_US
++      cp -f ezmlmrc.en_US ezmlmrc
++
++es: \
++ezmlmrc.es
++      cp -f ezmlmrc.es ezmlmrc
++
++us: \
++ezmlmrc.en_US
++      cp -f ezmlmrc.en_US ezmlmrc
++
++ezmlmrc: \
++ezmlmrc.en_US
++      cp -f ezmlmrc.en_US ezmlmrc
++
++fr: \
++ezmlmrc.fr
++      cp -f ezmlmrc.fr ezmlmrc
++
++id: \
++ezmlmrc.id
++      cp -f ezmlmrc.id ezmlmrc
++
++ita: \
++ezmlmrc.it
++      cp -f ezmlmrc.it ezmlmrc
++
++jp: \
++ezmlmrc.jp
++      cp -f ezmlmrc.jp ezmlmrc
++
++pl: \
++ezmlmrc.pl
++      cp -f ezmlmrc.pl ezmlmrc
++
++pt: \
++ezmlmrc.pt
++      cp -f ezmlmrc.pt ezmlmrc
++
++pt_BR: \
++ezmlmrc.pt_BR
++      cp -f ezmlmrc.pt_BR ezmlmrc
++
++ru: \
++ezmlmrc.ru
++      cp -f ezmlmrc.ru ezmlmrc
++
++sv: \
++ezmlmrc.sv
++      cp -f ezmlmrc.sv ezmlmrc
++
++mysql:
++      ln -sf sub_mysql/ezmlm-mktab ezmlm-mktab
++      ln -sf sub_mysql/checktag.c checktag.c; rm -f checktag.o
++      ln -sf sub_mysql/issub.c issub.c; rm -f issub.o
++      ln -sf sub_mysql/logmsg.c logmsg.c; rm -f logmsg.o
++      ln -sf sub_mysql/subscribe.c subscribe.c; rm -f subscribe.o
++      ln -sf sub_mysql/opensql.c opensql.c; rm -f opensql.o
++      ln -sf sub_mysql/putsubs.c putsubs.c; rm -f putsubs.o
++      ln -sf sub_mysql/tagmsg.c tagmsg.c; rm -f tagmsg.o
++      ln -sf sub_mysql/searchlog.c searchlog.c; rm -f searchlog.o
++      ln -sf sub_mysql/conf-sqlld conf-sqlld; touch conf-sqlld
++      ln -sf sub_mysql/conf-sqlcc conf-sqlcc; touch conf-sqlcc
++
++pgsql:
++      ln -sf sub_pgsql/ezmlm-mktab ezmlm-mktab
++      ln -sf sub_pgsql/checktag.c checktag.c; rm -f checktag.o
++      ln -sf sub_pgsql/issub.c issub.c; rm -f issub.o
++      ln -sf sub_pgsql/logmsg.c logmsg.c; rm -f logmsg.o
++      ln -sf sub_pgsql/subscribe.c subscribe.c; rm -f subscribe.o
++      ln -sf sub_pgsql/opensql.c opensql.c; rm -f opensql.o
++      ln -sf sub_pgsql/putsubs.c putsubs.c; rm -f putsubs.o
++      ln -sf sub_pgsql/tagmsg.c tagmsg.c; rm -f tagmsg.o
++      ln -sf sub_pgsql/searchlog.c searchlog.c; rm -f searchlog.o
++      ln -sf sub_pgsql/conf-sqlld conf-sqlld; touch conf-sqlld
++      ln -sf sub_pgsql/conf-sqlcc conf-sqlcc; touch conf-sqlcc
++
++std:
++      ln -sf sub_std/ezmlm-mktab ezmlm-mktab
++      ln -sf sub_std/checktag.c checktag.c; rm -f checktag.o
++      ln -sf sub_std/issub.c issub.c; rm -f issub.o
++      ln -sf sub_std/logmsg.c logmsg.c; rm -f logmsg.o
++      ln -sf sub_std/subscribe.c subscribe.c; rm -f subscribe.o
++      ln -sf sub_std/opensql.c opensql.c; rm -f opensql.o
++      ln -sf sub_std/putsubs.c putsubs.c; rm -f putsubs.o
++      ln -sf sub_std/tagmsg.c tagmsg.c; rm -f tagmsg.o
++      ln -sf sub_std/searchlog.c searchlog.c; rm -f searchlog.o
++      ln -sf sub_std/conf-sqlld conf-sqlld; touch conf-sqlld
++      ln -sf sub_std/conf-sqlcc conf-sqlcc; touch conf-sqlcc
++
++
+--- constmap.c 1998/05/20 22:37:38     1.1
++++ constmap.c 1998/12/12 18:57:23     1.3
+@@ -18,6 +18,39 @@
+   return h;
+ }
++/* Returns index of string in constmap. 1 = first string, 2 = second ... */
++/* 0 not found. Use for commands */ 
++int constmap_index(cm,s,len)
++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 pos + 1;
++    pos = cm->next[pos];
++  }
++  return 0;
++}
++
++/* returns pointer to sz of string with index "idx". 1 = first, 2 = second...*/
++char *constmap_get(cm,idx)
++struct constmap *cm;
++int idx;
++
++{
++  if (idx <= 0 || idx > cm->num)
++    return 0;
++  else
++    return cm->input[idx-1];
++}
++
+ char *constmap(cm,s,len)
+ struct constmap *cm;
+ char *s;
+@@ -38,6 +71,9 @@
+ }
+ int constmap_init(cm,s,len,flagcolon)
++/* if flagcolon is true, we process only the stuff before the colon on */
++/* each line. Otherwise, it's the entire line. Still, the entire line */
++/* is stored! */
+ struct constmap *cm;
+ char *s;
+ int len;
+--- constmap.h 1998/05/20 22:37:38     1.1
++++ constmap.h 1999/09/29 03:16:11     1.3
+@@ -16,5 +16,6 @@
+ extern int constmap_init();
+ extern void constmap_free();
+ extern char *constmap();
+-
++extern char *constmap_get();
++extern int constmap_index();
+ #endif
+--- error.h    1999/01/09 01:36:11     1.1
++++ error.h    1999/01/09 01:59:56     1.2
+@@ -16,6 +16,7 @@
+ extern int error_pipe;
+ extern int error_perm;
+ extern int error_acces;
++extern int error_notdir;
+ extern char *error_str();
+ extern int error_temp();
+--- error.c    1999/01/09 01:36:42     1.1
++++ error.c    1999/01/09 01:59:56     1.2
+@@ -17,7 +17,7 @@
+ -2;
+ #endif
+-int error_noent = 
++int error_noent =
+ #ifdef ENOENT
+ ENOENT;
+ #else
+@@ -92,4 +92,11 @@
+ EACCES;
+ #else
+ -13;
++#endif
++
++int error_notdir =
++#ifdef ENOTDIR
++ENOTDIR;
++#else
++-14;
+ #endif
+--- ezmlm-weed.c       1999/04/11 19:09:55     1.1
++++ ezmlm-weed.c       1999/12/19 16:49:32     1.4
+@@ -5,18 +5,24 @@
+ #include "substdio.h"
+ #include "getln.h"
+ #include "strerr.h"
++#include "errtxt.h"
+ char buf0[256];
+ substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
+ #define FATAL "ezmlm-weed: fatal: "
++void die_nomem()
++{
++  strerr_die2x(111,FATAL,ERR_NOMEM);
++}
++
+ void get(sa)
+ stralloc *sa;
+ {
+   int match;
+   if (getln(&ss0,sa,&match,'\n') == -1)
+-    strerr_die2sys(111,FATAL,"unable to read input: ");
++    strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+   if (!match) _exit(0);
+ }
+@@ -30,6 +36,9 @@
+ stralloc line7 = {0};
+ stralloc line8 = {0};
++stralloc boundary = {0};
++stralloc dsnline = {0};
++
+ char warn1[] = "    **********************************************";
+ char warn2[] = "    **      THIS IS A WARNING MESSAGE ONLY      **";
+ char warn3[] = "    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **";
+@@ -40,19 +49,46 @@
+ int flagsr = 0;
+ int flagas = 0;
+ int flagbw = 0;
++int flagdsn = 0;
++
++int isboundary()
++/* returns 1 if line.len contains the mime bondary, 0 otherwise */
++{
++    if (line.s[0] == '-' && line.s[1] == '-' && line.len >= boundary.len + 3)
++      if (!byte_diff(line.s + 2,boundary.len,boundary.s))     /* boundary */
++        return 1;
++    return 0;
++}
+ void main()
+ {
+-  int match;
++  unsigned int i,j;
+   for (;;) {
+     get(&line);
+     if (line.len == 1) break;
+-
++    if (line.s[0] == ' ' || line.s[0] == '\t') {      /* continuation */
++      if (flagdsn) {
++      if (!stralloc_catb(&dsnline,line.s,line.len - 1)) die_nomem();
++      continue;
++      }
++    }
++    flagdsn = 0;
+     if (stralloc_starts(&line,"Subject: success notice"))
+       _exit(99);
+     if (stralloc_starts(&line,"Subject: deferral notice"))
+       _exit(99);
++    if (stralloc_starts(&line,"Precedence: bulk"))
++      _exit(99);
++    if (stralloc_starts(&line,"Precedence: junk"))
++      _exit(99);
++/* for Novell Groupwise */
++    if (stralloc_starts(&line,"Subject: Message status - delivered"))
++      _exit(99);
++    if (stralloc_starts(&line,"Subject: Message status - opened"))
++      _exit(99);
++    if (stralloc_starts(&line,"Subject: Out of Office AutoReply:"))
++      _exit(99);
+     if (stralloc_starts(&line,"From: Mail Delivery Subsystem <MAILER-DAEMON@"))
+       flagmds = 1;
+@@ -62,6 +98,71 @@
+       flagsr = 1;
+     if (stralloc_starts(&line,"Auto-Submitted: auto-generated (warning"))
+       flagas = 1;
++    if (case_startb(line.s,line.len,"Content-type: multipart/report"))
++      if (!stralloc_copyb(&dsnline,line.s,line.len - 1)) die_nomem();
++      flagdsn = 1;
++  }                   /* end of header */
++
++  if (flagdsn) {      /* always only one recipient/action */
++    flagdsn = 0;      /* will be set for correct report type */
++    for (i=0; i < dsnline.len; i += 1+byte_chr(dsnline.s+i,dsnline.len-i,';')) {
++      while (dsnline.s[i] == ' ' || dsnline.s[i] == '\t')
++      if (++i >= dsnline.len) break;
++      if (case_startb(dsnline.s + i,dsnline.len - i,"report-type=")) {
++      i += 12;
++      while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t' || dsnline.s[i] =='"')
++        if (++i >= dsnline.len) break;
++      if (case_startb(dsnline.s + i,dsnline.len - i,"delivery-status"))
++        flagdsn = 1;
++      } else if (case_startb(dsnline.s + i,dsnline.len - i,"boundary=")) {
++      i += 9;
++      while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t')
++        if (++i >= dsnline.len) break;
++      if (dsnline.s[i] == '"') {
++        if (++i >= dsnline.len) break;
++        j = i + byte_chr(dsnline.s + i,dsnline.len - i,'"');
++        if (j >= dsnline.len) break;
++      } else {
++        j = i;
++        while (dsnline.s[j] !=' ' && dsnline.s[j] !='\t' &&
++              dsnline.s[j] !=';')
++          if (++j >= dsnline.len) break;
++      }                               /* got boundary */
++      if (!stralloc_copyb(&boundary,dsnline.s+i,j-i)) die_nomem();
++      }
++    }
++  }
++  if (flagdsn && boundary.len) {      /* parse DSN message */
++    get(&line);                       /* if bad format we exit(0) via get() */
++    for (;;) {
++      if (isboundary()) {
++      if (line.len == boundary.len + 5 && line.s[line.len - 1] == '-'
++              && line.s[line.len - 2] == '-')
++        _exit(99);                    /* end: not failure report */
++        get(&line);                   /* Content-type */
++        if (case_startb(line.s,line.len,"content-type:")) {
++        i = 13;
++        while (line.s[i] == ' ' || line.s[i] == '\t')
++              if (++i >= line.len) break;
++        if (case_startb(line.s+i,line.len-i,"message/delivery-status")) {
++          for (;;) {
++            get(&line);
++            if (isboundary()) break;
++            if (case_startb(line.s,line.len,"action:")) {
++              i = 8;
++              while (line.s[i] == ' ' || line.s[i] == '\t')
++                if (++i >= line.len) break;
++              if (case_startb(line.s + i, line.len - i,"failed"))
++                _exit(0);     /* failure notice */
++              else
++                _exit(99);    /* there shouldn't be more than 1 action */
++            }
++            }
++        }
++        }
++      } else
++      get(&line);
++    }
+   }
+   get(&line1);
+--- ezmlm-weed.1       1999/08/01 16:45:46     1.1
++++ ezmlm-weed.1       1999/12/19 16:53:18     1.3
+@@ -7,6 +7,8 @@
+ .B ezmlm-weed
+ reads a mail message from its standard input.
+ If it recognizes the message as an MTA warning message or success message,
++or as a message with precedence ``bulk'' or ``junk'' as generated by
++vacation autoresponders,
+ it exits 99;
+ this will cause
+ .B qmail-alias
+@@ -33,6 +35,13 @@
+    Subject: deferral notice
+ .EE
++Delivery-status notification (DSN, rfc1891). All DSN messages with ``Action''
++other than ``failed'':
++
++.EX
++   Content-type: multipart/report
++.EE
++
+ Warning message from sendmail, MIME form:
+ .EX
+@@ -104,6 +113,21 @@
+ .EX
+    THIS IS A WARNING MESSAGE ONLY
+ .EE
++
++Notification messages from Novell Groupwise:
++
++.EX
++  Subject: Message status - delivered
++.EE
++.br
++.EX
++  Subject: Message status - opened
++.EE
++.br
++.EX
++  Subject: Out of Office AutoReply:
++.EE
++
+ .SH "SEE ALSO"
+ ezmlm-return(1),
+ qmail-command(8)
diff --git a/idxthread.c b/idxthread.c
new file mode 100644 (file)
index 0000000..b8ed2b0
--- /dev/null
@@ -0,0 +1,682 @@
+/*$Id: idxthread.c,v 1.35 1999/11/22 01:47:45 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+/* idxthread.c contains routines to from the ezmlm-idx subject index build */
+/* a structure of unique subjects as well as a table of messages with      */
+/* pointers to the subject. This leads to information on message threads   */
+/* arranged chronologically within the thread, and with the threads        */
+/* arranged chronologically by the first message within the range.         */
+/* idx_mkthreads() will arrange the author list in a similar manner. This  */
+/* saves some space, and takes a little extra time. It's needed when       */
+/* generating an author index. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "alloc.h"
+#include "str.h"
+#include "stralloc.h"
+#include "strerr.h"
+#include "lock.h"
+#include "idx.h"
+#include "errtxt.h"
+#include "substdio.h"
+#include "fmt.h"
+#include "readwrite.h"
+#include "makehash.h"
+#include "yyyymm.h"
+
+#define DATENO 100
+static stralloc line = {0};            /* primary input */
+static stralloc authline = {0};                /* second line of primary input */
+static stralloc dummyind = {0};
+
+static substdio ssindex;
+static char indexbuf[1024];
+
+static char strnum[FMT_ULONG];
+
+struct stat st;
+                       /* if no data, these may be the entire table, so */
+                       /* need to be static */
+static subentry sdummy;
+static authentry adummy;
+
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+int fdlock;
+
+/* NOTE: These do NOT prevent double locking */
+static void lockup(fatal)
+char *fatal;
+{
+  fdlock = open_append("lock");
+  if (fdlock == -1)
+    strerr_die2sys(111,fatal,ERR_OPEN_LOCK);
+  if (lock_ex(fdlock) == -1) {
+    close(fdlock);
+    strerr_die2sys(111,fatal,ERR_OBTAIN_LOCK);
+  }
+}
+
+static void unlock()
+{
+    close(fdlock);
+}
+
+static void newsub(psubt,subject,sublen,msg,fatal)
+/* Initializes subentry pointed to by psubt, adds a '\0' to subject,    */
+/* allocates space and copies in subject, and puts a pointer to it in   */
+/* the entry. */
+subentry *psubt;
+char *subject;
+unsigned int sublen;
+unsigned long msg;
+char *fatal;
+{
+  register char *cpfrom, *cpto;
+  register unsigned int cpno;
+
+  psubt->higher = (subentry *) 0;
+  psubt->lower = (subentry *) 0;
+  psubt->firstmsg = msg;
+  psubt->lastmsg = msg;
+  psubt->msginthread = 1;
+  if (!(psubt->sub = alloc ((sublen) * sizeof(char))))
+    die_nomem(fatal);
+  cpto = psubt->sub;
+  cpno = sublen;
+  cpfrom = subject;
+  while (cpno--) *(cpto++) = *(cpfrom++);
+  psubt->sublen = sublen;
+}
+
+static void newauth(pautht,author,authlen,msg,fatal)
+/* Allocates space for author of length authlen+1 adding a terminal '\0' */
+/* and puts the pointer in pautht->auth. Analog to newsub().             */
+authentry *pautht;     /* entry for current message */
+char *author;          /* pointer to author string (not sz!) */
+unsigned int authlen;  /* lenth of author */
+unsigned long msg;
+char *fatal;           /* sz */
+
+{
+  register char *cpfrom, *cpto;
+  register unsigned int cpno;
+
+  pautht->higher = (subentry *) 0;
+  pautht->lower = (subentry *) 0;
+  pautht->firstmsg = msg;
+  if (!(pautht->auth = alloc ((authlen) * sizeof(char))))
+    die_nomem(fatal);
+  cpto = pautht->auth;
+  cpno = authlen;
+  cpfrom = author;
+  while (cpno--) *(cpto++) = *(cpfrom++);
+  pautht->authlen = authlen;
+}
+
+static void init_dummy(fatal)
+char *fatal;
+{
+  unsigned int i;
+
+  if (!stralloc_ready(&dummyind,HASHLEN + 1)) die_nomem(fatal);
+  for (i = 0; i< HASHLEN; i++)
+    dummyind.s[i] = 'a';
+  dummyind.len = HASHLEN;
+  if (!stralloc_append(&dummyind," ")) die_nomem(fatal);
+}
+
+void idx_mkthreads(pmsgtable,psubtable,pauthtable,pdatetable,
+       msg_from,msg_to,msg_latest,locked,fatal)
+/* Threads messages msg_from -> msg_to into pmsgtable & psubtable. When  */
+/* reading the latest index file (containing msg_latest) it locks the    */
+/* directory, unless it is already locked (as in digest creation).       */
+/* msgtable has the subject number 1.. (0 if there is no subject match,  */
+/* which should happen only if the subject index is corrupt.)            */
+
+/* 19971107 Changed to deal with index files that are missing, or have   */
+/* missing entries, not necessarily reflecting missing archive files.    */
+/* This all to make ezmlm-get more robust to get maximal info out of     */
+/* corrupted archives.                                                   */
+
+  msgentry **pmsgtable;                /* table of message<->subject */
+  subentry **psubtable;                /* subject no, len, str char * */
+  authentry **pauthtable;      /* author no, len, str char * */
+  dateentry **pdatetable;      /* message per date */
+  unsigned long msg_from;      /* first message in range */
+  unsigned long msg_to;                /* last message in range */
+  unsigned long msg_latest;    /* latest message in archive (for locking) */
+  int locked;                  /* if already locked */
+  char *fatal;                 /* Program-specific */
+
+{
+  unsigned long idxlatest;     /* need to lock for this (last) index file */
+  unsigned long msg;           /* current msg number */
+  unsigned long endmsg;                /* max msg in this idx file */
+  unsigned long tmpmsg;                /* index entry's msg number */
+  unsigned long idx;           /* current index file no */
+  unsigned long idxto;         /* index containing end of range */
+  unsigned long ulmrange;      /* total # of messages in range */
+  char *subject;               /* subject on line */
+  unsigned int sublen;         /* length of subject */
+  char *auth;
+  unsigned int authlen;
+  unsigned int pos,posa;
+  unsigned long submax;                /* max subject num in subtable */
+  subentry *psubnext;          /* points to next entry in subtable */
+  subentry *psubt;             /* points to entry in subtable */
+  authentry *pauthnext;                /* points to next entry in authtable */
+  authentry *pautht;           /* points to entry in authtable */
+  int fd;                      /* index file handle */
+  int flagmissingindex;                /* current index file is missing */
+  int flagauth;                        /* read index entry has author info */
+  int hasauth;                 /* current msg's entry has author info */
+  msgentry *pmsgt;
+  int res;
+  int match;
+  unsigned int datepos,datemax;
+  unsigned int datetablesize,datetableunit;
+  unsigned int lastdate = 0;
+  unsigned int thisdate;
+  register msgentry *x, *y;
+
+                               /* a few unnecessary sanity checks */
+  if (msg_to > msg_latest)
+    msg_to = msg_latest;
+  if (msg_to < msg_from)
+    strerr_die2x(100,fatal,"Program error: bad range in idx_mkthreads");
+  ulmrange = msg_to - msg_from + 1;
+  if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry))))
+        die_nomem(fatal);
+  y = *pmsgtable;
+  x = y + ulmrange;            /* clear */
+  while (--x >= y) {
+    x->subnum = 0;
+    x->authnum = 0;
+    x->date = 0;
+  }
+                               /* max entries - acceptable waste for now */
+  if (!(*psubtable = (subentry *) alloc((ulmrange+1) * sizeof(subentry))))
+        die_nomem(fatal);
+
+  if (!(*pauthtable = (authentry *) alloc((ulmrange+1) * sizeof(authentry))))
+        die_nomem(fatal);
+  datetableunit = DATENO * sizeof(dateentry);
+  datetablesize = datetableunit;
+  if (!(*pdatetable = (dateentry *) alloc(datetablesize)))
+        die_nomem(fatal);
+  datepos = 0;
+  datemax = DATENO - 2;                /* entry 0 and end marker */
+  lastdate = 0;
+
+  idxlatest = msg_latest / 100;
+  idxto = msg_to / 100;
+  submax = 0;
+  psubnext = *psubtable;       /* dummy node to get tree going. Basically, */
+  psubt = &sdummy;             /* assure that subject > psubt-sub and that */
+  init_dummy(fatal);           /* below ok unless HASHLEN > 40 */
+  psubt->sub = "                                       ";
+  psubt->sublen = 40;          /* there is something to hold psubt->higher */
+  psubt->higher = (subentry *) 0;
+  psubt->lower = (subentry *) 0;
+  pauthnext = *pauthtable;
+  pautht = &adummy;
+  pautht->auth = psubt->sub;
+  pautht->authlen = psubt->sublen;
+  pautht->higher = (authentry *) 0;
+  pautht->lower = (authentry *) 0;
+  for (idx = msg_from / 100; idx <= idxto; idx++) {
+                               /* make index file name */
+    if (!stralloc_copys(&line,"archive/")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal);
+    if (!stralloc_cats(&line,"/index")) die_nomem(fatal);
+    if (!stralloc_0(&line)) die_nomem(fatal);
+    if (!locked && idx == idxlatest)
+      lockup(fatal);
+    flagmissingindex = 0;
+    fd = open_read(line.s);
+    if (fd == -1) {
+      if (errno == error_noent) {      /* this means the index is not here */
+                                       /* but the lists is supposedly indexed*/
+        flagmissingindex = 1;
+      } else
+        strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    } else
+      substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf));
+
+    msg = 100L * idx;                  /* current msg# */
+    endmsg = msg + 99L;                        /* max msg in this index */
+    if (!msg) msg = 1L;                        /* for start to make msg > tmpmsg */
+    tmpmsg = 0L;                       /* msg number of read index line */
+    if (endmsg > msg_to)               /* skip non-asked for subjects */
+      endmsg = msg_to;
+    for (; msg <= endmsg; msg++) {
+      if (!flagmissingindex && (msg > tmpmsg)) {
+        flagauth = 0;
+        if (getln(&ssindex,&line,&match,'\n') == -1)
+          strerr_die3sys(111,fatal,ERR_READ,"index: ");
+        if (!match)
+          flagmissingindex = 1;
+        else {
+          pos = scan_ulong(line.s,&tmpmsg);
+          if (line.s[pos++] == ':') {
+            if (getln(&ssindex,&authline,&match,'\n') == -1)
+              strerr_die3sys(111,fatal,ERR_READ,"index: ");
+            if (!match)
+              flagmissingindex = 1;
+            else {
+              flagauth = 1;
+           }
+            pos++;
+          }
+        }
+      }
+      if (msg < msg_from)      /* Nothing before start of range */
+        continue;
+      if (msg == tmpmsg) {
+        subject = line.s + pos;
+        sublen = line.len - pos;
+       if (sublen <= HASHLEN)
+         strerr_die2x(100,fatal,ERR_BAD_INDEX);
+        hasauth = flagauth;
+      } else {
+        subject = dummyind.s;
+        sublen = dummyind.len;
+        hasauth = 0;
+      }
+      for(;;) {                /* search among already known subjects */
+        res = str_diffn(psubt->sub,subject,HASHLEN);
+        if (res < 0) {
+          if (psubt->higher)
+            psubt = psubt->higher;
+          else {
+            newsub(psubnext,subject,sublen,msg,fatal);
+            psubt->higher = psubnext;
+            psubt = psubnext;
+            psubnext++;
+            break;
+          }
+        } else if (res > 0) {
+          if (psubt->lower)
+            psubt = psubt->lower;
+          else {
+            newsub(psubnext,subject,sublen,msg,fatal);
+            psubt->lower = psubnext;
+            psubt = psubnext;
+            psubnext++;
+            break;
+          }
+        } else {
+          psubt->lastmsg = msg;
+         (psubt->msginthread)++;       /* one more message in thread */
+         break;
+        }
+      }
+                               /* first subnum =1 (=0 is empty for thread) */
+      pmsgt = *pmsgtable + msg - msg_from;
+      pmsgt->subnum = (unsigned int) (psubt - *psubtable + 1);
+      pmsgt->date = lastdate;
+      if (hasauth) {
+       pos = 0;
+       while (authline.s[pos] && authline.s[pos] != ' ') pos++;
+       if (authline.s[++pos]) {
+         thisdate = date2yyyymm(authline.s + pos);
+         if (thisdate) pmsgt->date = thisdate;
+         if (pmsgt->date > lastdate) {
+           lastdate = pmsgt->date;
+           if (datepos >= datemax) {           /* more space */
+             datemax += DATENO;
+             if (!(*pdatetable = (dateentry *) alloc_re(*pdatetable,
+                       datetablesize,datetablesize+datetableunit)))
+               die_nomem(fatal);
+           }
+           (*pdatetable)[datepos].msg = msg;   /* first msg this mo */
+           (*pdatetable)[datepos].date = lastdate;
+           datepos++;
+         }
+         posa = byte_chr(authline.s,authline.len,';');
+         if (authline.len > posa + HASHLEN + 1 && authline.s[pos+1] != ' ') {
+                                       /* old: "; auth", new: ";hash auth" */
+           auth = authline.s + posa + 1;
+           authlen = authline.len - posa - 1;
+         } else {
+           auth = dummyind.s;
+           authlen = dummyind.len;
+         }
+       }
+                       /* allright! Same procedure, but for author */
+        for (;;) {     /* search among already known authors */
+          res = str_diffn(pautht->auth,auth,HASHLEN);
+          if (res < 0) {
+            if (pautht->higher)
+              pautht = pautht->higher;
+            else {
+              newauth(pauthnext,auth,authlen,msg,fatal);
+              pautht->higher = pauthnext;
+              pautht = pauthnext;
+              pauthnext++;
+              break;
+            }
+          } else if (res > 0) {
+            if (pautht->lower)
+              pautht = pautht->lower;
+            else {
+              newauth(pauthnext,auth,authlen,msg,fatal);
+              pautht->lower = pauthnext;
+              pautht = pauthnext;
+              pauthnext++;
+              break;
+            }
+          } else {
+            break;
+          }
+        }                      /* link from message to this author */
+        pmsgt->authnum = (unsigned int) (pautht - *pauthtable + 1);
+        pautht = *pauthtable;
+      }
+
+      psubt = *psubtable;      /* setup psubt. Done here rather than before */
+                               /* the for loop, so that we can start off    */
+                               /* the dummy node. */
+    }
+    if (fd != -1)
+      close(fd);
+    if (!locked && idx == idxlatest)
+      unlock();                        /* 'locked' refers to locked before calling */
+  }
+  psubnext->sub = (char *) 0;          /* end of table marker */
+  pauthnext->auth = (char *) 0;                /* end of table marker */
+  (*pdatetable)[datepos].msg = msg_to + 1;
+  (*pdatetable)[datepos].date = lastdate + 1;
+}
+
+
+void idx_mkthread(pmsgtable,psubtable,pauthtable,msg_from,msg_to,msg_master,
+               msg_latest,locked,fatal)
+/* Works like idx_mkthreads, except that it finds the subject for message   */
+/* msg_master, then identifies messages in the range that have the same     */
+/* subject. msgtable entries with subject 0 do not match, with '1' do match.*/
+
+msgentry **pmsgtable;          /* pointer to table of message<->subject */
+subentry **psubtable;          /* ptr to tbl of subject no, len, str char * */
+authentry **pauthtable;
+unsigned long msg_from;                /* first message in range */
+unsigned long msg_to;          /* last message in range */
+unsigned long msg_latest;      /* latest message in archive (for locking) */
+unsigned long msg_master;      /* master message for single thread, else 0*/
+int locked;                    /* if already locked */
+char *fatal;                   /* Program-specific */
+
+{
+  unsigned long idxlatest;     /* need to lock for this (last) index file */
+  unsigned long idxto;         /* index for last msg in range */
+  unsigned long idx;           /* current index file no */
+  unsigned long msg;           /* index entry's msg number */
+  unsigned long ulmrange;      /* total # of messages in range */
+  subentry *psubt;             /* points to last entry in subtable */
+  int ffound;                  /* msg subject was found in subtable */
+  int flagauth;                        /* there is author info */
+  int firstfound = 1;          /* = 1 until first message in thread found */
+  int res;                     /* comparison result */
+  char *auth;
+  unsigned int authlen;
+  authentry *pauthnext;                /* points to next entry in authtable */
+  authentry *pautht;           /* points to entry in authtable */
+  unsigned int pos;
+  int fd;                      /* index file handle */
+  int match;
+  msgentry *pmsgt;
+  register msgentry *x,*y;
+
+  if ((ulmrange = msg_to - msg_from +1) <= 0)
+    strerr_die2x(100,fatal,"Program error: bad range in idx_mkthreads");
+  if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry))))
+         die_nomem(fatal);
+  y = *pmsgtable;
+  x = y + ulmrange;
+  while (--x >= y) {
+    x->subnum = 0;
+    x->authnum = 0;
+    x->date = 0;
+  }
+
+  if (!(*psubtable = (subentry *) alloc(2 * sizeof(subentry))))
+          die_nomem(fatal);
+
+  if (!(*pauthtable = (authentry *) alloc((ulmrange + 1) * sizeof(authentry))))
+          die_nomem(fatal);
+
+  pauthnext = *pauthtable;
+  pautht = &adummy;
+  init_dummy();
+  pautht->auth = "                     ";
+  pautht->authlen = 21;
+  pautht->higher = (authentry *) 0;
+  pautht->lower = (authentry *) 0;
+  idxlatest = msg_latest / 100;
+  idxto = msg_to / 100;
+  idx = msg_master / 100;      /* index for master subject */
+
+                               /* Get master subject */
+  if (!stralloc_copys(&line,"archive/")) die_nomem(fatal);
+  if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal);
+  if (!stralloc_cats(&line,"/index")) die_nomem(fatal);
+  if (!stralloc_0(&line)) die_nomem(fatal);
+  ffound = 0;
+  if (!locked && idx == idxlatest)
+    lockup(fatal);
+  fd = open_read(line.s);
+  psubt = *psubtable;
+  if (fd == -1) {
+    if (errno != error_noent)
+      strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    else
+      strerr_die2x(111,fatal,ERR_NOINDEX);     /* temp - admin can fix! */
+  } else {
+    substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf));
+    for(;;) {
+      if (getln(&ssindex,&line,&match,'\n') == -1)
+          strerr_die3sys(111,fatal,ERR_OPEN,"index: ");
+      if (!match)
+        break;
+      pos=scan_ulong(line.s,&msg);
+      if (line.s[pos++] == ':') {       /* marker for author info */
+        pos++;
+        flagauth = 1;
+      } else
+        flagauth = 0;
+      if (msg == msg_master) {
+        newsub(psubt,line.s+pos,line.len-pos,msg,fatal);
+                                       /* need to update msg later! */
+        ffound = 1;
+        break;
+      }
+      if (flagauth) {                  /* skip author line */
+        if (getln(&ssindex,&line,&match,'\n') == -1)
+          strerr_die3sys(111,fatal,ERR_OPEN,"index: ");
+      if (!match)
+        break;
+      }
+    }
+    close(fd);
+  }
+  if (!locked && idx == idxlatest)
+    unlock();
+  if (!ffound)
+      strerr_die2x(100,fatal,ERR_NOINDEX);
+  for (idx = msg_from / 100; idx <= idxto; idx++) {
+               /* make index file name */
+    if (!stralloc_copys(&line,"archive/")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal);
+    if (!stralloc_cats(&line,"/index")) die_nomem(fatal);
+    if (!stralloc_0(&line)) die_nomem(fatal);
+    if (!locked && idx == idxlatest)
+      lockup(fatal);
+    fd = open_read(line.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    } else {
+      substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf));
+      for(;;) {
+        if (getln(&ssindex,&line,&match,'\n') == -1)
+          strerr_die3sys(111,fatal,ERR_READ,"index: ");
+        if (!match)
+          break;
+        pos=scan_ulong(line.s,&msg);
+        if (line.s[pos++] == ':') {
+          pos++;
+          flagauth = 1;
+          if (getln(&ssindex,&authline,&match,'\n') == -1)
+            strerr_die3sys(111,fatal,ERR_READ,"index: ");
+          if (!match)
+            break;
+        } else
+          flagauth = 0;
+        if (msg < msg_from)    /* Nothing before start of range */
+          continue;
+        if (msg > msg_to)      /* Don't do anything after range */
+          break;
+        if (!str_diffn(psubt->sub,line.s+pos,HASHLEN)) {
+          pmsgt = *pmsgtable + msg - msg_from;
+          if (firstfound) {    /* update to first message with this subj */
+            psubt->firstmsg = msg;
+            firstfound = 0;
+          }
+         psubt->lastmsg = msg;
+          pmsgt->subnum = 1;
+          if (flagauth) {
+           if (*authline.s)
+             pmsgt->date = date2yyyymm(authline.s + 1);
+            pos = byte_chr(authline.s,authline.len,';');
+           if (authline.len > pos + HASHLEN + 1 && authline.s[pos+1] != ' ') {
+                                       /* old: "; auth", new: ";hash auth" */
+             auth = authline.s + pos + 1;
+             authlen = authline.len - pos - 1;
+           } else {
+             auth = dummyind.s;
+             authlen = dummyind.len;
+           }
+           for (;;) {          /* search among already known authors */
+             res = str_diffn(pautht->auth,auth,HASHLEN);
+             if (res < 0) {
+               if (pautht->higher)
+                 pautht = pautht->higher;
+               else {
+                 newauth(pauthnext,auth,authlen,msg,fatal);
+                 pautht->higher = pauthnext;
+                 pautht = pauthnext;
+                 pauthnext++;
+                 break;
+               }
+             } else if (res > 0) {
+               if (pautht->lower)
+                 pautht = pautht->lower;
+               else {
+                 newauth(pauthnext,auth,authlen,msg,fatal);
+                 pautht->lower = pauthnext;
+                 pautht = pauthnext;
+                 pauthnext++;
+                 break;
+               }
+             } else {
+               break;
+             }
+           }                   /* link from message to this author */
+           pmsgt->authnum = (unsigned int) (pautht - *pauthtable + 1);
+            pautht = *pauthtable;
+         }
+
+        }
+      }
+      close(fd);
+    }
+    if (!locked && idx == idxlatest)
+      unlock();
+  }
+  ++psubt;
+  psubt->sub = (char *) 0;     /* end of table marker */
+  pauthnext->auth = (char *) 0;        /* end of table marker */
+}
+
+void idx_mklist(pmsgtable,psubtable,pauthtable,msg_from,msg_to,fatal)
+/* Like mkthreads, except that it works without a subject index. The result */
+/* is just a dummy subject and a sequential list of messages. This to allow */
+/* use of the same routines when creating digest from lists that have no    */
+/* subject index (for whatever reason). */
+msgentry **pmsgtable;          /* pointer to table of message<->subject */
+subentry **psubtable;          /* ptr to tbl of subject no, len, str char * */
+authentry **pauthtable;
+unsigned long msg_from;                /* first message in range */
+unsigned long msg_to;          /* last message in range */
+char *fatal;                   /* Program-specific */
+{
+  unsigned long ulmrange;
+  register msgentry *x,*y;
+  subentry *psubt;
+  authentry *pautht;
+
+  if ((ulmrange = msg_to - msg_from +1) <= 0)
+    strerr_die2x(111,fatal,"bad range in idx_mkthreads :");
+
+  if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry))))
+         die_nomem(fatal);
+
+  y = *pmsgtable;
+  x = y + ulmrange;
+  while (--x >= y) {
+    x->subnum = 1;
+    x->authnum = 0;
+    x->date = 0;
+  }
+
+  if (!(*psubtable = (subentry *) alloc(2 * sizeof(subentry))))
+          die_nomem(fatal);
+  psubt = *psubtable;
+  newsub(psubt,dummyind.s,dummyind.len,msg_from,fatal);
+  psubt->lastmsg = msg_to;
+  ++psubt;
+  psubt->sub = (char *) 0;
+  if (!(*pauthtable = (authentry *) alloc(sizeof(authentry))))
+          die_nomem(fatal);    /* nodata. Avoid dangling ptr. */
+  pautht = *pauthtable;
+  pautht->auth = 0;            /* tells app that there are no author data */
+  pautht->higher = (authentry *) 0;
+  pautht->lower = (authentry *) 0;
+}
+
+void idx_destroythread(msgtable,subtable,authtable)
+/* Frees space allocated by idxthread routines. This is needed only if */
+/* one does several threadings in one program run. Otherwise, exit()   */
+/* should free all allocated memory, which will be faster. */
+msgentry *msgtable; subentry *subtable; authentry *authtable;
+{
+  subentry *psubt;
+  authentry *pautht;
+
+  psubt = subtable;            /* free subjects */
+  while(psubt->sub) {
+    alloc_free(psubt->sub);
+    psubt++;
+  }
+
+  pautht = authtable;          /* free authors */
+  while(pautht->auth) {
+    alloc_free(pautht->auth);
+    pautht++;
+  }
+
+  alloc_free(subtable);                /* free subtable */
+  alloc_free(authtable);       /* free authtable */
+  alloc_free(msgtable);                /* free msgtable */
+  subtable = (subentry *) 0;   /* kill pointers */
+  authtable = (authentry *) 0;
+  msgtable = (msgentry *) 0;
+}
diff --git a/idxthread.h b/idxthread.h
new file mode 100644 (file)
index 0000000..dc7ff4d
--- /dev/null
@@ -0,0 +1,11 @@
+
+#ifndef IDXTHREAD_H
+#define IDXTHREAD_H
+
+/* threading */
+extern void idx_mkthread();
+extern void idx_mkthreads();
+extern void idx_mklist();
+extern void idx_destroythread();
+
+#endif
diff --git a/issub.c b/issub.c
deleted file mode 100644 (file)
index 81ab6ad5d390b53c6e76aeb811ccbb8b1fe16a20..0000000000000000000000000000000000000000
--- a/issub.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "stralloc.h"
-#include "getln.h"
-#include "readwrite.h"
-#include "substdio.h"
-#include "open.h"
-#include "byte.h"
-#include "case.h"
-#include "lock.h"
-#include "error.h"
-#include "issub.h"
-#include "uint32.h"
-
-static stralloc addr = {0};
-static stralloc line = {0};
-static stralloc fn = {0};
-static int fd;
-static substdio ss;
-static char ssbuf[256];
-
-static int doit(userhost)
-char *userhost;
-{
-  int j;
-  uint32 h;
-  char ch;
-  int match;
-
-  if (!stralloc_copys(&addr,"T")) return -2;
-  if (!stralloc_cats(&addr,userhost)) return -2;
-
-  j = byte_rchr(addr.s,addr.len,'@');
-  if (j == addr.len) return 0;
-  case_lowerb(addr.s + j + 1,addr.len - j - 1);
-
-  h = 5381;
-  for (j = 0;j < addr.len;++j)
-    h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
-  ch = 64 + (h % 53);
-
-  if (!stralloc_0(&addr)) return -2;
-
-  if (!stralloc_copys(&fn,"subscribers/")) return -2;
-  if (!stralloc_catb(&fn,&ch,1)) return -2;
-  if (!stralloc_0(&fn)) return -2;
-
-  fd = open_read(fn.s);
-  if (fd == -1) {
-    if (errno != error_noent) return -3;
-    return 0;
-  }
-  substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
-
-  for (;;) {
-    if (getln(&ss,&line,&match,'\0') == -1) { close(fd); return -3; }
-    if (!match) break;
-    if (line.len == addr.len)
-      if (!byte_diff(line.s,line.len,addr.s)) { close(fd); return 1; }
-  }
-
-  close(fd);
-  return 0;
-}
-
-struct strerr issub_err;
-
-int issub(userhost)
-char *userhost;
-{
-  int fdlock;
-  int r;
-
-  fdlock = open_append("lock");
-  if (fdlock == -1)
-    STRERR_SYS(-1,issub_err,"unable to open lock: ")
-  if (lock_ex(fdlock) == -1) {
-    close(fdlock);
-    STRERR_SYS(-1,issub_err,"unable to obtain lock: ")
-  }
-
-  r = doit(userhost);
-  close(fdlock);
-
-  if (r == -2) STRERR(-1,issub_err,"out of memory")
-  if (r == -3) STRERR_SYS3(-1,issub_err,"unable to read ",fn.s,": ")
-
-  return r;
-}
diff --git a/issub.c b/issub.c
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..8d7ce9e31472e69e1da9ff4ef9c02ca5c230303e
--- /dev/null
+++ b/issub.c
@@ -0,0 +1 @@
+sub_std/issub.c
\ No newline at end of file
diff --git a/log.c b/log.c
index 15e732e..bf3c7a3 100644 (file)
--- a/log.c
+++ b/log.c
@@ -6,14 +6,21 @@
 #include "fmt.h"
 #include "open.h"
 
 #include "fmt.h"
 #include "open.h"
 
+/* appends (not crash-proof) a line to "Log". The format is: */
+/* "timestamp event address[ comment]\n". address is free of ' ' */
+/* Unprintable chars are changed to '?'. Comment may have spaces */
+
 static substdio ss;
 static char buf[1];
 static char num[FMT_ULONG];
 static stralloc line = {0};
 static substdio ss;
 static char buf[1];
 static char num[FMT_ULONG];
 static stralloc line = {0};
+static stralloc fn = {0};
 
 
-void log(event,addr)
+void log(dir,event,addr,comment)
+char *dir;
 char *event;
 char *addr;
 char *event;
 char *addr;
+char *comment;
 {
   char ch;
   int fd;
 {
   char ch;
   int fd;
@@ -26,9 +33,22 @@ char *addr;
     if ((ch < 33) || (ch > 126)) ch = '?';
     if (!stralloc_append(&line,&ch)) return;
   }
     if ((ch < 33) || (ch > 126)) ch = '?';
     if (!stralloc_append(&line,&ch)) return;
   }
+  if (comment && *comment) {
+    if (!stralloc_cats(&line," ")) return;
+    while (ch = *comment++) {
+      if (ch == '\t')
+        ch = ' ';
+      else 
+        if ((ch < 32) || (ch > 126)) ch = '?';
+      if (!stralloc_append(&line,&ch)) return;
+    }
+  }
   if (!stralloc_cats(&line,"\n")) return;
 
   if (!stralloc_cats(&line,"\n")) return;
 
-  fd = open_append("Log");
+  if (!stralloc_copys(&fn,dir)) return;
+  if (!stralloc_cats(&fn,"/Log")) return;
+  if (!stralloc_0(&fn)) return;
+  fd = open_append(fn.s);
   if (fd == -1) return;
   substdio_fdbuf(&ss,write,fd,buf,sizeof(buf));
   substdio_putflush(&ss,line.s,line.len);
   if (fd == -1) return;
   substdio_fdbuf(&ss,write,fd,buf,sizeof(buf));
   substdio_putflush(&ss,line.s,line.len);
diff --git a/logmsg.c b/logmsg.c
new file mode 120000 (symlink)
index 0000000..e540bca
--- /dev/null
+++ b/logmsg.c
@@ -0,0 +1 @@
+sub_std/logmsg.c
\ No newline at end of file
diff --git a/makehash.c b/makehash.c
new file mode 100644 (file)
index 0000000..efa4971
--- /dev/null
@@ -0,0 +1,136 @@
+/*Id:$*/
+/*Name:$*/
+
+#include "stralloc.h"
+#include "surf.h"
+#include "uint32.h"
+#include "makehash.h"
+
+typedef struct {
+  uint32 seed[32];
+  uint32 sum[8];
+  uint32 out[8];
+  uint32 in[12];
+  int todo;
+} surfpcs;
+
+#define SURFPCS_LEN 32
+
+static void surfpcs_init(s,k)
+surfpcs *s;
+uint32 k[32];
+{
+  int i;
+  for (i = 0;i < 32;++i) s->seed[i] = k[i];
+  for (i = 0;i < 8;++i) s->sum[i] = 0;
+  for (i = 0;i < 12;++i) s->in[i] = 0;
+  s->todo = 0;
+}
+
+static uint32 littleendian[8] = {
+  50462976, 117835012, 185207048, 252579084,
+  319951120, 387323156, 454695192, 522067228
+} ;
+#define end ((unsigned char *) littleendian)
+
+#define data ((unsigned char *) s->in)
+#define outdata ((unsigned char *) s->out)
+
+static void surfpcs_addlc(s,x,n)
+       /* modified from Dan's surfpcs_add by skipping ' ' & '\t' and */
+       /* case-independence */
+surfpcs *s;
+unsigned char *x;
+unsigned int n;
+{
+  register unsigned char ch;
+  int i;
+  while (n--) {
+    ch = *x++;
+    if (ch == ' ' || ch == '\t') continue;
+    if (ch >= 'A' && ch <= 'Z')
+      data[end[s->todo++]] = ch - 'A' + 'a';
+    else
+      data[end[s->todo++]] = ch;
+    if (s->todo == 32) {
+      s->todo = 0;
+      if (!++s->in[8])
+        if (!++s->in[9])
+          if (!++s->in[10])
+            ++s->in[11];
+      surf(s->out,s->in,s->seed);
+      for (i = 0;i < 8;++i)
+       s->sum[i] += s->out[i];
+    }
+  }
+}
+
+static void surfpcs_out(s,h)
+surfpcs *s;
+unsigned char h[32];
+{
+  int i;
+  surfpcs_addlc(s,".",1);
+  while (s->todo) surfpcs_addlc(s,"",1);
+  for (i = 0;i < 8;++i) s->in[i] = s->sum[i];
+  for (;i < 12;++i) s->in[i] = 0;
+  surf(s->out,s->in,s->seed);
+  for (i = 0;i < 32;++i) h[i] = outdata[end[i]];
+}
+
+void makehash(indata,inlen,hash)
+char *indata;
+unsigned int inlen;
+char *hash;
+       /* makes hash[COOKIE=20] from stralloc *indata, ignoring case and */
+       /* SPACE/TAB */
+{
+  unsigned char h[32];
+  surfpcs s;
+  uint32 seed[32];
+  int i;
+
+  for (i = 0;i < 32;++i) seed[i] = 0;
+  surfpcs_init(&s,seed);
+  surfpcs_addlc(&s,indata,inlen);
+  surfpcs_out(&s,h);
+  for (i = 0;i < 20;++i)
+    hash[i] = 'a' + (h[i] & 15);
+}
+
+static stralloc dummy = {0};
+
+void mkauthhash(s,len,h)
+char *s; unsigned int len; char *h;
+/* This is a string that should be the same for all messages from a given   */
+/* author. Doesn't have to be the real rfc822 address. We look for a '@'    */
+/* and grab everything up to the next '>', ' ', or ';'. We go back the same */
+/* way, then take everything up to the '@' or the first '-'. The latter     */
+/* avoids problems with posters that band their addresses.                  */
+{
+  unsigned int i,j,k,l;
+  register char ch;
+
+  j = k = l = 0;
+  i = byte_rchr(s,len,'@');
+  if (i < len) {               /* if not then i=sa->len, j=k=l=0 */
+    j = i;
+    while (++j < len) {                /* if not found, then j=sa->len */
+      ch = s[j];
+      if (ch == '>' || ch == ' ' || ch == ';') break;
+    }
+    k = i;
+    while (k > 0) {            /* k <= i */
+      ch = s[--k];
+      if (ch == '<' || ch == ' ' || ch == ';') break;
+    }
+    l = k;                     /* k <= l <= i; */
+    while (l < i && s[l] != '-') ++l;
+    if (!stralloc_copyb(&dummy,s + k, l - k)) die_nomem();
+    if (!stralloc_catb(&dummy,s + i, j - i)) die_nomem();
+    makehash(dummy.s,dummy.len,h);
+  } else                       /* use entire line if no '@' found */
+    makehash(s,len,h);
+}
+
+
diff --git a/makehash.h b/makehash.h
new file mode 100644 (file)
index 0000000..2d947e1
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef MAKEHASH_H
+#define MAKEHASH_H
+
+#define HASHLEN 20
+
+extern void makehash();
+extern void mkauthhash();
+
+#endif
+
diff --git a/mime.h b/mime.h
new file mode 100644 (file)
index 0000000..27626a0
--- /dev/null
+++ b/mime.h
@@ -0,0 +1,81 @@
+#ifndef MIME_H
+#define MIME_H
+
+#include "stralloc.h"
+
+extern void decodeQ();
+extern void decodeB();
+extern void encodeQ();
+extern void encodeB();
+extern void decodeHDR();
+extern void concatHDR();
+extern int unfoldHDR();
+
+#ifdef WITH_PROTO
+extern unsigned int author_name(char **,char *,unsigned int);
+#else
+extern unsigned int author_name();
+#endif
+
+/* Characters */
+#define ESC 0x1B
+#define SI 0x0F
+#define SO 0x0E
+/* iso-2022-jp back-to-ascii seq */
+#define TOASCII "\x1B(B"
+/* to JP. Last char [B|@] must be added */
+#define TOJP "\x1B$"
+
+/* iso-2022 SI sequence as string */
+#define TOSI "\x0F"
+/* SI \n SO */
+#define SI_LF_SO "\x0F\n\x0E"
+
+/* in these bit 0 determines the number of bytes (1 or 2) in ss2/ss3 codes */
+/* it is 2 for CN,1 for JP, and they are not used for KR  bit 3 for        */
+/* iso-2022 */
+#define CS_2022_MASK 0x08
+#define CS_2022_JP 0x08
+#define CS_2022_KR 0xA0
+#define CS_NONE 0
+#define CS_BAD 0xffff
+
+#define CS_2022_CN 0x09
+/* Other Chinese ones. bit 7 set means MSB of 2-byte seq. No ss2/ss3 consid*/
+#define CS_CN 0x10
+
+#define MIME_NONE 0
+#define MIME_APPLICATION_OCTETSTREAM 1
+#define MIME_MULTI 0x80
+#define MIME_MULTI_ALTERNATIVE 0x81
+#define MIME_MULTI_MIXED 0x82
+#define MIME_MULTI_DIGEST 0x83
+#define MIME_MULTI_SIGNED 0x84
+
+#define MIME_TEXT 0x40
+#define MIME_TEXT_PLAIN 0x41
+#define MIME_TEXT_HTML 0x42
+#define MIME_TEXT_ENRICHED 0x43
+#define MIME_TEXT_VCARD 0x44
+
+#define MIME_MESSAGE 0x20
+#define MIME_MESSAGE_RFC822 0x21
+
+#define CTENC_NONE 0
+#define CTENC_QP 1
+#define CTENC_BASE64 2
+
+/* this is a linked list of mime type info. */
+typedef struct {
+       int level;
+       unsigned int mimetype;
+       unsigned int ctenc;
+       unsigned int cs;                /* charset flag - expand later */
+       void *previous;
+       void *next;
+       stralloc boundary;
+       stralloc charset;
+       stralloc ctype;
+} mime_info;
+
+#endif
diff --git a/opensql.c b/opensql.c
new file mode 120000 (symlink)
index 0000000..5a27e82
--- /dev/null
+++ b/opensql.c
@@ -0,0 +1 @@
+sub_std/opensql.c
\ No newline at end of file
diff --git a/putsubs.c b/putsubs.c
new file mode 120000 (symlink)
index 0000000..79ffb49
--- /dev/null
+++ b/putsubs.c
@@ -0,0 +1 @@
+sub_std/putsubs.c
\ No newline at end of file
diff --git a/qmail-qmqpc.tar.gz b/qmail-qmqpc.tar.gz
new file mode 100644 (file)
index 0000000..4d70ee1
Binary files /dev/null and b/qmail-qmqpc.tar.gz differ
diff --git a/qmail-verh.tar.gz b/qmail-verh.tar.gz
new file mode 100644 (file)
index 0000000..8c8196b
Binary files /dev/null and b/qmail-verh.tar.gz differ
diff --git a/qmail.c b/qmail.c
index 7484331..1ee257b 100644 (file)
--- a/qmail.c
+++ b/qmail.c
@@ -6,18 +6,25 @@
 #include "fd.h"
 #include "qmail.h"
 #include "auto_qmail.h"
 #include "fd.h"
 #include "qmail.h"
 #include "auto_qmail.h"
+#include "alloc.h"
+#include "stralloc.h"
+#include "idx.h"
 
 
-static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
+static char *binqqargs[2] = { PROG_QMAIL_QUEUE, 0 } ;
 
 
-int qmail_open(qq)
+int qmail_open(qq,sa)
 struct qmail *qq;
 struct qmail *qq;
+stralloc *sa;
 {
   int pim[2];
   int pie[2];
 {
   int pim[2];
   int pie[2];
+  unsigned i,j;
+  char **cpp;
 
 
+  qq->msgbytes = 0L;
   if (pipe(pim) == -1) return -1;
   if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
   if (pipe(pim) == -1) return -1;
   if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
+
   switch(qq->pid = vfork()) {
     case -1:
       close(pim[0]); close(pim[1]);
   switch(qq->pid = vfork()) {
     case -1:
       close(pim[0]); close(pim[1]);
@@ -28,8 +35,24 @@ struct qmail *qq;
       close(pie[1]);
       if (fd_move(0,pim[0]) == -1) _exit(120);
       if (fd_move(1,pie[0]) == -1) _exit(120);
       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);
-      execv(*binqqargs,binqqargs);
+      if (chdir(auto_qmail) == -1) _exit(61);
+      j = 2;                           /* empty sa - qmqpc c control args */
+      if (sa) {                                /* count args */
+       for (i = 0; i + 1 < sa->len; i++) {
+         if (sa->s[i] == '\0') j++;
+       }                               /* make space */
+       if (!(cpp = (char **) alloc(j * sizeof (char *)))) _exit(51);
+       cpp[0] = PROG_QMAIL_QMQPC;
+       cpp[j - 1] = (char *) 0;
+       if (sa->len) cpp[1] = sa->s;
+       j = 2;
+       for (i = 0; i + 1 < sa->len; i++) {
+         if (sa->s[i] == '\0')
+           cpp[j++] = sa->s + i + 1;   /* build args */
+       }
+       execv(*cpp,cpp);
+      } else
+       execv(*binqqargs,binqqargs);
       _exit(120);
   }
 
       _exit(120);
   }
 
@@ -53,11 +76,17 @@ void qmail_fail(qq) struct qmail *qq;
 void qmail_put(qq,s,len) struct qmail *qq; char *s; int len;
 {
   if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1;
 void qmail_put(qq,s,len) struct qmail *qq; char *s; int len;
 {
   if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1;
+  qq->msgbytes += len;
 }
 
 void qmail_puts(qq,s) struct qmail *qq; char *s;
 {
 }
 
 void qmail_puts(qq,s) struct qmail *qq; char *s;
 {
-  if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1;
+  register int len;
+  if (!qq->flagerr) {
+    len = str_len(s);
+    if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1;
+  }
+  qq->msgbytes += len;
 }
 
 void qmail_from(qq,s) struct qmail *qq; char *s;
 }
 
 void qmail_from(qq,s) struct qmail *qq; char *s;
@@ -77,27 +106,49 @@ void qmail_to(qq,s) struct qmail *qq; char *s;
   qmail_put(qq,"",1);
 }
 
   qmail_put(qq,"",1);
 }
 
-int qmail_close(qq)
+char *qmail_close(qq)
 struct qmail *qq;
 {
   int wstat;
 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);
 
 
   qmail_put(qq,"",1);
   if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
   close(qq->fde);
 
-  if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID;
-  if (wait_crashed(wstat)) return QMAIL_CRASHED;
-  switch(wait_exitcode(wstat)) {
-    case 0: if (qq->flagerr) return QMAIL_BUG; return 0;
-    case 112: return QMAIL_USAGE;
-    case 115: return QMAIL_TOOLONG;
-    case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS;
-    case 121: return QMAIL_READ;
-    case 122: return QMAIL_WRITE;
-    case 123: return QMAIL_NOMEM;
-    case 124: return QMAIL_TIMEOUT;
-    case 120: return QMAIL_EXECSOFT;
-    default: /* 101 or 102 */ return QMAIL_BUG;
+  if (wait_pid(&wstat,qq->pid) != qq->pid)
+    return "Zqq waitpid surprise (#4.3.0)";
+  if (wait_crashed(wstat))
+    return "Zqq crashed (#4.3.0)";
+  exitcode = wait_exitcode(wstat);
+
+  switch(exitcode) {
+    case 115: /* compatibility */
+    case 11: return "Denvelope address too long for qq (#5.1.3)";
+    case 31: return "Dmail server permanently rejected message (#5.3.0)";
+    case 51: return "Zqq out of memory (#4.3.0)";
+    case 52: return "Zqq timeout (#4.3.0)";
+    case 53: return "Zqq write error or disk full (#4.3.0)";
+    case 0: if (!qq->flagerr) return ""; /* fall through */
+    case 54: return "Zqq read error (#4.3.0)";
+    case 55: return "Zqq unable to read configuration (#4.3.0)";
+    case 56: return "Zqq trouble making network connection (#4.3.0)";
+    case 61: return "Zqq trouble in home directory (#4.3.0)";
+    case 63:
+    case 64:
+    case 65:
+    case 66:
+    case 62: return "Zqq trouble creating files in queue (#4.3.0)";
+    case 71: return "Zmail server temporarily rejected message (#4.3.0)";
+    case 72: return "Zconnection to mail server timed out (#4.4.1)";
+    case 73: return "Zconnection to mail server rejected (#4.4.1)";
+    case 74: return "Zcommunication with mail server failed (#4.4.2)";
+    case 91: /* fall through */
+    case 81: return "Zqq internal bug (#4.3.0)";
+    case 120: return "Zunable to exec qq (#4.3.0)";
+    default:
+      if ((exitcode >= 11) && (exitcode <= 40))
+       return "Dqq permanent problem (#5.3.0)";
+      return "Zqq temporary problem (#4.3.0)";
   }
 }
   }
 }
diff --git a/qmail.h b/qmail.h
index 7864ea1..8906ab0 100644 (file)
--- a/qmail.h
+++ b/qmail.h
@@ -2,35 +2,39 @@
 #define QMAIL_H
 
 #include "substdio.h"
 #define QMAIL_H
 
 #include "substdio.h"
+#include "stralloc.h"
 
 struct qmail {
   int flagerr;
   unsigned long pid;
 
 struct qmail {
   int flagerr;
   unsigned long pid;
+  unsigned long msgbytes;
   int fdm;
   int fde;
   substdio ss;
   char buf[1024];
 } ;
 
   int fdm;
   int fde;
   substdio ss;
   char buf[1024];
 } ;
 
+#ifdef WITH_PROTO
+
+extern int qmail_open(struct qmail *, stralloc *);
+extern void qmail_put(struct qmail *, char *, int);
+extern void qmail_puts(struct qmail *, char *);
+extern void qmail_from(struct qmail *, char *);
+extern void qmail_to(struct qmail *, char *);
+extern void qmail_fail(struct qmail *);
+extern char *qmail_close(struct qmail *);
+extern unsigned long qmail_qp(struct qmail *);
+
+#else
+
 extern int qmail_open();
 extern void qmail_put();
 extern void qmail_puts();
 extern void qmail_from();
 extern void qmail_to();
 extern void qmail_fail();
 extern int qmail_open();
 extern void qmail_put();
 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();
 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
 
 #endif
 
 #endif
diff --git a/searchlog.c b/searchlog.c
new file mode 120000 (symlink)
index 0000000..c6f1952
--- /dev/null
@@ -0,0 +1 @@
+sub_std/searchlog.c
\ No newline at end of file
diff --git a/sub_mysql/README b/sub_mysql/README
new file mode 100644 (file)
index 0000000..28d028e
--- /dev/null
@@ -0,0 +1,153 @@
+$Id: README,v 1.3 1999/02/20 20:05:19 lindberg Exp $
+$Name: ezmlm-idx-040 $
+INFORMATION ON BUILDING/USING EZMLM WITH MYSQL SUPPORT
+
+(c) 1999,      Frederik Lindberg,
+               lindberg@id.wustl.edu
+               You may use under GPL.
+
+For information on MySQL, see http://www.tcx.se.
+
+Most of this information is available in FAQ.idx.
+
+If you are interested in contributing/testing a subscriber db interface
+for another SQL server, please see sub_std/README and the routines here,
+and contact lindberg@id.wustl.edu (it may already be in process). See end
+of this file for other ways to contribute.
+
+conf-mysql must be edited to reflect your system. On many systems, you
+also need to include ``-lsocket'', as well as change the paths to the
+/usr/local equivalents. For the i386.rpm-based systems, you need at
+least MySQL-devel to build the files. Look at your mysql docs for more info.
+
+TABLES USED FOR (My)SQL SUPPORT
+
+The basic philosophy is that the database can be on any host (if you use
+SENDER restrictions, connectivity to the main host is more important than
+to the sublists), and you choose the database and "table root" names. The
+default database is ``ezmlm'' and the default table root is ``list''. Each
+list has a separate table root. Any number of lists can share a database.
+
+The main list address table is named with the table root only, others have
+that name with various suffixes. In the following ``list'' is used as the
+table root.
+
+ADDRESS TABLES
+list           subscriber addresses
+list_slog      subscriber address log
+list_allow     subscriber aliases for posts on SENDER checked lists.
+list_allow_slog        subscriber log for list_allow
+list_deny      blacklisted addresses for posts on SENDER checked lists.
+list_deny_slog log for list_deny.
+list_mod       moderator addresses
+list_mod_slog  log for list_mod
+list_digest    subscriber log for digest list.
+list_digest_slog       log for list_digest
+
+MESSAGE LOGGING TABLES
+list_cookie    message cookie table for main list
+list_mlog      message logging table for main list
+list_digest_cookie     message cookie table for digest list
+list_digest_mlog       message logging table for digest list
+
+SUBLIST SPLIT TABLES
+list_name      sublist split table for main list
+list_digest_name       sublist split table for digest list.
+
+
+ezmlm-mktab(1) is a script that outputs the table definintions. Look at
+the output for a detailed field description.
+
+The address tables contain (address,domain,hash,h,num). For normal
+lists only the address field is used. For main->sublist clusters, the other
+fields are used for load splitting. The domain is the first up to 3 characters
+of the last part of the domain name. The hash is a address hash [0-52] differnt
+from the one used by ezmlm for splitting within DIR/subscribers. When using
+the address field as a primary key, the size of the index was unreasonable.
+Therefore, ``num'' is used as a dummy primary key, and ``h'' (a 32 bit hash
+of the address) is used as an index. This markedly speeds up (un)sub with
+large (>30,000 rows) subscriber tables.
+
+The *_slog tables contain the same info as DIR/Log, i.e. address, timestamp,
+entry-type, entry-direction, and fromline. The entry-type is the first letter
+of the type of entry (probe, manual, `` '' for normal), entry-direction is
+``+'' for addition, ``-'' for removal. Fromline is the From: header contents
+taken from the subscribe confirm message or from ezmlm-sub (if used with -n).
+It is blank for all address removals, and may be blank also for additions. It
+is used by the list-log.xx command. It is trivial to JOIN this table with the
+address table to get e.g. subsciber names, subscription dates, etc. These
+tables also have the 32-bit hash ``h'' as an index. Joins should be done on
+``h'' as well as ``address'' for better performance.
+
+The *_cookie tables contain message number, timestamp, and cookie. For each
+message a pseudo-random cookie is generated that is ``impossible'' to guess
+beforehand. For lists with sublists, this is used as basic authentication,
+i.e. the sublist will refuse to process a message that doesn't contain the
+correct cookie or that the sublist has already successfully processed.
+
+The *_mlog tables contain log entries from main and sublists. These are
+timestamp, listno, done. Listno is the lowest listnumber for an active list
+entry with the name of this sublist as looked up in the *_name table. Done
+is -1 for bounce, 0 for arrived, 1 for finished processing, and 2 for receipt
+received. The routines are set up so that only the first attempt for each
+combination (listno,code) is logged.
+
+The *_name tables contain listno,name,domain,hash_lo,hash_hi,msgnum_lo,
+msgnum_hi,notuse. Listno is auto_increment and unique. Name is the name of the
+sublist. domain is the last up to 3 characters of the top domain name for
+addresses served by this list (default = ''). It is is '', the list servers
+all_domains_that_are_not_served_by_another list (in addition to domain '').
+Of the addresses that match the domain criterion, the list serves the subset
+with hash between hash_lo and hash_hi (defaults 0, 52). Any entry is ingnored if
+notuse != 0 OR the current message number is not between msgnum_lo and
+msgnum_hi.
+
+For normal lists that are not distributed (i.e. they are a single list),
+entries in the *_name tables are not needed and logging is not very
+relevant.
+
+For most lists, the only addresses that are stored in the SQL database are
+the subscribers of list and digest, and the ``allow'' aliases. It is NOT
+normally advisable to store moderator addresses there, since they are
+needed only at the main list and secrecy is more important. ``Deny'' addresses
+are few and again only needed at the main list. ``Allow'' are put in the
+SQL database when using the default ezmlmrc file only to make all relevant
+addresses manipulatable via the SQL server. The other tables are created, in
+case they are  wanted (the cost for having them as empty table is zero). The
+basedir/sql file is the decision point. If it exists, an SQL table is used;
+if not a local ezmlm db is used.
+
+CONTRIBUTIONS REQESTED
+
+I would be very grateful if there are users out there willing to do any of
+the following and contribute it to this package. Please check with me first
+(lindberg@id.wustl.edu), as the project may already be in progress/done.
+
+1. Interfaces for other SQL servers. Oracle, SyBase, ...
+
+2. A GUI admin utility to add/remove/manipulate the sublist split, essentially
+   by modifying list_[digest_]name in a safe way. Ideally WWW if it can be
+   done securely. If you use some standard interface (JDBC/DBD) it would be
+   useful also with other SQL severs. This could even be an Access program
+   using ODBC, although writing it for a platform running qmail/ezmlm makes
+   most sense.
+
+3. a WWW GUI that allows users to subscribe/unsubscribe in a safe way. A random
+   password would be created the first time and stored in a new address->pw
+   table and mailed to the subscriber address. With that password, the user
+   would be able to [un]subscribe to lists, edit the name (for compatibility
+   implemented by adding a subscribe line to list_[digest]slog). Add/remove
+   aliases. Ideally, it should also allow searching by subscriber name. This
+   would search *_slog.fromline. If less that 'x' alternatives are found, the
+   user would be presented with names (not addresses), allowing the user to
+   cause the subscription name and password to be sent to the respective
+   subscription address. With that info, the subscriber can then unsubscribe,
+   even if s/he has forgotten the subscription address. It is complicated
+   slightly by the fact that ``fromline'' is the crude line and needs to be
+   rfc822 parsed. Again, use of a standard interface is encouraged to make it
+   compatible also with other SQL servers.
+
+The aim of all this is to make it easy to use ezmlm to run very large lists,
+easy to set up sites that handle subscriber interaction, archive access, etc,
+and hopefully easier to integrate many ezmlm as done by some WWW sites today.
+
diff --git a/sub_mysql/checktag.c b/sub_mysql/checktag.c
new file mode 100644 (file)
index 0000000..05de3ce
--- /dev/null
@@ -0,0 +1,104 @@
+/*$Id: checktag.c,v 1.11 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "cookie.h"
+#include "makehash.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <mysql.h>
+
+static stralloc key = {0};
+static stralloc line = {0};
+static stralloc quoted = {0};
+static char strnum[FMT_ULONG];
+static char newcookie[COOKIE];
+
+char *checktag (dir,num,listno,action,seed,hash)
+/* reads dir/sql. If not present, returns success (NULL). If dir/sql is    */
+/* present, checks hash against the cookie table. If match, returns success*/
+/* (NULL), else returns "". If error, returns error string. */
+
+char *dir;                             /* the db base dir */
+unsigned long num;                     /* message number */
+unsigned long listno;                  /* bottom of range => slave */
+char *action;
+char *seed;                            /* cookie base */
+char *hash;                            /* cookie */
+{
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *table = (char *) 0;
+  char *r;
+
+  if ((r = opensql(dir,&table))) {
+    if (*r) return r;
+    if (!seed) return (char *) 0;              /* no data - accept */
+
+    strnum[fmt_ulong(strnum,num)] = '\0';      /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+      case -1:
+       return ERR_READ_KEY;
+      case 0:
+       return ERR_NOEXIST_KEY;
+    }
+
+    cookie(newcookie,key.s,key.len,strnum,seed,action);
+    if (byte_diff(hash,COOKIE,newcookie)) return "";
+    else return (char *) 0;
+
+  } else {
+
+/* SELECT msgnum FROM table_cookie WHERE msgnum=num and cookie='hash' */
+/* succeeds only is everything correct. 'hash' is quoted since it is  */
+/*  potentially hostile. */
+    if (listno) {                      /* only for slaves */
+      if (!stralloc_copys(&line,"SELECT listno FROM ")) return ERR_NOMEM;
+      if (!stralloc_cats(&line,table)) return ERR_NOMEM;
+      if (!stralloc_cats(&line,"_mlog WHERE listno=")) return ERR_NOMEM;
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,listno)))
+       return ERR_NOMEM;
+      if (!stralloc_cats(&line," AND msgnum=")) return ERR_NOMEM;
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+      if (!stralloc_cats(&line," AND done > 3")) return ERR_NOMEM;
+      if (mysql_real_query((MYSQL *) psql,line.s,line.len) != 0)
+       return mysql_error((MYSQL *) psql);                     /* query */
+      if (!(result = mysql_use_result((MYSQL *) psql)))                /* use result */
+       return mysql_error((MYSQL *) psql);
+      if ((row = mysql_fetch_row(result)))
+       return "";                                      /*already done */
+      else                                             /* no result */
+        if (!mysql_eof(result))
+         return mysql_error((MYSQL *) psql);
+      mysql_free_result(result);                       /* free res */
+    }
+
+    if (!stralloc_copys(&line,"SELECT msgnum FROM ")) return ERR_NOMEM;
+    if (!stralloc_cats(&line,table)) return ERR_NOMEM;
+    if (!stralloc_cats(&line,"_cookie WHERE msgnum=")) return ERR_NOMEM;
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+    if (!stralloc_cats(&line," and cookie='")) return ERR_NOMEM;
+    if (!stralloc_ready(&quoted,COOKIE * 2 + 1)) return ERR_NOMEM;
+    quoted.len = mysql_escape_string(quoted.s,hash,COOKIE);
+    if (!stralloc_cat(&line,&quoted)) return ERR_NOMEM;
+    if (!stralloc_cats(&line,"'")) return ERR_NOMEM;
+
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len) != 0) /* select */
+       return mysql_error((MYSQL *) psql);
+    if (!(result = mysql_use_result((MYSQL *) psql)))
+       return mysql_error((MYSQL *) psql);
+    if (!mysql_fetch_row(result)) {
+    if (!mysql_eof(result))            /* some error occurred */
+       return mysql_error((MYSQL *) psql);
+      mysql_free_result(result);       /* eof => query ok, but null result*/
+      return "";                       /* not parent => perm error */
+    }
+    mysql_free_result(result);         /* success! cookie matches */
+    if (listno)
+      (void) logmsg(dir,num,listno,0L,3);      /* non-ess mysql logging */
+    return (char *)0;
+  }
+}
diff --git a/sub_mysql/conf-sqlcc b/sub_mysql/conf-sqlcc
new file mode 100644 (file)
index 0000000..45507d5
--- /dev/null
@@ -0,0 +1,4 @@
+-I/usr/include/mysql
+
+# the top line will be used when compiling. Edit to reflect your mysql
+# installation. This is for a the MySQL-3.22.10.i386 rpm.
diff --git a/sub_mysql/conf-sqlld b/sub_mysql/conf-sqlld
new file mode 100644 (file)
index 0000000..0e0a69f
--- /dev/null
@@ -0,0 +1,4 @@
+-L/usr/lib/mysql -lmysqlclient -lnsl -lm
+
+# the top line will be used when linking. Edit to reflect your mysql
+# installation. This is for a the MySQL-3.22.10.i386 rpm.
diff --git a/sub_mysql/ezmlm-mktab b/sub_mysql/ezmlm-mktab
new file mode 100755 (executable)
index 0000000..8fea02b
--- /dev/null
@@ -0,0 +1,200 @@
+#!/bin/sh
+# Simple script to generate input to mysql to generate tables for a list
+# All tables are created, even though it is not advisable to put e.g. the
+# moderator table in the SQL database nor is it very useful to put the
+# blacklist/deny table there. The subscriber lists for the main and digest
+# lists should be there, and it's reasonable to put the "extra" list there
+# if used.
+ECHO='echo'
+CAT='cat'
+CUT='cut'
+
+
+CREATE='y'
+DROP='n'
+TROOT='list'
+# size of std cookie
+COOKIE='20'
+
+                                       # not everyone has getopt :-(
+while [ "`${ECHO} "$1" | ${CUT} -c1`" = "-" ]; do
+       case "$1" in
+               -c)     CREATE='y'; shift;;
+               -C)     CREATE='n'; shift;;
+               -d)     DROP='y'; shift;;
+               -D)     DROP='n'; shift;;
+               -cd|-dc)        CREATE='y'; DROP='y'; shift;;
+               -cD|-Dc)        CREATE='y'; DROP='n'; shift;;
+               -Cd|-dC)        CREATE='n'; DROP='y'; shift;;
+               -CD|-DC)        CREATE='n'; DROP='n'; shift;;
+               --)     shift; break;;
+               *)      echo "usage: emzlm-mktab [-cCdD] table_toot"; exit 100;;
+       esac
+done
+
+[ ! -z "$1" ] && TROOT="$1";
+
+
+if [ "$DROP" = "y" ]; then
+  cat <<EOF
+
+/* drop old tables. This may fail unless you use mysql -f */
+/* Usage: */
+/* ezmlm-mktab [-d] troot | mysql -hhost -uuserid -ppw datab -f */
+
+DROP TABLE ${TROOT};
+DROP TABLE ${TROOT}_slog;
+DROP TABLE ${TROOT}_digest;
+DROP TABLE ${TROOT}_digest_slog;
+DROP TABLE ${TROOT}_mod;
+DROP TABLE ${TROOT}_mod_slog;
+DROP TABLE ${TROOT}_allow;
+DROP TABLE ${TROOT}_allow_slog;
+DROP TABLE ${TROOT}_deny;
+DROP TABLE ${TROOT}_deny_slog;
+/* eliminated name table - no need */
+DROP TABLE ${TROOT}_cookie;
+DROP TABLE ${TROOT}_mlog;
+DROP TABLE ${TROOT}_digest_cookie;
+DROP TABLE ${TROOT}_digest_mlog;
+
+EOF
+
+fi
+
+if [ $CREATE = 'y' ]; then
+  cat << EOF
+
+/* Main address table */
+/* Need varchar. Domain = 3 chars => fixed length, as opposed to varchar */
+/* Always select on domain and hash, so that one index should do         */
+/* primary key(address) is very inefficient for MySQL. */
+/* MySQL tables do not need a primary key. Other RDBMS require one. For  */
+/* the log tables, just add an INT AUTO_INCREMENT. For the address table,*/
+/* do that or use address as a primary key. */
+
+create TABLE ${TROOT} (
+       hash            TINYINT UNSIGNED NOT NULL,
+       address         VARCHAR(255) NOT NULL,
+       INDEX h (hash),
+       INDEX a (address(12)));
+
+/* Subscription log table. No addr idx to make insertion fast, since that is */
+/* almost the only thing we do with this table */
+create TABLE ${TROOT}_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR(1) NOT NULL,
+       etype           CHAR(1) NOT NULL,       
+       INDEX (tai));
+
+/* digest list table */
+create TABLE ${TROOT}_digest (
+       hash            TINYINT UNSIGNED NOT NULL,
+       address         VARCHAR(255) NOT NULL,
+       INDEX h (hash),
+       INDEX a (address(12)));
+
+/* digest list subscription log */
+create TABLE ${TROOT}_digest_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR(1) NOT NULL,
+       etype           CHAR(1) NOT NULL,       
+       INDEX (tai));
+
+/* moderator addresses */
+create TABLE ${TROOT}_mod (
+       hash            TINYINT UNSIGNED NOT NULL,
+       address         VARCHAR(255) NOT NULL,
+       INDEX h(hash),
+       INDEX a(address(12)));
+
+/* moderator subscription log */
+create TABLE ${TROOT}_mod_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR(1) NOT NULL,
+       etype           CHAR(1) NOT NULL,       
+       INDEX (tai));
+
+/* "allow" address table */
+create TABLE ${TROOT}_allow (
+       hash            TINYINT UNSIGNED NOT NULL,
+       address         VARCHAR(255) NOT NULL,
+       INDEX h(hash),
+       INDEX a(address(12)));
+
+/* extra address table log */
+create TABLE ${TROOT}_allow_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR(1) NOT NULL,
+       etype           CHAR(1) NOT NULL,       
+       INDEX (tai));
+
+/* blacklist address table */
+create TABLE ${TROOT}_deny (
+       hash            TINYINT UNSIGNED NOT NULL,
+       address         VARCHAR(255) NOT NULL,
+       INDEX h(hash),
+       INDEX a(address(12)));
+
+/* blacklist subscription log */
+create TABLE ${TROOT}_deny_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR(1) NOT NULL,
+       etype           CHAR(1) NOT NULL,       
+       INDEX (tai));
+
+/* main list inserts a cookie here. Sublists check it */
+CREATE TABLE ${TROOT}_cookie (
+       msgnum          INTEGER UNSIGNED NOT NULL,
+       tai             TIMESTAMP NOT NULL,
+       cookie          CHAR($COOKIE) NOT NULL,
+       chunk           TINYINT UNSIGNED NOT NULL DEFAULT 0,
+       bodysize        INTEGER UNSIGNED NOT NULL DEFAULT 0,
+       PRIMARY KEY (msgnum));
+
+/* main and sublist log here when the message is done */
+/* done=0 for arrived, done=4 for sent, 5 for receit. */
+/* tai reflects last change */
+CREATE TABLE ${TROOT}_mlog (
+       msgnum          INTEGER UNSIGNED NOT NULL,
+       listno          INTEGER UNSIGNED NOT NULL,
+       tai             TIMESTAMP,
+       subs            INTEGER UNSIGNED NOT NULL DEFAULT 0,
+       done            TINYINT NOT NULL DEFAULT 0,
+       PRIMARY KEY listmsg (listno,msgnum,done));
+
+/* ezmlm-get when creating a digests inserts a cookie here. Sublists check it */
+CREATE TABLE ${TROOT}_digest_cookie (
+       msgnum          INTEGER UNSIGNED NOT NULL,
+       tai             TIMESTAMP NOT NULL,
+       cookie          CHAR($COOKIE) NOT NULL,
+       chunk           TINYINT UNSIGNED NOT NULL DEFAULT 0,
+       bodysize        INTEGER UNSIGNED NOT NULL DEFAULT 0,
+       PRIMARY KEY (msgnum));
+
+/* ezmlm-get and digest sublists log here when the message is done */
+/* done=0 for arrived, done=4 for sent, 5 for receit. */
+/* tai reflects last change */
+CREATE TABLE ${TROOT}_digest_mlog (
+       msgnum          INTEGER UNSIGNED NOT NULL,
+       listno          INTEGER UNSIGNED NOT NULL,
+       tai             TIMESTAMP,
+       subs            INT UNSIGNED NOT NULL DEFAULT 0,
+       done            TINYINT NOT NULL DEFAULT 0,
+       PRIMARY KEY listmsg (listno,msgnum,done));
+
+EOF
+
+fi
+exit 0
+
diff --git a/sub_mysql/issub.c b/sub_mysql/issub.c
new file mode 100644 (file)
index 0000000..a2b760c
--- /dev/null
@@ -0,0 +1,174 @@
+/*$Id: issub.c,v 1.16 1999/12/11 03:04:19 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "strerr.h"
+#include "error.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+#include <mysql.h>
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc quoted = {0};
+static stralloc fn = {0};
+static substdio ss;
+static char ssbuf[512];
+static char szh[FMT_ULONG];
+
+char *issub(dbname,userhost,tab,fatal)
+/* Returns (char *) to match if userhost is in the subscriber database     */
+/* dbname, 0 otherwise. dbname is a base directory for a list and may NOT  */
+/* be NULL        */
+/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/
+
+char *dbname;          /* directory to basedir */
+char *userhost;
+char *tab;             /* override table name */
+char *fatal;
+
+{
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *ret;
+  char *table;
+  unsigned long *lengths;
+
+  int fd;
+  unsigned int j;
+  uint32 h,lch;
+  char ch,lcch;
+  int match;
+
+  table = tab;
+  if ((ret = opensql(dbname,&table))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local db */
+
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len) return 0;
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* totally lc version of addr */
+
+    h = 5381;
+    lch = h;                   /* make hash for both for backwards comp */
+    for (j = 0;j < addr.len;++j) {     /* (lcaddr.len == addr.len) */
+      h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+      lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+    }
+    ch = 64 + (h % 53);
+    lcch = 64 + (lch % 53);
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+        if (!match) break;
+        if (line.len == lcaddr.len)
+          if (!case_diffb(line.s,line.len,lcaddr.s))
+            { close(fd); return line.s+1; }
+      }
+
+      close(fd);
+    }
+       /* here if file not found or (file found && addr not there) */
+
+    if (ch == lcch) return 0;
+
+       /* try case sensitive hash for backwards compatibility */
+    fn.s[fn.len - 2] = ch;
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+      return 0;
+    }
+    substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+    for (;;) {
+      if (getln(&ss,&line,&match,'\0') == -1)
+        strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      if (!match) break;
+      if (line.len == addr.len)
+        if (!case_diffb(line.s,line.len,addr.s))
+          { close(fd); return line.s+1; }
+    }
+
+    close(fd);
+
+    return 0;
+  } else {                                             /* SQL version  */
+       /* SELECT address FROM list WHERE address = 'userhost' AND hash */
+       /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
+       /* even easier to defeat. Just faking sender to the list name would*/
+       /* work. Since sender checks for posts are bogus anyway, I don't */
+       /* know if it's worth the cost of the "WHERE ...". */
+
+    if (!stralloc_copys(&addr,userhost)) die_nomem(fatal);
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len) return 0;
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+
+    if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line," WHERE address = '")) die_nomem(fatal);
+    if (!stralloc_ready(&quoted,2 * addr.len + 1)) die_nomem(fatal);
+    if (!stralloc_catb(&line,quoted.s,
+       mysql_escape_string(quoted.s,userhost,addr.len))) die_nomem(fatal);
+    if (!stralloc_cats(&line,"'"))
+               die_nomem(fatal);
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len))      /* query */
+               strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    if (!(result = mysql_use_result((MYSQL *) psql)))
+               strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    row = mysql_fetch_row(result);
+    ret = (char *) 0;
+    if (!row) {                /* we need to return the actual address as other */
+                       /* dbs may accept user-*@host, but we still want */
+                       /* to make sure to send to e.g the correct moderator*/
+                       /* address. */
+      if (!mysql_eof(result))
+               strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    } else {
+      if (!(lengths = mysql_fetch_lengths(result)))
+               strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (!stralloc_copyb(&line,row[0],lengths[0])) die_nomem(fatal);
+      if (!stralloc_0(&line)) die_nomem(fatal);
+      ret = line.s;
+      while ((row = mysql_fetch_row(result))); /* maybe not necessary */
+      mysql_free_result(result);
+    }
+    return ret;
+  }
+}
diff --git a/sub_mysql/logmsg.c b/sub_mysql/logmsg.c
new file mode 100644 (file)
index 0000000..ca601e8
--- /dev/null
@@ -0,0 +1,54 @@
+/*$Id: logmsg.c,v 1.10 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+#include <mysql.h>
+#include <mysqld_error.h>
+
+static stralloc logline = {0};
+static char strnum[FMT_ULONG];
+
+char *logmsg(dir,num,listno,subs,done)
+/* creates an entry for message num and the list listno and code "done". */
+/* Returns NULL on success, "" if dir/sql was not found, and the error   */
+/* string on error.   NOTE: This routine does nothing for non-sql lists! */
+char *dir;
+unsigned long num;
+unsigned long listno;
+unsigned long subs;
+int done;
+{
+  char *table = (char *) 0;
+  char *ret;
+
+  if ((ret = opensql(dir,&table))) {
+    if (*ret)
+      return ret;
+    else
+      return (char *) 0;       /* no SQL => success */
+  }
+  if (!stralloc_copys(&logline,"INSERT INTO ")) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,table)) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,"_mlog (msgnum,listno,subs,done) VALUES ("))
+       return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno)))
+       return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,subs))) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (done < 0) {
+    done = - done;
+    if (!stralloc_append(&logline,"-")) return ERR_NOMEM;
+  }
+  if (!stralloc_catb(&logline,strnum,fmt_uint(strnum,done))) return ERR_NOMEM;
+  if (!stralloc_append(&logline,")")) return ERR_NOMEM;
+
+  if (mysql_real_query((MYSQL *) psql,logline.s,logline.len))  /* log query */
+    if (mysql_errno((MYSQL *) psql) != ER_DUP_ENTRY)   /* ignore dups */
+       return mysql_error((MYSQL *) psql);
+  return (char *) 0;
+}
diff --git a/sub_mysql/opensql.c b/sub_mysql/opensql.c
new file mode 100644 (file)
index 0000000..4b903a9
--- /dev/null
@@ -0,0 +1,112 @@
+/*$Id: opensql.c,v 1.6 1999/11/14 21:29:29 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <mysql.h>
+
+static stralloc myp = {0};
+static stralloc ers = {0};
+static stralloc fn = {0};
+static stralloc ourdb = {0};
+static char *ourtable = (char *) 0;
+
+char *opensql(dbname,table)
+/* reads the file dbname/sql, and if the file exists, parses it into the    */
+/* components. The string should be host:port:user:pw:db:table.         If  */
+/* the file does not exists, returns "". On success returns NULL. On error  */
+/* returns error string for temporary error. If table is NULL it is         */
+/* left alone. If *table is not null, it overrides the table in the sql     */
+/* file. If we already opended dbname the cached info is used, rather than  */
+/* rereading the file. Note that myp is static and all pointers point to it.*/
+char *dbname;  /* database directory */
+char **table;  /* table root_name */
+
+{
+  char *host = (char *) 0;
+  unsigned long port = 0L;
+  char *db = "ezmlm";          /* default */
+  char *user = (char *) 0;
+  char *pw = (char *) 0;
+  unsigned int j;
+  char *cp;
+
+  if (!stralloc_copys(&fn,dbname)) return ERR_NOMEM;
+  if (fn.len == ourdb.len && !str_diffn(ourdb.s,fn.s,fn.len)) {
+    if (table) {
+      if (*table) ourtable = *table;
+      else *table = ourtable;
+    }
+    return 0;
+  }
+  if (!stralloc_cats(&fn,"/sql")) return ERR_NOMEM;
+  if (!stralloc_0(&fn)) return ERR_NOMEM;
+               /* host:port:db:table:user:pw:name */
+
+  myp.len = 0;
+  switch (slurp(fn.s,&myp,128)) {
+       case -1:        if (!stralloc_copys(&ers,ERR_READ)) return ERR_NOMEM;
+                       if (!stralloc_cat(&ers,&fn)) return ERR_NOMEM;
+                       if (!stralloc_0(&ers)) return ERR_NOMEM;
+                       return ers.s;
+       case 0: return "";
+  }
+  if (!stralloc_copy(&ourdb,&fn)) return ERR_NOMEM;
+  if (!stralloc_append(&myp,"\n")) return ERR_NOMEM;
+  for (j=0; j< myp.len; ++j) {
+    if (myp.s[j] == '\n') { myp.s[j] = '\0'; break; }
+  }
+                                               /* get connection parameters */
+  if (!stralloc_0(&myp)) return ERR_NOMEM;
+  host = myp.s;
+  if (myp.s[j = str_chr(myp.s,':')]) {
+    cp = myp.s + j++;
+    *(cp++) = '\0';
+    scan_ulong(cp,&port);
+    if (myp.s[j += str_chr(myp.s+j,':')]) {
+      j++;
+      user = myp.s + j;
+      if (myp.s[j += str_chr(myp.s+j,':')]) {
+        pw = myp.s + j++;
+       *(pw++) = '\0';
+       if (myp.s[j += str_chr(myp.s+j,':')]) {
+          db = myp.s + j++;
+         *(db++) = '\0';
+         if (myp.s[j += str_chr(myp.s+j,':')]) {
+           ourtable = myp.s + j++;
+           *(ourtable++) = '\0';
+         }
+       }
+      }
+    }
+  }
+  if (host && !*host) host = (char *) 0;
+  if (user && !*user) user = (char *) 0;
+  if (pw && !*pw) pw = (char *) 0;
+  if (db && !*db) db = (char *) 0;
+  if (ourtable && !*ourtable) ourtable = (char *) 0;
+  if (table) {
+    if (*table) ourtable = *table;
+    else *table = ourtable;
+    if (!*table) return ERR_NO_TABLE;
+  }
+  if (!psql) {
+    if (!((MYSQL *) psql = mysql_init((MYSQL *) 0)))
+        return ERR_NOMEM;                                      /* init */
+    if (!(mysql_real_connect((MYSQL *) psql, host, user, pw, db,
+       (unsigned int) port, 0, CLIENT_COMPRESS)))              /* conn */
+               return mysql_error((MYSQL *) psql);
+  }
+  return (char *) 0;
+}
+
+void closesql()
+/* close connection to SQL server, if open */
+{
+       if (psql) mysql_close((MYSQL *) psql);
+       psql = (void *) 0;                      /* destroy pointer */
+       ourdb.len = 0;                          /* destroy cache */
+       return;
+}
+
diff --git a/sub_mysql/putsubs.c b/sub_mysql/putsubs.c
new file mode 100644 (file)
index 0000000..2a98dfc
--- /dev/null
@@ -0,0 +1,128 @@
+#include "error.h"
+#include "strerr.h"
+#include "readwrite.h"
+#include "str.h"
+#include "fmt.h"
+#include "stralloc.h"
+#include "open.h"
+#include "substdio.h"
+#include "case.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "qmail.h"
+#include <mysql.h>
+
+static substdio ssin;
+static char inbuf[512];
+char strnum[FMT_ULONG];
+static stralloc line = {0};
+static stralloc domains = {0};
+static stralloc quoted = {0};
+static stralloc fn = {0};
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void die_write(fatal)
+char *fatal;
+{
+  strerr_die3x(111,fatal,ERR_WRITE,"stdout");
+}
+
+unsigned long putsubs(dbname,hash_lo,hash_hi,
+       subwrite,flagsql,fatal)
+/* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */
+/* that userhost is excluded. 'dbname' is the base directory name. For the  */
+/* mysql version, dbname is the directory where the file "sql" with mysql   */
+/* access info is found. If this file is not present or if flagmysql is not */
+/* set, the routine falls back to the old database style. subwrite must be a*/
+/* function returning >=0 on success, -1 on error, and taking arguments     */
+/* (char* string, unsigned int length). It will be called once per address  */
+/* and should take care of newline or whatever needed for the output form.  */
+
+char *dbname;          /* database base dir */
+unsigned long hash_lo;
+unsigned long hash_hi;
+int subwrite();                /* write function. */
+int flagsql;
+char *fatal;           /* fatal error string */
+
+{
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *table = (char *) 0;
+  unsigned long *lengths;
+
+  unsigned int i;
+  int fd;
+  unsigned long no = 0L;
+  int match;
+  unsigned int pos = 0;
+  unsigned int hashpos;
+  char *ret = (char *) 0;
+
+  if (!flagsql || (ret = opensql(dbname,&table))) {
+    if (flagsql && *ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local db */
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal);
+                               /* NOTE: Also copies terminal '\0' */
+    hashpos = fn.len - 2;
+    if (hash_lo > 52) hash_lo = 52;
+    if (hash_hi > 52) hash_hi = 52;
+    if (hash_hi < hash_lo) hash_hi = hash_lo;
+
+    for (i = hash_lo;i <= hash_hi;++i) {
+      fn.s[hashpos] = 64 + i;  /* hash range 0-52 */
+      fd = open_read(fn.s);
+      if (fd == -1) {
+        if (errno != error_noent)
+         strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      } else {
+        substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+        for (;;) {
+          if (getln(&ssin,&line,&match,'\0') == -1)
+            strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+          if (!match)
+            break;
+          if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal);
+          no++;
+        }
+        close(fd);
+      }
+    }
+    return no;
+
+  } else {                                     /* SQL Version */
+
+                                               /* main query */
+    if (!stralloc_copys(&line,"SELECT address FROM "))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line," WHERE hash BETWEEN ")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_lo)))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line," AND ")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_hi)))
+               die_nomem(fatal);
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len))      /* query */
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    if (!(result = mysql_use_result((MYSQL *) psql)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    no = 0;
+    while ((row = mysql_fetch_row(result))) {
+       /* this is safe even if someone messes with the address field def */
+    if (!(lengths = mysql_fetch_lengths(result)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (subwrite(row[0],lengths[0]) == -1) die_write(fatal);
+      no++;                                    /* count for list-list fxn */
+    }
+    if (!mysql_eof(result))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    mysql_free_result(result);
+    return no;
+  }
+}
diff --git a/sub_mysql/searchlog.c b/sub_mysql/searchlog.c
new file mode 100644 (file)
index 0000000..8d8278f
--- /dev/null
@@ -0,0 +1,163 @@
+/*$Id: searchlog.c,v 1.15 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "case.h"
+#include "scan.h"
+#include "stralloc.h"
+#include "str.h"
+#include "open.h"
+#include "datetime.h"
+#include "date822fmt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "error.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <mysql.h>
+
+static stralloc line = {0};
+static stralloc outline = {0};
+static char date[DATE822FMT];
+static datetime_sec when;
+static struct datetime dt;
+static substdio ssin;
+static char inbuf[256];
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void lineout(subwrite,fatal)
+int subwrite();
+char *fatal;
+{
+  (void) scan_ulong(line.s,&when);
+  datetime_tai(&dt,when);              /* there is always at least a '\n' */
+  if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1))
+       die_nomem(fatal);
+  if (!stralloc_cats(&outline,": ")) die_nomem(fatal);
+  if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal);
+  if (subwrite(outline.s,outline.len) == -1)
+       strerr_die3x(111,fatal,ERR_WRITE,"output");
+  return;
+}
+
+void searchlog(dir,search,subwrite,fatal)
+/* opens dir/Log, and outputs via subwrite(s,len) any line that matches   */
+/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */
+/* is replaced by a '_'. mysql version. Falls back on "manual" search of  */
+/* local Log if no mysql connect info. */
+
+char *dir;             /* work directory */
+char *search;          /* search string */
+int subwrite();                /* output fxn */
+char *fatal;           /* fatal */
+{
+
+  register unsigned char x;
+  register unsigned char y;
+  register unsigned char *cp;
+  register unsigned char *cpsearch;
+  unsigned register char *cps;
+  unsigned register char ch;
+  unsigned char *cplast, *cpline;
+  unsigned int searchlen;
+  int fd,match;
+  char *ret;
+
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *table = (char *) 0;
+  char **ptable = &table;
+  char *sublist = (char *) 0;
+  unsigned long *lengths;
+
+  if (!search) search = "";    /* defensive */
+  searchlen = str_len(search);
+  case_lowerb(search,searchlen);
+  cps = (unsigned char *) search;
+  while ((ch = *(cps++))) {    /* search is potentially hostile */
+    if (ch >= 'a' && ch <= 'z') continue;
+    if (ch >= '0' && ch <= '9') continue;
+    if (ch == '.' || ch == '_') continue;
+    *(cps - 1) = '_';          /* will match char specified as well */
+  }
+
+  if ((ret = opensql(dir,ptable))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local log */
+  if (!stralloc_copys(&line,dir)) die_nomem(fatal);
+  if (!stralloc_cats(&line,"/Log")) die_nomem(fatal);
+  if (!stralloc_0(&line)) die_nomem(fatal);
+  fd = open_read(line.s);
+  if (fd == -1)
+    if (errno != error_noent)
+       strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    else
+        strerr_die3x(100,fatal,line.s,ERR_NOEXIST);
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,fatal,ERR_READ_INPUT);
+    if (!match) break;
+    if (!searchlen) {
+      lineout(subwrite,fatal);
+    } else {
+      cpline = (unsigned char *) line.s - 1;
+      cplast = cpline + line.len - searchlen; /* line has \0 at the end */
+      while ((cp = ++cpline) <= cplast) {
+       cpsearch = (unsigned char *) search;
+       for (;;) {
+         x = *cpsearch++;
+         if (!x) break;
+         y = *cp++ - 'A';
+         if (y <= (unsigned char) ('Z' - 'A')) y += 'a'; else y += 'A';
+         if (x != y && x != '_') break;                /* '_' = wildcard */
+       }
+       if (!x) {
+         lineout(subwrite,fatal);
+         break;
+       }
+      }
+    }
+  }
+  close(fd);
+  } else {
+
+/* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address   */
+/* LIKE '%search%' ORDER BY tai; */
+/* The '*' is formatted to look like the output of the non-mysql version */
+/* This requires reading the entire table, since search fields are not   */
+/* indexed, but this is a rare query and time is not of the essence.     */
+
+    if (!stralloc_cats(&line,"SELECT CONCAT(FROM_UNIXTIME(UNIX_TIMESTAMP(tai)),"
+       "'-0000: ',UNIX_TIMESTAMP(tai),' ',edir,etype,' ',address,' ',"
+       "fromline) FROM ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"_slog ")) die_nomem(fatal);
+    if (*search) {     /* We can afford to wait for LIKE '%xx%' */
+      if (!stralloc_cats(&line,"WHERE fromline LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%' OR address LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%'")) die_nomem(fatal);
+    }  /* ordering by tai which is an index */
+      if (!stralloc_cats(&line," ORDER by tai")) die_nomem(fatal);
+
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len))      /* query */
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    if (!(result = mysql_use_result((MYSQL *) psql)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    while ((row = mysql_fetch_row(result))) {
+    if (!(lengths = mysql_fetch_lengths(result)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (subwrite(row[0],lengths[0]) == -1) die_write(fatal);
+    }
+    if (!mysql_eof(result))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+    mysql_free_result(result);
+  }
+}
diff --git a/sub_mysql/subscribe.c b/sub_mysql/subscribe.c
new file mode 100644 (file)
index 0000000..f309253
--- /dev/null
@@ -0,0 +1,376 @@
+/*$Id: subscribe.c,v 1.22 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "strerr.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "lock.h"
+#include "error.h"
+#include "subscribe.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "log.h"
+#include "idx.h"
+#include <mysql.h>
+#include <mysqld_error.h>
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc domain = {0};
+static stralloc logline = {0};
+static stralloc quoted = {0};
+static stralloc fnnew = {0};
+static stralloc fn = {0};
+static stralloc fnlock = {0};
+static char szh[FMT_ULONG];
+
+void die_read(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+}
+
+void die_write(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_WRITE,fnnew.s,": ");
+}
+
+static int fd;
+static substdio ss;
+static char ssbuf[256];
+static int fdnew;
+static substdio ssnew;
+static char ssnewbuf[256];
+
+int subscribe(dbname,userhost,flagadd,comment,event,flagmysql,
+       forcehash,tab,fatal)
+/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database  */
+/* dbname. Comment is e.g. the subscriber from line or name. It is added to  */
+/* the log. Event is the action type, e.g. "probe", "manual", etc. The       */
+/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0   */
+/* on failure. If flagmysql is set and the file "sql" is found in the        */
+/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
+/* >=0 it is used in place of the calculated hash. This makes it possible to */
+/* add addresses with a hash that does not exist. forcehash has to be 0..99. */
+/* for unsubscribes, the address is only removed if forcehash matches the    */
+/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
+/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
+/* used for sublist addresses (to avoid removal) and sublist aliases (to     */
+/* prevent users from subscribing them (although the cookie mechanism would  */
+/* prevent the resulting duplicate message from being distributed. */
+
+char *dbname;
+char *userhost;
+int flagadd;
+char *comment;
+char *event;
+int flagmysql;
+int forcehash;
+char *tab;
+char *fatal;
+{
+  int fdlock;
+
+  MYSQL_RES *result;
+  MYSQL_ROW row;
+  char *cp,*cpafter,*cpat;
+  char szhash[3] = "00";
+  char *r = (char *) 0;
+  char *table = (char *) 0;
+  char **ptable = &table;
+
+  unsigned int j;
+  uint32 h,lch;
+  unsigned char ch,lcch;
+  int match;
+  int flagwasthere;
+
+  if (userhost[str_chr(userhost,'\n')])
+    strerr_die2x(100,fatal,ERR_ADDR_NL);
+
+  if (tab) ptable = &tab;
+
+  if (!flagmysql || (r = opensql(dbname,ptable))) {
+    if (r && *r) strerr_die2x(111,fatal,r);
+                                               /* fallback to local db */
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+    if (addr.len > 401)
+      strerr_die2x(100,fatal,ERR_ADDR_LONG);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len)
+      strerr_die2x(100,fatal,ERR_ADDR_AT);
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* make all-lc version of address */
+
+    if (forcehash >= 0 && forcehash <= 52) {
+      ch = lcch = (unsigned char) forcehash;
+    } else {
+      h = 5381;
+      lch = h;
+      for (j = 0;j < addr.len;++j) {
+        h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+        lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+      }
+      lcch = 64 + (lch % 53);
+      ch = 64 + (h % 53);
+    }
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_copys(&fnlock,dbname)) die_nomem(fatal);
+
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_copy(&fnnew,&fn)) die_nomem(fatal);
+       /* code later depends on fnnew = fn + 'n' */
+    if (!stralloc_cats(&fnnew,"n")) die_nomem(fatal);
+    if (!stralloc_cats(&fnlock,"/lock")) die_nomem(fatal);
+    if (!stralloc_0(&fnnew)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+    if (!stralloc_0(&fnlock)) die_nomem(fatal);
+
+    fdlock = open_append(fnlock.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,fatal,ERR_OPEN,fnlock.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,fatal,ERR_OBTAIN,fnlock.s,": ");
+
+                               /* do lower case hashed version first */
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    flagwasthere = 0;
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    }
+    else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1) {
+         close(fd); close(fdnew); die_read(fatal);
+        }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+           flagwasthere = 1;
+           if (!flagadd)
+             continue;
+         }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1) {
+         close(fd); close(fdnew); die_write(fatal);
+        }
+      }
+
+      close(fd);
+    }
+
+    if (flagadd && !flagwasthere)
+      if (substdio_bput(&ssnew,addr.s,addr.len) == -1) {
+        close(fdnew); die_write(fatal);
+      }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    if ((ch == lcch) || flagwasthere) {
+      close(fdlock);
+      if (flagadd ^ flagwasthere) {
+        if (!stralloc_0(&addr)) die_nomem(fatal);
+        log(dbname,event,addr.s+1,comment);
+        return 1;
+      }
+      return 0;
+    }
+
+                       /* If unsub and not found and hashed differ, OR */
+                       /* sub and not found (so added with new hash) */
+                       /* do the 'case-dependent' hash */
+
+    fn.s[fn.len - 2] = ch;
+    fnnew.s[fnnew.len - 3] = ch;
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          { close(fd); close(fdnew); die_read(fatal); }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+            flagwasthere = 1;
+            continue;  /* always want to remove from case-sensitive hash */
+          }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1)
+          { close(fd); close(fdnew); die_write(fatal); }
+      }
+
+      close(fd);
+    }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    close(fdlock);
+    if (flagadd ^ flagwasthere) {
+      if (!stralloc_0(&addr)) die_nomem(fatal);
+      log(dbname,event,addr.s+1,comment);
+      return 1;
+    }
+    return 0;
+
+  } else {                             /* SQL version */
+    domain.len = 0;                    /* clear domain */
+                                       /* lowercase and check address */
+    if (!stralloc_copys(&addr,userhost)) die_nomem(fatal);
+    if (addr.len > 255)                        /* this is 401 in std ezmlm. 255 */
+                                       /* should be plenty! */
+      strerr_die2x(100,fatal,ERR_ADDR_LONG);
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len)
+      strerr_die2x(100,fatal,ERR_ADDR_AT);
+    cpat = addr.s + j;
+    case_lowerb(cpat + 1,addr.len - j - 1);
+    if (!stralloc_ready(&quoted,2 * addr.len + 1)) die_nomem(fatal);
+    quoted.len = mysql_escape_string(quoted.s,addr.s,addr.len);
+       /* stored unescaped, so it should be ok if quoted.len is >255, as */
+       /* long as addr.len is not */
+
+    if (forcehash < 0) {
+      if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+      case_lowerb(lcaddr.s,j);         /* make all-lc version of address */
+      h = 5381;
+      for (j = 0;j < lcaddr.len;++j) {
+        h = (h + (h << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+      }
+      ch = (h % 53);                   /* 0 - 52 */
+    } else
+      ch = (forcehash % 100);
+
+    szhash[0] = '0' + ch / 10;         /* hash for sublist split */
+    szhash[1] = '0' + (ch % 10);
+
+    if (flagadd) {
+      if (!stralloc_copys(&line,"LOCK TABLES ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);
+      if (!stralloc_cats(&line," WRITE")) die_nomem(fatal);
+      if (mysql_real_query((MYSQL *) psql,line.s,line.len))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);
+      if (!stralloc_cats(&line," WHERE address='")) die_nomem(fatal);
+      if (!stralloc_cat(&line,&quoted)) die_nomem(fatal);      /* addr */
+      if (!stralloc_cats(&line,"'")) die_nomem(fatal);
+      if (mysql_real_query((MYSQL *) psql,line.s,line.len))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (!(result = mysql_use_result((MYSQL *) psql)))
+       strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if ((row = mysql_fetch_row(result))) {                   /* there */
+       while (mysql_fetch_row(result));                        /* use'm up */
+       mysql_free_result(result);
+       if (mysql_query((MYSQL *) psql,"UNLOCK TABLES"))
+         strerr_die2x(111,"fatal",mysql_error((MYSQL *) psql));
+        return 0;                                              /* there */
+      } else {                                                 /* not there */
+       mysql_free_result(result);
+       if (mysql_errno((MYSQL *) psql))                        /* or ERROR */
+         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+       if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal);
+       if (!stralloc_cats(&line,table)) die_nomem(fatal);
+       if (!stralloc_cats(&line," (address,hash) VALUES ('"))
+               die_nomem(fatal);
+       if (!stralloc_cat(&line,&quoted)) die_nomem(fatal);     /* addr */
+       if (!stralloc_cats(&line,"',")) die_nomem(fatal);
+       if (!stralloc_cats(&line,szhash)) die_nomem(fatal);     /* hash */
+       if (!stralloc_cats(&line,")")) die_nomem(fatal);
+        if (mysql_real_query((MYSQL *) psql,line.s,line.len))  /* INSERT */
+         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+       if (mysql_query((MYSQL *) psql,"UNLOCK TABLES"))
+         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      }
+    } else {                                                   /* unsub */
+      if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);
+      if (!stralloc_cats(&line," WHERE address='")) die_nomem(fatal);
+      if (!stralloc_cat(&line,&quoted)) die_nomem(fatal);      /* addr */
+      if (forcehash >= 0) {
+       if (!stralloc_cats(&line,"' AND hash=")) die_nomem(fatal);
+       if (!stralloc_cats(&line,szhash)) die_nomem(fatal);
+      } else {
+        if (!stralloc_cats(&line,"' AND hash BETWEEN 0 AND 52"))
+               die_nomem(fatal);
+      }
+      if (mysql_real_query((MYSQL *) psql,line.s,line.len))
+         strerr_die2x(111,fatal,mysql_error((MYSQL *) psql));
+      if (mysql_affected_rows((MYSQL *) psql) == 0)
+       return 0;                               /* address wasn't there*/
+    }
+
+               /* log to subscriber log */
+               /* INSERT INTO t_slog (address,edir,etype,fromline) */
+               /* VALUES('address',{'+'|'-'},'etype','[comment]') */
+
+    if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem(fatal);
+    if (!stralloc_cats(&logline,table)) die_nomem(fatal);
+    if (!stralloc_cats(&logline,
+       "_slog (address,edir,etype,fromline) VALUES ('")) die_nomem(fatal);
+    if (!stralloc_cat(&logline,&quoted)) die_nomem(fatal);
+    if (flagadd) {                                             /* edir */
+      if (!stralloc_cats(&logline,"','+','")) die_nomem(fatal);
+    } else {
+      if (!stralloc_cats(&logline,"','-','")) die_nomem(fatal);
+    }
+    if (*(event + 1))  /* ezmlm-0.53 uses '' for ezmlm-manage's work */
+      if (!stralloc_catb(&logline,event+1,1)) die_nomem(fatal);        /* etype */
+    if (!stralloc_cats(&logline,"','")) die_nomem(fatal);
+    if (comment && *comment) {
+       j = str_len(comment);
+       if (!stralloc_ready(&quoted,2 * j + 1)) die_nomem(fatal);
+       quoted.len = mysql_escape_string(quoted.s,comment,j);   /* from */
+       if (!stralloc_cat(&logline,&quoted)) die_nomem(fatal);
+    }
+    if (!stralloc_cats(&logline,"')")) die_nomem(fatal);
+
+    if (mysql_real_query((MYSQL *) psql,logline.s,logline.len))
+               ;                               /* log (ignore errors) */
+    if (!stralloc_0(&addr))
+               ;                               /* ignore errors */
+    log(dbname,event,addr.s,comment);          /* also log to old log */
+    return 1;                                  /* desired effect */
+  }
+}
diff --git a/sub_mysql/tagmsg.c b/sub_mysql/tagmsg.c
new file mode 100644 (file)
index 0000000..55b57e7
--- /dev/null
@@ -0,0 +1,92 @@
+/*$Id: tagmsg.c,v 1.11 1999/11/10 04:08:27 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "strerr.h"
+#include "cookie.h"
+#include "slurp.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "makehash.h"
+#include <mysql.h>
+#include <mysqld_error.h>
+
+static stralloc line = {0};
+static stralloc key = {0};
+static char hash[COOKIE];
+static char strnum[FMT_ULONG]; /* message number as sz */
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(100,fatal,ERR_NOMEM);
+}
+
+void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal)
+/* This routine creates a cookie from num,seed and the */
+/* list key and returns that cookie in hashout. The use of sender/num and */
+/* first char of action is used to make cookie differ between messages,   */
+/* the key is the secret list key. The cookie will be inserted into       */
+/* table_cookie where table and other data is taken from dir/sql. We log  */
+/* arrival of the message (done=0). */
+
+char *dir;                     /* db base dir */
+unsigned long msgnum;          /* number of this message */
+char *seed;                    /* seed. NULL ok, but less entropy */
+char *action;                  /* to make it certain the cookie differs from*/
+                               /* one used for a digest */
+char *hashout;                 /* calculated hash goes here */
+unsigned long bodysize;
+unsigned long chunk;
+char *fatal;
+{
+  char *table = (char *) 0;
+  char *ret;
+  unsigned int i;
+
+  strnum[fmt_ulong(strnum,msgnum)] = '\0';     /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+      case -1:
+       strerr_die3sys(111,fatal,ERR_READ,"key: ");
+      case 0:
+       strerr_die3x(100,fatal,"key",ERR_NOEXIST);
+    }
+    cookie(hash,key.s,key.len,strnum,seed,action);
+    for (i = 0; i < COOKIE; i++)
+      hashout[i] = hash[i];
+
+  if ((ret = opensql(dir,&table))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+    return;                            /* no sql => success */
+
+  } else {
+    if (chunk >= 53L) chunk = 0L;      /* sanity */
+
+       /* INSERT INTO table_cookie (msgnum,cookie) VALUES (num,cookie) */
+       /* (we may have tried message before, but failed to complete, so */
+       /* ER_DUP_ENTRY is ok) */
+    if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"_cookie (msgnum,cookie,bodysize,chunk) VALUES ("))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line,strnum)) die_nomem(fatal);
+    if (!stralloc_cats(&line,",'")) die_nomem(fatal);
+    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"',")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,bodysize)))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line,",")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,chunk))) die_nomem(fatal);
+    if (!stralloc_cats(&line,")")) die_nomem(fatal);
+    if (mysql_real_query((MYSQL *) psql,line.s,line.len) != 0)
+      if (mysql_errno((MYSQL *) psql) != ER_DUP_ENTRY) /* ignore dups */
+        strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); /* cookie query */
+
+    if (! (ret = logmsg(dir,msgnum,0L,0L,1))) return;  /* log done=1*/
+    if (*ret) strerr_die2x(111,fatal,ret);
+  }
+
+  return;
+}
diff --git a/sub_mysql/to40x b/sub_mysql/to40x
new file mode 100755 (executable)
index 0000000..5f6f872
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+cat <<EOF
+ALTER TABLE ${1}_cookie
+        ADD COLUMN chunk TINYINT NOT NULL DEFAULT 0;
+ALTER TABLE ${1}_cookie
+        ADD COLUMN bodysize INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE ${1}_mlog
+        ADD COLUMN subs INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE ${1}_digest_cookie
+        ADD COLUMN chunk TINYINT NOT NULL DEFAULT 0;
+ALTER TABLE ${1}_digest_cookie
+        ADD COLUMN bodysize INTEGER NOT NULL DEFAULT 0;
+ALTER TABLE ${1}_digest_mlog
+        ADD COLUMN subs INTEGER NOT NULL DEFAULT 0;
+
diff --git a/sub_pgsql/README b/sub_pgsql/README
new file mode 100644 (file)
index 0000000..942d15c
--- /dev/null
@@ -0,0 +1,169 @@
+$Id: README,v 1.1 1999/08/21 02:00:37 lindberg Exp $
+$Name: ezmlm-idx-040 $
+INFORMATION ON BUILDING/USING EZMLM WITH POSTGRESQL SUPPORT
+
+Original source:
+(c) 1999,      Frederik Lindberg,
+               lindberg@id.wustl.edu
+               You may use under GPL.
+
+and for PostgreSQL modifications:
+(c) 1999, Magnus Stålåker
+        stalaker@umc.se
+
+For information on PostgreSQL, see http://www.postgresql.org/
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+NOTICE! This is a untested beta! USE WITH CAUTION!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+This version of the PostgresSQL supports the basic subscriber address
+database and subscription logging. The log that is searched by the -log.
+command is the local listdir/Log file, NOT the SQL database. Message
+logging is not supported, and central admin of list clusters is not
+supported. Still, the current support covers the functionality used in
+99% of lists.
+
+Most of this information is available in FAQ.idx.
+
+If you are interested in contributing/testing a subscriber db interface
+for another SQL server, please see sub_std/README and the routines here,
+and contact lindberg@id.wustl.edu (it may already be in process). See end
+of this file for other ways to contribute.
+
+conf-mysql must be edited to reflect your system. On many systems, you
+also need to include ``-lsocket'', as well as change the paths to the
+/usr/local equivalents. For the i386.rpm-based systems, you need at
+least MySQL-devel to build the files. Look at your mysql docs for more info.
+
+TABLES USED FOR (My)SQL SUPPORT
+
+The basic philosophy is that the database can be on any host (if you use
+SENDER restrictions, connectivity to the main host is more important than
+to the sublists), and you choose the database and "table root" names. The
+default database is ``ezmlm'' and the default table root is ``list''. Each
+list has a separate table root. Any number of lists can share a database.
+
+The main list address table is named with the table root only, others have
+that name with various suffixes. In the following ``list'' is used as the
+table root.
+
+ADDRESS TABLES
+list           subscriber addresses
+list_slog      subscriber address log
+list_allow     subscriber aliases for posts on SENDER checked lists.
+list_allow_slog        subscriber log for list_allow
+list_deny      blacklisted addresses for posts on SENDER checked lists.
+list_deny_slog log for list_deny.
+list_mod       moderator addresses
+list_mod_slog  log for list_mod
+list_digest    subscriber log for digest list.
+list_digest_slog       log for list_digest
+
+MESSAGE LOGGING TABLES (not supported by this version of the interface)
+list_cookie    message cookie table for main list
+list_mlog      message logging table for main list
+list_digest_cookie     message cookie table for digest list
+list_digest_mlog       message logging table for digest list
+
+SUBLIST SPLIT TABLES (not supported by this version of the interface)
+list_name      sublist split table for main list
+list_digest_name       sublist split table for digest list.
+
+
+ezmlm-mktab(1) is a script that outputs the table definintions. Look at
+the output for a detailed field description.
+
+The address tables contain (address,domain,hash,h,num). For normal
+lists only the address field is used. For main->sublist clusters, the other
+fields are used for load splitting. The domain is the first up to 3 characters
+of the last part of the domain name. The hash is a address hash [0-52] differnt
+from the one used by ezmlm for splitting within DIR/subscribers. When using
+the address field as a primary key, the size of the index was unreasonable.
+Therefore, ``num'' is used as a dummy primary key, and ``h'' (a 32 bit hash
+of the address) is used as an index. This markedly speeds up (un)sub with
+large (>30,000 rows) subscriber tables.
+
+The *_slog tables contain the same info as DIR/Log, i.e. address, timestamp,
+entry-type, entry-direction, and fromline. The entry-type is the first letter
+of the type of entry (probe, manual, `` '' for normal), entry-direction is
+``+'' for addition, ``-'' for removal. Fromline is the From: header contents
+taken from the subscribe confirm message or from ezmlm-sub (if used with -n).
+It is blank for all address removals, and may be blank also for additions. It
+is used by the list-log.xx command. It is trivial to JOIN this table with the
+address table to get e.g. subsciber names, subscription dates, etc. These
+tables also have the 32-bit hash ``h'' as an index. Joins should be done on
+``h'' as well as ``address'' for better performance.
+
+The *_cookie tables contain message number, timestamp, and cookie. For each
+message a pseudo-random cookie is generated that is ``impossible'' to guess
+beforehand. For lists with sublists, this is used as basic authentication,
+i.e. the sublist will refuse to process a message that doesn't contain the
+correct cookie or that the sublist has already successfully processed.
+
+The *_mlog tables contain log entries from main and sublists. These are
+timestamp, listno, done. Listno is the lowest listnumber for an active list
+entry with the name of this sublist as looked up in the *_name table. Done
+is -1 for bounce, 0 for arrived, 1 for finished processing, and 2 for receipt
+received. The routines are set up so that only the first attempt for each
+combination (listno,code) is logged.
+
+The *_name tables contain listno,name,domain,hash_lo,hash_hi,msgnum_lo,
+msgnum_hi,notuse. Listno is auto_increment and unique. Name is the name of the
+sublist. domain is the last up to 3 characters of the top domain name for
+addresses served by this list (default = ''). It is is '', the list servers
+all_domains_that_are_not_served_by_another list (in addition to domain '').
+Of the addresses that match the domain criterion, the list serves the subset
+with hash between hash_lo and hash_hi (defaults 0, 52). Any entry is ingnored if
+notuse != 0 OR the current message number is not between msgnum_lo and
+msgnum_hi.
+
+For normal lists that are not distributed (i.e. they are a single list),
+entries in the *_name tables are not needed and logging is not very
+relevant.
+
+For most lists, the only addresses that are stored in the SQL database are
+the subscribers of list and digest, and the ``allow'' aliases. It is NOT
+normally advisable to store moderator addresses there, since they are
+needed only at the main list and secrecy is more important. ``Deny'' addresses
+are few and again only needed at the main list. ``Allow'' are put in the
+SQL database when using the default ezmlmrc file only to make all relevant
+addresses manipulatable via the SQL server. The other tables are created, in
+case they are  wanted (the cost for having them as empty table is zero). The
+basedir/sql file is the decision point. If it exists, an SQL table is used;
+if not a local ezmlm db is used.
+
+CONTRIBUTIONS REQESTED
+
+I would be very grateful if there are users out there willing to do any of
+the following and contribute it to this package. Please check with me first
+(lindberg@id.wustl.edu), as the project may already be in progress/done.
+
+1. Interfaces for other SQL servers. Oracle, SyBase, ...
+
+2. A GUI admin utility to add/remove/manipulate the sublist split, essentially
+   by modifying list_[digest_]name in a safe way. Ideally WWW if it can be
+   done securely. If you use some standard interface (JDBC/DBD) it would be
+   useful also with other SQL severs. This could even be an Access program
+   using ODBC, although writing it for a platform running qmail/ezmlm makes
+   most sense.
+
+3. a WWW GUI that allows users to subscribe/unsubscribe in a safe way. A random
+   password would be created the first time and stored in a new address->pw
+   table and mailed to the subscriber address. With that password, the user
+   would be able to [un]subscribe to lists, edit the name (for compatibility
+   implemented by adding a subscribe line to list_[digest]slog). Add/remove
+   aliases. Ideally, it should also allow searching by subscriber name. This
+   would search *_slog.fromline. If less that 'x' alternatives are found, the
+   user would be presented with names (not addresses), allowing the user to
+   cause the subscription name and password to be sent to the respective
+   subscription address. With that info, the subscriber can then unsubscribe,
+   even if s/he has forgotten the subscription address. It is complicated
+   slightly by the fact that ``fromline'' is the crude line and needs to be
+   rfc822 parsed. Again, use of a standard interface is encouraged to make it
+   compatible also with other SQL servers.
+
+The aim of all this is to make it easy to use ezmlm to run very large lists,
+easy to set up sites that handle subscriber interaction, archive access, etc,
+and hopefully easier to integrate many ezmlm as done by some WWW sites today.
+
diff --git a/sub_pgsql/checktag.c b/sub_pgsql/checktag.c
new file mode 100644 (file)
index 0000000..330c236
--- /dev/null
@@ -0,0 +1,106 @@
+/*$Id: checktag.c,v 1.3 1999/12/23 02:40:57 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "cookie.h"
+#include "makehash.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static stralloc key = {0};
+static stralloc line = {0};
+static strnum[FMT_ULONG];
+static newcookie[COOKIE];
+
+char *checktag (dir,num,listno,action,seed,hash)
+/* reads dir/sql. If not present, returns success (NULL). If dir/sql is    */
+/* present, checks hash against the cookie table. If match, returns success*/
+/* (NULL), else returns "". If error, returns error string. */
+
+
+char *dir;                             /* the db base dir */
+unsigned long num;                     /* message number */
+unsigned long listno;                  /* bottom of range => slave */
+char *action;
+char *seed;                            /* cookie base */
+char *hash;                            /* cookie */
+{
+  PGresult *result;
+  /*  int row; */
+  char *table = (char *) 0;
+  char *r;
+
+  if ((r = opensql(dir,&table))) {
+    if (*r) return r;
+    if (!seed) return (char *) 0;              /* no data - accept */
+
+    strnum[fmt_ulong(strnum,num)] = '\0';      /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+    case -1:
+      return ERR_READ_KEY;
+    case 0:
+      return ERR_NOEXIST_KEY;
+    }
+
+    cookie(newcookie,key.s,key.len,strnum,seed,action);
+    if (byte_diff(hash,COOKIE,newcookie)) return "";
+    else return (char *) 0;
+
+  } else {
+
+    /* SELECT msgnum FROM table_cookie WHERE msgnum=num and cookie='hash' */
+    /* succeeds only is everything correct. 'hash' is quoted since it is  */
+    /* potentially hostile. */
+    if (listno) {                      /* only for slaves */
+      if (!stralloc_copys(&line,"SELECT listno FROM ")) return ERR_NOMEM;
+      if (!stralloc_cats(&line,table)) return ERR_NOMEM;
+      if (!stralloc_cats(&line,"_mlog WHERE listno=")) return ERR_NOMEM;
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,listno)))
+       return ERR_NOMEM;
+      if (!stralloc_cats(&line," AND msgnum=")) return ERR_NOMEM;
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+      if (!stralloc_cats(&line," AND done > 3")) return ERR_NOMEM;
+
+      if (!stralloc_0(&line)) return ERR_NOMEM;
+      result = PQexec( psql, line.s );
+      if(result == NULL)
+       return (PQerrorMessage(psql));
+      if( PQresultStatus(result) != PGRES_TUPLES_OK)
+       return (char *) (PQresultErrorMessage(result));
+      if( PQntuples(result) > 0 ) {
+       PQclear(result);
+       return("");
+      } else
+       PQclear(result);
+    }
+
+    if (!stralloc_copys(&line,"SELECT msgnum FROM ")) return ERR_NOMEM;
+    if (!stralloc_cats(&line,table)) return ERR_NOMEM;
+    if (!stralloc_cats(&line,"_cookie WHERE msgnum=")) return ERR_NOMEM;
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+    if (!stralloc_cats(&line," and cookie='")) return ERR_NOMEM;
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash))) return ERR_NOMEM;
+    if (!stralloc_cats(&line,"'")) return ERR_NOMEM;
+
+    if (!stralloc_0(&line)) return ERR_NOMEM;
+    result = PQexec(psql,line.s);
+    if (result == NULL)
+      return (PQerrorMessage(psql));
+    if (PQresultStatus(result) != PGRES_TUPLES_OK)
+      return (char *) (PQresultErrorMessage(result));
+    if(PQntuples(result) < 0) {
+      PQclear( result );
+      return("");
+    }
+
+    PQclear(result);
+    if (listno)
+      (void) logmsg(dir,num,listno,0L,3);      /* non-ess mysql logging */
+    return (char *)0;
+  }
+}
diff --git a/sub_pgsql/conf-sqlcc b/sub_pgsql/conf-sqlcc
new file mode 100644 (file)
index 0000000..886cf2f
--- /dev/null
@@ -0,0 +1,6 @@
+-I/usr/include/pgsql
+
+# the top line will be used when compiling. Edit to reflect your PostgreSQL
+# installation. The above is correct for RedHat rpms.
+# -I/usr/local/pgsql/include would be correct for BSD installations.
diff --git a/sub_pgsql/conf-sqlld b/sub_pgsql/conf-sqlld
new file mode 100644 (file)
index 0000000..610f5cd
--- /dev/null
@@ -0,0 +1,4 @@
+-L/usr/local/pgsql/lib -lpq -lcrypt
+
+# the top line will be used when linking. Edit to reflect your PostgreSQL
+# installation. 
diff --git a/sub_pgsql/ezmlm-mktab b/sub_pgsql/ezmlm-mktab
new file mode 100755 (executable)
index 0000000..9ac2b33
--- /dev/null
@@ -0,0 +1,216 @@
+#!/bin/sh
+# Simple script to generate input to psql to generate tables for a list
+# All tables are created, even though it is not advisable to put e.g. the
+# moderator table in the SQL database nor is it very useful to put the
+# blacklist/deny table there. The subscriber lists for the main and digest
+# lists should be there, and it's reasonable to put the "extra" list there
+# if used.
+ECHO='echo'
+CAT='cat'
+CUT='cut'
+
+CREATE='y'
+DROP='n'
+TROOT='list'
+# size of std cookie
+COOKIE='20'
+
+                                       # not everyone has getopt :-(
+while [ "`${ECHO} "$1" | ${CUT} -c1`" = "-" ]; do
+       case "$1" in
+               -c)     CREATE='y'; shift;;
+               -C)     CREATE='n'; shift;;
+               -d)     DROP='y'; shift;;
+               -D)     DROP='n'; shift;;
+               -cd|-dc)        CREATE='y'; DROP='y'; shift;;
+               -cD|-Dc)        CREATE='y'; DROP='n'; shift;;
+               -Cd|-dC)        CREATE='n'; DROP='y'; shift;;
+               -CD|-DC)        CREATE='n'; DROP='n'; shift;;
+               --)     shift; break;;
+               *)      echo "usage: emzlm-mktab [-cCdD] table_toot"; exit 100;;
+       esac
+done
+
+[ ! -z "$1" ] && TROOT="$1";
+
+if [ "$DROP" = "y" ]; then
+  cat <<EOF
+
+/* drop old tables.  */
+/* Usage: */
+/* ezmlm-mktab [-d] troot | psql -h host -u userid -d database */
+
+DROP TABLE ${TROOT};
+DROP TABLE ${TROOT}_slog;
+DROP TABLE ${TROOT}_digest;
+DROP TABLE ${TROOT}_digest_slog;
+DROP TABLE ${TROOT}_mod;
+DROP TABLE ${TROOT}_mod_slog;
+DROP TABLE ${TROOT}_allow;
+DROP TABLE ${TROOT}_allow_slog;
+DROP TABLE ${TROOT}_deny;
+DROP TABLE ${TROOT}_deny_slog;
+DROP TABLE ${TROOT}_name;
+DROP TABLE ${TROOT}_cookie;
+DROP TABLE ${TROOT}_mlog;
+DROP TABLE ${TROOT}_digest_name;
+DROP TABLE ${TROOT}_digest_cookie;
+DROP TABLE ${TROOT}_digest_mlog;
+DROP SEQUENCE ${TROOT}_name_listno_seq;
+DROP SEQUENCE ${TROOT}_digest_name_listno_seq;
+
+EOF
+
+fi
+
+if [ $CREATE = 'y' ]; then
+  cat << EOF
+
+/* Main address table */
+create TABLE ${TROOT} (
+       hash            INT4 NOT NULL,
+       address         VARCHAR(255) PRIMARY KEY );
+
+/* Subscription log table. No addr idx to make insertion fast, since that is */
+/* almost the only thing we do with this table */
+create TABLE ${TROOT}_slog (
+       tai             TIMESTAMP DEFAULT now(),
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR NOT NULL,
+       etype           CHAR NOT NULL
+       );
+
+/* digest list table */
+create TABLE ${TROOT}_digest (
+       hash            INT4 NOT NULL,
+       address         TEXT NOT NULL
+       );
+
+/* digest list subscription log */
+create TABLE ${TROOT}_digest_slog (
+       tai             TIMESTAMP DEFAULT now(),
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR NOT NULL,
+       etype           CHAR NOT NULL
+       );
+
+/* moderator addresses */
+create TABLE ${TROOT}_mod (
+       hash            INT4 NOT NULL,
+       address         TEXT NOT NULL
+);
+
+/* moderator subscription log */
+create TABLE ${TROOT}_mod_slog (
+       tai             TIMESTAMP DEFAULT now(),
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR NOT NULL,
+       etype           CHAR NOT NULL
+       );
+
+/* "allow" address table */
+create TABLE ${TROOT}_allow (
+       hash            INT4 NOT NULL,
+       address         VARCHAR(255) NOT NULL
+       );
+
+/* extra address table log */
+create TABLE ${TROOT}_allow_slog (
+       tai             TIMESTAMP DEFAULT now(),
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR NOT NULL,
+       etype           CHAR NOT NULL
+       );
+
+/* blacklist address table */
+create TABLE ${TROOT}_deny (
+       hash            INT4  NOT NULL,
+       address         VARCHAR(255) NOT NULL
+       );
+
+/* blacklist subscription log */
+create TABLE ${TROOT}_deny_slog (
+       tai             TIMESTAMP,
+       address         VARCHAR(255) NOT NULL,
+       fromline        VARCHAR(255) NOT NULL,
+       edir            CHAR NOT NULL,
+       etype           CHAR NOT NULL
+       );
+
+/* sublist restriction table */
+/* notuse != 0 => defer message. = 0 => process message */
+/* no reason for index - will always be small */
+create TABLE ${TROOT}_name (
+       listno          SERIAL,
+       name            VARCHAR(255) NOT NULL,
+       notuse          INT4 NOT NULL DEFAULT 0,
+       msgnum_lo       INT8 NOT NULL DEFAULT 0,
+       msgnum_hi       INT8 NOT NULL DEFAULT 4294967295,
+       hash_lo         INT4 NOT NULL DEFAULT 0,
+       hash_hi         INT4 NOT NULL DEFAULT 52,
+       domain          CHAR(3) NOT NULL DEFAULT '',
+       PRIMARY KEY (listno));
+
+/* main list inserts a cookie here. Sublists check it */
+CREATE TABLE ${TROOT}_cookie (
+       msgnum          INT4 NOT NULL,
+       tai             TIMESTAMP NOT NULL DEFAULT now(),
+       cookie          CHAR(20) NOT NULL,
+       chunk           INT4 NOT NULL DEFAULT 0,
+       bodysize        INT4 NOT NULL DEFAULT 0,
+       PRIMARY KEY (msgnum));
+
+/* main and sublist log here when the message is done */
+/* done=0 for arrived, done=1 for sent. tai reflects last change, as e.g. */
+/* done=0 may be overwritten in case first delivery to the list fails.    */
+CREATE TABLE ${TROOT}_mlog (
+       msgnum    INT4 NOT NULL,
+       listno    INT4 NOT NULL,
+       tai       TIMESTAMP DEFAULT now(),
+       subs      INT4 NOT NULL DEFAULT 0,
+       done      INT4 NOT NULL DEFAULT 0,
+       PRIMARY KEY (listno,msgnum,done));
+
+/* digest sublist restriction table */
+/* notuse != 0 => defer message. = 0 => process message */
+/* no index, since table unlikely to have >30 or so rows */
+create TABLE ${TROOT}_digest_name (
+       listno          SERIAL,
+       name            VARCHAR(255) NOT NULL,
+       notuse          INT4 NOT NULL DEFAULT 0,
+       msgnum_lo       INT8 NOT NULL DEFAULT 0,
+       msgnum_hi       INT8 NOT NULL DEFAULT 4294967295,
+       hash_lo         INT4 NOT NULL DEFAULT 0,
+       hash_hi         INT4 NOT NULL DEFAULT 52,
+       domain          CHAR(3) NOT NULL DEFAULT '',
+       PRIMARY KEY (listno));
+
+/* ezmlm-get when creating a digests inserts a cookie here. Sublists check it*/
+CREATE TABLE ${TROOT}_digest_cookie (
+       msgnum          INT4 NOT NULL,
+       tai             TIMESTAMP NOT NULL DEFAULT now(),
+       cookie          CHAR(20) NOT NULL,
+       chunk           INT4 NOT NULL DEFAULT 0,
+       bodysize        INT4 NOT NULL DEFAULT 0,
+       PRIMARY KEY (msgnum));
+
+/* ezmlm-get and digest sublists log here when the message is done */
+/* done=0 for arrived, done=1 for sent. tai reflects last change */
+CREATE TABLE ${TROOT}_digest_mlog (
+       msgnum          INT4 NOT NULL,
+       listno          INT4 NOT NULL,
+       tai             TIMESTAMP DEFAULT now(),
+       subs            INT4 NOT NULL DEFAULT 0,
+       done            INT4 NOT NULL DEFAULT 0,
+       PRIMARY KEY (listno,msgnum,done));
+
+EOF
+
+fi
+exit 0
+
+
diff --git a/sub_pgsql/issub.c b/sub_pgsql/issub.c
new file mode 100644 (file)
index 0000000..42b744d
--- /dev/null
@@ -0,0 +1,165 @@
+/*$Id: issub.c,v 1.4 1999/12/11 03:04:03 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "strerr.h"
+#include "error.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc fn = {0};
+static substdio ss;
+static char ssbuf[512];
+
+char *issub(dbname,userhost,tab,fatal)
+/* Returns (char *) to match if userhost is in the subscriber database     */
+/* dbname, 0 otherwise. dbname is a base directory for a list and may NOT  */
+/* be NULL        */
+/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/
+
+char *dbname;          /* directory to basedir */
+char *userhost;
+char *tab;             /* override table name */
+char *fatal;
+
+{
+  PGresult *result;
+  char *ret;
+  char *table;
+
+  int fd;
+  unsigned int j;
+  uint32 h,lch;
+  char ch,lcch;
+  int match;
+
+  table = tab;
+  if ((ret = opensql(dbname,&table))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local db */
+
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len) return 0;
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* totally lc version of addr */
+
+    h = 5381;
+    lch = h;                   /* make hash for both for backwards comp */
+    for (j = 0;j < addr.len;++j) {     /* (lcaddr.len == addr.len) */
+      h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+      lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+    }
+    ch = 64 + (h % 53);
+    lcch = 64 + (lch % 53);
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+        if (!match) break;
+        if (line.len == lcaddr.len)
+          if (!case_diffb(line.s,line.len,lcaddr.s))
+            { close(fd); return line.s+1; }
+      }
+
+      close(fd);
+    }
+       /* here if file not found or (file found && addr not there) */
+
+    if (ch == lcch) return 0;
+
+       /* try case sensitive hash for backwards compatibility */
+    fn.s[fn.len - 2] = ch;
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+      return 0;
+    }
+    substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+    for (;;) {
+      if (getln(&ss,&line,&match,'\0') == -1)
+        strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      if (!match) break;
+      if (line.len == addr.len)
+        if (!case_diffb(line.s,line.len,addr.s))
+          { close(fd); return line.s+1; }
+    }
+
+    close(fd);
+
+    return 0;
+  } else {                                             /* SQL version  */
+       /* SELECT address FROM list WHERE address = 'userhost' AND hash */
+       /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
+       /* even easier to defeat. Just faking sender to the list name would*/
+       /* work. Since sender checks for posts are bogus anyway, I don't */
+       /* know if it's worth the cost of the "WHERE ...". */
+
+    if (!stralloc_copys(&addr,userhost)) die_nomem(fatal);
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len) return 0;
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+
+    if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal);
+    if (!stralloc_cat(&line,&addr)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"$'")) die_nomem(fatal);
+
+    if (!stralloc_0(&line)) die_nomem(fatal);
+    result = PQexec(psql,line.s);
+    if (result == NULL)
+      strerr_die2x(111,fatal,PQerrorMessage(psql));
+    if (PQresultStatus(result) != PGRES_TUPLES_OK )
+      strerr_die2x(111,fatal,PQresultErrorMessage(result));
+
+    /* No data returned in QUERY */
+    if (PQntuples(result) < 1)
+      return (char *)0;
+
+    if (!stralloc_copyb(&line,PQgetvalue(result,0,0),PQgetlength(result,0,0)))
+       die_nomem(fatal);
+    if (!stralloc_0(&line)) die_nomem(fatal);
+
+    PQclear(result);
+    return line.s;
+  }
+}
+
diff --git a/sub_pgsql/logmsg.c b/sub_pgsql/logmsg.c
new file mode 100644 (file)
index 0000000..8f734ec
--- /dev/null
@@ -0,0 +1,83 @@
+/*$Id: logmsg.c,v 1.3 1999/12/23 02:40:57 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static stralloc logline = {0};
+static strnum[FMT_ULONG];
+
+char *logmsg(dir,num,listno,subs,done)
+/* creates an entry for message num and the list listno and code "done". */
+/* Returns NULL on success, "" if dir/sql was not found, and the error   */
+/* string on error.   NOTE: This routine does nothing for non-sql lists! */
+char *dir;
+unsigned long num;
+unsigned long listno;
+unsigned long subs;
+int done;
+{
+  char *table = (char *) 0;
+  char *ret;
+
+  PGresult *result;
+  PGresult *result2;
+
+  if ((ret = opensql(dir,&table))) {
+    if (*ret)
+      return ret;
+    else
+      return (char *) 0;       /* no SQL => success */
+  }
+  if (!stralloc_copys(&logline,"INSERT INTO ")) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,table)) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,"_mlog (msgnum,listno,subs,done) VALUES ("))
+       return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno)))
+       return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,subs))) return ERR_NOMEM;
+  if (!stralloc_cats(&logline,",")) return ERR_NOMEM;
+  if (done < 0) {
+    done = - done;
+    if (!stralloc_append(&logline,"-")) return ERR_NOMEM;
+  }
+  if (!stralloc_catb(&logline,strnum,fmt_uint(strnum,done))) return ERR_NOMEM;
+  if (!stralloc_append(&logline,")")) return ERR_NOMEM;
+
+  if (!stralloc_0(&logline)) return ERR_NOMEM;
+  result = PQexec(psql,logline.s);
+  if(result==NULL)
+    return (PQerrorMessage(psql));
+  if(PQresultStatus(result) != PGRES_COMMAND_OK) { /* Check if duplicate */
+    if (!stralloc_copys(&logline,"SELECT msgnum FROM ")) return ERR_NOMEM;
+    if (!stralloc_cats(&logline,table)) return ERR_NOMEM;
+    if (!stralloc_cats(&logline,"_mlog WHERE msgnum = ")) return ERR_NOMEM;
+    if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num)))
+      return ERR_NOMEM;
+    if (!stralloc_cats(&logline," AND listno = ")) return ERR_NOMEM;
+    if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno)))
+      return ERR_NOMEM;
+    if (!stralloc_cats(&logline," AND done = ")) return ERR_NOMEM;
+    if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,done)))
+      return ERR_NOMEM;
+    /* Query */
+    if (!stralloc_0(&logline)) return ERR_NOMEM;
+    result2 = PQexec(psql,logline.s);
+    if (result2 == NULL)
+      return (PQerrorMessage(psql));
+    if (PQresultStatus(result2) != PGRES_TUPLES_OK)
+      return (char *) (PQresultErrorMessage(result2));
+    /* No duplicate, return ERROR from first query */
+    if (PQntuples(result2)<1)
+      return (char *) (PQresultErrorMessage(result));
+    PQclear(result2);
+  }
+  PQclear(result);
+  return (char *) 0;
+}
diff --git a/sub_pgsql/opensql.c b/sub_pgsql/opensql.c
new file mode 100644 (file)
index 0000000..265822a
--- /dev/null
@@ -0,0 +1,111 @@
+/*$Id: opensql.c,v 1.4 1999/11/28 19:55:31 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <unistd.h>
+#include <libpq-fe.h> 
+
+static stralloc myp = {0};
+static stralloc ers = {0};
+static stralloc fn = {0};
+static stralloc ourdb = {0};
+static char *ourtable = (char *) 0;
+
+char *opensql(dbname,table)
+/* reads the file dbname/sql, and if the file exists, parses it into the    */
+/* components. The string should be host:port:user:pw:db:table.         If  */
+/* the file does not exists, returns "". On success returns NULL. On error  */
+/* returns error string for temporary error. If table is NULL it is         */
+/* left alone. If *table is not null, it overrides the table in the sql     */
+/* file. If we already opended dbname the cached info is used, rather than  */
+/* rereading the file. Note that myp is static and all pointers point to it.*/
+char *dbname;  /* database directory */
+char **table;  /* table root_name */
+
+{
+  char *host = (char *) 0;
+  char *port = (char *) 0;
+  char *db = "ezmlm";          /* default */
+  char *user = (char *) 0;
+  char *pw = (char *) 0;
+  unsigned int j;
+
+  if (!stralloc_copys(&fn,dbname)) return ERR_NOMEM;
+  if (fn.len == ourdb.len && !str_diffn(ourdb.s,fn.s,fn.len)) {
+    if (table) {
+      if (*table) ourtable = *table;
+      else *table = ourtable;
+    }
+    return 0;
+  }
+  if (!stralloc_cats(&fn,"/sql")) return ERR_NOMEM;
+  if (!stralloc_0(&fn)) return ERR_NOMEM;
+               /* host:port:db:table:user:pw:name */
+
+  myp.len = 0;
+  switch (slurp(fn.s,&myp,128)) {
+       case -1:        if (!stralloc_copys(&ers,ERR_READ)) return ERR_NOMEM;
+                       if (!stralloc_cat(&ers,&fn)) return ERR_NOMEM;
+                       if (!stralloc_0(&ers)) return ERR_NOMEM;
+                       return ers.s;
+       case 0: return "";
+  }
+  if (!stralloc_copy(&ourdb,&fn)) return ERR_NOMEM;
+  if (!stralloc_append(&myp,"\n")) return ERR_NOMEM;
+  for (j=0; j< myp.len; ++j) {
+    if (myp.s[j] == '\n') { myp.s[j] = '\0'; break; }
+  }
+                                               /* get connection parameters */
+  if (!stralloc_0(&myp)) return ERR_NOMEM;
+  host = myp.s;
+  if (myp.s[j = str_chr(myp.s,':')]) {
+    port = myp.s + j++;
+    *(port++) = '\0';
+    if (myp.s[j += str_chr(myp.s+j,':')]) {
+      user = myp.s + j++;
+      *(user++) = '\0';
+      if (myp.s[j += str_chr(myp.s+j,':')]) {
+        pw = myp.s + j++;
+       *(pw++) = '\0';
+       if (myp.s[j += str_chr(myp.s+j,':')]) {
+          db = myp.s + j++;
+         *(db++) = '\0';
+         if (myp.s[j += str_chr(myp.s+j,':')]) {
+           ourtable = myp.s + j++;
+           *(ourtable++) = '\0';
+         }
+       }
+      }
+    }
+  }
+
+  if (host && !*host) host = (char *) 0;
+  if (user && !*user) user = (char *) 0;
+  if (pw && !*pw) pw = (char *) 0;
+  if (db && !*db) db = (char *) 0;
+  if (ourtable && !*ourtable) ourtable = (char *) 0;
+  if (table) {
+    if (*table) ourtable = *table;
+    else *table = ourtable;
+    if (!*table) return ERR_NO_TABLE;
+  }
+  if (!psql) {
+    /* Make connection to database */
+    psql = PQsetdbLogin( host, port, NULL, NULL, db, user, pw);
+    /* Check  to see that the backend connection was successfully made */
+    if (PQstatus(psql) == CONNECTION_BAD)
+      return PQerrorMessage(psql);
+  }
+  return (char *) 0;
+}
+
+void closesql()
+/* close connection to SQL server, if open */
+{
+  if (psql) PQfinish(psql);
+  psql = (void *) 0; /* Destroy pointer */
+  return;
+}
+
diff --git a/sub_pgsql/putsubs.c b/sub_pgsql/putsubs.c
new file mode 100644 (file)
index 0000000..c53213c
--- /dev/null
@@ -0,0 +1,128 @@
+#include "error.h"
+#include "strerr.h"
+#include "readwrite.h"
+#include "str.h"
+#include "fmt.h"
+#include "stralloc.h"
+#include "open.h"
+#include "substdio.h"
+#include "case.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "qmail.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static substdio ssin;
+static char inbuf[512];
+char strnum[FMT_ULONG];
+static stralloc line = {0};
+static stralloc fn = {0};
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void die_write(fatal)
+char *fatal;
+{
+  strerr_die3x(111,fatal,ERR_WRITE,"stdout");
+}
+
+unsigned long putsubs(dbname,hash_lo,hash_hi,
+       subwrite,flagsql,fatal)
+/* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */
+/* that userhost is excluded. 'dbname' is the base directory name. For the  */
+/* mysql version, dbname is the directory where the file "sql" with mysql   */
+/* access info is found. If this file is not present or if flagmysql is not */
+/* set, the routine falls back to the old database style. subwrite must be a*/
+/* function returning >=0 on success, -1 on error, and taking arguments     */
+/* (char* string, unsigned int length). It will be called once per address  */
+/* and should take care of newline or whatever needed for the output form.  */
+
+char *dbname;          /* database base dir */
+unsigned long hash_lo;
+unsigned long hash_hi;
+int subwrite();                /* write function. */
+int flagsql;
+char *fatal;           /* fatal error string */
+
+{
+  PGresult *result;
+  int row_nr;
+  int length;
+  char *row;
+  char *table = (char *) 0;
+
+  unsigned int i;
+  int fd;
+  unsigned long no = 0L;
+  int match;
+  unsigned int hashpos;
+  char *ret = (char *) 0;
+
+  if (!flagsql || (ret = opensql(dbname,&table))) {
+    if (flagsql && *ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local db */
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal);
+                               /* NOTE: Also copies terminal '\0' */
+    hashpos = fn.len - 2;
+    if (hash_lo > 52) hash_lo = 52;
+    if (hash_hi > 52) hash_hi = 52;
+    if (hash_hi < hash_lo) hash_hi = hash_lo;
+
+    for (i = hash_lo;i <= hash_hi;++i) {
+      fn.s[hashpos] = 64 + i;  /* hash range 0-52 */
+      fd = open_read(fn.s);
+      if (fd == -1) {
+        if (errno != error_noent)
+         strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      } else {
+        substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+        for (;;) {
+          if (getln(&ssin,&line,&match,'\0') == -1)
+            strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+          if (!match)
+            break;
+          if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal);
+          no++;
+        }
+        close(fd);
+      }
+    }
+    return no;
+
+  } else {                                     /* SQL Version */
+
+                                               /* main query */
+    if (!stralloc_copys(&line,"SELECT address FROM "))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line," WHERE hash BETWEEN ")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_lo)))
+               die_nomem(fatal);
+    if (!stralloc_cats(&line," AND ")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_hi)))
+      die_nomem(fatal);
+    if (!stralloc_0(&line)) die_nomem(fatal);
+    result = PQexec(psql,line.s);
+    if (result == NULL)
+      strerr_die2x(111,fatal,PQerrorMessage(psql));
+    if (PQresultStatus(result) != PGRES_TUPLES_OK)
+      strerr_die2x(111,fatal,PQresultErrorMessage(result));
+
+    no = 0;
+    for (row_nr=0;row_nr<PQntuples(result);row_nr++) {
+      /* this is safe even if someone messes with the address field def */
+      length = PQgetlength(result,row_nr,0);
+      row = PQgetvalue(result,row_nr,0);
+      if (subwrite(row,length) == -1) die_write(fatal);
+      no++;                                    /* count for list-list fxn */
+    }
+    PQclear(result);
+    return no;
+  }
+}
diff --git a/sub_pgsql/searchlog.c b/sub_pgsql/searchlog.c
new file mode 100644 (file)
index 0000000..efbad0a
--- /dev/null
@@ -0,0 +1,166 @@
+/*$Id: searchlog.c,v 1.2 1999/10/07 23:31:01 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "case.h"
+#include "scan.h"
+#include "stralloc.h"
+#include "str.h"
+#include "open.h"
+#include "datetime.h"
+#include "date822fmt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "error.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static stralloc line = {0};
+static stralloc outline = {0};
+static date[DATE822FMT];
+static datetime_sec when;
+static struct datetime dt;
+static substdio ssin;
+static char inbuf[256];
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void lineout(subwrite,fatal)
+int subwrite();
+char *fatal;
+{
+  (void) scan_ulong(line.s,&when);
+  datetime_tai(&dt,when);              /* there is always at least a '\n' */
+  if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1))
+       die_nomem(fatal);
+  if (!stralloc_cats(&outline,": ")) die_nomem(fatal);
+  if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal);
+  if (subwrite(outline.s,outline.len) == -1)
+       strerr_die3x(111,fatal,ERR_WRITE,"output");
+  return;
+}
+
+void searchlog(dir,search,subwrite,fatal)
+/* opens dir/Log, and outputs via subwrite(s,len) any line that matches   */
+/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */
+/* is replaced by a '_'. mysql version. Falls back on "manual" search of  */
+/* local Log if no mysql connect info. */
+
+char *dir;             /* work directory */
+char *search;          /* search string */
+int subwrite();                /* output fxn */
+char *fatal;           /* fatal */
+{
+
+  register unsigned char x;
+  register unsigned char y;
+  register unsigned char *cp;
+  register unsigned char *cpsearch;
+  unsigned register char *cps;
+  unsigned register char ch;
+  unsigned char *cplast, *cpline;
+  unsigned int searchlen;
+  int fd,match;
+  char *ret;
+
+  PGresult *result;
+  int row_nr;
+  int length;
+  char *row;
+
+  char *table = (char *) 0;
+
+  if (!search) search = "";    /* defensive */
+  searchlen = str_len(search);
+  case_lowerb(search,searchlen);
+  cps = (unsigned char *) search;
+  while ((ch = *(cps++))) {    /* search is potentially hostile */
+    if (ch >= 'a' && ch <= 'z') continue;
+    if (ch >= '0' && ch <= '9') continue;
+    if (ch == '.' || ch == '_') continue;
+    *(cps - 1) = '_';          /* will match char specified as well */
+  }
+
+  if ((ret = opensql(dir,&table))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+                                               /* fallback to local log */
+  if (!stralloc_copys(&line,dir)) die_nomem(fatal);
+  if (!stralloc_cats(&line,"/Log")) die_nomem(fatal);
+  if (!stralloc_0(&line)) die_nomem(fatal);
+  fd = open_read(line.s);
+  if (fd == -1)
+    if (errno != error_noent)
+       strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    else
+        strerr_die3x(100,fatal,line.s,ERR_NOEXIST);
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,fatal,ERR_READ_INPUT);
+    if (!match) break;
+    if (!searchlen) {
+      lineout(subwrite,fatal);
+    } else {
+      cpline = (unsigned char *) line.s - 1;
+      cplast = cpline + line.len - searchlen; /* line has \0 at the end */
+      while ((cp = ++cpline) <= cplast) {
+       cpsearch = (unsigned char *) search;
+       for (;;) {
+         x = *cpsearch++;
+         if (!x) break;
+         y = *cp++ - 'A';
+         if (y <= (unsigned char) ('Z' - 'A')) y += 'a'; else y += 'A';
+         if (x != y && x != '_') break;                /* '_' = wildcard */
+       }
+       if (!x) {
+         lineout(subwrite,fatal);
+         break;
+       }
+      }
+    }
+  }
+  close(fd);
+  } else {
+
+/* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address   */
+/* LIKE '%search%' ORDER BY tai; */
+/* The '*' is formatted to look like the output of the non-mysql version */
+/* This requires reading the entire table, since search fields are not   */
+/* indexed, but this is a rare query and time is not of the essence.     */
+       
+    if (!stralloc_cats(&line,"SELECT tai::datetime||': '||tai::int8||' '"
+    "||address||' '||edir||etype||' '||fromline FROM ")) die_nomem(fatal);
+
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"_slog ")) die_nomem(fatal);
+    if (*search) {     /* We can afford to wait for LIKE '%xx%' */
+      if (!stralloc_cats(&line,"WHERE fromline LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%' OR address LIKE '%")) die_nomem(fatal);
+      if (!stralloc_cats(&line,search)) die_nomem(fatal);
+      if (!stralloc_cats(&line,"%'")) die_nomem(fatal);
+    }  /* ordering by tai which is an index */
+    if (!stralloc_cats(&line," ORDER by tai")) die_nomem(fatal);
+      
+    if (!stralloc_0(&line)) die_nomem(fatal);  
+    result = PQexec(psql,line.s);
+    if (result == NULL)
+      strerr_die2x(111,fatal,PQerrorMessage(psql));
+    if (PQresultStatus(result) != PGRES_TUPLES_OK)
+      strerr_die2x(111,fatal,PQresultErrorMessage(result));
+    
+    for(row_nr=0; row_nr<PQntuples(result); row_nr++) {
+      row = PQgetvalue(result,row_nr,0);
+      length = PQgetlength(result,row_nr,0);
+      if (subwrite(row,length) == -1) die_write(fatal);
+    }
+    PQclear(result);
+       
+  }
+}
diff --git a/sub_pgsql/subscribe.c b/sub_pgsql/subscribe.c
new file mode 100644 (file)
index 0000000..3237be1
--- /dev/null
@@ -0,0 +1,371 @@
+/*$Id: subscribe.c,v 1.3 1999/10/07 23:31:01 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "strerr.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "lock.h"
+#include "error.h"
+#include "subscribe.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "log.h"
+#include "idx.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc domain = {0};
+static stralloc logline = {0};
+static stralloc fnnew = {0};
+static stralloc fn = {0};
+static stralloc fnlock = {0};
+
+void die_read(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+}
+
+void die_write(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_WRITE,fnnew.s,": ");
+}
+
+static int fd;
+static substdio ss;
+static char ssbuf[256];
+static int fdnew;
+static substdio ssnew;
+static char ssnewbuf[256];
+
+int subscribe(dbname,userhost,flagadd,comment,event,flagsql,
+       forcehash,tab,fatal)
+/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database  */
+/* dbname. Comment is e.g. the subscriber from line or name. It is added to  */
+/* the log. Event is the action type, e.g. "probe", "manual", etc. The       */
+/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0   */
+/* on failure. If flagmysql is set and the file "sql" is found in the        */
+/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
+/* >=0 it is used in place of the calculated hash. This makes it possible to */
+/* add addresses with a hash that does not exist. forcehash has to be 0..99. */
+/* for unsubscribes, the address is only removed if forcehash matches the    */
+/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
+/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
+/* used for sublist addresses (to avoid removal) and sublist aliases (to     */
+/* prevent users from subscribing them (although the cookie mechanism would  */
+/* prevent the resulting duplicate message from being distributed. */
+
+char *dbname;
+char *userhost;
+int flagadd;
+char *comment;
+char *event;
+int flagsql;
+int forcehash;
+char *tab;
+char *fatal;
+{
+  int fdlock;
+
+  PGresult *result;
+
+  char *cpat;
+  char szhash[3] = "00";
+  char *r = (char *) 0;
+  char *table = (char *) 0;
+  char **ptable = &table;
+
+  unsigned int j;
+  uint32 h,lch;
+  unsigned char ch,lcch;
+  int match;
+  int flagwasthere;
+
+  if (userhost[str_chr(userhost,'\n')])
+    strerr_die2x(100,fatal,ERR_ADDR_NL);
+
+  if (tab) ptable = &tab;
+
+  if (!flagsql || (r = opensql(dbname,ptable))) {
+    if (r && *r) strerr_die2x(111,fatal,r);
+                                               /* fallback to local db */
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+    if (addr.len > 401)
+      strerr_die2x(100,fatal,ERR_ADDR_LONG);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len)
+      strerr_die2x(100,fatal,ERR_ADDR_AT);
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* make all-lc version of address */
+
+    if (forcehash >= 0 && forcehash <= 52) {
+      ch = lcch = (unsigned char) forcehash;
+    } else {
+      h = 5381;
+      lch = h;
+      for (j = 0;j < addr.len;++j) {
+        h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+        lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+      }
+      lcch = 64 + (lch % 53);
+      ch = 64 + (h % 53);
+    }
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_copys(&fnlock,dbname)) die_nomem(fatal);
+
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_copy(&fnnew,&fn)) die_nomem(fatal);
+       /* code later depends on fnnew = fn + 'n' */
+    if (!stralloc_cats(&fnnew,"n")) die_nomem(fatal);
+    if (!stralloc_cats(&fnlock,"/lock")) die_nomem(fatal);
+    if (!stralloc_0(&fnnew)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+    if (!stralloc_0(&fnlock)) die_nomem(fatal);
+
+    fdlock = open_append(fnlock.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,fatal,ERR_OPEN,fnlock.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,fatal,ERR_OBTAIN,fnlock.s,": ");
+
+                               /* do lower case hashed version first */
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    flagwasthere = 0;
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    }
+    else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1) {
+         close(fd); close(fdnew); die_read(fatal);
+        }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+           flagwasthere = 1;
+           if (!flagadd)
+             continue;
+         }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1) {
+         close(fd); close(fdnew); die_write(fatal);
+        }
+      }
+
+      close(fd);
+    }
+
+    if (flagadd && !flagwasthere)
+      if (substdio_bput(&ssnew,addr.s,addr.len) == -1) {
+        close(fdnew); die_write(fatal);
+      }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    if ((ch == lcch) || flagwasthere) {
+      close(fdlock);
+      if (flagadd ^ flagwasthere) {
+        if (!stralloc_0(&addr)) die_nomem(fatal);
+        log(dbname,event,addr.s+1,comment);
+        return 1;
+      }
+      return 0;
+    }
+
+                       /* If unsub and not found and hashed differ, OR */
+                       /* sub and not found (so added with new hash) */
+                       /* do the 'case-dependent' hash */
+
+    fn.s[fn.len - 2] = ch;
+    fnnew.s[fnnew.len - 3] = ch;
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          { close(fd); close(fdnew); die_read(fatal); }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+            flagwasthere = 1;
+            continue;  /* always want to remove from case-sensitive hash */
+          }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1)
+          { close(fd); close(fdnew); die_write(fatal); }
+      }
+
+      close(fd);
+    }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    close(fdlock);
+    if (flagadd ^ flagwasthere) {
+      if (!stralloc_0(&addr)) die_nomem(fatal);
+      log(dbname,event,addr.s+1,comment);
+      return 1;
+    }
+    return 0;
+
+  } else {                             /* SQL version */
+    domain.len = 0;                    /* clear domain */
+                                       /* lowercase and check address */
+    if (!stralloc_copys(&addr,userhost)) die_nomem(fatal);
+    if (addr.len > 255)                        /* this is 401 in std ezmlm. 255 */
+                                       /* should be plenty! */
+      strerr_die2x(100,fatal,ERR_ADDR_LONG);
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len)
+      strerr_die2x(100,fatal,ERR_ADDR_AT);
+    cpat = addr.s + j;
+    case_lowerb(cpat + 1,addr.len - j - 1);
+
+    if (forcehash < 0) {
+      if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+      case_lowerb(lcaddr.s,j);         /* make all-lc version of address */
+      h = 5381;
+      for (j = 0;j < lcaddr.len;++j) {
+        h = (h + (h << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+      }
+      ch = (h % 53);                   /* 0 - 52 */
+    } else
+      ch = (forcehash % 100);
+
+    szhash[0] = '0' + ch / 10;         /* hash for sublist split */
+    szhash[1] = '0' + (ch % 10);
+
+    if (flagadd) {
+      if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);
+      if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal);
+      if (!stralloc_cat(&line,&addr)) die_nomem(fatal);        /* addr */
+      if (!stralloc_cats(&line,"$'")) die_nomem(fatal);
+      if (!stralloc_0(&line)) die_nomem(fatal);
+      result = PQexec(psql,line.s);
+      if (result == NULL)
+       strerr_die2x(111,fatal,PQerrorMessage(psql));
+      if (PQresultStatus(result) != PGRES_TUPLES_OK)
+       strerr_die2x(111,fatal,PQresultErrorMessage(result));
+
+      if (PQntuples(result)>0) {                       /* there */
+       PQclear(result);
+        return 0;                                              /* there */
+      } else {                                                 /* not there */
+       PQclear(result);
+       if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal);
+       if (!stralloc_cats(&line,table)) die_nomem(fatal);
+       if (!stralloc_cats(&line," (address,hash) VALUES ('"))
+               die_nomem(fatal);
+       if (!stralloc_cat(&line,&addr)) die_nomem(fatal);       /* addr */
+       if (!stralloc_cats(&line,"',")) die_nomem(fatal);
+       if (!stralloc_cats(&line,szhash)) die_nomem(fatal);     /* hash */
+       if (!stralloc_cats(&line,")")) die_nomem(fatal);
+       if (!stralloc_0(&line)) die_nomem(fatal);
+       result = PQexec(psql,line.s);
+       if (result == NULL)
+         strerr_die2x(111,fatal,PQerrorMessage(psql));
+       if (PQresultStatus(result) != PGRES_COMMAND_OK)
+         strerr_die2x(111,fatal,PQresultErrorMessage(result));
+      }
+    } else {                                                   /* unsub */
+      if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);
+      if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal);
+      if (!stralloc_cat(&line,&addr)) die_nomem(fatal);        /* addr */
+      if (forcehash >= 0) {
+       if (!stralloc_cats(&line,"$' AND hash=")) die_nomem(fatal);
+       if (!stralloc_cats(&line,szhash)) die_nomem(fatal);
+      } else {
+        if (!stralloc_cats(&line,"$' AND hash BETWEEN 0 AND 52"))
+               die_nomem(fatal);
+      }
+      
+      if (!stralloc_0(&line)) die_nomem(fatal);
+      result = PQexec(psql,line.s);
+      if (result == NULL)
+       strerr_die2x(111,fatal,PQerrorMessage(psql));
+      if (PQresultStatus(result) != PGRES_COMMAND_OK)
+       strerr_die2x(111,fatal,PQresultErrorMessage(result));
+      if (atoi(PQcmdTuples(result))<1)
+       return 0;                               /* address wasn't there*/
+      PQclear(result);
+    }
+
+               /* log to subscriber log */
+               /* INSERT INTO t_slog (address,edir,etype,fromline) */
+               /* VALUES('address',{'+'|'-'},'etype','[comment]') */
+
+    if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem(fatal);
+    if (!stralloc_cats(&logline,table)) die_nomem(fatal);
+    if (!stralloc_cats(&logline,
+       "_slog (address,edir,etype,fromline) VALUES ('")) die_nomem(fatal);
+    if (!stralloc_cat(&logline,&addr)) die_nomem(fatal);
+    if (flagadd) {                                             /* edir */
+      if (!stralloc_cats(&logline,"','+','")) die_nomem(fatal);
+    } else {
+      if (!stralloc_cats(&logline,"','-','")) die_nomem(fatal);
+    }
+    if (*(event + 1))  /* ezmlm-0.53 uses '' for ezmlm-manage's work */
+      if (!stralloc_catb(&logline,event+1,1)) die_nomem(fatal);        /* etype */
+    if (!stralloc_cats(&logline,"','")) die_nomem(fatal);
+    if (comment && *comment) {
+      if (!stralloc_cats(&logline,comment)) die_nomem(fatal);
+    }
+    if (!stralloc_cats(&logline,"')")) die_nomem(fatal);
+
+    if (!stralloc_0(&logline)) die_nomem(fatal);
+    result = PQexec(psql,logline.s);           /* log (ignore errors) */
+    PQclear(result);
+
+    if (!stralloc_0(&addr))
+               ;                               /* ignore errors */
+    log(dbname,event,addr.s,comment);          /* also log to old log */
+    return 1;                                  /* desired effect */
+  }
+}
diff --git a/sub_pgsql/tagmsg.c b/sub_pgsql/tagmsg.c
new file mode 100644 (file)
index 0000000..a99797a
--- /dev/null
@@ -0,0 +1,115 @@
+/*$Id: tagmsg.c,v 1.2 1999/10/07 23:31:01 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "strerr.h"
+#include "cookie.h"
+#include "slurp.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "makehash.h"
+#include <unistd.h>
+#include <libpq-fe.h>
+
+static stralloc line = {0};
+static stralloc key = {0};
+static char hash[COOKIE];
+static char strnum[FMT_ULONG]; /* message number as sz */
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(100,fatal,ERR_NOMEM);
+}
+
+void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal)
+/* This routine creates a cookie from num,seed and the */
+/* list key and returns that cookie in hashout. The use of sender/num and */
+/* first char of action is used to make cookie differ between messages,   */
+/* the key is the secret list key. The cookie will be inserted into       */
+/* table_cookie where table and other data is taken from dir/sql. We log  */
+/* arrival of the message (done=0). */
+
+char *dir;                     /* db base dir */
+unsigned long msgnum;          /* number of this message */
+char *seed;                    /* seed. NULL ok, but less entropy */
+char *action;                  /* to make it certain the cookie differs from*/
+                               /* one used for a digest */
+char *hashout;                 /* calculated hash goes here */
+unsigned long bodysize;
+unsigned long chunk;
+char *fatal;
+{
+  PGresult *result;
+  PGresult *result2; /* Need for dupicate check */
+  char *table = (char *) 0;
+  char *ret;
+  unsigned int i;
+
+  strnum[fmt_ulong(strnum,msgnum)] = '\0';     /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+      case -1:
+       strerr_die3sys(111,fatal,ERR_READ,"key: ");
+      case 0:
+       strerr_die3x(100,fatal,"key",ERR_NOEXIST);
+    }
+    cookie(hash,key.s,key.len,strnum,seed,action);
+    for (i = 0; i < COOKIE; i++)
+      hashout[i] = hash[i];
+
+  if ((ret = opensql(dir,&table))) {
+    if (*ret) strerr_die2x(111,fatal,ret);
+    return;                            /* no sql => success */
+
+  } else {
+    if (chunk >= 53L) chunk = 0L;      /* sanity */
+
+       /* INSERT INTO table_cookie (msgnum,cookie) VALUES (num,cookie) */
+       /* (we may have tried message before, but failed to complete, so */
+       /* ER_DUP_ENTRY is ok) */
+    if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal);
+    if (!stralloc_cats(&line,table)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"_cookie (msgnum,cookie,bodysize,chunk) VALUES ("))
+      die_nomem(fatal);
+    if (!stralloc_cats(&line,strnum)) die_nomem(fatal);
+    if (!stralloc_cats(&line,",'")) die_nomem(fatal);
+    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(fatal);
+    if (!stralloc_cats(&line,"',")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,bodysize)))
+      die_nomem(fatal);
+    if (!stralloc_cats(&line,",")) die_nomem(fatal);
+    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,chunk))) die_nomem(fatal);
+    if (!stralloc_cats(&line,")")) die_nomem(fatal);
+    
+    if (!stralloc_0(&line)) die_nomem(fatal);
+    result = PQexec(psql,line.s);
+    if (result == NULL)
+      strerr_die2x(111,fatal,PQerrorMessage(psql));
+    if (PQresultStatus(result) != PGRES_COMMAND_OK) { /* Possible tuplicate */
+      if (!stralloc_copys(&line,"SELECT msgnum FROM ")) die_nomem(fatal);
+      if (!stralloc_cats(&line,table)) die_nomem(fatal);         
+      if (!stralloc_cats(&line,"_cookie WHERE msgnum = ")) die_nomem(fatal);
+      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) 
+       die_nomem(fatal);
+      /* Query */
+      if (!stralloc_0(&line)) die_nomem(fatal);
+      result2 = PQexec(psql,line.s);
+      if (result2 == NULL)
+       strerr_die2x(111,fatal,PQerrorMessage(psql));
+      if (PQresultStatus(result2) != PGRES_TUPLES_OK)
+       strerr_die2x(111,fatal,PQresultErrorMessage(result2));
+      /* No duplicate, return ERROR from first query */
+      if (PQntuples(result2)<1) 
+       strerr_die2x(111,fatal,PQresultErrorMessage(result));
+      PQclear(result2);
+    }
+    PQclear(result);
+
+    if (! (ret = logmsg(dir,msgnum,0L,0L,1))) return;  /* log done=1*/
+    if (*ret) strerr_die2x(111,fatal,ret);
+  }
+
+  return;
+}
diff --git a/sub_std/README b/sub_std/README
new file mode 100644 (file)
index 0000000..d721a22
--- /dev/null
@@ -0,0 +1,31 @@
+$Id: README,v 1.2 1999/02/20 20:03:11 lindberg Exp $
+$Name: ezmlm-idx-040 $
+STANDARD EZMLM DATABASE INTERFACE
+
+These files comprise the ezmlm subscriber database interface. issub.c and
+subscribe.c are backwards compatible with ezmlm-0.53 in terms of function,
+but use a case-insensitive hash for address storage, and take a few
+extra args to be plug-in compatible with alternative interfaces. Logging to
+the subscriber log (DIR/Log) is done from subscribe.c rather than externally,
+and the subscriber from line is logged as well.
+
+searchlog.c allows access to DIR/Log.
+
+putsubs.c does all output of subscriber addresses, both to qmail for subscibers,
+moderator sendouts, etc, and to list subscribers in reply to the -list command.
+
+Alternative subscriber db interface routines should perform equivalent services,
+and fall back to these services if the alternative interface is not configured,
+e.g. if DIR/sql doe not exist.
+
+HOW TO SET UP A CLUSTER OF LIST AND SUBLISTS WITH STD DBS
+
+See FAQ.idx.
+
+See SQL-enabled ezmlm list documentation in FAQ.idx for a different
+trade-off between these points.
+
+
+
+
+
diff --git a/sub_std/checktag.c b/sub_std/checktag.c
new file mode 100644 (file)
index 0000000..f84350a
--- /dev/null
@@ -0,0 +1,46 @@
+/*$Id: checktag.c,v 1.4 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "cookie.h"
+#include "makehash.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+
+static stralloc key = {0};
+static stralloc line = {0};
+static stralloc quoted = {0};
+static char strnum[FMT_ULONG];
+static char newcookie[COOKIE];
+
+char *checktag (dir,num,listno,action,seed,hash)
+/* reads dir/sql. If not present, checks that the hash of seed matches */
+/* hash and returns success (NULL). If not match returns "". If error, */
+/* returns error string */
+
+char *dir;                             /* the db base dir */
+unsigned long num;                     /* message number */
+unsigned long listno;                  /* bottom of range => slave */
+char *action;
+char *seed;                            /* cookie base */
+char *hash;                            /* cookie */
+{
+
+    if (!seed) return (char *) 0;              /* no data - accept */
+
+    strnum[fmt_ulong(strnum,num)] = '\0';      /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+      case -1:
+       return ERR_READ_KEY;
+      case 0:
+       return ERR_NOEXIST_KEY;
+    }
+
+    cookie(newcookie,key.s,key.len,strnum,seed,action);
+    if (byte_diff(hash,COOKIE,newcookie)) return "";
+    else return (char *) 0;
+
+}
diff --git a/sub_std/conf-sqlcc b/sub_std/conf-sqlcc
new file mode 100644 (file)
index 0000000..ce074b1
--- /dev/null
@@ -0,0 +1,4 @@
+
+
+# the top line will be used when compiling. This version is for
+# linking without mysql support.
diff --git a/sub_std/conf-sqlld b/sub_std/conf-sqlld
new file mode 100644 (file)
index 0000000..dcfa3d1
--- /dev/null
@@ -0,0 +1,4 @@
+
+
+# the top line will be used when linking. This version is for
+# linking without mysql support.
diff --git a/sub_std/ezmlm-mktab b/sub_std/ezmlm-mktab
new file mode 100755 (executable)
index 0000000..828448a
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+echo
+echo "This is the standard database version. You do not need to"
+echo "create any separate databases for this version."
+echo
+exit 1
+
diff --git a/sub_std/issub.c b/sub_std/issub.c
new file mode 100644 (file)
index 0000000..22e6367
--- /dev/null
@@ -0,0 +1,120 @@
+/*$Id: issub.c,v 1.4 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "strerr.h"
+#include "error.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc quoted = {0};
+static stralloc fn = {0};
+static substdio ss;
+static char ssbuf[512];
+static char szh[FMT_ULONG];
+
+char *issub(dbname,userhost,tab,fatal)
+/* Returns (char *) to match if userhost is in the subscriber database     */
+/* dbname, 0 otherwise. dbname is a base directory for a list and may NOT  */
+/* be NULL        */
+/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/
+
+char *dbname;          /* directory to basedir */
+char *userhost;
+char *tab;             /* override table name */
+char *fatal;
+
+{
+
+  int fd;
+  unsigned int j;
+  uint32 h,lch;
+  char ch,lcch;
+  int match;
+
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len) return (char *) 0;
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* totally lc version of addr */
+
+    h = 5381;
+    lch = h;                   /* make hash for both for backwards comp */
+    for (j = 0;j < addr.len;++j) {     /* (lcaddr.len == addr.len) */
+      h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+      lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+    }
+    ch = 64 + (h % 53);
+    lcch = 64 + (lch % 53);
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+        if (!match) break;
+        if (line.len == lcaddr.len)
+          if (!case_diffb(line.s,line.len,lcaddr.s))
+            { close(fd); return line.s+1; }
+      }
+
+      close(fd);
+    }
+       /* here if file not found or (file found && addr not there) */
+
+    if (ch == lcch) return (char *) 0;
+
+       /* try case sensitive hash for backwards compatibility */
+    fn.s[fn.len - 2] = ch;
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent)
+        strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": ");
+      return (char *) 0;
+    }
+    substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+    for (;;) {
+      if (getln(&ss,&line,&match,'\0') == -1)
+        strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      if (!match) break;
+      if (line.len == addr.len)
+        if (!case_diffb(line.s,line.len,addr.s))
+          { close(fd); return line.s+1; }
+    }
+
+    close(fd);
+
+    return (char *) 0;
+}
diff --git a/sub_std/logmsg.c b/sub_std/logmsg.c
new file mode 100644 (file)
index 0000000..594a96a
--- /dev/null
@@ -0,0 +1,19 @@
+/*$Id: logmsg.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "fmt.h"
+#include "subscribe.h"
+#include "errtxt.h"
+
+static stralloc logline = {0};
+static strnum[FMT_ULONG];
+
+char *logmsg(dir,num,listno,subs,done)
+char *dir;
+unsigned long num;
+unsigned long listno;
+unsigned long subs;
+int done;
+{
+      return (char *) 0;       /* no SQL => success */
+}
diff --git a/sub_std/opensql.c b/sub_std/opensql.c
new file mode 100644 (file)
index 0000000..9601da3
--- /dev/null
@@ -0,0 +1,27 @@
+/*$Id: opensql.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "strerr.h"
+#include "errtxt.h"
+#include "subscribe.h"
+
+static stralloc myp = {0};
+static stralloc ers = {0};
+static stralloc fn = {0};
+static stralloc ourdb = {0};
+static char *ourtable = (char *) 0;
+
+char *opensql(dbname,table)
+char *dbname;  /* database directory */
+char **table;  /* table root_name */
+
+{
+       return 0;
+}
+
+void closesql()
+/* close connection to SQL server, if open */
+{
+       return;
+}
+
diff --git a/sub_std/putsubs.c b/sub_std/putsubs.c
new file mode 100644 (file)
index 0000000..d3de6bc
--- /dev/null
@@ -0,0 +1,86 @@
+#include "error.h"
+#include "strerr.h"
+#include "readwrite.h"
+#include "str.h"
+#include "fmt.h"
+#include "stralloc.h"
+#include "open.h"
+#include "substdio.h"
+#include "case.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "qmail.h"
+
+static substdio ssin;
+static char inbuf[512];
+char strnum[FMT_ULONG];
+static stralloc line = {0};
+static stralloc domains = {0};
+static stralloc quoted = {0};
+static stralloc fn = {0};
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static void die_write(fatal)
+char *fatal;
+{
+  strerr_die3x(111,fatal,ERR_WRITE,"stdout");
+}
+
+unsigned long putsubs(dbname,hash_lo,hash_hi,
+       subwrite,flagsql,fatal)
+/* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */
+/* that userhost is excluded. 'dbname' is the base directory name. */
+/* subwrite must be a*/
+/* function returning >=0 on success, -1 on error, and taking arguments     */
+/* (char* string, unsigned int length). It will be called once per address  */
+/* and should take care of newline or whatever needed for the output form.  */
+
+char *dbname;          /* database base dir */
+unsigned long hash_lo;
+unsigned long hash_hi;
+int subwrite();                /* write function. */
+int flagsql;
+char *fatal;           /* fatal error string */
+
+{
+
+  unsigned int i;
+  int fd;
+  unsigned long no = 0L;
+  int match;
+  unsigned int hashpos;
+
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal);
+                               /* NOTE: Also copies terminal '\0' */
+    hashpos = fn.len - 2;
+    if (hash_lo > 52) hash_lo = 52;
+    if (hash_hi > 52) hash_hi = 52;
+    if (hash_hi < hash_lo) hash_hi = hash_lo;
+
+    for (i = hash_lo;i <= hash_hi;++i) {
+      fn.s[hashpos] = 64 + i;  /* hash range 0-52 */
+      fd = open_read(fn.s);
+      if (fd == -1) {
+        if (errno != error_noent)
+         strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+      } else {
+        substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+        for (;;) {
+          if (getln(&ssin,&line,&match,'\0') == -1)
+            strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+          if (!match)
+            break;
+          if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal);
+          no++;
+        }
+        close(fd);
+      }
+    }
+    return no;
+}
diff --git a/sub_std/searchlog.c b/sub_std/searchlog.c
new file mode 100644 (file)
index 0000000..1cee6f9
--- /dev/null
@@ -0,0 +1,114 @@
+/*$Id: searchlog.c,v 1.6 1999/10/09 14:22:38 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "case.h"
+#include "scan.h"
+#include "stralloc.h"
+#include "str.h"
+#include "open.h"
+#include "datetime.h"
+#include "date822fmt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "strerr.h"
+#include "error.h"
+#include "errtxt.h"
+#include "subscribe.h"
+
+static stralloc line = {0};
+static stralloc outline = {0};
+static char date[DATE822FMT];
+static datetime_sec when;
+static struct datetime dt;
+static substdio ssin;
+static char inbuf[256];
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(100,fatal,ERR_NOMEM);
+}
+
+static void lineout(subwrite,fatal)
+int subwrite();
+char *fatal;
+{
+  (void) scan_ulong(line.s,&when);
+  datetime_tai(&dt,when);              /* there is always at least a '\n' */
+  if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1))
+       die_nomem(fatal);
+  if (!stralloc_cats(&outline,": ")) die_nomem(fatal);
+  if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal);
+  if (subwrite(outline.s,outline.len) == -1)
+       strerr_die3x(111,fatal,ERR_WRITE,"output");
+  return;
+}
+
+void searchlog(dir,search,subwrite,fatal)
+/* opens dir/Log, and outputs via subwrite(s,len) any line that matches */
+/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */
+/* is replaced by a '_' */
+
+char *dir;             /* work directory */
+char *search;          /* search string */
+int subwrite();                /* output fxn */
+char *fatal;           /* fatal */
+{
+
+  register unsigned char x;
+  register unsigned char y;
+  register unsigned char *cp;
+  register unsigned char *cpsearch;
+  unsigned register char *cps;
+  unsigned register char ch;
+  unsigned char *cplast, *cpline;
+  unsigned int searchlen;
+  int fd,match;
+
+  searchlen = str_len(search);
+  case_lowerb(search,searchlen);
+  cps = (unsigned char *) search;
+  while ((ch = *(cps++))) {            /* search is potentially hostile */
+    if (ch >= 'a' && ch <= 'z') continue;
+    if (ch >= '0' && ch <= '9') continue;
+    if (ch == '.' || ch == '_') continue;
+    *(cps - 1) = '_';                  /* will [also] match char specified */
+  }
+
+  if (!stralloc_copys(&line,dir)) die_nomem(fatal);
+  if (!stralloc_cats(&line,"/Log")) die_nomem(fatal);
+  if (!stralloc_0(&line)) die_nomem(fatal);
+  fd = open_read(line.s);
+  if (fd == -1)
+    if (errno != error_noent)
+       strerr_die4sys(111,fatal,ERR_OPEN,line.s,": ");
+    else
+        strerr_die3x(100,fatal,line.s,ERR_NOEXIST);
+  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
+
+  for (;;) {
+    if (getln(&ssin,&line,&match,'\n') == -1)
+      strerr_die2sys(111,fatal,ERR_READ_INPUT);
+    if (!match) break;
+    if (!searchlen) {
+      lineout(subwrite,fatal);
+    } else {           /* simple case-insensitive search */
+      cpline = (unsigned char *) line.s - 1;
+      cplast = cpline + line.len - searchlen; /* line has \0 at the end */
+      while ((cp = ++cpline) <= cplast) {
+       cpsearch = (unsigned char *) search;
+       for (;;) {
+         x = *cpsearch++;
+         if (!x) break;
+         y = *cp++ - 'A';
+         if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+         if (x != y && x != '_') break;                /* '_' = wildcard */
+       }
+       if (!x) {
+         lineout(subwrite,fatal);
+         break;
+       }
+      }
+    }
+  }
+  close(fd);
+}
diff --git a/sub_std/subscribe.c b/sub_std/subscribe.c
new file mode 100644 (file)
index 0000000..278bc8e
--- /dev/null
@@ -0,0 +1,244 @@
+/*$Id: subscribe.c,v 1.5 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "getln.h"
+#include "readwrite.h"
+#include "substdio.h"
+#include "strerr.h"
+#include "open.h"
+#include "byte.h"
+#include "case.h"
+#include "lock.h"
+#include "error.h"
+#include "subscribe.h"
+#include "uint32.h"
+#include "fmt.h"
+#include "errtxt.h"
+#include "log.h"
+#include "idx.h"
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(111,fatal,ERR_NOMEM);
+}
+
+static stralloc addr = {0};
+static stralloc lcaddr = {0};
+static stralloc line = {0};
+static stralloc domain = {0};
+static stralloc logline = {0};
+static stralloc quoted = {0};
+static stralloc fnnew = {0};
+static stralloc fn = {0};
+static stralloc fnlock = {0};
+static char szh[FMT_ULONG];
+
+void die_read(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_READ,fn.s,": ");
+}
+
+void die_write(fatal)
+char *fatal;
+{
+  strerr_die4sys(111,fatal,ERR_WRITE,fnnew.s,": ");
+}
+
+static int fd;
+static substdio ss;
+static char ssbuf[256];
+static int fdnew;
+static substdio ssnew;
+static char ssnewbuf[256];
+
+int subscribe(dbname,userhost,flagadd,comment,event,flagmysql,
+       forcehash,tab,fatal)
+/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database  */
+/* dbname. Comment is e.g. the subscriber from line or name. It is added to  */
+/* the log. Event is the action type, e.g. "probe", "manual", etc. The       */
+/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0   */
+/* on failure. If flagmysql is set and the file "sql" is found in the        */
+/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
+/* >=0 it is used in place of the calculated hash. This makes it possible to */
+/* add addresses with a hash that does not exist. forcehash has to be 0..99. */
+/* for unsubscribes, the address is only removed if forcehash matches the    */
+/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
+/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
+/* used for sublist addresses (to avoid removal) and sublist aliases (to     */
+/* prevent users from subscribing them (although the cookie mechanism would  */
+/* prevent the resulting duplicate message from being distributed. */
+
+char *dbname;
+char *userhost;
+int flagadd;
+char *comment;
+char *event;
+int flagmysql;
+int forcehash;
+char *tab;
+char *fatal;
+{
+  int fdlock;
+
+  char szhash[3] = "00";
+
+  unsigned int j;
+  uint32 h,lch;
+  unsigned char ch,lcch;
+  int match;
+  int flagwasthere;
+
+  if (userhost[str_chr(userhost,'\n')])
+    strerr_die2x(100,fatal,ERR_ADDR_NL);
+
+    if (!stralloc_copys(&addr,"T")) die_nomem(fatal);
+    if (!stralloc_cats(&addr,userhost)) die_nomem(fatal);
+    if (addr.len > 401)
+      strerr_die2x(100,fatal,ERR_ADDR_LONG);
+
+    j = byte_rchr(addr.s,addr.len,'@');
+    if (j == addr.len)
+      strerr_die2x(100,fatal,ERR_ADDR_AT);
+    case_lowerb(addr.s + j + 1,addr.len - j - 1);
+    if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal);
+    case_lowerb(lcaddr.s + 1,j - 1);   /* make all-lc version of address */
+
+    if (forcehash >= 0 && forcehash <= 52) {
+      ch = lcch = (unsigned char) forcehash;
+    } else {
+      h = 5381;
+      lch = h;
+      for (j = 0;j < addr.len;++j) {
+        h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
+        lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j];
+      }
+      lcch = 64 + (lch % 53);
+      ch = 64 + (h % 53);
+    }
+
+    if (!stralloc_0(&addr)) die_nomem(fatal);
+    if (!stralloc_0(&lcaddr)) die_nomem(fatal);
+    if (!stralloc_copys(&fn,dbname)) die_nomem(fatal);
+    if (!stralloc_copys(&fnlock,dbname)) die_nomem(fatal);
+
+    if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal);
+    if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal);
+    if (!stralloc_copy(&fnnew,&fn)) die_nomem(fatal);
+       /* code later depends on fnnew = fn + 'n' */
+    if (!stralloc_cats(&fnnew,"n")) die_nomem(fatal);
+    if (!stralloc_cats(&fnlock,"/lock")) die_nomem(fatal);
+    if (!stralloc_0(&fnnew)) die_nomem(fatal);
+    if (!stralloc_0(&fn)) die_nomem(fatal);
+    if (!stralloc_0(&fnlock)) die_nomem(fatal);
+
+    fdlock = open_append(fnlock.s);
+    if (fdlock == -1)
+      strerr_die4sys(111,fatal,ERR_OPEN,fnlock.s,": ");
+    if (lock_ex(fdlock) == -1)
+      strerr_die4sys(111,fatal,ERR_OBTAIN,fnlock.s,": ");
+
+                               /* do lower case hashed version first */
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    flagwasthere = 0;
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    }
+    else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1) {
+         close(fd); close(fdnew); die_read(fatal);
+        }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+           flagwasthere = 1;
+           if (!flagadd)
+             continue;
+         }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1) {
+         close(fd); close(fdnew); die_write(fatal);
+        }
+      }
+
+      close(fd);
+    }
+
+    if (flagadd && !flagwasthere)
+      if (substdio_bput(&ssnew,addr.s,addr.len) == -1) {
+        close(fdnew); die_write(fatal);
+      }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    if ((ch == lcch) || flagwasthere) {
+      close(fdlock);
+      if (flagadd ^ flagwasthere) {
+        if (!stralloc_0(&addr)) die_nomem(fatal);
+        log(dbname,event,addr.s+1,comment);
+        return 1;
+      }
+      return 0;
+    }
+
+                       /* If unsub and not found and hashed differ, OR */
+                       /* sub and not found (so added with new hash) */
+                       /* do the 'case-dependent' hash */
+
+    fn.s[fn.len - 2] = ch;
+    fnnew.s[fnnew.len - 3] = ch;
+    fdnew = open_trunc(fnnew.s);
+    if (fdnew == -1) die_write(fatal);
+    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
+
+    fd = open_read(fn.s);
+    if (fd == -1) {
+      if (errno != error_noent) { close(fdnew); die_read(fatal); }
+    } else {
+      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
+
+      for (;;) {
+        if (getln(&ss,&line,&match,'\0') == -1)
+          { close(fd); close(fdnew); die_read(fatal); }
+        if (!match) break;
+        if (line.len == addr.len)
+          if (!case_diffb(line.s,line.len,addr.s)) {
+            flagwasthere = 1;
+            continue;  /* always want to remove from case-sensitive hash */
+          }
+        if (substdio_bput(&ssnew,line.s,line.len) == -1)
+          { close(fd); close(fdnew); die_write(fatal); }
+      }
+
+      close(fd);
+    }
+
+    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); }
+    if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); }
+    close(fdnew);
+
+    if (rename(fnnew.s,fn.s) == -1)
+      strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": ");
+
+    close(fdlock);
+    if (flagadd ^ flagwasthere) {
+      if (!stralloc_0(&addr)) die_nomem(fatal);
+      log(dbname,event,addr.s+1,comment);
+      return 1;
+    }
+    return 0;
+
+}
diff --git a/sub_std/tagmsg.c b/sub_std/tagmsg.c
new file mode 100644 (file)
index 0000000..0919346
--- /dev/null
@@ -0,0 +1,55 @@
+/*$Id: tagmsg.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+#include "stralloc.h"
+#include "scan.h"
+#include "fmt.h"
+#include "strerr.h"
+#include "cookie.h"
+#include "slurp.h"
+#include "errtxt.h"
+#include "subscribe.h"
+#include "makehash.h"
+
+static stralloc line = {0};
+static stralloc key = {0};
+static char hash[COOKIE];
+static char strnum[FMT_ULONG]; /* message number as sz */
+
+static void die_nomem(fatal)
+char *fatal;
+{
+  strerr_die2x(100,fatal,ERR_NOMEM);
+}
+
+void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal)
+/* This routine creates a cookie from num,seed and the */
+/* list key and returns that cookie in hashout. The use of sender/num and */
+/* first char of action is used to make cookie differ between messages,   */
+/* the key is the secret list key. */
+
+char *dir;                     /* db base dir */
+unsigned long msgnum;          /* number of this message */
+char *seed;                    /* seed. NULL ok, but less entropy */
+char *action;                  /* to make it certain the cookie differs from*/
+                               /* one used for a digest */
+char *hashout;                 /* calculated hash goes here */
+unsigned long bodysize;
+unsigned long chunk;
+char *fatal;
+{
+  unsigned int i;
+
+  strnum[fmt_ulong(strnum,msgnum)] = '\0';     /* message nr ->string*/
+
+    switch(slurp("key",&key,32)) {
+      case -1:
+       strerr_die3sys(111,fatal,ERR_READ,"key: ");
+      case 0:
+       strerr_die3x(100,fatal,"key",ERR_NOEXIST);
+    }
+    cookie(hash,key.s,key.len,strnum,seed,action);
+    for (i = 0; i < COOKIE; i++)
+      hashout[i] = hash[i];
+
+    return;
+}
deleted file mode 100644 (file)
index fee21e2587928759fea8dc2633229f15f52bbd79..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#include "stralloc.h"
-#include "getln.h"
-#include "readwrite.h"
-#include "substdio.h"
-#include "strerr.h"
-#include "open.h"
-#include "byte.h"
-#include "case.h"
-#include "lock.h"
-#include "error.h"
-#include "uint32.h"
-#include "subscribe.h"
-
-static stralloc addr = {0};
-static stralloc line = {0};
-static stralloc fnnew = {0};
-static stralloc fn = {0};
-
-static int fd;
-static substdio ss;
-static char ssbuf[256];
-static int fdnew;
-static substdio ssnew;
-static char ssnewbuf[256];
-
-static int doit(userhost,flagadd)
-char *userhost;
-int flagadd;
-{
-  int j;
-  uint32 h;
-  char ch;
-  int match;
-  int flagwasthere;
-
-  if (userhost[str_chr(userhost,'\n')]) return -8;
-  if (!stralloc_copys(&addr,"T")) return -2;
-  if (!stralloc_cats(&addr,userhost)) return -2;
-  if (addr.len > 401) return -7;
-
-  j = byte_rchr(addr.s,addr.len,'@');
-  if (j == addr.len) return -6;
-  case_lowerb(addr.s + j + 1,addr.len - j - 1);
-
-  h = 5381;
-  for (j = 0;j < addr.len;++j)
-    h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j];
-  ch = 64 + (h % 53);
-
-  if (!stralloc_0(&addr)) return -2;
-
-  if (!stralloc_copys(&fn,"subscribers/")) return -2;
-  if (!stralloc_catb(&fn,&ch,1)) return -2;
-  if (!stralloc_copy(&fnnew,&fn)) return -2;
-  if (!stralloc_cats(&fnnew,"n")) return -2;
-  if (!stralloc_0(&fnnew)) return -2;
-  if (!stralloc_0(&fn)) return -2;
-
-  fdnew = open_trunc(fnnew.s);
-  if (fdnew == -1) return -4;
-  substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));
-
-  flagwasthere = 0;
-
-  fd = open_read(fn.s);
-  if (fd == -1) {
-    if (errno != error_noent) { close(fdnew); return -3; }
-  }
-  else {
-    substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));
-
-    for (;;) {
-      if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); return -3; }
-      if (!match) break;
-      if (line.len == addr.len)
-        if (!byte_diff(line.s,line.len,addr.s)) {
-         flagwasthere = 1;
-         if (!flagadd)
-           continue;
-       }
-      if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); return -4; }
-    }
-
-    close(fd);
-  }
-
-  if (flagadd && !flagwasthere)
-    if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); return -4; }
-
-  if (substdio_flush(&ssnew) == -1) { close(fdnew); return -4; }
-  if (fsync(fdnew) == -1) { close(fdnew); return -4; }
-  close(fdnew);
-
-  if (rename(fnnew.s,fn.s) == -1) return -5;
-  return flagadd ^ flagwasthere;
-}
-
-struct strerr subscribe_err;
-
-int subscribe(userhost,flagadd)
-char *userhost;
-int flagadd;
-{
-  int fdlock;
-  int r;
-
-  fdlock = open_append("lock");
-  if (fdlock == -1)
-    STRERR_SYS(-1,subscribe_err,"unable to open lock: ")
-  if (lock_ex(fdlock) == -1) {
-    close(fdlock);
-    STRERR_SYS(-1,subscribe_err,"unable to obtain lock: ")
-  }
-
-  r = doit(userhost,flagadd);
-  close(fdlock);
-
-  if (r == -2) STRERR(-1,subscribe_err,"out of memory")
-  if (r == -3) STRERR_SYS3(-1,subscribe_err,"unable to read ",fn.s,": ")
-  if (r == -4) STRERR_SYS3(-1,subscribe_err,"unable to write ",fnnew.s,": ")
-  if (r == -5) STRERR_SYS3(-1,subscribe_err,"unable to move temporary file to ",fn.s,": ")
-  if (r == -6) STRERR(-2,subscribe_err,"address does not contain @")
-  if (r == -7) STRERR(-2,subscribe_err,"address is too long")
-  if (r == -8) STRERR(-2,subscribe_err,"address contains newline")
-
-  return r;
-}
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..1c16baebb9c8c280121683a4258c4b918926504a
--- /dev/null
@@ -0,0 +1 @@
+sub_std/subscribe.c
\ No newline at end of file
index 48a2f1c..ee43887 100644 (file)
@@ -1,10 +1,60 @@
+/*$Id: subscribe.h,v 1.14 1999/10/03 19:23:31 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
 #ifndef SUBSCRIBE_H
 #define SUBSCRIBE_H
 
 #ifndef SUBSCRIBE_H
 #define SUBSCRIBE_H
 
-#include "strerr.h"
+#include "stralloc.h"
 
 
-extern struct strerr subscribe_err;
+/* these are the subroutines used for interfacing with the subscriber and  */
+/* moderator address databases. For the put/to address output routines     */
+/* the 'username' if defined is omitted from the output. flagadd = 1 adds  */
+/* a subscriber, flagadd = 0 removes the address. To use e.g. a SQL data-  */
+/* base for addresses, just replace these routines and rebuild ezmlm.      */
+
+#ifdef WITH_PROTO
+
+extern int subscribe(char *dir,char *username,int flagadd,char *from,
+       char *event, int flagmysql, int forcehash,
+       char *table_override, char *FATAL);
+
+extern char *issub(char *dir,char *username, char *table_override, char *FATAL);
+
+extern unsigned long putsubs(char *dir,
+       unsigned long hash_lo, unsigned long hash_hi,
+       int subwrite(), int flagsql, char *fatal);
+
+/*             int subwrite(char *string, unsigned int length); */
+
+extern void tagmsg(char *dir, unsigned long msgnum,
+       char *seed, char *action, char *hashout,
+       unsigned long bodysize, unsigned long chunk, char *fatal);
+
+extern char *logmsg(char *dir, unsigned long msgnum, unsigned long,
+       unsigned long subs, int done);
+
+extern char *checktag(char *dir, unsigned long msgnum, unsigned long listno,
+       char *action, char *seed, char *hash);
+
+extern void searchlog(char *dir, char *search, int subwrite(), char *fatal);
+
+extern char *opensql(char *dir, char **table);
+
+extern void closesql();
+
+#else
 
 extern int subscribe();
 
 extern int subscribe();
+extern char *issub();
+extern unsigned long putsubs();
+extern void tagmsg();
+extern char *logmsg();
+char *checktag();
+extern int subreceipt();
+extern char *getlistno();
+extern char *opensql();
+extern void closesql();
+extern void searchlog();
 
 #endif
 
 #endif
+extern void *psql;             /* contains SQL handle */
+#endif
diff --git a/tagmsg.c b/tagmsg.c
new file mode 120000 (symlink)
index 0000000..4f795c9
--- /dev/null
+++ b/tagmsg.c
@@ -0,0 +1 @@
+sub_std/tagmsg.c
\ No newline at end of file
diff --git a/unfoldHDR.c b/unfoldHDR.c
new file mode 100644 (file)
index 0000000..6004f0b
--- /dev/null
@@ -0,0 +1,303 @@
+/*$Id: unfoldHDR.c,v 1.14 1999/11/06 05:25:14 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include "stralloc.h"
+#include "strerr.h"
+#include "case.h"
+#include "byte.h"
+#include "errtxt.h"
+#include "mime.h"
+
+static stralloc tmpdata = {0};
+
+static int trimre(cpp,cpend,prefix,fatal)
+char **cpp;
+char *cpend;
+stralloc *prefix;
+char *fatal;
+
+{
+  int r = 0;
+  register char *cp;
+  char *cpnew;
+  int junk;
+  unsigned int i,j;
+  unsigned int serial;
+
+  cp = *cpp;
+  serial = prefix->len;                /* pointer to serial number */
+  if (serial)
+    serial = byte_rchr(prefix->s,prefix->len,'#');
+
+  junk = 1;
+  while (junk) {
+    junk = 0;
+    while (cp <= cpend && (*cp == ' ' || *cp == '\t')) cp++;
+    cpnew = cp;
+    while (++cpnew <= cpend) { /* /(..+:\s)/ is a reply indicator */
+      if (*cpnew == ' ') {
+        if (cpnew < cp + 3) break;     /* at least 3 char before ' ' */
+       if (*(cpnew - 1) != ':') break; /* require ':' before ' ' */
+       if (cpnew > cp + 5) {           /* if > 4 char before ':' require */
+         register char ch;
+         ch = *(cpnew - 2);            /* XX^3, XX[3], XX(3) */
+         if (ch != ')' && ch != ']' && (ch < '0' || ch > '9'))
+           break;
+       }
+       junk = 1;
+       r |= 1;
+       cp = cpnew + 1;
+        break;
+      }
+    }
+       /* prefix removal is complicated by the inconsistent handling of ' ' */
+       /* when there are rfc2047-encoded words in the subject. We first     */
+       /* compare prefix before "serial" ignoring space, then skip the      */
+       /* number, then compare after "serial". If both matched we've found  */
+       /* the prefix. */
+    if (serial) {
+      cpnew = cp;
+      i = 0;
+      while (i < serial && cpnew <= cpend) {
+        if (*cpnew != ' ') {
+          if (prefix->s[i] == ' ') {
+            ++i;
+            continue;
+          }
+          if (*cpnew != prefix->s[i]) break;
+          ++i;
+        }
+        ++cpnew;
+      }
+      if (i == serial) {               /* match before serial */
+        j = prefix->len;
+        if (serial != j) {             /* got a '#' */
+          while (cpnew <= cpend &&     /* skip number/space */
+               *cpnew == ' ' || (*cpnew <= '9' && *cpnew >= '0')) ++cpnew;
+          i = serial + 1;
+          while (i < j && cpnew <= cpend) {
+            if (*cpnew != ' ') {
+              if (prefix->s[i] == ' ') {
+                ++i;
+                continue;
+              }
+              if (*cpnew != prefix->s[i]) break;
+              ++i;
+            }
+            ++cpnew;
+          }
+        }
+        if (i == j) {
+          cp = cpnew;
+          junk = 1;
+          r |= 2;
+        }
+      }
+    }
+  }
+  *cpp = cp;
+  return r;
+}
+
+static int trimend(indata,np,fatal)
+char *indata;
+unsigned int *np;
+char *fatal;
+       /* looks at indata of length n from the end removing LWSP & '\n' */
+       /* and any trailing '-Reply'. Sets n to new length and returns:  */
+       /* 0 - not reply, 1 - reply. */
+{
+  char *cplast;
+  int junk;
+  int r = 0;
+
+  if (*np == 0) return 0;
+  cplast = indata + *np - 1;   /* points to last char on line */
+  junk = 1;
+  while (junk) {
+    junk = 0;
+    while (cplast >= indata &&
+             (*cplast == ' ' || *cplast == '\t' ||
+              *cplast == '\r' || *cplast == '\n')) 
+            --cplast;
+    if (cplast - indata  >= 5 && case_startb(cplast - 5,6,"-Reply")) {
+      cplast -= 6;
+      r = 1;
+      junk = 1;
+    }
+  }
+  *np = (unsigned int) (cplast - indata + 1);  /* new length */
+  return r;
+}
+
+int unfoldHDR(indata,n,outdata,charset,prefix,flagtrimsub,fatal)
+char *indata;
+unsigned int n;
+stralloc *outdata;
+char *charset;
+stralloc *prefix;
+int flagtrimsub;
+char *fatal;
+       /* takes a header as indata. Removal of reply-indicators is done */
+       /* but removal of line breaks and Q and B decoding should have   */
+       /* been done. Returns a */
+       /* single line header without trailing \n or \0. Mainly, we      */
+       /* remove redundant shift codes   */
+       /* returns 0 = no reply no prefix */
+       /*         1 = reply no prefix    */
+       /*         2 = no reply, prefix   */
+       /*         3 = reply & pefix      */
+{
+  int r = 0;
+  char *cp,*cpesc,*cpnext,*cpend,*cpout;
+  char state,cset,newcset;
+  int reg,newreg;
+
+  cp = indata;         /* JIS X 0201 -> ISO646 us-ascii */
+  cpend = cp + n - 1;
+  cpnext = cp;
+  if (!stralloc_copys(&tmpdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(&tmpdata,n)) die_nomem(fatal);
+
+  if(!case_diffb(charset,11,"iso-2022-jp")) {
+       /* iso-2022-jp-2 (rfc1554) and its subset iso-2022-jp. The reg #s */
+       /* are from the rfc. Don't ask why they have multiple length G0   */
+       /* charset designations ... JIS X 0201-roman is identical to      */
+       /* iso646 us-ascii except for currency and tilde. Making them the */
+       /* same increases hits without significant loss. JIS X 0208-1978  */
+       /* is superceded by JIS X 0208-1983 and converted here as well.   */
+
+    while (cp < cpend) {
+      if (*cp++ != ESC) continue;
+      if (*cp == '(') {
+        if (++cp > cpend) break;
+        if (*cp == 'J') *cp = 'B';
+        ++cp;
+      } else if (*cp == '$') {
+        if (++cp > cpend) break;
+        if (*cp == '@') *cp = 'B';
+        ++cp;
+      }
+    }
+               /* eliminate redundant ESC seqs */
+    cp = indata;
+    cpnext = cp;
+    reg = 6;
+    while (cp < cpend) {
+      if (*cp++ != ESC) continue;
+      cpesc = cp - 1;
+      if (*cp == '$') {
+        if (++cp > cpend) break;
+        if (*cp == 'B') newreg = 87;
+        else if (*cp == 'A') newreg = 58;
+        else if (*cp == '(') {
+          if (++cp > cpend) break;
+          if (*cp == 'C') newreg = 149;
+          else if (*cp == 'D') newreg = 159;
+          else continue;
+        } else continue;
+      } else if (*cp == '(') {
+        if (++cp > cpend) break;
+        if (*cp == 'B') newreg = 6;
+        else continue;
+      } else continue;
+      if (++cp > cpend) break;
+      while (*cp == ' ' || *cp == '\t')
+        if (++cp >= cpend) break;      /* skip space */
+      if (*cp == ESC)                  /* maybe another G0 designation */
+        if (*(cp+1) == '(' || *(cp+1) == '$') {         /* yep! */
+          if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal);
+          cpnext = cp;
+         continue;
+      }
+      if (reg == newreg) {
+        if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal);
+        cpnext = cp;
+      } else {
+        reg = newreg;
+      }                /* copy remainder of line */
+    }
+    if (!stralloc_catb(&tmpdata,cpnext,cpend - cpnext + 1)) die_nomem(fatal);
+    if (reg != 6) {    /* need to return to us-ascii at the end of the line */
+      if (!stralloc_cats(&tmpdata,TOASCII)) die_nomem(fatal);
+    } else {           /* maybe "-Reply at the end?" */
+      r = trimend(tmpdata.s,&(tmpdata.len),fatal);
+    }
+
+  } else if (!case_diffb(charset,11,"iso-2022-cn") ||
+             !case_diffb(charset,11,"iso-2022-kr")) {
+       /* these use SI/SO and ESC $ ) x as the SO designation. In -cn and */
+       /* -cn-ext, 'x' can be a number of different letters. In -kr it's  */
+       /* always 'C'. This routine may work also for other iso-2022 sets  */
+       /* also handles iso-2022-cn-ext */
+    cpesc = (char *) 0;        /* points to latest ESC */
+    state = SI;                /* us-ascii */
+    --cp;              /* set up for loop */
+
+    while (++cp <= cpend) {
+      if (*cp == SI || *cp == SO) {
+        if (state == *cp) {             /* already in state. Skip shift seq */
+          if (!stralloc_catb(&tmpdata,cpnext,cp-cpnext-1)) die_nomem(fatal);
+          cpnext = cp;
+        } else                         /* set new state */
+          state = *cp;
+        if (++cp > cpend) break;
+        continue;
+      }
+      if (*cp != ESC) continue;
+      if (cp + 3 > cpend) break;       /* not space for full SO-designation */
+      cpesc = cp;
+      if (*cp != '$') continue;
+      if (++cp > cpend) break;
+      if (*cp != ')') continue;
+      if (++cp > cpend) break;
+      newcset = *cp;
+      if (++cp > cpend) break;
+      while (cp <= cpend && (*cp == ' ' || *cp == '\t')) ++cp;
+      if (cp + 3 > cpend) break;       /* no space for full SO-designation */
+      if ((*cp == ESC && *(cp+1) == '$' && *(cp+2) == ')')
+               || (newcset == cset)) {
+                       /* skip if a second SO-designation right after or */
+                       /* this SO-designation is already active, skip */
+        if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal);
+        --cp;          /* "unpeek" so that next iteration will see char */
+        cpnext = cpesc + 4;
+        continue;
+      } else {
+        cset = newcset;
+        continue;
+      }
+    }
+                       /* get remainder of line */
+    if (!stralloc_catb(&tmpdata,cpnext,cpend - cpnext + 1)) die_nomem(fatal);
+    if (state != SI)   /* need to end in ascii */
+      if (!stralloc_cats(&tmpdata,TOSI)) die_nomem(fatal);
+    else               /* ascii end; maybe "-Reply" at the end? */
+      r = trimend(tmpdata.s,&(tmpdata.len),fatal);
+
+  } else {             /* other character sets = no special treatment */
+    r = trimend(cp,&n,fatal);          /* -reply */
+    if (!stralloc_copyb(&tmpdata,cp,n)) die_nomem(fatal);
+  }
+
+  cp = tmpdata.s;
+  n = tmpdata.len;
+  cpend = cp + n - 1;
+  if (flagtrimsub) {    /* remove leading reply indicators & prefix*/
+    r |= trimre(&cp,cpend,prefix,fatal);
+    n = (unsigned int) (cpend-cp+1);
+  }
+                       /* there shouldn't be '\0' or '\n', but make sure as */
+                       /* it would break the message index */
+  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
+  if (!stralloc_ready(outdata,n)) die_nomem(fatal);
+  outdata->len = n;
+  cpout = outdata->s;
+  while (n--) {                /* '\n' and '\0' would break the subject index */
+    if (!*cp || *cp == '\n') *cpout = ' ';
+    else *cpout = *cp;
+    ++cp; ++cpout;
+  }
+  return r;
+}
+
diff --git a/yyyymm.h b/yyyymm.h
new file mode 100644 (file)
index 0000000..ffbf6b8
--- /dev/null
+++ b/yyyymm.h
@@ -0,0 +1,15 @@
+#ifndef YYYYMM_H
+#define YYYYMM_H
+
+#ifdef WITH_PROTO
+#include "stralloc.h"
+
+extern unsigned int date2yyyymm(char *);
+extern int dateline(stralloc *, unsigned long);
+#else
+extern unsigned int date2yyyymm();
+extern int dateline();
+#endif
+
+#endif
+