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:
--- /dev/null
+$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
+========================
--- /dev/null
+$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]'
+
--- /dev/null
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+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
--- /dev/null
+$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'.
+
--- /dev/null
+ 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.
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:
+#$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
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; \
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
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
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`" ) > \
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
&& 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
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
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
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
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
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
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
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
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
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`" ) > \
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
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 \
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
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
./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 \
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 && \
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
+
+
--- /dev/null
+$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)
+
--- /dev/null
+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
--- /dev/null
+$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.
+
ezmlm 0.53
+$Name: ezmlm-idx-040 $
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+#ifndef AUTO_CRON_H
+#define AUTO_CRON_H
+
+extern char auto_cron[];
+
+#endif
--- /dev/null
+#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);
+}
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+sub_std/checktag.c
\ No newline at end of file
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+/usr/bin
+
+This is the directory housing the crontab binary
--- /dev/null
+sub_std/conf-sqlcc
\ No newline at end of file
--- /dev/null
+sub_std/conf-sqlld
\ No newline at end of file
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;
}
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;
extern int constmap_init();
extern void constmap_free();
extern char *constmap();
-
+extern char *constmap_get();
+extern int constmap_index();
#endif
--- /dev/null
+/*$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);
+}
+
--- /dev/null
+#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
--- /dev/null
+
+/*$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;
+}
+
+
--- /dev/null
+/*$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;
+}
+
+
--- /dev/null
+#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;
+ }
+ }
+}
+
--- /dev/null
+/*$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);
+}
+
--- /dev/null
+/*$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);
+}
+
+
--- /dev/null
+/* $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);
+}
+
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* 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;
+}
-2;
#endif
-int error_noent =
+int error_noent =
#ifdef ENOENT
ENOENT;
#else
#else
-13;
#endif
+
+int error_notdir =
+#ifdef ENOTDIR
+ENOTDIR;
+#else
+-14;
+#endif
extern int error_pipe;
extern int error_perm;
extern int error_acces;
+extern int error_notdir;
extern char *error_str();
extern int error_temp();
--- /dev/null
+/*$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
+
--- /dev/null
+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 }
+
+
--- /dev/null
+# 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
+
--- /dev/null
+.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)
--- /dev/null
+# [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;
--- /dev/null
+.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)
+
--- /dev/null
+/*$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");
+ }
+}
+
--- /dev/null
+.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)
+
--- /dev/null
+/*$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(">"); break;
+ case '<': oputs("<"); break;
+ case '"': oputs("""); break;
+ case '&': oputs("&"); 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(">"); break;
+ case '<': oputs("<"); break;
+ case '"': oputs("""); break;
+ case '&': oputs("&"); 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(">"); break;
+ case '<': oputs("<"); break;
+ case '"': oputs("""); break;
+ case '&': oputs("&"); 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("[<-</A> ");
+ linktoindex(infop,ITEM_SUBJECT);
+ oputs(">thread</A> ");
+ link_msg(infop,ITEM_SUBJECT,DIRECT_NEXT);
+ oputs("->]</A> \n");
+ link_msg(infop,ITEM_MESSAGE,DIRECT_PREV);
+ oputs("[<-</A> ");
+ linktoindex(infop,ITEM_INDEX);
+ oputs(">time</A> ");
+ link_msg(infop,ITEM_MESSAGE,DIRECT_NEXT);
+ oputs("->]</A> \n");
+ link_msg(infop,ITEM_AUTHOR,DIRECT_PREV);
+ oputs("[<-</A> ");
+ linktoindex(infop,ITEM_AUTHOR);
+ oputs(">author</A> ");
+ link_msg(infop,ITEM_AUTHOR,DIRECT_NEXT);
+ oputs("->]</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("[<-]");
+ break;
+ case DIRECT_NEXT:
+ oputs("[->]");
+ break;
+ case DIRECT_FIRST:
+ oputs("[<<-]");
+ break;
+ case DIRECT_LAST:
+ oputs("[->>]");
+ 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(">[<<-]</A>\n");
+ if (tmpmsg >= 100) infop->target = tmpmsg - 100;
+ linktoindex(infop,ITEM_INDEX);
+ oputs(">[<-]</A>\n");
+ infop->target = tmpmsg + 100;
+ linktoindex(infop,ITEM_INDEX);
+ oputs(">[->]</A>\n");
+ infop->target = MAXULONG;
+ linktoindex(infop,ITEM_INDEX);
+ oputs(">[->>]</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);
+}
--- /dev/null
+.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)
--- /dev/null
+
+# [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
+
--- /dev/null
+.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)
--- /dev/null
+/*$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("ed,&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);
+}
+
--- /dev/null
+.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)
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+ }
+}
+
--- /dev/null
+.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)
+
--- /dev/null
+/*$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("ed,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("ed,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("ed,&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("ed,&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);
+ }
+}
--- /dev/null
+.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)
--- /dev/null
+# 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
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+}
+
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+}
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+}
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
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),
-#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 "error.h"
#include "readwrite.h"
+#include "substdio.h"
+#include "subscribe.h"
#include "exit.h"
-#include "open.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "errtxt.h"
+#include "idx.h"
#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()
{
- 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;
- 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);
}
.SH SYNOPSIS
.B ezmlm-make
[
-.B \-aApP
+.B \-+
+][
+.B \-a..zABD..Z
+][
+.B \-C03..9 arg
]
.I dir
+[
.I dot
.I local
.I host
+.I [digestcode]
+]
.SH DESCRIPTION
.B ezmlm-make
sets up a new mailing list,
.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 .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
- ezmlm-make ~/SOS ~/.qmail-sos joe-sos isp.net
+ ezmlm-make ~joe/SOS ~joe/.qmail-sos joe-sos isp.net
.EE
Typical use of
.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
+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
-(Default.) Archived.
+(Default.) Archived and configured with
+.B ezmlm-get(1)
+for archive access.
.B ezmlm-make
will touch
-.IR dir\fB/archived ,
+.I dir\fB/archived
+and
+.I dir\fB/indexed
so that
-.B ezmlm-send
+.B ezmlm-send(1)
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 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.
+.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"
+ezmlm-clean(1),
+ezmlm-get(1),
ezmlm-manage(1),
+ezmlm-moderate(1),
ezmlm-send(1),
+ezmlm-store(1),
ezmlm-sub(1),
ezmlm-unsub(1),
ezmlm(5)
+/*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 "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 WARNING "ezmlm-make: warning: "
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()
{
- strerr_die2x(100,FATAL,"dir must start with slash");
+ strerr_die2x(100,FATAL,ERR_SLASH);
}
void die_newline()
{
- strerr_die2x(100,FATAL,"newlines not allowed");
+ strerr_die2x(100,FATAL,ERR_NEWLINE);
}
void die_quote()
{
- strerr_die2x(100,FATAL,"quotes not allowed");
+ strerr_die2x(100,FATAL,ERR_QUOTE);
}
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;
+char sz[2] = "?";
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()
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;
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)
- strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_CREATE,dotplus.s,": ");
keyaddtime();
}
{
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];
-void fopen(slash)
+void f_open(slash)
char *slash;
{
int fd;
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));
}
-void fput(buf,len)
+void f_put(buf,len)
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)
- 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)
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_FLUSH,dirplus.s,": ");
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 */
- strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": ");
+ strerr_die4sys(111,FATAL,ERR_CLOSE,dirplus.s,": ");
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;
{
+ unsigned long euid;
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);
- 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;
- 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 (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);
}
+
.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
-.IR dir .
+.IR dir ,
+as well as for the associated digest list.
.B ezmlm-manage
is normally invoked from a
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
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
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
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.
+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
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.
+.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),
+ezmlm-list(1),
ezmlm(5),
qmail-command(8)
+/*$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 "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: "
-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()
{
- 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 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;
+int match;
+unsigned int max;
char strnum[FMT_ULONG];
char date[DATE822FMT];
char hash[COOKIE];
+char boundary[COOKIE];
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 *ac;
{
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;
- 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;
qmail_put(&qq,buf,len);
return len;
}
+
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);
+ }
+ if (!quote("ed,&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("ed,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("ed,&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("ed,&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("ed,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("ed,&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("ed,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;
{
- char *dir;
- char *sender;
- char *host;
char *local;
+ char *def;
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 i;
- int flagconfirm;
- int flaghashok;
- int flaggoodfield;
- int match;
+ int flagdone;
+ register char ch;
- umask(022);
+ (void) umask(022);
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 (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+ if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
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)
- 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,'@')])
- 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,"#@[]"))
- strerr_die2x(100,FATAL,"I don't reply to bounce messages (#5.7.2)");
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
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:
- strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+ strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
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(&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);
+ 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]) {
- 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 (!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("ed,&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("ed,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("ed,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("ed,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("ed,&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("ed,"")) 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("ed,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("ed,&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 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();
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
- copy("text/get-bad");
+ copy(&qq,"text/get-bad",flagcd,FATAL);
else {
if (fstat(fd,&st) == -1)
- copy("text/get-bad");
+ copy(&qq,"text/get-bad",flagcd,FATAL);
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);
- 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,"> ");
}
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("ed,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;
+ closesql();
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);
}
}
+
--- /dev/null
+sub_std/ezmlm-mktab
\ No newline at end of file
--- /dev/null
+.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)
--- /dev/null
+.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)
--- /dev/null
+/*$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("ed,&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("ed,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);
+ }
+}
--- /dev/null
+.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)
--- /dev/null
+/*$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("ed,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(¶graph,"")) die_nomem();
+ for (;;) {
+ if (getln(&ssin,&line,&match,'\n') == -1)
+ strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+ if (!match) die_trash();
+ if (!stralloc_cat(¶graph,&line)) die_nomem();
+ if (line.len <= 1) break;
+ }
+
+ if (!flaghaveheader) {
+ if (!stralloc_copy(&header,¶graph)) 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,¶graph)) die_nomem();
+ flaghaveintro = 1;
+ continue;
+ }
+
+ if (paragraph.s[0] == '-')
+ break;
+
+ if (paragraph.s[0] == '<') { /* find address */
+ if (!stralloc_copy(&failure,¶graph)) 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);
+}
+
.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.
+
+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
+.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.
-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
+.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.
+.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)
#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 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];
-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 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;
{
+ unsigned long maxmsgsize = 0L;
+ unsigned long minmsgsize = 0L;
+ unsigned long msgsize = 0L;
int opt;
- char *x;
- int len;
+ char linetype = ' ';
+ char *cp, *cpstart, *cpafter;
+ char *dir;
+ char *err;
+ char *sender;
+ unsigned int len;
int match;
- while ((opt = getopt(argc,argv,"cCsS")) != opteof)
+ while ((opt = getopt(argc,argv,"bBcCfFhHqQsStT")) != opteof)
switch(opt) {
+ case 'b': flagbody = 1; break;
+ case 'B': flagbody = 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;
- 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 (;;) {
- 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 (flagheaderreject)
+ if (constmap(&headerrejectmap,line.s,byte_chr(line.s,line.len,':')))
+ strerr_die2x(100,FATAL,ERR_MAILING_LIST);
+
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);
}
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+}
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
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:
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),
+/*$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 "now.h"
#include "cookie.h"
#include "subscribe.h"
-#include "issub.h"
+#include "errtxt.h"
+#include "idx.h"
#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()
{
- 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()
{
- strerr_die1x(0,"ezmlm-return: info: trash address");
+ strerr_die2x(99,INFO,"trash address");
}
char outbuf[1024];
char strnum[FMT_ULONG];
char hash[COOKIE];
char hashcopy[COOKIE];
+char *hashp = (char *) 0;
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};
+void *psql = (void *) 0;
stralloc quoted = {0};
+stralloc ddir = {0};
char *sender;
+char *dir;
+char *workdir;
void die_hashnew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fnhashnew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fnhashnew.s,": "); }
void die_datenew()
-{ strerr_die4sys(111,FATAL,"unable to write ",fndatenew.s,": "); }
+{ strerr_die4sys(111,FATAL,ERR_WRITE,fndatenew.s,": "); }
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;
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_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();
- fndatenew.s[7] = 'W';
+ fndatenew.s[wpos] = 'W';
fd = open_trunc(fndatenew.s);
if (fd == -1) die_datenew();
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)
{
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_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();
- 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();
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();
- fnhashnew.s[7] = 'H';
+ fnhashnew.s[pos] = 'H';
fdnew = open_trunc(fnhashnew.s);
if (fdnew == -1) die_hashnew();
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)
- 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));
}
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 (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 intro = {0};
stralloc failure = {0};
stralloc paragraph = {0};
+int flagmasterbounce = 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;
int argc;
char **argv;
{
- char *dir;
- char *host;
char *local;
char *action;
+ char *def;
+ char *ret;
+ char *cp;
unsigned long msgnum;
unsigned long cookiedate;
unsigned long when;
+ unsigned long listno = 0L;
int match;
- int i;
+ unsigned int i;
+ int flagdig = 0;
+ int flagmaster = 0;
+ int flagreceipt = 0;
int fdlock;
+ register char ch;
umask(022);
sig_pipeignore();
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");
- if (!sender) strerr_die2x(100,FATAL,"SENDER not set");
+ if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
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)
- strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+ strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
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:
- 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 (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();
- 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);
- 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]) {
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);
- _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));
}
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,¶graph)) 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);
}
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
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
.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.
deletes any incoming fields with names listed in
.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
.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
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)
+/* $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 "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()
{
- strerr_die1x(100,"ezmlm-send: usage: ezmlm-send dir");
+ strerr_die1x(100,"ezmlm-send: usage: ezmlm-send [-cClLqQrR] [-h header] dir");
}
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 szmsgnum[FMT_ULONG];
+char hash[HASHLEN];
stralloc fnadir = {0};
stralloc fnaf = {0};
+stralloc fnif = {0};
+stralloc fnifn = {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 fdindex;
+int fdindexn;
+char hashout[COOKIE+1];
+
substdio ssarchive;
char archivebuf[1024];
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;
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;
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()
{
- strerr_die4sys(111,FATAL,"unable to write to ",fnaf.s,": ");
+ strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": ");
}
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();
}
-void puts(buf) char *buf;
+void qa_puts(buf) char *buf;
{
qmail_puts(&qq,buf);
if (flagarchived)
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;
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()
-{
+{ /* this one deals with msgnum, not outnum! */
int fd;
fd = open_trunc("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)
- strerr_die2sys(111,FATAL,"unable to move numnew to num: ");
+ strerr_die3sys(111,FATAL,ERR_MOVE,"numnew: ");
}
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;
{
- int fd;
- char *dir;
+ unsigned long subs;
int fdlock;
char *sender;
+ char *mlheader = (char *) 0;
+ char *ret;
+ char *err;
int flagmlwasthere;
+ int flagqmqp = 0; /* don't use qmqp by default */
+ int flaglistid = 0; /* no listid header added */
int match;
- int i;
- char ch;
+ unsigned int i;
+ int r,fd;
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();
- 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)
- strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
+ strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
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)
- 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);
+ 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(&mailinglist,"mailinglist",1,FATAL,dir);
+ set_cpoutlocal(&outlocal);
+ set_cpouthost(&outhost);
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 (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,"#@[]"))
- strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)");
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
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 (!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_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)
- 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)
- 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));
+ /* 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) {
- 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;
+ flagfoundokpart = 1;
flagbadfield = 0;
-
+ flagbadpart = 0;
+ flagseenext = 0;
+ flagsubline = 0;
+ flagfromline = 0;
+ flagreceived = 0;
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 (line.len == 1)
+ if (line.len == 1) { /* end of header */
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 (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))
- 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 (!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)
- 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 (fchmod(fdarchive,0744) == -1) die_archive();
+ if (fchmod(fdarchive,MODE_ARCHIVE | 0700) == -1) die_archive();
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_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();
-
- 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);
- default:
+ } else {
--msgnum;
+ cumsize -= (msgsize + 128L) >> 8;
numwrite();
- strerr_die2x(111,FATAL,"temporary qmail-queue error");
+ strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
}
}
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+ }
+}
+
+
--- /dev/null
+.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)
--- /dev/null
+/*$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("ed,&outlocal)) die_nomem();
+ if (!stralloc_copy(&reject,"ed)) 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,"ed)) 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("ed,&outlocal)) die_nomem();
+ if (!stralloc_cat(&subject,"ed)) 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);
+}
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
.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
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)
+/*$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 "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 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;
{
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)
- 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);
}
--- /dev/null
+.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)
+
--- /dev/null
+# 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
+
+
--- /dev/null
+.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)
--- /dev/null
+/*$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);
+}
+
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 ...
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,
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)
#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 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;
{
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);
}
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
.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),
+/*$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 "substdio.h"
#include "stralloc.h"
#include "slurp.h"
+#include "sgetopt.h"
#include "getconf.h"
#include "byte.h"
#include "error.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: "
-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 digdir = {0};
+stralloc charset = {0};
+char boundary[COOKIE];
+
+substdio ssout;
+char outbuf[16];
unsigned long when;
char *dir;
+char *workdir;
+int flagdig = 0;
+char flagcd = '\0'; /* default: don't use transfer encoding */
stralloc fn = {0};
+stralloc bdname = {0};
+stralloc fnlasth = {0};
+stralloc fnlastd = {0};
+stralloc lasth = {0};
+stralloc lastd = {0};
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;
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 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;
{
- int i;
+ unsigned int i;
int fd;
int match;
int fdhash;
+ char *err;
datetime_sec msgwhen;
fd = open_read(fn.s);
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,"");
- 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 (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);
+ 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,"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("ed,&outlocal)) die_nomem();
qmail_put(&qq,quoted.s,quoted.len);
qmail_puts(&qq,"\nTo: ");
if (!quote2("ed,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) {
- 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);
+ } 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 (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();
- 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();
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);
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)
- 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;
{
- DIR *bouncedir;
- direntry *d;
+ DIR *bouncedir, *bsdir, *hdir;
+ direntry *d, *ds;
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();
-
- 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 (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:
- strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
+ strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
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);
+ if (flagdig)
+ if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
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)
- strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
+ strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
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)
- 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 (!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);
}
.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
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
.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)
#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);
}
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 **";
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;
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);
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.
.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,
.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.
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.
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
.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 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
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,
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
.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
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,
.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)
--- /dev/null
+# 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!
+
--- /dev/null
+.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)
--- /dev/null
+.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),
--- /dev/null
+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#>ÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð¡£
+
--- /dev/null
+#$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é ]
+
+
--- /dev/null
+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.
+
--- /dev/null
+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.
--- /dev/null
+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.
+
--- /dev/null
+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.
+
+
--- /dev/null
+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.
+
+
--- /dev/null
+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.
+
+
--- /dev/null
+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.
--- /dev/null
+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
+
--- /dev/null
+#$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!
+
+
--- /dev/null
+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.
+
+
--- /dev/null
+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.
+
+
--- /dev/null
+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, ÉÌÉ þÁ÷ï -- þÁÓÔÏ ÚÁÄÁ×ÁÅÍÙÅ ÷ÏÐÒÏÓÙ É ïÔ×ÅÔÙ.
+
+úÄÅÓØ ÐÏËÁ ÐÕÓÔÏ. íÏÖÅÔ ËÔÏ-ÎÉÂÕÄØ ÎÁÐÉÛÅÔ?
+
--- /dev/null
+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.
+
--- /dev/null
+#$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.
--- /dev/null
+.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)
+
--- /dev/null
+/*$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
+
--- /dev/null
+--- 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)
--- /dev/null
+/*$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;
+}
--- /dev/null
+
+#ifndef IDXTHREAD_H
+#define IDXTHREAD_H
+
+/* threading */
+extern void idx_mkthread();
+extern void idx_mkthreads();
+extern void idx_mklist();
+extern void idx_destroythread();
+
+#endif
+++ /dev/null
-#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;
-}
--- /dev/null
+sub_std/issub.c
\ No newline at end of file
#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;
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);
--- /dev/null
+sub_std/logmsg.c
\ No newline at end of file
--- /dev/null
+/*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);
+}
+
+
--- /dev/null
+#ifndef MAKEHASH_H
+#define MAKEHASH_H
+
+#define HASHLEN 20
+
+extern void makehash();
+extern void mkauthhash();
+
+#endif
+
--- /dev/null
+#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
--- /dev/null
+sub_std/opensql.c
\ No newline at end of file
--- /dev/null
+sub_std/putsubs.c
\ No newline at end of file
#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;
+stralloc *sa;
{
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; }
-
+
switch(qq->pid = vfork()) {
case -1:
close(pim[0]); close(pim[1]);
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);
}
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;
{
- 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;
qmail_put(qq,"",1);
}
-int qmail_close(qq)
+char *qmail_close(qq)
struct qmail *qq;
{
int wstat;
+ int exitcode;
qmail_put(qq,"",1);
if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
close(qq->fde);
- if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID;
- if (wait_crashed(wstat)) return QMAIL_CRASHED;
- switch(wait_exitcode(wstat)) {
- case 0: if (qq->flagerr) return QMAIL_BUG; return 0;
- case 112: return QMAIL_USAGE;
- case 115: return QMAIL_TOOLONG;
- case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS;
- case 121: return QMAIL_READ;
- case 122: return QMAIL_WRITE;
- case 123: return QMAIL_NOMEM;
- case 124: return QMAIL_TIMEOUT;
- case 120: return QMAIL_EXECSOFT;
- default: /* 101 or 102 */ return QMAIL_BUG;
+ if (wait_pid(&wstat,qq->pid) != qq->pid)
+ return "Zqq waitpid surprise (#4.3.0)";
+ if (wait_crashed(wstat))
+ return "Zqq crashed (#4.3.0)";
+ exitcode = wait_exitcode(wstat);
+
+ switch(exitcode) {
+ case 115: /* compatibility */
+ case 11: return "Denvelope address too long for qq (#5.1.3)";
+ case 31: return "Dmail server permanently rejected message (#5.3.0)";
+ case 51: return "Zqq out of memory (#4.3.0)";
+ case 52: return "Zqq timeout (#4.3.0)";
+ case 53: return "Zqq write error or disk full (#4.3.0)";
+ case 0: if (!qq->flagerr) return ""; /* fall through */
+ case 54: return "Zqq read error (#4.3.0)";
+ case 55: return "Zqq unable to read configuration (#4.3.0)";
+ case 56: return "Zqq trouble making network connection (#4.3.0)";
+ case 61: return "Zqq trouble in home directory (#4.3.0)";
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 62: return "Zqq trouble creating files in queue (#4.3.0)";
+ case 71: return "Zmail server temporarily rejected message (#4.3.0)";
+ case 72: return "Zconnection to mail server timed out (#4.4.1)";
+ case 73: return "Zconnection to mail server rejected (#4.4.1)";
+ case 74: return "Zcommunication with mail server failed (#4.4.2)";
+ case 91: /* fall through */
+ case 81: return "Zqq internal bug (#4.3.0)";
+ case 120: return "Zunable to exec qq (#4.3.0)";
+ default:
+ if ((exitcode >= 11) && (exitcode <= 40))
+ return "Dqq permanent problem (#5.3.0)";
+ return "Zqq temporary problem (#4.3.0)";
}
}
#define QMAIL_H
#include "substdio.h"
+#include "stralloc.h"
struct qmail {
int flagerr;
unsigned long pid;
+ unsigned long msgbytes;
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_close();
+extern char *qmail_close();
extern unsigned long qmail_qp();
-
-#define QMAIL_WAITPID -2
-#define QMAIL_CRASHED -3
-#define QMAIL_USAGE -4
-#define QMAIL_BUG -5
-#define QMAIL_SYS -6
-#define QMAIL_READ -7
-#define QMAIL_WRITE -8
-#define QMAIL_NOMEM -9
-#define QMAIL_EXECSOFT -11
-#define QMAIL_TIMEOUT -13
-#define QMAIL_TOOLONG -14
+#endif
#endif
--- /dev/null
+sub_std/searchlog.c
\ No newline at end of file
--- /dev/null
+$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.
+
--- /dev/null
+/*$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("ed,COOKIE * 2 + 1)) return ERR_NOMEM;
+ quoted.len = mysql_escape_string(quoted.s,hash,COOKIE);
+ if (!stralloc_cat(&line,"ed)) 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;
+ }
+}
--- /dev/null
+-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.
--- /dev/null
+-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.
--- /dev/null
+#!/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
+
--- /dev/null
+/*$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("ed,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;
+ }
+}
--- /dev/null
+/*$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;
+}
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+/*$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);
+ }
+}
--- /dev/null
+/*$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("ed,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,"ed)) 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,"ed)) 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,"ed)) 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,"ed)) 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("ed,2 * j + 1)) die_nomem(fatal);
+ quoted.len = mysql_escape_string(quoted.s,comment,j); /* from */
+ if (!stralloc_cat(&logline,"ed)) 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 */
+ }
+}
--- /dev/null
+/*$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;
+}
--- /dev/null
+#!/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;
+
--- /dev/null
+$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.
+
--- /dev/null
+/*$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;
+ }
+}
--- /dev/null
+-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.
+
--- /dev/null
+-L/usr/local/pgsql/lib -lpq -lcrypt
+
+# the top line will be used when linking. Edit to reflect your PostgreSQL
+# installation.
--- /dev/null
+#!/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
+
+
--- /dev/null
+/*$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;
+ }
+}
+
--- /dev/null
+/*$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;
+}
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+#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;
+ }
+}
--- /dev/null
+/*$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);
+
+ }
+}
--- /dev/null
+/*$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 */
+ }
+}
--- /dev/null
+/*$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;
+}
--- /dev/null
+$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.
+
+
+
+
+
--- /dev/null
+/*$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;
+
+}
--- /dev/null
+
+
+# the top line will be used when compiling. This version is for
+# linking without mysql support.
--- /dev/null
+
+
+# the top line will be used when linking. This version is for
+# linking without mysql support.
--- /dev/null
+#!/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
+
--- /dev/null
+/*$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;
+}
--- /dev/null
+/*$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 */
+}
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+#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;
+}
--- /dev/null
+/*$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);
+}
--- /dev/null
+/*$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;
+
+}
--- /dev/null
+/*$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;
+}
+++ /dev/null
-#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;
-}
--- /dev/null
+sub_std/subscribe.c
\ No newline at end of file
+/*$Id: subscribe.h,v 1.14 1999/10/03 19:23:31 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
#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 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
+extern void *psql; /* contains SQL handle */
+#endif
--- /dev/null
+sub_std/tagmsg.c
\ No newline at end of file
--- /dev/null
+/*$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;
+}
+
--- /dev/null
+#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
+