From: Mark Wooding Date: Tue, 14 Feb 2006 14:25:57 +0000 (+0000) Subject: Import ezmlm-idx 0.40 X-Git-Tag: idx/0.40^0 X-Git-Url: https://git.distorted.org.uk/~mdw/ezmlm/commitdiff_plain/f8beb284087c279acfb30506f5bb32baa4949b44 Import ezmlm-idx 0.40 --- diff --git a/BIN b/BIN index 76f0320..1c9db2b 100644 --- a/BIN +++ b/BIN @@ -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: diff --git a/CHANGES.idx b/CHANGES.idx new file mode 100644 index 0000000..49a4f8a --- /dev/null +++ b/CHANGES.idx @@ -0,0 +1,842 @@ +$Id: CHANGES.idx,v 1.66 1999/12/24 04:33:03 lindberg Exp $ +$Name: ezmlm-idx-040 $ + +BUGS: -ezmlm-idx does not implement a full rfc822 parser. Comments can be + inserted to defeat the MIME parsing mechanism, such as: + Content-Type: (comment) test/plain + This type of comment, while legal, does not occur in normal messages. + Guiding info past ezmlm-idx MIME parsing is easier done by enclosing + a message within a message. The mechanism isn't intended as a + "secure" way of preventing e.g. "application/ms-tnef" from being + disseminated. + If you think this is a problem, E-mail lindberg@id.wustl.edu. + Mimeremove/reject work only at the outer MIME layer. + -ezmlm-request requires addresses to be user@host. While rfc822 + compliant, addresses like ``"the man" @ host'' are not accepted. + -ezmlm-cgi doesn't deal optimally with holes in the archive. + -ezmlm-cgi seems not to work with Chinese. The problem has been to + find someone willing/able to participate in debugging. + +TODO: +-ezmlm-cgi to run directly under tcpserver. + +Acknowledgements, some are missing. Please write lindberg@id.wustl.edu +if you're missing. + +Some ezmlmrc are not updated and won't work right: +cn_GB,cs,pl,ru,da,pt_BR,pt + +If you fix them, please send them to lindberg@id.wustl.edu for inclusion +in the next version. + +ezmlm-idx-0.40, 19991220 +======================== +-Fixed bug in sub_mysql/issub.c that caused return of undef pointer for + non-subs. Security problem for sender checks, but not for moderation. Of + course only mysql version affected. +-Updated ezmlmrc translations. Thanks all who worked on this. +-added ezmlmrc.es. Thanks Vicent Mas/Francesc Alted/Sonia Lorente/Cyndy DePoy. +-added ezmlmrc.cn_GB. Thanks HG. +-ezmlm-weed: Groupwise garbage filter added. Thanks, SA. +-mysql: include files now don't have a dir. This is so that one can have + them in e.g. /usr/include. conf-sqlcc adjusted. +-Removed utils/. Not updated - add when done. +-Full PostgresSQL support. Thanks, MS. +-Corrected ordering of searchlog output for MySQL version to match default. + Thanks, MS. +-ezmlm-moderate/store: Fork /bin/sh ... instead of sh for people with unset + PATH. Thanks, TM. +-ezmlm-manage: rfc2369 headers added where possible also to admin + messages. Main finesse is that the WELCOME message has a custom + List-Unsubscribe header. -U/-S logic deconvoluted. -nN added. +-ezmlm-store: -B to send only header of message to moderate, rather than + the entire message. Used for send-only list with very large posts. +-ezmlm-reject: -b to reject messages with body or subject starting with + ``subscribe'' or ``unsubscribe''. +-support for List-ID (draft). Added to all list messages if DIR/listid is + present. The first line of that file is added after "List-ID: ". +-ezmlmrc: Added List-Subscribe header. Rewrite some texts, move some info + from bottom to help. Add ezmlm-archive (-i), add some switches to make + announcement lists easier. +-ezmlm-make: Modifed to make -I default since -i now controls ezmlm-archive + with all lists configured with ezmlm-get. Also, ezmlm-make will not overwrite + files tagged with #E in ezmlmrc when in edit mode (-+ or -e). This preserves + manual customization. The behavior can be overridden with -++ or -ee to + reset the list texts (old behavior). Added version check for ezmlmrc Tx, SA. +-ezmlm-archive and ezmlm-cgi added: Very easy to set up WWW access to list + archive. Support for various charsets incl iso-2022-*. For Russian, + one would need to do substitutions when making entries in archive/n/index. + This is not supported yet, so summary view entries may be incorrect if + the messages use Russian text in a charset different from the one the list + uses. Probably doesn't work for Chinese - lack of willing/able testers. +-qmail-qmqp support via idx.h and DIR/qmqpservers. If your bandwidth is + limited, look at this (see ezmlm-send(1)/ezmlm-get(1)/ezmlm(5)). If you + have large lists, sublist them locally and specify different QMQP servers + for each sublist via DIR/qmqpservers. Added qmail-qmqpc.tar.gz patch to + allow specifying QMQP server on command line. With this, DIR/qmqpservers can + be used to specify different servers for different lists for busy servers. +-ezmlm-gate: added -q file. Each line in "file" is processed as per + dot-qmail(5). 111 => temp_err, 99 => post, 100 => moderate, 0 => check sub. + Any other exit code will result in a bounce. + NOTE: This changes the behavior of ezmlm-gate used with only one DIR + argument (not used in any std listsetup for previous versions). Before, + this tested for subscriber status, now messages will + be moderated. This use is not set up by any ezmlm-make option and should + be _extremely_ rate. To obtain the old behavior, simply specify the + list directory twice. +-Made conf-sqlcc and conf-sqlld to support both phases of the build. Adjusted + mysql includes to not assume they're in a "mysql" subdir. + + +ezmlm-idx-0.324, 19990905 (PostgresSQL) +======================================= +-Minor typo in ezmlmrc.fr fixed. +-Added [partial] PostgresSQL interface by Magnus Stalaker. See INSTALL.idx. +-Added ezmlm-store Cc: docs mistakenly missed in 0.323. +-Fixed problem with "it/itall" target (Thanks MW). + + +ezmlm-idx-0.323, 19990815 (bug fix) +=================================== +-ezmlm-store: Cc: list-accept-subscribe remote admin conf added to mod + requests. For lists using ezmlm-gate, this allows adding poster as allowed + alias. Thanks RVI for suggesting. +-Added qmail-verh.tar.gz (0.03). This is the 0.02 qmail patch and a patch + to change ezmlmrc to take advantage of it. See docs inside. +-conf-sqlcc/conf-sqlld instead of conf-sql to allow include file additions + (conf-cc) and libraries (conf-ld) for RDBMS interfaces. +-Added ezmlmrc.id and ezmlmrc.it. Thanks APN and RDC. +-ezmlm-manage: Mime boundary was missing for subscribe notifications for + moderated lists using QP/base64 encoding. Thanks TF. +-ezmlm-get: Logic to prevent digest triggering from list-@host. +-ezmlm-get: Digest parts have file names list_msgnum.txt instead of + list.msgnum to work around a MS Outlook bug. Thanks, MH. +-ezmlm-request: Support for multipart MIME when used as a majordomo emulator. + Thanks, Johannes Ehrfeldt for reporting the bug. +-ezmlm-send: trailer was added to mutipart/non-alternative. Problems with + multipart/signed. Now, trailer for multipart is added only to mixed, + digest, and parallel. Thanks BPF. +-ezmlm-reject.1: typo. +-ezmlm-test.sh multiple minor changes to work on more platforms. Still, if + it doesn't work, the problem is most likely here, and not in ezmlm(idx) + itself. Thanks RM DM and others. +-ezmlm-moderate: added missing newline at beginning of MIME reject message. + Thanks, XXX. +-idx.h fixed ALT_XX alternative command names which erroneously started '-'. + Looks bad, but was of no consequence. + + +ezmlm-idx-0.322, 19990505 (bug fix) +=================================== +-ezmlmrc.*: Added x-confirm-reading-to and x-pmrqc. Thanks JK. +-ezmlmrc.ru: Added Russian version contributed by RVI. Thanks. +-ezmlmrc: Czech version of ezmlmrc is ezmlmrc.cz. Should be ezmlmrc.cs. Fixed. +-searchlog.c: Made the MySQL version also match in address field to make + the records returned the same as for std version. +-ezmlm-store: -allow-subscribe confirm address in Cc: header to make it easier + for the moderator to add the poster to the allow database. (Thanks, RVI.) +-ezmlm-manage: -query from remote admin for subscriber failed due to use of + static storage within issub(). Fixed. +-ezmlm-manage: Made remote admin unsub failure return error. For sub it's + important to be silent for multi-moderator setups, but since unsub is never + moderated, it's ok to return negative feedback, since it may be needed by + remote admins. As a consequence it was trivial to add -Q[Q] not quiet to + provide [un]subscribe feedback to the owner. +-ezmlm-send/reject: "boundary" in Content-type can be delimited by ';'. + Without, some messages could be erroneously rejected when using mimeremove. + New error text added to errtxt.h. + + +ezmlm-idx-0.321, 19990322 (bug fix) +=================================== +-added ezmlm-limit to limit list traffic. As this is a bug fix release, + ezmlm-limit should be considered experimental and is not built/installed + by default. (Thanks, TM for suggesting.) +-subscribe.c: in some cases a ``T'' was incorrectly added before the address + in the DIR/Log subscription log. Corrected (Thanks, PH.). +-ezmlm-test: reordered some tests to avoid timing problems on some + platforms. Tested hostname output since it may return a non-FQDN host name. + Added tests for most of the fixed bugs. +-ezmlm-tstdig: improved DEFAULT logic. Failed with existing incorrect inlocal + in virtual domains. +-ezmlm-manage bug: deny access control fixed. +-ezmlm-request/ezmlm-tstdig: qmail>=1.02 doesn't set DEFAULT when there is + nothing matching. Unable to detect qmail version here. Changed logic to + always be correct with qmail>=1.02 and virtually always for earlier versions. + Missing inlocal is taken as meaning qmail>=1.02. +-ezmlm-request: mdomo emulator: Corrected address listed for WHICH. +-ezmlm-request: Silent exit on bounces (NULL sender). Fake SENDER spam to the + majordomo address otherwise causes double bounces to postmaster who has + better things to do. +-ezmlmrc: corrected missing ezmlm-return in bouncer for normal (^6W) lists. + (Thanks Matt McGlynn.) +-opensql.c: psql needs to be destroyed for ezmlm-reqest WHICH which may open + connections to several servers. +-searchlog.c: made inbuf/ssin static. Was incorrect and generated linker + warning on some systems, but had no functional consequences. Thanks, SOH. +-ezmlm-test: converted "export ENVIRON=value" to "ENVIRON=value; export ENVIRON" + to work with Solaris sh. Also, moved final ezmlm-warn section to the end + to avoid timing issue on some systems. "ps" test for qmail made non-fatal, + as differing options on different ps make it more likely that ps use is + the problem than that qmail is not running. (Thanks, SOH.) + + +ezmlm-idx-0.32, 19990222 +======================== +-updated ezmlm-test. It tests most functions, and for important new features + or bugs discovered we'll add new tests in future. Thanks ME for patient + testing, suggestions, and "de-bashing". +-added a rfc2369 headers for list-help, list-post, and list-unsubscribe. + It takes little space, and may promote support in MUAs. +-ezmlm-get: list-get.9999999_x now always returns at least HISTGET messages + (default 30) provided that "9999999" is larger that the latest message number. + This allows embedding of an address for new subscribers to get at least what + has transpired since the latest digest and usually 30 messages before that, + to quickly see what's going on. +-ezmlm-get: list-get for non-digested lists now returns the latest HISTGET + (default 30) messages instead of the latest message. To get the latest message, + mail list-get-9999999, where "9999999" is larger than the latest message + number. +-Added ezmlm-manage/get -B switch to suppress text/bottom + request addition to + ezmlm-manage messages (except of course -help). +-ezmlm-send uses copy() for trailer and headeradd. <#h#>, <#l#>, and <#n#> + in these texts are substituted with outhost, outlocal, and message number, + respectively. Now you can add ``To receive this thread, mail + <#l#>-get.<#n#>@<#h#>'' to the trailer. Removed dir/sequence feature, since + this can now be done with headeradd. copy() modified to suppress blank + lines when copying headers. extern decl in copy.h fixed. A consequence + is that headeradd isn't added to the archive copy which is good. <#n#> + for ezmlm-get is the latest message processed, except for the digest, where + it is the first message in the digest (which is also the digest msg #). +-Added ezmlm-split (previously separate). Modified to use the same split + mechanisms as the SQL routines. -D switch to support easier reorganisation, + with extensive docs in man page. Interconversion between ezmlm-split and SQL + use is now relatively easy. +-Reorganized files. The subscriber db sources are now in sub_std/ for the + standard ezmlm db, sub_mysql/ for the mysql version. Normally, there are + symlinks to the std version. ``make mysql'' changes the symlinks to sub_mysql + and ``make std'' can be used to set them back. +-Replaced ezmlm-glmake with ``ezmlm-make -Cezmlmglrc''. See ezmlmglrc.5. +-Added status.pl for status monitoring of ``list trees'' via httpd. In utils/. +-Added feedback logging support with ezmlm-receipt and ezmlm-make -w. ezmlm-send + and ezmlm-get for the SQL version log info to the db. +-Added support for setting up a minimal (SQL-enabled) sublist: + ezmlm-make -Cezmlmsubrc. See ezmlmsubrc.5. +-Added ezmlm-make -w to remove ezmlm-warn invocation and if used with -6 to + configure ezmlm-receipt in place of ezmlm-return. Used for main list in + SQL-enabled list clusters for feedback and bounce logging. +-Added MySQL support. ezmlm-make -6. This is a _major_ change and makes it + trivial to do sublisting and dynamically redistribute load. see ezmlm.5. +-Modified ezmlm-return to add -dD switches. Previous design decision to have + ezmlm-return autodetect digest vs normal bounces cause problems when + sublisting a digest list. -dD force non-digest vs digest function and we'll + set uyp new lists with that, but keep autodetection for compatibility with + existing lists. ezmlmrc files modified appropriately. German version + updated and improved by Frank Tegtmeyer. Thanks! +-Modified ezmlm-warn/return bounce handling. DIR/bounce now has a ``h'' + subdir, further subdivided a-p for storage of h... files, where the first + character of the hash is used for the subdir, and a ``d'' subdir, containing + subdirs, each holding bounce (d... files) for a 10,000 s interval. This way, + only ``ripe'' bounce files are processed by ezmlm-warn. Also, ``lastd'' to + prevent unnecessary reparsing of bounces and ``lasth'' to keep track for + ``h'' subdir cleaning of remaining files older than 3x time out. +-Modified all programs to use DEFAULT if available. With qmail>=1.02, this + allows one to ignore inhost/inlocal so that special adjustment for virtual + domain lists is no longer required. Works the old way with qmail<1.02. +-DIR/extra and DIR/blacklist for extra allowed SENDERs and SENDER blacklisting + have been renamed DIR/allow and DIR/deny. This is used sparingly and the old + nomenclature was confusing. ``mkdir DIR/allow; mv DIR/extra/* DIR/allow'' + and the corresponding move for DIR/deny will take care of it. +-Extended the remote admin -log command. Now, -log.xxx will return only + Log lines matching 'xxx'. '.' matches '.' and '_' matches any character. +-The ``From:'' line of subscribers confirmation message will be logged to + ``Log''. This allows the administrator to use the Log to by name locate the + subscription address of a user. + + +ezmlm-idx-0.316, 19990815 (bug fixes only) +========================================== +-Migrated back fixes for 0.322 -> 0.323 that are applicable to 0.31x: +-ezmlm-get: Made filename extension constant for digest parts to work around + Outlook bug. +-ezmlm-manage: Mime boundary added for mod-sub-ok message when QP/base64 is + used. +-ezmlm-manage.1: Typo. +-ezmlm-moderate: Missing newline for non-MIME reject message. +-ezmlm-request: Support by global interface of multipart/alternative messages. +-ezmlm-send: Trailer only for some types of multipart messages. +-ezmlm-reject.1: Typo. + + +ezmlm-idx-0.315, 19990505 (bug fixes only) +========================================== +-Bug fixes fed back from up to 0.322. +-ezmlm-send/reject: "boundary" in Content-type can be delimited by ';'. + Without, some messages could be erroneously rejected when using mimeremove. + New error text added to errtxt.h. +-ezmlm-manage: -query from remote admin for subscriber failed due to use of + static storage within issub(). Fixed. +-ezmlm-manage bug: deny access control fixed. + + +ezmlm-idx-0.314, 19990216 (bug fixes only) +========================================== +-Added ezmlm-test, a script that tests [most] ezmlm + idx program functions. +-added ezmlmrc.cz (Thanks, Jan Kasprzak). +-ezmlm-make -e failed if DIR/config didn't exist. Fixed. (Thanks, SOH.) +-ezmlm-make man page bug for virtual domain (Thanks, XX). +-ezmlm-get segfaulted when run from the command line with LOCAL undefined. + Fixed. (Thanks, ME.) + +ezmlm-idx-0.313, 19981121 (bug fixes almost only) +================================================= +-ezmlm-get returns 0 for success in editor and command line use, rather than + 99. No impact on current lists, but makes more sense. +-ezmlm-warn tests >= for timeout rather than >. No impact other than easier + use with future test script. +-ezmlm-manage -get function was broken - fixed. Needed for backwards compat + with ezmlm-0.53. (Thanks, KS.) +-Reorganized INSTALL.idx, UPGRADE.idx, README.idx and introduced FILES.idx + to simplify. Made corrections to FAQ.idx, but no additions. +-ezmlm-send no longer adds trailer to multipart/mixed messages. Also, multipart + messages consisting of only "mimeremove" parts will be bounced. (Thanks, BE.) + The trailer is suppressed for base64-encoded messages. In both cases, + trailer addition might corrupt the message. Default charset is added if none + specified (was left empty). +-The US version of ezmlmrc is now ``ezmlmrc.en_US'' and ``make'' by default + copies it to ezmlmrc. Added support to Makefile and docs to copy in other + versions via e.g. ``make jp''. Target ezmlmrc is there to not overwrite with + ezmlmrc.en_US on ``make setup''. +-Changed ezmlmrc so that headeradd/headerremove/sub-ok/mod-sub are not rewritten + when editing lists. (Thanks, GS.) +-In ezmlm-idx and ezmlm-send, made dirs without trailing slash (mkdir with + it bombs on Ultrix). (Thanks, BW.) +-added check for NULL sender is zapnosub() in ezmlm-get. Fixed NULL pointer + use when the command is -dig- and no digest code was given on the command + line. +-added 'x' to FORMATS in idx.h. (Thanks, MMcL.) +-ezmlm-reject changed to honor subject continuation lines. Eudora likes to + break right after "Subject:" which caused rejection for empty subject. + (Thanks, SOH.) Same for To:. Also deals with quoted content types. Error + message now always states the offending MIME type. +-Added "(null)", "(none)", and "(no subject)" to rejected subjects. What are + these MUA authors thinking?? +-ezmlm-reject bug fixed to reject commands in subjects. (Thanks, JH.) +-ezmlm-request bug fixed to allow correct processing of complete command + addresses in the subject, even for virtual domains. (Thanks, EC.) +-ezmlmrc.de corrected (Thanks, FT). +-Made local check in ezmlm-tstdig case-insensitive (Thanks, Rick Myers). +-Fixed ezmlm-glconf to work with 'sh', not only 'bash' (missing ';' before '}') + (Thanks, MS). +-ezmlm-manage: text/bottom added also when moderated subscription is + completed (Thanks, SOH). Added -log command to ezmlm-manage. Allows remote + admins to retrieve Log if -l switch is set. Added -log into to mod-help via + ezmlmrc. +-Made character defines sun4 cc compliant in decode{Q|B}.c and unfoldHDR.c. +-Added support for "Sv:" and "Rv:" reply indicators (Nordic, Spanish). +-Improved/expanded ezmlm-check. +-Added -+ switch to ezmlm-make. Makes letter switches sticky (not -cC). + <#F#> is all letter switches, not only the ones set. (Thanks, SOH). Also, + added virtual domain info to ezmlm-make.1. + +ezmlm-idx-0.312, 19980805 (bug fixes only and support scripts added) +==================================================================== +-Fixed declaration of char16table[] in decodeQ.c to get clean mips64 compile + (Thanks, MF). +-Fixed ezmlm-request so that <#l#> and <#h#> are substituted correctly. +-Added ezmlm-glmake to create a global list setup. Left ezdomo.tar.gz since that + is what's documented in the FAQ. +-Fixed inconsistencies/errors in the ezdomo.tar.gz example files (Thanks, PN). +-Changed ezmlm-return.c to understand qmail preVERP error messages even if + qmail is patched to use MIME error messages. +-Added ezmlm-glconf and man page to the package. The program creates a config + file for the "majordomo-style" interface from a user's existing lists. +-Updated ezmlmrc and translations to not overwrite text/faq|info when editing + the list and add a note on -faq/-info to text/bottom and on -list/-edit + to text/mod-help. Thanks to the "usual suspects" for the translations! +-Corrected small bug in ezmlmrc.de and ezmlmrc.da. +-Corrected small bug in ezmlm-check -s switch handling (Thanks, DS). +-Fixed bug in unfoldHDR.c affecting handling of subject prefixes without + message number (Thanks, LL). + +ezmlm-idx-0.311, 19980701 (bug fix only) +======================================== +-Restored the mistakenly amputated ezmlmrc (English only, others were ok). +-Fixed ezmlm-gate to tolerate unset $SENDER (Thanks, AP). + +ezmlm-idx-0.31, 19980630 +======================== +-Added ezmlm-manage -m switch for moderated unsubscription, pre request. + (Thanks, FT). +-made cookie for accept/reject the same: ezmlm-moderate/ezmlm-store. +-ezmlmrc.da (Thanks, TF). Other ezmlmrc updated (Thanks: see README.idx). +-copy.c modified to allow NUL, multiple tags per line, and <#h#> => outhost. + (Thanks, TM). +-ezmlm-manage sends replies to "-help" from "list-return-@". This will break + all autoresponder loops for admin messages after 1 round. Otherwise, + ezmlm-warn and a broken responder can start an endless manage<->responder + exchange. (Thanks, MM.) +-Simplified tosubs(). Slightly less efficient with qmail, but avoids a lot + of problems. +-Added umask(022) to ezmlm-unsub.c and ezmlm-sub.c, in case they + are the ones to create dir/lock. +-ezmlm-moderate and ezmlm-gate changed to pass on switches for exec'd + programs. ezmlm-moderate sets sender for ezmlm-send so that -C switch + works also for moderated lists. +-ezmlm-accept now autoconfigured with ezmlm bin path and installed. +-ezmlm-manage allows remote access to the ``extra'' db (-allow-subscribe) + with same restrictions as for the main list. Access to the ``blacklist'' + db for remote admins only (-deny-subscribe). +-ezmlmrc changed to skip ezmlm-reject in editor of sublists. +-ezmlm-reject now rejects messages that do not contain the list + address in To:/Cc: (Thanks, DJB). ezmlmrc modified, since it requires + the ezmlm-reject line to have the list dir on the command line. Not full + rfc822 parser (see BUGS in ezmlm-reject.1!). +-made missing file in copy.c a permanent error. This way, it's discovered + sooner, as the list owner may not have access to maillog. +-docs updates, including adding terminal '/' to directories to make them + clearly distinct from files. +-Safer storage of return-path by ezmlm-store. +-ezmlm-send now adds a "Return-Path:" header to the archive copy. This way, + listowners without maillog access can get all the info (together with + "received:" and "delivered-to: lines). +-ezmlm-send -R switch to remove "Received:" headers that cause bounces to users + (due to too low sendmail hopcount) that can subscribe and are reached by + probes just fine. "received:" headers still go to the archive (Thanks, TM). +-Fixed minor bug in "reply-indicator" trimming (unfoldHDR.c). +-Make default behavior of -get command to send the messages that have arrived + since the last digest (up to MAXGET) if there has ever been a digest (only + last message otherwise). +-"prefix" number substitution changed to LAST '#'. Support for rfc2047 encoded + prefix. With iso-2022-* this will work only if characters after '#' are + ascii only, due to the removal of redundant ESC sequences from subjects before + comparison, and the need for any line to end in ascii. Improved robustness + of unfoldHDR.c (could be crashed with some illegal encoded words). +-Make reject messages come From: list-owner@listhost in ezmlm-moderate. A + "Reply-To: address" is added if "-t address" is on the command + line (Thanks, YG). +-ezmlm-get digesting now orders headers only for rfc1153 (mandated), otherwise + displays them as they come. The default headers included are the same, but + this can be overridden with dir/digheaders containing a list of the headers + to include. +-ezmlm-request takes the first line starting with a letter and interprets it + as a command, if the subject is empty or does not start with a letter. + Only one line is interpreted. +-ezmlm-request if used with "-f config" interprets "config" as a config file + of lists and list info. When used with this switch, it ignores the subject and + expects a command on the first body line. This is to service e.g. the + majordomo@host address. See man page. +-ezmlm-request understands a number of command synonyms to make it easier for + users familiar to other MLMs. These are just translated into regular ezmlm + commands for use with the list. +-ezmlm-manage services -faq, -info, and -query commands (see man page). Stubs +for faq/info added to ezmlmrc and to edit-list via ezmlmrc. +-ezmlm-check fixes for grep not understanding '-q' and a ezmlm-check -S switch + to avoid subscriber listing (Thanks, TEE). + +ezmlm-idx-0.302, 19980617 (bug fixes only) +========================================== +-Removed args from copy_insertsubject() call in ezmlm-send.c +-made ezmlm-make enforce absolute "dot". +-Fixed MIME newline bug in ezmlm-moderate/store/clean. (Thanks, JS). +-Fixed missing arg in postmsg() call from previous fix (Thanks, MF). + +ezmlm-idx-0.301, 19980508 (bug fixes only) +========================================== +-Digest format is multipart/digest again. The new format MIXED/'x' is + identical, except that it is multipart/mixed. The former works well for + most MUA. The latter is better for Pine when ezmlm texts are content- + transfer-encoded. +-RFC1153 format ignores content-transfer-encoding. This works fine with + us-ascii. For non-us-ascii it works if the mail path is 8-bit clean. RFC1153 + is really a us-ascii format, since the messages are dependent on the + encoding of the main message. This way is as good as it can get. +-Added many content-types to mimeremove in ezmlmrc (Thanks, SP). +-Removed most of the -x stuff in ezmlmrc. Now, -x only adds MIME content-type + stripping (extensive) and limits message body size to 2-40000 bytes. If you + want "Reply-To:" munging, edit ezmlmrc. The "mailto:" stuff was bad, and + the references to list-owner@host for intractable problems are now standard. +-Changed ezmlmrc extensions to iso 639: SV - Swedish. +-Added ezmlmrc files for DE, PL (Thanks, FT, SP). +-Fixed ezmlm-get: -index reply lacked MIME end boundary (Thanks, KI). +-Fixed bug in ezmlm-get: outformat error when using digest trigger messages + in dir/editor. (Thanks YG). +-Fixed bug in ezmlm-clean: cp_setlocal wasn't called. +-Improved ezmlmrc files so that digest links and dirs are not created for + on-digested lists. Decreases number of .qmail files. +-Fixed bug in ezmlm-get: Headers from trigger message are no longer copied + to digest (but are still copied to -index/-get/-thread reply). (Thanks STH.) +-Fixed ezmlm-0.53 bug in ezmlm-return. The "d..." file was the same for all + addresses of a pre-VERP bounce, resulting in only the first one being + processed correctly (sent to DJB). +-Changed ezmlm-get to include dir/headeradd headers for digest. (Thanks PH.) +-Changed ezmlm-get to send digest "To: list@list" from "list-digest@host". + This way, the list address is one of the "reply-to-all" addresses, just + as for list messages. (Thanks PH.) +-Corrected ezmlmrc: in some places "d" was used for "n" switch resuling in + missing dir/text files for editing if editing was enabled and digest + were not. (Thanks JS.) +-Corrected ezmlmrc/se/jp to add terminal ';' to list in ezmlm-issubn + lines. Caused trouble with strict /bin/sh as on FreeBSD. (Thanks STH.) +-Corrected ezmlm-make man page to show that "digestcode" is optional. + + +ezmlm-idx-0.30, 19980325 +======================== +-Fixed bug in continuation line handling for digest. In some circumstances, + continuations ended up with the wrong header. (Thanks SA). +-Changed digest format to multipart/mixed as pine has trouble with an + encoded text/plain part first in multipart/digest (although this is + rfc2046-ok). (Thanks SA). +-Updated FAQ, *.idx, and man pages for new functionality. +-Changed subdb.a folding qputsubs.c into putsubs.c and passing a pointer + to the write function. Better and necessary to allow QP/base64 output by + the ezmlm-manage -list command. +-Added ezmlm-warn -t switch to modify bounce time-out as well as moved the + compile-time default to idx.h (Thanks Mark Delany). +-Added note on "make clean" to INSTALL/UPGRADE.idx (Thanks Peter Hunter). +-Added support for message numbers in the prefix. This violates mail standards, + but is very popular in Japan. (Thanks KI for inspiring this.) ezmlm-idx-0.30 + does prefix differently, so that it modifies the subject as little as possible + for compliance with IETF recs and rfcs. ezmlm-idx-0.23 when prefix was used, + used a processed and unfolded subject, which was less correct, and could cause + problems with very long subjects. +-Changed MAXEDIT to 10k. This should accomodate all reasonable dir/text files. + A limit _is_ required (see FAQ: SECURITY). +-Made any _user-generated_ commands case-insensitive throughout (ezmlm-get, + -manage, -request). Note: ezmlm-generated ones, such as "list-accept" are + still case-sensitive. (Thanks GS for reminding me.) +-Separated ezmlm-make switches for SENDER checks. -u for posts, -g for archive. + Also changed names of other switches. -n for text file editing, -d for + digest list. ezmlm-manage edit is now -eE, but the old -dD is still accepted. +-Modified most programs to service requests for both list and digest list, + depending on LOCAL. For ezmlm-warn a command line -d switch is used to + process digest bounces. Created copy.h/c as a general routine that + does encoding and on-the-fly substitution of <#l#> to the name of the list + being serviced. ezmlmrc modified to set up list appropriately and create + a digest list for switch -d. The very rudimentary digest list is always + called 'list-digest' for the list 'list' and lives as a subscriber and a + bounce dir in dir/digest. log.c modified to take the dir as an argument. + copy.c introduced. Can deal with encoding and substitution for <#l#>, + <#B#>, <#R#>. +-Made dir/extra standard. All subscriber restriction (ezmlm-make -u) is + to accept addresses that are subscribers of either list or in dir/extra. +-Added REMOVE as a forbidden subject in ezmlm-reject. +-Added support for rejection based on message and message part MIME + Content-type. ezmlm-send can from composite MIME messages filter out + body parts based on content-type. Trailers are added as MIME parts + to composite MIME messages and in the Content-transfer-encoding of the + message for single body messages. +-min and max message size restrictions moved from ezmlm-send/store to + ezmlm-reject. +-Added support for optional base64 and quoted-printable encoding of trailer + and all outgoing ezmlm messages. The same encodings are accepted as input + for moderator comments and edited text files. +-Added hash for threading due to inconsistent/incorrect handling of LWSP + by iso-2022-jp MUAs. Now threading works for rfc2047 encoded subjects. +-Added support for rfc2047 encoded From: lines and continuation for From: + lines. +-Moved relevant parts of idxsub.c into ezmlm-send and ezmlm-idx. +-Added MIME en/decoding routines to support rfc2047 encoded subject lines. + Also, added code to remove redundant ESC sequences when unfolding headers + in iso-2022-jp* and iso-2022-cn* and iso-2022-kr. Only iso-2022-jp has been + tested. +-Added ezmlm-idx -d switch to use date from 'Date:' header instead of the + qmail received line. For old archives processed through ezmlm-send to + re-archive. Remove (GMT), (PST), and DOW, and make 2-digit years xx where + xx >= 70 19xx and others 20xx. + + +ezmlm-idx-0.231, 19980302 +========================= +-ezmlm-check.sh elsif -> elif. +-Allowed ezmlm-make -a switch (was missing; Thanks MF). +-Removed subject truncation for index: for prefixed lists it is used and +rfc2047-encoded subjects are often longer. +-Fixed idxsub.c bug (subject continuation lines skipped by ezmlm-idx if + 'Subject:' is after 'From:'). (Thanks, SOH.) + + +ezmlm-idx-0.23, 19980120 +======================== +-ezmlm-check fixed to remove bash-specific pattern matching. (Thanks, VV). +-ezmlm-both now makes completely functional list & digest list with digest + creation from dir/editor. If address is given, it becomes the owner, remote + admin, and a subscriber of both lists. By default, the remote admin is allowed + to get a subscriber list. +-updated ezmlmrc.fr. +-ezmlm commands now have alternates defined via idx.h, allowing aliases, rather + than replacement of command names in non-English domain. +-Modified ezmlm-tstdig to run easily from within dir/editor and dir/manager. + Had to add dir/tstdig timestamp when run from dir/editor, to prevent triggering + a new digest while one is being made. Now no new request is issued within one + hour after the last one. + Changed ezmlmrc to make this default for digested lists. +-New switches for ezmlm-make. +-Added ezmlm-get -f and -t switches for easier use on the command line and + in dir/editor. Made it "context-sensitive" by testing LOCAL. +-Via ezmlmrc added -q switch for processing commands to list-request, + a -3 hrs switch to configure ezmlm-tstdig in dir/manager, and some cleanup + in texts. +-Modified ezmlm-make to fall back to system ezmlmrc files (with warning) + if the -c switch is used by no custom ezmlmrc file is found. This makes + it possible for a GUI to rely more on ezmlm-make. +-Added ezmlm-request to redirect 'Subject:' line requests. +-Added ezmlm-cron, a very restrictive crond interface enabling users + without direct cron access to generate digest trigger messages. Suitable + to be run from scripts for non-shell users as well. See ezmlm-cron.1. +-modified ezmlmrc to set up sublists (-0 sublist@subhost), directories in + dir/modpost|modsub|remote with -789, and SENDER restriction on posts and + archive retrieval (-6 digest_dir). Doc'd in ezmlm-make.1. +-modified ezmlm-make to allow 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 in ezmlmrc. + + +ezmlm-idx-0.20, 19971030 +======================== +-Requests to ezmlm-moderate to accept/reject already processed messages + returns an error ONLY if the requested action is different from the actual + fate of the message. Keeps moderators happier in multi-moderator lists, + without info loss, with less traffic. +-A moderator's (un)subscribe CONFIRM reply results in target notification, + only if the target's status changed. Multiple moderators confirming no + longer yields multiple messages to target. +-ezmlm-manage copy() takes 2 arguments, the file name and a fall-back file + name in case the first file does not exist. CONFIRM requests to moderators + use text/mod-(un)sub-confirm (fall back: text/(un)sub-confirm). ezmlmrc + changed to set these up. +-Added MIME header to ezmlm-get -index response (to get DIR/charset effect). +-Updated docs and FAQ.idx. +-Pre-release compile testing on several platforms. (Thanks YG, ARB, MF, SK). +-Added DIR/msgsize. If it exists and is not 0, ezmlm-send and ezmlm-store will + bounce posts in excess of 'msgsize' bytes body size. +-Fixed ezmlm-clean to that when multiple messages time out, the message-id:s + are different. +-ezmlm-clean and ezmlm-moderate now by default return the post as a + MIME attachment. Use '-M' for old format. +-Rewrote ezmlm-make to work from the ezmlmrc template file for better + and easier customization. Changed moderator rejection comment tag to '%%%' + from '###' to support '#' as a comment character in ezmlmrc. '###' still + works. +-Added DIR/sequence for optional message number header, and DIR/charset for + character set. Thanks, SK. Default Compiled is now US-ASCII, as per rfc2046. +-Added TEST.idx, SECURITY.idx. +-ezmlm-get allows remote admins archive access even for non-public lists. The + ezmlm-get -pP switches override DIR/public effects. +-ezmlm-manage still does moderator-initiated (un)sub when DIR/public is absent. +-Fixed bug: Updated MIME to rfc2046. With this the ezmlm-get 'm' format is no + longer rfc1153-like. 'r' still gives rfc1153. Moderation attachments are now + message/rfc822. Hopefully, the pine attachment viewer will catch up. + Thanks, YG [and Mutt developers] for teaching me the errors of my ways. Also, + see ezmlm-get.1(BUGS). +-ezmlm-manage gives moderator help and does list if target is moderator, + rather than sender. Allows moderator to access from secondary account (to + which mail sent to the primary account is forwarded). +-ezmlm-store checks DIR/modpost for leading '/' and if found assumes that the + first line is the base directory for message moderators. +-ezmlm-manage checks DIR/modsub and DIR/remote contents for a leading '/'. + If found, it is assumed to be the base-dir for moderators. NB: if both + DIR/modsub and DIR/remote have entries, only DIR/modsub is used, i.e. it + is not possible to have different dbs for remote admin and (un)sub mods. +-Modified ezmlm-manage to add separate moderator confirm commands (tc/vc) + to allow also subscription moderator via forwarded mail. This is essentially + a total rewrite of ezmlm-manage. Also, the -S and -U switches were added to + allow optional omission of the user confirm phase for (un)subscribe. + USE OF THESE SWITCHES DRASTICALLY DECREASES SECURITY, except for + moderated lists. Since there have been many request for this (and it + seems reasonable in some circumstances) these options have been added. + Make sure you understand the consequences if you use them. +-Fixed bug: Added exit code to ezmlm-moderate. Thanks BG. +-Added include for sys/types.h to ezmlm-clean.c and ezmlm-store.c, changed + ulong/uint to unsigned long/int, removed void from empty parameter lists for + two functions, all to compile on BSDI 2.1 and Sun. Thanks, ARB and TE. +-Combined ezmlm-mod with ezmlm-idx and fused mod.h into idx.h. + +ezmlm-idx-0.12, 19970910 +======================== +-Cleanups to allow compile on SGI. Thanks MF. + +ezmlm-idx-0.11, 19970907 +======================== +-Fixed bug: ezmlm-idx failed to check for error return from issub.c. +-Fixed bug: ezmlm-idx would crash on empty subjects. +-Moved out command names and lengths to idx.h making changing to other + languages easier. Please use this only for totally local lists. +-Added -cC switches to ezmlm-get to disable all but -dig. Useful for secret + lists that are archived and digested. +-Fixed bug: -dig would give "nothing to digest" with only 1 new message. Now + it sends that message out (previously, this message would have been in the + next digest as soon as more messages had arrived). +-Added DIR/prefix. If it exists, it is prefixed to outgoing subjects. Not + added to archive/index. ezmlm-idx deals with it. 'Re: ' is prefixed for + replies, since we use reply-parsed subject in ezmlm-send. A lot of pain for + little gain, but for some reason this seems to be a 'must'. +-Changed idxsub routines to return 1 if reply indicators were fund, 0 else. +-Changed idxthread routines from int to void (don't return anything). +-Split out errtxt.h from idx.h in anticipation of ezmlm-mod. +-changed ezmlm-send to honor 'mailing-list' in headerremove. +-fixed ezmlm-make to deal with non-archived and non-indexed lists and to + point out that -index works in sets of 100. +-ezmlm-get error msg on non-sub -thread request fixed. +-Added DIR/text/trailer. If it exists, it is added to all messages, as + suggested by Fred B. Ringel. It is not copied to the archive. +-ezmlm-make changed to adapt text/bottom to archived/indexed status of list. +-Fixed usage text for ezmlm-send. +-'Reply-To:' header from messages is included in standard MIME digests + (after reading Dan's comments on Reply-To munging). rfc1153 doesn't allow it. +-Changed ezmlm-get.c default to NOT restrict get/index/thread to subscribers. +-Fixed ezmlm-get.1 to correctly reflect effect of -s/-S switches. +-Fixed FAQ and added more info. + +ezmlm-idx-0.10, 19970801 +======================== +-Added several items to FAQ. +-Made digestcode case-insensitive. +-Fixed format bugs causing trouble with PINE (Thanks Fred B. Ringel). +-Improved handling of missing index file in indexed archives. +-Added info on -get and -index restrictions to text/bottom. +-Added FAQ.idx (a little silly at the moment ;-). +-Added CHANGES.idx. + Updated README.idx, UPDATE.idx, ezmlm.5 and other man pages. +-Added text/digest to allow standard info to be added to the list. A place + holder is put in by ezmlm-manage, since the exact info depends on the + digest list. +-Moved all error messages into defines in idx.h to support alternative + languages. +-folded subject indexing into ezmlm-send. +-ezmlm-get.c: Added -s (default) restricting -get, -index, -thread to + subscribers. -S on the command line removes this restriction. +-Added support for the horrid German 'Aw:' and 'Aw[..]:' replies. +-All linear white space is converted to a single ' ' in subject indexing. + Existing archives should be re-indexed using the new ezmlm-idx. Probably rarely + needed, but it's more correct. +-Added support for subject continuation lines (rfc822). Probably very rarely + needed. +-Limited '-thread' to +/- 2000 messages (defines in ezmlm-get.c) from the + "master message" to limit resource use on large archives. +-Changed limit for '-get' to 50 messages, '-index' to 20 sets (2000 subjects). +-Added digestcode support to ezmlm-make as a 5th argument. Default=blank. +-Added arguments to digest option. If one is given, digesting starts with that + message and dignum/digissue are used/updated. If both are given, dignum and + digissue are not updated and the issue number is the number of the first + message in the archive. +-Added digest support. Enabled by specifying a 'digestcode'last on the + ezmlm-get command line. +-Removed the now redundant -fF (filter) and -qQ (quote) options. +-Changed message format for returned messages allowing rfc1153, MIME + multipart/digest, or MIME multipart/digest ordering and retaining only headers + as per rfc1153, with the addition of 'Content-Type:' to better support + alternative character sets. The latter format is the default. +-Fixed bug in -thread: search for messages was set to start at the beginning + of the index containing the "master message", rather than at the beginning of + the archive. +-Fixed bug: A few stralloc* were incorrectly stdio* in sindex.c. + +ezmlm-idx-0.02, 19970702 +======================== +-Adapted to changes in ezmlm-0.52 => ezmlm-0.53. + +ezmlm-idx-0.01, 19970615 +======================== diff --git a/DOWNGRADE.idx b/DOWNGRADE.idx new file mode 100644 index 0000000..59a1114 --- /dev/null +++ b/DOWNGRADE.idx @@ -0,0 +1,36 @@ +$Id: DOWNGRADE.idx,v 1.3 1997/12/30 21:30:56 lindberg Exp $ +$Name: ezmlm-idx-040 $ + +MODIFYING ezmlm-idx lists to work with "virgin" ezmlm-0.53 + +With ezmlm-idx-0.22, the routines issub.c and subscribe.c are modified to +store subscriber addresses using a hash based on the lower case address, +rather than a case sensitive hash. This was done to avoid the many problems +with subscribers using mixed case addresses (User@host and user@host) without +realizing that these are different. + +These changes have no impact on lower case-only addresses. For mixed case +addresses, the case in the local part is retained. If not found, a second +lookup is done with a hash based on the mixed case address. This results in +backwards compatibility with ezmlm-0.53 subscriber list. + +In the unlikely event that you use ezmlm-idx and then decide to go back to +ezmlm-0.53 alone, mixed case addresses stored in the new location +(case-insensitive hash) will not be found by the old ezmlm-0.53 programs. +To place them in the ezmlm-0.53 position, do the following with your lists +after installing the "virgin" ezmlm-0.53 binaries and backing up everything +under DIR/subscribers: + + % ezmlm-list DIR >tmp.tmp + % rm -rf DIR/subscribers/* + % xargs ezmlm-sub DIR + + +o + + +o + + +o + + +o + + +o + + +o + + +o + + TThhee llaatteesstt vveerrssiioonn ooff eezzmmllmm--iiddxx + 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 _m_a_y 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. + + + +o + + +o ftp + mirror in Austria. + + +o http + access to the same mirror. + + +o ftp + mirror in Japan. + + eezzmmllmmrrcc((55)) ffiilleess ffoorr ddiiffffeerreenntt llaanngguuaaggeess + 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. + + + +o + + +o + + +o + + +o + + eezzmmllmm--iissssuubb--00..0055 + + +o . 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. + + +o Also via mirrors mentioned above. + + + RRPPMMss aanndd SSRRPPMMSS ooff qqmmaaiill,, eezzmmllmm aanndd eezzmmllmm--iiddxx + + +o + + +o + + + 11..66.. WWhheerree ccaann II ffiinndd ddooccuummeennttaattiioonn ffoorr eezzmmllmm aanndd ppaattcchheess?? + + + mmaann ppaaggeess + All ezmlm component programs come with their own man pages. + Thus, for info on _e_z_m_l_m_-_s_e_n_d, 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 + + + + + + eezzmmllmm((55)) + General info on ezmlm and list directories is in eezzmmllmm..55: + + + + % man ezmlm + + + + + or + + + + % cd ezmlm-0.53 + % man ./ezmlm.5 + + + + + _N_O_T_E_: 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)). + + + TTeexxtt ffiilleess iinn tthhee ddiissttrriibbuuttiioonn + ezmlm comes with a RREEAADDMMEE file with general instructions, an + IINNSSTTAALLLL file with installation instructions, an UUPPGGRRAADDEE file for + upgrading from a previous version and a CCHHAANNGGEESS file with + information on changes from previous versions. ezmlm-idx comes + with similar files suffixed with ``..iiddxx''. 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''. + + + ````EEzzmmaann'''',, aann eezzmmllmm//iiddxx mmaannuuaall + 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: + + +o ezman for download + + +o An on-line html version + + + TThhiiss FFAAQQ + This FAQ is built from a sgml source. It is available in the + following formats: + + +o A text file + + +o An on-line html version + + +o Html for download + + + +o A postscript (letter) version + + + +o A postscript (A4) version + + + +o Via mirrors mentioned for the ezmlm-idx package. + + +o An up-to-date text version,FFAAQQ..iiddxx, included with the ezmlm-idx + package. + + + WWWWWW rreessoouurrcceess + + AAnn oonn--lliinnee vveerrssiioonn ooff tthhiiss FFAAQQ + The main site with an up-to-date + mirror list. German mirror. + Polish mirror. + Japanese mirror. + Portuguese mirror. + Austrian mirror. + Canadian mirror. + + GGeenneerraall qqmmaaiill aanndd eezzmmllmm iinnffoo + + +o Dan J. Bernstein's qmail page + + + +o Dan J. Bernstein's ezmlm page + + + +o Russell Nelson's qmail page + + +o Mirrors of www.qmail.org . + Substitute your two-letter country abbreviation for ``ISO''. + + TThhee qqmmaaiill mmaaiilliinngg lliisstt aarrcchhiivvee + + + +o + + TThhee eezzmmllmm mmaaiilliinngg lliisstt aarrcchhiivvee + + +o + 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. + + MMaaiilliinngg lliissttss + 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: + + +o Dan Bernstein's ezmlm list: ezmlm-subscribe@list.cr.yp.to + + +o A digest version of the ezmlm list fredr-ezmlm-digest- + subscribe@rivertown.net + + +o Dan Bernstein's qmail list: qmail-subscribe@list.cr.yp.to + + +o The Japanese ezmlm list: ezmlm-subscribe@jp.qmail.org + + +o The Japanese qmail list: qmail-subscribe@jp.qmail.org + + +o A ezmlm/idx digest list of djb-qmail: qmail-digest- + subscribe@id.wustl.edu + + +o A ezmlm/idx sublist of djb-qmail (you can test ezmlm-idx + commands): qmail-index@id.wustl.edu + + + 11..77.. WWhheerree ddoo II sseenndd ccoommmmeennttss oonn tthhiiss ddooccuummeenntt?? + + To the authors via E-mail: + + +o Fred Lindberg, lindberg@id.wustl.edu + + +o Fred B. Ringel, fredr@rivertown.net + + + 11..88.. HHooww ttoo eexxppeerriimmeenntt wwiitthh nneeww vveerrssiioonnss ooff eezzmmllmm--iiddxx.. + + ezmlm-idx>=0.23 writes DDIIRR//ccoonnffiigg 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 _l_o_s_e _m_a_n_u_a_l _c_u_s_t_o_m_i_z_a_t_i_o_n_s _t_o _s_o_m_e _o_f _y_o_u_r + _f_i_l_e_s. However, text files and DDIIRR//hheeaaddeerraadddd 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 IINNSSTTAALLLL..iiddxx (if you haven't used ezmlm-idx before) + or UUPPGGRRAADDEE..iiddxx (if you've got a previous version of ezmlm-idx + installed), setting ccoonnff--bbiinn 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 //eettcc//eezzmmllmmrrcc file, you may need to temporarily + place the eezzmmllmmrrcc((55)) file for the ezmlm version you want to test in + ddoottddiirr 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. + + + 22.. QQuuiicckk ssttaarrtt + + + 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 ccoonnff--bbiinn and ccoonnff--mmaann 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 (FFAAQQ..iiddxx in the distribution), + RREEAADDMMEE//RREEAADDMMEE..iiddxx, IINNSSTTAALLLL//IINNSSTTAALLLL..iiddxx, and UUPPGGRRAADDEE..iiddxx. + + + 33.. OOvveerrvviieeww ooff mmaaiilliinngg lliisstt mmaannaaggeemmeenntt aanndd mmaaiilliinngg lliisstt mmaannaaggeerrss + + (To be written. Until then, please consult the + manual for ezmlm and ezmlm-idx related + material.) + + + 44.. OOvveerrvviieeww ooff eezzmmllmm ffuunnccttiioonn + + + 44..11.. TThhee bbaassiicc sseettuupp.. + + In designing ezmlm, _D_a_n _J_. _B_e_r_n_s_t_e_i_n 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. + + + 44..22.. IInnvveennttiioonnss iinn eezzmmllmm.. + + 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. + + + 44..33.. TThhee qqmmaaiill ddeelliivveerryy mmeecchhaanniissmm.. + + 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 ..qqmmaaiill 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 ..qqmmaaiill 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 ..qqmmaaiill 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 + ..qqmmaaiill 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. + + + 44..44.. WWhhaatt tthhee ddiiffffeerreenntt pprrooggrraammss ddoo.. + + See ezmlm(5) and the man pages for the different programs (listed in + ezmlm(5)). + + + 44..55.. WWhhaatt tthhee ddiiffffeerreenntt ffiilleess iinn tthhee lliisstt ddiirreeccttoorryy ddoo.. + + See ezmlm(5). + + + 44..66.. TThhee ppaappeerr ppaatthh ffoorr ppoossttss.. + + Messages to the list are delivered to a ..qqmmaaiill file, usually ~~//..qqmmaaiill-- + lliissttnnaammee which is linked to DDIIRR//eeddiittoorr. 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 ..qqmmaaiill-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, DDIIRR//eeddiittoorr 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 DDIIRR//eeddiittoorr 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, DDIIRR//eeddiittoorr 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. + + + 44..77.. TThhee eezzmmllmm ppaatthh ffoorr mmooddeerraattiioonn mmeessssaaggeess.. + + Replies to moderation requests are channeled to DDIIRR//mmooddeerraattoorr. 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 _c_o_n_t_r_a_r_y to the moderation message. + Thus, if you accept a message already accepted, no error message is + sent. ezmlm-clean(1) is also invoked from DDIIRR//mmooddeerraattoorr for house + keeping. + + + 44..88.. TThhee eezzmmllmm ppaatthh ffoorr aaddmmiinniissttrraattiivvee mmeessssaaggeess.. + + Administrative requests for both list and digest lists are captured by + ~~//..qqmmaaiill--lliissttnnaammee--ddeeffaauulltt linked to DDIIRR//mmaannaaggeerr. 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 DDIIRR//tteexxtt// 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. + + 44..99.. TThhee eezzmmllmm ppaatthh ffoorr bboouunncceess.. + + Bounces to the list are handled by DDIIRR//bboouunncceerr. For the digest list + this is DDIIRR//ddiiggeesstt//bboouunncceerr. 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 DDIIRR//bboouunnccee// for the list and + DDIIRR//ddiiggeesstt//bboouunnccee// for the digest. This is the information that + ezmlm-warn(1) (invoked from DDIIRR//eeddiittoorr and DDIIRR//mmaannaaggeerr) uses and + processes for automatic bounce handling. ezmlm-return(1) will also + unsubscribe a subscriber from whom a probe message has bounced. + + + 44..1100.. MMeessssaaggeess ttoo lliisstt--oowwnneerr aanndd lliisstt--ddiiggeesstt--oowwnneerr.. + + These are processed by DDIIRR//oowwnneerr and delivered to DDIIRR//mmaaiillbbooxx by + default. It is better to put the real owner address in this location. + This can be done manually, via editing of eezzmmllmmrrcc((55)), or via the + ezmlm-make(1) -5 switch. Again, some house-keeping functions are also + executed. + + + 44..1111.. SSttrruuccttuurree ooff ssuubbssccrriibbeerr ddaattaabbaasseess.. + + ezmlm subscriber E-mail addresses are stored within DDIIRR//ssuubbssccrriibbeerrss// + 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 DDIIRR//ssuubbssccrriibbeerrss// 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''). + + + 44..1122.. LLooccaall ccaassee iinn EE--mmaaiill aaddddrreesssseess.. + + 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. + + + 44..1133.. TTeessttiinngg SSEENNDDEERR ttoo aallllooww ppoossttss oonnllyy ffrroomm lliisstt ssuubbssccrriibbeerrss.. + + 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 + DDIIRR//aallllooww//. 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 DDIIRR//aallllooww// 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 ..qqmmaaiill 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 DDIIRR//, DDIIRR//ddiiggeesstt//, or DDIIRR//aallllooww// and exit silently, put the + following into the relevant ..qqmmaaiill 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 _N_O_T 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 DDIIRR//ddeennyy, 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. + + + 44..1144.. HHooww ccooookkiieess wwoorrkk.. + + Each ezmlm list has it's own ``key'' created by ezmlm-make at setup + time. This key is stored in DDIIRR//kkeeyy, 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: + + +o the request, + + +o the time, + + +o 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 + _P_G_P). + + + 44..1155.. HHooww mmooddeerraattoorr EE--mmaaiill aaddddrreesssseess aarree ssttoorreedd.. + + Moderator E-mail addresses are stored just like ezmlm subscriber + addresses, in a set of up to 53 files within the ssuubbssccrriibbeerrss + subdirectory of the list's bbaasseeddiirr//. For subscribers, the bbaasseeddiirr// is + the list directory itself, i.e. DDIIRR//. For moderators, the default is + DDIIRR//mmoodd//, which can be overridden by placing a bbaasseeddiirr name (starting + with a ``/'') in DDIIRR//mmooddssuubb, DDIIRR//rreemmoottee, or DDIIRR//mmooddppoosstt for + subscription moderation, remote administration, and message + moderation, respectively. This permits the use of one moderator + database for multiple lists. _N_o_t_e_: _S_u_b_s_c_r_i_p_t_i_o_n _m_o_d_e_r_a_t_o_r_s _a_n_d _r_e_m_o_t_e + _a_d_m_i_n_i_s_t_r_a_t_o_r_s _a_r_e _a_l_w_a_y_s _t_h_e _s_a_m_e _a_d_d_r_e_s_s_e_s_. _I_f _b_o_t_h DDIIRR//mmooddssuubb and + DDIIRR//rreemmoottee contain paths, only the DDIIRR//mmooddssuubb path is used. + + + 44..1166.. HHooww ssuubbssccrriippttiioonn mmooddeerraattiioonn wwoorrkkss.. + + 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 _d_i_f_f_e_r_e_n_t _a_c_t_i_o_n _c_o_d_e. 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 _s_h_o_u_l_d know) the + qmail/ezmlm/unix paradigm: _i_f _y_o_u_'_r_e _n_o_t _t_o_l_d _o_t_h_e_r_w_i_s_e_, _y_o_u_r _c_o_m_m_a_n_d + _w_a_s _c_a_r_r_i_e_d _o_u_t _s_u_c_c_e_s_s_f_u_l_l_y. 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 DDIIRR//mmooddssuubb and adding + the subscription moderator to DDIIRR//mmoodd//: + + + % ezmlm-sub DIR/mod moderator@host + + + + + To use an alternative basedir for subscription moderators, place that + directory name with a leading ``/'' in DDIIRR//mmooddssuubb. + + + 44..1177.. HHooww rreemmoottee aaddmmiinniissttrraattiioonn wwoorrkkss.. + + 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 DDIIRR//rreemmoottee and adding the + remote administrator E-mail address(es) to DDIIRR//mmoodd//: + + + % ezmlm-sub DIR/mod remoteadm@host + + + + + To use an alternative basedir for remote administrators, place that + directory name with a leading ``/'' in DDIIRR//mmooddssuubb. Remote administra- + tors and subscription moderators databases always consist of the same + E-mail addresses. If both are enabled and one of DDIIRR//mmooddssuubb and + DDIIRR//rreemmoottee contains an alternative basedir name, this basedir is used + for both functions. If both DDIIRR//mmooddssuubb and DDIIRR//rreemmoottee contain direc- + tory names, the one in DDIIRR//mmooddssuubb 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. + + + 44..1188.. HHooww mmeessssaaggee mmooddeerraattiioonn wwoorrkkss.. + + ezmlm-store(1), invoked in DDIIRR//eeddiittoorr, receives messages for message + moderated lists. If DDIIRR//mmooddppoosstt 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 DDIIRR//mmooddppoosstt exists, ezmlm-store(1) places the + message in DDIIRR//mmoodd//ppeennddiinngg//. 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 DDIIRR//mmooddeerraattoorr. ezmlm-moderate(1) validates the request, + and if the request is valid and the message is found in + DDIIRR//mmoodd//ppeennddiinngg//, 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 + DDIIRR//mmoodd//rreejjeecctteedd// or DDIIRR//mmoodd//aacccceepptteedd// for ``reject'' and ``accept'' + requests, respectively. + + If a valid reply is received but the message is no longer in + DDIIRR//mmoodd//ppeennddiinngg//, ezmlm-moderate(1) looks for the corresponding stub + in DDIIRR//mmoodd//rreejjeecctteedd// and DDIIRR//mmoodd//aacccceepptteedd//. 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 + DDIIRR//mmoodd//ppeennddiinngg// until it times out. Cleanup of both messages and + stubs is accomplished by ezmlm-clean(1) which is invoked through both + DDIIRR//eeddiittoorr and DDIIRR//mmooddeerraattoorr 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 DDIIRR//mmooddttiimmee) 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 DDIIRR//mmoodd//. This can be changed to + any other bbaasseeddiirr by placing the name of that directory with a leading + ``/'' in DDIIRR//mmooddppoosstt. Although the default basedirs for message + moderation and subscription moderation/remote administration are the + same, both the functions and actors are entirely independent. + + + 44..1199.. HHooww QQMMQQPP ssuuppppoorrtt wwoorrkkss + + 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 DDIIRR//qqmmqqppsseerrvveerrss//00. The list housed in + DDIIRR 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 DDIIRR//qqmmqqppsseerrvveerrss//00, just as you normally + would in //vvaarr//qqmmaaiill//ccoonnttrrooll//qqmmqqppsseerrvveerrss. 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. + + + 44..2200.. HHooww mmeessssaaggeess aarree ssttoorreedd iinn tthhee aarrcchhiivvee.. + + The structure of the ezmlm list archive is described in the ezmlm(5) + manual page. Basically, the message is stored in DDIIRR//aarrcchhiivvee//nn//mm, + where ``n'' is the message number divided by 100 and ``m'' the + remainder (2 digits). The first message is stored in DDIIRR//aarrcchhiivvee//00//0011. + + + 44..2211.. HHooww tthhee mmeessssaaggee iinnddeexx wwoorrkkss.. + + 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 DDIIRR//aarrcchhiivvee//nn//iinnddeexx, where ``n'' is the + message number mod 100. Thus, the directory DDIIRR//aarrcchhiivvee//5522// 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. + + + 44..2222.. HHooww tthhrreeaaddiinngg wwoorrkkss.. + + 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. + + + 44..2233.. HHooww ddiiggeessttss wwoorrkk.. + + 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 + DDIIRR//ddiiggeesstt//. Digest list subscriber addresses in + DDIIRR//ddiiggeesstt//ssuubbssccrriibbeerrss// and digest list bounce information in + DDIIRR//ddiiggeesstt//bboouunnccee//. 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 (DDIIRR//ddiiggiissssuuee and DDIIRR//ddiiggnnuumm) 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: + + CCoommmmaanndd lliinnee + 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''). + + + ffrroomm DDIIRR//eeddiittoorr + 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 DDIIRR//eeddiittoorr + digests are triggered only when messages are received). + + In DDIIRR//eeddiittoorr, 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 DDIIRR//eeddiittoorr: + + + |/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. + + ffrroomm DDIIRR//mmaannaaggeerr + 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 DDIIRR//mmaannaaggeerr 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 DDIIRR//mmaannaaggeerr. 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 DDIIRR//eeddiittoorr works + very well, and does not require any extra setup work. + + CCoommbbiinnaattiioonn sseettuuppss + The default setup in the ezmlmrc(5) file included in the + distribution is the DDIIRR//eeddiittoorr 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 DDIIRR//mmaannaaggeerr), with + extra digest sent when traffic is unusually high (via the ezmlm- + tstdig/ezmlm-get limits set in DDIIRR//eeddiittoorr). 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. + + + 44..2244.. HHooww WWWWWW aarrcchhiivvee aacccceessss wwoorrkkss.. + + If the list is set up with ezmlm-make -i, ezmlm-archive(1) will be + invoked from DDIIRR//eeddiittoorr. This program creates indices for threads, + subjects, and authors under DDIIRR//aarrcchhiivvee from the iinnddeexx files. ezmlm- + cgi(1) is set up per user or globally (see man page) and told about + different lists via the //eettcc//eezzmmllmm//eezzccggiirrcc 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. + + + + + 44..2255.. HHooww eezzmmllmm--ttssttddiigg wwoorrkkss.. + + ezmlm-tstdig(1) looks at DDIIRR//nnuumm and DDIIRR//ddiiggnnuumm 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 DDIIRR//eeddiittoorr, or in + DDIIRR//mmaannaaggeerr. In the latter two cases, ezmlm-tstdig(1) verifies that + the list local address is correct. If invoked in DDIIRR//mmaannaaggeerr, 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 DDIIRR//ttssttddiigg 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. + + + 44..2266.. HHooww ssuubblliissttss wwoorrkk.. + + 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 DDIIRR//ssuubblliisstt. + + 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 DDIIRR//ssuubblliisstt 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 DDIIRR//eeddiittoorr so that the _e_z_m_l_m_- + _s_e_n_d line contains the command line option ``--hh _X_-_L_i_s_t_p_r_o_c_e_s_s_o_r_- + _V_e_r_s_i_o_n_:'' (before DDIIRR). 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 _a_n_d 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 DDIIRR//eeddiittoorr has ``-h'' and + ``DDIIRR'' on it, ezmlm-reject(1) will read DDIIRR//hheeaaddeerrrreejjeecctt and reject + messages that have any header specified in that file. See the ezmlm- + reject(1) man page for suitable headers. + + + + 44..2277.. HHooww ssuubblliissttiinngg ccaann bbee mmaaddee ttrraannssppaarreenntt ttoo tthhee uusseerr.. + + 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 DDIIRR//mmaannaaggeerr. If it detects a subscribe or unsubscribe + command, it will forward the command to the appropriate sublist based + on a ``split file'' DDIIRR//sspplliitt. 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''). + + 44..2288.. HHooww ttoo sseerrvviiccee ccoommmmaannddss iinn tthhee ssuubbjjeecctt lliinnee.. + + 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 + DDIIRR//mmaannaaggeerr. 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 DDIIRR//mmaannaaggeerr 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 DDIIRR//oouuttllooccaall (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 DDIIRR//oouuttllooccaall, ezmlm-request(1) prefixes the + line with the contents of DDIIRR//oouuttllooccaall, thereby building a complete + ezmlm command. If a host name is specified, it must match the contents + of DDIIRR//oouutthhoosstt, 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 DDIIRR//mmaannaaggeerr. + + To set up a list to include ezmlm-request processing, use the ezmlm- + make(1) ``-q'' switch. The default is to not do this. + + + 44..2299.. HHooww ttoo ssuuppppoorrtt aalltteerrnnaattiivvee ccoommmmaanndd nnaammeess.. + + 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. + + + + + 44..3300.. HHooww ttoo aadddd yyoouurr oowwnn ccoommmmaannddss.. + + The qmail/ezmlm mechanism makes it very easy to add your own commands. + You can add them to DDIIRR//mmaannaaggeerr, but this requires great care in terms + of ordering and exit codes. Easier is to set them up separately with a + ..qqmmaaiill--lliisstt--ccoommmmaanndd 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 <>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 + DDIIRR//bboouunnccee//dd//, one per 10,000 seconds. The corresponding address + hashes are stored in 16 subdirectories of DDIIRR//bboouunnccee//hh//. Instead of + looking at all bounces, ezmlm-warn(1) processes only the bounces in + DDIIRR//bboouunnccee//dd// subdirectories that are ``due''. In addition, ezmlm- + warn(1) uses DDIIRR//bboouunnccee//llaassttdd 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. + + + 44..3388.. HHooww tthhee iinnffoo aanndd ffaaqq ccoommmmaannddss wwoorrkk.. + + The _-_i_n_f_o and _-_f_a_q commands simply reply with the contents of the + DDIIRR//tteexxtt//iinnffoo and DDIIRR//tteexxtt//ffaaqq files. Edit these files directly or + remotely (see ``How to remotely edit dir/text files''). The + DDIIRR//tteexxtt//iinnffoo 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''). + + + 44..3399.. HHooww tthhee gglloobbaall eezzmmllmm lliisstt aaddddrreessss wwoorrkkss.. + + 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. + + + 44..4400.. HHooww eezzmmllmm--ccrroonn wwoorrkkss.. + + 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 + eezzccrroonnrrcc 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 + + + + 44..4411.. HHooww eezzmmllmm--mmaakkee wwoorrkkss.. + + 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 //eettcc// 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 + ..eezzmmllmmrrcc 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 + _e_z_m_l_m_r_c_._a_l_t'' to use _e_z_m_l_m_r_c_._a_l_t 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 DDIIRR//kkeeyy 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 DDIIRR//ccoonnffiigg. 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 DDIIRR//ccoonnffiigg. 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 + DDIIRR//ccoonnffiigg. + + _N_o_t_e_: DDIIRR//tteexxtt// 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 eezzmmllmmrrcc, use ``-ee'' or ``-++''. + + _N_o_t_e_: 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. + + + 44..4422.. WWhhaatt nnaammeess ccaann II uussee ffoorr mmyy lliissttss?? + + 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 nnoott part of the ..qqmmaaiill 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 ~~aalliiaass// directory. + + + 44..4433.. LLiissttss iinn vviirrttuuaall ddoommaaiinnss + + 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. + + + 44..4444.. HHooww ddoo II mmaakkee ccuussttoommiizzaattiioonn ssiimmppllee ffoorr mmee//mmyy uusseerrss?? + + 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 ``eezzmmllmmrrcc''. A default eezzmmllmmrrcc((55)) is installed in the + ezmlm binary directory. If installed, a system-wide customized ezmlmrc + file in //eettcc//eezzmmllmmrrcc (or symlinked from there) overrides this. + Installing a ~~//..eezzmmllmmrrcc file in a user ddoottddiirr and using the ezmlm- + make(1) ``-c'' switch allows further per user customization (see + ``Customizing ezmlm-make operation''). + + + 55.. eezzmmllmm ssuuppppoorrtt ffoorr SSQQLL ddaattaabbaasseess.. + + + 55..11.. WWhhyy uussee aann SSQQLL ddaattaabbaassee wwiitthh eezzmmllmm?? + + 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. + + + 55..22.. WWhhyy nnoott ttoo uussee aann SSQQLL ddaattaabbaassee wwiitthh eezzmmllmm.. + + 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. + + + 55..33.. TTaabblleess uusseedd ffoorr ((MMyy))SSQQLL ssuuppppoorrtt.. + + 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. + + + 55..33..11.. AAddddrreessss ttaabblleess.. + + + lliisstt + List subscriber addresses. + + lliisstt__ddiiggeesstt + Digest list subscriber addresses. + + lliisstt__aallllooww + 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. + + lliisstt__ddeennyy + 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. + + lliisstt__mmoodd + Moderator addresses. Created for completeness, but not used in + the default configuration. If moderators are used, the addresses + are stored in a local database. + + + 55..33..22.. SSuubbssccrriibbeerr lloogg ttaabblleess.. + + 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''). + + + 55..33..33.. MMeessssaaggee llooggggiinngg ttaabblleess.. + + For both the list and the digest list, there are a pair of tables that + log messages: + + + lliisstt__ccooookkiiee + 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 DDIIRR//kkeeyy, 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''. + + + lliisstt__mmlloogg + 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 _a_f_t_e_r 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. + + + + + 55..44.. HHooww ttoo sseett uupp aa ssiimmppllee lliisstt wwiitthh SSQQLL ssuuppppoorrtt.. + + To use SQL database support, you have to compile the programs with SQL + support. Currently, only MySQL support is available. See IINNSSTTAALLLL..iiddxx + 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 ssqqll 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. + + + 55..44..11.. HHeellppeerr pprrooggrraammss ffoorr SSQQLL--eennaabblleedd lliissttss.. + + 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. + + + CCrreeaattiinngg tthhee ttaabblleess + 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. + ). + + 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. + + + CCrreeaattiinngg aa uusseerr eennttrryy + Create a user that has full access to the database from the list + host. How to do this depends on the RDBMS. + + + CCrreeaattiinngg tthhee lliisstt + 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). + + + 55..55.. MMaannuuaallllyy mmaanniippuullaattiinngg tthhee ssuubbssccrriibbeerrss ooff aa SSQQLL--eennaabblleedd lliisstt.. + + 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). + + + 55..66.. CCoonnvveerrttiinngg ttoo aanndd ffrroomm aanndd SSQQLL ddaattaabbaassee.. + + Just like other programs, ezmlm-list(1), ezmlm-sub(1), and ezmlm- + unsub(1) will work with normal address databases in the absence of + DDIIRR//ssqqll. However, they also have a ``-M'' switch to force this + behavior even in the presence of DDIIRR//ssqqll. 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). + + _N_o_t_e_: This inter-conversion requires the DDIIRR//ssqqll 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 DDIIRR//ssqqll exists. + + + 55..77.. OOppttiimmiizziinngg MMyySSQQLL ffoorr eezzmmllmm.. + + + 55..77..11.. AAddddrreessss SSEELLEECCTTss,, aaddddiittiioonnss,, rreemmoovvaallss.. + + 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). + + + 55..88.. MMaaiinntteennaannccee ooff tthhee MMyySSQQLL ddaattaabbaassee.. + + 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 ( + ) for more info. + + + 66.. PPoossssiibbllee eerrrroorr ccoonnddiittiioonnss iinn eezzmmllmm lliissttss.. + + + 66..11.. WWhhaatt ddoo II ddoo iiff eezzmmllmm ddooeessnn''tt wwoorrkk?? + + Try to determine where the problem occurs and how to reproduce it: + + +o Do messages to ezmlm return an error message to the sender or not? + + +o What is/are the error message(s)? + + +o What does ezmlm log into the mail log? + + +o Are you using a setup with virtual domains, and qmail<1.02 or + ezmlm-idx<0.31? If so, have you adjusted DDIIRR//iinnllooccaall (see + ``Adapting ezmlm-make for virtual domains'')? + + +o Are posts sent out to the subscribers? + + +o Are there subscribers? + + + % ezmlm-list DIR + + + + + +o Are there moderators? + + + + % ezmlm-list moddir + + + + + where ``moddir'' is the contents of DDIIRR//rreemmoottee (for remote admin + lists), of DDIIRR//mmooddssuubb (for subscription moderated lists) or DDIIRR//mmoodd-- + ppoosstt (for message moderation), if and only if the contents start with + a forward slash. The default in all cases is DDIIRR//mmoodd//. If both + DDIIRR//mmooddssuubb and DDIIRR//rreemmoottee contain directory names, the one in DDIIRR//mmoodd-- + ssuubb is used for both subscription moderation and remote admin. + + +o 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). + + +o Read the qmail log and capture relevant parts. + + +o Did you customize the package at all? If so, try the default + settings which are known to work. + + +o Did you customize eezzmmllmmrrcc((55))? Try to use the default copy (skip the + -c switch). + + +o Did your customization of ..eezzmmllmmrrcc fail to have an effect? + Remember to use the -c switch. The ..eezzmmllmmrrcc file used is the one in + ``dotdir'', i.e. the directory where the ..qqmmaaiill files go, usually, + but NOT necessarily, the one in your home directory. + + +o 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. + + +o Make sure to take notes of how the list was created (which flags + you used, etc.). + + +o use ezmlm-check(1) (see ``Using ezmlm-check to find setup + errors''). and compare the variables identified by ezmlm-check to + DDIIRR//iinnllooccaall, etc. If you don't get a reply from ezmlm-check, then + message was not delivered properly. Check your qmail setup. + + +o Try to find your problem or a question/item close to it in the FAQ. + + +o 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. + + + 66..22.. HHooww ddoo II rreeppoorrtt eezzmmllmm bbuuggss?? + + 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. + + + 66..33.. WWhheerree ddoo II sseenndd ssuuggggeessttiioonnss ffoorr eezzmmllmm--iiddxx iimmpprroovveemmeennttss?? + + E-mail to lindberg@id.wustl.edu, ideally with a context diff. For + ezmlm proper, ezmlm@list.cr.yp.to may be better. + + + 66..44.. UUssiinngg eezzmmllmm--tteesstt ttoo cchheecckk tthhee eezzmmllmm((--iiddxx)) pprrooggrraammss.. + + 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. ~~//____TTSSTTDDIIRR____eerrrr may contain a relevant error + message. For further help, E-mail lindberg@id.wustl.edu. + + + 66..55.. UUssiinngg eezzmmllmm--cchheecckk ttoo ffiinndd sseettuupp eerrrroorrss.. + + ezmlm-check(1) is included in the ezmlm-idx distribution. ezmlm- + check(1) is an evolving shell script which when put into a ..qqmmaaiill 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 + DDIIRR//iinnhhoosstt 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 DDIIRR//eeddiittoorr + (for mail to list), DDIIRR//mmaannaaggeerr (for mail to list-subscribe, list- + help, etc), DDIIRR//mmooddeerraattoorr (for mail to list-accept, list-reject). + ezmlm-check(1) will send its output to SENDER. The rest of the ..qqmmaaiill + 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. + + + 66..66.. PPoossttss aarree rreejjeecctteedd:: SSoorrrryy,, nnoo mmaaiillbbooxx hheerree bbyy tthhaatt nnaammee + ((##55..11..11)).. + + 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 ~~vviirrtt//..qqmmaaiill--tteesstt + 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 ~~uusseerr//..qqmmaaiill--tteesstt + 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 ~~vviirrtt//..qqmmaaiill--tteesstt for the list test@virtual.dom and ~~uusseerr//..qqmmaaiill-- + tteesstt for the list user-test@host. + + + 66..77.. PPoosstt aarree nnoott sseenntt ttoo ssuubbssccrriibbeerrss.. + + + NNoonn--mmooddeerraatteedd lliissttss + + 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!). + + + MMeessssaaggee mmooddeerraatteedd lliissttss + + 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 DDIIRR//mmssgg-- + ssiizzee 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). + + + GGeenneerraall + + 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), tthhee mmoosstt ccoommmmoonn eerrrroorr iiss + tthhaatt tthheerree aarree nnoo ssuubbssccrriibbeerrss.. 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. + + + 66..88.. eezzmmllmm--mmaakkee ffaaiillss:: uussaaggee:: eezzmmllmm--mmaakkee ...... + + 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. + + + 66..99.. eezzmmllmm--mmaakkee ffaaiillss:: UUnnaabbllee ttoo ccrreeaattee ...... + + This error occurs when ezmlm-make is used to set up a list, and it + tries to create a directory or a ..qqmmaaiill--lliisstt 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: _N_O_T_E_: _D_O _N_O_T _U_S_E _T_H_E_S_E + _C_O_M_M_A_N_D_S _W_I_T_H_O_U_T _U_N_D_E_R_S_T_A_N_D_I_N_G _T_H_E_M_. 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 DDIIRR//tteexxtt//), make backup + copies first, run ezmlm-make, then copy the backups to DDIIRR//tteexxtt//. Of + course, it is usually easier to create a custom ..eezzmmllmmrrcc, 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 DDIIRR//eeddiittoorr will be overwritten. For instance, if + you manually added checks to DDIIRR//eeddiittoorr or added a pointer to a custom + moderator database in e.g. DDIIRR//mmooddssuubb these changes will be lost. To + retain such changes (especially ones that are common for several of + your lists), place them in a local ~~//..eezzmmllmmrrcc file instead. You can + either make such changes the default for your lists, or you can + configure ~~//..eezzmmllmmrrcc so that they are added only if a specific ezmlm- + make switch is used. (see ``Customizing ezmlm-make operation''). + + + 66..1100.. eezzmmllmm--mmaakkee ffaaiillss:: ...... eezzmmllmmrrcc ddooeess nnoott eexxiisstt + + There is no readable ezmlmrc(5) file in //eettcc//eezzmmllmm nor in the ezmlm + binary directory. If you have ..eezzmmllmmrrcc in ``dotdir'' (see + ``Terminology: dotdir'') use the ezmlm-make(1) ``-c'' switch (see + ``Customizing ezmlm-make operation''). _N_o_t_e_: The default location for + a global edited eezzmmllmmrrcc file is //eettcc//eezzmmllmm//eezzmmllmmrrcc as of ezmlm- + idx-0.40. + + + 66..1111.. IInnddeexx//ggeett//tthhrreeaadd rreeqquueessttss ffaaiill qquuiieettllyy oorr wwiitthh eerrrroorrss ffrroomm + eezzmmllmm--mmaannaaggee.. + + Make sure this is an indexed list and has an ``ezmlm-get'' line first + in DDIIRR//mmaannaaggeerr. 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. + + + 66..1122.. DDiiggeesstt ttrriiggggeerriinngg rreeqquueessttss ffaaiill.. + + (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. + + + 66..1133.. RReemmoottee aaddmmiinniissttrraattiioonn ((uunn))ssuubbssccrriibbee ccoonnffiirrmm rreeqquueessttss ggoo ttoo tthhee + uusseerr,, nnoott tthhee mmooddeerraattoorr.. + + Either the list is not set up for remote administration (i.e. + DDIIRR//rreemmoottee 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 + DDIIRR//rreemmoottee. If you are using a non-default moderator db location, make + sure that the moddir name is in DDIIRR//rreemmoottee (for remote admin only) or + DDIIRR//mmooddssuubb (if there is subscription moderation as well). In both + cases, the contents will be ignored unless they start with a ``/''. + + + 66..1144.. ((UUnn))ssuubbssccrriibbeerrss ddooeess nnoott rreecceeiivvee aa ((uunn))ssuubbssccrriibbee aacckknnoowwlleeddggee-- + mmeenntt + + 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). + + + 66..1155.. MMeessssaaggeess ppoosstteedd ttoo aa mmooddeerraatteedd lliisstt aarree sseenntt oouutt wwiitthhoouutt mmooddeerr-- + aattiioonn.. + + The list is not set up as a moderated list. Check DDIIRR//eeddiittoorr. 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 DDIIRR//eeddiittoorr. + If there is, the list is not moderated. Also, DDIIRR//mmooddppoosstt 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 DDIIRR//mmooddppoosstt, but may be confusing if the user is unaware of + this ezmlm-store(1) feature. + + + 66..1166.. MMeessssaaggeess ppoosstteedd ttoo aa mmooddeerraatteedd lliisstt ddoo nnoott rreessuulltt iinn mmooddeerraattiioonn + rreeqquueessttss.. + + + +o Check that ~~//..qqmmaaiill--lliisstt is a link to DDIIRR//eeddiittoorr. + + +o Check that DDIIRR//eeddiittoorr contains ezmlm-store(1) and not ezmlm- + send(1). If this is not the case, the list is not message + moderated. + + +o Check for the presence of DDIIRR//mmooddppoosstt. If this file is missing, the + list is not moderated, even if DDIIRR//eeddiittoorr is set up with ezmlm- + store(1). + + +o 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. + + +o Check to see that there are indeed moderators: + + + + % ezmlm-list moddir + + + + + where ``moddir'' is the contents of DDIIRR//mmooddppoosstt if they start with a + ``/'', otherwise those of DDIIRR//rreemmoottee (same ``/'' requirement), and + DDIIRR//mmoodd// by default. + + + +o 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 + + + + + + 66..1177.. MMooddeerraattiioonn rreeqquueesstt rreepplliieess ddoo nnoott rreessuulltt iinn tthhee aapppprroopprriiaattee + aaccttiioonn.. + + + +o Check that the address in the moderation request is correct. + + +o Check that the ~~//..qqmmaaiill--lliisstt--aacccceepptt--ddeeffaauulltt and ~~..//qqmmaaiill--lliisstt-- + rreejjeecctt--ddeeffaauulltt links exists and point to DDIIRR//mmooddeerraattoorr. + + +o Check that DDIIRR//mmooddeerraattoorr invokes ezmlm-moderate(1), and that there + is a copy of ezmlm-send(1) in the ezmlm binary directory. + + +o Check the qmail log to see that the replies were delivered to this + address. + + +o Check directory ownerships. For lists under alias: + + + + % chown -R alias DIR + + + + + _N_O_T_E_: 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 _a_l_i_a_s, 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. + + +o Check the qmail logs: After the delivery of the moderation request, + ezmlm-send(1) should run to send messages to all the list + subscribers. + + +o 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. + + + 66..1188.. MMooddeerraattoorr ccoommmmeennttss wwiitthh mmooddeerraattiioonn rreeqquueesstt rreepplliieess aarree nnoott + aaddddeedd ttoo tthhee ppoosstt//sseenntt ttoo tthhee ppoosstteerr.. + + 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 aacccceepptteedd + 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 + DDIIRR//eeddiittoorr 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>%%% + + + + + 66..1199.. SSoommee hheeaaddeerrss aarree mmiissssiinngg ffrroomm mmeessssaaggeess iinn tthhee ddiiggeesstt.. + + By default, only a subset of message headers are sent out in any + digest and archive retrieval requests. First, headers in + DDIIRR//hheeaaddeerrrreemmoovvee 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. + + + 66..2200.. SSoommee RReecceeiivveedd:: hheeaaddeerrss aarree mmiissssiinngg ffrroomm mmeessssaaggeess.. + + 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. + + + 66..2211.. MMyy MMuutttt uusseerrss ccaannnnoott tthhrreeaadd tthheeiirr ddiiggeesstt mmeessssaaggeess.. + + The digest by default removed non-essential headers like ``In-Reply- + To:'' from messages. Modern MUAs, like _M_u_t_t 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. + + + 66..2222.. PPoossttss ffaaiill:: MMeessssaaggee aallrreeaaddyy hhaass MMaaiilliinngg--LLiisstt ((##55..77..22)).. + + 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 + DDIIRR//ssuubblliisstt. Check the ownership of DDIIRR//ssuubblliisstt, 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''). + + + 66..2233.. TThhee llaasstt lliinnee ooff aa DDIIRR//tteexxtt// ffiillee iiss iiggnnoorreedd.. + + Only complete lines ending with ``newline'' are copied. The last line + in the DDIIRR//tteexxtt// file most likely lacks a terminal ``newline''. + + + 66..2244.. NNoo CCOONNFFIIRRMM rreeqquueessttss aarree sseenntt ttoo mmooddeerraattoorrss.. + + 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 ``DDIIRR//mmoodd//''. + + 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. + + + 66..2255.. DDeelliivveerriieess ffaaiill ````tteemmppoorraarryy qqmmaaiill--qquueeuuee eerrrroorr'''' + + 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. + + + + + + 66..2266.. HHooww ttoo ddeeaall wwiitthh ccoorrrruupptteedd ssuubbssccrriibbeerr lliissttss + + 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 DDIIRR//ssuubbssccrriibbeerrss//, 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. + + + 66..2277.. VVaaccaattiioonn pprrooggrraamm rreepplliieess aarree ttrreeaatteedd aass bboouunncceess bbyy eezzmmllmm.. + + 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 DDIIRR//hheeaaddeerraadddd. For older lists, use ``ezmlm-make -+'' or + ``ezmlm-make -e'' to update them, or just add a ``Precedence: bulk'' + line to DDIIRR//hheeaaddeerraadddd. + + + 66..2288.. DDiiggeessttss ddoo nnoott ccoommee aatt rreegguullaarr hhoouurrss.. + + 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 + + + + + + 66..2299.. PPrreevveennttiinngg llooooppss ffrroomm mmiissccoonnffiigguurreedd ssuubbssccrriibbeerr aaddddrreesssseess.. + + 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 DDIIRR//ddeennyy// 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 DDIIRR//eeddiittoorr or DDIIRR//mmaannaaggeerr. 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. + + + 66..3300.. AA uusseerr ccaann ssuubbssccrriibbee aanndd rreecceeiivveess wwaarrnniinngg aanndd pprroobbee mmeessssaaggeess,, + bbuutt nnoo mmeessssaaggeess ffrroomm tthhee lliisstt.. + + 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 _-_g_e_t_v 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. + + + 77.. CCuussttoommiizziinngg eezzmmllmm--mmaakkee ooppeerraattiioonn vviiaa eezzmmllmmrrcc + + + 77..11.. UUssiinngg eezzmmllmm--mmaakkee ttoo eeddiitt eexxiissttiinngg lliissttss.. + + 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 (DDIIRR//nnuumm), digest counters (DDIIRR//ddiiggnnuumm + and DDIIRR//ddiiggiissssuuee), the key (DDIIRR//kkeeyy) 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 DDIIRR//ccoonnffiigg) 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. + + _N_O_T_E_: ezmlm-make(1) ``-e'' and ``-+'' will OVERWRITE any manual + customizations you have made to the program files, but not text files + and DDIIRR//hheeaaddeerraadddd, DDIIRR//hheeaaddeerrrreemmoovvee, etc. To reset all such files + (such as when changing list name), use ``-ee'' or ``-++''. + + To make general customizations, please change eezzmmllmmrrcc((55)) (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''). + + + 77..22.. WWhhaatt iiss eezzmmllmmrrcc?? + + ezmlm-make(1) has a number of default switches that through eezzmmllmmrrcc((55)) + 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 eezzmmllmmrrcc((55)) file in + //eettcc//eezzmmllmmrrcc (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 ..eezzmmllmmrrcc in the ``dotdir'', i.e. the + directory in which the ..qqmmaaiill--lliisstt 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). + + eezzmmllmmrrcc((55)) controls everything except creation of the list directory + itself and the key used for cookie generation. The syntax of + eezzmmllmmrrcc((55)) 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. + + + 77..33.. CChhaannggiinngg ddeeffaauullttss ffoorr DDIIRR//tteexxtt// ffiilleess.. + + Copy the ezmlmrc(5) file from the ezmlm bin directory to ..eezzmmllmmrrcc in + your ..qqmmaaiill file base directory (usually your home directory): + + + % cp /usr/local/bin/ezmlm/ezmlmrc ~/.ezmlmrc + + + + + The base eezzmmllmmrrcc((55)) file lives in the ezmlm binary directory, which + may differ from ``//uussrr//llooccaall//bbiinn//eezzmmllmm//eezzmmllmmrrcc'' if you do not have a + default setup. If your system administrator has placed a ezmlmrc(5) + file into the //eettcc directory, start with that one instead, as it is + likely to already contain some useful local customization and + comments. + + Now edit ~~//..eezzmmllmmrrcc. Find the tag corresponding to the text file you + want to change, e.g. ``'', 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 ``'' is copied into DDIIRR//tteexxtt//ffiillee if and + only if the ezmlm-make(1) ``-rms'' switches are all used. For more + info, see documentation in eezzmmllmmrrcc((55)) and the ezmlm-make(1) man page. + To invoke a custom ..eezzmmllmmrrcc file, use the ezmlm-make(1) ``-c'' + (custom) switch. + + + 77..44.. CChhaannggiinngg ddeeffaauulltt mmooddeerraattoorr ddiirreeccttoorriieess.. + + See above. Edit the ..eezzmmllmmrrcc file to add a directory name to e.g. + ``''. Also, you need to create that directory, and the + subscribers subdirectory under it. NOTE: DDIIRR//mmoodd// is still required as + the base directory for the message moderation queue. + 77..55.. AAddaappttiinngg eezzmmllmm--mmaakkee ffoorr vviirrttuuaall ddoommaaiinnss.. + + 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 DDIIRR//iinnllooccaall. 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 ..eezzmmllmmrrcc file in ~~vviirrtt//. In + the ``'' section of this file, enter ``virt-<#L#>'' instead + of ``<#L#>''. Now, all lists created under ~~vviirrtt 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 + ``''. + + Running: + + + % ezmlm-make -c ~virt/LIST ~virt/.qmail-dom1-list \ + list host1.dom.com + + + + + will produce a LLIISSTT//iinnllooccaall 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 (_S_i_c_!)). For more info, + see ezmlm-make(1) and comments in eezzmmllmmrrcc. + + + 77..66.. SSeettttiinngg uupp eezzmmllmm--mmaakkee ffoorr ssppeecciiaall ssiittuuaattiioonnss.. + + 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 ..eezzmmllmmrrcc 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 eezzmmllmmrrcc((55)). Many + switches, have special meanings via eezzmmllmmrrcc((55)) and are documented in + the man page. Any other switches can be used for customization (_N_O_T_E_: + _w_e _m_a_y _u_s_e _s_w_i_t_c_h_e_s _o_t_h_e_r _t_h_a_n _`_`_-_x_y_z_'_' _f_o_r _s_p_e_c_i_f_i_c _p_u_r_p_o_s_e_s _i_n + _f_u_t_u_r_e _v_e_r_s_i_o_n_s_.) The ``-xyz'' switches will always be available for + your use, with the ``-x'' switch being configured for some + demo/special features in the distributed eezzmmllmmrrcc((55)). 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 eezzmmllmmrrcc((55)) 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 DDIIRR//ccoonnffiigg (if available). + + + 88.. RReessttrriiccttiinngg mmeessssaaggee ppoossttiinngg ttoo tthhee lliisstt.. + + + + 88..11.. RReeqquuiirriinngg tthhee lliisstt aaddddrreessss iinn TToo:://CCcc:: hheeaaddeerrss.. + + 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. + + + 88..22.. RReejjeeccttiinngg mmeessssaaggeess sseenntt ffrroomm ootthheerr mmaaiilliinngg lliissttss.. + + 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 + DDIIRR//hheeaaddeerrrreejjeecctt. 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 DDIIRR on + the ezmlm-reject(1) line in DDIIRR//eeddiittoorr. Naturally, you can make this + the default by editing ezmlmrc(5) (See ``Customizing ezmlm-make + operation''). + + + 88..33.. RReessttrriiccttiinngg ppoossttss bbaasseedd oonn tthhee SSuubbjjeecctt lliinnee.. + + 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 DDIIRR//eeddiittoorr 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 DDIIRR//bbaadd__wwoorrddss. + + + 88..44.. RReessttrriiccttiinngg tthhee ssiizzee ooff ppoossttss.. + + If the ``DIR'' argument is specified on the ezmlm-reject(1) line in + DDIIRR//eeddiittoorr and DDIIRR//mmssggssiizzee 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 DDIIRR//mmssggssiizzee 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 eezzmmllmmrrcc((55)): + + + + max:min + + + + + The ezmlm-make(1) ``-x'' switch adds this with 40000:2. + + + 88..55.. RReessttrriiccttiinngg ppoossttss bbaasseedd oonn MMIIMMEE ccoonntteenntt--ttyyppee.. + + ezmlm-reject(1) will look for DDIIRR//mmssggssiizzee, DDIIRR//mmiimmeerreejjeecctt, and + DDIIRR//mmiimmeerreemmoovvee if the ``DIR'' argument is specified (``DIR'' can be + left out to conserve resources on lists that do not use these + features). _N_o_t_e_: _T_h_e _`_`_D_I_R_'_' _a_r_g_u_m_e_n_t _i_s _a_l_s_o _r_e_q_u_i_r_e_d _f_o_r _t_h_e _t_h_e + _T_o_:_/_C_c_: _l_i_s_t _a_d_d_r_e_s_s _r_e_s_t_r_i_c_t_i_o_n _(_s_e_e _`_`_R_e_q_u_i_r_i_n_g _t_h_e _l_i_s_t _a_d_d_r_e_s_s _i_n + _T_o_:_/_C_c_: _h_e_a_d_e_r_s_'_'_)_. If the message contains MIME parts that are of a + content-type listed in DDIIRR//mmiimmeerreejjeecctt they are rejected. If the + message is a simple MIME message of a content-type listed in either + DDIIRR//mmiimmeerreejjeecctt or DDIIRR//mmiimmeerreemmoovvee it is also rejected. + + There is currently no ezmlm-make(1) switch for DDIIRR//mmiimmeerreejjeecctt, but it + can easily be configured by editing eezzmmllmmrrcc((55)). The ezmlm-make ``-x'' + switch configures DDIIRR//mmiimmeerreemmoovvee (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. + + + 88..66.. RReessttrriiccttiinngg ppoossttss ttoo lliisstt ssuubbssccrriibbeerrss.. + + 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; } + + + + + _A_L_L _O_N _O_N_E _L_I_N_E to DDIIRR//eeddiittoorr 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 + DDIIRR//ddiiggeesstt// from the ezmlm-issubn command line. To allow posts from an + address that is not a subscriber, simply add it to the addresses in + DDIIRR//aallllooww//: + + + % 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)''. + + + + 88..77.. RReessttrriiccttiinngg ppoossttss ttoo aann aarrbbiittrraarryy sseett ooff EE--mmaaiill aaddddrreesssseess + ((hhiigghheerr sseeccuurriittyy ooppttiioonn)).. + + 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. + + + 88..88.. CCoommpplleetteellyy rreessttrriiccttiinngg ppoossttss.. + + To completely prevent posting (for instance a message-of-the-day + list), set up a normal list, and just remove ~~//..qqmmaaiill--lliisstt and + DDIIRR//eeddiittoorr 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 + + + + + _N_O_T_E: 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 DDIIRR//ssuubbssccrriibbeerrss// and other address lists. + + + 88..99.. AA ggeenneerraall ssoolluuttiioonn ttoo rreessttrriiccttiinngg ppoossttss bbaasseedd oonn SSEENNDDEERR.. + + 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 DDIIRR//eeddiittoorr in place of the + ezmlm-send(1) line. To the ezmlm-gate(1) command line add the list + directory twice, then a digest directory DDIIRR//ddiiggeesstt// (if it exists), + then DDIIRR//aallllooww//. Create DDIIRR//mmooddppoosstt. 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 DDIIRR//aallllooww//, 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 DDIIRR//aallllooww//. 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 DDIIRR//eeddiittoorr and DDIIRR//mmooddeerraattoorr. + + 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. + + + 99.. CCuussttoommiizziinngg oouuttggooiinngg mmeessssaaggeess.. + + + 99..11.. AAddddiinngg aa ttrraaiilleerr ttoo oouuttggooiinngg mmeessssaaggeess.. + + Put the text in DDIIRR//tteexxtt//ttrraaiilleerr. 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. + + + 99..22.. AAddddiinngg aa ssuubbjjeecctt pprreeffiixx ttoo oouuttggooiinngg mmeessssaaggeess.. + + Put the exact text in DDIIRR//pprreeffiixx. You can include the message number + assigned to the post in the list archive by adding the ``#'' character + in the text in DDIIRR//pprreeffiixx (example: put ``lsqb;listname-#rsqb;'' in + DDIIRR//pprreeffiixx). 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 DDIIRR//pprreeffiixx. + + 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. + + + 99..33.. AAddddiinngg aa hheeaaddeerr ttoo oouuttggooiinngg mmeessssaaggeess.. + + Put the exact header text as a line in DDIIRR//hheeaaddeerraadddd. Thus, if you'd + like a ``Precedence: bulk'' header added to outgoing messages, put a + line ``Precedence: bulk'' into DDIIRR//hheeaaddeerraadddd. 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 DDIIRR//hheeaaddeerraadddd, 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. + + + 99..44.. AAddddiinngg aa mmeessssaaggee nnuummbbeerr hheeaaddeerr.. + + Don't! A sequence header may be useful for users whose systems don't + pass on the ``Return-to:'' header to the MUA. + + Use DDIIRR//hheeaaddeerraadddd 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 DDIIRR//sseeqquueennccee 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. + + 99..55.. RReemmoovviinngg hheeaaddeerrss ffrroomm oouuttggooiinngg mmeessssaaggeess.. + + Put the header up to, but excluding the ``:'' in DDIIRR//hheeaaddeerrrreemmoovvee. + + + 99..66.. RReemmoovviinngg MMIIMMEE ppaarrttss ffrroomm mmeessssaaggeess.. + + 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 DDIIRR//mmiimmeerreemmoovvee. This is + automatically configured when using the ezmlm-make(1) ``-x'' switch. + + + 99..77.. LLiimmiittiinngg ````RReecceeiivveedd::'''' hheeaaddeerrss iinn oouuttggooiinngg mmeessssaaggeess.. + + 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. + + + 99..88.. SSeettttiinngg ````RReeppllyy--TToo:: lliisstt@@hhoosstt''''.. + + 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 + DDIIRR//hheeaaddeerrrreemmoovvee, and ``Reply-To: list@host.dom'' into DDIIRR//hheeaaddeerraadddd. + + + 99..99.. CCoonnffiigguurriinngg tthhee lliisstt ssoo ppoossttss aarree nnoott ccooppiieedd ttoo tthhee oorriiggiinnaall + sseennddeerr.. + + 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 DDIIRR//eeddiittoorr. + + + 99..1100.. CCuussttoommiizziinngg eezzmmllmm nnoottiiffiiccaattiioonn mmeessssaaggeess.. + + Most of ezmlm's more commonly used messages are stored in DDIIRR//tteexxtt//. + These messages can be edited manually for a list once it is set up, or + on a global basis via modification of eezzmmllmmrrcc((55)). 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 DDIIRR//tteexxtt//ssuubb--ookk (and for subscription + moderated lists DDIIRR//tteexxtt//mmoodd--ssuubb) for new subscriber information (such + as the traditional ``welcome'' message, or a list charter or list + posting rules/guidelines); DDIIRR//tteexxtt//uunnssuubb--nnoopp is useful for messages + to frustrated users unsuccessful in their unsubscribe attempts; + DDIIRR//tteexxtt//hheellpp for general help information in reply to list-help@host + or unrecognized commands, DDIIRR//tteexxtt//bboottttoomm for inclusion at the bottom + of virtually all ezmlm messages; DDIIRR//tteexxtt//mmoodd--hheellpp for moderator + information; DDIIRR//tteexxtt//ttrraaiilleerr for a (few) line(s) at the bottom of + each post; DDIIRR//tteexxtt//ddiiggeesstt for information in the ``Administrivia'' + section of digests. + + + 99..1111.. SSppeecciiffyyiinngg cchhaarraacctteerr sseett aanndd ccoonntteenntt--ttrraannssffeerr--eennccooddiinngg ffoorr oouutt-- + ggooiinngg eezzmmllmm mmeessssaaggeess.. + + 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. DDIIRR//tteexxtt// 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 DDIIRR//cchhaarrsseett (default: us- + ascii). To specify quoted-printable or base64 content-transfer- + encoding, add ``:Q'' or ``:B'' after the character set name in + DDIIRR//cchhaarrsseett. + + + 1100.. CCuussttoommiizziinngg aarrcchhiivvee rreettrriieevvaall.. + + + 1100..11.. SSppeecciiffyyiinngg tthhee ffoorrmmaatt ffoorr rreettrriieevveedd mmeessssaaggeess.. + + 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. + + + 1100..22.. SSppeecciiffyyiinngg tthhee ddeeffaauulltt ffoorrmmaatt ffoorr ddiiggeessttss aanndd aarrcchhiivvee + rreettrriieevvaall.. + + 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''). + + + 1100..33.. LLiimmiittiinngg tthhee nnuummbbeerr ooff mmeessssaaggeess ppeerr --ggeett//--iinnddeexx rreeqquueesstt.. + + 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 iiddxx..hh and recompiling. Remember to edit tteexxtt//bboottttoomm, + tteexxtt//bboouunnccee, and eezzmmllmmrrcc((55)) to reflect these changes so that your + users won't get confused. + + + 1111.. RReessttrriiccttiinngg aarrcchhiivvee rreettrriieevvaall.. + + + 1111..11.. RReessttrriiccttiinngg aarrcchhiivvee aacccceessss ttoo ssuubbssccrriibbeerrss.. + + 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 DDIIRR//aallllooww//. + 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 + DDIIRR//aallllooww// 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. + + + 1111..22.. RReessttrriiccttiinngg aavvaaiillaabbllee aarrcchhiivvee rreettrriieevvaall ccoommmmaannddss.. + + 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 + DDIIRR//mmaannaaggeerr. If you don't want digest creation via trigger messages + and DDIIRR//mmaannaaggeerr, but use other means to created digests, you can + remove the ezmlm-get(1) line from DDIIRR//mmaannaaggeerr. + + + 1111..33.. RReessttrriiccttiinngg aarrcchhiivvee rreettrriieevvaall ttoo mmooddeerraattoorrss.. + + If DDIIRR//ppuubblliicc 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 DDIIRR//ppuubblliicc, 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 DDIIRR//ppuubblliicc. Also, look + at the ezmlm-make ``-b'' switch. + + + 1111..44.. AAlllloowwiinngg aarrcchhiivvee rreettrriieevvaall ffrroomm aa nnoonn--ppuubblliicc lliisstt.. + + A non-public list lacks DDIIRR//ppuubblliicc. 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. + + + 1122.. CCuussttoommiizziinngg ddiiggeessttss.. + + + 1122..11.. SSeettttiinngg uupp aa ddiiggeesstt lliisstt.. + + 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. + + + 1122..22.. GGeenneerraattiinngg ddaaiillyy ddiiggeessttss.. + + 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 DDIIRR//eeddiittoorr 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 DDIIRR//eeddiittoorr 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 eezzmmllmmrrcc 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. + + + + + + 1122..33.. GGeenneerraattiinngg tthhee ffiirrsstt ddiiggeesstt.. + + 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 DDIIRR//ddiiggnnuumm. + + If you want the next digest to start at message 456, you can always + edit DDIIRR//ddiiggnnuumm to contain '455'. If you want the next digest to be + named issue 678, put '677' into DDIIRR//ddiiggiissssuuee. + + + 1122..44.. AAddddiinngg ssttaannddaarrdd aaddmmiinniissttrraattiivvee iinnffoorrmmaattiioonn ttoo ddiiggeessttss.. + + The text in DDIIRR//tteexxtt//ddiiggeesstt is copied into the ``Administrivia'' + section of the digest. This information can be customized on a + system-wide basis by editing //eettcc//eezzmmllmmrrcc, on a user-wide basis by + editing ~~//..eezzmmllmmrrcc, or for the list by directly editing the + DDIIRR//tteexxtt//ddiiggeesstt 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''). + + + 1122..55.. CCoonnttrroolllliinngg tthhee ddiiggeesstt ffoorrmmaatt.. + + 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 + DDIIRR//eeddiittoorr. Just add the ``-fx'' switch to the ezmlm-get(1) command + line there. Edit ~~//eezzmmllmmrrcc to assure that such customizations will be + used for future list creations/edits. + + + 1122..66.. CCuussttoommiizziinngg bboouunnccee hhaannddlliinngg.. + + 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 DDIIRR//eeddiittoorr, and DDIIRR//mmaannaaggeerr 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. + + + 1133.. RReemmoottee aaddmmiinniissttrraattiioonn.. + + + 1133..11.. HHooww ccaann II rreemmootteellyy aadddd mmooddeerraattoorrss,, ssuubbssccrriibbeerr aalliiaasseess,, eettcc?? + + On any list, the DDIIRR//aallllooww// 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 DDIIRR//ddeennyy// 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 DDIIRR//mmoodd// databases (i.e., without shell + access), you need to set up a non-public, remotely administered list + which ``resides'' within the DDIIRR//mmoodd. _P_l_e_a_s_e _c_a_r_e_f_u_l_l_y _c_o_n_s_i_d_e_r _t_h_e + _i_m_p_l_i_c_a_t_i_o_n_s _o_f _m_a_k_i_n_g _i_t _p_o_s_s_i_b_l_e _t_o _r_e_m_o_t_e_l_y _a_d_d_, _r_e_m_o_v_e_, _a_n_d _l_i_s_t + _m_o_d_e_r_a_t_o_r_s_. _I_n _m_a_n_y _c_i_r_c_u_m_s_t_a_n_c_e_s_, _t_h_i_s _i_s _d_a_n_g_e_r_o_u_s_. + + After setting up your list with the specific functionality you need, + use the following command for DDIIRR//mmoodd//: + + + % 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 ~~//..qqmmaaiill--lliisstt--mmoodd and ~~//DDIIRR//mmoodd//eeddiittoorr. 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. + + + 1133..22.. MMooddeerraattiinngg ppoossttss ffrroomm aa sseeccoonnddaarryy aaccccoouunntt.. + + 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. + + 1133..33.. MMooddeerraattiinngg ssuubbssccrriippttiioonn ffrroomm aa sseeccoonnddaarryy aaccccoouunntt.. + + 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 DDIIRR//rreemmoottee). + + + 1133..44.. AAuuttoommaattiiccaallllyy aapppprroovviinngg ppoossttss oorr ssuubbssccrriippttiioonnss.. + + 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. + + + 1133..55.. AAlllloowwiinngg rreemmoottee aaddmmiinniissttrraattoorrss ttoo ggeett aa ssuubbssccrriibbeerr lliisstt.. + + 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 eezzmmllmmrrcc((55)) (see + ``Customizing ezmlm-make operation''). + + + + + + 1133..66.. AAlllloowwiinngg rreemmoottee aaddmmiinniissttrraattoorrss ttoo rreettrriieevvee oorr sseeaarrcchh aa ssuubb-- + ssccrriippttiioonn lloogg.. + + 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. + + + 1133..77.. AAlllloowwiinngg uusseerrss ttoo ggeett aa ssuubbssccrriibbeerr lliisstt.. + + If you want any user to be able to get a subscriber list, you can set + up a separate link to DDIIRR//lliisstt 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. + + + 1133..88.. CChhaannggiinngg tthhee ttiimmeeoouutt ffoorr mmeessssaaggeess iinn tthhee mmooddeerraattiioonn qquueeuuee.. + + Put the time, in hours, into DDIIRR//mmooddttiimmee. This value may not exceed + the range of 24-120 h set at compile time by the defines in iiddxx..hh. + + + 1133..99.. FFiinnddiinngg oouutt hhooww mmaannyy mmeessssaaggeess aarree wwaaiittiinngg ffoorr mmooddeerraattiioonn.. + + + + % 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. lliisstt--cchhkkqquueeuuee@@hhoosstt. (See ezmlm-check(1) and ``adding + your own commands'' for examples.) + + + 1133..1100.. UUssiinngg tthhee ssaammee mmooddeerraattoorrss ffoorr mmuullttiippllee lliissttss.. + + 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 //ppaatthh//mmooddddiirr into DDIIRR//mmooddssuubb (for moderation + of subscribes), DDIIRR//rreemmoottee (for remote admin if DDIIRR//mmooddssuubb does not + exist), and DDIIRR//mmooddppoosstt (for moderation of messages). + + For example: + + + + % echo "/home/joe/mods" > ~joe/DIR/modsub + + + + + _N_O_T_E_: The path must start with a '/'. + + + 1133..1111.. UUssiinngg ddiiffffeerreenntt mmooddeerraattoorrss ffoorr mmeessssaaggee aanndd ssuubbssccrriippttiioonn mmooddeerr-- + aattiioonn.. + + Proceed as in the previous point, but set up two different moddirs. + Naturally, one of these can be DDIIRR//mmoodd// (preferably the one for posts, + to keep it cleaner). Then modify the appropriate files (DDIIRR//mmooddppoosstt + and DDIIRR//mmooddssuubb) to contain absolute paths to the correct moddir. + + + 1133..1122.. tthhee ````ssuuppeerr mmooddeerraattoorr'''' aabbllee ttoo aadddd//rreemmoovvee mmooddeerraattoorrss + rreemmootteellyy.. SSeettttiinngg uupp mmooddeerraatteedd lliissttss wwiitthh tthhee lliisstt oowwnneerr aass + + This is done by crating a list that has DDIIRR//mmoodd// as it's main list + directory, then adding the ``super moderator'' to DDIIRR//mmoodd//mmoodd// (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). + + + + + + 1133..1133.. CCuussttoommiizziinngg eezzmmllmm aaddmmiinniissttrraattiivvee mmeessssaaggeess.. + + Subject lines, and other ezmlm output for moderation are controlled by + defines in iiddxx..hh and by files in DDIIRR//tteexxtt. To customize these, change + iiddxx..hh and recompile or for DDIIRR//tteexxtt files, edit eezzmmllmmrrcc((55)) (see + ``Customizing ezmlm-make operation''). + + You can also configure the list to allow remote administrators to edit + files in DDIIRR//tteexxtt// via E-mail (see ``How text file editing works''). + + + 1133..1144.. MMaannuuaallllyy aapppprroovviinngg aa mmeessssaaggee aawwaaiittiinngg mmooddeerraattiioonn.. + + All you have to do is to pipe the corresponding message to ``ezmlm- + send DIR''. Messages awaiting moderation are kept in DDIIRR//mmoodd//ppeennddiinngg//. + 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 ~~jjooee//SSOOSS//. + + + 1133..1155.. MMaannuuaallllyy rreejjeeccttiinngg aa mmeessssaaggee aawwaaiittiinngg mmooddeerraattiioonn.. + + Simply deleting the file from DDIIRR//mmoodd//ppeennddiinngg// 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 DDIIRR//mmooddttiimmee; default 120). + + + + + 1144.. SSuubblliissttss.. + + 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). + + + 1144..11.. SSuubblliissttss ooff eezzmmllmm lliissttss.. + + 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. + + + 1144..22.. SSuubblliissttss ooff nnoonn--eezzmmllmm lliissttss.. + + 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 DDIIRR//eeddiittoorr of your sublist and add a ``-h + _L_i_s_t_p_r_o_c_e_s_s_o_r_-_V_e_r_s_i_o_n_:'' option to the ezmlm-send(1) line, but + replacing ``_L_i_s_t_p_r_o_c_e_s_s_o_r_-_V_e_r_s_i_o_n_:'' with your mainlist header. + + Now your list will accept only messages from mainlist@mainhost and + with the header specified. + + + 1144..33.. HHooww ttoo sseett uupp aa cclluusstteerr ooff lliisstt aanndd ssuubblliissttss wwiitthh ssttaannddaarrdd + ddaattaabbaasseess.. + + 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: + + + +o + + ccrreeaattee tthhee mmaaiinn lliisstt + + + ezmlm-make dir dot local host + + + + + +o + + aadddd aann eezzmmllmm--sspplliitt((11)) iinnvvooccaattiioonn + Before the ezmlm-manage(1) line in DDIIRR//mmaannaaggeerr add: + + + |/path/ezmlm-split dir + + + + + +o + + ddeecciiddee hhooww ttoo sspplliitt tthhee llooaadd + 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. + + +o + + CCrreeaattee tthhee ssuubblliissttss + 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 + + + + + +o + + ssuubbssccrriibbee tthhee rreessppeeccttiivvee ssuubblliissttss ttoo tthhee mmaaiinn lliisstt + 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. + 1155.. MMiiggrraattiioonn ttoo EEzzmmllmm ffrroomm ootthheerr MMaaiilliinngg LLiisstt MMaannaaggeerrss.. + + 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. + + + 1155..11.. BBaassiicc CCoonncceeppttss.. + + Ezmlm is different from other mailing list managers in that it is + _l_i_s_t_-_c_e_n_t_r_i_c rather than _h_o_s_t_-_c_e_n_t_r_i_c. With a _l_i_s_t_-_c_e_n_t_r_i_c 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 DDIIRR//mmaannaaggeerr. + + Other mailing list managers are _h_o_s_t_-_c_e_n_t_r_i_c, 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. [_N_o_t_e_: 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 _h_o_s_t_-_c_e_n_t_r_i_c style mailing list manger is available. + This is based on the use of ezmlm-request(1) with the ``-f + ccoonnffiigg__ffiillee'' switch. + + + 1155..22.. SSeettttiinngg uupp eezzmmllmm ttoo rreessppoonndd ttoo hhoosstt--cceennttrriicc ccoommmmaannddss.. + + 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 + eezzddoommoo//cchhaarrsseett. + + All that remains is to set up DDIIRR//eezzddoommoo..ccff 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 DDIIRR//eezzddoommoo..ccff 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 DDIIRR//, 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. + + + 1155..33.. CCoommmmaannddss ooff ootthheerr mmaaiilliinngglliisstt mmaannaaggeerrss rreeccooggnniizzeedd bbyy eezzmmllmm.. + + + 1155..33..11.. LLiissttpprroocc//LLiissttsseerrvv.. + + 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. NNoottee:: eezzmmllmm wwiillll oonnllyy rreessppoonndd ttoo oonnee ccoommmmaanndd ppeerr mmeessssaaggee.. + + ssyynnttaaxx:: ccoommmmaanndd lliissttnnaammee [[ssuubbssccrriibbeerr@@hhoosstt]] + + + SSuuppppoorrtteedd ccoommmmaannddss + subscribe, sub, unsubscribe, unsub, list, help, review. + + AAddddiittiioonnaall ssuuppppoorrtteedd ccoommmmaannddss + 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. + + + 1155..33..22.. MMaajjoorrddoommoo.. + + ssyynnttaaxx:: ccoommmmaanndd lliissttnnaammee [[ssuubbssccrriibbeerr@@hhoosstt]] + + + SSuuppppoorrtteedd ccoommmmaannddss + lists, subscribe, unsubscribe, help, which, who. + AAddddiittiioonnaall ssuuppppoorrtteedd ccoommmmaannddss + 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. + + + 1155..33..33.. SSmmaarrttlliisstt.. + + 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. + + + SSuuppppoorrtteedd ccoommmmaannddss + subscribe, unsubscribe. + + AAddddiittiioonnaall SSuuppppoorrtteedd CCoommmmaannddss + All ezmlm user and ezmlm owner commands. + + + 1166.. OOppttiimmiizziinngg lliisstt ppeerrffoorrmmaannccee.. + + 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. + + + 1166..11.. CCrroonndd--ggeenneerraatteedd ddiiggeessttss ffoorr bbeetttteerr ppeerrffoorrmmaannccee.. + + With the default setup, ezmlm-tstdig(1) in DDIIRR//eeddiittoorr 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. + + + 1166..22.. OOppttiimmiizziinngg eexxeeccuuttiioonn ooff eezzmmllmm--wwaarrnn((11)).. + + 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 ( + 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. + + _N_o_t_e_: the ezmlm-make(1) ``-w'' switch has a special meaning if used at + the same time as enabling SQL-support (``-6''; see man pages). + + + 1166..33.. DDeeccrreeaassiinngg eezzmmllmm--wwaarrnn ttiimmee oouutt ttoo iinnccrreeaassee ppeerrffoorrmmaannccee.. + + 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. + + + 1166..44.. UUssee eezzmmllmm wwiitthhoouutt eezzmmllmm--iiddxx ffoorr mmaaxxiimmuumm ppeerrffoorrmmaannccee.. + + 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. + + + 1166..55.. NNoott aarrcchhiivviinngg ttoo mmaaxxiimmiizzee ppeerrffoorrmmaannccee.. + + 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. + + + 1166..66.. SSuubblliissttss ttoo mmaaxxiimmiizzee ppeerrffoorrmmaannccee.. + + 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). + + + 1177.. MMiisscceellllaanneeoouuss.. + + + 1177..11.. HHooww ddoo II qquuiicckkllyy cchhaannggee tthhee pprrooppeerrttiieess ooff mmyy lliisstt?? + + + + ezmlm-make -+ [changed_switches] dir + + + + + ezmlm-make(1) stores configuration info in DDIIRR//ccoonnffiigg 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. + + + 1177..22.. OOppeenn aarrcchhiivveedd lliisstt wwiitthh ddaaiillyy ddiiggeessttss.. + + 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 DDIIRR//ddiiggeesstt//ssuubbssccrriibbeerrss//, + i.e. the subscriber database with the base directory DDIIRR//ddiiggeesstt//. + + +o See ``setting up a digest list'' on how to set up the lists. + + + 1177..33.. VVaarriiaattiioonnss iinn mmooddeerraattiioonn + + 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 DDIIRR//mmooddssuubb or DDIIRR//rreemmoottee (for remote admin and + subscription moderation - always the same db for both functions) or in + DDIIRR//mmooddppoosstt for message moderation. You can point several lists to the + same moderator db, thus using the same moderators for several lists. + _N_O_T_E_: 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''). + + + 1177..44.. LLiissttss tthhaatt aallllooww rreemmoottee aaddmmiinn,, bbuutt nnoott uusseerr iinniittiiaatteedd ssuubbssccrriipp-- + ttiioonn oorr aarrcchhiivvee rreettrriieevvaall.. + + Create a regular remote admin list, but remove DDIIRR//ppuubblliicc. 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''). + + + 1177..55.. LLiissttss tthhaatt aallllooww rreemmoottee aaddmmiinn,, uusseerr aarrcchhiivvee rreettrriieevvaall,, bbuutt nnoott + uusseerr--iinniittiiaatteedd ssuubbssccrriippttiioonn.. + + Create a regular remote admin list, remove DDIIRR//ppuubblliicc, and add the + ``-p'' [public] switch to the ezmlm-get(1) command line in + DDIIRR//mmaannaaggeerr. This overrides the normal DDIIRR//ppuubblliicc 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 ~~//..qqmmaaiill--lliissttnnaammee--hheellpp to + DDIIRR//hheellpp, and invoke a script that copies help info from there. See + ezmlm-check(1) for an example. + + + 1177..66.. LLiissttss tthhaatt rreessttrriicctt aarrcchhiivvee rreettrriieevvaall ttoo ssuubbssccrriibbeerrss.. + + Use a standard list, but add the ezmlm-get(1) ``-s'' command line + switch in DDIIRR//mmaannaaggeerr. Only subscribers can receive archive excerpts. + Digests work as usual. This can be set up using the ezmlm-make(1) + ``-g'' switch. + + + 1177..77.. LLiissttss tthhaatt ddoo nnoott aallllooww aarrcchhiivvee rreettrriieevvaall aatt aallll.. + + Use a standard list, but add the ``-C'' switch to both the ezmlm- + get(1) and ezmlm-manage(1) command lines in DDIIRR//mmaannaaggeerr. No archive + retrieval commands will be honored. Digest can be created as usual + (See ``Restricting archive retrieval''). + + + 1177..88.. LLiissttss tthhaatt ddoo nnoott aallllooww aarrcchhiivvee rreettrriieevvaall aanndd ddoo nnoott aallllooww + ddiiggeesstt ttrriiggggeerriinngg ppeerr mmaaiill.. + + For maximal archive security, set up a normal indexed and archived + list, then remove the ezmlm-get(1) line from DDIIRR//mmaannaaggeerr 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. + + + 1177..99.. LLiissttss tthhaatt aallllooww aarrcchhiivvee rreettrriieevvaall oonnllyy ttoo mmooddeerraattoorrss,, bbuutt + aallllooww uusseerr--iinniittiiaatteedd ssuubbssccrriippttiioonn.. + + Create a normal remote admin (+ subscription moderated) list, and add + the ``-P'' (not public) switch to the ezmlm-get(1) command line in + DDIIRR//mmaannaaggeerr. Subscription will not be affected, but ezmlm-get(1) will + send archive excerpts only to moderators. Digests are unaffected. + + + 1177..1100.. LLiissttss tthhaatt ddoo nnoott rreeqquuiirree uusseerr ccoonnffiirrmmaattiioonn ffoorr ((uunn))ssuubbssccrriipp-- + ttiioonn.. + + + 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. + + + 1177..1111.. AAnnnnoouunncceemmeenntt lliissttss ffoorr aa ssmmaallll sseett ooff ttrruusstteedd ppoosstteerrss + + Set up the list with ezmlm-make ``-om'' and add the ``trusted E-mail + addresses'' to DDIIRR//mmoodd// 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. + + + 1177..1122.. AAnnnnoouunncceemmeenntt lliissttss aalllloowwiinngg mmooddeerraatteedd ppoossttss ffrroomm aannyyoonnee.. + + 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 DDIIRR//mmooddppoosstt (needs leading + ``/''), and add the post moderator(s) to DDIIRR//mmoodd// using ezmlm-sub(1) + as shown above. + + + 1177..1133.. AAnnnnoouunncceemmeenntt lliissttss wwiitthh lleessss sseeccuurriittyy aanndd mmoorree ccoonnvveenniieennccee.. + + 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 DDIIRR//mmooddppoosstt exists, + ezmlm-store(1) will send out other messages for moderation. To bounce + such messages, create DDIIRR//mmooddppoosstt, 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. + + + 1188.. EEzzmmllmm--iiddxx ccoommppiillee ttiimmee ooppttiioonnss.. + + + 1188..11.. LLooccaattiioonn ooff bbiinnaarriieess.. + + This is configured via ccoonnff--bbiinn as for other ezmlm programs. The + default is //uussrr//llooccaall//bbiinn//eezzmmllmm. + + + 1188..22.. LLooccaattiioonn ooff mmaann ppaaggeess.. + + This is configured via ccoonnff--mmaann as for other ezmlm programs. The + default is //uussrr//llooccaall//mmaann. + + + 1188..33.. BBaassee ddiirreeccttoorryy ooff qqmmaaiill--iinnssttaallllaattiioonn.. + + This is configured via ccoonnff--qqmmaaiill as for other ezmlm programs. The + default is //vvaarr//qqmmaaiill. + + + 1188..44.. SShhoorrtt hheeaaddeerr tteexxttss,, eettcc.. + + Ezmlm-idx text (short lines, such as ``Administrivia'' for digests), + command names, etc, are defined in iiddxx..hh, used at compile time. You + can change them by changing the defines in this file. + + + 1188..55.. AArrbbiittrraarryy lliimmiittss.. + + iiddxx..hh contains defines for some ezmlm-idx arbitrary limits, such as + the maximum number of messages per ``-get'' request. They can be + changed here. + + + 1188..66.. CCoommmmaanndd nnaammeess.. + + There is support for one alias per user command for + internationalization. (See ``Multiple language support''.) + + + 1188..77.. EErrrroorr mmeessssaaggeess.. + + All ezmlm-idx error messages are defines in eerrrrttxxtt..hh, 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). + + + + 1188..88.. PPaatthhss aanndd ootthheerr oodddd ccoonnffiigguurraattiioonn iitteemmss.. + + idx.h also has defines for //eettcc//eezzmmllmmrrcc, 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. + + + 1199.. MMuullttiippllee llaanngguuaaggee ssuuppppoorrtt.. + + + 1199..11.. CCoommmmaanndd nnaammeess.. + + 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''. + + + 1199..22.. TTeexxtt ffiilleess.. + + Most ezmlm responses are made from text files in DDIIRR//tteexxtt//. 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 eezzmmllmmrrcc..jjpp to //eettcc//eezzmmllmmrrcc, 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 //uussrr//ddoocc// hierarchy. + + If you have made an eezzmmllmmrrcc((55)) 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 eezzmmllmmrrcc 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 + iiddxx..hh 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 eerrrrttxxtt..hh. + + + 1199..33.. MMuullttii--bbyyttee cchhaarraacctteerr ccooddee ssuuppppoorrtt.. + + 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 _p_e_r + _s_e support other character sets. However, any single-byte character + set is supported, as long as the us-ascii character sequence ``'' (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, + ``'' sequence within the text risks substitution. In practice, + both of these should be very rare and easily avoidable when setting up + an ezmlmrc(5). + + + 2200.. SSuubbssccrriibbeerr nnoottiiffiiccaattiioonn ooff mmooddeerraattiioonn eevveennttss.. + + + 2200..11.. GGeenneerraall ooppiinniioonnss.. + + This is a collection of the authors opinions and an explanation of + ezmlm-idx moderation design, which you may or may not agree with. + + + 2200..22.. UUsseerrss sshhoouulldd kknnooww tthhaatt tthhee lliisstt iiss ssuubbssccrriippttiioonn mmooddeerraatteedd.. + + 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 DDIIRR//tteexxtt// files. + + + 2200..33.. SSuubbssccrriibbeerrss sshhoouulldd kknnooww tthhaatt ppoossttss aarree mmooddeerraatteedd.. + + 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. + + + 2200..44.. SSeennddeerrss ooff ppoossttss sshhoouulldd bbee nnoottiiffiieedd ooff rreejjeeccttiioonnss.. + + 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 DDIIRR//eeddiittoorr and DDIIRR//mmooddeerraattoorr). 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. + + + 2211.. EEzzmmllmm--iiddxx sseeccuurriittyy.. + + + 2211..11.. GGeenneerraall aassssuummppttiioonnss.. + + 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. + + + 2211..22.. SSEENNDDEERR mmaanniippuullaattiioonn.. + + 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. + + + 2211..33.. eezzmmllmm ccooookkiieess.. + + 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. + + + 2211..44.. LLiissttss wwiitthhoouutt rreemmoottee aaddmmiinn//ssuubbssccrriippttiioonn mmooddeerraattiioonn.. + + 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). + + + 2211..55.. MMeessssaaggee mmooddeerraattiioonn.. + + 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. + + + 2211..66.. SSuubbssccrriippttiioonn mmooddeerraattiioonn.. + + 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. + + + 2211..77.. RReemmoottee aaddmmiinniissttrraattiioonn.. + + 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. + + + 2211..88.. RReemmoottee eeddiittiinngg ooff eezzmmllmm tteexxtt ffiilleess.. + + ezmlm-manage(1) can allow remote administrators to edit files in + DDIIRR//tteexxtt. 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 DDIIRR//tteexxtt + 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 iiddxx..hh)) 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. + + + 2211..99.. DDiiggeesstt ggeenneerraattiioonn aanndd aarrcchhiivvee rreettrriieevvaall.. + + 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 DDIIRR//mmaannaaggeerr 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 DDIIRR//eeddiittoorr 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 + DDIIRR//ppuubblliicc. 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 (DDIIRR//tteexxtt//mmoodd--hheellpp) 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). + + + 2211..1100.. CCoonnvveenniieennccee ffoorr sseeccuurriittyy:: tthhee eezzmmllmm--mmaannaaggee ````--SS'''' aanndd ````--UU'''' + sswwiittcchheess.. + + 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 (DDIIRR//rreemmoottee 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. + + + 2211..1111.. DDeenniiaall ooff sseerrvviiccee.. + + 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 DDIIRR//ppuubblliicc, 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 DDIIRR//eeddiittoorr as in the default setup with the + ezmlm-make(1) ``-d'' switch. + + + 2211..1122.. MMooddeerraattoorr aannoonnyymmiittyy.. + + 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 eezzmmllmm--ssttoorree..cc. + + 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 DDIIRR//mmooddttiimmee - and the parameters are likewise + configurable at compile time via iiddxx..hh) 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. + 2211..1133.. CCoonnffiiddeennttiiaalliittyy ooff ssuubbssccrriibbeerr EE--mmaaiill aaddddrreesssseess.. + + 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. + + + 2211..1144.. HHeellpp mmeessssaaggee ffoorr mmooddeerraattoorrss.. + + ezmlm-manage sends DDIIRR//tteexxtt//mmoodd--hheellpp, rather than DDIIRR//tteexxtt//hheellpp in + reply to messages to list-help@host if the target address is a + moderator. DDIIRR//tteexxtt//mmoodd--hheellpp should not contain secrets or other + confidential information. + + + 2211..1155.. SSuubblliissttss.. + + 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 DDIIRR//eeddiittoorr 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 DDIIRR//hheeaaddeerr-- + aadddd 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. + + + 2211..1166.. SSQQLL ddaattaabbaasseess.. + + 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. + + + 2211..1177.. RReeppoorrttiinngg sseeccuurriittyy pprroobblleemmss.. + + Please send private E-mail about any security problems with the ezmlm- + idx additions to Fred Lindberg, lindberg@id.wustl.edu. For ezmlm, + please send them via private E-mail to Dan J. Bernstein, the author of + ezmlm proper. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FILES.idx b/FILES.idx new file mode 100644 index 0000000..3c2095d --- /dev/null +++ b/FILES.idx @@ -0,0 +1,165 @@ +CHANGES.idx +DOWNGRADE.idx +FAQ.idx +FILES.idx +INSTALL.idx +LICENCE.TXT +README.idx +TARGETS +UPGRADE.idx +author.c +auto_cron.h +case_diffs.c +case_starts.c +checktag.c +concatHDR.c +conf-cron +conf-sqlcc +conf-sqlld +copy.c +copy.h +date2yyyymm.c +dateline.c +decodeB.c +decodeHDR.c +decodeQ.c +encodeB.c +encodeQ.c +env.c +errtxt.h +ezcgi.css +ezcgirc +ezmlm-accept.1 +ezmlm-accept.sh +ezmlm-archive.1 +ezmlm-archive.c +ezmlm-cgi.1 +ezmlm-cgi.c +ezmlm-check.1 +ezmlm-check.sh +ezmlm-clean.1 +ezmlm-clean.c +ezmlm-cron.1 +ezmlm-cron.c +ezmlm-gate.1 +ezmlm-gate.c +ezmlm-get.1 +ezmlm-get.c +ezmlm-glconf.1 +ezmlm-glconf.sh +ezmlm-idx.1 +ezmlm-idx.c +ezmlm-issubn.1 +ezmlm-issubn.c +ezmlm-limit.1 +ezmlm-limit.c +ezmlm-list.c +ezmlm-make.1 +ezmlm-make.c +ezmlm-manage.1 +ezmlm-manage.c +ezmlm-mktab +ezmlm-mktab.1 +ezmlm-moderate.1 +ezmlm-moderate.c +ezmlm-receipt.1 +ezmlm-receipt.c +ezmlm-reject.1 +ezmlm-reject.c +ezmlm-request.1 +ezmlm-request.c +ezmlm-return.c +ezmlm-send.c +ezmlm-split.1 +ezmlm-split.c +ezmlm-store.1 +ezmlm-store.c +ezmlm-sub.c +ezmlm-test.1 +ezmlm-test.sh +ezmlm-tstdig.1 +ezmlm-tstdig.c +ezmlm-unsub.c +ezmlm-warn.c +ezmlmglrc +ezmlmglrc.5 +ezmlmrc.5 +ezmlmrc.cs +ezmlmrc.da +ezmlmrc.de +ezmlmrc.en_US +ezmlmrc.es +ezmlmrc.fr +ezmlmrc.id +ezmlmrc.it +ezmlmrc.jp +ezmlmrc.pl +ezmlmrc.pt_BR +ezmlmrc.ru +ezmlmrc.sv +ezmlmsubrc +ezmlmsubrc.5 +idx.h +idx.patch +idxthread.c +idxthread.h +issub.c +logmsg.c +makehash.c +makehash.h +mime.h +opensql.c +putsubs.c +qmail-qmqpc.tar.gz +qmail-verh.tar.gz +qmail.c +qmail.h +searchlog.c +subscribe.c +subscribe.h +tagmsg.c +unfoldHDR.c +yyyymm.h + +sub_mysql: +README +checktag.c +conf-sqlcc +conf-sqlld +ezmlm-mktab +issub.c +logmsg.c +opensql.c +putsubs.c +searchlog.c +subscribe.c +tagmsg.c +to40x + +sub_pgsql: +README +checktag.c +conf-sqlcc +conf-sqlld +ezmlm-mktab +issub.c +logmsg.c +opensql.c +putsubs.c +searchlog.c +subscribe.c +tagmsg.c + +sub_std: +README +checktag.c +conf-sqlcc +conf-sqlld +ezmlm-mktab +issub.c +logmsg.c +opensql.c +putsubs.c +searchlog.c +subscribe.c +tagmsg.c diff --git a/INSTALL.idx b/INSTALL.idx new file mode 100644 index 0000000..6a7d899 --- /dev/null +++ b/INSTALL.idx @@ -0,0 +1,274 @@ +$Id: INSTALL.idx,v 1.49 1999/12/24 20:12:57 lindberg Exp $ +$Name: ezmlm-idx-040 $ + +Like any other piece of software (and information generally), ezmlm-idx +comes with NO WARRANTY. + +This file is for installing ezmlm-idx for the first time on a system +that may have ezmlm-0.53. If you're already using ezmlm-idx, see +UPGRADE.idx instead. + +Things you have to decide before starting: + + Common for ezmlm-0.53: + Put the desired ezmlm bin path into conf-bin. Default "/usr/local/bin/ezmlm", + but for e.g. rpm packages it's "/usr/bin". Adjust conf-man accordingly. + For installations (e.g. Debian) where qmail is not in "/var/qmail", adjust + conf-qmail. + + NOTE: If you follow the test instructions in INSTALL of ezmlm-0.53 after + adding ezmlm-idx, step 6 will fail. Before this step, edit + ~/testlist/editor and remove the ezmlm-reject line. + +HOW TO BUILD, TEST, AND INSTALL: + + 1. Expand the ezmlm-0.53.tar.gz archive. expand the ezmlm-idx-0.xx.tar.gz + archive: + % zcat ezmlm-0.53.tar.gz | tar -xvf + % zcat ezmlm-idx-0.xx.tar.gz | tar -xvf + + 2. Copy the contents of the archive to your ezmlm-0.53 directory. + % mv ezmlm-idx-0.xx/* ezmlm-0.53/ + + 3. Patch the ezmlm-0.53 source: + % cd ezmlm-0.53 + % patch < idx.patch + + If you patch utility failes with this, get GNU patch. + [ezmlm-issubn, an enhanced version of ezmlm-issub is part of this package. + The patch for the ezmlm-return bug is also part of this package.] + + 4. If your 'crontab' binary does not live in '/usr/bin' edit 'conf-cron' + now to reflect the correct path. + + 5. RDBM Support. + + MySQL: + If you want to compile ezmlm with MySQL support (http://www.tcx.se), + edit sub_mysql/conf-sqlcc (include files) and mysql/conf-sqlld (libraries) + to reflect your MySQL installation (see MySQL documentation). The files + are preset for RedHat Linux-i386. On some systems, the ``-lnsl'' should + be removed from conf-sqlld. The package has been tested with MySQL 3.22. + + (Programs compiled with MySQL support will work like + their non-MySQL counterparts for lists that are not specifically + set up to take advantage of MySQL support.) Do: + % make mysql + + PostgresSQL: + If you want to compile ezmlm with PostgreSQL support + (http://www.postgreSQL.org), edit sub_pgsql/conf-sqlcc (include files) + and pgsql/conf-sqlld (libraries) to reflect your PostgreSQL installation + (see PostgreSQL documentation). Do: + % make pgsql + + Others: + If you're familiar with C programming for the particular RDBMS, it will + take you no more than a few hours to adapt the files in sub_mysql (see + docs there). Create a new sub_????, tar and gzip it and send it to + lindberg#@id.wustl.edu for inclusion into the package. + + 6. Compile the programs and man pages: + % make clean + % make; make man + + 7. To use a language other than US English as the default for list texts: + % make ISO + + where ``iso'' is the ISO language designation. Currently supported + are: cz, da, de, en_US, fr, jp, pl, pt_BR, sv. NOTE: A normal ``make'' sets + up the en_US version (as before). ezmlmrc files for your language + may be available via ftp://id.wustl.edu/pub/patches/ezmlmrc. If not, + please feel free to contribute one (translate ezmlmrc.en_US, but leave + comments intact for "diff"). + + 8. Test the programs: + a. Create a user ``eztest'' or edit ezmlm-test to use another user name. + This user should be able to execute the new binaries and also needs + to have read access to ezmlm-test (chmod 755 ezmlm-test). + b. Change to that user. + c. From the build directory, execute ezmlm-test: + % ./ezmlm-test + + ezmlm-test will set up a test list, execute the various programs, and + test most functions of most programs. It works only if your qmail + installation works and allows sending mail to the local user. If you + use another user name, add ``-u other_user_name''. NOTE that the + arguments must be separated by a space from the switches. + + Occasionally, ezmlm-test fails. This is usually due to problems with + ezmlm-test on your particular platform/installation and not due to + problems in ezmlm-idx. Please report problems with ezmlm-test, and if + you can, patches for correcting it. + + + 9. To test the SQL functions, set up a mysql database ``ezmlm'' accessible + to a user at this host (see MySQL/PostgreSQL docs; the ezmlm-mktab script + creates the necessary tables (see man page) but you must first create a + database and a user with sufficient access. + + The following command creates a database for use with ezmlm-test. + NOTE that ezmlm-mktab and ezmlm-test options must be separated from the + switch, whereas the passwd argument for mysql -p must immediately + follow the switch. + % ./ezmlm-mktab -d list | mysql -hhost -uuser -ppasswd -f ezmlm + + or for PostgresSQL: + % ./ezmlm-mktab -d list | pgsql [...] ezmlm + + Now, as the ``eztest'' user, execute: + % ./ezmlm-test -l user -p passwd -h host + + This will test the SQL part of the binaries. ``host'' defaults to + ``localhost'' and ``user'' defaults to ``ezmlm''. There is no default + for passwd and indeed ezmlm-test uses this switch to know to work + with SQL support. To execute under a user other than ``eztest'', + add a ``-u testuser'' switch. Note that -p has to be specified even if + the database has no password. In this case, use -p ''. + +10. If you for some reason want to rebuild binaries without MySQL support, do: + % make std + % make + +11. Copy binaries and man pages to the correct locations. + # make setup + (or copy manually). + If you'd like to retest the installation, change uid to the test user + ``eztest'' and change to the ezmlm binary directory. Now run ezmlm-test + as before. + + +12. Your lists will run as before. To enable ezmlm-idx features like + threaded archive access, digest, etc, use: + + % ezmlm-make -e [switches] DIR dot local host + + where ``DIR dot local host'' are the arguments used to create the list, + and ``switches'' are desired options (see ezmlm-make man page). Future + adjustments can be made with: + + % ezmlm-make -+ [switches] DIR + + where ``switches'' are desired _changes_ from the previous configuration. + +------ OPTIONAL ------ + +13. If you want qmail to add a subscriber-adapted List-Unsubscribe header to + outgoing messages, apply the enclosed qmail-verh-0.03.tar.gz patch to + qmail-1.03 and follow the documentation in that archive. This is a + failsafe way in which to unsubscribe, even if subscriber or list have + changed address. + +14. If you want to use large lists with custom QMQP servers, apply the + qmail-qmqp.tar.gz patch per instructions in the archive. You need this + only if you want per-[sub]list control over the QMQP servers used. + +15. (This can be done later if you decide to use ezmlm-cron(1). It is not + needed for normal lists and mainly for ``legacy installations''.) + The ezmlm-cron(1) program can be run SUID/SGID a special user with crond + access. This allows your users to use ezmlm-cron to generate digest + trigger messages, without being able to directly use crond. To enable + this feature create a special user, e.g. "ezmlm". Then: + + # chown ezmlm /usr/local/bin/ezmlm-cron + # chmod 4555 /usr/local/bin/ezmlm-cron + + and create ~ezmlm/ezcronrc as described in the ezmlm-cron(1) man + page. You may need to modify the path in the commands above if + you have installed ezmlm in a non-default location. ezmlm-cron refuses + to run SUID root. + + This user can read its crontab file which may contain digest codes from + other users. Thus, this should be a reserved user name, not one of an + ordinary user. + + +16. If you would like to make your archived lists available via the World + Wide Web, you must install the ezmlm-cgi program which comes with + ezmlm-idx versions starting with ezmlm-idx-0.40. When ezmlm-idx is compiled + with the 'make' command, ezmlm-cgi is compiled also, however, it is not + installed. Installation of the program allows one to view the archives by + date, thread and author. See, ezmlm-cgi.1 for more details. + +17. ezmlm-cgi must be installed where all other common gateway interface + ("CGI") programs are installed on your system. For most Un*x based system, + this will be in a directory titled 'cgi-bin' which is also, generally + speaking, in the root directory for your web server. For example, for apache + installations where /usr/local/apache is the root directory for the web + server, the directory /usr/local/apache/cgi-bin is where globally availably + CGI programs are located. You must copy the ezmlm-cgi program to this + location: + + % cp /ezmlm-0.53/ezmlm-cgi /usr/local/apache/cgi-bin + +18. ezmlm-cgi should be installed SUID root. Examine the source code to make + yourself comfortable that the program is safe. After copying the program to + the 'cgi-bin' directory, change the ownerships and permissions as follows: + + % chown root.root ezmlm-cgi + % chmod 4755 ezmlm-cgi + + If you are using ezmlm-cgi for a single user, you can install it SUID that + user and place the config file (see below) as .ezcgirc in the same directory + as the program. If the list archive is readable to the httpd user, you do + not have to install it SUID at all (see man page for details). + +19. ezmlm-cgi uses a configuration files called 'ezcgirc' which must reside + in the /etc/ezmlm directory. First create the directory: + + % mkdir /etc/ezmlm + + Then use your favorite text editor to create the ezcgirc file. + + The file parameters are set forth on the first line. Comments are + allowed if preceded by the '#' in position 1. Lists are input by number + which is an arbitrary identifier with the exception of list '0' which is the + default list shown on the web page. As an example, the following utilizes a + list 'test@example.com' which is owned by the 'alias' user with a UID of + 7827. The list resides in the directory '/var/qmail/alias/test' and its home + page is at 'http://www.example.com/test'. With the foregoing setup, the + ezcgirc file's contents are as follows: + +# Format for ezcgirc file +#listno;uid;listdir;listaddr;buttonbar;charset;style;bannerprog +0;7827;/var/qmail/alias/test;test@example.com;[Home]=http://www.example.com/test + + Note there are no entries for 'charset', 'style' and 'bannerprog' Where + no entries are made, the default variables are assumed. The above + configuration assumes that the character set 'iso-8859-1' and that no + style sheet is used. Since formatting is largely controlled by the + style sheet, the output doesn't look exciting on a GUI browser. Start with + ezcgi.css in the distribution, and modify to taste. See www.ezmlm.org + for URLs to archives using different style sheets/banners. + +20. Finally, before accessing the list via the web, you must archive any + existing list and add an entry to listdir/editor to archive future posts. + You must also run ezmlm-idx (first see man pages for both programs): + + % ezmlm-idx DIR + % ezmlm-archive -c DIR + +21. For any existing lists which you would like to archive, + add the following line after the call to ezmlm-send in listdir/editor: + + | /usr/local/ezmlm/ezmlm-archive listdir/DIR || exit 0 + + This is automatically done when running: + + % ezmlm-make -+i DIR + +22. To display your web based archive, open your browser as follows: + + %lynx http://localhost/cgi-bin/ezmlm-cgi + + ------------- End Optional items ----------- + +23. That's it! To report success (helps to track platform-specific problems): + + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail cfl-src@id.wustl.edu + +Replace First M. Last with your name. + +Send bugs reports, ideally with patch, to 'lindberg@id.wustl.edu'. + diff --git a/LICENCE.TXT b/LICENCE.TXT new file mode 100644 index 0000000..ee0775e --- /dev/null +++ b/LICENCE.TXT @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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.) + +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. + + 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. + + 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 + + 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. + + + Copyright (C) 19yy + + 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. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/MAN b/MAN index df7b2a7..06f2e71 100644 --- a/MAN +++ b/MAN @@ -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: diff --git a/Makefile b/Makefile index 111a542..e3c7ab3 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,14 @@ +#$Id: Makefile,v 1.117 1999/12/23 02:42:12 lindberg Exp $ +#$Name: ezmlm-idx-040 $ SHELL=/bin/sh - +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 @@ alloc_re.o: \ 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 @@ compile auto-str.c substdio.h auto-str.c readwrite.h auto-str.c \ exit.h auto-str.c ./compile auto-str.c +auto_cron.c: \ +auto-str conf-cron + ./auto-str auto_cron `head -1 conf-cron` > auto_cron.c + +auto_cron.o: \ +compile auto_cron.c + ./compile auto_cron.c + auto_bin.c: \ auto-str conf-bin ./auto-str auto_bin `head -1 conf-bin` > auto_bin.c @@ -79,13 +98,18 @@ case.3 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 @@ case_startb.o: \ 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 @@ compile cookie.c cookie.h cookie.c str.h cookie.c uint32.h cookie.c \ surfpcs.h uint32.h surfpcs.h cookie.c ./compile cookie.c +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 @@ compile trydrent.c direntry.h1 direntry.h2 && 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.0: \ error_temp.3 nroff -man error_temp.3 > error_temp.0 +ezmlm-accept: \ +ezmlm-accept.sh warn-auto.sh conf-bin + (cat warn-auto.sh; \ + echo EZPATH=\'`head -1 conf-bin`\'; \ + cat ezmlm-accept.sh ) > ezmlm-accept + +ezmlm-accept.0: \ +ezmlm-accept.1 + nroff -man ezmlm-accept.1 > ezmlm-accept.0 + +ezmlm-archive: \ +load ezmlm-archive.o getconf.o slurpclose.o slurp.o getln.a sig.a \ +strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \ +lock.a fd.a getopt.a idxthread.o yyyymm.a + ./load ezmlm-archive getconf.o slurpclose.o slurp.o getln.a sig.a \ + idxthread.o yyyymm.a strerr.a substdio.a stralloc.a alloc.a \ + error.a str.a fs.a open.a lock.a fd.a getopt.a + +ezmlm-archive.0: \ +ezmlm-archive.1 + nroff -man ezmlm-archive.1 > ezmlm-archive.0 + +ezmlm-archive.o: \ +compile ezmlm-archive.c alloc.h error.h stralloc.h gen_alloc.h str.h \ +sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h \ +makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h sgetopt.h subgetopt.h + ./compile ezmlm-archive.c + +ezmlm-cgi: \ +load ezmlm-cgi.o getconf.o slurpclose.o slurp.o constmap.o getln.a sig.a \ +mime.a strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \ +lock.a fd.a getopt.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a + ./load ezmlm-cgi getconf.o slurpclose.o slurp.o constmap.o getln.a \ + mime.a sig.a env.a case.a datetime.o now.o mime.a wait.a yyyymm.a \ + strerr.a substdio.a stralloc.a alloc.a error.a str.a fs.a open.a \ + lock.a fd.a getopt.a + +ezmlm-cgi.0: \ +ezmlm-cgi.1 + nroff -man ezmlm-cgi.1 > ezmlm-cgi.0 + +ezmlm-cgi.o: \ +compile ezmlm-cgi.c alloc.h error.h stralloc.h gen_alloc.h str.h \ +sig.h slurp.h getconf.h strerr.h getln.h substdio.h readwrite.h env.h \ +makehash.h fmt.h strerr.h errtxt.h idx.h idxthread.h mime.h \ +constmap.h sgetopt.h subgetopt.h datetime.h now.h fork.h wait.h + ./compile ezmlm-cgi.c + +ezmlm-check: \ +ezmlm-check.sh warn-auto.sh conf-bin + (cat warn-auto.sh; \ + echo EZPATH=\'`head -1 conf-bin`\'; \ + echo QMPATH=\'`head -1 conf-qmail`\'; \ + cat ezmlm-check.sh ) > ezmlm-check + +ezmlm-check.0: \ +ezmlm-check.1 + nroff -man ezmlm-check.1 > ezmlm-check.0 + +ezmlm-clean: \ +load ezmlm-clean.o auto_qmail.o getconf.o copy.o mime.a \ +now.o datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o \ +getln.a env.a sig.a strerr.a substdio.a stralloc.a alloc.a surf.a \ +error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a cookie.o getopt.a + ./load ezmlm-clean auto_qmail.o getconf.o copy.o mime.a \ + now.o datetime.o date822fmt.o slurpclose.o \ + slurp.o qmail.o quote.o getln.a env.a sig.a strerr.a \ + substdio.a stralloc.a alloc.a error.a str.a fs.a case.a \ + open.a seek.a wait.a lock.a fd.a cookie.o getopt.a surf.a + +ezmlm-clean.0: \ +ezmlm-clean.1 + nroff -man ezmlm-clean.1 > ezmlm-clean.0 + +ezmlm-clean.o: \ +compile ezmlm-clean.c error.h stralloc.h gen_alloc.h str.h \ +env.h sig.h slurp.h getconf.h strerr.h byte.h getln.h case.h copy.h mime.h \ +qmail.h substdio.h readwrite.h seek.h quote.h datetime.h now.h cookie.h \ +date822fmt.h direntry.h fmt.h strerr.h errtxt.h idx.h sgetopt.h subgetopt.h + ./compile ezmlm-clean.c + +ezmlm-cron: \ +load ezmlm-cron.o strerr.a stralloc.a alloc.a error.a open.a auto_qmail.o \ +getopt.a getln.a str.a substdio.a sig.a fs.a open.a fd.a lock.a wait.a \ +case.a auto_cron.o + ./load ezmlm-cron getopt.a getln.a strerr.a substdio.a \ + stralloc.a alloc.a sig.a fs.a open.a fd.a lock.a error.a \ + wait.a case.a str.a auto_qmail.o auto_cron.o + +ezmlm-cron.0: \ +ezmlm-cron.1 + nroff -man ezmlm-cron.1 > ezmlm-cron.0 + +ezmlm-cron.o: \ +compile ezmlm-cron.c strerr.h substdio.h stralloc.h error.h str.h \ +fork.h readwrite.h wait.h errtxt.h idx.h sgetopt.h auto_qmail.h \ +fmt.h auto_cron.h + ./compile ezmlm-cron.c + +ezmlm-gate: \ +load ezmlm-gate.o subdb.a auto_bin.o getopt.a getln.a env.a sig.a strerr.a \ +stralloc.a alloc.a error.a str.a case.a wait.a substdio.a open.a lock.a \ +fs.a getconf.o slurpclose.o slurp.o seek.a conf-sqlld + ./load ezmlm-gate subdb.a getconf.o slurpclose.o slurp.o \ + getopt.a getln.a auto_bin.o env.a sig.a fs.a \ + strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a wait.a \ + open.a lock.a seek.a ${SQLLD} + +ezmlm-gate.0: \ +ezmlm-gate.1 + nroff -man ezmlm-gate.1 > ezmlm-gate.0 + +ezmlm-gate.o: \ +compile ezmlm-gate.c idx.h errtxt.h subscribe.h auto_bin.h \ +sgetopt.h subgetopt.h substdio.h getconf.h \ +env.h sig.h strerr.h stralloc.h alloc.h error.h str.h case.h \ +fork.h wait.h exit.h getln.h open.h + ./compile ezmlm-gate.c + +ezmlm-get: \ +load ezmlm-get.o idxthread.o subdb.a auto_qmail.o getopt.a now.o getconf.o \ +datetime.o date822fmt.o slurpclose.o slurp.o qmail.o quote.o makehash.o \ +cookie.o surf.a yyyymm.a \ +constmap.o getln.a env.a sig.a strerr.a substdio.a mime.a stralloc.a alloc.a \ +error.a str.a fs.a case.a open.a seek.a wait.a lock.a fd.a copy.o conf-sqlld + ./load ezmlm-get idxthread.o subdb.a auto_qmail.o getopt.a getconf.o \ + now.o datetime.o date822fmt.o cookie.o makehash.o slurpclose.o slurp.o \ + yyyymm.a \ + constmap.o substdio.a copy.o mime.a strerr.a stralloc.a alloc.a \ + qmail.o quote.o surf.a getln.a env.a sig.a \ + error.a str.a fs.a case.a \ + open.a seek.a wait.a lock.a fd.a ${SQLLD} + +ezmlm-get.o: \ +compile ezmlm-get.c idx.h errtxt.h error.h getconf.h stralloc.h gen_alloc.h \ +str.h cookie.h env.h sig.h slurp.h strerr.h byte.h getln.h case.h qmail.h \ +substdio.h readwrite.h seek.h quote.h sgetopt.h subgetopt.h datetime.h now.h \ +date822fmt.h fmt.h strerr.h copy.h errtxt.h idx.h idxthread.h mime.h \ +constmap.h makehash.h + ./compile ezmlm-get.c + +ezmlm-get.0: \ +ezmlm-get.1 + nroff -man ezmlm-get.1 > ezmlm-get.0 + +ezmlm-greturn: \ +load ezmlm-greturn.o quote.o getconf.o subdb.a log.o \ +slurpclose.o slurp.o now.o cookie.o surf.a lock.a env.a sig.a \ +strerr.a getln.a substdio.a stralloc.a alloc.a error.a str.a fs.a \ +case.a open.a conf-sqlld + ./load ezmlm-greturn quote.o getconf.o subdb.a \ + log.o slurpclose.o slurp.o now.o cookie.o surf.a lock.a \ + env.a sig.a strerr.a getln.a substdio.a stralloc.a alloc.a \ + error.a str.a fs.a case.a open.a ${SQLLD} + +ezmlm-greturn.0: \ +ezmlm-greturn.1 + nroff -man ezmlm-greturn.1 > ezmlm-greturn.0 + +ezmlm-greturn.o: \ +compile ezmlm-greturn.c stralloc.h gen_alloc.h stralloc.h str.h env.h sig.h \ +slurp.h getconf.h strerr.h byte.h case.h getln.h substdio.h error.h \ +quote.h readwrite.h fmt.h datetime.h now.h cookie.h \ +strerr.h subscribe.h + ./compile ezmlm-greturn.c + +ezmlm-gwarn: \ +load ezmlm-gwarn.o auto_qmail.o getconf.o mime.a cookie.o subdb.a now.o \ +slurpclose.o slurp.o quote.o datetime.o date822fmt.o qmail.o surf.a \ +case.a strerr.a sig.a getln.a substdio.a stralloc.a alloc.a error.a \ +open.a lock.a str.a fs.a fd.a wait.a copy.o getopt.a conf-sqlld + ./load ezmlm-gwarn auto_qmail.o getconf.o mime.a \ + cookie.o subdb.a getopt.a \ + now.o slurpclose.o slurp.o quote.o datetime.o date822fmt.o \ + qmail.o surf.a case.a strerr.a sig.a getln.a substdio.a \ + stralloc.a alloc.a error.a open.a lock.a str.a fs.a fd.a \ + wait.a copy.o ${SQLLD} + +ezmlm-gwarn.0: \ +ezmlm-gwarn.1 + nroff -man ezmlm-gwarn.1 > ezmlm-gwarn.0 + +ezmlm-gwarn.o: \ +compile ezmlm-gwarn.c direntry.h readwrite.h getln.h \ +substdio.h stralloc.h gen_alloc.h slurp.h getconf.h byte.h error.h str.h \ +sig.h now.h datetime.h date822fmt.h fmt.h cookie.h qmail.h substdio.h \ +qmail.h copy.h mime.h idx.h errtxt.h sgetopt.h subgetopt.h + ./compile ezmlm-gwarn.c + +ezmlm-idx: \ +load ezmlm-idx.o slurp.o slurpclose.o mime.a wait.a getopt.a \ +getln.a strerr.a sig.h sig.a open.a lock.a substdio.a stralloc.a \ +alloc.a error.a str.a fd.a case.a fs.a getconf.o makehash.o surf.o mime.a + ./load ezmlm-idx \ + mime.a slurp.o slurpclose.o wait.a getln.a strerr.a sig.a open.a \ + lock.a mime.a substdio.a stralloc.a alloc.a error.a str.a fd.a \ + getopt.a case.a fs.a getconf.o makehash.o surf.o + +ezmlm-idx.o: \ +compile ezmlm-idx.c stralloc.h getconf.h \ +substdio.h subfd.h strerr.h error.h sgetopt.h \ +lock.h sig.h slurp.h open.h getln.h case.h \ +str.h fmt.h readwrite.h exit.h idx.h mime.h errtxt.h uint32.h + ./compile ezmlm-idx.c + +ezmlm-idx.0: \ +ezmlm-idx.1 + nroff -man ezmlm-idx.1 > ezmlm-idx.0 + +ezmlm-glconf: \ +ezmlm-glconf.sh warn-auto.sh conf-bin + (cat warn-auto.sh; \ + echo EZPATH=\'`head -1 conf-bin`\'; \ + cat ezmlm-glconf.sh ) > ezmlm-glconf + +ezmlm-glconf.0: \ +ezmlm-glconf.1 + nroff -man ezmlm-glconf.1 > ezmlm-glconf.0 + +ezmlm-issubn: \ +load ezmlm-issubn.o subdb.a getconf.o slurpclose.o slurp.o \ +env.a fs.a strerr.a getln.a getopt.a conf-sqlld \ +substdio.a stralloc.a alloc.a error.a str.a case.a open.a lock.a + ./load ezmlm-issubn subdb.a getconf.o slurpclose.o slurp.o \ + getopt.a env.a fs.a strerr.a \ + getln.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a ${SQLLD} + +ezmlm-issubn.0: \ +ezmlm-issubn.1 + nroff -man ezmlm-issubn.1 > ezmlm-issubn.0 + +ezmlm-issubn.o: \ +compile ezmlm-issubn.c strerr.h subscribe.h env.h errtxt.h sgetopt.h idx.h + ./compile ezmlm-issubn.c + +ezmlm-limit: \ +load ezmlm-limit.o getconf.o slurpclose.o slurp.o substdio.a stralloc.a \ +alloc.a error.a str.a case.a open.a lock.a getopt.a fs.a sig.a now.o + ./load ezmlm-limit getconf.o slurpclose.o slurp.o getopt.a \ + strerr.a substdio.a stralloc.a alloc.a error.a str.a case.a \ + open.a lock.a fs.a sig.a now.o + +ezmlm-limit.0: \ +ezmlm-limit.1 + nroff -man ezmlm-limit.1 > ezmlm-limit.0 + +ezmlm-limit.o: \ +compile ezmlm-limit.c stralloc.h strerr.h substdio.h readwrite.h sig.h lock.h \ +getconf.h fmt.h now.h sgetopt.h error.h errtxt.h idx.h datetime.h + ./compile ezmlm-limit.c + ezmlm-list: \ -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 @@ sgetopt.h ezmlm-make.c stralloc.h gen_alloc.h stralloc.h ezmlm-make.c \ strerr.h ezmlm-make.c exit.h ezmlm-make.c readwrite.h ezmlm-make.c \ open.h ezmlm-make.c substdio.h ezmlm-make.c str.h ezmlm-make.c \ auto_bin.h ezmlm-make.c ezmlm-make.c ezmlm-make.c ezmlm-make.c \ -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 @@ ezmlm-manage.c readwrite.h ezmlm-manage.c seek.h ezmlm-manage.c \ quote.h ezmlm-manage.c datetime.h ezmlm-manage.c now.h datetime.h \ datetime.h now.h ezmlm-manage.c date822fmt.h ezmlm-manage.c fmt.h \ ezmlm-manage.c subscribe.h strerr.h strerr.h subscribe.h \ -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 @@ compile ezmlm-return.c stralloc.h gen_alloc.h stralloc.h \ ezmlm-return.c str.h ezmlm-return.c env.h ezmlm-return.c sig.h \ ezmlm-return.c slurp.h ezmlm-return.c getconf.h ezmlm-return.c \ strerr.h ezmlm-return.c byte.h ezmlm-return.c case.h ezmlm-return.c \ -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.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 @@ -380,6 +882,18 @@ ezmlm.0: \ ezmlm.5 nroff -man ezmlm.5 > ezmlm.0 +ezmlmglrc.0: \ +ezmlmglrc.5 + nroff -man ezmlmglrc.5 > ezmlmglrc.0 + +ezmlmrc.0: \ +ezmlmrc.5 + nroff -man ezmlmrc.5 > ezmlmrc.0 + +ezmlmsubrc.0: \ +ezmlmsubrc.5 + nroff -man ezmlmsubrc.5 > ezmlmsubrc.0 + fd.a: \ makelib fd_copy.o fd_move.o ./makelib fd.a fd_copy.o fd_move.o @@ -496,16 +1010,23 @@ install.c open.h install.c error.h install.c strerr.h install.c \ byte.h install.c ./compile install.c +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 @@ gen_alloc.h stralloc.h log.c log.h log.c now.h datetime.h now.h log.c \ fmt.h log.c open.h log.c ./compile log.c +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 @@ make-makelib.sh auto-ccld.sh 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 @@ make-makelib warn-auto.sh 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 @@ -582,6 +1122,16 @@ open_trunc.o: \ compile open_trunc.c open_trunc.c open_trunc.c open.h open_trunc.c ./compile open_trunc.c +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 @@ scan_ulong.o: \ 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 @@ strerr_sys.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 @@ -818,12 +1380,10 @@ compile subgetopt.c subgetopt.h subgetopt.h subgetopt.c ./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 @@ systype: \ find-systype trycpp.c ./find-systype > systype +tagmsg.o: \ +compile tagmsg.c stralloc.h slurp.h scan.h fmt.h strerr.h cookie.h conf-sqlcc + ./compile tagmsg.c ${SQLCC} + uint32.h: \ tryulong32.c compile load uint32.h1 uint32.h2 ( ( ./compile tryulong32.c && ./load tryulong32 && \ @@ -907,3 +1471,124 @@ makelib wait_pid.o wait_pid.o: \ compile wait_pid.c wait_pid.c wait_pid.c error.h wait_pid.c ./compile wait_pid.c + +yyyymm.a: \ +makelib date2yyyymm.o dateline.o + ./makelib yyyymm.a date2yyyymm.o dateline.o + +ch: \ +ezmlmrc.ch + cp -f ezmlmrc.ch_GB ezmlmrc + +ch_GB: \ +ezmlmrc.ch_GB + cp -f ezmlmrc.ch_GB ezmlmrc + +cs: \ +ezmlmrc.cs + cp -f ezmlmrc.cs ezmlmrc + +da: \ +ezmlmrc.da + cp -f ezmlmrc.da ezmlmrc + +de: \ +ezmlmrc.de + cp -f ezmlmrc.de ezmlmrc + +en_US: \ +ezmlmrc.en_US + cp -f ezmlmrc.en_US ezmlmrc + +en: \ +ezmlmrc.en_US + cp -f ezmlmrc.en_US ezmlmrc + +es: \ +ezmlmrc.es + cp -f ezmlmrc.es ezmlmrc + +us: \ +ezmlmrc.en_US + cp -f ezmlmrc.en_US ezmlmrc + +ezmlmrc: \ +ezmlmrc.en_US + cp -f ezmlmrc.en_US ezmlmrc + +fr: \ +ezmlmrc.fr + cp -f ezmlmrc.fr ezmlmrc + +id: \ +ezmlmrc.id + cp -f ezmlmrc.id ezmlmrc + +ita: \ +ezmlmrc.it + cp -f ezmlmrc.it ezmlmrc + +jp: \ +ezmlmrc.jp + cp -f ezmlmrc.jp ezmlmrc + +pl: \ +ezmlmrc.pl + cp -f ezmlmrc.pl ezmlmrc + +pt: \ +ezmlmrc.pt + cp -f ezmlmrc.pt ezmlmrc + +pt_BR: \ +ezmlmrc.pt_BR + cp -f ezmlmrc.pt_BR ezmlmrc + +ru: \ +ezmlmrc.ru + cp -f ezmlmrc.ru ezmlmrc + +sv: \ +ezmlmrc.sv + cp -f ezmlmrc.sv ezmlmrc + +mysql: + ln -sf sub_mysql/ezmlm-mktab ezmlm-mktab + ln -sf sub_mysql/checktag.c checktag.c; rm -f checktag.o + ln -sf sub_mysql/issub.c issub.c; rm -f issub.o + ln -sf sub_mysql/logmsg.c logmsg.c; rm -f logmsg.o + ln -sf sub_mysql/subscribe.c subscribe.c; rm -f subscribe.o + ln -sf sub_mysql/opensql.c opensql.c; rm -f opensql.o + ln -sf sub_mysql/putsubs.c putsubs.c; rm -f putsubs.o + ln -sf sub_mysql/tagmsg.c tagmsg.c; rm -f tagmsg.o + ln -sf sub_mysql/searchlog.c searchlog.c; rm -f searchlog.o + ln -sf sub_mysql/conf-sqlld conf-sqlld; touch conf-sqlld + ln -sf sub_mysql/conf-sqlcc conf-sqlcc; touch conf-sqlcc + +pgsql: + ln -sf sub_pgsql/ezmlm-mktab ezmlm-mktab + ln -sf sub_pgsql/checktag.c checktag.c; rm -f checktag.o + ln -sf sub_pgsql/issub.c issub.c; rm -f issub.o + ln -sf sub_pgsql/logmsg.c logmsg.c; rm -f logmsg.o + ln -sf sub_pgsql/subscribe.c subscribe.c; rm -f subscribe.o + ln -sf sub_pgsql/opensql.c opensql.c; rm -f opensql.o + ln -sf sub_pgsql/putsubs.c putsubs.c; rm -f putsubs.o + ln -sf sub_pgsql/tagmsg.c tagmsg.c; rm -f tagmsg.o + ln -sf sub_pgsql/searchlog.c searchlog.c; rm -f searchlog.o + ln -sf sub_pgsql/conf-sqlld conf-sqlld; touch conf-sqlld + ln -sf sub_pgsql/conf-sqlcc conf-sqlcc; touch conf-sqlcc + +std: + ln -sf sub_std/ezmlm-mktab ezmlm-mktab + ln -sf sub_std/checktag.c checktag.c; rm -f checktag.o + ln -sf sub_std/issub.c issub.c; rm -f issub.o + ln -sf sub_std/logmsg.c logmsg.c; rm -f logmsg.o + ln -sf sub_std/subscribe.c subscribe.c; rm -f subscribe.o + ln -sf sub_std/opensql.c opensql.c; rm -f opensql.o + ln -sf sub_std/putsubs.c putsubs.c; rm -f putsubs.o + ln -sf sub_std/tagmsg.c tagmsg.c; rm -f tagmsg.o + ln -sf sub_std/searchlog.c searchlog.c; rm -f searchlog.o + ln -sf sub_std/conf-sqlld conf-sqlld; touch conf-sqlld + ln -sf sub_std/conf-sqlcc conf-sqlcc; touch conf-sqlcc + + diff --git a/README.idx b/README.idx new file mode 100644 index 0000000..7ffd895 --- /dev/null +++ b/README.idx @@ -0,0 +1,337 @@ +$Id: README.idx,v 1.70 1999/12/24 04:20:45 lindberg Exp $ +$Name: ezmlm-idx-040 $ + +(c) 1997, 1998, 1999 Fred Lindberg, lindberg@id.wustl.edu (code+docs+faq) + Fred B. Ringel, fredr@rivertown.net (faq) + +This software is distributed under the GNU General Public Licence as +published by the Free Software Foundation. See the file LICENCE.TXT for +the conditions under which this software is made available. + +Like any other piece of software (and information generally), ezmlm-idx +comes with NO WARRANTY. + +This is an addition and patch to ezmlm-0.53 [(c) Dan J. Bernstein]. +Ezmlm-idx uses Dan's libraries and heavily relies on ezmlm-0.53 code. +ezmlm-idx does not function without ezmlm-0.53. + +ezmlm-0.53 provides basic message distribution, subscriber address handling, +message archiving (single quoted message retrieval only), and bounce +handling. ezmlm-idx adds multi-message threaded archive retrieval, digests, +remote administration, message and subscription moderation, subscriber-only +restrictions, message trailer, subject prefix, subscriber name storage, +customizable setup, multi-language and MIME support and more. In addition, +improved bounce handling, case-insensitive subscriber address storage, +and support for distributed lists (main + sublist transparent to the +subscriber). Ezmlm-idx can now be compiled with MySQL or Postgres support. + +See INSTALL.idx for installation instructions. +See UPGRADE.idx to upgrade from a previous version of ezmlm-idx. +See CHANGES.idx to see what's new in this version. +See FILES.idx for a list of files in this package. +See FAQ.idx for more info on ezmlm(-idx) functions and setup (see below on + how to get the latest version). +See ezman-0.xx* for a user's/administrator's manual to ezmlm/idx. Available + on line at http://www.ezmlm.org/ and for download at + ftp://ftp.ezmlm.org/pub/patches/ezman/ and mirrors. + +NOTE: Some ezmlmrc translations may not be up-to-date. ezmlm-make will +complain and the results may not match the documentation. Changes required +are small. If you correct a translation, please submit it for inclusion +in the next ezmlm-idx version. + +*.rpm will put ezmlm-cgi in the bin directory. To use it, you must manually +move it to a cgi-bin directory, set ownership and SUID (if needed), and +set up /ezmlm/ezcgirc. + +See http://pobox.com/~djb/ezmlm.html for the latest information about +ezmlm. + +See ftp://ftp.id.wustl.edu/pub/patches for the latest version of ezmlm-idx and +downloadable versions of the FAQ. + +See http://www.ezmlm.org/ for ezmlm FAQ and docs on line. + +Mail ``ezmlm-subscribe@list.cr.yp.to'' to join the ezmlm mailing +list (averages 3 messages per day). This list is run by Dan J. Bernstein +using ezmlm-0.53. + +Send general comments and questions to: +lindberg@id.wustl.edu or fredr@rivertown.net. + +Send bug reports and patches to: +lindberg@id.wustl.edu. + +Below, acknowledgements and a list of systems where ezmlm-idx has been reported +to work. + +ACKNOWLEDGEMENTS +- Fred B. Ringel, first and foremost, for a great collaboration, ideas, testing, + docs clarification. This makes it so much more fun. +- Dan J. Bernstein for qmail, ezmlm, and great libraries. +- Toshinori Maeno (TM; tmaeno@hpcl.titech.ac.jp) for finding an ezmlm-idx-0.20 + bug, and MIME suggestions, suggestions about hopcount and received headers, + return-path header in archive, sublist loop detection, ezmlm-limit suggestion, + many other suggestions and explanations, help to get ezmlm-cgi Japanese + support to work, as well as pre-release testing. +- Frank Tegtmeyer for inciting digests and format info/suggestions, and for + ezmlmrc.de. +- Magnus Stålåker (MAS; stalaker@umc.se) for the PostgresSQL interface. +- Mark Delany for the original ezmlm-issub and for suggesting reordering + unlink() and doit() in ezmlm-warn. +- Raul Miller and Chris Garrigues for format info/suggestions. +- Thomas Erskine (TEE; tom@crc.doc.ca) for fix to clean sunos-4.1.3 compiles + and pre-release compilation on many platforms, fixes for bash-isms in + ezmlm-check, and testing. +- Shuhei Kobayashi (SK; shuhei-k@jaist.ac.jp) for MIME corrections/suggestions, + X-sequence suggestions, ezmlm-check/make corrections, and pre-release testing. +- Yusuf Goolamabbas (YG; yusufg@krdl.org.sg) and the Mutt developers for + pointing out outdated MIME, ezmlmrc improvements, outformat bug, suggestion + about ezmlm-moderate -r switch, and pre-release testing. +- Brian Gentry (BG; gentry@usaccess-inc.com) for reporting the + ezmlm-moderate-0.12 exit code bug. +- Anand R. Buddhev (ARB; arb@iconnect.co.ke) for fix to clean BSDI 2.1 compiles + and pre-release testing. +- Masashi Fujita (MF; objectx@polyphony.scei.co.jp) for fix to clean SGI + compiles, lint advice, MIME suggestions, pre-release testing, a patch for + the ezmlm-make-0.21 -c bug, ezmlmrc.jp, and finding postmsg bug in 0.301. +- Matthew D. Stock (MDS; stock@perdix.acsu.buffalo.edu) for pre-release testing. +- Ximenes Zalteca for finding an ezmlm-send-0.21 bug. +- Jukka Suomela (JS; jukka@narnia.tky.hut.fi) for inciting the ezmlm-send -cC + switch. +- John White (johnjohn@triceratops.com) for questions leading to ezmlm-tstdig, + and for testing the example script. +- Torben Fjerdingstad (TF; unitfj@tfj.uni-c.dk) for testing case-insensitive + issub.c and subscribe.c, for TARGETS, for suggesting a no-copy-to-SENDER + option, for ezmlmrc.da, for reporting missing MIME end for base64/QP + moderated [un]sub confirms, and for pre-release testing. +- Shinya O'Hira (SOH; Shinya_Oohira@justsystem.co.jp) for reporting the + ezmlm-make-0.22 lock file name bug and for testing the fix. Also for many + helpful suggestions and hard work testing rfc2047 subject support. +- Sadhu(sadhu@aloha.net) & Tracy Reed (TR; treed@ultraviolet.org) for reporting + the ezmlm-send-0.22 undefined SENDER bug, and testing the fix. +- Scott Balantyne (SDB; sdb@ssr.com) for inciting the modifications for digest + out of dir/editor. +- Frank Denis (j@industrie.capgemini.fr) for ezmlmrc.fr. +- Marc Evans (marc@destek.net) for reporting the ezmlm-make-0.221 64-bit bug + and pre-release testing, and inciting, improving, and testing ezmlm-test. +- Vince Vielhaber (VV; vev@michvhf.com) for reporting ezmlm-check problems with + non-bash and testing fixes. +- Andrew Pam (AP; xanni@xanadu.net) for suggesting the ezmlm-idx -d switch and + reporting the ezmlm-gate failure on NULL $SENDER bug. +- Glen Stewart (GS; glen_stewart@associate.com) for reminding me about command + case insensitivity and ezmlmrc typo fixes. +- Kenji Ikeda (KI; noroi@nt.is.dnp.co.jp) for a patch to ezmlm-idx-0.23 to get + message numbers in subjects. I've added code to ezmlm-idx-0.30 implementing + this is a similar manner. Sen Nagata (sen_ml@eccosys.com) for suggesting this + earlier. Bugfix for missing MIME boundary in -index reply. +- Sebastian Andersson (SA; sa@hogia.net) for ezmlmrc.sv, MIME suggestions, + ezmlm-weed patch, ezmlmrc version check suggestion and pre-release testing. +- Giorgos Stathakopoulos (GS; stathako@cti.gr) for pre-release testing. +- David Summers (DS; david@summersoft.fay.ar.us) for pre-release testing, + reporting a ezmlm-check bug and SPEC files for rpm:s. +- Steinar Haug (STH; sthaug@nethelp.no) for pointing out missing ';' in + ezmlmrc (caused problems with /bin/sh on FreeBSD), and the trigger message + received lines in the digest header. +- Peter Hunter (PH) for suggesting dir/headeradd and list address in digest + headers and for reporting a "cosmetic" bug in subscription logging. +- Jim Simmons (JS) for finding the n/d switch misnaming in ezmlmrc for text file + editing. +- Sergiusz Pawlowicz (SP; ser@arch.pwr.wroc.pl) for ezmlmrc.pl, and many entries + for mimeremove. +- Wanderlei Antonio Cavassin (WAC; cavassin@connectiva.com.br) for + ezmlmrc.pt_BR. +- Jim Simmons ( ) for finding a missing-newline-mime bug in + ezmlm-moderate/store/clean. +- Monte Mitzelfelt (MM; monte@gonefishing.org) for suggesting alternative + From: for ezmlm-manage help messages to break responder loops. +- Louis Larry (LL; luois@kediri.webindonesia.com) for reporting a 0.311 prefix + handling bug. +- Sigi Remsmurr (SR; service@isk.de), Bill Nugent (whn@topelo.lopi.com), James + Smallacombe (JS; up@3am) for ezmlmrc corrections/suggestions. +- Matthew Saunders (MS; matts@easynet.net) for ezmlm-glconf.sh corrections and + reporting crashability of ezmlm-get by abnormal use (fixed). +- Petr Novotny (PN; Petr.Novotny@antek.cz) for ezdomo.tar.gz corrections. +- Evan Champion (EC; evanc@synapse.net) for ezmlm-request bug report. +- Jeff Hill (JH; jhill@hronline.com) for ezmlm-reject bug report. +- Bruno Wolff (BW; bruno@cerberus.umn.edu) for Ultrix fixes. +- Butch Evans (BE; butch@###.com) for reporting trailer problems with + multipart/alternative messages and testing fix. +- Kragen Sitaker (KS; kragen@pobox.com) for reporting ezmlm-manage -get bug. +- Lars B. Rasmusson (LBR; lbr@mjolner.dk) for prerelease testing with sun cc. +- Mike McLeish (MMcL; Mike.Mcleish@chatsoft.com) for reporting problems + using the 'x' format and testing the fix. +- Jan Kasprzak (JK; kas@informatics.muni.cz) for ezmlmrc.cs and headerremove + suggestions. +- Matt McGlynn for reporting 0.32 ezmlmrc -return omission. +- Roman V Isaev (RVI; rm@techno.ru) for ezmlmrc.ru as well as suggestions + on -allow automation. +- Aria Prima Novianto (APN; aria@isnet.org) for ezmlmrc.id. +- Roberto De Carlo (RDC; rodeca@flashnet.it) for ezmlmrc.it. +- Vicent Mas, Francesc Alted, Sonia Lorente, and Cyndy DePoy for ezmlmrc.es. +- HaiFeng Guo (HFG; haifeng@ms.lawton.com.cn) for ezmlmrc.cn_GB. +- Benjamin Pflugman (BPF; philemon@spin.de) for reporting multipart/signed + problems and testing fix. +- Rik Myers (RM; rik@sumthin.nu), Daniel Mattos (DM; daniel@tiii.com) and others + for helping make ezmlm-test less platform-sensitive. +- Michael Hirohama (MH; michael@sooth.com) for reporting Outlook problems and + testing a work-around. +- Mate Wierdl (MW; mw@wierdlpc.msci.memphis.edu) for SPEC file kit and + suggestions on ezmlm-test, "it", etc, and pre-release testing. +- Numerous users for suggestions/corrections for the documentation. +- I'm sure I've forgotten others who have contributed ideas, questions, + comments. Thanks! + +EZMLM-IDX HAS BEEN REPORTED TO WORK ON (With ezmlm-0.53): +0.12: linux-2.0.18-:i386-:-:i486-:- (Thanks Dileep Agrawal) +0.12: linux-2.0.23-:i386-:-:i486-:- (Thanks TV) +0.12: linux-2.0.31-:i386-:-:i486-:- (Thanks Nathan D. Faber) +0.20: linux-2.0.23-:i386-:-:i486:-:- +0.20: linux-2.0.31-:i386-:-:pentium:-:- (Thanks FBR) +0.20: linux-2.0.23-:i386-:-:pentium:-:- (Thanks YG) +0.20: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.20: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB) +0.20: sunos-4.1.4-2-:sparc-:sun4:sun4m- (Thanks SK) +0.20: freebsd-2.2.2-release-:i386-:-:pentium.pro-:- (Thanks MDS) +0.21: linux-2.0.23-:i386-:-:i486-:- +0.21: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.21: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE) +0.21: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB) +0.21: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH) +0.22: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.22: linux-2.0.23-:i386-:-:i486-:- +0.22: linux-2.0.31-:i386-:-:ppro-:- (Thanks YG) +0.22: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR) +0.22: linux-2.0.32-:i386-:-:pentium-:- (Thanks TF) +0.22: freebsd-2.2.1-release-:i386-:-:-:- (Thanks TM) +0.22: freebsd-2.2.5-stable-:i386-:-:pentium.pro-:- (Thanks MDS) +0.22: osf1-v4.0-386-:-:-:alpha-:- (Thanks TEE) +0.22: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE) +0.22: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4u-:sun4u- (Thanks YG) +0.22: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (Thanks TEE) +0.22: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH) +0.23: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.23: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB) +0.23: freebsd-2.2.1-release-:i386-:-:-:- (Thanks TM) +0.23: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.23: linux-2.0.30-:i386-:-:i486-:- +0.23: linux-2.0.32-:i386-:-:i486-:- (Thanks BCL; Bruce C. Law) +0.23: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR) +0.23: osf1-v4.0-386-:-:-:alpha-:- (Thanks TEE) +0.23: osf1-v4.0-564-:-:-:alpha-:- (Thanks ME) +0.23: sunos-4.1.3-3-:unknown-:sun4-:sun4m-:sun4m- (Thanks TEE) +0.23: sunos-5.5-generic_103093-06-:sparc-:sun4-:sun4m-:sun4m- (Thanks TEE) +0.23: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH) +0.30: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.30: bsd.os-2.1-:i386-:-:pentium-:- (Thanks ARB) +0.30: freebsd-2.2.5-release-:i386-:-:-:- (Thanks TM) +0.30: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.30: linux-2.0.30-:i386-:-:i486-:- +0.30: linux-2.0.31-:i386-:-:ppro:-:- (Thanks YG) +0.30: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR) +0.30: osf1-v4.0-564-:-:-:alpha-:- (Thanks ME) +0.30: sunos-5.6-generic-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH) +0.301: freebsd-2.2.5-release-:i386-:-:pentium.pro-:- (Thanks Matthew S. Soffen) +0.301: linux-2.0.30-:-:-:sparc-:- (Thanks Bill Himmelstoss) +0.301: linux-2.0.30-:i386-:-:i486-:- +0.301: linux-2.0.32-:i386-:-:pentium-:- (Thanks FBR) +0.301: linux-2.0.33-:i386-:-:i486-:- (Thanks BCL) +0.301: linux-2.0.32-:i386-:-:ppro-:- +0.302: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.302: linux-2.0.31-:i386-:-:ppro:-:- (Thanks YG) +0.302: linux-2.0.32-:i386-:-:i486-:- +0.302: linux-2.0.34-:i386-:-:pentium-:- (Thanks FBR) +0.31: freebsd-2.2.6-release-:i386-:-:-:- (Thanks TM) +0.31: linux-2.0.32-:i386-:-:ppro-:- +0.31: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.311: linux-2.0.31-:i386-:-:ppro-:- (Thanks YG) +0.311: linux-2.0.32-:i386-:-:ppro-:- +0.311: linux-2.0.33-:i386-:-:i486-:- (Thanks BCL) +0.311: linux-2.0.35-:i386-:-:i486-:- (Thanks PN) +0.312: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.312: freebsd-3.0-current-:i386-:-:pentium/p54c-:- (Thanks MS) +0.312: irix-5.3-08031224-:-:-:ip12-:- (Thanks Rob Stone) +0.312: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.312: irix64-6.4-02121744-:-:-:ip30-:- (Thanks MF) +0.312: linux-2.0.32-:i386-:-:ppro-:- +0.312: linux-2.1.115-:i386-:-:pentium-:- (Thanks Uwe Ohse) +0.312: sunos-5.6-generic_105181-06-:sparc-:sun4-:sun4u-:sun4u- (Thanks GS) +0.312: sunos-5.6-generic_105182-08-:i386-:i86pc-:i86pc-:i86pc- (Thanks LBR) +0.313: aix-4-2-:-:-:00720704c00-:- (Thanks TF) +0.313: freebsd-2.2.6-release-:i386-:-:-:- (Thanks TM) +0.313: freebsd-2.2.6-release-:i386-:-:pentium-:- (Thanks Dave Walton) +0.313: freebsd-3.0-release-:i386-:-:pentium.ii.(qtr-micr)-:- (Tx Erik Gault) +0.313: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.313: irix64-6.4-02121744-:-:-:ip30-:- (Thanks MF) +0.313: linux-2.0.32-:i386-:-:ppro-:- +0.313: linux-2.0.35-:i386-:-:pentium-:- (Thanks crt@ice.degan.si) +0.313: linux-2.0.36-:i386-:-:pentium-:- (Thanks FBR) +0.313: linux-2.2.0-pre4-:i386-:-:i486-:- (Thanks Chris Van Meter) +0.313: sunos-5.6-generic_105181-04-:sparc-:sun4-:sun4u-:sun4u- (Thanks SOH) +0.313: sunos-5.6-generic_105181-08-:sparc-:sun4-:sun4u-:sun4u- (Thanks LBR) +0.313: ultrix-4.3-0-:-:-:risc-:- (Thanks BW) +0.314: amigaos-3.1-40.60-:-:-:m68k-:- (Thanks Kirk Strauser) +0.314: freebsd-2.2.8-stable-:i386-:-:pentium.ii-:- +0.314: linux-2.0.32-:i386-:-:ppro-:- +0.32: bsd.os-4.0-:i386-:-:-:- (Thanks ME) +0.32: freebsd-2.2.7-stable-:i386-:-:pentium.pro-:- (Thanks Chris Johnson) +0.32: freebsd-3.0-release-:i386-:-:pentium.ii.(qtr-micr)-:- (Thanks MS) +0.32: irix-5.3-11091812-:-:-:ip22-:- (Thanks MF) +0.32: linux-2.0.34-:i386-:-:i486-:- (Thanks Benjamin T. Brillat) +0.32: linux-2.0.34-:i386-:-:ppro-:- (Thanks Troy N. Poppe) +0.32: linux-2.0.36-:i386-:-:pentium-:- (Thanks Peter J. Hunter) +0.32: linux-2.0.36-:i386-:-:ppro-:- (Thanks FT) +0.32: linux-2.2.0-pre4-:i386-:-:pentium-:- (Thanks FBR) +0.32: linux-2.2.1-:i386-:-:pentium-:- (Thanks FBR) +0.32: netbsd-1.3i-:i386-:-:intel.pentium.(p54c).(586-class)-:- (Thanks GC Wing) +0.321: bsd.os-4.0-:i386-:-:pentium.ii-:- (Thanks RV Isaev) +0.321: freebsd-3.1-release-:i386-:-:pentium.ii-:- (Thanks AR Buddhdev) +0.321: freebsd-3.1-release-:i386-:-:pentium.ii/xeon/celeron-:- (Tx A Iijima) +0.321: freebsd-3.1-stable-:i386-:-:pentium.ii/xeon/celeron-:- (Tx B Fuerst) +0.321: linux-2.0.34-:i386-:-:pentium-:- (Thanks root@issaries.com.au) +0.321: linux-2.0.36-:i386-:-:pentium-:- (Thanks MC Yoon) +0.321: linux-2.0.36-:i386-:-:i486-:- (Thanks K Ralph) +0.321: linux-2.0.36-:i386-:-:ppro-:- (Thanks JD Mitchell) +0.321: linux-2.2.2-:i386-:-:pentium-:- (Thanks R Siemer) +0.321: linux-2.2.4-:i386-:-:pentium-:- (Thanks JM Charette) +0.321: linux-2.2.5-:i386-:-:ppro-:- (Thanks SM Moret) +0.321: sunos-5.6-generic_105181-10-:sparc-:sun4-:sun4u-:sun4u- (Tx JA Marshall) +0.322: aix-4-2-:-:-:000720704c00-:- (Thanks TF) +0.322: linux-2.0.35-:i386-:-:i486-:- (Thanks Robert Siemer) +0.322: linux-2.0.36-:i386-:-:i486-:- (Thanks Ryan C. Hughes) +0.322: linux-2.0.36-:i386-:-:pentium-:- (Thanks Kengo Nakajima) +0.322: linux-2.2.10-:i386-:-:pentium-:- (Thanks Peter Green) +0.322: linux-2.0.36-:i386-:-:ppro-:- (Thanks Jeff Hill) +0.322: linux-2.2.5-15-:i386-:-:pentium-:- (Thanks Raj H.) +0.322: linux-2.2.5-15-:i386-:-:ppro-:- (Thanks peter@mail.gradwell.com) +0.322: linux-2.2.5-:i386-:-:ppro-:- (Thanks Achim Gosse) +0.322: linux-2.2.9-:i386-:-:pentium-:- (Thanks FBR) +0.322: netbsd-1.4-:sparc-:-:mb86900/1a.or.l64801.@.25.mhz,.wtl3170/2.fpu-:- (Tx R Nurges) +0.322: sunos-5.6-generic_105181-05-:sparc-:sun4-:sun4u-:sun4u- (Tx Ralf Weber) +0.322: sunos-5.6-generic_105181-13-:sparc-:sun4-:sun4u-:sun4u- (Tx MN Boyiazis) +0.322: sunos-5.7-generic-:sparc-:sun4-:sun4u-:sun4u- (Tx Paul Theodoropoulos) +0.322: sunos-5.7-generic_106541-02-:sparc-:sun4-:sun4u-:sun4u- (Tx Bo Fussing) +0.323: linux-2.0.36-:i386-:-:pentium-:- (TX RVI) +0.323: linux-2.2.3-:i386-:-:pentium-:- (TX Ludovico Magocavallo) +0.323: linux-2.2.7-:i386-:-:ppro-:- (TX Achim Gosse) +0.324: bsd.os-4.0.1-:i386-:-:-:- (Tx Peeter Pirn) +0.324: freebsd-3.3-stable-:i386-:-:pentium/p54c-:- (Tx J B Bell) +0.324: freebsd-4.0-19990816-current-:i386-:-:pentium.ii/xeon/celeron-:- (Tx MS) +0.324: irix-6.5-04151556-:-:-:ip22-:- (Tx Claudio Nieder) +0.324: linux-2.0.36-:i386-:-:pentium-:- (Tx Michael P. McMillan) +0.324: linux-2.0.38-:i386-:-:pentium-:- (Tx Anton V. Bobykin) +0.324: linux-2.2.1-:-:-:armv4l-:- (Tx Jim Zajkowski) +0.324: linux-2.2.12-20-:i386-:-:ppro-:- (Tx Michael D. Mooney) +0.324: linux-2.2.12-:i386-:-:p2-:- (TX Oden Eriksson) +0.324: linux-2.2.13-:i386-:-:pentium-:- (Tx Tibor Szentmarjay) +0.324: linux-2.2.5-22-:alpha-:-:alpha-:- (Tx Steve J. Borho) +0.324: linux-2.2.5-22-:i386-:-:ppro-:- (Tx Yann M. Aubert) +0.324: linux-2.2.7-:i386-:-:ppro-:- (Tx Brad W. Baker) +0.324: openbsd-2.5-generic#172-:openbsd.sparc-:-:sparc-:- (Tx Grant L Miller) +0.324: openbsd-2.5-generic#243-:openbsd.i386-:-:i386-:- (Tx Grant L Miller) +0.324: sunos-5.5-generic-:sparc-:sun4-:sun4c-:sun4c- (Tx D Andrew Reynhout) +0.40: freebsd-3.3-release-:i386-:-:prentium.iii-:- (Tx MAS) +0.40: linux-2.2.11-:i386-:-:pentium-:- (Tx FBR) +0.40: linux-2.2.5-22-:i386-:-:ppro-:- [RH6.0] +0.40: linux-2.2.13-:i386-:-:ppro-:- [Debian] (Tx MAS) + diff --git a/TARGETS b/TARGETS new file mode 100644 index 0000000..6ae1653 --- /dev/null +++ b/TARGETS @@ -0,0 +1,191 @@ +alloc.a +alloc.o +alloc_re.o +author.o +auto-ccld.sh +auto-str +auto-str.o +auto_bin.c +auto_bin.o +auto_cron.c +auto_cron.o +auto_qmail.c +auto_qmail.o +byte_chr.o +byte_copy.o +byte_cr.o +byte_diff.o +byte_rchr.o +byte_zero.o +case.a +case_diffb.o +case_diffs.o +case_lowerb.o +case_startb.o +case_starts.o +checktag.o +compile +concatHDR.o +constmap.o +cookie.o +copy.o +date2yyyymm.o +date822fmt.o +dateline.o +datetime.o +decodeB.o +decodeHDR.o +decodeQ.o +direntry.h +encodeB.o +encodeQ.o +env.a +env.o +envread.o +error.a +error.o +error_str.o +ezmlm-accept +ezmlm-archive +ezmlm-archive.o +ezmlm-cgi +ezmlm-cgi.o +ezmlm-check +ezmlm-clean +ezmlm-clean.o +ezmlm-cron +ezmlm-cron.o +ezmlm-gate +ezmlm-gate.o +ezmlm-get +ezmlm-get.o +ezmlm-glconf +ezmlm-idx +ezmlm-idx.o +ezmlm-issubn +ezmlm-issubn.o +ezmlm-limit +ezmlm-limit.o +ezmlm-list +ezmlm-list.o +ezmlm-make +ezmlm-make.o +ezmlm-manage +ezmlm-manage.o +ezmlm-moderate +ezmlm-moderate.o +ezmlm-reject +ezmlm-reject.o +ezmlm-request +ezmlm-request.o +ezmlm-return +ezmlm-return.o +ezmlm-send +ezmlm-send.o +ezmlm-split +ezmlm-split.o +ezmlm-store +ezmlm-store.o +ezmlm-sub +ezmlm-sub.o +ezmlm-test +ezmlm-tstdig +ezmlm-tstdig.o +ezmlm-unsub +ezmlm-unsub.o +ezmlm-warn +ezmlm-warn.o +ezmlm-weed +ezmlm-weed.o +ezmlmrc +fd.a +fd_copy.o +fd_move.o +find-systype +fmt_str.o +fmt_uint.o +fmt_uint0.o +fmt_ulong.o +fork.h +fs.a +getconf.o +getln.a +getln.o +getln2.o +getopt.a +hasflock.h +hassgact.h +idxthread.o +issub.o +load +lock.a +lock_ex.o +log.o +logmsg.o +make-compile +make-load +make-makelib +makehash.o +makelib +mime.a +now.o +open.a +open_append.o +open_read.o +open_trunc.o +opensql.o +putsubs.o +qmail.o +quote.o +scan_8long.o +scan_ulong.o +searchlog.o +seek.a +seek_set.o +sgetopt.o +sig.a +sig_catch.o +sig_pipe.o +slurp.o +slurpclose.o +str.a +str_chr.o +str_cpy.o +str_diff.o +str_diffn.o +str_len.o +str_rchr.o +str_start.o +stralloc.a +stralloc_arts.o +stralloc_cat.o +stralloc_catb.o +stralloc_cats.o +stralloc_copy.o +stralloc_eady.o +stralloc_opyb.o +stralloc_opys.o +stralloc_pend.o +strerr.a +strerr.o +strerr_die.o +strerr_sys.o +subdb.a +subfderr.o +subgetopt.o +subscribe.o +substdi.o +substdio.a +substdio.o +substdio_copy.o +substdo.o +surf.a +surf.o +surfpcs.o +systype +tagmsg.o +uint32.h +unfoldHDR.o +wait.a +wait_pid.o +yyyymm.a diff --git a/UPGRADE.idx b/UPGRADE.idx new file mode 100644 index 0000000..3e18bc2 --- /dev/null +++ b/UPGRADE.idx @@ -0,0 +1,190 @@ +$Id: UPGRADE.idx,v 1.39 1999/12/19 16:47:30 lindberg Exp $ +$Name: ezmlm-idx-040 $ + +Like any other piece of software (and information generally), ezmlm-idx +comes with NO WARRANTY. + +This file is for upgrading from earlier version of ezmlm-idx/mod. If you use +ezmlm-0.53 but have not installed a previous version of ezmlm-idx, +see INSTALL.idx. For details on what's new in this version, see CHANGES.idx. + +1. Proceed as per INSTALL.idx. + NOTE: If you follow the test instructions in INSTALL of ezmlm-0.53 after + adding ezmlm-idx, step 6 will fail. Before this step, edit + ~/testlist/editor and remove the ezmlm-reject line. + + +Steps required for upgrading from ezmlm-idx-0.31x/32x +----------------------------------------------------- +In the unlikely event that you have lists that have been manually configured +to use ezmlm-gate (sender check/moderation combination) using only a single +directory, add the same directory to the command line a second time. If you +do not do this, all messages will be moderated, i.e. no major problem. No +other changes are required, but you may want to use some of the new features +(see CHANGES.idx). + +See below to migrate customized ezmlmrc files. + +Run ezmlm-idx on your lists. The index file format has changed. The old +format will still work, but only the new format can be used with WWW archive +access. + +To enable WWW archive access for your list(s) see the "Optional" section in +INSTALL.idx. + +If you used MySQL support, you need to update the tables. A few new fields +have been added for performance moitoring and billing. sub_mysql/to40x will +generate the necessary SQL. For each list, do: + +sh sub_mysql/to40x list | mysql ... + +where ``list'' is the tableroot for the list. + +Additional steps for upgrading from ezmlm-idx-0.30x +--------------------------------------------------- + +If your old lists use SENDER restriction on posts with aliases (DIR/extra) +and blacklisted addresses (DIR/blacklist) you need to change the name of +these directories to DIR/allow and DIR/deny, respectively, and rebuild the list +(see below). Without this change the list will still function normally, but +addresses cannot be added/removed from these addresses remotely (e.g. via +list-allow-subscribe). Other than this, your lists will function without +modifications if you are upgrading from ezmlm-idx>=0.30. + +See below for changing the names of the extra databases. + + +Additional steps for upgrading from ezmlm-idx<0.30 +-------------------------------------------------- +1. Reindex the subject index for existing lists: + + % ezmlm-idx DIR + + for each list directory 'DIR'. + +2. For existing digest lists, assuming the list "joe-sos" and the digest list + "joe-sos-digest". + + a. Remove links to the digest list: + + % rm -f ~joe/.qmail-sos-digest* + + b. edit the main list to include a digest list: + + % ezmlm-make -edxxx ~joe/SOS ~joe/.qmail joe-sos id.com gaga + + where 'xxx' are switches used in creating the original list. For lists + created with ezmlm-idx-0.23 or later, the arguments after the list + directory may be omitted. + + c. Move the digest subscriber info: + + % mv ~joe/SOS-digest/subscribers/* ~joe/SOS/digest/subscribers + + The digest list bounce info will be lost, as the key used for the new + digest is the same as for the list, and different for that from the old + digest. At worst, this will make the info for a digest user on missed + digests incomplete. It may also slightly delay the removal + of a permanently bouncing subscriber addresses. + + +Additional steps for upgrading from ezmlm-idx<0.23x +--------------------------------------------------- +For subscription-moderated lists created with ezmlm-idx<0.23: + +1. If you have subscription moderated lists created with ezmlm-idx<0.23, + they likely lack dir/text/mod-sub-confirm and dir/text/mod-unsub-confirm. + Ezmlm-idx-0.23 substituted dir/text/(un)sub-confirm if the above files were + missing, but ezmlm-idx>=0.30 will not work without these files. Again, + ezmlm-make -e is the easiest way to update the list. Alternatively, + just copy dir/text/(un)sub-confirm to dir/text/mod-(un)sub-confirm. + +------------------------------------------------------------------------------ +That's it! To report success (this helps to track platform-specific problems): + + % ( echo 'First M. Last'; cat `cat SYSDEPS` ) \ + | mail cfl-src@id.wustl.edu + +Replace First M. Last with your name. + +Send bugs reports, ideally with patch, to 'lindberg@id.wustl.edu'. + + +------------------------------------------------------------------------------ + + + Additional information +------------------------ + +Migrating customized ezmlmrc files +================================== + +ezmlmrc is upgraded from ezmlm-idx-0.31x/32x, but the changes are not required +for using the list. + +The changes from ezmlm-0.30x are minimal, but fix a couple of bugs, see +CHANGES.idx). If you have custom ezmlmrc files and wish to update them, +do the following: + + First create a diff between the old ezmlmrc distribution and the + custom ezmlmrc file: + + % cp /usr/local/bin/ezmlm/ezmlmrc ~/ezmlmrc.orig + % cp ~/.ezmlmrc ~/ezmlmrc + % diff -c ~/ezmlmrc.orig ~/ezmlmrc ~/ezmlmrc.diff + + Next, apply the changes to the new ezmlmrc: + + % cp .../ezmlm-idx-0.33/ezmlmrc ~/ezmlmrc + % patch ~/ezmlmrc < ~/ezmlmrc.diff + + Next check for rejected parts (you need to apply them manually): + + % cat ~/ezmlmrc.rej + +Any existing list can be edited with 'ezmlm-make -e dir dot local host [code]' +with the appropriate switches to take advantage of new ezmlm functions. If +you make ezmlmrc files in other languages, please make them public domain and +mail them to lindberg@id.wustl.edu for inclusion in future versions of +ezmlm-idx. + +Adjusting the name of the extra databases (from ezmlm-idx<0.30): +=============================================================== + + % mv DIR/extra DIR/allow + % mv DIR/blacklist DIR/deny + % ezmlm-make -+ DIR + +Additional steps required when upgrading from ezmlm-idx<0.30: + +1. Reindex the subject index for existing lists: + + % ezmlm-idx DIR + + for each list directory 'DIR'. + +2. For existing digest lists, assuming the list "joe-sos" and the digest list + "joe-sos-digest". + + a. Remove links to the digest list: + + % rm -f ~joe/.qmail-sos-digest* + + b. edit the main list to include a digest list: + + % ezmlm-make -edxxx ~joe/SOS ~joe/.qmail joe-sos id.com gaga + + where 'xxx' are switches used in creating the original list. For lists + created with ezmlm-idx-0.23 or later, the arguments after the list + directory may be omitted. + + c. Move the digest subscriber info: + + % mv ~joe/SOS-digest/subscribers/* ~joe/SOS/digest/subscribers + + The digest list bounce info will be lost, as the key used for the new + digest is the same as for the list, and different for that from the old + digest. At worst, this will make the info for a digest user on missed + digests incomplete. It may also slightly delay the removal + of a permanently bouncing subscriber addresses. + diff --git a/VERSION b/VERSION index 6049539..a01a1fd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1,2 @@ ezmlm 0.53 +$Name: ezmlm-idx-040 $ diff --git a/author.c b/author.c new file mode 100644 index 0000000..c5bf0dc --- /dev/null +++ b/author.c @@ -0,0 +1,103 @@ +/*$Id: author.c,v 1.3 1999/09/29 03:11:44 lindberg Exp $*/ +/*$Name:*/ + +unsigned int author_name(char **sout,char *s,unsigned int l) +/* s is a string that contains a from: line argument\n. We parse */ +/* s as follows: If there is an unquoted '<' we eliminate everything after */ +/* it else if there is a unquoted ';' we eliminate everything after it. */ +/* Then, we eliminate LWSP and '"' from the beginning and end. Note that */ +/* this is not strict rfc822, but all we need is a display handle that */ +/* doesn't show the address. If in the remaining text there is a '@' we put*/ +/* in a '.' instead. Also, there are some non-rfc822 from lines out there */ +/* and we still want to maximize the chance of getting a handle, even if it*/ +/* costs a little extra work.*/ +{ + int squote = 0; + int dquote = 0; + int level = 0; + int flagdone; + unsigned int len; + char ch; + char *cpfirst,*cp; + char *cpcomlast = 0; + char *cpquotlast = 0; + char *cpquot = 0; + char *cpcom = 0; + char *cplt = 0; + + if (!s || !l) { /* Yuck - pass the buck */ + *sout = s; + return 0; + } + cp = s; len = l; + + while (len--) { + ch = *(cp++); + if (squote) { + squote = 0; + continue; + } + if (ch == '\\') { + squote = 1; + continue; + } + if (ch == '"') { /* "name" */ + 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 */ + 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 */ + while (cpfirst <= cp && + (*cpfirst == ' ' || *cpfirst == '\t' || *cpfirst == '<')) cpfirst++; + while (cp >= cpfirst && + (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '>')) cp--; + if (cp >= cpfirst || flagdone) + break; + cp = s + l - 1; + cpfirst = s; + flagdone = 1; + } + + *sout = cpfirst; + len = cp - cpfirst + 1; + while (cpfirst <= cp) { + if (*cpfirst == '@') + *cpfirst = '.'; + cpfirst++; + } + return len; +} + diff --git a/auto_cron.h b/auto_cron.h new file mode 100644 index 0000000..bdd9387 --- /dev/null +++ b/auto_cron.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CRON_H +#define AUTO_CRON_H + +extern char auto_cron[]; + +#endif diff --git a/case_diffs.c b/case_diffs.c new file mode 100644 index 0000000..212c645 --- /dev/null +++ b/case_diffs.c @@ -0,0 +1,19 @@ +#include "case.h" + +int case_diffs(s,t) +register char *s; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) break; + if (!x) break; + } + return ((int)(unsigned int) x) - ((int)(unsigned int) y); +} diff --git a/case_starts.c b/case_starts.c new file mode 100644 index 0000000..2278a0a --- /dev/null +++ b/case_starts.c @@ -0,0 +1,18 @@ +#include "case.h" + +int case_starts(s,t) +register char *s; +register char *t; +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (!y) return 1; + if (x != y) return 0; + } +} diff --git a/checktag.c b/checktag.c new file mode 120000 index 0000000..fe4e410 --- /dev/null +++ b/checktag.c @@ -0,0 +1 @@ +sub_std/checktag.c \ No newline at end of file diff --git a/concatHDR.c b/concatHDR.c new file mode 100644 index 0000000..604892c --- /dev/null +++ b/concatHDR.c @@ -0,0 +1,45 @@ +/*$Id: */ +/*$Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "strerr.h" +#include "case.h" +#include "byte.h" +#include "mime.h" +#include "errtxt.h" + +void concatHDR(indata,n,outdata,fatal) +char *indata; +unsigned int n; +stralloc *outdata; +char *fatal; +/* takes a concatenated string of line and continuation line, trims leading */ +/* and trailing LWSP and collapses line breaks and surrounding LWSP to ' '. */ +/* indata has to end in \n or \0 or this routine will write beyond indata! */ +/* if indata ends with \0, this will be changed to \n. */ + +{ + register char *cp,*cpout; + char *cplast; + if (!stralloc_copys(outdata,"")) die_nomem(fatal); + if (!stralloc_ready(outdata,n)) die_nomem(fatal); + cpout = outdata->s; + if (n == 0) return; + cplast = indata + n - 1; + cp = cplast; + while (*cplast == '\0' || *cplast == '\n') --cplast; + if (cp == cplast) die_nomem(fatal); /* just in case */ + *(++cplast) = '\n'; /* have terminal '\n' */ + cp = indata; + while (cp <= cplast) { + while (*cp == ' ' || *cp == '\t') ++cp; /* LWSP before */ + while (*cp != '\n') *(cpout++) = *(cp++); /* text */ + ++cp; /* skip \n */ + --cpout; /* last char */ + while (*cpout == ' ' || *cpout == '\t') --cpout; /* LWSP after */ + *(++cpout) = ' '; /* replace with single ' ' */ + ++cpout; /* point to free byte */ + } + outdata->len = cpout - outdata->s; +} + diff --git a/conf-cron b/conf-cron new file mode 100644 index 0000000..612a7e3 --- /dev/null +++ b/conf-cron @@ -0,0 +1,3 @@ +/usr/bin + +This is the directory housing the crontab binary diff --git a/conf-sqlcc b/conf-sqlcc new file mode 120000 index 0000000..6d13424 --- /dev/null +++ b/conf-sqlcc @@ -0,0 +1 @@ +sub_std/conf-sqlcc \ No newline at end of file diff --git a/conf-sqlld b/conf-sqlld new file mode 120000 index 0000000..7432a47 --- /dev/null +++ b/conf-sqlld @@ -0,0 +1 @@ +sub_std/conf-sqlld \ No newline at end of file diff --git a/constmap.c b/constmap.c index 722e3b8..8c742c2 100644 --- a/constmap.c +++ b/constmap.c @@ -18,6 +18,39 @@ int len; 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 len; } 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; diff --git a/constmap.h b/constmap.h index 3f29179..66be99f 100644 --- a/constmap.h +++ b/constmap.h @@ -16,5 +16,6 @@ struct constmap { extern int constmap_init(); extern void constmap_free(); extern char *constmap(); - +extern char *constmap_get(); +extern int constmap_index(); #endif diff --git a/copy.c b/copy.c new file mode 100644 index 0000000..24f0034 --- /dev/null +++ b/copy.c @@ -0,0 +1,211 @@ +/*$Id: copy.c,v 1.10 1999/08/07 19:28:16 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +/* Copies a file relative the current directory and substitutes */ +/* !A at the beginning of a line for the target, */ +/* !R at the beginning of a line for the confirm reply address, */ +/* The following substitutions are also made. If not set, ????? */ +/* will be printed: <#l#> outlocal */ +/* will be printed: <#h#> outhost */ +/* will be printed: <#n#> outmsgnum */ +/* Other tags are killed, e.g. removed. A missing file is a */ +/* permanent error so owner finds out ASAP. May not have access to */ +/* maillog. Content transfer encoding is done for 'B' and 'Q'. For */ +/* 'H' no content transfer encoding is done, but blank lines are */ +/* suppressed. Behavior for other codes is undefined. This includes*/ +/* lower case 'q'/'b'! If code is 'H' substitution of target and */ +/* verptarget is prevented as it may create illegal headers. */ + +#include "stralloc.h" +#include "substdio.h" +#include "strerr.h" +#include "str.h" +#include "getln.h" +#include "case.h" +#include "readwrite.h" +#include "qmail.h" +#include "errtxt.h" +#include "error.h" +#include "quote.h" +#include "copy.h" +#include "mime.h" + /* for public setup functions only */ +#define FATAL "copy: fatal: " + +static stralloc line = {0}; +static stralloc outline = {0}; +static stralloc qline = {0}; +static stralloc outlocal = {0}; +static stralloc outhost = {0}; +static substdio sstext; +static char textbuf[256]; +static char *target = "?????"; +static char *verptarget = "?????"; +static char *confirm = "?????"; +static char *szmsgnum = "?????"; + +void set_cpoutlocal(ln) +stralloc *ln; +{ /* must be quoted for safety. Note that substitutions that use */ + /* outlocal within an atom may create illegal addresses */ + if (!quote(&outlocal,ln)) + strerr_die2x(111,FATAL,ERR_NOMEM); +} + +void set_cpouthost(ln) +stralloc *ln; +{ + if (!stralloc_copy(&outhost,ln)) + strerr_die2x(111,FATAL,ERR_NOMEM); +} + +void set_cptarget(tg) +char *tg; +{ + target = tg; +} + +void set_cpverptarget(tg) +char *tg; +{ + verptarget = tg; +} + +void set_cpconfirm(cf) +char *cf; +{ + confirm = cf; +} + +void set_cpnum(cf) +char *cf; +{ + szmsgnum = cf; +} + +static struct qmail *qq; + +static void codeput(l,n,code,fatal) +char *l; +unsigned int n; +char code; +char *fatal; + +{ + if (!code || code == 'H') + qmail_put(qq,l,n); + else { + if (code == 'Q') + encodeQ(l,n,&qline,fatal); + else + encodeB(l,n,&qline,0,fatal); + qmail_put(qq,qline.s,qline.len); + } +} + +static void codeputs(l,code,fatal) +char *l; +char code; +char *fatal; +{ + codeput(l,str_len(l),code,fatal); +} + +void copy(qqp,fn,q,fatal) +struct qmail *qqp; +char *fn; /* text file name */ +char q; /* = '\0' for regular output, 'B' for base64, */ + /* 'Q' for quoted printable,'H' for header */ +char *fatal; /* FATAL error string */ + +{ + int fd; + int match, done; + unsigned int pos,nextpos; + + qq = qqp; + if ((fd = open_read(fn)) == -1) + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn,": "); + else + strerr_die4sys(100,fatal,ERR_OPEN,fn,": "); + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn,": "); + if (match) { /* suppress blank line for 'H'eader mode */ + if (line.len == 1 && q == 'H') continue; + if (line.s[0] == '!') { + if (line.s[1] == 'R') { + codeput(" ",3,q,fatal); + codeputs(confirm,q,fatal); + codeput("\n",1,q,fatal); + continue; + } + if (line.s[1] == 'A') { + codeput(" ",3,q,fatal); + codeputs(target,q,fatal); + codeput("\n",1,q,fatal); + continue; + } + } + /* Find tags <#x#>. Replace with for x=R confirm, for x=A */ + /* target, x=l outlocal, x=h outhost. For others, just */ + /* skip tag. If outlocal/outhost are not set, the tags are*/ + /* skipped. If confirm/taget are not set, the tags are */ + /* replaced by "???????" */ + pos = 0; + nextpos = 0; + done = 0; + outline.len = 0; /* zap outline */ + while ((pos += byte_chr(line.s+pos,line.len-pos,'<')) != line.len) { + if (pos + 4 < line.len && + line.s[pos+1] == '#' && + line.s[pos+3] == '#' && + line.s[pos+4] == '>') { /* tag. Copy first part of line */ + done = 1; /* did something */ + if (!stralloc_catb(&outline,line.s+nextpos,pos-nextpos)) + die_nomem(fatal); + switch(line.s[pos+2]) { + case 'A': + if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE); + if (!stralloc_cats(&outline,target)) die_nomem(fatal); + break; + case 'R': + if (!stralloc_cats(&outline,confirm)) die_nomem(fatal); + break; + case 'l': + if (!stralloc_cat(&outline,&outlocal)) die_nomem(fatal); + break; + case 'h': + if (!stralloc_cat(&outline,&outhost)) die_nomem(fatal); + break; + case 't': + if (q == 'H') strerr_die(111,ERR_SUBST_UNSAFE); + if (!stralloc_cats(&outline,verptarget)) die_nomem(fatal); + break; + case 'n': + if (!stralloc_cats(&outline,szmsgnum)) die_nomem(fatal); + break; + default: + break; /* unknown tags killed */ + } + pos += 5; + nextpos = pos; + } else + ++pos; /* try next position */ + } + if (!done) + codeput(line.s,line.len,q,fatal); + else { + if (!stralloc_catb(&outline,line.s+nextpos,line.len-nextpos)) + die_nomem(fatal); /* remainder */ + codeput(outline.s,outline.len,q,fatal); + } + + } else + break; + } + close(fd); +} + diff --git a/copy.h b/copy.h new file mode 100644 index 0000000..3a642eb --- /dev/null +++ b/copy.h @@ -0,0 +1,11 @@ +#ifndef COPY_H +#define COPY_H + +/* copy (qq,fn,fatal) */ +extern void copy(); +extern void set_cpoutlocal(); +extern void set_cpouthost(); +extern void set_cptarget(); +extern void set_cpconfirm(); +extern void set_cpnum(); +#endif diff --git a/date2yyyymm.c b/date2yyyymm.c new file mode 100644 index 0000000..dd6ea87 --- /dev/null +++ b/date2yyyymm.c @@ -0,0 +1,71 @@ + +/*$Id: date2yyyymm.c,v 1.1 1999/10/09 16:45:43 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "yyyymm.h" + +unsigned int date2yyyymm(s) +char *s; +/* expects a qmail date string s and returns yyyymm */ +/* if there are problems, it returns 0. If there is no terminating char */ +/* we may segfault if the syntax is bad. Assure that the ';' is there */ +/* or add '\0' */ +{ + unsigned int mo; + unsigned int year; /* must hold yyyymm - ok to year 65K */ + char ch,ch1,ch2; + +/* jan feb mar apr may jun jul aug sep oct nov dec */ +/* - strictly qmail datefmt dependent*/ + for (;;s++) { + ch = *s; + if (ch != ' ' && (ch < '0' || ch > '9')) break; + } + mo = 0; + if (!(ch = *(s++))) return 0; + if (ch >= 'a') ch -= ('a' - 'A'); /* toupper */ + if (!(ch1 = *(s++))) return 0; /* rfc822 hrds are case-insens */ + if (ch1 >= 'a') ch1 -= ('a' - 'A'); + if (!(ch2 = *(s++))) return 0; + if (ch2 >= 'a') ch2 -= ('a' - 'A'); + + switch (ch) { + case 'J': + if (ch1 == 'A' && ch2 == 'N') { mo = 1; break; } + if (ch1 == 'U') { + if (ch2 == 'N') mo = 6; + else if (ch2 == 'L') mo = 7; + } + break; + case 'F': if (ch1 == 'E' && ch2 == 'B') mo = 2; break; + case 'A': + if (ch1 == 'P' && ch2 == 'R') mo = 4; + else if (ch1 == 'U' && ch2 == 'G') mo = 8; + break; + case 'M': + if (ch1 != 'A') break; + if (ch2 == 'R') mo = 3; + else if (ch2 == 'Y') mo = 5; + break; + case 'S': if (ch1 == 'E' && ch2 == 'P') mo = 9; break; + case 'O': if (ch1 == 'C' && ch2 == 'T') mo = 10; break; + case 'N': if (ch1 == 'O' && ch2 == 'V') mo = 11; break; + case 'D': if (ch1 == 'E' && ch2 == 'C') mo = 12; break; + default: + break; + } + if (!mo || *(s++) != ' ') + return 0L; /* mo true means s[0-2] valid */ + year = 0L; + for (;;) { + register unsigned char chy; + chy = (unsigned char) *(s++); + if (chy < '0' || chy > '9') { + if (year) break; + else return 0; + } + year = year * 10 + (chy - '0'); + } + return year * 100 + mo; +} + + diff --git a/dateline.c b/dateline.c new file mode 100644 index 0000000..77a11bd --- /dev/null +++ b/dateline.c @@ -0,0 +1,41 @@ +/*$Id: dateline.c,v 1.2 1999/10/09 17:44:37 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "fmt.h" +#include "yyyymm.h" +#include "stralloc.h" + +static char strnum[FMT_ULONG]; + +int dateline(dt,d) +stralloc *dt; unsigned long d; +/* converts yyyymm from unsigned long d to text dt */ +{ + char *mo; + switch (d % 100) { + case 1: mo = "January"; break; + case 2: mo = "February"; break; + case 3: mo = "March"; break; + case 4: mo = "April"; break; + case 5: mo = "May"; break; + case 6: mo = "June"; break; + case 7: mo = "July"; break; + case 8: mo = "August"; break; + case 9: mo = "September"; break; + case 10: mo = "October"; break; + case 11: mo = "November"; break; + case 12: mo = "December"; break; + case 0: mo = "????"; break; + default: cgierr("I don't know any month > 12", + "",""); + } + if (!stralloc_copys(dt,mo)) return -1; + if (!stralloc_cats(dt," ")) return -1; + if ((d/100)) { + if (!stralloc_catb(dt,strnum,fmt_ulong(strnum,d/100))) return -1; + } else + if (!stralloc_cats(dt,"????")) return 0; + return 1; +} + + diff --git a/decodeB.c b/decodeB.c new file mode 100644 index 0000000..78406bc --- /dev/null +++ b/decodeB.c @@ -0,0 +1,71 @@ +#include "stralloc.h" +#include "strerr.h" +#include "uint32.h" +#include "errtxt.h" + + /* Characters and translation as per rfc2047. */ +static char char64table[128] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +#define char64enc(c) (((c) & 0x80) ? -1 : char64table[(c)]) + +static void die_nomem(fatal) + char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +void decodeB(cpfrom,n,outdata,fatal) +char *cpfrom; +unsigned int n; +stralloc *outdata; +char *fatal; +/* does B decoding of the string pointed to by cpfrom up to the character */ +/* before the one pointed to by cpnext, and appends the results to mimeline*/ +{ + uint32 hold32; + char holdch[4] = "???"; + int i,j; + char c; /* needs to be signed */ + char *cp, *cpnext; + + cp = cpfrom; + cpnext = cp + n; + i = 0; + hold32 = 0L; + if (!stralloc_readyplus(outdata,n)) die_nomem(fatal); + for (;;) { + if (i == 4) { + for (j = 2; j >= 0; --j) { + holdch[j] = hold32 & 0xff; + hold32 = hold32 >> 8; + } + if (!stralloc_cats(outdata,holdch)) die_nomem(fatal); + if (cp >= cpnext) + break; + hold32 = 0L; + i = 0; + } + if (cp >= cpnext) { /* pad */ + c = 0; + } else { + c = char64enc(*cp); + ++cp; + } + if (c < 0) /* ignore illegal characters */ + continue; + else { + hold32 = (hold32 << 6) | (c & 0x7f); + ++i; + } + } +} + diff --git a/decodeHDR.c b/decodeHDR.c new file mode 100644 index 0000000..4693d3d --- /dev/null +++ b/decodeHDR.c @@ -0,0 +1,92 @@ +/*$Id: decodeHDR.c,v 1.2 1998/02/28 19:03:02 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "strerr.h" +#include "error.h" +#include "case.h" +#include "byte.h" +#include "uint32.h" +#include "mime.h" +#include "errtxt.h" + +static void die_nomem(fatal) + char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +void decodeHDR(indata,n,outdata,charset,fatal) +char *indata; +unsigned int n; +stralloc *outdata; +char *charset; +char *fatal; + +/* decodes indata depending on charset. May put '\n' and '\0' into out */ +/* data and can take them as indata. */ +{ + unsigned int pos; + char *cp,*cpnext,*cpstart,*cpenc,*cptxt,*cpend,*cpafter; + + cpnext = indata; + cpafter = cpnext + n; + cpstart = cpnext; + if (!stralloc_copys(outdata,"")) die_nomem(fatal); + if (!stralloc_ready(outdata,n)) die_nomem(fatal); + for (;;) { + cpstart = cpstart + byte_chr(cpstart,cpafter-cpstart,'='); + if (cpstart == cpafter) + break; + ++cpstart; + if (*cpstart != '?') + continue; + ++cpstart; + cpenc = cpstart + byte_chr(cpstart,cpafter-cpstart,'?'); + if (cpenc == cpafter) + continue; + cpenc++; + cptxt = cpenc + byte_chr(cpenc,cpafter-cpenc,'?'); + if (cptxt == cpafter) + continue; + cptxt++; + cpend = cptxt + byte_chr(cptxt,cpafter-cptxt,'?'); + if (cpend == cpafter || *(cpend + 1) != '=') + continue; + /* We'll decode anything. On lists with many charsets, this may */ + /* result in unreadable subjects, but that's the case even if */ + /* no decoding is done. This way, the subject will be optimal */ + /* for threading, but charset info is lost. We aim to correctly */ + /* decode us-ascii and all iso-8859/2022 charsets. Exacly how */ + /* these will be displayed depends on dir/charset. */ + cp = cpnext; + /* scrap lwsp between coded strings */ + while (*cp == ' ' || *cp == '\t') + cp++; + if (cp != cpstart - 2) + if (!stralloc_catb(outdata,cpnext, cpstart - cpnext - 2)) + die_nomem(fatal); + cpnext = cp + 1; + cpstart = cpnext; + switch (*cpenc) { + case 'b': + case 'B': + pos = outdata->len; + decodeB(cptxt,cpend-cptxt,outdata,2,fatal); + cpnext = cpend + 2; + cpstart = cpnext; + break; + case 'q': + case 'Q': + decodeQ(cptxt,cpend-cptxt,outdata,fatal); + cpnext = cpend + 2; + cpstart = cpnext; + break; + default: /* shouldn't happen, but let's be reasonable */ + cpstart = cpend + 2; + break; + } + } + if (!stralloc_catb(outdata,cpnext,indata-cpnext+n)) die_nomem(fatal); +} + diff --git a/decodeQ.c b/decodeQ.c new file mode 100644 index 0000000..7e5d388 --- /dev/null +++ b/decodeQ.c @@ -0,0 +1,77 @@ +/*$Id: decodeQ.c,v 1.3 1998/10/29 21:48:24 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "strerr.h" +#include "errtxt.h" +#include "mime.h" + +/* takes a string pointed to by cpfrom and adds the next 'n' bytes to */ +/* outdata, replacing any Quoted-Printable codes with the real characters. */ +/* NUL and LF in the input are allowed, but anything that decodes to these */ +/* values is ignored. */ + +static char char16table[128] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +#define char16enc(c) (((c) & 0x80) ? -1 : char16table[(c)]) + +static void die_nomem(fatal) + char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +void decodeQ(cpfrom,n,outdata,fatal) +char *cpfrom; +unsigned int n; +stralloc *outdata; +char *fatal; +/* does Q decoding of the string pointed to by cpfrom up to the character */ +/* before the one pointed to by cpnext, and appends the results to mimeline*/ +{ + char *cp,*cpnext,*cpmore; + char holdch[2]; + char ch1,ch2; /* need to be signed */ + + cpmore = cpfrom; + cp = cpfrom; + cpnext = cp + n; + if (!stralloc_readyplus(outdata,n)) die_nomem(fatal); + + while (cp < cpnext) { + if (*cp == '_') *cp = ' '; /* '_' -> space */ + else if (*cp == '=') { /* "=F8" -> '\xF8' */ + /* copy stuff before */ + if (!stralloc_catb(outdata,cpmore,cp-cpmore)) die_nomem(fatal); + cpmore = cp; + ++cp; + if (*cp == '\n') { /* skip soft line break */ + ++cp; + cpmore = cp; + continue; + } + ch1 = char16enc(*cp); + if (++cp >= cpnext) + break; + ch2 = char16enc(*cp); + if (ch1 >= 0 && ch2 >= 0) { /* ignore illegals */ + holdch[0] = (ch1 << 4 | ch2) & 0xff; + if (!stralloc_catb(outdata,holdch,1)) die_nomem(fatal); + cpmore += 3; + } + } + ++cp; + } /* copy stuff after */ + if (!stralloc_catb(outdata,cpmore,cpnext-cpmore)) die_nomem(fatal); +} + + diff --git a/encodeB.c b/encodeB.c new file mode 100644 index 0000000..1672de9 --- /dev/null +++ b/encodeB.c @@ -0,0 +1,99 @@ +/* $Id: encodeB.c,v 1.3 1998/03/21 18:30:27 lindberg Exp $*/ +/* $Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "uint32.h" +#include "mime.h" +#include "strerr.h" +#include "errtxt.h" + +static void die_nomem(fatal) + char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static unsigned char base64char[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned int pos = 0; +static unsigned int i = 0; +static uint32 hold32; +static unsigned char *cpout; + +static void addone(ch) +unsigned char ch; +{ + if (!(pos++)) + hold32 = (uint32) ch; + else + hold32 = (hold32 << 8) | ch; + if (pos == 3) { + *cpout++ = base64char[(hold32 >> 18) & 0x3f]; + *cpout++ = base64char[(hold32 >> 12) & 0x3f]; + *cpout++ = base64char[(hold32 >> 6) & 0x3f]; + *cpout++ = base64char[hold32 & 0x3f]; + if (++i == 18) { + *cpout++ = '\n'; + i = 0; + } + pos = 0; + } +} + +static void dorest() +{ + switch (pos) { + case 2: + hold32 = hold32 << 2; + *cpout++ = base64char[(hold32 >> 12) & 0x3f]; + *cpout++ = base64char[(hold32 >> 06) & 0x3f]; + *cpout++ = base64char[hold32 & 0x3f]; + *cpout++ = '='; + break; + case 1: + hold32 = hold32 << 4; + *cpout++ = base64char[(hold32 >> 06) & 0x3f]; + *cpout++ = base64char[hold32 & 0x3f]; + *cpout++ = '='; + *cpout++ = '='; + break; + default: + break; + } + *cpout++ = '\n'; +} + +void encodeB(indata,n,outdata,control,fatal) +unsigned char *indata; +unsigned int n; +stralloc *outdata; +int control; /* 1 = init, 2 = flush */ +char *fatal; + /* converts any character with the high order bit set to */ + /* base64. In: n chars of indata, out: stralloc outdata */ + /* as '=' is not allowed within the block, we cannot flush after */ + /* each line, so we carry over data from call to call. The last */ + /* call to encodeB should have control = 2 to do the flushing. */ + /* control = 0 resets, and the routine starts out reset. */ +{ + register unsigned char ch; + + if (control == 1) { + pos = 0; + i = 0; + } + if (!stralloc_copys(outdata,"")) die_nomem(fatal); + if (!stralloc_ready(outdata,n*8/3 + n/72 + 5)) die_nomem(fatal); + cpout = (unsigned char *) outdata->s; + while (n--) { + ch = *indata++; + if (ch == '\n') + addone('\r'); + addone(ch); + } + if (control == 2) + dorest(); + outdata->len = (unsigned int) (cpout - (unsigned char *) outdata->s); +} + diff --git a/encodeQ.c b/encodeQ.c new file mode 100644 index 0000000..080b875 --- /dev/null +++ b/encodeQ.c @@ -0,0 +1,58 @@ +/* $Id: encodeQ.c,v 1.2 1998/02/28 19:03:02 lindberg Exp $*/ +/* $Name: ezmlm-idx-040 $*/ + +#include "errtxt.h" +#include "mime.h" +#include "stralloc.h" +#include "strerr.h" + +static void die_nomem(fatal) + char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static char *hexchar = "0123456789ABCDEF"; + +void encodeQ(indata,n,outdata,fatal) +char *indata; +unsigned int n; +stralloc *outdata; +char *fatal; + + /* converts any character with the high order bit set to */ + /* quoted printable. In: n chars of indata, out: stralloc outdata*/ + +{ + register char *cpout; + register char ch; + unsigned int i; + char *cpin; + + cpin = indata; + i = 0; + /* max 3 outchars per inchar & 2 char newline per 72 chars */ + if (!stralloc_copys(outdata,"")) die_nomem(fatal); + if (!stralloc_ready(outdata,n * 3 + n/36)) die_nomem(fatal); /* worst case */ + cpout = outdata->s; + while (n--) { + ch = *cpin++; + if (ch != ' ' && ch != '\n' && ch != '\t' && + (ch > 126 || ch < 33 || ch == 61)) { + *(cpout++) = '='; + *(cpout++) = hexchar[(ch >> 4) & 0xf]; + *(cpout++) = hexchar[ch & 0xf]; + i += 3; + } else { + if (ch == '\n') + i = 0; + *(cpout++) = ch; + } + if (i >= 72) { + *(cpout++) = '='; + *(cpout++) = '\n'; + i = 0; + } + } + outdata->len = (unsigned int) (cpout - outdata->s); +} diff --git a/env.c b/env.c new file mode 100644 index 0000000..05d527b --- /dev/null +++ b/env.c @@ -0,0 +1,113 @@ +/* env.c, envread.c, env.h: environ library +Daniel J. Bernstein, djb@silverton.berkeley.edu. +Depends on str.h, alloc.h. +Requires environ. +19960113: rewrite. warning: interface is different. +No known patent problems. +*/ + +#include "str.h" +#include "alloc.h" +#include "env.h" + +int env_isinit = 0; /* if env_isinit: */ +static int ea; /* environ is a pointer to ea+1 char*'s. */ +static int en; /* the first en of those are ALLOCATED. environ[en] is 0. */ + +static void env_goodbye(i) int i; +{ + alloc_free(environ[i]); + environ[i] = environ[--en]; + environ[en] = 0; +} + +static char *null = 0; + +void env_clear() +{ + if (env_isinit) while (en) env_goodbye(0); + else environ = &null; +} + +static void env_unsetlen(s,len) char *s; int len; +{ + int i; + for (i = en - 1;i >= 0;--i) + if (!str_diffn(s,environ[i],len)) + if (environ[i][len] == '=') + env_goodbye(i); +} + +int env_unset(s) char *s; +{ + if (!env_isinit) if (!env_init()) return 0; + env_unsetlen(s,str_len(s)); + return 1; +} + +static int env_add(s) char *s; +{ + char *t; + t = env_findeq(s); + if (t) env_unsetlen(s,t - s); + if (en == ea) + { + ea += 30; + if (!alloc_re(&environ,(en + 1) * sizeof(char *),(ea + 1) * sizeof(char *))) + { ea = en; return 0; } + } + environ[en++] = s; + environ[en] = 0; + return 1; +} + +int env_put(s) char *s; +{ + char *u; + if (!env_isinit) if (!env_init()) return 0; + u = alloc(str_len(s) + 1); + if (!u) return 0; + str_copy(u,s); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; +} + +int env_put2(s,t) char *s; char *t; +{ + char *u; + int slen; + if (!env_isinit) if (!env_init()) return 0; + slen = str_len(s); + u = alloc(slen + str_len(t) + 2); + if (!u) return 0; + str_copy(u,s); + u[slen] = '='; + str_copy(u + slen + 1,t); + if (!env_add(u)) { alloc_free(u); return 0; } + return 1; +} + +int env_init() +{ + char **newenviron; + int i; + for (en = 0;environ[en];++en) ; + ea = en + 10; + newenviron = (char **) alloc((ea + 1) * sizeof(char *)); + if (!newenviron) return 0; + for (en = 0;environ[en];++en) + { + newenviron[en] = alloc(str_len(environ[en]) + 1); + if (!newenviron[en]) + { + for (i = 0;i < en;++i) alloc_free(newenviron[i]); + alloc_free(newenviron); + return 0; + } + str_copy(newenviron[en],environ[en]); + } + newenviron[en] = 0; + environ = newenviron; + env_isinit = 1; + return 1; +} diff --git a/error.c b/error.c index d51304f..f9b617d 100644 --- a/error.c +++ b/error.c @@ -17,7 +17,7 @@ ENOMEM; -2; #endif -int error_noent = +int error_noent = #ifdef ENOENT ENOENT; #else @@ -93,3 +93,10 @@ EACCES; #else -13; #endif + +int error_notdir = +#ifdef ENOTDIR +ENOTDIR; +#else +-14; +#endif diff --git a/error.h b/error.h index 01bd3dc..42fdc81 100644 --- a/error.h +++ b/error.h @@ -16,6 +16,7 @@ extern int error_again; extern int error_pipe; extern int error_perm; extern int error_acces; +extern int error_notdir; extern char *error_str(); extern int error_temp(); diff --git a/errtxt.h b/errtxt.h new file mode 100644 index 0000000..ae82bf9 --- /dev/null +++ b/errtxt.h @@ -0,0 +1,156 @@ +/*$Id: errtxt.h,v 1.46 1999/11/29 04:54:01 lindberg Exp $*/ +/*Name: $*/ + +#ifndef ERRTXT_H +#define ERRTXT_H + +/* Error messages. If you translate these, I would urge you to keep the */ +/* English version as well. I'm happy to include any bilingual versions */ +/* of this file with future versions of ezmlm-idx. */ + +#define ERR_NOMEM "out of memory" +#define ERR_NOCMD "command not available" +#define ERR_CLOSE "unable to close " +#define ERR_WRITE "unable to write " +#define ERR_READ "unable to read " +#define ERR_READ_KEY "unable to read key" +#define ERR_FLUSH "unable to flush " +#define ERR_SEEK "unalble to seek " +#define ERR_SYNC "unable to sync " +#define ERR_CHMOD "unable to chmod " +#define ERR_STAT "unable to stat " +#define ERR_DELETE "unable to delete " +#define ERR_READ_INPUT "unable to read input: " +#define ERR_SEEK_INPUT "unable to seek input: " +#define ERR_CREATE "unable to create " +#define ERR_MOVE "unable to move " +#define ERR_OPEN "unable to open " +#define ERR_OBTAIN "unable to obtain " +#define ERR_OPEN_LOCK "unable to open lock: " +#define ERR_OBTAIN_LOCK "unable to obtain lock: " +#define ERR_NOLOCAL "LOCAL not set" +#define ERR_NODTLINE "DTLINE not set" +#define ERR_NOSENDER "SENDER not set" +#define ERR_NOHOST "HOST not set" +#define ERR_NOEXIST " does not exist" +#define ERR_NOEXIST_KEY " key does not exist" +#define ERR_SWITCH "unable to switch to " +#define ERR_BOUNCE "I do not reply to bounce messages (#5.7.2)" +#define ERR_ANONYMOUS "I do not reply to senders without host names (#5.7.2)" +#define ERR_NOT_PUBLIC "Sorry, I've been told to reject all requests (#5.7.2)" +#define ERR_NOT_ARCHIVED "Sorry, this list is not archived (#5.1.1)" +#define ERR_NOT_INDEXED "Sorry, this list is not indexed (#5.1.1)" +#define ERR_NOT_AVAILABLE "Command not available (#5.1.1)" +#define ERR_NOT_ALLOWED "Command allowed only to moderators (#5.7.1)" +#define ERR_BAD_ADDRESS "I don't accept messages at this address (inlocal and/or inhost don't match) (#5.1.1)" +#define ERR_BAD_RETURN_ADDRESS "Invalid bounce or receipt address format (#5.1.1)" +#define ERR_BAD_REQUEST "Illegal request format (#5.7.1)" +#define ERR_QMAIL_QUEUE "unable to run qmail-queue: " +#define ERR_TMP_QMAIL_QUEUE "temporary qmail-queue error: " +#define ERR_NOT_PARENT "this message is not from my parent list (#5.7.2)" +#define ERR_SUBLIST "sublist messages must have a Mailing-List header (#5.7.2)" +#define ERR_MAILING_LIST "message already has a Mailing-List header (maybe I should be a sublist) (#5.7.2)" +#define ERR_LOOPING "this message is looping: it already has my Delivered-To line (#5.4.6)" +#define ERR_SUBSCRIBER_CAN "only subscribers can " +#define ERR_571 " (#5.7.1)" +#define ERR_EMPTY_DIGEST "nothing to digest" +#define ERR_EMPTY_LIST "no messages in archive" +#define ERR_NOINDEX "Sorry, I can't find the index for this message" +#define ERR_BAD_INDEX "Old format or corrupted index. Run ezmlm-idx! (#5.3.0)" +#define ERR_BAD_DIGCODE "incorrect digest code (#5.7.1)" +#define ERR_UNEXPECTED "program logic error (#5.3.0)" +#define ERR_BAD_ALL "Sorry, after removing unacceptable MIME parts from your message I was left with nothing (#5.7.0)" +#define ERR_MIME_QUOTE "MIME boundary lacks end quote" +#define ERR_SUBST_UNSAFE "Sorry, substitution of target addresses into headers with <#A#> or <#T#> is unsafe and not permitted." + +/* ezmlm-request unique */ +#define ERR_REQ_LISTNAME "This command requires a mailing list name (#5.1.1)" +#define ERR_REQ_LOCAL "the local part of the command string does not match this list (#5.1.1)" + +/* ezmlm-reject unique */ +#define ERR_MAX_SIZE "Sorry, I don't accept messages larger than " +#define ERR_MIN_SIZE "Sorry, I don't accept messages shorter than " +#define ERR_SIZE_CODE " (#5.2.3)" +#define ERR_NO_ADDRESS "List address must be in To: or Cc: (#5.7.0)" +#define ERR_NO_SUBJECT "Sorry, I don't accept message with empty Subject (#5.7.0)" +#define ERR_SUBCOMMAND "Sorry, I don't accept commands in the subject line. Please send a message to the -help address shown in the the ``Mailing-List:'' header for command info (#5.7.0)" +#define ERR_BODYCOMMAND "Sorry, as the message starts with ``[un]subscribe'' it looks like an adminstrative request. Please send a message to the -help address shown in the ``Mailing-List:'' header for [un]subscribe info (#5.7.0)" +#define ERR_BAD_TYPE "Sorry, I don't accept messages of MIME Content-Type '" +#define ERR_BAD_PART "Sorry, a message part has an unacceptable MIME Content-Type: " +#define ERR_JUNK "Precedence: junk - message ignored" + +/* ezmlm-manage unique */ +#define ERR_SUB_NOP "target is already a subscriber" +#define ERR_UNSUB_NOP "target is not a subscriber" +#define ERR_BAD_NAME "only letters and underscore allowed in file name (#5.6.0)" +#define ERR_NO_MARK "missing start-of-text or end-of-text mark (#5.6.0)" +#define ERR_EDSIZE "Maximum edit file size exceeded (#5.6.0)" +#define ERR_BAD_CHAR "NUL or other illegal character in input (#5.6.0)" +#define ERR_EXTRA_SUB "Processed SENDER check addition request for: " +#define ERR_EXTRA_UNSUB "Processed SENDER check removal request for: " + + +/* ezmlm-moderation functions unique */ +#define ERR_MOD_TIMEOUT "I'm sorry, I no longer have this message" +#define ERR_MOD_ACCEPTED "I'm sorry, I've already accepted this message" +#define ERR_MOD_REJECTED "I'm sorry, I've already rejected this message" +#define ERR_MOD_COOKIE "Illegal or outdated moderator request (#5.7.1)" +#define ERR_FORK "unable to fork: " +#define ERR_EXECUTE "unable to execute " +#define ERR_CHILD_CRASHED "child crashed" +#define ERR_CHILD_FATAL "fatal error from child" +#define ERR_CHILD_TEMP "temporary error from child" +#define ERR_CHILD_UNKNOWN "unknown error from child" +#define ERR_UNIQUE "unable to create unique message file name" +#define ERR_NO_POST "I'm sorry, you are not allowed to post messages to this list (#5.7.2)" + +/* ezmlm-make unique */ +#define ERR_VERSION "ezmlmrc version mismatch. Behavior may not match docs." +#define ERR_ENDTAG "tag lacks /> end marker: " +#define ERR_LINKDIR "linktag lacks /dir: " +#define ERR_FILENAME "continuation tag without defined file name: " +#define ERR_PERIOD "periods not allowed in tags: " +#define ERR_SLASH "dir and dot must start with slash" +#define ERR_NEWLINE "newlines not allowed in dir" +#define ERR_QUOTE "quotes not allowed in dir" +#define ERR_SYNTAX " syntax error: " + +/* ezmlm-limit unique */ +#define ERR_EXCESS_MOD "excess traffic: moderating" +#define ERR_EXCESS_DEFER "excess traffic: deferring" + +/* ezmlm-cron unique */ +#define ERR_SAME_HOST "list and digest must be on same host" +#define ERR_DOW "single comma-separated digits only for day-of-week" +#define ERR_NOT_CLEAN "Bad character in address components" +#define ERR_SUID "Sorry, I won't run as root" +#define ERR_UID "user id not found" +#define ERR_EUID "effective user id not found" +#define ERR_BADUSER "user not allowed" +#define ERR_BADHOST "list host not allowed" +#define ERR_BADLOCAL "list local not allowed" +#define ERR_LISTNO "max number of list entries exceeded" +#define ERR_NO_MATCH "no matching entry found" +#define ERR_SETUID "unable to set uid: " +#define ERR_CFHOST "bounce-host required on first line of " +#define ERR_EXCLUSIVE "action-controlling switches are mutually exclusive" +#define ERR_CRONTAB "crontab update failed. Contact you sysadmin with the above error information" + +/* ezmlm-gate */ +#define ERR_REJECT "Sorry, I've been told to reject this message (#5.7.0)" + +/* issub/subscribe ... */ +#define ERR_ADDR_AT "address does not contain @" +#define ERR_ADDR_LONG "address is too long" +#define ERR_ADDR_NL "address contains newline" + +/* sql */ +#define ERR_COOKIE "message does not have valid authentication token" +#define ERR_NOT_ACTIVE "this sublist is not active" +#define ERR_PARSE "unable to parse " +#define ERR_DONE "message already successfully processed by this list" +#define ERR_MAX_BOUNCE "max bounces exceeded: bounce will not be saved" +#define ERR_NO_TABLE "no table specified in database connect data" + +#endif + diff --git a/ezcgi.css b/ezcgi.css new file mode 100644 index 0000000..f4c4f87 --- /dev/null +++ b/ezcgi.css @@ -0,0 +1,24 @@ +BODY { background-color: #ffffe0; margin-left: 5%; margin-right: 5% } + + a:link { color: black } + a:active { color: black } + + H1 { color: red; font-size: 200% ; text-align: center} + H2 { color: green; font-size: 150%; text-align: left } + + HR { border: medium; color: #00426B } + + DIV.idx { margin-left: 5%; margin-right: 5% } + a.alk { color: green; font-style: italic } + + LI.subjbody { margin-left: 15% } + LI.authbody { margin-left: 10% } + + DIV.rfc822hdr { text-align: left; font-size: 100% } + EM.rfc822hdr { font-weight: bold; font-family: arial, sans-serif } + SPAN.subject { font-weight: bold; font-size: 150% } + a.relk { color: red } + +DIV.copyright { font-size: 50%; text-align: right } + + diff --git a/ezcgirc b/ezcgirc new file mode 100644 index 0000000..13e101f --- /dev/null +++ b/ezcgirc @@ -0,0 +1,15 @@ +# listno;[-]UID;DIR;[-]listaddr;button[,button ...];style;banner + +# Default list. "alias" UID=7771. One extra button pointing to my home page ;-) +0;7771;/var/qmail/alias/QMAIL;qmail@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg + +# the real qmail archive. Because of '-' before the list name, the from +# address is not shown, only the associated "handle". More buttons here. +1;7771;/var/qmail/alias/QMAIL;-qmail@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg,[qmail.org]=http://www.qmail.org,[djb]=http://www.pobox.com/~djb/qmail.html + +# This is another alias list. The '-' before the 7771 suppresses the chroot(), +# which is needed since banner program "./niles" uses /bin/sh, cat, etc. The +# style sheet is specified as well. Blank lines are ok, but all chars on config +# lines are significant. +2;-7771;/var/qmail/alias/SAMBA;samba@id.wustl.edu;[Home]=http://id.wustl.edu/~lindberg;iso-8859-1;/ezcgi.css;./niles + diff --git a/ezmlm-accept.1 b/ezmlm-accept.1 new file mode 100644 index 0000000..bbb86f3 --- /dev/null +++ b/ezmlm-accept.1 @@ -0,0 +1,30 @@ +.TH ezmlm-accept 1 +.SH NAME +ezmlm-accept \- accept messages in moderation queue +.SH SYNOPSIS +.B ezmlm-accept +.I dir +.I file +[ +.I file1 ... +] +.SH DESCRIPTION +.B ezmlm-accept +copies +.IR file , +.IR file1 ,\ ... +to +.B ezmlm-send +.IR dir . +.B ezmlm-accept +removes each file that was successfully processed by +.BR ezmlm-send . + +This can be used to manually ``accept'' messages in a +.I ezmlm +moderation queue. +.SH "SEE ALSO" +ezmlm(5), +ezmlm-moderate(1), +ezmlm-send(1), +ezmlm-store(1) diff --git a/ezmlm-accept.sh b/ezmlm-accept.sh new file mode 100644 index 0000000..b723259 --- /dev/null +++ b/ezmlm-accept.sh @@ -0,0 +1,30 @@ +# [should have a bin/sh line and EZPATH added above by make] +# +# script to accept files in DIR/mod/pending. Use as: +# ezmlm-accept DIR file1 [file2 ...] +# where ``DIR'' is the list directory and ``file1'' is a file to be +# accepted. ``ezmlm-accept DIR DIR/mod/pending/*'' will accept all +# pending files. Files that are successfully sent to the list are +# deled. See man page for details. + +EZSEND="${EZPATH}/ezmlm-send" +FATAL='ezmlm-accept: fatal:' +if [ ! -x "$EZSEND" ]; then + echo "$FATAL please edit script to the correct ezmlm-send path" + exit 100; +fi + +DIR="$1" + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "$FATAL usage: ezmlm-accept DIR file1 [file2 ...]" + exit 100; +fi + +while [ -n "$2" ]; do + if [ -x "$2" ]; then + $EZSEND $DIR < "$2" && rm -f "$2" + fi + shift +done +exit 0; diff --git a/ezmlm-archive.1 b/ezmlm-archive.1 new file mode 100644 index 0000000..ca764f8 --- /dev/null +++ b/ezmlm-archive.1 @@ -0,0 +1,178 @@ +.TH ezmlm-archive 1 +.SH NAME +ezmlm-archive \- create thread and author index for a mailing list archive +.SH SYNOPSIS +.B ezmlm-archive +[ +.B \-cCFTvV +][ +.B \-f\fI msg1 +] +][ +.B \-t\fI msg2 +] +.I dir +.SH DESCRIPTION +.B ezmlm-archive +reads the index files from a message archive, and creates a subject index, a +collection of subject files, and a collection of author files. These +files are suitable as an index for WWW access to, and navigation through +a mailing list archive by +.BR ezmlm-cgi(1) . + +The index files read are created by +.B ezmlm-idx(1) +on a per-list basis and by +.B ezmlm-send(1) +on a per-message archive for a indexed list. + +The output files created are: +.TP +.I dir\fB/archive/threads/yyyymm +The thread index. It contains one line per subject, starting with the +number of the first message with that subject within the set +investigated, ``:'', a 20 character +subject hash, blank, ``\[n\]'' where ``n'' is the number of messages in the +thread, blank, and the subject. +The file ``yyyymm'' contains +entries for all threads that have messages in the month ``yyyymm'' +or that have messages both before and after that month. +The subject hash is a key to the subject files; the message number is +a key to the index file. +The lines are in ascending order by message number when the index is +created +.I de novo +on an existing archive. When the messages are added one-by-one as in normal +archive operation, ``n'' is the number of message in the thread +.I for the particular month +and the order is in reverse of latest message, i.e. the last extended thread +is shown last. The message number accompanying a thread is +always a message within the thread. It is the first in +archives created +on existing lists, and the last message in incrementally created archives. +Use the corresponding subject index file to get a list of all +messages in the thread in ascending order. +.TP +.I dir\fB/archive/subjects/xx/yyyyyyyyyyyyyyyyyy +A subject file. The first line is the subject hash, a space, and the subject. +This is followed by one line per message with this subject, in the format +message number, ``:'', date (yyyymm), ``:'', +author hash, blank, author from line. The lines are +sorted by message number. The author hash is a key to the author files; +the message number is a key to the index file. The file in the example +would be for the subject hash ``xxyyyyyyyyyyyyyyyyyy''. +.TP +.I dir\fB/archive/authors/xx/yyyyyyyyyyyyyyyyyy +An author file. The first line is the author hash, a space, and the author +from line. +This is followed by one line per message with this author, in the format +message number, ``:'', date (yyyymm), ``:'', +subject hash, blank, subject. The lines are +sorted by message number. The subject hash is a key to the subject files; +the message number is a key to the index file. The file in the example +would be for the author hash ``xxyyyyyyyyyyyyyyyyyy''. + +.I dir\fB/archnum +keeps track of the last message processed. Normally, +.B ezmlm-archive +will process entries for messages from one above the contents of this file +up to an including the message number in +.IR dir\fB/num . +.SH OPTIONS +.B ezmlm-archive +writes messages in a crash-proof manner when run in normal mode. When overriding +the normal message range with any of the options listed, the normal +.B sync(3) +of the output files is suppressed for efficiency. Should the computer crash +during this time the state of the indices is not defined. Use the +.B \-s +option in the (extremely rare) cases where this would be a problem. +.TP +.B \-c +Create a new index. This overrides +.I dir\fB/archnum +causing +.B ezmlm-archive +to start with the first message in the archive. Synonym for +.BR \-f\fI0 . +.B NOTE: +.B ezmlm-archive +does not remove files in the index. While it will overwrite/update old files +it will not remove files that are obsolete for other reasons. +.TP +.B \-C +(Default.) +Process entries starting with the message after the message listed in +.IR dir\fB/archnum . +.TP +.B \-f\fI msg1 +Process messages from the archive section (set of 100 messages) +containing message +.IR msg1 . +This is useful if you have removed part of the archive, as it will shorten +processing time and decrease memory use. +.B NOTE: +.B ezmlm-archive +does not remove files in the index. While it will overwrite/update old files +it will not remove files that are obsolete for other reasons. The number of +messages per thread will be incorrect when using of the +.B \-f +and +.B \-t +switches leads to partial re-indexing of already indexed messages. +.TP +.B \-F +(Default.) +Do not change the starting message from the default +(see +.BR \-C ). +.TP +.B \-s +Always sync files. +.TP +.B \-S +(Default.) +Sync files, except when on of the message range modifying options is +used. +.TP +.B \-t\fI msg2 +Process messages to message +.I msg2 +instead of the last message in the archive. Again, files written are +corrected, but other files are not explicitly removed. +.TP +.B \-T +(Default.) +Process entries for messages up to the last message in the archive. +.TP +.B \-v +Display +.B ezmlm-archive +version info. +.TP +.B \-V +Display +.B ezmlm-archive +version info. +.SH "MEMORY USAGE" +.B ezmlm-archive +stores its linked lists in memory. On at 32-bit architecture, it uses +12 bytes per message, 28 bytes per thread (plus one copy of the subject), +and 20 bytes per author (plus one copy of the author from line). + +In normal list use, it processes only at most a few messages at a time, +but for initial processing of a large archive, considerable amounts of +memory may be used. Assuming +40 bytes for subject/from line, 5 messages per thread, 100,000 messages, +and 1000 authors, this is 2.5 MB. For 1,000,000 messages this is about 20 MB. + +Thus, for large archives, it may be useful to use the +.I \-t +switch to process the archive in multiple subsets, starting with e.g. the first +100,000, then the next, and so on. +.SH "SEE ALSO" +ezmlm-cgi(1), +ezmlm-idx(1), +ezmlm-send(1), +ezmlm(5) + diff --git a/ezmlm-archive.c b/ezmlm-archive.c new file mode 100644 index 0000000..9026789 --- /dev/null +++ b/ezmlm-archive.c @@ -0,0 +1,479 @@ +/*$Id: ezmlm-archive.c,v 1.13 1999/11/28 20:13:32 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "alloc.h" +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "sig.h" +#include "getconf.h" +#include "strerr.h" +#include "getln.h" +#include "substdio.h" +#include "readwrite.h" +#include "fmt.h" +#include "sgetopt.h" +#include "idxthread.h" +#include "makehash.h" +#include "idx.h" +#include "errtxt.h" + +#define FATAL "ezmlm-archive: fatal: " +#define WARNING "ezmlm-archive: warning: inconsistent index: " + +substdio ssin; +char inbuf[1024]; +substdio ssout; +char outbuf[1024]; +substdio ssnum; +char numbuf[16]; + +stralloc line = {0}; +stralloc num = {0}; +stralloc fn = {0}; +stralloc fnn = {0}; + +char strnum[FMT_ULONG]; +int flagerror = 0; +int flagsync = 1; /* sync() by default, not for -c or -f or -t */ +char *dir; + +struct ca { + char *s; /* start */ + unsigned int l; /* length */ +} ca; + +void die_usage() { + strerr_die1x(100, + "ezmlm-archive: usage: " + "ezmlm-archive [-cCFsSTvV] [-f min_msg] [-t max_msg] dir"); +} + +void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } + +void close_proper(ss,s,sn) +/* flush,sync,close,move sn->s) */ +substdio *ss; +char *s, *sn; +{ + if (substdio_flush(ss) == -1) + strerr_die6sys(111,FATAL,ERR_FLUSH,dir,"/",s,": "); + if (flagsync) + if (fsync(ss->fd) == -1) + strerr_die6sys(111,FATAL,ERR_SYNC,dir,"/",s,": "); + if (close(ss->fd) == -1) + strerr_die6sys(111,FATAL,ERR_CLOSE,dir,"/",s,": "); + if (rename(sn,s) == -1) + strerr_die6sys(111,FATAL,ERR_MOVE,dir,"/",sn,": "); +} + +void write_threads(msgtable,subtable,authtable,datetable,from,to) +/* Add the current threading data to the thread database without dups */ +/* Writes the subject index first, then processes the individual files */ +msgentry *msgtable; subentry *subtable; authentry *authtable; +dateentry *datetable; +unsigned long from,to; +{ + msgentry *pmsgt; + subentry *psubt,*psubtm, *psubtlast; + subentry *presubt = (subentry *)0; + authentry *pautht; + dateentry *pdatet; + char *cp,*cp1; + unsigned long msg; + unsigned long ulmsginthread; + unsigned long subnum; + unsigned long authnum; + unsigned long msgnum; + unsigned int pos,l; + unsigned int startdate,nextdate; + unsigned int startmsg,nextmsg; + int fd = -1; + int fdn = -1; + int match; + int ffound; + int lineno; + int res; + + psubtm = subtable; /* now for new threads */ + pdatet = datetable; + nextmsg = 0L; + nextdate = pdatet->date; + while (psubtm->sub) { /* these are in msgnum order */ + if (!presubt) /* for rewind */ + if (psubtm->lastmsg >= nextmsg) + presubt = psubtm; /* this thread extends beyond current month */ + if (psubtm->firstmsg >= nextmsg) { /* done with this month */ + if (fdn != -1) close_proper(&ssout,fn.s,fnn.s); + psubtlast = psubtm; /* last thread done */ + if (presubt) /* need to rewind? */ + psubtm = presubt; /* do it */ + psubt = psubtm; /* tmp pointer to reset done flag */ + presubt = (subentry *)0; /* reset rewind pointer */ + pdatet++; /* next month */ + startdate = nextdate; /* startdate */ + nextdate = pdatet->date; /* end date */ + startmsg = nextmsg; /* first message in month */ + nextmsg = pdatet->msg; /* first message in next month */ + if (!stralloc_copys(&fn,"archive/threads/")) die_nomem(); + if (!stralloc_catb(&fn,strnum,fmt_uint(strnum,startdate))) die_nomem(); + if (!stralloc_copy(&fnn,&fn)) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + if (!stralloc_cats(&fnn,"n")) die_nomem(); + if (!stralloc_0(&fnn)) die_nomem(); + if ((fdn = open_trunc(fnn.s)) == -1) + strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fnn.s,": "); + substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf)); + if ((fd = open_read(fn.s)) == -1) { + if (errno != error_noent) + strerr_die6sys(111,FATAL,ERR_OPEN,dir,"/",fn.s,": "); + } else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": "); + if (!match) break; + pos = scan_ulong(line.s,&msgnum); + pos++; /* skip ':' */ + if (msgnum >= from) + continue; /* ignore entries from threading range */ + if (line.len < pos + HASHLEN) { + flagerror = -1; /* and bad ones */ + continue; + } + psubt = subtable; + cp = line.s + pos; + ffound = 0; /* search among already known subjects */ + for (;;) { + res = str_diffn(psubt->sub,cp,HASHLEN); + if (res < 0) { + if (psubt->higher) + psubt = psubt->higher; + else + break; + } else if (res > 0) { + if (psubt->lower) + psubt = psubt->lower; + else + break; + } else { + ffound = 1; + break; + } + } + if (!ffound) { + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } else { /* new # of msg in thread */ + cp += HASHLEN; /* HASHLEN [#] Subject always \n at end */ + if (*(cp++) == ' ' && *(cp++) == '[') { + cp += scan_ulong(cp,&ulmsginthread); + if (*cp == ']') { + psubt->msginthread += (unsigned char) (ulmsginthread & 0xff); + } + } else + flagerror = -5; + } + } + close(fd); + } + continue; + } + + if (psubtm->firstmsg < nextmsg && psubtm->lastmsg >= startmsg) { + if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,psubtm->lastmsg))) + die_nomem(); + if (!stralloc_cats(&line,":")) die_nomem(); + if (!stralloc_catb(&line,psubtm->sub,HASHLEN)) die_nomem(); + if (!stralloc_cats(&line," [")) die_nomem(); + if (!stralloc_catb(&line,strnum, + fmt_ulong(strnum,(unsigned long) psubtm->msginthread))) + die_nomem(); + if (!stralloc_cats(&line,"]")) die_nomem(); + if (!stralloc_catb(&line,psubtm->sub + HASHLEN,psubtm->sublen - HASHLEN)) + die_nomem(); /* has \n */ + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + psubtm++; + } + if (fdn != -1) + close_proper(&ssout,fn.s,fnn.s); + + psubt = subtable; + while (psubt->sub) { /* now the threads */ + if (!stralloc_copys(&fn,"archive/subjects/")) die_nomem(); + if (!stralloc_catb(&fn,psubt->sub,2)) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + if (mkdir(fn.s,0755) == -1) + if (errno != error_exist) + strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fn.s,": "); + fn.s[fn.len - 1] = '/'; + if (!stralloc_catb(&fn,psubt->sub+2,HASHLEN-2)) die_nomem(); + if (!stralloc_copy(&fnn,&fn)) die_nomem(); + if (!stralloc_cats(&fnn,"n")) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + if (!stralloc_0(&fnn)) die_nomem(); + if ((fdn = open_trunc(fnn.s)) == -1) + strerr_die4sys(111,FATAL,ERR_CREATE,fnn.s,": "); + substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf)); + if ((fd = open_read(fn.s)) == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": "); + if (substdio_puts(&ssout,psubt->sub) == -1) /* write subject */ + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } else { /* copy data */ + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + lineno = 0; + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": "); + if (!match) break; + if (!lineno) { /* write subject */ + if (line.len < HASHLEN + 1 || line.s[HASHLEN] != ' ') + flagerror = -3; + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + lineno = 1; + continue; + } + (void) scan_ulong(line.s,&msgnum); + if (msgnum >= from) break; + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + (void) close(fd); /* close old index */ + } + + subnum = (unsigned long) (psubt - subtable + 1); /* idx of this subj */ + pmsgt = msgtable + psubt->firstmsg - from; /* first message entry */ + for (msg = psubt->firstmsg; msg <= psubt->lastmsg; msg++) { + if (pmsgt->subnum == subnum) { + if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem(); + if (!stralloc_cats(&line,":")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_uint(strnum,pmsgt->date))) + die_nomem(); + if (!stralloc_cats(&line,":")) die_nomem(); + if (pmsgt->authnum) { + pautht = authtable + pmsgt->authnum - 1; + cp = pautht->auth; + cp1 = cp + str_chr(cp,' '); + if (cp + HASHLEN != cp1) + strerr_die1x(100,ERR_BAD_INDEX); + if (!stralloc_cats(&line,cp)) + die_nomem(); /* hash */ + } else + if (!stralloc_cats(&line,"\n")) die_nomem(); + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + pmsgt++; + } + close_proper(&ssout,fn.s,fnn.s); + psubt++; + } + + /* (no master author index) */ + pautht = authtable; + while (pautht->auth) { /* now the authors */ + if (!stralloc_copys(&fn,"archive/authors/")) die_nomem(); + if (!stralloc_catb(&fn,pautht->auth,2)) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + if (mkdir(fn.s,0755) == -1) + if (errno != error_exist) + strerr_die6sys(111,FATAL,ERR_CREATE,dir,"/",fn.s,": "); + fn.s[fn.len - 1] = '/'; + if (!stralloc_catb(&fn,pautht->auth+2,HASHLEN-2)) die_nomem(); + if (!stralloc_copy(&fnn,&fn)) die_nomem(); + if (!stralloc_cats(&fnn,"n")) die_nomem(); + if (!stralloc_0(&fn)) die_nomem(); + if (!stralloc_0(&fnn)) die_nomem(); + if ((fdn = open_trunc(fnn.s)) == -1) + strerr_die4sys(111,FATAL,ERR_CREATE,fnn.s,": "); + substdio_fdbuf(&ssout,write,fdn,outbuf,sizeof(outbuf)); + if ((fd = open_read(fn.s)) == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,ERR_OPEN,fn.s,": "); + else { /* didn't exist before: write author */ + if (substdio_put(&ssout,pautht->auth,pautht->authlen) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + } else { /* copy data */ + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + lineno = 0; + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die6sys(111,FATAL,ERR_READ,dir,"/",fn.s,": "); + if (!match) break; + if (!lineno) { /* write author */ + if (line.len < HASHLEN + 1 || line.s[HASHLEN] != ' ') + flagerror = - 4; + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + lineno = 1; + continue; + } + (void) scan_ulong(line.s,&msgnum); + if (msgnum >= from) break; + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + (void) close(fd); /* close old index */ + } + + authnum = (unsigned long) (pautht - authtable + 1); /* idx of this auth */ + pmsgt = msgtable + pautht->firstmsg - from; /* first message entry */ + for (msg = pautht->firstmsg; msg <= to; msg++) { + if (pmsgt->authnum == authnum) { + if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem(); + if (!stralloc_cats(&line,":")) die_nomem(); + if (!stralloc_catb(&line,strnum,fmt_uint(strnum,pmsgt->date))) + die_nomem(); + if (!stralloc_cats(&line,":")) die_nomem(); + if (pmsgt->subnum) { + psubt = subtable + pmsgt->subnum - 1; + if (!stralloc_catb(&line,psubt->sub,psubt->sublen)) + die_nomem(); + } + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + } + pmsgt++; + } + close_proper(&ssout,fn.s,fnn.s); + pautht++; + } +} + +int main(argc,argv) +int argc; +char **argv; +{ + unsigned long archnum = 0L; + unsigned long to = 0L; + unsigned long max; + int fd; + int fdlock; + int flagcreate = 0; + int flagsyncall = 0; + int opt; + msgentry *msgtable; + subentry *subtable; + authentry *authtable; + dateentry *datetable; + + (void) umask(022); + sig_pipeignore(); + + while ((opt = getopt(argc,argv,"cCf:FsSt:TvV")) != opteof) + switch (opt) { + case 'c': flagcreate = 1; + flagsync = 0; + break; /* start at beginning of archive */ + case 'C': flagcreate = 0; + break; /* Do only archnum+1 => num */ + case 'f': if (optarg) { + (void) scan_ulong(optarg,&archnum); + archnum = (archnum / 100) * 100; + } + flagsync = 0; + break; + case 'F': archnum = 0; break; + case 's': flagsyncall = 1; break; + case 'S': flagsyncall = 0; break; + case 't': if (optarg) { + (void) scan_ulong(optarg,&to); + } + flagsync = 0; + break; + case 'T': to = 0; break; + case 'v': + case 'V': strerr_die2x(0,"ezmlm-archive version: ",EZIDX_VERSION); + default: + die_usage(); + } + + if (flagsyncall) flagsync = 1; /* overrides */ + dir = argv[optind++]; + if (!dir) die_usage(); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); + + if (mkdir("archive/threads",0755) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/threads: "); + if (mkdir("archive/subjects",0755) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/subjects: "); + if (mkdir("archive/authors",0755) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archive/authors: "); + + /* Lock list to assure that no ezmlm-send is working on it */ + /* and that the "num" message is final */ + fdlock = open_append("lock"); + if (fdlock == -1) + strerr_die2sys(111,FATAL,ERR_OPEN_LOCK); + if (lock_ex(fdlock) == -1) { + (void) close(fdlock); + strerr_die2sys(111,FATAL,ERR_OBTAIN_LOCK); + } + /* get num */ + if (!getconf_line(&num,"num",0,FATAL,dir)) + strerr_die1x(100,ERR_EMPTY_LIST); + (void) close(fdlock); + + if (!stralloc_0(&num)) die_nomem(); /* parse num */ + (void) scan_ulong(num.s,&max); + if (!to || to > max) to = max; + + fdlock = open_append("archive/lock"); /* lock index */ + if (fdlock == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/archive/lock: "); + if (lock_ex(fdlock) == -1) { + (void) close(fdlock); + strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/archive/lock: "); + } + if (!flagcreate && !archnum) { /* adjust archnum (from) / to */ + if (getconf_line(&num,"archnum",0,FATAL,dir)) { + if (!stralloc_0(&num)) die_nomem(); + (void) scan_ulong(num.s,&archnum); + archnum++; + } + } + + if (archnum > to) + _exit(0); /* nothing to do */ + + /* do the subject threading */ + idx_mkthreads(&msgtable,&subtable,&authtable,&datetable, + archnum,to,max,0,FATAL); + /* update the index */ + write_threads(msgtable,subtable,authtable,datetable,archnum,to); + /* update archnum */ + if ((fd = open_trunc("archnumn")) == -1) + strerr_die4sys(111,FATAL,ERR_CREATE,dir,"/archnumn: "); + substdio_fdbuf(&ssnum,write,fd,numbuf,sizeof(numbuf)); + if (substdio_put(&ssnum,strnum,fmt_ulong(strnum,to)) == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + if (substdio_puts(&ssnum,"\n") == -1) + strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnn.s,": "); + close_proper(&ssnum,"archnum","archnumn"); + switch (flagerror) { + case 0: + _exit(0); /* go bye-bye */ + case -1: + strerr_die2x(99,WARNING,"threads entry with illegal format"); + case -2: + strerr_die2x(99,WARNING,"thread in index, but threadfile missing"); + case -3: + strerr_die2x(99,WARNING,"a subject file lacks subject"); + case -4: + strerr_die2x(99,WARNING,"an author file lacks author/hash"); + case -5: + strerr_die2x(99,WARNING,"threads entry lacks message count"); + default: + strerr_die2x(99,WARNING,"something happened that isn't quite right"); + } +} + diff --git a/ezmlm-cgi.1 b/ezmlm-cgi.1 new file mode 100644 index 0000000..6103ed8 --- /dev/null +++ b/ezmlm-cgi.1 @@ -0,0 +1,349 @@ +.TH ezmlm-cgi 1 +.SH NAME +ezmlm-cgi \- provide WWW access to the list archive +.SH SYNOPSIS +.B ezmlm-cgi +.SH DESCRIPTION +.B ezmlm-cgi +is executed by the httpd daemon and generates HTTP/CGI/html 4.0-compliant +self-referencing output of index pages for threads in a given month, +messages in a thread, messages by a given author, messages by date, +and messages themselves with full navigation controls. It uses the +archive directly, aided by index files created by +.BR ezmlm-idx(1) , +and +.B ezmlm-send(1) +as part of normal archive access and digest indexing, and +by +.BR ezmlm-archive(1) . + +.B ezmlm-cgi +uses the httpd-supplied variables +.B PATH_INFO +to obtain the list number, +.B QUERY_STRING +to obtain the command, as well as +.BR SERVER_NAME , +.BR SERVER_PORT , +and +.B SCRIPT_NAME +to create a self-referencing URL. + +When +.B ezmlm-cgi +is invoked without a command, it shows the threads for the +current month. +If no list number is supplied, the default list is shown (see below). +.SH CONFIGURATION +.B ezmlm-cgi +expects to find configuration info in +.B /etc/ezmlm/ezcgirc +when run SUID root, or +.B .ezcgirc +otherwise. The entries in this file describe one list per line. Blank lines +and comments +starting with a ``#'' in position 1 are allowed and ignored. No extra +blanks, tab, etc, are allowed. Entries must be +of the following format: + +.EX +.I listno;uid;listdir;listaddr;buttonbar;charset;style;bannerprog +.EE + +.B where: +.TP 5 +.I listno +is the list number using ``0'' for the default list if desired; +.TP 5 +.I uid +the user id to switch to if installed SUID root (default invoking user id) and +if preceded by ``-'' chroot() is suppressed for SUID root installations; +.TP 5 +.I listdir + the absolute path to the list base directory (required); +.TP 5 +.I listaddr +the list address as local@host (required) and if preceded by ``-'' the +``From:'' E-mail address is replaced by the posters name/handle as a +further precaution against address harvesting; +.TP 5 +.I buttonbar +a set of comma-separated fields of the type +.IR ``[Home]=http://example.com/list.html''. +The text before the ``='' is the exact text displayed and the subsequent +text should be the URL linked to that button. Use the braces to make the +buttons be consistent with preexisting navigation buttons. It is desirable +to add a ``[Help]'' button with a link to an explanation of the various +displays generated by +.BR ezmlm-cgi . +.TP 5 +.I charset +the character set used for the main pages (default ``iso-8859-1''); +.TP 5 +.I style +the style sheet used (default none, which doesn't look pretty); +.TP 5 +.I bannerprog +the path to a banner program which is given +the name of the script and the list as arguments (default none). The path +is relative to ``listdir'' and can point anywhere in the file system. However, +for SUID root installations access is normally restricted via +.BR chroot(3) . +(See SECURITY.) +If +.I ``bannerprog'' +starts with a less-than character (''<'') it is assumed to +be a URL which is inserted as is, rather than executed. +.TP 5 +.I ``;'' +the separator can be any non-numeric character and can be different for +different +.I ezcgirc +lines. There +is no quoting/escaping mechanism. Thus, choose a character not present in +any of the arguments. ``bannerprog'' as the last argument is an exception, +and may contain any characters except LF and NUL. +.SH OPTIONS +.TP 5 +If ``uid'' is preceded by a minus sign (``-''), +.B ezmlm-cgi +will not call +.B chroot(3) . +This potentially decreases security, but may be needed to +execute ``bannerprog''. +.TP 5 +If ``listaddr'' is preceded by a minus sign (``-''), +.B ezmlm-cgi +will, as a precaution against address harvesting robots, +remove the sender's E-mail address also in the message view. This is +already done in all other views. The archive user can still obtain the address +by requesting the message by E-mail. +.SH OUTPUT +.B ezmlm-cgi +outputs 5 different views. +.TP +.I thread index +shows the threads which have messages in a given month. The subject is +prefixed with the number of messages in the thread for the given month. When +.B ezmlm-archive(1) +is first run against an existing archive, the number is the total number of +messages in the thread. The subject and author are links to the respective +thread or author index. The threads are ordered in reverse order of latest +message, i.e. the thread that last received a message is listed last. When +.B ezmlm-archive(1) +is run against an existing archive, the initial sort is in order of the +first message in the thread. + +The subject in the +.I thread index +is a link to the last message in the thread. +.TP +.I thread +shows the messages in the respective thread in date order. For each message +the author is shown linked to the message. +.TP +.I author index +shows the subject of all messages posted from a given address in order of +arrival at the list. Links are to the messages. +.TP +.I message by date +shows entries in order of arrival of sets of 100 messages. Links are to +the message and to the author. +.TP +.I message +shows the message itself. The message has links to the previous and next +message by time, in the thread, or by the same author. There are also links +to the other views, as well as links to subscribe, or request FAQ, +the message or the thread by E-mail. The navigation bar is very concise +to optimize appearance in +.BR lynx . +It is self-explanatory to anyone daring to experiment. For others, you may +wish to supply a ``help'' button. +The message subject is a +.I mailto: +link for a follow-up post to the list. +.SH "OUTPUT FORMATTING" +.B ezmlm-cgi +outputs html 4.0 in a format suitable for +.I Lynx +and other text-mode browsers. The format is designed for easy optional +enhancement +via CSS1/2 type +style sheets in the format ``text/css''. +.B ezmlm-cgi +is self-documenting in this respect. Simply review the output in the different +views and the sample style sheet to see the class structure. +.SH "EXTERNAL LINKS TO MESSAGES" +.B ezmlm-cgi +will accept a PATH_INFO of the following format: + +.EX +.I /listno/message +.EE + +.B where: +.TP 5 +.I listno +is the list number per config file; +.TP 5 +.I message +is the message number. + +Thus, +.B ezmlm-cgi\fI/2/20000 +will return message 20000 from list 2. + +.B ezmlm-cgi +uses a second syntax based on QUERY_STRING for internal links. This +command set is implemented only as far as required for normal +.B ezmlm-cgi +function. Useful are: +.TP +.B ezmlm-cgi\fB?listno?ams:message +which will return in order the list of messages posted by the author of message +.I message +on list +.IR listno , +and +.TP +.B ezmlm-cgi\fB?listno?sms:message +which will return in order the list of messages with the same subject as message +.I message +.I message +on list +.IR listno , +i.e. the ``thread''. +.SH ROBOTS +There are many possible URLs for the same message. +To still allow external indexing, +.B ezmlm-cgi +supports the command +.I ezmlm-cgi/index +which returns a page with links to all lists, except the default list. These +links indirectly lead exactly once to each message. +None of the links used contain +a ``?''. Thus, to index the archives, allow access to scripts in the +(separate) +.I directory +where +.B ezmlm-cgi +is installed, but deny access to +.IR directory\fB/ezmlm-cgi\fI? . +Any message will have a ``nofollow'' robot META tag, and any view reached by +a URL based on QUERY_STRING will in addition have a ``noindex'' robot META tag +to avoid trapping robots in the archive. +.SH EXECUTION +.B ezmlm-cgi +can operate in three modes, +.IR SUID\ root , +.IR SUID\ user , +and +.IR normal . + +In +.I normal +and +.I SUID user +mode, +.B ezmlm-cgi +will read the configuration file +.B .ezcgirc +from the working directory set by the httpd daemon +(per +.B cgi +definition this should be the same directory as +.B ezmlm-cgi +is in), then +change directory to the list directory. ``uid'' is ignored. +.I SUID user +may be required to read the particular archive if it is not owned by the +httpd user. For user installations or systems where +the httpd user has access to all the lists, +.I normal +mode usually gives sufficient access. + +In +.I SUID\ root +mode, +.B ezmlm-cgi +will read the configuration info from +.B /etc/ezmlm/ezcgirc +then change directory to that directory, then +change root to that directory, then change +userid to ``uid''. If ``uid'' is not specified, it will change to the +uid of the process invoking +.B ezmlm-cgi +(normally the httpd user). If the archive files are world-readable, but the list +directory is not, it is safest to leave ``uid'' blank. The httpd user will still +be able to read the files. +.SH "EXECUTION OF BANNER PROGRAMS" +A banner program can be specified in the config file. It is executed +immediately before the end of the text. The formatting for +``'' is active and the banner program output is encapsulated in +a ``\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("\n"); + oputs("\n"); + if (local) { + oputs(local); + oputs("@"); + oputs(host); + oputs(": "); + } + if (t) oputs(t); + if (s) htmlencode_put(s,l); + oputs("\n"); + if (class && *class && stylesheet && *stylesheet) { + oputs("\n"); + } + if (!flagrobot) /* robot access allowed to follow */ + oputs("\n"); + if (flagrobot < 2) + oputs("\n"); + if (flagspecial & SPC_BASE) + oput(base.s,base.len); + oputs("\n"); + if (class && *class) { + oputs("\n"); + } else + oputs("\n"); + +} + +void html_footer(int flagspecial) +{ + oputs("
"); + if ((flagspecial & SPC_BANNER) && banner && *banner) { + oputs("\n"); + } + oputs("\n\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(""); +} + +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("\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("

"); + oputs("Messages "); + oput(line.s,line.len); + oputs("

\n"); + oputs("
\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(")
\n"); + } + } + } + close(fd); + oputs("\n

\n"); + indexlinks(infop); + html_footer(SPC_BANNER); + return 1; +} + +void objectlinks(struct msginfo *infop, char item) +{ + oputs("\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("

On: "); + oput(line.s+HASHLEN+1,line.len-HASHLEN-2); + oputs("

\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("

By: "); + oput(line.s+HASHLEN+1,line.len-HASHLEN-2); + oputs("

\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("

Threads for "); + oput(dtline.s,dtline.len); + oputs("

\n"); + break; + default: die_prog("unrecognized object type in show_object"); + } + + oputs("
\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("
    \n"); + else + oputs("

    "); + oputs("

  • "); + datelink(infop,thisdate,DIRECT_SAME); + lastdate = thisdate; + oputs("

    \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("
    \n"); + } + close(fd); + oputs("
\n"); + if (!infop->target) + oputs(""); + oputs("
\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. */ +/*
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("
\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(""); + 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("

\n"); + for (i = 0; i < NO_HDRS; i++) { + if (!hdr[i].len || !headers_shown[i]) continue; + if (i == HDR_SUBJECT - 1 && flagtoplevel) + oputs(""); + oputs(""); + oputs(constmap_get(&headermap,i + 1)); + oputs(":"); + decodeHDR(hdr[i].s,hdr[i].len,&line,"",FATAL); + if (i == HDR_SUBJECT - 1 && flagtoplevel) { + 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(""); + oputs("\n
"); + } + oputs("
\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
");
+		toggle_flagpre(1);
+		flagshowheaders = 1;
+		flaginheader = 1;
+		flagmime = 0;		/* need new MIME-Version header */
+		continue;
+	  case MIME_TEXT_HTML:
+		if (flagshowhtml) {
+		  oputs("
\n"); + flaghtml = 1; + } else { + oputs("[\""); + oput(mime_current->ctype.s,mime_current->ctype.len); + oputs("\" not shown]\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("
\n
\n");
+		toggle_flagpre(1);
+		continue;
+	  case MIME_TEXT_VCARD:
+	  default:		/* application/octetstream...*/
+		oputs("
[\""); + oput(mime_current->ctype.s,mime_current->ctype.len); + oputs("\" not shown]\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("
\n"); + close(fd); + oputs("
\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("[link]\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("d_name); + oputs("\">[link]\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," 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]\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,"\n")) die_nomem(); + if (!stralloc_copys(&url," tmptarget) { + cache = 2; /* won't change */ + firstdate(&msginfo,1); /* first thread index */ + msginfo.direction = DIRECT_FIRST; + date2msg(&msginfo); /* (may not be 1 if parts removed) */ + } + ret = show_index(&msginfo); + } + break; + default: + strerr_die2x(100,FATAL,"bad item in main"); + } + if (!ret) { + findlastmsg(&msginfo); /* as last resort; last msgindex */ + cache = 0; + ret = show_message(&msginfo); + } + + _exit(0); +} diff --git a/ezmlm-check.1 b/ezmlm-check.1 new file mode 100644 index 0000000..e2e07d7 --- /dev/null +++ b/ezmlm-check.1 @@ -0,0 +1,52 @@ +.TH ezmlm-check 1 +.SH NAME +ezmlm-check \- Mails back results of ezmlm list check +.SH SYNOPSIS +.B ezmlm-check +[ +.B \-sS +] +.I [dir] +.SH DESCRIPTION +.B ezmlm-check +mails useful environment variables to SENDER via +.BR qmail-inject . +It is usually invoked for debugging purposes in a +.I .qmail +file to determine the value of relevant environment variables. +If +.I dir +is specified, +.B ezmlm-check +attempts to evaluate the +.I ezmlm +mailing list set up in +.I dir +and return information about the setup as well as possible +errors. + +.B ezmlm-check +will flag errors with +.BR ``???\ ERROR'' , +likely errors with +.BR ``???'' , +and potential errors/problems with +.BR ``!!!'' . + +If +.B ezmlm-check +is invoked from the shell, it will print to stdout. +In this case, diagnostics are more limited, +since important environment variables +normally supplied by qmail are not available. +.SH OPTIONS +.TP 5 +.B \-s +(Default.) List subscribers. +.TP 5 +.B \-S +Do not list subscribers. +.SH "SEE ALSO" +ezmlm(5), +qmail(7), +qmail-inject(8) diff --git a/ezmlm-check.sh b/ezmlm-check.sh new file mode 100644 index 0000000..b844d1b --- /dev/null +++ b/ezmlm-check.sh @@ -0,0 +1,670 @@ + +# [should have a bin/sh line and EZPATH/QMPATH added above by make] +# +# script to diagnose ezmlm lists +# call as is for environment only, or as ezmlm-check 'DIR' for more info + +listsubscribers=yes +if [ "$1" = '-S' ] ; then + listsubscribers=no + shift +else + if [ "$1" = '-s' ] ; then + shift + fi +fi + +QINJECT="${QMPATH}/bin/qmail-inject" +EZLIST="${EZPATH}/ezmlm-list" +MYNAME='ezmlm-check' +MYDTLINE="Delivered-To: ${MYNAME}" +FATAL="${MYNAME}: fatal:" +EZERR="??? ERROR:" +EZWARN="!!! Warning:" +# This should be a ``grep'' that does regexps. Needs to recognize ^ and $. +GREP='grep' +CAT='cat' +CUT='cut' +ECHO='echo' +# Needed to isolate some lines in the DIR/editor ... files +HEAD='head' +TAIL='tail' +# needed to count characters in $USER +WC='wc' +# should mark executables with '*' and list one file per line +LS='ls -F1' +# should list links as: "... symlink -> file" +LLS='ls -l' +if [ ! -x "$QINJECT" ]; then + ${ECHO} "$FATAL edit script to for path to qmail-inject" + exit 100 +fi + +if [ -z "$SENDER" ] ; then + RCP="${CAT}" +else + RCP="$QINJECT" + if ${CAT} - | ${GREP} "${MYDTLINE}" >/dev/null 2>&1 + then + ${ECHO} "FATAL this message is looping: it already has my Delivered-To line (#5.4.6)" + exit 100 + fi +fi + +if [ ! -z "$1" -a ! -d "$1" ]; then + ${ECHO} "$FATAL $1 is not a directory"; exit 100 +fi + +# reset variables +GET=''; DIGEST=''; FLAGARCH=''; FLAGIND=''; INLOCAL=''; INLOCALOK=''; INHOST='' +MANAGE=''; OUTLOCAL=''; OUTHOST=''; SPEC=''; SRESTRICT=''; STORE=''; REMOTE='' +MODSUB=''; MODPOST=''; SPEC='' + +( + ${ECHO} "Delivered-To: ezmlm-check" + ${ECHO} "To: $SENDER" + ${ECHO} "Subject: ${MYNAME} results" + ${ECHO} + ${ECHO} "Important environment variables:" + ${ECHO} + ${ECHO} "SENDER ='$SENDER'" + ${ECHO} "NEWSENDER ='$NEWSENDER'" + ${ECHO} "RECIPIENT ='$RECIPIENT'" + ${ECHO} "USER ='$USER'" + ${ECHO} "DEFAULT ='$DEFAULT'" + ${ECHO} "LOCAL ='$LOCAL'" + ${ECHO} "HOST ='$HOST'" + ${ECHO} "---------------------------------------------------" + if [ ! -z "$1" ]; then + ${ECHO} "Checking basic list setup:" + ${ECHO} + if [ ! -r "$1/mailinglist" ]; then + ${ECHO} "$EZERR $1/mailinglist does not exist" + fi + if [ -e "$1/num" ]; then + if [ ! -w "$1/num" ]; then + ${ECHO} "$EZERR $1/num is not writable to $USER" + else + NUM=`${CAT} "$1/num" | ${HEAD} -1` + ${ECHO} "... latest message was message # $NUM" + fi + else + ${ECHO} "... no num. This must be a new list ..." + fi + ${ECHO} + if [ -e "$1/lock" -a ! -w "$1/lock" ]; then + ${ECHO} "$EZERR User $USER does not have write premission to $1/lock" + fi + if [ -e "$1/lockbounce" -a ! -w "$1/lockbounce" ]; then + ${ECHO} "$EZERR User $USER does not have write premission to $1/lockbounce" + fi + if [ ! -r "$1/inlocal" ]; then + ${ECHO} "$EZERR $1/inlocal does not exist" + elif [ ! -r "$1/inhost" ]; then + ${ECHO} "$EZERR $1/inhost does not exist" + else + INLOCAL=`${CAT} "$1/inlocal"| ${HEAD} -1` + INHOST=`${CAT} "$1/inhost"| ${HEAD} -1` + if [ -z "$HOST" ]; then + ${ECHO} "$EZERR HOST is empty. Likely running from the command" + ${ECHO} " line. Run from $1/editor to check if HOST matches" + ${ECHO} " $1/inhost and LOCAL matches $1/inlocal." + ${ECHO} " Mismatches here are the most common setup error." + ${ECHO} + else + if [ "$HOST" != "$INHOST" ]; then + ${ECHO} "$EZERR HOST does not match $1/inhost" + else + ${ECHO} "... $1/inhost OK" + fi + if ${ECHO} "$LOCAL" | ${GREP} -G "^$INLOCAL" >/dev/null 2>&1 + then + ${ECHO} "... $1/inlocal OK" + else + ${ECHO} \ + "$EZERR LOCAL does not begin with contents of $1/inlocal" + fi + fi + fi + if [ ! -r "$1/outlocal" ]; then + ${ECHO} "$EZERR $1/outlocal does not exist" + else + OUTLOCAL=`${CAT} "$1/outlocal"| ${HEAD} -1` + fi + if [ ! -r "$1/outhost" ]; then + ${ECHO} "$EZERR $1/outhost does not exist" + else + OUTHOST=`${CAT} "$1/outhost"| ${HEAD} -1` + fi + ${ECHO} "... The list is named ${OUTLOCAL}@${OUTHOST}" + if [ "$OUTHOST" != "$INHOST" ]; then + HOSTMATCH='1'; + ${ECHO} + ${ECHO} "??? $1/inhost and $1/outhost do not" + ${ECHO} " match. This is very unusual ..." + fi + if ${ECHO} "$INLOCAL" | ${GREP} "^${USER}" >/dev/null ; then + USERSTART='1'; INLOCALOK='1' + fi + if [ -z "$USERSTART" ]; then + ${ECHO} + ${ECHO} "??? $1/inlocal does not start with the user name." + ${ECHO} " This is an error, unless $INLOCAL starts with" + ${ECHO} " an alias of \"$USER\"." + fi + if [ "$INLOCAL" = "$OUTLOCAL" ]; then + ${ECHO} "... $1/inlocal matches $1/outlocal" + ${ECHO} " suggesting that this is a regular user-owned list." + CHARS=`${ECHO} " $USER" | ${WC} -c` + LIST=`${ECHO} "$OUTLOCAL" | cut -c$CHARS-` + else + if ${ECHO} "$INLOCAL" | ${GREP} "$OUTLOCAL$" >/dev/null ; then + if [ ! -z "$USERSTART" ]; then + ${ECHO} "... It appears that $OUTHOST is a virtual domain" + ${ECHO} " controlled by $USER." + LIST="$OUTLOCAL" + if [ ! -z "$HOSTMATCH" ]; then + ${ECHO} " This part of the setup appears correct." + fi + else + ${ECHO} + ${ECHO} "$EZWARN $1/inlocal ends with the contents" + ${ECHO} " of $1/outlocal, but does not start with" + ${ECHO} " $USER. If this message persists when you" + ${ECHO} " run this program from $1/editor," + ${ECHO} " there is a setup error." + fi + else + ${ECHO} + ${ECHO} "$EZWARN $1/inlocal does not end with the contents" + ${ECHO} " of $1/outlocal. This is almost always wrong." + fi + fi + if [ ! -r "$1/editor" ]; then + ${ECHO} "$EZERR $1/editor does not exist" + else + ${ECHO} + ${ECHO} "$1/editor:" + ${ECHO} "============================" + ${CAT} "$1/editor" + ${ECHO} "============================" + ${ECHO} + fi + if [ ! -r "$1/manager" ]; then + ${ECHO} "$EZERR $1/manager does not exist" + else + ${ECHO} "$1/manager:" + ${ECHO} "============================" + ${CAT} "$1/manager" + ${ECHO} "============================" + ${ECHO} + fi + if [ ! -r "$1/bouncer" ]; then + ${ECHO} "$EZERR $1/bouncer does not exist" + else + ${ECHO} "$1/bouncer:" + ${ECHO} "============================" + ${CAT} "$1/bouncer" + ${ECHO} "============================" + ${ECHO} + fi + if [ ! -r "$1/owner" ]; then + ${ECHO} "$EZERR $1/owner does not exist" + else + ${ECHO} "$1/owner:" + ${ECHO} "============================" + ${CAT} "$1/owner" + ${ECHO} "============================" + ${ECHO} + OWNER=`${GREP} "@" < $1/owner` + fi + if [ ! -r "$1/headeradd" ]; then + ${ECHO} "$EZERR $1/headeradd does not exist" + else + ${ECHO} "$1/headeradd:" + ${ECHO} "============================" + ${CAT} "$1/headeradd" + ${ECHO} "============================" + ${ECHO} + fi + if [ ! -r "$1/headerremove" ]; then + ${ECHO} "$EZERR $1/headerremove does not exist" + else + ${ECHO} "$1/headerremove:" + ${ECHO} "============================" + ${CAT} "$1/headerremove" + ${ECHO} "============================" + ${ECHO} + fi + ${ECHO} "---------------------------------------------------" + ${ECHO} "Checking standard options:" + ${ECHO} + if [ -r "$1/public" ]; then + ${ECHO} "... public" + else + ${ECHO} "... not public" + fi + if [ -r "$1/archived" ]; then + FLAGARCH='1' + ${ECHO} "... archived" + else + ${ECHO} "... not archived" + fi + if [ -r "$1/indexed" ]; then + FLAGARCH='1' + FLAGIND='1' + ${ECHO} "... indexed" + else + ${ECHO} "... not indexed" + fi + if [ ! -z "$FLAGARCH" ]; then + if [ ! -d "$1/archive" ]; then + ${ECHO} "$EZERR $1/archive is not a directory" + else + if [ ! -z "$NUM" -a ! -r "$1/archive/0/index" \ + -a ! -z "$FLAGIND" ]; then + ${ECHO} "$EZWARN list is archived, but there is no index." + ${ECHO} " Please run ezmlm-idx!" + fi + fi + fi + if [ ! -d "$1/bounce" ]; then + ${ECHO} "$EZERR $1/bounce is not a directory" + fi + if [ -r "$1/prefix" ]; then + PREFIX=`${HEAD} -1 "$1/prefix"` + ${ECHO} "... using $1/prefix as subject prefix: $PREFIX" + ${ECHO} + fi + if [ -r "$1/sublist" ]; then + ${ECHO} "... this is a sublist for:" + ${HEAD} -1 < "$1/sublist" + else + ${ECHO} "... not a sublist" + fi + if [ ! -d "$1/text" ]; then + ${ECHO} "$EZERR $1/text is not a directory" + fi + ${ECHO} "... Contents of $1/text not checked" + ${ECHO} + if [ ! -z "$OWNER" ]; then + ${ECHO} "... Mail to owner goes to: $OWNER" + else + ${ECHO} "$EZWARN Mail to owner seems not to be forwarded." + ${ECHO} " Remember to check the mailbox once in a while!" + fi + ${ECHO} + ${ECHO} "--------------------------------------------------" + ${ECHO} + ${ECHO} "... Links should be:" + ${ECHO} " ~/.qmail-{list} -> $1/editor" + ${ECHO} " ~/.qmail-{list}-default -> $1/manager" + ${ECHO} " ~/.qmail-{list}-owner -> $1/owner" + ${ECHO} " ~/.qmail-{list}-return-default -> $1/bouncer" + if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then + ${ECHO} + ${ECHO} " As far as I can see, '{list}' should be '$LIST'." + ${ECHO} " If so and if .qmail files should be in $HOME ..." + BN="$HOME/.qmail-$LIST" + FN="$BN" + if ${LLS} "$FN" 2>/dev/null | ${GREP} "$1/editor$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + FN="$BN-default" + if ${LLS} "$FN" | ${GREP} "$1/manager$" >/dev/null ; then + ${ECHO} " $FN OK" + else + ${ECHO} "??? $FN is BAD" + fi + FN="$BN-owner" + if ${LLS} "$FN" | ${GREP} "$1/owner$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + FN="$BN-return-default" + if ${LLS} "$FN" | ${GREP} "$1/bouncer$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + fi + ${ECHO} "--------------------------------------------------" + ${ECHO} "Checking subscribers:" + ${ECHO} + if [ ! -d "$1/subscribers" ]; then + ${ECHO} "$EZERR $1/subscribers is not a directory" + else + if [ ! -x "$EZLIST" ]; then + ${ECHO} "$EZLIST is not available for listing" + else + if [ "$listsubscribers" = "yes" ] ; then + ${ECHO} "... Subscribers are:" + if ${EZLIST} "$1" | ${GREP} '@' ; then + : + else + ${ECHO} "$EZWARN no subscribers!" + fi + else + if ${EZLIST} "$1" | ${GREP} '@' >/dev/null 2>&1 ; then + ${ECHO} "... There are subscribers." + else + ${ECHO} "$EZWARN no subscribers!" + fi + fi + fi + fi + ${ECHO} + ${ECHO} "--------------------------------------------------" + ${ECHO} "Checking for digest:" + ${ECHO} + if ${GREP} 'ezmlm-tstdig' < $1/editor >/dev/null 2>&1 ; then + if ${GREP} -1 'ezmlm-tstdig' < $1/editor \ + | ${TAIL} -1 | ${GREP} 'ezmlm-get' >/dev/null; then + ${ECHO} "... integrated digest via $1/editor" + DIGEST='1' + ${ECHO} + fi + fi + if [ -z "$DIGEST" ]; then + ${ECHO} "... no digest via $1/editor" + else + ${ECHO} "... links should be:" + ${ECHO} " ~/.qmail-{list}-digest-return-default -> $1/bouncer" + ${ECHO} " ~/.qmail-{list}-digest-owner -> $1/owner" + if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then + ${ECHO} + ${ECHO} " As far as I can see, '{list}' should be '$LIST'." + ${ECHO} " If so and if .qmail files should be in $HOME ..." + BN="$HOME/.qmail-$LIST" + FN="$BN-digest-return-default" + if ${LLS} "$FN" 2>/dev/null | \ + ${GREP} "$1/bouncer$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + FN="$BN-digest-owner" + if ${LLS} "$FN" 2>/dev/null | \ + ${GREP} "$1/owner$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + fi + fi + if [ -d "$1/digest" ]; then + if [ ! -d "$1/digest/subscribers" ]; then + ${ECHO} "$EZERR $1/digest exists, but $1/digest/subscribers" + ${ECHO} "$EZERR is not a directory" + ${ECHO} + else + if [ ! -x "$EZLIST" ]; then + ${ECHO} "$EZLIST is not available for listing" + else + if [ "$listsubscribers" = "yes" ] ; then + ${ECHO} + ${ECHO} "... Digest subscribers are:" + if ${EZLIST} "$1" | ${GREP} '@' ; then + : + else + ${ECHO} "$EZWARN no subscribers!" + fi + else + if ${EZLIST} "$1" | ${GREP} '@' >/dev/null 2>&1 ; then + ${ECHO} "... There are digest subscribers." + else + ${ECHO} "$EZWARN no subscribers!" + fi + fi + fi + ${ECHO} + fi + fi + ${ECHO} "---------------------------------------------------" + ${ECHO} "Checking for subscription moderation/remote admin:" + ${ECHO} + if [ -r "$1/remote" ]; then + FLAGMOD='1' + ${ECHO} "... set up for remote administration" + REMOTE=`${CAT} "$1/remote"| ${HEAD} -1` + if ${ECHO} "$REMOTE" | ${GREP} -G "^/" >/dev/null 2>&1 + then + MODDIR="$REMOTE" + else + MODDIR="$1/mod" + fi + REMOTE='1' + else + ${ECHO} "... no remote admin" + fi + if [ -r "$1/modsub" ]; then + FLAGMOD='1' + ${ECHO} "... subscription moderated" + MODSUB=`${CAT} "$1/modsub"| ${HEAD} -1` + if ${ECHO} "$MODSUB" | ${GREP} -G "^/" >/dev/null 2>&1 + then + MODDIR="$MODSUB" + elif [ -z "$MODDIR" ]; then + MODDIR="$1/mod" + fi + else + ${ECHO} "... no subscription moderation" + fi + if [ "$FLAGMOD" = '1' ]; then + ${ECHO} + ${ECHO} "Mods/remote admins stored based in $MODDIR:" + ${ECHO} + if [ ! -d "$MODDIR" ]; then + ${ECHO} "$EZERR moderator dir $MODDIR doesn't exist!" + elif [ -e "$MODDIR/lock" -a ! -w "$MODDIR/lock" ]; then + ${ECHO} "$EZERR $MODDIR/lock is not writable to user $USER" + elif [ ! -x "$EZLIST" ]; then + ${ECHO} "${EZLIST} not available for listing" + else + if ${EZLIST} "$MODDIR" | ${GREP} '@' ; then + : + else + ${ECHO} "$EZERR no subscription moderators/remote admins!" + fi + fi + ${ECHO} + fi + ${ECHO} "---------------------------------------------------" + ${ECHO} "Checking for message moderation:" + ${ECHO} + if ${GREP} 'ezmlm-gate' < "$1/editor" > /dev/null 2>&1; then + GATE='1' + fi + if ${GREP} 'ezmlm-store' < "$1/editor" > /dev/null 2>&1; then + STORE='1' + fi + FLAGMOD='' + if [ -r "$1/modpost" ]; then + FLAGMOD='1' + MODPOST=`${CAT} "$1/modpost" | ${HEAD} -1` + if ${ECHO} "$MODPOST" | ${GREP} -G "^/" >/dev/null 2>&1 + then + MODDIR="$MODPOST" + else + MODDIR="$1/mod" + fi + fi + if [ "$STORE" = '1' -a -z "$FLAGMOD" ]; then + ${ECHO} "??? it looks from $1/editor like the list is set up" + ${ECHO} " for message moderation. However, since $1/modpost" + ${ECHO} " doesn't exist, ezmlm-store posts them directly. If" + ${ECHO} " this is not intended, please create $1/modpost." + ${ECHO} + FLAGMOD='1' + MODDIR="$1/mod" + elif [ -z "$STORE" -a -z "$GATE" -a "$FLAGMOD" = '1' ]; then + ${ECHO} "??? $1/modpost exists, leading me to think you'd like" + ${ECHO} " message moderation, but I can't find any call to" + ${ECHO} " ezmlm-store in $1/editor." + ${ECHO} + elif [ -z "$STORE" -a "$GATE" = '1' ]; then + if [ -z "$FLAGMOD" ]; then + ${ECHO} "??? The list is set up with ezmlm-gate in $1/editor." + ${ECHO} " However, since $1/modpost does not exist all" + ${ECHO} " messages will be accepted!" + FLAGMOD='1' + MODDIR="$1/mod" + else + ${ECHO} "... The list is set up with ezmlm-gate in $1/editor." + ${ECHO} " Since $1/modpost exists, subscriber messages" + ${ECHO} " will be accepted and others will be send for" + ${ECHO} " moderation." + fi + fi + if [ "$FLAGMOD" = '1' ]; then + ${ECHO} "... message moderated" + ${ECHO} + ${ECHO} "Message moderators based in $MODDIR:" + ${ECHO} + if [ ! -d "$MODDIR" ]; then + ${ECHO} "$EZERR moderator dir $MODDIR doesn't exist!" + elif [ -e "$MODDIR/lock" -a ! -w "$MODDIR/lock" ]; then + ${ECHO} "$EZERR $MODDIR/lock is not writable to user $USER" + elif [ ! -x "$EZLIST" ]; then + ${ECHO} "${EZLIST} not available for listing" + else + if ${EZLIST} "$MODDIR" | ${GREP} '@' ; then + : + else + ${ECHO} "$EZERR no message moderators!" + fi + fi + ${ECHO} + MT="120" + if [ -r "$1/modtime" ]; then + MODTIME=`${CAT} "$1/modtime" | ${HEAD} -1` + if [ "$MODTIME" -eq 0 ]; then + MT="120" + elif [ "$MODTIME" -lt 24 ]; then + MT="24" + elif [ "$MODTIME" -gt 240 ]; then + MT="240" + else + MT="${MODTIME}" + fi + fi + ${ECHO} "... Messages awaiting moderation time out after $MT hours" + if [ ! -d "$1/mod/pending" ]; then + ${ECHO} "$EZERR $MODDIR/pending is not a directory" + else + MODNUM=`${LS} "$1/mod/pending" | ${GREP} -c '*'` + ${ECHO} "... there are $MODNUM messages awaiting moderator action" + fi + if [ ! -d "$1/mod/accepted" ]; then + ${ECHO} "$EZERR $MODDIR/accepted is not a directory" + fi + if [ ! -d "$1/mod/rejected" ]; then + ${ECHO} "$EZERR $MODDIR/rejected is not a directory" + fi + if [ ! -r "$1/moderator" ]; then + ${ECHO} "$EZERR $1/moderator is not readable to user $USER" + else + if ${GREP} 'ezmlm-moderate' < "$1/moderator" >/dev/null 2>&1 + then + : + else + ${ECHO} "$EZERR $1/moderator lacks ezmlm-moderate entry" + fi + ${ECHO} + ${ECHO} "$1/moderator:" + ${ECHO} "============================" + ${CAT} "$1/moderator" + ${ECHO} "============================" + ${ECHO} + fi + ${ECHO} + ${ECHO} "... Links should be:" + ${ECHO} " ~/.qmail-{list}-accept-default -> $1/moderator" + ${ECHO} " ~/.qmail-{list}-reject-default -> $1/moderator" + ${ECHO} + if [ ! -z "$LIST" -a ! -z "$INLOCALOK" ]; then + ${ECHO} + ${ECHO} " As far as I can see, '{list}' should be '$LIST'." + ${ECHO} " If so and if .qmail files should be in $HOME ..." + BN="$HOME/.qmail-$LIST" + FN="$BN-accept-default" + if ${LLS} "$FN" 2>/dev/null | \ + ${GREP} "$1/moderator$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + FN="$BN-reject-default" + if ${LLS} "$FN" 2>/dev/null | \ + ${GREP} "$1/moderator$" >/dev/null ; then + ${ECHO} " $FN is OK" + else + ${ECHO} "??? $FN is BAD" + fi + fi + else + ${ECHO} "... no message moderation" + fi + ${ECHO} + ${ECHO} "---------------------------------------------------" + ${ECHO} "Checking for SENDER checks:" + ${ECHO} + if ${GREP} 'ezmlm-issubn -n' < "$1/editor" >/dev/null 2>&1 ; then + ${ECHO} "... Some type of blacklisting in use" + SRESTRICT='1' + fi + if ${GREP} 'ezmlm-issubn' < "$1/editor" |\ + ${GREP} -v -- '-n' >/dev/null 2>&1 ; then + ${ECHO} "... Some type of SENDER check in use for posts" + SRESTRICT='1' + fi + if [ -z "$SRESTRICT" ]; then + ${ECHO} "... no SENDER restrictions found for posts" + fi + ${ECHO} + GET=` ${GREP} 'ezmlm-get' < "$1/manager" | \ + ${CUT} -d' ' -f2- | ${CUT} -d\' -f1` + if ${ECHO} "$GET" | ${GREP} 's' >/dev/null ; then + ${ECHO} "... Only subscribers may access the archive" + else + ${ECHO} "... no SENDER restrictions for archive access" + fi + ${ECHO} + ${ECHO} "---------------------------------------------------" + ${ECHO} "Checking for special options:" + ${ECHO} + MANAGE=` ${GREP} 'ezmlm-manage' < "$1/manager" | \ + ${CUT} -d' ' -f2- | ${CUT} -d\' -f1` + if ${ECHO} "$MANAGE" | ${GREP} 'e' >/dev/null ; then + ${ECHO} "... remote editing of $1/text/ files enabled" + SPEC='1' + fi + if ${ECHO} "$MANAGE" | ${GREP} 'l' >/dev/null ; then + ${ECHO} "... remote listing of subscribers enabled" + SPEC='1' + fi + if [ "$SPEC" = '1' -a -z "$REMOTE" ] ; then + ${ECHO} \ + "$EZERR but remote admin is not enabled, so this will not work!" + fi + ${ECHO} "---------------------------------------------------" + fi + ${ECHO} + ${ECHO} "EXT ='$EXT'" + ${ECHO} "EXT1 ='$EXT1'" + ${ECHO} "EXT2 ='$EXT2'" + ${ECHO} "EXT3 ='$EXT3'" + ${ECHO} "EXT4 ='$EXT4'" + ${ECHO} "DTLINE = $DTLINE" + ${ECHO} "RPLINE = $RPLINE" + ${ECHO} "UFLINE = $UFLINE" + ${ECHO} "---------------------------------------------------" + ${ECHO} + ${ECHO} "Hope that helps!" +) | "$RCP" || exit 100 + +exit 99 + diff --git a/ezmlm-clean.1 b/ezmlm-clean.1 new file mode 100644 index 0000000..652507e --- /dev/null +++ b/ezmlm-clean.1 @@ -0,0 +1,117 @@ +.TH ezmlm-clean 1 +.SH NAME +ezmlm-clean \- clean moderation directory +.SH SYNOPSIS +.B ezmlm-clean [mMrRvV] +.I dir +.SH DESCRIPTION +If +.I dir\fB/modpost +exists, +.B ezmlm-clean +sends out messages for timed-out posts in the moderation directory +and removes stubs for rejected and accepted posts +for the mailing list stored in +.IR dir . +If +.I dir\fB/modpost +does not exist, +.B ezmlm-clean +does nothing and exits. + +.B ezmlm-clean +reads +.I dir\fB/modtime +and extracts a time-out ``time'' in hours from it. If ``time'' is 0 or +.I dir\fB/modtime +is empty or doesn't exist, +a default of 120 h is used. If a time is given, it is limited to +the range 24 h to 240 h. + +.B ezmlm-clean +then looks through +.I dir\fB/mod/accepted/ +and +.I dir\fB/mod/rejected/ +and removes message stubs older than ``time''. ``Time'' is +a minimum retention time. Since the files are processed only +when +.B ezmlm-clean +is run, the delay before a message is timed-out may +be substantially longer if the list does not receive many messages. + +Message age +determined by the time parsed +.I from the file name, +not from the creation time. +Thus, there is no good way to extend the life of +the file by e.g. touching it. Also, files in these directories are not +checked for the proper format. Thus, most non-message files in these +directories will be deleted the first time +.B ezmlm-clean +is run. + +For messages in +.I dir\fB/mod/pending/ +no action is taken on read-only files. Messages without the owner execute +bit set are silently removed, as they are the result of incomplete +.B ezmlm-store(1) +executions. For other messages, a notification of the time out is sent +to the sender, before the file is removed. + +.B ezmlm-clean +logs errors to the mail log. +Re-delivery should be avoided by suffixing any +.I \.qmail +line invoking +.B ezmlm-clean +with '|| exit 0'. +.SH OPTIONS +.TP +.B \-m +(Default.) +The timed-out post is sent as a MIME enclosure. +.TP +.B \-M +The timed-out post is appended to the message. +.TP +.B \-r +(Default.) +The timed-out post is returned to sender. +.TP +.B \-R +The timed-out post is discarded without sender notification. +.B Note: +.B ezmlm-clean +is normally run from both +.I dir\fB/editor +and +.IR dir\fB/moderator . +To suppress sender notification, the switch needs to be specified +for all invocations of +.BR ezmlm-clean . +.TP +.B \-v +Display +.B ezmlm-clean +version information. +.TP +.B \-V +Display +.B ezmlm-clean +version information. +.SH "CHARACTER SETS" +If +.I dir\fB/charset +exists, +.B ezmlm-clean +will use the character set listed for all messages. Otherwise, the +default ``us-ascii'' will be used. The character set can be suffixed +by ``:'' followed by a code. If the code is ``Q'', outgoing messages are +sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded. +Otherwise, text is sent as is. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-moderate(1), +ezmlm-store(1), +ezmlm(5) diff --git a/ezmlm-clean.c b/ezmlm-clean.c new file mode 100644 index 0000000..ce8c04f --- /dev/null +++ b/ezmlm-clean.c @@ -0,0 +1,355 @@ +/*$Id: ezmlm-clean.c,v 1.30 1999/05/12 22:15:26 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include +#include +#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); +} + diff --git a/ezmlm-cron.1 b/ezmlm-cron.1 new file mode 100644 index 0000000..98fa3e2 --- /dev/null +++ b/ezmlm-cron.1 @@ -0,0 +1,245 @@ +.TH ezmlm-cron 1 +.SH NAME +ezmlm-cron \- Sets up digest request messages generation via crond +.SH SYNOPSIS +.B ezmlm-cron +[ +.B \-cCdDlL +][ +.B \-w \fIdow +][ +.B \-t \fIhh:mm +][ +.B \-i \fIhrs +] +.I listadr code[f] +.SH DESCRIPTION +.B ezmlm-cron +is a very restrictive interface to +.BR crond(8) . +It edits the effective user's ~/crontab (see crontab(5)) +file. It then executes +.B crontab(1) +to update crond(8) with the changes. + +.B ezmlm-cron +sets up the generation of trigger messages to the list +.I listadr +and the digest code +.IR code . +A optional digest format specifier +.I f +can be added to +.IR code . + +.B ezmlm-cron +reads +.IR dir\fB/ezcronrc , +where +.I dir +is the home directory of the effective user. The first line of this file is the +host name, 'host', to which bounces should be sent. Any bounces for lists +set up by 'user' will go to 'user@host'. Subsequent lines are entries +for users made up of: +.IR user:local:host:num:[list1[,list2...]] . +The ':'-separated parameters are: +.TP +.I user +the user name to which this line corresponds. +.TP +.I local +the list address must start with exactly these characters (case sensitive). +If this field is empty, any list local address is allowed. +.TP +.I host +the list host name must exactly match this parameter (case insensitive). +If this field is empty, any list host address is allowed. (Host names for +the list and the digest list must still match.) +.TP +.I num +the user is permitted a maximum of +.I num +entries. +.TP +.I list1 [,list2...] +a set of complete list names separated by commas. The user may edit +entries for these lists, even if they do not match the criteria set +above. If these lists exist, they are counted in determining +.IR num . +No while space is allowed before or between list names. If no list names +are specified, the final ':' can be omitted. + +The first line matching the executing user will be used. + +If +.B ezmlm-cron +is installed SUID +.IR euser , +the configuration and crontab files from that user's home directory +will be used for all +.B ezmlm-cron +actions. This way, users on a system can be given limited +.B crond(8) +access via +.B ezmlm-cron +restricted by +.I dir\fB/ezcronrc +and to the generation of digest trigger messages. This is especially +useful for users without shell access or access to +.BR crond(8) . +.I euser +is usually 'ezmlm'. +To install +.B ezmlm-cron +SUID ezmlm: + +.EX + # chown ezmlm /usr/local/bin/ezmlm/ezmlm-cron + # chmod 4555 /usr/local/bin/ezmlm/ezmlm-cron +.EE + +.B ezmlm-cron +refuses to run if installed SUID root. +.B ezmlm-cron +when executed by 'root', +will still use the files in ~root. + +To allow +.B crond(8) +access, you may need to list the effective user (all users allowed access +or ~ezmlm if +.B ezmlm-cron +is installed SUID ezmlm) in +.BR /etc/cron.allow . +See +.B crontab(1) +for further information. +.SH OPTIONS +The +.BR \-c , +.BR \-d , +and +.B \-l +switches are mutually exclusive. + +.TP +.B \-c +List user entry from +.IR ezcronrc . +.TP +.B \-C +(Default.) +Do not list user entry. +.TP +.B \-d +Delete entry. +.B ezmlm-cron +will search +.I ~euser\fB/crontab +for an entry belonging to the executing user, permitted by +.I ~euser\fB/ezcronrc +and matching the command line arguments supplied. +.I code +is ignored and may be omitted. +.TP +.B \-D +(Default.) +Do not delete entry. +.TP +.B \-i\fI hrs +Generate trigger message with +.I hrs +hours interval. Accepted intervals are 0, 1 ,2, 3, 6, 12, 24, 48, and 72 hours. +Other numbers will be silently adjusted upwards to the nearest accepted +interval +(intervals above 72 hours will result in weekly trigger messages). +.TP +.B \-l +List entries. If no other command line arguments are given, +.B ezmlm-cron +lists the entries created in the name of the user. If +.I listadr +is given, +.B ezmlm-cron +will list the entries for all the matching lists, even if the entries +were not set up by the current user. Arguments, if given, still have to +comply with the rules set in +.IR ezcronrc . + +Crude +.B crontab(5) +lines are listed. These are taken from the ~/crontab file. Usually, +these are active entries, although if the last execution of +.B crontab(1) +failed, they may not be. +.TP +.B \-L +(Default.) +Do not list entry. +.TP +.B \-t\fI hh:mm +The time for the trigger message. Other trigger messages will be sent +.I hrs +hours before and after this time. +.TP +.B \-w\fI dow +The days of the week on which trigger messages are sent. day 0 and 7 are +Sunday, 1 is Monday, etc (see crontab(5)). The string specified for +.I dow +must consists of single comma-separated digits in the range '0'-'7' +only. The default is every day, except for +.I hrs +of 48 (default Monday, Wednesday, Friday), 72 (default Monday and Thursday), +or greater than 72 (default Monday). +Both +.I hrs +and +.I dow +can be specified. In this case, trigger messages are sent +on the day specified by +.I dow +at the interval +specified by +.IR hrs . +If +.I hrs +is greater than 24 h, it is ignored and +trigger messages are generated daily or as specified by +.IR dow . +.SH FILES +.TP +.I ~euser/ezcronrc +The configuration file for +.BR ezmlm-cron . +.I euser +is the effective user id. This is the executing user, unless +.B ezmlm-cron +is installed SUID +.IR otheruser , +in which case it is +.IR otheruser . +.TP +.I ~euser/crontab +The file edited by +.BR ezmlm-cron . +.I euser +is the effective user. +.TP +.I ~euser/crontabl +The lock file used to assure that only one process at a time is editing the +.B crond(8) +settings. +.I euser +is the effective user. +.SH BUGS +.B ezmlm-cron +should use the output of 'crontab -l' to list crontab lines, rather than +parse the crontab file (and assume that the last execution of +.B crontab(1) +was successful). +.SH "SEE ALSO" +crond(8), +crontab(1), +crontab(5), +ezmlm(5), +ezmlm-get(1) diff --git a/ezmlm-cron.c b/ezmlm-cron.c new file mode 100644 index 0000000..e35f7ea --- /dev/null +++ b/ezmlm-cron.c @@ -0,0 +1,507 @@ +#include +#include +#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: ' to qmail-inject */ + if (!stralloc_cats(&addr,"%Return-path: <")) die_nomem(); + if (!stralloc_cats(&addr,user.s)) die_nomem(); + if (!stralloc_cats(&addr,"@")) die_nomem(); + if (!stralloc_cat(&addr,&rp)) die_nomem(); + if (!stralloc_cats(&addr,">\n")) die_nomem(); + } + if (!stralloc_0(&addr)) die_nomem(); + + if (!flaglist) { + /* now to rewrite crontab we need to lock */ + fdlock = open_append("crontabl"); + if (fdlock == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,dir.s,"/crontabl: "); + if (lock_ex(fdlock) == -1) { + close(fdlock); + strerr_die4sys(111,FATAL,ERR_OBTAIN,dir.s,"/crontabl: "); + } + } /* if !flaglist */ + if ((fdin = open_read("crontab")) == -1) { + if (errno != error_noent) + strerr_die4sys(111,FATAL,ERR_READ,dir.s,"/crontab: "); + } else + substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf)); + if (flaglist) + substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf)); + else { + if ((fdout = open_trunc("crontabn")) == -1) + strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: "); + substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf)); + } + line.len = 0; + + if (fdin != -1) { + for (;;) { + if (!flaglist && line.len) { + line.s[line.len-1] = '\n'; + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: "); + } + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,ERR_READ,dir.s,"/crontab: "); + if (!match) + break; + flagours = 0; /* assume entry is not ours */ + foundlocal = 0; + line.s[line.len - 1] = '\0'; /* match so at least 1 char */ + pos = 0; + while (line.s[pos] == ' ' && line.s[pos] == '\t') ++pos; + if (line.s[pos] == '#') + continue; /* cron comment */ + pos = str_chr(line.s,'/'); + if (!str_start(line.s+pos,auto_qmail)) continue; + pos += str_len(auto_qmail); + if (!str_start(line.s+pos,qmail_inject)) continue; + pos += str_len(qmail_inject); + poslocal = pos; + pos = byte_rchr(line.s,line.len,'<'); /* should be Return-Path: < */ + if (pos == line.len) + continue; /* not ezmlm-cron line */ + pos++; + len = str_chr(line.s+pos,'@'); + if (len == user.len - 1 && !str_diffn(line.s+pos,user.s,len)) { + flagours = 1; + ++nolists; /* belongs to this user */ + } + if (!local) { + foundlocal = 1; + } else { + pos = poslocal + str_chr(line.s+poslocal,'@'); + if (pos + lenhost +1 >= line.len) continue; + if (case_diffb(line.s+pos+1,lenhost,host)) continue; + if (line.s[pos+lenhost+1] != '%') continue; + /* check local */ + if (poslocal + lenlocal + 5 >= line.len) continue; + if (!str_start(line.s+poslocal,local)) continue; + pos2 = poslocal+lenlocal; + if (!str_start(line.s+pos2,"-dig-")) continue; + foundlocal = 1; + } + if (foundlocal) { + foundmatch = 1; + if (flaglist && (local || flagours)) { + if (substdio_put(&ssout,line.s,line.len) == -1) + strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: "); + if (substdio_put(&ssout,"\n",1) == -1) + strerr_die3sys(111,FATAL,ERR_WRITE,"stdout: "); + } + line.len = 0; /* same - kill line */ + if (flagours) + --nolists; + } + } + close(fdin); + } + if (flaglist) { + if (substdio_flush(&ssout) == -1) + strerr_die3sys(111,FATAL,ERR_FLUSH,"stdout: "); + if (foundmatch) /* means we had a match */ + _exit(0); + else + strerr_die2x(100,FATAL,ERR_NO_MATCH); + } + /* only -d and regular use left */ + + if (nolists >= maxlists && !flagdelete) + strerr_die2x(100,FATAL,ERR_LISTNO); + if (!flagdelete) + if (substdio_put(&ssout,addr.s,addr.len-1) == -1) + strerr_die4sys(111,FATAL,ERR_WRITE,dir.s,"/crontabn: "); + if (flagdelete && !foundlocal) + strerr_die2x(111,FATAL,ERR_NO_MATCH); + if (substdio_flush(&ssout) == -1) + strerr_die4sys(111,FATAL,ERR_FLUSH,dir.s,"/crontabn: "); + if (fsync(fdout) == -1) + strerr_die4sys(111,FATAL,ERR_SYNC,dir.s,"/crontabn++: "); + if (close(fdout) == -1) + strerr_die4sys(111,FATAL,ERR_CLOSE,dir.s,"/crontabn: "); + if (rename("crontabn","crontab") == -1) + strerr_die4sys(111,FATAL,ERR_MOVE,dir.s,"/crontabn: "); + sendargs[0] = "sh"; + sendargs[1] = "-c"; + + if (!stralloc_copys(&line,auto_cron)) die_nomem(); + if (!stralloc_cats(&line,"/crontab '")) die_nomem(); + if (!stralloc_cats(&line,dir.s)) die_nomem(); + if (!stralloc_cats(&line,"/crontab'")) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + sendargs[2] = line.s; + sendargs[3] = 0; + switch(child = fork()) { + case -1: + strerr_die2sys(111,FATAL,ERR_FORK); + case 0: + if (setreuid(euid,euid) == -1) + strerr_die2sys(100,FATAL,ERR_SETUID); + execvp(*sendargs,sendargs); + if (errno == error_txtbsy || errno == error_nomem || + errno == error_io) + strerr_die4sys(111,FATAL,ERR_EXECUTE,sendargs[2],": "); + else + strerr_die4sys(100,FATAL,ERR_EXECUTE,sendargs[2],": "); + } + /* parent */ + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + strerr_die2x(111,FATAL,ERR_CHILD_CRASHED); + switch(wait_exitcode(wstat)) { + case 0: + _exit(0); + default: + strerr_die2x(111,FATAL,ERR_CRONTAB); + } +} diff --git a/ezmlm-gate.1 b/ezmlm-gate.1 new file mode 100644 index 0000000..cd45cd5 --- /dev/null +++ b/ezmlm-gate.1 @@ -0,0 +1,116 @@ +.TH ezmlm-gate 1 +.SH NAME +ezmlm-gate \- Gate posts depending on message SENDER +.SH SYNOPSIS +.B ezmlm-gate [-cCmMpPrRsSvV] [-q file] +.I dir [moddir1] [moddir2 ...] +.SH DESCRIPTION +.B ezmlm-gate +checks if SENDER is in it least one of the subscriber lists +with base directory +.IR moddir1 , +.IR moddir2 , +etc. +If it is, the message is posted via +.B ezmlm-send +to the list in +.IR dir . +If not, the message is sent for moderation via +.BR ezmlm-store . + +The default is to send the message for moderation. +.SH OPTIONS +.TP +.B \-cCmMpPrRsS +Passed on to ezmlm-store(1) and ezmlm-send(1). +.TP +.B \-cCrR +Passed on to ezmlm-send(1). +.TP +.B \-q\fI file +Execute arbitration programs in +.IR file . +Lines in +.I file +are executed just like in regular +.IR .qmail +files with the difference that all lines are assumed to be program +names. See +.BR dot-qmail(5) . +Programs are executed by /bin/sh and the message is on stdin of the +executed program. +The leading ``|'' is optional. Comments and blank lines are allowed. If a +program exits 111, delivery is deferred. If it exits 99, the message is +sent to the list. If it exits 0, the next line is executed. If it exits +with any other exit code, the message is sent for moderation. Subscriber +status per +.IR moddir1 , +.IR moddir2 , +etc, is tested only if all the programs have been executed and the final +exit code is 0. Thus, programs can cause moderation (100), posting (99), or +defer the decision to the next program and ultimately to subscriber status. +.TP +.B \-v +Display version information. +.TP +.B \-V +Display version information. + +.SH USAGE +.B ezmlm-gate +is best used if you want to restrict posts to a set of addresses using +SENDER checks. Obviously, this is not secure, but it +can help quite a bit to keep +garbage off the list. For more secure setups, see +.BR ezmlm-store(1) . +For other arbitration such as SPAM protection, use the +.B \-q +option. For instance, invoking +.B ezmlm-reject(1) +here would cause failing messages to be sent for moderation rather that being +rejected. + +Set up the list with a +.B ezmlm-gate +line in +.I dir\fB/editor +and touch +.IR dir\fB/modpost . +Add the moderator(s) (usually the list owner): + +.EX +.B ezmlm-sub +.I dir\fB/mod +moderator@host +.EE + +This will via +.B ezmlm-send +directly distribute +all posts from subscriber addresses and send out the rest for moderation +to the moderator(s) via +.BR ezmlm-store . +To test several subscriber databases, e.g. the list and the list-digest +subscribers, add the corresponding list directories to the +.B ezmlm-gate +command line. + +This can be expanded to include users that post from addresses other than +the one they are subscribed as: just create another directory 'addl', and +a 'subscribers' subdirectory of it, and add 'addl' to the +.B ezmlm-gate +command line. Now just add all problem addresses to the 'addl' address +database using +.BR ezmlm-sub . +The entire point is that post from subscribers of any union +of list go through, posts from identified 'aliases' go through and all +others go for approval to the list owner. Thus, legitimate users are never +rejected and 'aliases' rapidly identified by the owner/moderator and +their handling automated one by one, by simply adding them to 'addl'. +.SH "SEE ALSO" +dot-qmail(5), +ezmlm(5), +ezmlm-issubn(1), +ezmlm-reject(1), +ezmlm-send(1), +ezmlm-store(1) diff --git a/ezmlm-gate.c b/ezmlm-gate.c new file mode 100644 index 0000000..25d9b59 --- /dev/null +++ b/ezmlm-gate.c @@ -0,0 +1,213 @@ +/*$Id: ezmlm-gate.c,v 1.18 1999/10/09 16:49:56 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "strerr.h" +#include "error.h" +#include "env.h" +#include "sig.h" +#include "str.h" +#include "seek.h" +#include "fork.h" +#include "wait.h" +#include "exit.h" +#include "getconf.h" +#include "auto_bin.h" +#include "sgetopt.h" +#include "errtxt.h" +#include "idx.h" +#include "subscribe.h" + +#define FATAL "ezmlm-gate: fatal: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-gate: usage: ezmlm-gate [-cCmMpPqrRsSvV] " + "dir [moddir [...]]"); +} +void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } + +stralloc line = {0}; +stralloc cmds = {0}; +stralloc send = {0}; +stralloc sendopt = {0}; +stralloc storeopt = {0}; +void *psql = (void *) 0; + +char szchar[2] = "-"; + char *sendargs[4]; + int child; + int wstat; + char *pmod; + +int mailprog(s) + char *s; +{ + int r; + + sendargs[0] = "/bin/sh"; /* 100 perm error, 111 temp, 99 dom ok */ + sendargs[1] = "-c"; /* 0 rec ok, others bounce */ + sendargs[2] = s; + sendargs[3] = (char *)0; + switch(child = fork()) { + case -1: + strerr_die2sys(111,FATAL,ERR_FORK); + case 0: + execv(*sendargs,sendargs); + if (errno == error_txtbsy || errno == error_nomem || + errno == error_io) + strerr_die5sys(111,FATAL,ERR_EXECUTE, + "/bin/sh -c ",sendargs[2],": "); + else + strerr_die5sys(100,FATAL,ERR_EXECUTE, + "/bin/sh -c ",sendargs[2],": "); + } + /* parent */ + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + strerr_die2x(111,FATAL,ERR_CHILD_CRASHED); + switch((r = wait_exitcode(wstat))) { + case 0: case 99: case 100: break; + case 111: /* temp error */ + strerr_die2x(111,FATAL,ERR_CHILD_TEMP); + default: + strerr_die2x(100,FATAL,ERR_REJECT); /* other errors => bounce */ + } + if (seek_begin(0) == -1) /* rewind */ + strerr_die2sys(111,FATAL,ERR_SEEK_INPUT); + return r; +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *sender; + char *moddir; + char *queryext = (char *) 0; + int opt; + int ret = 0; + unsigned int i,j,k; + + umask(022); + sig_pipeignore(); + /* storeopts to ezmlm-store only. Others to both (ezmlm-store may */ + /* pass them on to ezmlm-send. */ + if (!stralloc_copys(&sendopt," -")) die_nomem(); + if (!stralloc_copys(&storeopt," -")) die_nomem(); + + while ((opt = getopt(argc,argv, + "cCmMpPq:Q:sSrRt:T:vV")) != opteof) + switch(opt) { /* pass on unrecognized options */ + case 'c': /* ezmlm-send flags */ + case 'C': + case 'r': + case 'R': + szchar[0] = opt; + if (!stralloc_append(&sendopt,szchar)) die_nomem(); + break; + case 'm': /* ezmlm-store flags */ + case 'M': + case 'p': + case 'P': + case 's': + case 'S': + szchar[0] = opt; + if (!stralloc_append(&storeopt,szchar)) die_nomem(); + break; + case 'q': /* allow both qQ to be nice */ + case 'Q': if (optarg) queryext = optarg; break; + case 'v': + case 'V': strerr_die2x(0,"ezmlm-gate version: ",EZIDX_VERSION); + default: /* ezmlm-store flags */ + die_usage(); + } + + dir = argv[optind++]; + if (!dir) die_usage(); + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); + + sender = env_get("SENDER"); + + pmod = (char *) 0; + + if (queryext) { + getconf(&cmds,queryext,1,FATAL,dir); + i = 0; + for (j = 0;j < cmds.len; ++j) + if (!cmds.s[j]) { + switch (cmds.s[i]) { + case '\0': case '#': break; /* ignore blank/comment */ + case '|': + ret = mailprog(cmds.s + i + 1); break; + default: + ret = mailprog(cmds.s + i); break; + } + if (ret) break; + i = j + 1; + } + if (!ret || ret == 99) /* 111 => temp error */ + pmod = ""; /* 0, 99 => post */ + /* other => moderate */ + } + moddir = argv[optind++]; + if (moddir && !ret) { /* if exit 0 and moddir, add issub */ + pmod = (char *) 0; + while (moddir && !pmod && sender) { + pmod = issub(moddir,sender,(char *) 0,FATAL); + closesql(); + moddir = argv[optind++]; + } + } + + sendargs[0] = "sh"; + sendargs[1] = "-c"; + if (!stralloc_copys(&send,auto_bin)) die_nomem(); + if (pmod) { + if (!stralloc_cats(&send,"/ezmlm-send")) die_nomem(); + if (sendopt.len > 2) + if (!stralloc_cat(&send,&sendopt)) die_nomem(); + + } else { + if (!stralloc_cats(&send,"/ezmlm-store")) die_nomem(); + if (storeopt.len > 2) + if (!stralloc_cat(&send,&storeopt)) die_nomem(); + if (sendopt.len > 2) + if (!stralloc_cat(&send,&sendopt)) die_nomem(); + } + if (!stralloc_cats(&send," '")) die_nomem(); + if (!stralloc_cats(&send,dir)) die_nomem(); + if (!stralloc_cats(&send,"'")) die_nomem(); + if (!stralloc_0(&send)) die_nomem(); + sendargs[2] = send.s; + sendargs[3] = 0; + + switch(child = fork()) { + case -1: + strerr_die2sys(111,FATAL,ERR_FORK); + case 0: + execvp(*sendargs,sendargs); + if (errno == error_txtbsy || errno == error_nomem || + errno == error_io) + strerr_die4sys(111,FATAL,ERR_EXECUTE,sendargs[2],": "); + else + strerr_die4sys(100,FATAL,ERR_EXECUTE,sendargs[2],": "); + } + /* parent */ + wait_pid(&wstat,child); + if (wait_crashed(wstat)) + strerr_die2x(111,FATAL,ERR_CHILD_CRASHED); + switch(wait_exitcode(wstat)) { + case 100: + strerr_die2x(100,FATAL,ERR_CHILD_FATAL); + case 111: + strerr_die2x(111,FATAL,ERR_CHILD_TEMP); + case 0: + _exit(0); + default: + strerr_die2x(111,FATAL,ERR_CHILD_UNKNOWN); + } +} + diff --git a/ezmlm-get.1 b/ezmlm-get.1 new file mode 100644 index 0000000..12c4e3b --- /dev/null +++ b/ezmlm-get.1 @@ -0,0 +1,464 @@ +.TH ezmlm-get 1 +.SH NAME +ezmlm-get \- handles mailing list archive retrieval and digests +.SH SYNOPSIS +.B ezmlm-get +[ +.B \-bBcCpPsSvV +][ +.B \-f +.I format +] +.I dir +[ +.I digestcode[f] +] +.SH OPTIONS +.TP +.B \-b +(Default.) +Copy administrative information and the request to the bottom of replies. +This informs the recipient of other commands, and allows some error tracking +in case the recipient did not originate the request. +.TP +.B \-B +Suppress the normal administrative information and request copy. This may make +it harder for the recipient to diagnose problems and learn commands. +.TP +.B \-c +(Default.) +Process and reply to commands (does not affect digests). +.TP +.B \-C +Ignore all commands except digest. +.TP +.B \-f \fIformat +.B ezmlm-get +will use +.I format +as the default format for all returned message collections. The default +is 'm' for MIME with a header subset (see below). Format specifiers +send with individual requests override the default set with the +.B \-f +switch. +.TP +.B \-p +\-get, \-index, and \-thread commands are available to all users, +provided other flags are permissive. This overrides normal behavior, +which is to allow archive retrieval only to moderators, when +.I dir\fB/public +does not exist. This is useful to set up non-public lists that still give +users archive access. +.TP +.B \-P +\-get, \-index, and \-thread commands are available +only to moderators, even if +.I dir\fB/public +exists. The +.B \-C +and +.B \-s +flags can restrict this further. This is useful for public lists with +archive retrieval restricted to a subset of users (moderators). +.TP +.B \-s +\-get, \-index, and \-thread requests are processed only if +.B SENDER +is a subscriber. +.TP +.B \-S +(Default.) +Anyone can issue \-get, \-index, and \-thread requests. +.TP +.B \-v +Print version info. +.TP +.B \-V +Print version info. +.SH DESCRIPTION +.B ezmlm-get +handles archive retrieval and optionally makes and sends out +digests for the mailing list +stored in +.IR dir . +Subscribers of the digest list are stored in +.IR dir\fB/digest/subscribers/ . + +The contents of +.I dir\fB/headeradd +are added to the header of outgoing messages. + +.B ezmlm-get +is normally invoked from a +.B .qmail(7) +file. + +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. + +.B ezmlm-get +uses +.B LOCAL +to determine where it is invoked. If +.B LOCAL +is the list local name only, +.B ezmlm-get +assumes it is run from +.I dir\fB/editor +to produce a digest. +The digest is sent directly to the digest list subscribers. + +If +.B LOCAL +is empty or undefined, +.B ezmlm-get +assumes it is run from the command line or a script. In this case +it behaves as if run from +.I dir\fB/editor +and sends out a digest to the digest subscribers. + +Otherwise, +.B ezmlm-get +expects +.B LOCAL +to be of the form +.IR list\fB-\fIaction . +Here +.I list +is the first line of +.IR dir\fB/inlocal +and +.I action +is a request. +The output is sent to the envelope sender. + +.BR ezmlm-get +checks +.I action +for +.BR dig\.\fIdigestcode , +.BR index , +.BR thread , +and +.BR get . +If +.I action +is one of these, +.B ezmlm-get +handles the request and sends a reply. If successful, it +exits 99 (ignore remaining +.B .qmail(7) +file entries). +If +.I action +is not one of these, +.B ezmlm-get +exits 0 (success) to pass the message on to later handlers, +such as +.BR ezmlm-manage(1) . + +.B ezmlm-get +expects +.B HOST +to match the first line of +.IR dir\fB/inhost . + +.BR ezmlm-dig\.\fIdigestcode +returns a digest of messages received since the last digest, unless +numerical arguments are given. +.I digestcode +must be alphanumeric, and match (case-insensitive) +.I digestcode +on the +.B ezmlm-get +command line. Otherwise, the request will be ignored. This is to restrict +digest creation. The body of the requesting message up to the first line +starting with '-' is copied into the +.I administrivia +section of the digest. This is followed by the contents of +.IR dir\fB/text/digest , +if this file exists. + +.B Note: +Anyone who can read your +.I dir\fB/manager +file, digest-requesting scripts, or mail log knows the +.I digestcode +and can trigger digests. + +.B ezmlm-get +copies +.I dir\fB/mailinglist +into a +.B Mailing-List +field in its response. +If the incoming message has a +.B Mailing-List +field, +.B ezmlm-get +refuses to respond. +.B ezmlm-get +also refuses to respond to bounce messages. + +If +.I dir\fB/listid +exists, +.B ezmlm-get +will assume that the format is correct and +create a ``List-ID:'' header by placing the contents after the +text ``List-ID: ''. + +If +.I dir\fB/qmqpservers +exists, +.B ezmlm-get will use +.B qmail-qmqp(1) +to send digests. Other messages are sent by the normal qmail mechanism. + +If +.I dir\fB/public +does not exist, +.B ezmlm-get +rejects all archive retrieval attempts, unless the +.B \-p +command line switch is used. + +Archive retrieval actions can be of the form +.BR action[f] , +.BR action[f].\fInum +or +.BR action[f].\fInum_num2 , +where +.I num +is the message number for the action or +.I num_num2 +the range of message numbers for the action. + +.B f +is an optional format specifier for +.IR \-get , +.IR \-thread , +and +.I \-dig +requests. It is allowed, but ignored for +.I \-index +requests. Currently, the following are allowed: + +.TP +.B r +rfc1153. This is a ``plain'' non-MIME format for dumb clients. +.TP +.B m +(Default.) MIME +.I multipart/digest +with a subset of ordered headers sorted. +Currently, the following headers are +included in the order listed: +Date:, +To:, +From:, +Reply-To:, +Cc:, +MIME-Version:, +Content-Type:, +Message-ID:, +and Keywords:. +This can be customized with the optional file +.IR dir\fB/digheaders , +which should contain the desired headers up to but not including the colon. + +The format is no longer compliant +with rfc1153, as the rfc1153 format is incompatible with rfc2046, which +which the format is (should be) compatible. +.TP +.B x +MIXED: This is the same as the default MIME +format, except that the Content-Type is +.IR multipart/mixed . +This helps circumnavigate a Pine bug: when the digest is +content-transfer-encoded, Pine will refuse to display the initial +text/plain part of a +.I multipart/digest +message, but display the same part of a +.I multipart/mixed +message. Some MUAs for some strange reason treat the two multipart formats +differently. In some cases, ``x'' works better than ``m''. +.TP +.B v +VIRGIN: This is MIME +.I multipart/digest +with messages returned without any header filtering. +.TP +.B n +NATIVE: This is VIRGIN format without threading, i.e. messages are +presented in numerical order and the message index is suppressed. + +.PP +For flexibility and backwards compatibility, the '.' separating the action from +the first argument can be replaced by '\-', +or omitted. +Any non-alphanumeric character can separate +.I num2 +from +.IR num . +.PP + +If +.I action +is +.IR dig.digestcode , +.B ezmlm-get +returns a digest of the messages received since the last digest, and updates +the digest issue counter. + +If +.I action +is +.IR get , +.B ezmlm-get +sends back message(s) +.I num +or +.I num +through +.IR num2 . +from +.IR dir\fB/archive/ . +If +.I num +is omitted and +.I dir\fB/dignum +does not exist or is 0, the latest HISTGET message (default 30) are +returned. Otherwise, +the messages since the latest digest are returned including the last +message in that digest, so that always at least 1 message is send. If the +number of messages +exceeds MAXGET (default 100), only the MAXGET last messages are returned. +if +.I num +is greater than the latest message in the archive _and_ +.I num2 +is specified, the latest messages back to HISTGET before the end of the +latest digest up to MAXGET messages are returned. This is a good way of +always getting at least the latest 30 messages without knowing the latest +message number. A link with such a command could be put into e.g. +.IR dir\fB/text/sub-ok . + +.I num +and +.I num2 +are adjusted to make both > 0, and +.I num2 +>= +.IR num . +If either is greater than +the largest message number processed, it is silently +set to the largest message number. +At most 100 messages are +returned. + +If +.I action +is +.BI index , +.B ezmlm-get +sends back the subjects and authors of the message(s) +.I num +or +.IR num +through +.I num2 +in sets of 100 from +.IR dir\fB/archive/ . +.I num +and +.I num2 +are reasonable adjusted as for 'get'. No warnings are +sent. At most 20 sets of 100 message entries are returned per request. If +.I num +is omitted, +.B ezmlm-get +returns the last 100-200 message entries, which automatically gives +information about the last message number. + +If +.I action +is +.BI thread , +.B ezmlm-get +sends back the message(s) that have an index subject entry identical to +that of message +.I num +from +.IR dir\fB/archive/ . + +If +.I num2 +is given it is ignored. If +.I num +is out of range, and error +message is returned. The message range scanned for the subject is limited +to 2000 messages before and after the master message, i.e. the +.BR thread +argument. +This limit protects very large archives. +Most threads are expected to be considerably more short-lived. +In the unlikely event that there are further messages, +these can be retrieved by a second request for the +highest/lowest message returned in the first request. +.SH "CHARACTER SETS" +If +.I dir\fB/charset +exists, +.B ezmlm-get +will use the character set listed for all messages. Otherwise, the +default ``us-ascii'' will be used. The character set can be suffixed +by ``:'' followed by a code. If the code is ``Q'', outgoing messages are +sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded. +Otherwise, text is sent as is. +.SH "FILES" +.TP +.I dir\fB/dignum +The last message included in the latest normal mode digest. +.TP +.I dir\fB/digissue +The issue number of the latest normal mode digest. +.TP +.I dir\fB/text/get-bad +Returned if a/the message cannot be found. +.TP +.I dir\fB/text/digest +Copied into the +.I Administrivia +section of digests after the body of the requesting message. +.TP +.I dir\fB/charset +The character set used for all +.B ezmlm-get +messages (see above). +If not present, the default, ``us-ascii'', is used without encoding. +.SH BUGS +The digest format per rfc2046 +should (but is not required to) be multipart/mixed +with the table-of-contents a text/plain part, and the entire remainder of +the digest a multipart/digest part. The multipart/digest in turn should +contain all the messages. Many +MUA's fail to split out the individual messages from such a hierarchy, so the +format used by +.B ezmlm-get +is a simple multipart/digest, explicitly typing the table-of-contents +to text/plain, with the ``x'' format changing the mail content-type to +multipart/mixed. +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm-manage(1), +ezmlm-send(1), +ezmlm(5), +qmail-command(8), +qmail-qmqp(1) + diff --git a/ezmlm-get.c b/ezmlm-get.c new file mode 100644 index 0000000..f8146ac --- /dev/null +++ b/ezmlm-get.c @@ -0,0 +1,1459 @@ +/*$Id: ezmlm-get.c,v 1.113 1999/11/22 01:47:45 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#include +#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); + } +} diff --git a/ezmlm-glconf.1 b/ezmlm-glconf.1 new file mode 100644 index 0000000..df054be --- /dev/null +++ b/ezmlm-glconf.1 @@ -0,0 +1,54 @@ +.TH ezmlm-glconf 1 +.SH NAME +ezmlm-glconf \- create config file for global ezmlm-request address +.SH SYNOPSIS +.B ezmlm-glconf +[ +.B \-n +] +.IR dotdir [dotdir1 ...] > +.I config_file +.SH DESCRIPTION +.B ezmlm-glconf +scans +.IR dotdir , +usually the users home directory, +for files of type +.BR .qmail-return-*-default . +For normal ezmlm-lists, these are links to +.B bouncer +files, which on their last line have a call to +.B ezmlm-return(1) +or +.BR ezmlm-warn(1). +.B ezmlm-glconf +extracts the list directory from these, +and builds a +line for +.I config_file +from the information in the list directory. The first line of +the +.B /text/info +file of the list is assumed to contain a brief description of the list. If +not found ``no information available'' is used. + +.B ezmlm-glconf +output is sorted alphabetically by list name and if a digest list +exists, the digest list entry immediately follows the list entry. + +.SH OPTIONS +.TP +.B \-n +Add information on the current number of subscribers to the list information. +.SH CONFIGURATION +The descriptive text +.B ezmlm-glconf +uses for digest lists and the text used if +.B /text/info +is not readable/available can be changed by editing the script. +.SH "SEE ALSO" +ezmlm-glmake(1), +ezmlm-request(1), +ezmlm-return(1), +ezmlm-warn(1), +ezmlm(5) diff --git a/ezmlm-glconf.sh b/ezmlm-glconf.sh new file mode 100644 index 0000000..73f2e0d --- /dev/null +++ b/ezmlm-glconf.sh @@ -0,0 +1,107 @@ +# above should be a definition of EZPATH and the /bin/sh line +# automatically added at build time. +######################################################################### +# Script to build ezmlm-request config file for the global interface +# Lists are presented in alphabetical order and digest lists are +# directly after the main list. Digest list info is only that +# they are digest of the main list. If the -n switch is used, +# the current number of subscribers is added to the info text. +# +# Usage: ezmlm-glconf [-n] dotdir [dotdir1 ...] > config +# where ``dotdir'' is the directory where the users .qmail files +# reside (usually ``~''), and ``config'' is the config file for +# ezmlm-request servicing the global interface. +# +# Note: This config file will provide info on all lists available +# and allow ``which'' for all lists. You may want to edit the +# output before using it. +########################################################################## + +# Change if you change the name of the command +NAME='ezmlm-glconf' + +# Info text used for list-digest +DIGTXT='Digest of' +# ``subscribers'' for stating subscriber number +SUBTXT='subscribers' +# Info text if dir/text/info doesn't exist/is not readable +INFOTXT='No information available' + +# Set full path if you use the script as root or if the commands +# are not in your path. +HEAD='head' +TAIL='tail' +CAT='cat' +CUT='cut' +GREP='grep' +ECHO='echo' +LS='ls' +SORT='sort' +SED='sed' +WC='wc' + +# Nothing more to configure +########################################################################## + +SUB='' +EZLIST="${EZPATH}/ezmlm-list" +FATAL="${NAME}: fatal: " +WARN="${NAME}: warning: " +USAGE="${NAME} [-n] dotdir [dotdir1 ...] > config" + +if [ "$1" = "-n" ]; then + shift + if [ ! -x "${EZLIST}" ]; then + echo "${WARN} ezmlm-list not found. Edit ezmlm binary path." + else + SUB='yes' + fi +fi + +if [ -z "$1" ]; then + ${ECHO} "$USAGE" + exit 100 +fi + + +( +while [ -n "$1" ]; do + for i in `${LS} $1/.qmail-*-return-default` ; do + INFO='' + # get list directory + if [ -r "$i" ] ; then + DIR=`${TAIL} -1 "$i" | ${CUT} -d\' -f2` + # only dir that exists + if [ -d "$DIR" ] ; then + INFOFN="${DIR}/text/info" + if [ -r "${INFOFN}" ]; then + INFO=`${HEAD} -1 ${INFOFN}` + else + INFO="$INFOTXT" + ${ECHO} "$WARN No info for list in $DIR" 1>&2 + fi + + OUTLOCAL=`${CAT} $DIR/outlocal` + OUTHOST=`${CAT} $DIR/outhost` + if [ -z "$SUB" ]; then + SUBN='' + else + NO=`${EZLIST} ${DIR} | ${WC} -l |${SED} 's/ //g'` + SUBN=" (${NO} ${SUBTXT})" + fi + ${ECHO} "$i" | ${GREP} 'digest-return' >/dev/null && \ + { INFO="${DIGTXT} $OUTLOCAL@$OUTHOST."; \ + OUTLOCAL="${OUTLOCAL}~digest" ; } + ${ECHO} "$OUTLOCAL@$OUTHOST:$DIR:${INFO}${SUBN}" + else + ${ECHO} "$WARN $DIR not readable - list ignored" 1>&2 + fi + else + ${ECHO} "$WARN $i ignored: doesn't point to readable file" 1>&2 + fi + done ; + shift +done; +) | ${SORT} | ${SED} 's/~digest@/-digest@/' + # list-digest after list + # "~"-cludge needed to get order right diff --git a/ezmlm-idx.1 b/ezmlm-idx.1 new file mode 100644 index 0000000..60a07ea --- /dev/null +++ b/ezmlm-idx.1 @@ -0,0 +1,97 @@ +.TH ezmlm-idx 1 +.SH NAME +ezmlm-idx \- create index for mailing list archive +.SH SYNOPSIS +.B ezmlm-idx +[ +.B \-dDF +][ +.B \-f\I msg +] +.I dir +.SH DESCRIPTION +.B ezmlm-idx +reads all archived messages for the list in +.I dir +from +.IR dir\fB/archive/ +and creates a message index. The index file format is identical to +that produced by +.B ezmlm-send(1) +(when +.IR dir\fB/indexed +is present). + +.B ezmlm-idx +will ignore messages that do not have the owner execute bit set. + +.B ezmlm-idx +will create the the index file under a different name and then +move it into place. + +If +.IR dir\fB/indexed +does not exist, +.B ezmlm-idx +will create it to enable the use of the newly created subject and author index. + +.B ezmlm-idx +will remove reply-indicators and the prefix from the subject before +entry into the index, as described for +.BR ezmlm-send(1) . +.B ezmlm-idx +will decode rfc2047 encoded subject and author headers. When unfolding +split lines, +.B ezmlm-idx +will remove redundant escape sequences for the character +set specified in +.IR dir\fB/charset . + +.B ezmlm-idx +calculates a subject hash based on the normalized subject header. Normalization +removes linear whitespace, case information, and message reply indicators. +The subject hash is used by +.B ezmlm-get(1) +for message threading. +.SH OPTIONS +.TP +.B \-d +Use the ``Date:'' header for date information, rather than the top ``Received:'' +header. This is unreliable, but useful when messages have been transferred from +another type of archive by mailing them to ezmlm. +.B ezmlm-idx +converts dates with two-digit years ``xx'' to 19xx if xx is >= 70. Otherwise, +20xx is assumed. +.TP +.B \-D +(Default.) +Use the ``Received:'' header, not the ``Date:'' header. This is more reliable +since this is the header added by the receiving qmail. Also, this results +in always correctly formatted dates in the same time zone (usually UTC). +.TP +.B \-f\fI msg +Start indexing with the archive section containing message +.IR msg . +This is useful if you have removed part of the archive and do not want to +create (empty) directories and index files for these. It also decreases +.B ezmlm-idx +memory use. +.TP +.B \-F +(Default.) +Start indexing from message 1. +.TP +.B \-v +Display +.B ezmlm-idx +version info. +.TP +.B \-V +Display +.B ezmlm-idx +version info. +.SH "SEE ALSO" +ezmlm-archive(1), +ezmlm-get(1), +ezmlm-send(1), +ezmlm(5) diff --git a/ezmlm-idx.c b/ezmlm-idx.c new file mode 100644 index 0000000..c552357 --- /dev/null +++ b/ezmlm-idx.c @@ -0,0 +1,337 @@ +/*$Id: ezmlm-idx.c,v 1.29 1999/10/29 02:49:14 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#include +#include "stralloc.h" +#include "subfd.h" +#include "strerr.h" +#include "error.h" +#include "lock.h" +#include "slurp.h" +#include "open.h" +#include "getln.h" +#include "sgetopt.h" +#include "case.h" +#include "scan.h" +#include "str.h" +#include "fmt.h" +#include "readwrite.h" +#include "exit.h" +#include "substdio.h" +#include "idx.h" +#include "mime.h" +#include "errtxt.h" +#include "getconf.h" +#include "makehash.h" + +#define FATAL "ezmlm-idx: fatal: " + +char strnum[FMT_ULONG]; +char hash[HASHLEN]; + +stralloc fnadir = {0}; +stralloc fnif = {0}; +stralloc fnifn = {0}; +stralloc fnaf = {0}; + +stralloc line = {0}; +stralloc lines = {0}; +stralloc dummy = {0}; + +int fdindexn; +int fdlock; +int fd; +int flagdate = 0; /* use 'Received:' header by default, =1 -> 'Date:' */ + + /* for reading index and in ezmlm-idx for reading message */ +static substdio ssin; +static char inbuf[1024]; + +substdio ssindex; +char indexbuf[1024]; + +struct stat st; + +stralloc subject = {0}; +stralloc author = {0}; +stralloc authmail = {0}; +stralloc received = {0}; +stralloc prefix = {0}; +stralloc charset = {0}; + +struct strerr index_err; + +stralloc num = {0}; + +char buf0[256]; +substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0)); + +void die_usage() +{ + strerr_die1x(100,"ezmlm-idx: usage: ezmlm-idx [-dDF] [-f msg] dir"); + +} + +void die_nomem() +{ + strerr_die2x(100,FATAL,ERR_NOMEM); +} + +int idx_get_trimsubject() + +/* reads an open message from 'fd', extracts the subject (if any), and */ +/* returns the subject in 'sub', the author in 'author', and the received */ +/* rfc822 date to 'received'. 'fatal' is a program-specific error string. */ +/* returns: 0 - no reply no prefix */ +/* 1 - reply no prefix */ +/* 2 - prefix no reply */ +/* 3 - reply & prefix */ +/* No terminal '\n' in any of the strallocs! */ +{ +char *cp; +int foundsubject = 0; +int issubject = 0; +int isfrom = 0; +int foundreceived = 0; +int foundfrom = 0; +int match; +int r; +unsigned int pos,pos1; + + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2x(111,FATAL,ERR_READ_INPUT); + if (match) { + if (line.len == 1) + break; + if (*line.s == ' ' || *line.s == '\t') { + /* continuation */ + if (issubject) { + if (!stralloc_cat(&subject,&line)) die_nomem(); + } else if (isfrom) + if (!stralloc_cat(&author,&line)) die_nomem(); + } else { + issubject = 0; + isfrom = 0; + if (!foundsubject && case_startb(line.s,line.len,"Subject:")) { + if (!stralloc_copyb(&subject,line.s+8,line.len-8)) die_nomem(); + foundsubject = 1; + issubject = 1; + } else if (!foundfrom && case_startb(line.s,line.len,"From:")) { + if (!stralloc_copyb(&author,line.s+5,line.len-5)) die_nomem(); + foundfrom = 1; + isfrom = 1; + } else if (!flagdate && !foundreceived && + case_startb(line.s,line.len,"Received:")) { + pos = byte_chr(line.s,line.len,';'); + if (pos != line.len) + if (!stralloc_copyb(&received,line.s+pos+2,line.len - pos - 3)) + die_nomem(); + foundreceived = 1; + } else if (flagdate && !foundreceived && + case_startb(line.s,line.len,"Date:")) { + if (line.len < 22) continue; /* illegal */ + pos = 6 + byte_chr(line.s+6,line.len-6,','); + if (pos == line.len) + pos = 5; + ++pos; + while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos; /* dd */ + pos1 = pos + 3; + while (++pos1 < line.len && line.s[pos1] != ' '); /* mo */ + ++pos1; + if (!stralloc_copyb(&received,line.s+pos,pos1 - pos)) + die_nomem(); /* '01 Jun ' */ + if (pos1 + 2 < line.len) { + if (line.s[pos1 + 2] == ' ') { /* 2-digit */ + if (line.s[pos1] >= '7') { /* >= 70 */ + if (!stralloc_cats(&received,"19")) die_nomem(); + } else if (!stralloc_cats(&received,"20")) die_nomem(); + pos = pos1 + 3; /* 2 digit */ + } else + pos = pos1 + 5; /* 4 digit */ + if (pos < line.len) { + pos += byte_chr(line.s+pos,line.len-pos,' '); /* after time */ + if (pos < line.len) { + ++pos; /* zone */ + while (line.s[pos] != ' ' && line.s[pos] != '\n') ++pos; + } else + pos = line.len - 1; /* no zone. Illegal; better than 0 */ + if (!stralloc_catb(&received,line.s+pos1,pos - pos1)) + die_nomem(); + foundreceived = 1; + continue; + } + } + received.len = 0; /* bad format - scrap */ + } + } + } else + break; + } + + if (foundsubject) { + concatHDR(subject.s,subject.len,&lines,FATAL); /* make 1 line */ + decodeHDR(lines.s,lines.len,&line,charset.s,FATAL); /* decode mime */ + r= unfoldHDR(line.s,line.len,&subject,charset.s,&prefix,1,FATAL); + /* trim mime */ + } + else { + r = 0; + subject.len = 0; + } + return r; +} + +int main(argc,argv) +int argc; +char **argv; +{ + char *dir,*cp; + unsigned long msgnum = 0L; + unsigned long msgmax; + int opt,r; + + while ((opt = getopt(argc,argv,"dDf:FvV")) != opteof) + switch (opt) { + case 'd': flagdate = 1; break; + case 'D': flagdate = 0; break; + case 'f': if (optarg) (void) scan_ulong(optarg,&msgnum); break; + case 'F': msgnum = 0L; + case 'v': + case 'V': strerr_die2x(0,"ezmlm-archive version: ",EZIDX_VERSION); + default: die_usage(); + } + dir = argv[optind]; + if (!dir) die_usage(); + + if (chdir(dir) == -1) + strerr_die4sys(100,FATAL,ERR_SWITCH,dir,": "); + + (void) umask(022); + sig_pipeignore(); + /* obtain lock to write index files */ + fdlock = open_append("lock"); + if (fdlock == -1) + strerr_die2sys(100,FATAL,ERR_OPEN_LOCK); + if (lock_ex(fdlock) == -1) + strerr_die2sys(100,FATAL,ERR_OBTAIN_LOCK); + + getconf_line(&charset,"charset",0,FATAL,dir); + if (!stralloc_0(&charset)) die_nomem(); + + getconf_line(&prefix,"prefix",0,FATAL,dir); + /* support rfc2047-encoded prefix */ + decodeHDR(prefix.s,prefix.len,&line,charset.s,FATAL); + unfoldHDR(line.s,line.len,&prefix,charset.s,&dummy,0,FATAL); + /* need only decoded one */ + + /* Get message number */ + switch(slurp("num",&num,32)) { + case -1: + strerr_die4sys(100,FATAL,ERR_READ,dir,"/num: "); + case 0: + strerr_die4x(100,FATAL,dir,"/num",ERR_NOEXIST); + } + if (!stralloc_0(&num)) die_nomem(); + scan_ulong(num.s,&msgmax); + if (msgnum > msgmax) _exit(0); + if (msgnum) { + msgnum = (msgnum / 100) * 100 - 1; + } + while (++msgnum <= msgmax) { + if (msgnum == 1 || !(msgnum % 100)) { + if (!stralloc_copys(&fnadir,"archive/")) die_nomem(); + if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100))) + die_nomem(); + if (!stralloc_copy(&fnifn,&fnadir)) die_nomem(); + if (!stralloc_copy(&fnif,&fnadir)) die_nomem(); + if (!stralloc_cats(&fnif,"/index")) die_nomem(); + if (!stralloc_cats(&fnifn,"/indexn")) die_nomem(); + if (!stralloc_0(&fnadir)) die_nomem(); + if (!stralloc_0(&fnifn)) die_nomem(); + if (!stralloc_0(&fnif)) die_nomem(); + + /* May not exist, so be nice and make it */ + if (mkdir(fnadir.s,0755) == -1) + if (errno != error_exist) + strerr_die4sys(100,FATAL,ERR_CREATE,fnadir.s,": "); + + /* Open index */ + fdindexn = open_trunc(fnifn.s); + if (fdindexn == -1) + strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s,": "); + + /* set up buffers for index */ + substdio_fdbuf(&ssindex,write,fdindexn,indexbuf,sizeof(indexbuf)); + + /* Get subject without the 'Subject: ' */ + /* make sure there is one */ + } + + if (!stralloc_copys(&fnaf,fnadir.s)) die_nomem(); + if (!stralloc_cats(&fnaf,"/")) die_nomem(); + if (!stralloc_catb(&fnaf,strnum, + fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem(); + if (!stralloc_0(&fnaf)) die_nomem(); + fd = open_read(fnaf.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(100,FATAL,ERR_READ,fnaf.s,": "); + } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) + close(fd); + else { + subject.len = 0; /* clear in case they're missing in msg */ + author.len = 0; + received.len = 0; + r = idx_get_trimsubject(); + close(fd); + if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem(); + if (!stralloc_cats(&line,": ")) die_nomem(); + makehash(subject.s,subject.len,hash); + if (!stralloc_catb(&line,hash,HASHLEN)) die_nomem(); + if (!stralloc_cats(&line," ")) die_nomem(); + if (r & 1) /* reply */ + if (!stralloc_cats(&line,"Re: ")) die_nomem(); + if (!stralloc_cat(&line,&subject)) die_nomem(); + if (!stralloc_cats(&line,"\n\t")) die_nomem(); + if (!stralloc_cat(&line,&received)) die_nomem(); + if (!stralloc_cats(&line,";")) die_nomem(); + + concatHDR(author.s,author.len,&lines,FATAL); + mkauthhash(lines.s,lines.len,hash); + if (!stralloc_catb(&line,hash,HASHLEN)) die_nomem(); + + decodeHDR(cp,author_name(&cp,lines.s,lines.len),&author,charset.s,FATAL); + (void) unfoldHDR(author.s,author.len,&lines,charset.s,&prefix,0,FATAL); + + if (!stralloc_cats(&line," ")) die_nomem(); + if (!stralloc_cat(&line,&lines)) die_nomem(); + if (!stralloc_cats(&line,"\n")) die_nomem(); + if (substdio_put(&ssindex,line.s,line.len) == -1) + strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s, ": "); + } + + if (!((msgnum + 1) % 100) || + (msgnum == msgmax)) { /* last in this set */ + if (substdio_flush(&ssindex) == -1) + strerr_die4sys(100,FATAL,ERR_FLUSH,fnifn.s, ": "); + if (fsync(fdindexn) == -1) + strerr_die4sys(100,FATAL,ERR_SYNC,fnifn.s, ": "); + if (fchmod(fdindexn,MODE_ARCHIVE | 0700) == -1) + strerr_die4sys(100,FATAL,ERR_WRITE,fnifn.s, ": "); + if (close(fdindexn) == -1) + strerr_die4sys(100,FATAL,ERR_CLOSE,fnifn.s,": "); + if (rename(fnifn.s,fnif.s) == -1) + strerr_die4x(111,FATAL,ERR_MOVE,fnifn.s,": "); + } + } + fd = open_append("indexed"); + if (fd == -1) + strerr_die4sys(100,FATAL,ERR_CREATE,dir,"/indexed: "); + close(fd); + close(fdlock); + _exit(0); +} + diff --git a/ezmlm-issubn.1 b/ezmlm-issubn.1 new file mode 100644 index 0000000..59affa0 --- /dev/null +++ b/ezmlm-issubn.1 @@ -0,0 +1,74 @@ +.TH ezmlm-issubn 1 +.SH NAME +ezmlm-issubn \- test to see if an address is subscribed to a mailing list +.SH SYNOPSIS +.B ezmlm-issubn +[ +.B \-nN +] +.I dir +.I [ dir1 ... ] +.SH DESCRIPTION +.B ezmlm-issubn +checks to see if the address obtained from the environment variable +.I SENDER +is subscribed to the mailing list stored in +.I dir +or the mailing list in +.I dir1 +or ... + +If +.I SENDER +is not defined +.B ezmlm-issubn +exits with an error. + +If +.I SENDER +is on [any of] the mailing list[s], +.B ezmlm-issubn +exits with a zero exit code. + +If +.I box\fB@\fIdomain +is not on the mailing list, +.B ezmlm-issubn +exits 99. This exit code is non-success from a shell point of view, but to +qmail it means "success and skip remaining lines in the .qmail file). Thus, +a simple way to execute a delivery if the +.ezmlm-issubn +criteria are met is to place the +.B ezmlm-issubn +line first, followed by the action line. If SENDER is a subscriber, the +action line is executed, if not, the line is ignored without the generation +of an error condition. To generate a fatal error, just: + +.EX +|/path/ezmlm-issubn +.I dir1 ... +|| (echo "err msg"; exit 100) + +|/path/action_for_subscribers +|/path/more_for_subscribers +.EE + +.B ezmlm-issubn +exits 100 on permanent and 111 on temporary errors. +.SH OPTIONS +.TP +.B \-n +Negate exit code. Exit 99 if SENDER is a subscriber and exit 0 if not. +This is useful when trying to exclude SENDERs. +.TP +.B \-N +(Default.) +Normal exit codes: 0 is the address is in any of the lists, 99 if not. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm(5) diff --git a/ezmlm-issubn.c b/ezmlm-issubn.c new file mode 100644 index 0000000..3440b23 --- /dev/null +++ b/ezmlm-issubn.c @@ -0,0 +1,64 @@ +/*$Id: ezmlm-issubn.c,v 1.13 1999/08/07 20:45:16 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "strerr.h" +#include "env.h" +#include "subscribe.h" +#include "sgetopt.h" +#include "errtxt.h" +#include "idx.h" + +#define FATAL "ezmlm-issubn: fatal: " + +void *psql = (void *) 0; + +void die_usage() +{ + strerr_die1x(100,"ezmlm-issubn: usage: ezmlm-issubn [-nN] dir [dir1 ...]"); +} + +void die_sender() +{ + strerr_die2x(100,FATAL,ERR_NOSENDER); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *addr; + int flagsub = 0; + int opt; + + addr = env_get("SENDER"); + if (!addr) die_sender(); /* REQUIRE sender */ + + while ((opt = getopt(argc,argv,"nNvV")) != opteof) + switch(opt) { + case 'n': flagsub = 99; break; + case 'N': flagsub = 0; break; + case 'v': + case 'V': strerr_die2x(0, + "ezmlm-issubn version: ezmlm-0.53+",EZIDX_VERSION); + default: + die_usage(); + } + + dir = argv[optind]; + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); + + while ((dir = argv[optind++])) { + if (dir[0] != '/') + strerr_die2x(100,FATAL,ERR_SLASH); + if (issub(dir,addr,(char *) 0,FATAL)) { + closesql(); + _exit(flagsub); /* subscriber */ + } + } + closesql(); + if (flagsub) /* not subscriber anywhere */ + _exit(0); + else + _exit(99); +} diff --git a/ezmlm-limit.1 b/ezmlm-limit.1 new file mode 100644 index 0000000..e977a10 --- /dev/null +++ b/ezmlm-limit.1 @@ -0,0 +1,127 @@ +.TH ezmlm-limit 1 +.SH NAME +ezmlm-limit \- Limits traffic to list +.SH SYNOPSIS +.B ezmlm-limit +[ +.B -f\fI file +][ +.B -dDF +][ +.B \-t +.I secs +][ +.B -n +.I msgs +] +.I dir + +.B ezmlm-limit +is intended to limit traffic to a list in case an outside +source sends excessive messages. Traffic is limited by converting the list +to a message moderated list, or by deferring messages. + +.B ezmlm-limit +reads +.IR dir\fB/loopnum . +If it does not exist or contains a time stamp more than +.I secs +seconds old, it is updated. +If it exists, contains a time stamp less than +.I secs +seconds old, and +.I msgs +messages or more have passed since +.I dir\fB/loopnum +was created, +.B ezmlm-limit +creates +.IR dir\fB/modpost . +For lists set up with +.B ezmlm-store(1) +this results in future messages being moderated. + +As long as +.I dir\fB/modpost +does not exist, +.B ezmlm-store(1) +will simply forward the message to +.BR ezmlm-send(1). +Once +.I dir\fB/modpost +exists, messages will be queued for moderation. Thus, in case of error (such +as misconfigured auto responders) subscribers are spared +messages in excess of the limit. However, no messages are lost, since the +moderator(s) can (selectively) approve queued messages. + +If +.I dir\fB/modpost +already exists, +.B ezmlm-limit +will not take any action. + +Resetting the list requires manual +removal of +.IR dir\fB/modpost . Queued messages can be managed with regular moderation +or approved in bulk with +.BR ezmlm-accept(1) . + +.B ezmlm-limit +is not required for normal lists, since qmail and +ezmlm loop detection prevent problems caused by regular bounces. However, +it affords some protection against malice, and severely misconfigured +subscribers. + +.SH OPTIONS +.TP +.B \-d +Defer excess traffic. Excess messages are deferred and qmail will re-deliver. As +a consequence, traffic will be throttled to the maximum allowed. Due to qmail +delivery back-off, messages may not be disseminated in the order received. If +traffic is continuously above or close to the limit, some messages may be +delayed for a long time or even bounced. +.TP +.B \-D +(Default.) +Make the list moderated once excess traffic is detected. This requires the +list to be configured up with +.B ezmlm-store(1) +rather than +.BR ezmlm-send(1) , +which is easiest done by first creating a message moderated list, then removing +.IR dir\fB/modpost . +.TP +.B \-n\fI msgs +Trigger after +.I msgs +messages (default 30). +.TP +.B \-f\fI file +Instead of +.I dir\fB/loopnum +use +.I file +as the time stamp. This allows the use of multiple instances of +.B ezmlm-limit +for the same list. For instance, you may allow 60 messages per hour with one +instance and 150 messages per day with another. If +.I file +is relative, this is relative to +.IR dir . +.TP +.B \-F +(Default.) +Use +.I dir\fB/loopnum +as the time stamp. +.TP +.B \-t\fI secs +Check the number of messages within period of +.I secs +seconds (default 3600 seconds). +.SH "SEE ALSO" +ezmlm-accept(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-store(1), +ezmlm(5) diff --git a/ezmlm-limit.c b/ezmlm-limit.c new file mode 100644 index 0000000..9e21774 --- /dev/null +++ b/ezmlm-limit.c @@ -0,0 +1,134 @@ +/*$Id: ezmlm-limit.c,v 1.2 1999/10/31 18:58:48 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#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); +} diff --git a/ezmlm-list.1 b/ezmlm-list.1 index 38e140a..352989a 100644 --- a/ezmlm-list.1 +++ b/ezmlm-list.1 @@ -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 @@ the addresses in a mailing list are under the control 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), diff --git a/ezmlm-list.c b/ezmlm-list.c index c6ec801..644c514 100644 --- a/ezmlm-list.c +++ b/ezmlm-list.c @@ -1,62 +1,88 @@ -#include "stralloc.h" -#include "substdio.h" -#include "getln.h" +/*$Id: ezmlm-list.c,v 1.15 1999/09/12 20:25:33 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ #include "strerr.h" -#include "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); } diff --git a/ezmlm-make.1 b/ezmlm-make.1 index 834feed..ef898d8 100644 --- a/ezmlm-make.1 +++ b/ezmlm-make.1 @@ -4,12 +4,19 @@ ezmlm-make \- create a new mailing list .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, @@ -20,6 +27,45 @@ All mailing list information is stored in a new directory, .IR dir . .I dir must be an absolute pathname, starting with a slash. +.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 @@ -38,12 +84,49 @@ these .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 @@ -54,34 +137,872 @@ by .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 +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 +.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 +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 +.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 ``'' 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) diff --git a/ezmlm-make.c b/ezmlm-make.c index 09d2b3e..11fc6f4 100644 --- a/ezmlm-make.c +++ b/ezmlm-make.c @@ -1,3 +1,6 @@ +/*Id: ezmlm-make.c,v 1.31 1997/12/08 23:44:02 lindberg Exp lindberg $*/ +/*$Name: ezmlm-idx-040 $*/ + #include #include #include "sgetopt.h" @@ -9,41 +12,89 @@ #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() @@ -54,11 +105,8 @@ 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; @@ -76,8 +124,12 @@ 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(); } @@ -86,14 +138,15 @@ char *slash; { 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; @@ -101,335 +154,508 @@ char *slash; 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) { /* => 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); } + diff --git a/ezmlm-manage.1 b/ezmlm-manage.1 index a68438f..940a766 100644 --- a/ezmlm-manage.1 +++ b/ezmlm-manage.1 @@ -2,13 +2,14 @@ .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 @@ -52,6 +53,56 @@ expects 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 @@ -65,6 +116,186 @@ field, 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 @@ -75,7 +306,25 @@ where 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 @@ -97,12 +346,84 @@ Actions of 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 @@ -112,18 +433,146 @@ is 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) diff --git a/ezmlm-manage.c b/ezmlm-manage.c index d40ba0f..134c5a0 100644 --- a/ezmlm-manage.c +++ b/ezmlm-manage.c @@ -1,3 +1,6 @@ +/*$Id: ezmlm-manage.c,v 1.86 1999/12/23 02:43:55 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + #include #include #include "error.h" @@ -22,13 +25,56 @@ #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}; @@ -37,34 +83,200 @@ stralloc inlocal = {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; @@ -77,127 +289,528 @@ 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)); +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: \nList-Post: \nList-Subscribe: \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: &/:%+#",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(); @@ -207,138 +820,488 @@ char **argv; } } 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(); @@ -349,20 +1312,20 @@ char **argv; 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,"> "); @@ -371,33 +1334,72 @@ char **argv; } 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); } } + diff --git a/ezmlm-mktab b/ezmlm-mktab new file mode 120000 index 0000000..feb8cc6 --- /dev/null +++ b/ezmlm-mktab @@ -0,0 +1 @@ +sub_std/ezmlm-mktab \ No newline at end of file diff --git a/ezmlm-mktab.1 b/ezmlm-mktab.1 new file mode 100644 index 0000000..e593986 --- /dev/null +++ b/ezmlm-mktab.1 @@ -0,0 +1,61 @@ +.TH ezmlm-mktab 1 +.SH NAME +ezmlm-mktab \- create SQL table definition for ezmlm list +.SH SYNOPSIS +.B ezmlm-mktab +[ +.B \-dC +] +.I table_root +.SH DESCRIPTION +.B ezmlm-mktab +takes +.I table_root +and prints table definitions for +.IR table_root , +.IR table_root\fB_slog , +etc. All subscriber +and log tables are defined, although normally only a subset are used. + +.B ezmlm-mktab +also can also print the SQL drop commands to remove the same tables. +.SH OPTIONS +.TP +.B \-C +Do not print the table definitions for list creation. By default, table +definitions are printed. +.TP +.B \-d +Print table drop commands. Normally, they are omitted. When printed, they +are printed before the table definitions, so that existing tables are removed, +then recreated. +.SH USAGE +.B ezmlm-mktab +.B \-d +.I list \fR | mysql -hhost -uuser -p -f db + +This connects to the mysql server on ``host'' as ``user'' (prompting for +the password) and in database ``db'' creates tables +.IR list , +.IR list\fB_slog , +.IR list\fB_mlog , +the corresponding table sets for address lists +.IR list\fB_allow , +.IR list\fB_deny , +.IR list\fB_digest, +.IR list\fB_mod, +as well as +.IR list\fB_name , +.IR list\fB_digest_name , +.IR list\fB_cookie , +and +.IR list\fB_digest_cookie . + +Since the +.B \-d +switch is used, any of these tables already existing are first dropped, +with loss of any data already in them. +.SH "SEE ALSO" +ezmlm-send(1), +ezmlm(5), +mysql(1) diff --git a/ezmlm-moderate.1 b/ezmlm-moderate.1 new file mode 100644 index 0000000..a05c891 --- /dev/null +++ b/ezmlm-moderate.1 @@ -0,0 +1,170 @@ +.TH ezmlm-moderate 1 +.SH NAME +ezmlm-moderate \- process moderator actions for message +acceptance and rejection +.SH SYNOPSIS +.B ezmlm-moderate [-cCmMrRvV] +.B [-t\fI reply-to@host\fB] +.I dir ['/path/program args'] + +.SH DESCRIPTION +.B ezmlm-moderate +reads a mail message, expecting it to contain an +.I -accept +or +.I -reject +action request for the mailing list stored in +.I dir. + +.B ezmlm-moderate +verifies the cookie sent as part of the action request, and if correct +attempts to find the corresponding message in +.IR dir\fB/mod/pending/ . +If the message is found, it is either rejected or posted to the list, +depending on the action request. + +Posts to the list are handled by +piping the message to +.B ezmlm-send(1) +located in the ezmlm binary directory, as set at compile time. This is +usually the directory that ezmlm-moderate resides in. +.B ezmlm-send(1) +is provided with +.I dir +as the first argument. + +If the optional second argument is given, +.B ezmlm-moderate +pipes the message to that program, as executed by sh. +No parameters are supplied. + +.I dir +is passed as an argument to +.BR ezmlm-send(1) , +but NOT to any program specified as the optional +.B ezmlm-moderate +command line argument. + +.B ezmlm-moderate +does not bother to correctly set sender. +.B ezmlm-send(1) +doesn't care, and any other program that might be used can parse the +sender from the first line of the message, which is always +.I Return-Path: +as build from SENDER originally passed to +.BR ezmlm-store(1) . + +If the message is rejected, an optional moderator comment is copied into the +notification to the message sender. +A moderator comment is any text in the +.I -reject +request found between two lines with ``%%%'' starting in one of the first +5 positions of the line. The easiest is to use lines consisting of ``%%%'' +only. If the characters preceeding the ``%%%'' are found at the beginning +of any lines within the comment, the characters are removed. This is to +appropriately ignore any ``quote marks'' that you mail program might place at +the beginning of lines in a reply. + +.B ezmlm-moderate +messages are sent ``From:'' +.IR list-owner@listhost . +This allows the poster to easily complain to the owner of the list, in case +s/he objects. An optional ``Reply-To:'' header can be added via the +.BR \-r\fI\ reply-to@host . + +Once the message has been successfully accepted or rejected, it is removed from +.I dir\fB/mod/pending/ +and a stub is created in +.I dir\fB/mod/accepted/ +or +.IR dir\fB/mod/rejected/ , +respectively. +This is done in order to be able to notify the senders of later moderation +requests about the fate of the message. + +A failure to find the message in +.I dir\fB/mod/pending/ +is most often caused by the message already having been accepted or rejected +by another moderator. Therefore, +.B ezmlm-moderate +looks in +.I dir\fB/mod/accepted/ +and +.I dir\fB/mod/rejected/ +for a message stub. If found, +.B ezmlm-moderate +notifies the sender in the form of a fatal error +if the fate of the message was different from +that intended by the current action request. +Otherwise, the fate of the message is silently logged. + +If the message is not found, it has timed out and the message or +the message stub has been removed by +.BR ezmlm-clean(1) . +In this case, +.B ezmlm-moderate +notifies the moderator of the failure, but can no longer discern the fate +of the original message. Again, notification is in the form of a fatal +error from qmail. + +At the beginning of the message, +.B ezmlm-moderate +prints a new +.B Mailing-List +field with the contents of +.IR dir\fB/mailinglist . +It rejects the message if there is already a +.B Mailing-List +field. + +.B ezmlm-moderate +does not distribute bounce messages: +if the environment variable +.B SENDER +is set, and is either empty or +.BR #@[] , +.B ezmlm-moderate +rejects the message. +.SH OPTIONS +.TP +.B \-cCrR +Passed on to ezmlm-send(1). +.TP +.B \-m +(Default.) +The rejected post is sent as a MIME enclosure. +.TP +.B \-M +The rejected post is appended to the message. +.TP +.B \-t\fI reply-to@host +A ``Reply-To: +.IR reply-to@host '' +header will be added to the moderation request. +.TP +.TP +.B \-v +Display +.B ezmlm-moderate +version information. +.TP +.B \-V +Display +.B ezmlm-moderate +version information. +.SH "CHARACTER SETS" +If +.I dir\fB/charset +exists, +.B ezmlm-moderate +will use the character set listed for all messages. Otherwise, the +default ``us-ascii'' will be used. The character set can be suffixed +by ``:'' followed by a code. If the code is ``Q'', outgoing messages are +sent as ``Quoted-Printable'', if it is ``B'' they are sent ``base64'' encoded. +Otherwise, text is sent as is. +.SH "SEE ALSO" +ezmlm-clean(1), +ezmlm-make(1), +ezmlm-send(1), +ezmlm-store(1), +ezmlm(5) diff --git a/ezmlm-moderate.c b/ezmlm-moderate.c new file mode 100644 index 0000000..363d207 --- /dev/null +++ b/ezmlm-moderate.c @@ -0,0 +1,611 @@ +/*$Id: ezmlm-moderate.c,v 1.42 1999/10/09 16:49:56 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#include +#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); + } +} diff --git a/ezmlm-receipt.1 b/ezmlm-receipt.1 new file mode 100644 index 0000000..cc6531c --- /dev/null +++ b/ezmlm-receipt.1 @@ -0,0 +1,129 @@ +.TH ezmlm-receipt 1 +.SH NAME +ezmlm-receipt \- handle sublist replies at the main list +.SH SYNOPSIS +.B ezmlm-receipt +[ +.B \-dD +] +.I dir +.SH DESCRIPTION +.B ezmlm-receipt +handles mail from sublists of the main list +stored in +.I dir +and, if it exists, the associated main digest list. +.B ezmlm-receipt +is used for main list with only sublists as subscribers. It is not +useful for normal mailing lists. + +.B ezmlm-receipt +is normally invoked from a +.B .qmail +file. +It reads a mail message from its standard input, +and a mail envelope from the +.BR SENDER , +.BR LOCAL , +and +.BR HOST +environment variables. + +.B ezmlm-receipt +has two functions. It takes the place of +.B ezmlm-receipt(1) +for main lists that have only sublists as subscribers. +Bounces do not lead to removal of the bouncing +address. +.B emzlm-receipt +saves the +bounce, and logs the event to the mail log. +.B ezmlm-receipt +also saves the bounce to +.I dir\fB/bounce/dnnn.ppp +where +.B nnn +is a time stamp and +.B ppp +the PID of the process. A maximum of 50 bounces are saved. Further bounces +are discarded until room is made in the bounce directory by manually removing +files. +If the list uses and SQL +database, the even is logged to the _mlog table instead, and only if the +distribution cookie matches. The bounce is still saved, but only if it +contained a matching distribution cookie. + +.B ezmlm-receipt +also handles feedback messages from the sublist. These are used to monitor +that the sublist is able to send out messages. Receipt of feedback messages +is logged to the mail log. +If the list uses and SQL +database, the even is logged to the _mlog table instead, and only if the +distribution cookie matches. +.SH OPTIONS +.TP +.B \-d +.B ezmlm-receipt +will assume the message is for a digest list. +Normally, +.B ezmlm-receipt +will autodetect this from the bounce address. Autodetection makes +.B ezmlm-receipt +less flexible and will be removed in future versions. +.TP +.B \-D +.B ezmlm-receipt +will assume that the bounce is for a normal (non-digest) list. +Normally, +.B ezmlm-receipt +will autodetect this from the bounce address. Autodetection makes +.B ezmlm-receipt +less flexible and will be removed in future versions. +.B \-D +will become the default. +.SH ADDRESSES +.B ezmlm-receipt +handles mail sent to any of the following addresses: +.TP +.I local\fB\-return\- +Trash. +A help message or subscription acknowledgment bounced. +.TP +.I local\fB\-return\-\fImsg\fB\-\fIbox\fB=\fIdomain +Distribution bounce. +Message number +.I msg +was lost on the way to the sublist +.IR box\fB@\fIdomain . +.TP +.I local\fB\-return\-\fImsg\fB\- +Pre-VERP distribution bounce, in QSBMF format. +Message number +.I msg +was lost on the way to one or more sublists; +.B ezmlm-receipt +will parse the bounce to figure out the addresses. +.TP +.I local\fB\-return\-receipt +Feedback message from a sublist. +.B ezmlm-receipt +will figure out message number and sublist address from the envelope sender. + +For all the above addresses if, +.I local +is followed by +.IR \-digest , +messages are assumed to relate to the digest list, and are stored in +.I dir\fB/digest/bounce +rather than in +.I dir \fB/bounce . +.SH "SEE ALSO" +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-return(1), +ezmlm-send(1), +ezmlm-sub(1), +ezmlm-unsub(1), +ezmlm-weed(1), +ezmlm(5), +qmail-command(8) diff --git a/ezmlm-receipt.c b/ezmlm-receipt.c new file mode 100644 index 0000000..7b664f9 --- /dev/null +++ b/ezmlm-receipt.c @@ -0,0 +1,374 @@ +/*$Id: ezmlm-receipt.c,v 1.10 1999/02/05 04:57:44 lindberg Exp $*/ +/*$Name: ezmlm-idx-0324 $*/ +/* Handles receipts and bounces from sublists at the main list */ +/* Set up instead of ezmlm-return in DIR/bouncer of main list */ + +#include +#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); +} + diff --git a/ezmlm-reject.1 b/ezmlm-reject.1 index cb8cb7a..643ceb8 100644 --- a/ezmlm-reject.1 +++ b/ezmlm-reject.1 @@ -4,29 +4,149 @@ ezmlm-reject \- reject messages unsuitable for distribution .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) diff --git a/ezmlm-reject.c b/ezmlm-reject.c index ffeea99..55195e0 100644 --- a/ezmlm-reject.c +++ b/ezmlm-reject.c @@ -4,79 +4,450 @@ #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); } diff --git a/ezmlm-request.1 b/ezmlm-request.1 new file mode 100644 index 0000000..4f63e19 --- /dev/null +++ b/ezmlm-request.1 @@ -0,0 +1,216 @@ +.TH ezmlm-request 1 +.SH NAME +ezmlm-request \- Process subject line and body ezmlm commands +.SH SYNOPSIS +.B ezmlm-request +[ +.B \-f\fI config +] +.I dir +.SH DESCRIPTION +.B ezmlm-request +processes ezmlm commands in the subject line or message body. +.B ezmlm-request +enables these uses to send the message to +.I list\fB\-request\fI@host +with the complete command address line in the subject field, +or with commands and arguments separated by white +space. +.B ezmlm-request +uses the text to construct a ezmlm command message to the list. +If the subject does not start with a letter, +.B ezmlm-request +instead uses the first body line that starts with a letter. Processing +terminates if a line with a hyphen in the first position is encountered. + +All commands are expected to be in ezmlm command address format or formatted +as: + +.EX +.BR command [list@listhost [user@userhost]] +.EE + +.B ezmlm-request +when invoked with the +.B \-f +switch and a configuration file (see below), ignores the subject and processes +the first body line (per rules above) in conjunction with the configuration +file. It also services the +.B lists +and +.B which +commands. This can be used +to construct a global list interface, similar to that used by some other +mailing list managers. + +Messages at the +.I list\fB\-request\fI@host +are restricted to the local list. When +.B ezmlm-request +is invoked with the +.B \-f\fI config +switch, command messages are limited to lists in +.I config +or at the local host. + +Invalid requests for an existing ezmlm list will +lead to a ``help'' message from +.BR ezmlm-manage(1) . +.SH OPTIONS +.TP +.B \-f\fI config +Function as a global interface to ezmlm lists in accordance with +.IR config. +This file consists of lines starting in the first position +with ``list@host:listdir:description''. Lines that are blank or start + with ``#'' are ignored. ``listdir'' +and ``description'' are optional. If only ``list@host'' is given, the list +is used to restrict commands (see below), but not listed. To allow the list +to be shown by a ``list'' command, use ``list@host:''. To specify only +the list name and description, use ``list@host::description''. +If ``listdir'' is +present, the +.B which +command attempts to determine if the user is a subscriber of the list. +.B NOTE: +this will work only if the user running +.B ezmlm-request +has read access to the lists subscriber database. + +If ``listhost'' is not specified, +.B ezmlm-request +will use the ``listhost'' from the first +.I config +entry matching ``listlocal''. If ``listhost'' is specified, but not found +in +.IR config , +it is set to the contents of +.IR dir\fB/outhost . +.SH USAGE +Place an invocation of +.B ezmlm-request +in +.I dir\fB/manager +anywhere before the +.B ezmlm-manage(1) +line. + +Alternatively, set up +.I dir\fB/request +with an invocation of +.BR ezmlm-request . +Make a link from +.I ~/.qmail-list-request +to this file. + +For the global interface, place +.B /path/ezmlm-request -f \fIconfig dir +into a file. +Link +.I ~/.qmail-ezmlm +and +.I ~/.qmail-ezmlm-default +to this file. The latter allows +.B ezmlm-request +to handle its own bounces as well as to reply to messages to e.g. +\``user-ezmlm-lists@listhost''. +Create +.IR dir\fB/inlocal +and +.IR dir\fB/outlocal +with ``user-ezmlm'', +.IR dir\fB/outhost +with ``listhost'', +.IR dir\fB/headerremove +with headers to be stripped (copy from a list), +.IR dir/text\fB/help , +.IR dir/text\fB/top , +and +.I dir/text\fB/bottom +with the appropriate texts. +Also, create +.I config +with the appropriate contents. + +Mail to ``user-ezmlm@listhost'' will now be answered by +.BR ezmlm-request . +.SH "RECOGNIZED COMMANDS" +Any command not recognized by +.B ezmlm-request +is assumed to be valid, as long as it consists of only letters, numbers, +hyphen, underscore, period, and ``+''. This allows +.B ezmlm-request +to correctly handle commands added by the list owner. + +A number of commands are recognized by +.B ezmlm-request +but not processed. Instead they are mapped to +.B help +without arguments. These +are: +.BR system , +.BR put , +and +.BR set . + +.B ezmlm-request +also handles a number of aliases for ezmlm commands. Since +.B ezmlm-request +only passes on requests to the list, local restrictions apply. +For commands that have aliases, accepted aliases are listed: +.TP +.B subscribe +sub +.TP +.B unsubscribe +unsub, signoff, remove. +.TP +.B index +ind. +.TP +.B list +recipients, showdist, review, rev, who. +.TP + +Some commands are handled differently when used without arguments: +.TP +.B query +Treated like ``which''. +.TP +.B list +Treated like ``lists''. +.SH BUGS +.B ezmlm-request +places stricter requirements on addresses than rfc822. Thus, some addresses +that are rfc822-compliant cannot be used as +.B ezmlm-request +command arguments. If you fix this, +please send a patch to lindberg@id.wustl.edu. I think qmail has the same +restriction, though. + +.B ezmlm-request +uses NUL as a line terminator internally. Thus, if will fail if NUL is found +within the line it tries to interpret as a command. It is harmless, other than +that the remainder of the line will be ignored. + +The +.B ezmlm-request +\``which'' +command does not differentiate between a list for which the command is not +available, a list for which the subscriber db is not accessible, and a list +for which the address is not a subscriber. This should be considered a feature. +.SH BUGS +.B ezmlm-request +when used as a global interface and receiving multipart messages assumes that +the first line of the fist part is the command. Further, it assumes that the +first line starting``--'' is the first MIME boundary. This is virtually +always true, but it is easy to construct legal messages that do not fit these +assumptions. +.B ezmlm-request +in the global interface role +will fail if this first part or the entire message is base64 encoded. +.SH "SEE ALSO" +ezmlm-get(1), +ezmlm-manage(1), +ezmlm-send(1), +ezmlm(5) diff --git a/ezmlm-request.c b/ezmlm-request.c new file mode 100644 index 0000000..661616d --- /dev/null +++ b/ezmlm-request.c @@ -0,0 +1,826 @@ +/*$Id: ezmlm-request.c,v 1.34 1999/08/18 01:50:04 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "subfd.h" +#include "strerr.h" +#include "error.h" +#include "qmail.h" +#include "env.h" +#include "sig.h" +#include "open.h" +#include "getln.h" +#include "case.h" +#include "str.h" +#include "datetime.h" +#include "date822fmt.h" +#include "now.h" +#include "quote.h" +#include "readwrite.h" +#include "exit.h" +#include "substdio.h" +#include "getconf.h" +#include "constmap.h" +#include "fmt.h" +#include "sgetopt.h" +#include "byte.h" +#include "seek.h" +#include "errtxt.h" +#include "copy.h" +#include "idx.h" + +#define FATAL "ezmlm-request: fatal: " +#define INFO "ezmlm-request: info: " + +void die_usage() +{ + strerr_die1x(100,"ezmlm-request: usage: ezmlm-request [-f lists.cfg] dir"); +} + +void die_nomem() +{ + strerr_die2x(111,FATAL,ERR_NOMEM); +} + +void die_badaddr() +{ + strerr_die2x(100,FATAL,ERR_BAD_ADDRESS); +} + +char strnum[FMT_ULONG]; + +void *psql = (void *) 0; + +char *userlocal = (char *) 0; +char *userhost = (char *) 0; +char *listlocal = (char *) 0; +char *listhost = (char *) 0; +char *cfname = (char *) 0; +char *command = "help"; +stralloc line = {0}; +stralloc qline = {0}; +stralloc usr = {0}; +stralloc lhost = {0}; +stralloc subject = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; +stralloc listname = {0}; +stralloc hostname = {0}; +stralloc outhost = {0}; +stralloc headerremove = {0}; +stralloc mailinglist = {0}; +stralloc cmds = {0}; +stralloc from = {0}; +stralloc to = {0}; +stralloc charset = {0}; +char *boundary = "zxcaeedrqcrtrvthbdty"; /* cheap "rnd" MIME boundary */ +int flagcd = '\0'; /* no encoding by default */ + +struct constmap headerremovemap; +struct constmap commandmap; +int flaggotsub = 0; /* Found a subject */ + /* cmdstring has all commands seperated by '\'. cmdxlate maps each */ + /* command alias to the basic command, which is used to construct */ + /* the command address (positive numbers) or handled by this */ + /* program (negative numbers). Note: Any command not matched is */ + /* used to make a command address, so ezmlm request can handle */ + /* ("transmit") user-added commands. */ +const char *cmdstring = + "system\\help\\" /* 1,2 */ + "subscribe\\unsubscribe\\index\\" /* 3,4,5 */ + "info\\list\\query\\" /* 6,7,8 */ + "sub\\unsub\\remove\\signoff\\" /* 9,10,11,12 */ + "lists\\which\\" /* 13,14 */ + "ind\\rev\\review\\recipients\\" /* 15,16,17,18 */ + "who\\showdist\\" /* 19,20 */ + "put\\set"; /* 21,22 */ + + /* map aliases. -> 0 not recognized. -> 1 recognized will be made */ + /* help and arguments scrapped. < 0 handled locally. HELP without */ + /* args also handled locally */ + /* the last are not supported -> help */ +const int cmdxlate[] = { 0,1,2,3,4,5,6,7,8,3,4,4,4,-13,-14,5,7,7,7,7,7, + 1,1 }; + + /* If there are no arguments (listlocal = 0) then commands are mapped*/ + /* through this. This way, help, list, query, ... can mean something */ + /* here even though they have local funcions at the lists if used */ + /* with arguments. (Made same lengh as cmdxlate in case of bugs.) */ + /* Note: This is used ONLY for the global interface */ +const int noargsxlate[] = { 0,1,-2,3,4,5,-2,-13,-14,9,10,11,12,13,14,15,16,17, + 18,19,20,21,22 }; + + /* these need to be defined as the index of the corresponding */ + /* commands. They are handled by ezmlm-request. NOTE: Help is >0! */ +#define EZREQ_LISTS 13 +#define EZREQ_WHICH 14 +#define EZREQ_HELP 2 +#define EZREQ_BAD 1 + +substdio sstext; +char textbuf[1024]; +datetime_sec when; +struct datetime dt; +char date[DATE822FMT]; + +struct qmail qq; + +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return len; +} + +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf)); + +char inbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf)); +substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf)); + +substdio ssout; +char outbuf[1]; + +stralloc mydtline = {0}; + +void transferenc() +{ + if (flagcd) { + qmail_puts(&qq,"\n--"); + qmail_puts(&qq,boundary); + qmail_puts(&qq,"\nContent-Type: text/plain; charset="); + qmail_puts(&qq,charset.s); + qmail_puts(&qq,"\nContent-Transfer-Encoding: "); + if (flagcd == 'Q') + qmail_puts(&qq,"quoted-printable\n\n"); + else + qmail_puts(&qq,"base64\n\n"); + } +} + +int code_qput(s,n) +char *s; +unsigned int n; +{ + if (!flagcd) + qmail_put(&qq,s,n); + else { + if (flagcd == 'B') + encodeB(s,n,&qline,0,FATAL); + else + encodeQ(s,n,&qline,FATAL); + qmail_put(&qq,qline.s,qline.len); + } + return 0; /* always succeeds */ +} + +/* Checks the argument. Only us-ascii letters, numbers, ".+-_" are ok. */ +/* NOTE: For addresses this is more restrictive than rfc821/822. */ +void checkarg(s) +char *s; +{ + register char *cp; + register char ch; + cp = s; + if (!cp) return; /* undef is ok */ + while ((ch = *cp++)) { + if (ch >= 'a' && ch <= 'z') + continue; /* lc letters */ + if (ch >= '0' && ch <='9') /* digits */ + continue; + if (ch == '.' || ch == '-' || ch == '_' || ch == '+') + continue; /* ok chars */ + if (ch >= 'A' && ch <= 'Z') continue; /* UC LETTERS */ + strerr_die4x(100,ERR_NOT_CLEAN,": \"",s,"\""); + } + return; +} + +/* parses line poited to by cp into sz:s as per: */ +/* 1. listlocal-command-userlocal=userhost@listhost */ +/* 2. command userlocal@userhost */ +/* 3. command userlocal@userhost listlocal@listhost */ +/* 4. command listlocal@listhost */ +/* 5. command listlocal[@listhost] userlocal@userhost */ +/* 6. which [userlocal@userhost] */ +/* The first 3 are valid only if !cfname, i.e. -request operation and */ +/* listlocal and listhost are always set to outlocal@outhost. Options */ +/* 4-5 are for the global address (cfname is set). Here listhost is */ +/* taken from the first list in *cfname matching listlocal, or set to */ +/* outhost, if not specified. If specified, it's accepted if it matches */ +/* a list in *cfname and silently set to outhost otherwise. Pointers to */ +/* unspecified parts are set to NULL in this routine to be dealt with */ +/* elsewhere. "Which" special argument order (6) is fixed elsewhere. */ +/* If listhost is not given, "@outhost" is added. Absence of 'userhost' */ +/* is accepted to allow commands that take arguments that are not */ +/* addresses (e.g. -get12-34). */ + +void parseline(cp) +char *cp; + +{ + register char *cp1, *cp2; + char *cp3; + + cp1 = cp; + while (*cp1) { /* make tabs into spaces */ + if (*cp1 == '\t') *cp1 = ' '; + ++cp1; + } + /* NOTE: outlocal has '\0' added! */ + if (outlocal.len < str_len(cp) && cp[outlocal.len -1] == '-' && + case_starts(cp,outlocal.s)) { /* normal ezmlm cmd */ + command = cp + outlocal.len; /* after the '-' */ + listlocal = outlocal.s; + listhost = outhost.s; + cp1 = command; + while (*cp1 && *cp1 != '-') ++cp1; /* find next '-' */ + if (*cp1) { + *cp1 = '\0'; + userlocal = ++cp1; /* after '-' */ + cp1 = cp1 + str_rchr(cp1,'@'); /* @ _or_ end */ + *cp1 = '\0'; /* last '=' in userlocal */ + cp1 = userlocal + str_rchr(userlocal,'='); + if (*cp1) { /* found '=' */ + *cp1 = '\0'; /* zap */ + userhost = cp1 + 1; /* char after '=' */ + } + } + } else { /* '@' before ' ' means complete cmd */ + if (str_chr(cp,'@') < str_chr(cp,' ')) /* addr where inlocal failed */ + strerr_die2x(100,FATAL,ERR_REQ_LOCAL); + /* to match */ + command = cp; + cp1 = cp + str_chr(cp,' '); + if (*cp1) { + *cp1++ = '\0'; + while (*cp1 && *cp1 == ' ') ++cp1; /* skip spaces */ + } + cp2 = 0; + if (*cp1) { /* argument */ + cp2 = cp1 + str_chr(cp1,' '); + cp3 = cp2; + while (*cp2 && *cp2 == ' ') ++cp2; /* skip spaces */ + *cp3 = '\0'; + + if (!*cp2) + cp2 = 0; + else { + cp3 = cp2 + str_chr(cp2,' '); + *cp3 = '\0'; + } + } else + cp1 = 0; + + if (!cfname && !cp2) { /* the single arg is user if we serve a */ + cp2 = cp1; /* list. It's list if we serve "domo@" */ + cp1 = 0; + } + if (cp2) { + userlocal = cp2; + cp2 += str_chr(cp2,'@'); + if (*cp2) { + *cp2++ = '\0'; + userhost = cp2; + } + } + if (cp1) { + listlocal = cp1; + cp1 += str_chr(cp1,'@'); + if (*cp1) { + *cp1++ = '\0'; + listhost = cp1; + } + } + } + checkarg(command); /* better safe than sorry */ + checkarg(userlocal); checkarg(userhost); + checkarg(listlocal); checkarg(listhost); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *local; + char *action; + char *def; + char *sender; + char *psz; + char *err; + int cmdidx; + int flagsub; + int flagok; + int flagnosubject; + int match; + int flaginheader; + int flagbadfield; + int flagmultipart = 0; + int fd; + int opt; + unsigned int pos,pos1,len,last; + + (void)umask(022); + sig_pipeignore(); + + while ((opt = getopt(argc,argv,"f:F:vV")) != opteof) + switch(opt) { + case 'F': + case 'f': if (optarg) cfname = optarg; break; + case 'v': + case 'V': strerr_die2x(0,"ezmlm-request version: ",EZIDX_VERSION); + default: + die_usage(); + } + + dir = argv[optind]; + if (!dir) die_usage(); + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); + + /* do minimum to identify request for this program in case */ + /* it's invoked in line with e.g. ezmlm-manage */ + + def = env_get("DEFAULT"); + if (def) { /* qmail>=1.02 */ + action = def; + } else if (cfname) { /* older qmail OR just list-mdomo */ + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL); + len = str_len(local); + if (len >= 8 && !case_diffb(local + len - 8,8,"-return-")) { + action = "return-"; /* our bounce with qmail<1.02 */ + } else + action = ""; /* list-mdomo-xxx won't work for older lists */ + } else { /* older qmail versions */ + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + action = local + inlocal.len; + if (*action) + if (*(action++) != '-') die_badaddr(); /* check anyway */ + } + /* at this point action = "request" or "request-..." for std use; */ + /* "" for majordomo@ */ + if (!cfname) { /* expect request */ + if (case_starts(action,ACTION_REQUEST)) + action += str_len(ACTION_REQUEST); + else if (case_starts(action,ALT_REQUEST)) + action += str_len(ALT_REQUEST); + else + _exit(0); /* not for us */ + } + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + getconf_line(&outhost,"outhost",1,FATAL,dir); + + if (!stralloc_copy(&listname,&outlocal)) die_nomem(); + if (!stralloc_copy(&hostname,&outhost)) die_nomem(); + if (!stralloc_0(&outlocal)) die_nomem(); + if (!stralloc_0(&outhost)) die_nomem(); + + sender = env_get("SENDER"); + if (!sender) strerr_die2x(99,INFO,ERR_NOSENDER); + if (!*sender) + strerr_die2x(99,INFO,ERR_BOUNCE); + if (!sender[str_chr(sender,'@')]) + strerr_die2x(99,INFO,ERR_ANONYMOUS); + if (str_equal(sender,"#@[]")) + strerr_die2x(99,INFO,ERR_BOUNCE); + + getconf(&headerremove,"headerremove",1,FATAL,dir); + constmap_init(&headerremovemap,headerremove.s,headerremove.len,0); + + if (!stralloc_copys(&mydtline, + "Delivered-To: request processor for ")) die_nomem(); + if (!stralloc_cats(&mydtline,outlocal.s)) die_nomem(); + if (!stralloc_cats(&mydtline,"@")) die_nomem(); + if (!stralloc_cats(&mydtline,outhost.s)) die_nomem(); + if (!stralloc_cats(&mydtline,"\n")) die_nomem(); + + flagnosubject = 1; + if (action[0]) { /* mainly to allow ezmlm-lists or ezmlm-which with */ + flagnosubject = 0; /* a command address rather than a complete msg */ + command = action; + if (str_start(action,"return")) /* kill bounces */ + strerr_die2x(0,INFO,ERR_BOUNCE); + pos = 1 + str_chr(action + 1,'-'); + if (action[pos]) { /* start of target */ + action[pos] = '\0'; + userlocal = action + pos + 1; + pos = str_rchr(userlocal,'='); /* the "pseudo-@" */ + if (userlocal[pos]) { + userlocal[pos] = '\0'; + userhost = userlocal + pos + 1; + } + } + } else { + for (;;) { /* Get Subject: */ + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + if (line.len == 1) + break; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flagsub = 0; + + if (case_startb(line.s,line.len,"mailing-list:")) + strerr_die2x(100,FATAL,ERR_MAILING_LIST); + else if (case_startb(line.s,line.len,"Subject:")) { + flaggotsub = 1; + pos = 8; + last = line.len - 2; /* skip terminal '\n' */ + while (line.s[last] == ' ' || line.s[last] == '\t') --last; + while (pos <= last && + (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos; + if (!stralloc_copyb(&subject,line.s+pos,last-pos+1)) die_nomem(); + } else if (case_startb(line.s,line.len,"content-type:")) { + pos = 13; last = line.len - 2; /* not cont-line - ok */ + while (pos <= last && + (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos; + if (case_startb(line.s+pos,line.len - pos,"multipart/")) + flagmultipart = 1; + } else if (line.len == mydtline.len) + if (!byte_diff(line.s,line.len,mydtline.s)) + strerr_die2x(100,FATAL,ERR_LOOPING); + } else if (flagsub) { /* Continuation line */ + pos = 1; + len = line.len - 2; /* skip terminal '\n' */ + while (line.s[len] == ' ' || line.s[len] == '\t') --len; + while (pos < len && + (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos; + if (!stralloc_append(&subject," ")) die_nomem(); + if (!stralloc_copy(&subject,line.s+pos,len-pos+1)) die_nomem(); + } + if (!match) + break; + } + if (!cfname) { /* listserv@/majordomo@ ignore */ + register char ch; + if (!stralloc_0(&subject)) die_nomem(); + ch = *subject.s; /* valid commands/list names start w letter */ + if ((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A')) { + parseline(subject.s); + flagnosubject = 0; + } + } + if (cfname || flagnosubject) { + for (;;) { /* parse body */ + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + if (!match) break; + if (line.len == 1 && flagmultipart != 2) continue; + /* lazy MIME cludge assumes first '--...' is start border */ + /* which is virtually always true */ + if (flagmultipart == 1) { /* skip to first border */ + if (*line.s != '-' || line.s[1] != '-') continue; + flagmultipart = 2; + continue; + } else if (flagmultipart == 2) { /* skip content info */ + if (line.len != 1) continue; + flagmultipart = 3; /* may be part within part */ + continue; /* and blank line */ + } else if (flagmultipart == 3) { + if (*line.s == '-' && line.s[1] == '-') { + flagmultipart = 2; /* part within part */ + continue; + } + } + { + register char ch; + ch = *line.s; + if (line.len == 1 || + !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) + continue; /* skip if not letter pos 1 */ + } + /* Here we have a body line with something */ + if (!stralloc_copy(&subject,&line)) die_nomem(); /* save it */ + subject.s[subject.len-1] = '\0'; + parseline(subject.s); + break; + } + } + } + /* Do command substitution */ + if (!stralloc_copys(&cmds,cmdstring)) die_nomem(); + if (!stralloc_0(&cmds)) die_nomem(); + psz = cmds.s; + while (*psz) { + if (*psz == '\\') *psz = '\0'; + ++psz; + } + if (!constmap_init(&commandmap,cmds.s,cmds.len,0)) die_nomem(); + cmdidx = cmdxlate[constmap_index(&commandmap,command,str_len(command))]; + if (cmdidx == EZREQ_BAD) { /* recognized, but not supported -> help */ + listlocal = 0; /* needed 'cause arguments are who-knows-what */ + listhost = 0; + userlocal = 0; + userhost = 0; + cmdidx = EZREQ_HELP; + } + if (cfname && !listlocal && !userlocal && cmdidx > 0) + cmdidx = noargsxlate[cmdidx]; /* some done differently if no args */ + + /* =0 not found. This is treated as a list command! */ + if (cmdidx < 0 && !cfname) { + cmdidx = EZREQ_HELP; + } + if (qmail_open(&qq,(stralloc *) 0) == -1) + strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); + + if (cmdidx >= 0) { + /* Things handled elsewhere. We do want to handle a simple HELP */ + /* without arguments for e.g. majordomo@ from our own help file */ + + if (!stralloc_copys(&from,sender)) die_nomem(); + if (!stralloc_0(&from)) die_nomem(); + if (!listlocal) { + if (cfname) + strerr_die1x(100,ERR_REQ_LISTNAME); + else + listlocal = outlocal.s; /* This is at the -request address */ + } + /* if !cfname listhost is made outhost. If cfname, listhost=outhost */ + /* is ok. listhost=0 => first match in config. Other listhost is ok */ + /* only if match is found. Otherwise it's set to outhost. */ + + if (!cfname || (listhost && !case_diffs(listhost,outhost.s))) + listhost = outhost.s; + else { /* Check listhost against config file */ + pos = str_len(listlocal); + fd = open_read(cfname); + if (fd == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": "); + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + flagok = 0; /* got listhost match */ + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die3sys(111,FATAL,ERR_READ,cfname); + if (!match) + break; + if (line.len <= 1 || line.s[0] == '#') + continue; + if ((pos < line.len) && (line.s[pos] == '@') && + !byte_diff(line.s,pos,listlocal)) { + last = byte_chr(line.s,line.len,':'); + if (!stralloc_copyb(&lhost,line.s+pos+1,last-pos-1)) die_nomem(); + if (!stralloc_0(&lhost)) die_nomem(); + if (listhost) { + if (!case_diffs(listhost,lhost.s)) { + flagok = 1; + break; /* host did match */ + } else + continue; /* host didn't match */ + } else { /* none given - grab first */ + listhost = lhost.s; + flagok = 1; + break; + } + } + } + if (!flagok) + listhost = outhost.s; + close(fd); + } + if (!listhost) + listhost = outhost.s; + if (!userlocal) { + if (!stralloc_copys(&usr,sender)) die_nomem(); + if (!stralloc_0(&usr)) die_nomem(); + userlocal = usr.s; + userhost = usr.s + byte_rchr(usr.s,usr.len-1,'@'); + if (!*userhost) + userhost = 0; + else { + *userhost = '\0'; + ++userhost; + } + } + + if (!stralloc_copys(&to,listlocal)) die_nomem(); + if (!stralloc_cats(&to,"-")) die_nomem(); + if (cmdidx) { /* recognized - substitute */ + if (!stralloc_cats(&to,constmap_get(&commandmap,cmdidx))) + die_nomem(); + } else /* not recognized - use as is */ + if (!stralloc_cats(&to,command)) die_nomem(); + + if (!stralloc_cats(&to,"-")) die_nomem(); + if (!stralloc_cats(&to,userlocal)) die_nomem(); + if (userhost) { /* doesn't exist for e.g. -get */ + if (!stralloc_cats(&to,"=")) die_nomem(); + if (!stralloc_cats(&to,userhost)) die_nomem(); + } + if (!stralloc_cats(&to,"@")) die_nomem(); + if (!stralloc_cats(&to,listhost)) die_nomem(); + if (!stralloc_0(&to)) die_nomem(); + + qmail_put(&qq,mydtline.s,mydtline.len); + + flaginheader = 1; + flagbadfield = 0; + + if (seek_begin(0) == -1) + strerr_die2sys(111,FATAL,ERR_SEEK_INPUT); + substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); + + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + + if (flaginheader && match) { + if (line.len == 1) + flaginheader = 0; + if ((line.s[0] != ' ') && (line.s[0] != '\t')) { + flagbadfield = 0; + if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':'))) + flagbadfield = 1; + } + } + if (!(flaginheader && flagbadfield)) + qmail_put(&qq,line.s,line.len); + if (!match) + break; + } + } else { /* commands we deal with */ + cmdidx = - cmdidx; /* now positive */ + if (cmdidx == EZREQ_WHICH) { /* arg is user, not list */ + userlocal = listlocal; listlocal = 0; + userhost = listhost; listhost = 0; + } + if (!stralloc_copys(&from,outlocal.s)) die_nomem(); + if (!stralloc_cats(&from,"-return-@")) die_nomem(); + if (!stralloc_cats(&from,outhost.s)) die_nomem(); + if (!stralloc_0(&from)) die_nomem(); + + if (userlocal) { + if (!stralloc_copys(&to,userlocal)) die_nomem(); + if (!stralloc_cats(&to,"@")) die_nomem(); + if (userhost) { + if (!stralloc_cats(&to,userhost)) die_nomem(); + } else { + if (!stralloc_cats(&to,outhost.s)) die_nomem(); + } + } else + if (!stralloc_copys(&to,sender)) die_nomem(); + if (!stralloc_0(&to)) die_nomem(); + + /* now we need to look for charset and set flagcd appropriately */ + + if (getconf_line(&charset,"charset",0,FATAL,dir)) { + if (charset.len >= 2 && charset.s[charset.len - 2] == ':') { + if (charset.s[charset.len - 1] == 'B' || + charset.s[charset.len - 1] == 'Q') { + flagcd = charset.s[charset.len - 1]; + charset.s[charset.len - 2] = '\0'; + } + } + } else + if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem(); + if (!stralloc_0(&charset)) die_nomem(); + set_cpoutlocal(&listname); /* necessary in case there are <#l#> */ + set_cpouthost(&hostname); /* necessary in case there are <#h#> */ + /* we don't want to be send to a list*/ + qmail_puts(&qq,"Mailing-List: ezmlm-request"); + if (getconf(&line,"listid",0,FATAL)) { + qmail_puts(&qq,"List-ID: "); + qmail_put(&qq,line.s,line.len); + } + qmail_puts(&qq,"\nDate: "); + when = now(); + datetime_tai(&dt,when); + qmail_put(&qq,date,date822fmt(date,&dt)); + qmail_puts(&qq,"Message-ID: <"); + if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when))) + die_nomem(); + if (!stralloc_append(&line,".")) die_nomem(); + if (!stralloc_catb(&line,strnum, + fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); + if (!stralloc_cats(&line,".ezmlm@")) die_nomem(); + if (!stralloc_cats(&line,outhost.s)) die_nomem(); + if (!stralloc_0(&line)) die_nomem(); + qmail_puts(&qq,line.s); + qmail_puts(&qq,">\nFrom: "); + if (!quote2(&line,outlocal.s)) die_nomem(); + qmail_put(&qq,line.s,line.len); + if (cmdidx == EZREQ_HELP) + qmail_puts(&qq,"-return-@"); + else + qmail_puts(&qq,"-help@"); + qmail_puts(&qq,outhost.s); + qmail_puts(&qq,"\n"); + qmail_put(&qq,mydtline.s,mydtline.len); + qmail_puts(&qq,"To: "); + if (!quote2(&line,to.s)) die_nomem(); + qmail_put(&qq,line.s,line.len); + qmail_puts(&qq,"\n"); + qmail_puts(&qq,"MIME-Version: 1.0\n"); + if (flagcd) { + qmail_puts(&qq,"Content-Type: multipart/mixed; charset="); + qmail_puts(&qq,charset.s); + qmail_puts(&qq,";\n\tboundary="); + qmail_puts(&qq,boundary); + } else { + qmail_puts(&qq,"Content-type: text/plain; charset="); + qmail_puts(&qq,charset.s); + } + qmail_puts(&qq,"\nSubject: "); + if (!quote2(&line,outlocal.s)) die_nomem(); + qmail_put(&qq,line.s,line.len); + qmail_puts(&qq,TXT_RESULTS); + transferenc(); + copy(&qq,"text/top",flagcd,FATAL); + if (cmdidx == EZREQ_LISTS || cmdidx == EZREQ_WHICH) { + switch (cmdidx) { + case EZREQ_LISTS: + code_qput("LISTS:",6); + break; + case EZREQ_WHICH: + code_qput("WHICH (",7); + code_qput(to.s,to.len - 1); + code_qput("):\n\n",4); + break; + default: break; + } + fd = open_read(cfname); + if (fd == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": "); + substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); + for (;;) { + if (getln(&sstext,&line,&match,'\n') == -1) + strerr_die3sys(111,FATAL,ERR_READ,cfname); + if (!match) + break; + if (line.len <= 1 || line.s[0] == '#') + continue; + if (!stralloc_0(&line)) die_nomem(); + pos = str_chr(line.s,':'); + if (!line.s[pos]) + break; + line.s[pos] = '\0'; + ++pos; + pos1 = pos + str_chr(line.s + pos,':'); + if (line.s[pos1]) { + line.s[pos1] = '\0'; + ++pos1; + } else + pos1 = 0; + + switch (cmdidx) { + case EZREQ_LISTS: + code_qput("\n\n\t",3); + code_qput(line.s,pos-1); + code_qput("\n",1); + if (pos1) { + code_qput(line.s+pos1,line.len-2-pos1); + } + break; + case EZREQ_WHICH: + if (issub(line.s+pos,to.s,(char *) 0,FATAL)) { + code_qput(line.s,pos-1); + code_qput("\n",1); + } + closesql(); /* likely different dbs for different lists */ + break; + } + } + code_qput("\n",1); + close(fd); + } else + copy(&qq,"text/help",flagcd,FATAL); + + copy(&qq,"text/bottom",flagcd,FATAL); + if (flagcd) { + if (flagcd == 'B') { + encodeB("",0,&line,2,FATAL); /* flush */ + qmail_put(&qq,line.s,line.len); + } + qmail_puts(&qq,"\n--"); + qmail_puts(&qq,boundary); + qmail_puts(&qq,"\nContent-Type: message/rfc822"); + qmail_puts(&qq, + "\nContent-Disposition: inline; filename=request.msg\n\n"); + } + qmail_puts(&qq,"Return-Path: <"); + if (!quote2(&line,sender)) die_nomem(); + qmail_put(&qq,line.s,line.len); + qmail_puts(&qq,">\n"); + if (seek_begin(0) == -1) + strerr_die2sys(111,FATAL,ERR_SEEK_INPUT); + if (substdio_copy(&ssqq,&ssin2) != 0) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + if (flagcd) { + qmail_puts(&qq,"\n--"); + qmail_puts(&qq,boundary); + qmail_puts(&qq,"--\n"); + } + } + qmail_from(&qq,from.s); + qmail_to(&qq,to.s); + if (*(err = qmail_close(&qq)) != '\0') + strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1); + + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die3x(99,INFO, "qp ",strnum); +} diff --git a/ezmlm-return.1 b/ezmlm-return.1 index 3f84989..e3a8e89 100644 --- a/ezmlm-return.1 +++ b/ezmlm-return.1 @@ -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 a mail envelope from the 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 @@ bounced. 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), diff --git a/ezmlm-return.c b/ezmlm-return.c index 3bc2421..7ca3fb2 100644 --- a/ezmlm-return.c +++ b/ezmlm-return.c @@ -1,3 +1,7 @@ +/*$Id: ezmlm-return.c,v 1.26 1999/08/07 20:50:52 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include +#include "direntry.h" #include "stralloc.h" #include "str.h" #include "env.h" @@ -16,18 +20,21 @@ #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]; @@ -38,21 +45,37 @@ substdio ssin; 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; @@ -60,16 +83,31 @@ unsigned long when; 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(); @@ -86,7 +124,7 @@ stralloc *bounce; 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) @@ -97,16 +135,37 @@ stralloc *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(); @@ -123,11 +182,21 @@ stralloc *bounce; 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(); @@ -136,9 +205,10 @@ stralloc *bounce; 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)); @@ -148,7 +218,7 @@ stralloc *bounce; } 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(); @@ -158,7 +228,7 @@ stralloc *bounce; 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}; @@ -167,14 +237,11 @@ stralloc header = {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; @@ -183,16 +250,22 @@ void main(argc,argv) 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(); @@ -200,104 +273,158 @@ char **argv; 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]) { @@ -305,11 +432,12 @@ char **argv; 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)); @@ -332,6 +460,8 @@ char **argv; } 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(); @@ -355,10 +485,23 @@ char **argv; if (!stralloc_copyb(&line,failure.s + 1,i - 3)) die_nomem(); if (byte_chr(line.s,line.len,'\0') == line.len) { if (!stralloc_0(&line)) die_nomem(); - 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); } diff --git a/ezmlm-send.1 b/ezmlm-send.1 index ff70976..b7ccc59 100644 --- a/ezmlm-send.1 +++ b/ezmlm-send.1 @@ -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 @@ If 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 @@ It rejects the message if there is already a .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 @@ 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 .B SENDER @@ -46,6 +147,60 @@ is set, and is either empty or .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 @@ Third, 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) diff --git a/ezmlm-send.c b/ezmlm-send.c index 5748891..fa2913e 100644 --- a/ezmlm-send.c +++ b/ezmlm-send.c @@ -1,3 +1,5 @@ +/* $Id: ezmlm-send.c,v 1.77 1999/10/29 02:49:14 lindberg Exp $*/ +/* $Name: ezmlm-idx-040 $*/ #include "stralloc.h" #include "subfd.h" #include "strerr.h" @@ -17,27 +19,89 @@ #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]; @@ -48,7 +112,9 @@ stralloc outlocal = {0}; 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; @@ -56,7 +122,10 @@ char inbuf[1024]; 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; @@ -65,23 +134,33 @@ 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) @@ -91,8 +170,8 @@ void puts(buf) char *buf; 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; @@ -109,14 +188,12 @@ char *sender; 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"); @@ -124,70 +201,277 @@ void numwrite() substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf)); if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1) die_numnew(); + 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(); @@ -197,123 +481,326 @@ char **argv; 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); } } diff --git a/ezmlm-split.1 b/ezmlm-split.1 new file mode 100644 index 0000000..9c4e3e4 --- /dev/null +++ b/ezmlm-split.1 @@ -0,0 +1,171 @@ +.de Vb +.ft CW +.nf +.ne \\$1 +.. +.de Ve +.ft R + +.fi +.. +.TH ezmlm-split 1 +.SH NAME +ezmlm-split \- distribute (un)subscribe requests to sublists +.SH SYNOPSIS +.B ezmlm-split +.I dir +[ +.B \-dD +][ +.I splitfile +] +.SH DESCRIPTION +If the action is +.I \-subscribe +or +.IR \-unsubscribe , +.B ezmlm-split +analyzes the target of the request, + computing a hash in the range 0-52 from +the address, and determines the ``domain key'', i.e. +the two top levels of the host address in reverse order. +Thus, the domain entry for ``d@a.b.c'' becomes ``c.b'' +and the one for ``d@a'' becomes ``a''. + +The hash and domain parts are then tested against successive lines of +.I splitfile +(default is +.IR dir\fB/split ). +If a match is found, the request is forwarded to the corresponding +sublist, and +.B ezmlm-split +exits 99. If a match is not found or action is not +.I \-subscribe +or +.IR \-unsubscribe , +.B ezmlm-split +exits 0. + +In +.IR splitfile , +blank lines and lines with ``#'' in position 1 are ignored. Other lines are +expected to be of the format ``dom:low:hi:list@host'', where ``dom'' is +the top level domain, ``low''-``hi'' the range of the hash (defaults 0 and 52), +and ``list@host'' the name of the corresponding list (default is the +local list). A line is considered to match if the address hash is +between ``low'' and ``hi'' inclusive and ``dom'' is empty, +or if the ``domain key'' matches ``dom'' for the full length of ``dom''. Thus, +the address ``user@aol.com'' would match ``com'' and ``aol.com'', +but not ``host.com''. + +If the domain +specified is the top level domain up to 3 characters, the split is identical +as that used by the SQL subscriber interface. This is recommended. +There can be several entries for a given sublist. + +.B ezmlm-split +can be used also for list with SQL-based sublisting. In this case, +addresses matching the +.I splitfile +are forwarded to the respective non-SQL sublist, and non-matching addresses +are handed by the SQL sublist. + +.SH OPTIONS +.TP +.B \-d +(Default.) +Do. Forward requests to the appropriate list. +.TP +.B \-D +Do not process messages. Rather, read addresses, one per line from stdin, and +print ``sublist@host: address'' where ``sublist@host'' is the address to which +the request would have been forwarded in normal operation. This is used to +process a set of existing addresses into a set of address collections, one +per sublist. The output can be sorted and easily processed into a set of files, +one per sublist containing the addresses that sublist handles. +.SH "SPLIT LIST SETUP" +To use a hierarchy of sublists, set up the master list and add a +.B ezmlm-split +line before the +.B ezmlm-manage(1) +line in +.IR dir\fB/manager . +Create any number of sublists of the main list on other local or +distant hosts. Ideally, these should be non-archived, to point to the correct +message numbers of the main list archive (see +.BR ezmlm-send(1) . +You can use +.B ezmlm-make -C\fIezmlmsubrc +for this. If you don't, use the text files from the main list, except +.IR bounce-bottom . +Next, create +.I split +in the main list directory to achieve an appropriate split. Load splitting +between several local hosts is best achieved by hash, with a blank domain. +Geographical splitting with hosts in different countries is best done +via ``domain'' and naturally, a large domain can be subdivided by hash. + +Subscribers will receive all messages 'From:' the main list. When they +subscribe or unsubscribe, the request will be forwarded to the appropriate +sublist, which will handle the confirmation. All information, except +.I bounce-bottom +refers the user to the main list. Thus, to the user the list appears as +a single list with the address of the main list, and distribution among +sublists is at the discretion of the administrator of the main list. + +.SH "ADDING/REMOVING SUBLISTS" +In general, the main list should be disabled, while changing the sublist +split. This can be done by changing the mode of +.I dir\fB/lock +to 0 or by setting the sticky bit for the home directory of the user +controlling the list. + +To remove a sublist, edit the lines for that sublist in the splitfile to +point to another list, and add the existing subscribers of the removed +sublist to the sublist taking the load. +When splitting a sublist into several sublists, create the new sublists, +and edit the split file to distribute the load +between them (usually by hash). Process the subscribers of the old list +with: + +.Vb 1 + | ezmlm-split -D dir | sort | program +.Ve +where to get one file of addresses per new sublist, ``program'' could be: + +.Vb 12 +\&#!/usr/bin/perl +\&while (<>) { +\& ($f,$t) = split (':'); +\& $t =~ s/^\ //; +\& if ($f ne $of) { +\& $of = $f; +\& close(OUT) if ($of); +\& open(OUT,">$f") or die("Unable to open $f"); +\& } +\& print OUT $t; +\&} +\&close(OUT) if ($of); +.Ve + +Remove all subscribers from the old list, +and add the respective subscribers to each list. + +For any more drastic reorganizations, collect all the subscribes of the +affected sublists, create the new subscriber lists, and update the +subscribers of the affected lists. + +Reorganizations are easier done when lists use SQL support. By +temporarily using SQL support, reorganizations can be done on running +lists even when normally using +.B ezmlm-split +and local subscriber databases. +.SH "SEE ALSO" +ezmlm-list(1), +ezmlm-make(1), +ezmlm-manage(1), +ezmlm-sub(1) +ezmlm-unsub(1), +ezmlm(5), +ezmlmrc(5), +ezmlmsubrc(5) diff --git a/ezmlm-split.c b/ezmlm-split.c new file mode 100644 index 0000000..f115358 --- /dev/null +++ b/ezmlm-split.c @@ -0,0 +1,316 @@ +/*$Id: ezmlm-split.c,v 1.6 1999/05/12 22:17:54 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#include +#include "error.h" +#include "stralloc.h" +#include "str.h" +#include "env.h" +#include "sig.h" +#include "slurp.h" +#include "getconf.h" +#include "strerr.h" +#include "byte.h" +#include "getln.h" +#include "case.h" +#include "qmail.h" +#include "substdio.h" +#include "readwrite.h" +#include "quote.h" +#include "now.h" +#include "uint32.h" +#include "fmt.h" +#include "errtxt.h" +#include "idx.h" + +#define FATAL "ezmlm-split: fatal: " +#define INFO "ezmlm-split: info: " + +int flagdo = 1; /* default is manager function */ + +char *sender; +char *split; +stralloc outhost = {0}; +stralloc inlocal = {0}; +stralloc outlocal = {0}; +stralloc target = {0}; +stralloc lctarget = {0}; +stralloc line = {0}; +stralloc domain = {0}; +stralloc name = {0}; +stralloc from = {0}; +stralloc to = {0}; +char strnum[FMT_ULONG]; +unsigned long lineno; +int flagfound; + +void die_usage() { + strerr_die1x(100,"ezmlm-split: usage: ezmlm-split [-dD] dir [splitfile]"); } + +void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } + +void die_badaddr() +{ + strerr_die2x(100,FATAL,ERR_BAD_ADDRESS); +} + +void die_syntax() +{ + strnum[fmt_ulong(strnum,lineno)] = '\0'; + strerr_die6x(111,FATAL,split," syntax error line ",strnum,": ",line.s); +} + +char spbuf[1024]; /* should normally hold entire file */ +substdio sssp; + +struct qmail qq; +int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; +{ + qmail_put(&qq,buf,len); + return (int) len; +} +char qqbuf[1]; +substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf)); + +char outbuf[1]; +substdio ssout = SUBSTDIO_FDBUF(write,1,outbuf,(int) sizeof(outbuf)); + +char inbuf[1024]; +substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf)); + +int findname() +/* returns 1 if a matching line was found, 0 otherwise. name will contain */ +/* the correct list address in either case */ +{ + char *cpat,*cp,*cpname,*cp1,*cp2,*cplast; + unsigned long u; + uint32 h; + unsigned char hash,hash_hi,hash_lo; + unsigned int pos,pos_name,pos_hi; + char ch; + int fd,match; + + /* make case insensitive hash */ + flagfound = 0; /* default */ + cpname = ""; /* default */ + if (!stralloc_copy(&lctarget,&target)) die_nomem(); + case_lowerb(lctarget.s,lctarget.len -1); + h = 5381; + cp = lctarget.s; + while ((ch = *cp++)) { + h = (h + (h << 5)) ^ (uint32) ch; + } + hash = (h % 53); + + /* make domain pointer */ + cpat = lctarget.s + str_chr(lctarget.s,'@'); + if (!*cpat) + strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s); + cplast = cpat + str_len(cpat) - 1; + if (*cplast == '.') --cplast; /* annonying special case */ + cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.'); + if (cp1 != cplast) { /* got one '.' */ + if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem(); + cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.'); + if (cp2 == cp1) cp2 = cpat; + ++cp2; + if (!stralloc_append(&domain,".")) die_nomem(); + if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem(); + } else /* no '.' */ + if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem(); + if (!stralloc_0(&domain)) die_nomem(); + + if ((fd = open_read(split)) == -1) + strerr_die4sys(111,FATAL,ERR_OPEN,split,": "); + substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf)); + lineno = 0; + for (;;) { /* dom:hash_lo:hash_hi:listaddress */ + if (getln(&sssp,&line,&match,'\n') == -1) + strerr_die4sys(111,FATAL,ERR_READ,split,": "); + lineno++; + if (!match) + break; + if (line.s[0] == '#') continue; /* comment */ + line.s[line.len - 1] = '\0'; /* no need to allow \0 in lines */ + if (!line.s[pos = str_chr(line.s,':')]) + continue; /* usually blank line */ + line.s[pos] = '\0'; + if (pos == 0 || /* no domain */ + (case_starts(domain.s,line.s))) { /* or matching domain */ + if (!line.s[++pos]) die_syntax(); + pos_hi = pos + str_chr(line.s + pos,':'); + if (!line.s[pos_hi]) die_syntax(); + pos_hi++; + (void) scan_ulong(line.s + pos, &u); /* scan_uint() not in ezmlm */ + hash_lo = (unsigned char) u; + (void) scan_ulong(line.s + pos_hi, &u); + hash_hi = (unsigned char) u; + pos_name = pos_hi + str_chr(line.s + pos_hi,':'); + if (pos_hi == pos_name) hash_hi = 52L; /* default hi = 52 */ + if (line.s[pos_name]) pos_name++; + if (hash > hash_hi || hash < hash_lo) continue; /* not us */ + cpname = line.s + pos_name; + while (*cpname && /* isolate name */ + (*cpname == ' ' || *cpname == '\t')) cpname++; + pos = line.len - 2; + while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' || + line.s[pos] == '\t')) line.s[pos--] = '\0'; + break; + } + } + close(fd); + + if (*cpname) { + if (!stralloc_copys(&name,cpname)) die_nomem(); + if (byte_chr(name.s,name.len,'@') == name.len) { /* local sublist */ + if (!stralloc_append(&name,"@")) die_nomem(); + if (!stralloc_cat(&name,&outhost)) die_nomem(); + } + if (!stralloc_0(&name)) die_nomem(); + return 1; + } else { /* match without name or no match =>this list */ + if (!stralloc_copy(&name,&outlocal)) die_nomem(); + if (!stralloc_append(&name,"@")) die_nomem(); + if (!stralloc_cat(&name,&outhost)) die_nomem(); + if (!stralloc_0(&name)) die_nomem(); + return 0; + } +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *dir; + char *local; + char *action; + char *def; + char *dtline; + char *nhost; + char *err; + unsigned int i; + int match; + int optind = 1; + + sig_pipeignore(); + + dir = argv[optind++]; + if (!dir) die_usage(); + if (dir[0] == '-') { + if (dir[1] == 'd') flagdo = 1; + else if (dir[1] == 'D') flagdo = 0; + else die_usage(); + if (!(dir = argv[optind++])) die_usage(); + } + if (!(split = argv[optind])) + split = "split"; + + if (chdir(dir) == -1) + strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); + + getconf_line(&outhost,"outhost",1,FATAL,dir); + getconf_line(&outlocal,"outlocal",1,FATAL,dir); + + if (flagdo) { + sender = env_get("SENDER"); + if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER); + if (!*sender) + strerr_die2x(100,FATAL,ERR_BOUNCE); + if (!sender[str_chr(sender,'@')]) + strerr_die2x(100,FATAL,ERR_ANONYMOUS); + if (str_equal(sender,"#@[]")) + strerr_die2x(100,FATAL,ERR_BOUNCE); + + def = env_get("DEFAULT"); + if (def) { + action = def; + } else { + local = env_get("LOCAL"); + if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL); + getconf_line(&inlocal,"inlocal",1,FATAL,dir); + if (inlocal.len > str_len(local)) die_badaddr(); + if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr(); + action = local + inlocal.len + 1; + } + if (!stralloc_copys(&target,sender)) die_nomem(); + if (action[0]) { + i = str_chr(action,'-'); + if (action[i]) { + action[i] = '\0'; + if (!stralloc_copys(&target,action + i + 1)) die_nomem(); + i = byte_rchr(target.s,target.len,'='); + if (i < target.len) + target.s[i] = '@'; + } + } + if (!stralloc_0(&target)) die_nomem(); + + if (case_diffs(action,ACTION_SUBSCRIBE) && + case_diffs(action,ALT_SUBSCRIBE) && + case_diffs(action,ACTION_UNSUBSCRIBE) && + case_diffs(action,ALT_UNSUBSCRIBE)) + _exit(0); /* not for us */ + + if (findname()) { + /* new sender */ + if (!stralloc_copy(&from,&outlocal)) die_nomem(); + if (!stralloc_cats(&from,"-return-@")) die_nomem(); + if (!stralloc_cat(&from,&outhost)) die_nomem(); + if (!stralloc_0(&from)) die_nomem(); + if (name.s[i = str_rchr(name.s,'@')]) { /* name must have '@'*/ + nhost = name.s + i; + *(nhost++) = '\0'; + } + if (!stralloc_copys(&to,name.s)) die_nomem(); /* local */ + if (!stralloc_append(&to,"-")) die_nomem(); /* - */ + if (!stralloc_cats(&to,action)) die_nomem(); /* subscribe */ + if (!stralloc_append(&to,"-")) die_nomem(); /* - */ + if (target.s[i = str_rchr(target.s,'@')]) + target.s[i] = '='; + if (!stralloc_cats(&to,target.s)) die_nomem(); /* target */ + if (!stralloc_append(&to,"@")) die_nomem(); /* - */ + if (!stralloc_cats(&to,nhost)) die_nomem(); /* host */ + if (!stralloc_0(&to)) die_nomem(); + dtline = env_get("DTLINE"); + if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE); + + if (qmail_open(&qq,(stralloc *) 0) == -1) + strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); + qmail_puts(&qq,dtline); /* delivered-to */ + if (substdio_copy(&ssqq,&ssin) != 0) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + qmail_from(&qq,from.s); + qmail_to(&qq,to.s); + + if (*(err = qmail_close(&qq)) != '\0') + strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1); + + strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; + strerr_die3x(99,INFO,"qp ",strnum); + } + _exit(0); + } else { + + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,ERR_READ_INPUT); + if (!match) break; + if (line.len == 1) continue; /* ignore blank lines */ + if (line.s[0] == '#') continue; /* ignore comments */ + if (!stralloc_copy(&target,&line)) die_nomem(); + target.s[target.len - 1] = '\0'; + (void) findname(); + if (!stralloc_cats(&name,": ")) die_nomem(); + if (!stralloc_cats(&name,target.s)) die_nomem(); + if (!stralloc_append(&name,"\n")) die_nomem(); + if (substdio_put(&ssout,name.s,name.len) == -1) + strerr_die2sys(111,ERR_WRITE,"output: "); + } + if (substdio_flush(&ssout) == -1) + strerr_die2sys(111,ERR_FLUSH,"output: "); + _exit(0); + } +} + + diff --git a/ezmlm-store.1 b/ezmlm-store.1 new file mode 100644 index 0000000..1350577 --- /dev/null +++ b/ezmlm-store.1 @@ -0,0 +1,210 @@ +.TH ezmlm-store 1 +.SH NAME +ezmlm-store \- store messages posted to a moderated lists and send +moderation requests to the moderator(s). +.SH SYNOPSIS +.B ezmlm-store [-bBcCmMpPrRsSvV] +.I dir +.SH DESCRIPTION +.B ezmlm-store +reads a mail message and +stores it in +.I dir\fB/mod/pending/. +.B ezmlm-store +also sends a moderation request with a copy of the message to the list of +moderators stored in +.I dir\fB/mod/subscribers/. +If +.I dir\fB/modpost +contains a directory name, +.IR moddir , +with a leading forward slash, the moderator list in +.I /moddir/subscribers/ +is used instead. This allows separate sets of moderators for +subscription and message moderation, as +well as the use of the same moderator list for several +.B ezmlm +mailing lists, owned by the same user. If the +.B \-s +switch is used, the moderators are divided into two sets. Those pointed to by +.I dir\fB/modpost +which will receive confirmation requests for posts with their SENDER address, +and those stored with the base directory +.I dir\fB/mod/ +which will receive moderation requests for messages posted from SENDERs not +part of the first group. This can be used to have a set of trusted +users (``moderating'' themselves to thwart SENDER faking), and a set of more +traditional moderators, which receive approval requests for other posts. + +.B Note: +The contents of +.I dir\fB/modpost +do not affect the location of the message moderation queue. + +If SENDER is a moderator, the request is sent +to that moderator only. + +The moderation request includes cookies for message rejection and acceptance. +The moderator can take either action by replying to the appropriate address. +For moderator convenience, the +.I accept +address is given in +the ``Reply-To:'' header, and the +.I reject +address in the ``From:'' header. + +If the list is set up with remote administration and the sender is not a +moderator, the ``Cc:'' header will contain a confirmation address to add +the sender to the ``allow'' database. This allows the moderator to both +approve the post and add the sender to the list of accepted posters by +replying to ``all''. + +The (default) subject of all message moderation requests is +.B MODERATE for\fI listname@host. + +Once the request has been successfully sent to the moderators, +.B ezmlm-store +sets the owner-execute bit of the message in +.I dir\fB/mod/pending/. +Messages without this bit set are the result of incomplete executions of +.B ezmlm-store +and are ignored. + +At the beginning of the message, +.B ezmlm-store +prints a new +.B Mailing-List +field with the contents of +.IR dir\fB/mailinglist . +It rejects the message if there is already a +.B Mailing-List +field. + +.B ezmlm-store +does not distribute bounce messages: +if the environment variable +.B SENDER +is set, and is either empty or +.BR #@[] , +.B ezmlm-store +rejects the message. +.SH OPTIONS +.TP +.B \-b +(Default.) +With the moderation request, +send both headers and body of the message to be moderated. +.TP +.B \-B +With the moderation request, +send header, but not body of the message to be moderated. +This may be useful if moderation is used to allow one or a few poorly +connected addresses to post, and posts are very large (e.g. when the list +is used as a distribution channel of e.g. catalogs). +.TP +.B \-cCrR +Passed on to +.B ezmlm-send(1) +in case this program is executed. This happens only if +.I dir\fB/modpost +does not exist. +.TP +.B \-m +(Default.) +The post is sent as a MIME enclosure. +.TP +.B \-M +The post is appended to the message. +.TP +.B \-s +The contents of +.I dir\fB/modpost +with the default +.I dir\fB/mod/ +are used as the base directory for self-approving users, whereas +.I dir\fB/mod/ +is used as the base directory +for the moderators to whom approval requests for other +posts are sent. +.TP +.B \-S +(Default.) +The contents of +.I dir\fB/modpost +with the default +.I dir\fB/mod/ +are used as the base directory +for the moderators for all moderator functions. +.TP +.B \-p +(Default.) +Anyone can post. Posts that are not from a moderator are sent out to +all moderators for approval. Posts that are from a moderator are +sent only to that moderator. +.TP +.B \-P +Only moderators can post. Those posts are sent to the posting moderator +for approval. Posts from other addresses are bounced. This can be used +to relatively securely restrict posts to messages originating from +a given set of addresses. +.TP +.B \-v +Display +.B ezmlm-manage +version information. +.TP +.B \-V +Display +.B ezmlm-manage +version information. +.SH USAGE +First of all, remember that +.B ezmlm-store +will simply execute +.B ezmlm-send(1) +unless +.I dir\fB/modpost +exists. +For the switches, use +.B \-P +for lists where only moderators can post securely, i.e. they are +asked to approve their own posts after posting, +whereas other SENDERs are rejected. For +low-security more convenient versions of this type of restriction, see +.BR ezmlm-gate(1) . + +Normally (no switches), +posts from moderators are sent for approval only to the sending +moderator, whereas posts from other addresses are sent to all moderators. +Thus, you can set up an announcement list by adding all potential posters +as moderators. However, you may also want to allow others to post, as +long as the posts are approved. This would be default +.B ezmlm-store +function. + +To make the set of ``approved posters'' who approve their own posts, different +from the set of addresses that approve posts from other users, use the +.B \-s +switch. Add a directory name to +.IR dir\fB/modpost . +This directory is the base directory of the ``approved posters'' +database. Add the moderators for other posts to +.I dir\fB/mod/ +using +.BR ezmlm-sub(1) . +.SH "CHARACTER SETS" +If +.I dir\fB/charset +exists, +.B ezmlm-store +will use the character set listed for all messages. Otherwise, the +default ``us-ascii'' will be used. The character set can be suffixed +by ``:'' followed by a code. If the code is ``Q'', outgoing messages are +sent as ``Quoted-Printable'', if it is '`B'' they are sent ``base64'' encoded. +Otherwise, text is sent as is. +.SH "SEE ALSO" +ezmlm-clean(1), +ezmlm-manage(1), +ezmlm-make(1), +ezmlm-moderate(1), +ezmlm(5) diff --git a/ezmlm-store.c b/ezmlm-store.c new file mode 100644 index 0000000..d293cfa --- /dev/null +++ b/ezmlm-store.c @@ -0,0 +1,506 @@ +/*$Id: ezmlm-store.c,v 1.52 1999/10/09 16:49:56 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#include +#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); +} diff --git a/ezmlm-sub.1 b/ezmlm-sub.1 index 219b88f..ae4bf68 100644 --- a/ezmlm-sub.1 +++ b/ezmlm-sub.1 @@ -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 @@ adds each address .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 lowercase before adding 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) diff --git a/ezmlm-sub.c b/ezmlm-sub.c index 85fce6a..62e3166 100644 --- a/ezmlm-sub.c +++ b/ezmlm-sub.c @@ -1,9 +1,32 @@ +/*$Id: ezmlm-sub.c,v 1.18 1999/08/02 02:57:57 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ #include "strerr.h" #include "subscribe.h" -#include "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; @@ -11,23 +34,81 @@ char **argv; { 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); } diff --git a/ezmlm-test.1 b/ezmlm-test.1 new file mode 100644 index 0000000..65dee58 --- /dev/null +++ b/ezmlm-test.1 @@ -0,0 +1,153 @@ +.TH ezmlm-test 1 +.SH NAME +ezmlm-test \- test ezmlm programs +.SH SYNOPSIS +.B ezmlm-test +[ +.B \-on +][ +.B \-h\fI host +][ +.B \-u\fI user +][ +.B \-l\fI sqluser +][ +.B \-t\fI sqltable +][ +.B \-d\fI sqldatabase +][ +.B \-p\fI sqlpassword +][ +.B \-s\fI section +] +.I dir +.SH DESCRIPTION +.B ezmlm-test +is run from the ezmlm build directory. It will test most of the functions +of most of the programs in ezmlm-idx>=0.313. The program prints status +and error messages to stdout. It requires that qmail runs on the host and that +mail delivery to a local user functions. By default, it runs as the +user ``eztest'' who should have read and execute permission to the files +in the build directory. + +For testing with an SQL database (requires ezmlm-idx>=0.32; see +.BR -p ), +you need to have first created the tables in the database, e.g. using +.BR ezmlm-mktab . +A number of switches allow overriding the default connection information. + +.B ezmlm-test +creates the list ``eztest-__tstlist@host'' +in the directory ``~/__TSTDIR''. This directory and ``~/.qmail-__tstlist*'' +will be overwritten/removed by the program. In addition, +the file ``~/__TSTDIR_err'' is created. In cases of error, it often contains +the error message form the failing program. + +.B ezmlm-test +should complete without error. +As many invocations of the programs test several functions it is not easy +to determine what went wrong if +.B ezmlm-test +fails. Usually, ``~/__TSTDIR__err'' gives some leads, but then debugging +of the particular program is required. Usually, this involves recreating +the failing circumstances, including environment variables. +.SH OPTIONS +.TP +.B \-d\fI sqldatabase +If SQL support is tested, use +.I sqldatabase +as the database, overriding the default ``ezmlm''. See +.BR \-p . +.TP +.B \-h\fI host +Connect to an SQL server on +.IR host , +if an SQL database is used (see +.BR \-p ). +Default is empty, which for most database managers defaults to +localhost/unix socket. To specify a non-default port, +add ``:port'' to the host name. +.TP +.B \-l\fI sqluser +Connect as +.I sqluser +to the SQL server, if an SQL database is used (see +.BR \-p ). +By default, it is the same as the executing user as +specified by the +.B \-u +switch or the default ``eztest''. +.TP +.B \-n +Test assuming qmail>=1.02 and ezmlm-idx>=0.32. Normally, this is auto-detected. +This switch is for testing of +.B ezmlm-test +and unlikely to be generally useful. +.TP +.B \-o +Test assuming an old (<1.02) version of qmail which does not support +the DEFAULT environment variable. Normally, this is auto-detected, and +DEFAULT support is used if qmail>=1.02 and ezmlm-idx>=0.32. The ``old'' +style works with all versions of qmail, but requires adjustments for +virtual domains. DEFAULT support makes these adjustments unnecessary. +.TP +.B \-p\fI sqlpassword +Test with SQL support, and use +.I sqlpassword +as the connection password. By default, local databases, rather than an +SQL database are used for testing. To use the SQL database with an +empty password, specify +.BR \-p\ '' . +.TP +.B \-s\fI section +Restart +.B ezmlm-test +from section +.IR section . +This can be used to resume execution if the 30 s given for mail delivery +was not sufficient for the test message to be delivered. ``9'' can be +used to clean up any files remaining after incomplete execution of +.BR ezmlm-test . +This option should not be needed. +.TP +.B \-t\fI sqltable +Use +.I sqltable +as the table root name for the SQL database tables, if an SQL database +is used (see +.BR \-p ). +Default is ``list''. +.TP +.B \-u\fI user +Execute +.B ezmlm-test +as +.IR user . +Default is ``eztest''. The program refuses to run, unless the effective +user name matches this user name. +.SH BUGS +On some systems, some of the tests give a broken pipe error. This is because +code needs to be added to the make_message function to capture error messages. +These errors can be safely ignored for now. +.SH "SEE ALSO" +ezmlm(5), +ezmlm-clean(1), +ezmlm-gate(1), +ezmlm-get(1), +ezmlm-idx(1), +ezmlm-issubn(1), +ezmlm-list(1), +ezmlm-make(1), +ezmlm-manage(1), +ezmlm-mktab(1), +ezmlm-moderate(1), +ezmlm-request(1), +ezmlm-return(1), +ezmlm-send(1), +ezmlm-split(1), +ezmlm-store(1), +ezmlm-sub(1), +ezmlm-tstdig(1), +ezmlm-unsub(1), +ezmlm-warn(1) + diff --git a/ezmlm-test.sh b/ezmlm-test.sh new file mode 100644 index 0000000..a1d03b8 --- /dev/null +++ b/ezmlm-test.sh @@ -0,0 +1,2366 @@ +# Above should have been added a QMPATH definition +# DEBUG=1 +# This program is meant to test ezmlm-idx. +# Several criteria have to be met for this to work: +# 0. you need to have qmail installed allowing mail delivery to +# "eztest@host" and subaddresses. +# 2. you need to have a user "eztest" or edit the script to change to a +# user that exists on your system. +# 3. you need to be that user when you invoke this script and the script +# needs to reside in the same dir as the binaries you want to test. +# 4. this user needs to have execute permission for the build dir +# +# The script will use ~eztest/__TSTDIR and ~eztest/__TSTDIR__err and destroy +# any files therein. Both user name and directory names etc can be configured +# below, but this should only very rarely be necessary. +# +# This program is experimental and not yet properly documented. Please +# send comments to lindberg@id.wustl.edu. I'm attempting to make this a +# rigorous test for future ezmlm+idx installations so that full function +# can be verified when upgrading to a new version. + +# must be absolute +EZBIN=`pwd` + +# the user that should run the scripts (test list is created in this +# users home directory). +EZTEST='eztest' + +# HOST is normally set from /var/qmail/control/me. Set it here to override +HOST='' + +# Version of ezmlm-idx for which this test script is designed +OLD_VER='ezmlm-idx-031' # ezmlm-idx-0.31x +VER='ezmlm-idx-0.40' +EZVER='40' # default version + +#does the current version have qmail<1.02 support? +OLD_QMAIL='n' + +# basedir for test list. It and all files therein are destroyed by +# the script +DIR="$HOME/__TSTDIR" + +# part that follows user name of local name of the list +LIST='__tstlist' + +# file not within listdir where some error output is stored. If something +# fails, this file may have more info. +ERR="${DIR}__err" + +# file that can hold crated test msg to avoid sigpipe +TMP="${DIR}/__tmp" + +# defaults for SQL version - overridden by command line switches +TABLE='list' +DB='ezmlm' +SQLHOST='' +SQLUSR="$EZTEST" # -u overrides, -l overrides that + +# sets umask so that qmail paternalism doesn't complain. With most +# installations, there is a umask in the user's profile. 022 should be ok, +# but 002 is safer. + +UMASK='umask 002' + +#programs: +# to report disk usage summary +DU='du -s' +# Need full path in case qmail doesn't have these in the path +ECHO=`which echo` 2>/dev/null || ECHO='echo' +GREP=`which grep` 2>/dev/null || GREP='grep' +# std programs +HEAD='head' +MKDIR='mkdir' +MV='mv' +# a ps command that would list qmail if running. This works for RedHat Linux +PS='ps auxw' +RM='rm' +SED='sed' +STRINGS='strings' +TAIL='tail' +UNSET='unset' +WC='wc' +# if you don't have this, you can put 'echo "user"' where user is the current +# login user name. +WHOAMI='whoami' + +###################### END CONFIRGRABLE ITEMS ######################### +SQLUSER='' # must be empty +ARR='-------------------->' +ALLOW='allow' +DENY='deny' +DASH='-' +# switch for ezmlm-return +DLC='-d' +DUC='-D' +# file for ezmlm-request testing +REQ="${DIR}/__req" +# Set if we've found bug from old version +BUG='' +# Use RDBMS, set if -p was specified even if PW empty, e.g. Postgres +USESQL='' +# process arguments + +SECT="1" +while [ ! -z "$1" ]; do # not everyone has getopt :-( + case "$1" in + -/) + DASH='-/'; shift;; + -d) + DB="$2"; shift; shift;; + -h) + SQLHOST="$2"; shift; shift;; + -l) + SQLUSER="$2"; shift; shift;; + -n) + QMVER=n; shift;; + -o) + QMVER=o; shift;; + -p) + PW="$2"; USESQL=1; shift; shift;; + -u) + EZTEST="$2"; SQLUSR="$2"; shift; shift;; + -s) + SECT="$2"; shift; shift;; + -t) + TABLE="$2"; shift; shift;; + --) + shift; break;; + *) + ${ECHO} "$i" + ${ECHO} "Usage: ezmlm-test [-/] [-on] [-u user]" \ + "[-p sqlpassword [-l sqluser] [-d sqldb]" \ + "[-t sqltable] [-h sqlhost]] [-s section]" + ${ECHO} + ${ECHO} "args have to be separated from switches!" + ${ECHO} + ${ECHO} "defaults: -d ezmlm" + ${ECHO} " -h [empty => RDBMS default]" + ${ECHO} " -l eztest or -u arg if specified" + ${ECHO} " -n/o [autodetected]" + ${ECHO} " -p [empty - don't use SQL support]" + ${ECHO} " -s 1 [run test from beginning]" + ${ECHO} " -t list" + ${ECHO} " -u eztest" + ${ECHO} + exit 99;; + esac +done + +if [ -z "$SQLUSER" ]; then + SQLUSER="$SQLUSR" +fi + +USER=`${WHOAMI}` >/dev/null 2>&1 || \ + { ${ECHO} "whoami doesn't work. If you're not \"${EZTEST}\" the"; + ${ECHO} "will fail."; USER="${EZTEST}"; } + +if [ "$USER" != "${EZTEST}" ]; then + ${ECHO} "Must be user ${EZTEST} to execute"; exit 99 +fi +LOC="$EZTEST-$LIST" +# calculate position in LOCAL where [normally] default starts +LOCLEN=`${ECHO} "$LOC-" | ${WC} -c | ${SED} 's/ //g'` +REJLEN=`${ECHO} "$LOC-reject-" | ${WC} -c | ${SED} 's/ //g'` +ACCLEN=`${ECHO} "$LOC-accept-" | ${WC} -c | ${SED} 's/ //g'` + +${UMASK} >/dev/null || \ + { + ${ECHO} "Umask failed. Usually, this is OK. Fix this if ezmlm-test" + ${ECHO} "fails and messages remain queued with the qmail error" + ${ECHO} "'Uh-oh: .qmail file is writable'." + ${ECHO} + } + +DOT="$HOME/.qmail$DASH$LIST" + +if [ "$SECT" != "1" ]; then + ${ECHO} "Starting with section $SECT ..." +fi + +# test addresses. These are all within the list dir and all addresses +# are subaddresses of the list address. You can change this, but it is +# usually pointless. +SINK='sink' +SINKDIR="${DIR}/${SINK}" +SND="${LOC}-${SINK}" + +# moddir +MODACC='modacc' +MODDIR="${DIR}/${MODACC}" +MOD="$LOC-${MODACC}" + +# digdir +DIGGG='dig' +DIGDIR="${DIR}/${DIGGG}" +DIG="$LOC-${DIGGG}" + +# mandir +MANAG="man" +MANDIR="${DIR}/${MANAG}" +MAN="$LOC-${MANAG}" + +# bouncedir +BOUNCE='bnc' +BNC="$LOC-bnc" + +if [ -z "$HOST" ]; then + HOST=`${HEAD} -1 ${QMPATH}/control/me` || \ + { ${ECHO} "unable to get host name. Set HOST in script" ; exit 99; } +fi + +if [ ! -x "${EZBIN}/ezmlm-make" ]; then + ${ECHO} "can't execute ${EZBIN}/ezmlm-make. Most likely, user ``$USER''" + ${ECHO} "doesn't have execute permission to files in directory" + ${ECHO} "``${EZBIN}''. Adjust permissions or edit the script to" + ${ECHO} "use a different test user." + exit 99 +fi + +if [ ! -x "${QMPATH}/bin/qmail-local" ]; then + ${ECHO} "can't find qmail-local. Please correct the path in the script" + exit 99 +fi +if [ ! -x "${QMPATH}/bin/qmail-inject" ]; then + ${ECHO} "can't find qmail-inject. Please correct the path in the script" + exit 99 +fi +# Check if qmail is running. Don't fail if not, as it's most likely a +# ps issue and not a lack of qmail. +${PS} | ${GREP} qmai\l-send >/dev/null 2>&1 || \ + { + ${ECHO} "qmail isn't running or ps doesn't work as expected. If" + ${ECHO} "qmail is not running, this script will fail. Will continue..." + } + +############################### +# message generating function # +############################### +make_body() +{ + ${ECHO} "This is a simple message body" + ${ECHO} "--bound123ary" + ${ECHO} "Content-type: Text/pLAIn" + ${ECHO} + ${ECHO} "plain text" + ${ECHO} "--bound123ary" + ${ECHO} "Content-type: texT/Html" + ${ECHO} + ${ECHO} "html text" + ${ECHO} "--bound123ary--" + ${ECHO} + ${ECHO} "junk after boundary" + return 0 +} + +make_message() +{ + ${ECHO} "ReCEIved: #LAST#" + ${ECHO} "ReCeIved: #PENULTIMATE#" + ${ECHO} "retuRN-RECeipt-to: nobody" + ${ECHO} "To: $TO" + ${ECHO} "CC: " + ${ECHO} " $CC" + ${ECHO} "FROM: $FROM" + if [ ! -z "$CONTENT" ]; then + ${ECHO} "MIME-Version: 1.0" + ${ECHO} "Content-type: $CONTENT;" + ${ECHO} " boundary=bound123ary${AFTERBOUND}" + fi + if [ ! -z "$SUBJECT" ]; then + ${ECHO} "Subject: $SUBJECT" + fi + ${ECHO} + make_body + return 0 +} + +############################ +# function to test testmsg # +############################ +send_test() +{ + { + ${ECHO} "X-num: #TSTMSG$1#" + ${ECHO} "To: ${SND}@$HOST" + } | ${QMPATH}/bin/qmail-inject + return 0 +} + +############################ +# sleeping 5 secs function # +############################ +sleep_5() +{ + sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "." + sleep 1; ${ECHO} -n "."; sleep 1; ${ECHO} -n "." + sleep 1; ${ECHO} -n "${1}" + return 0 +} + +################################ +# waiting for delivery fuction # +################################ +wait_test() +{ +${ECHO} -n "max 35s for delivery: " +sleep_5 5s +TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` +if [ -z "$TSTMSG" ]; then + sleep_5 10s + TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` + if [ -z "$TSTMSG" ]; then + sleep_5 15s + TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` + if [ -z "$TSTMSG" ]; then + sleep_5 20s + TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` + if [ -z "$TSTMSG" ]; then + sleep_5 25s + TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` + if [ -z "$TSTMSG" ]; then + sleep_5 30s + TSTMSG=`${GREP} -l "#TSTMSG$1" $SINKDIR/new/* 2>/dev/null` + if [ -z "$TSTMSG" ]; then + ${ECHO} + ${ECHO} "Delivery of test message failed. Fix qmail or wait" + ${ECHO} "longer and continue with argument \"-s $1\"" + exit 100 + fi + fi + fi + fi + fi +fi +sleep_5 OK +${ECHO} +${RM} -f "$TSTMSG" > "${ERR}" 2>&1 || \ + { ${ECHO} "failed to remove test message for section $1"; exit 100; } +TSTMSG='' +return 0 +} + +######################## +# remove old test list # +######################## +if [ "$SECT" = "1" ]; then + if [ $USESQL ]; then + ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${MAN}@$HOST" "${DIG}@$HOST" \ + >"${ERR}" 2>&1 + ${EZBIN}/ezmlm-unsub "${DIR}/mod" "${MOD}@$HOST" \ + >"${ERR}" 2>&1 + ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "aaa@bbb" "ccc@ddd" "eee@fff" \ + >"${ERR}" 2>&1 + fi + ${RM} -rf "${DIR}" ${DOT}* "${ERR}" >/dev/null 2>&1 +fi +${ECHO} + +################# +# check version # +################# + +# assume ezmlm-idx and ezmlm-test are different versions +SAME_VER='n' + +TMP_VER=`${EZBIN}/ezmlm-make -V 2>&1` || \ + { + ${ECHO} "This program only works with ezmlm-idx" + exit 100 + } +# ezmlm-idx-0313 does not support DEFAULT, so no sense testing it +THIS_VER=`${ECHO} "$TMP_VER" | cut -d'+' -f2` +${ECHO} "$THIS_VER" | ${GREP} "ezmlm-idx" > /dev/null 2>&1 || + THIS_VER=`${ECHO} "$TMP_VER" | cut -d' ' -f4` + +${ECHO} "testing ezmlm-idx: $THIS_VER" +${ECHO} "Using FQDN host name: $HOST" + +${ECHO} "$THIS_VER" | ${GREP} "$OLD_VER" >/dev/null 2>&1 +if [ "$?" = "0" ]; then + DLC='' + DUC='' + EZVER='31' + QMVER='o' + ALLOW='extra' # support old nomenclature + DENY='blacklist' +else + ${ECHO} "$THIS_VER" | ${GREP} "$VER" >/dev/null 2>&1 + if [ "$?" != "0" ]; then + ${ECHO} "Warning: ezmlm-make version is not $VER" + ${ECHO} " test info may not be reliable" + ${ECHO} + fi +########## should add testing of From line logging for non-0.31x + SW_FROM="-f" +fi + +# Now see if we support old qmail + + ${ECHO} "$THIS_VER" | ${GREP} "ezmlm-idx-0.32" >/dev/null 2>&1 && \ + EZVER='32'; + +if [ "$EZVER" != '31' -a "$EZVER" != '32' -a "$QMVER" = 'o' ]; then + ${ECHO} "Sorry, this version of ezmlm-idx requires qmail>=1.02" + exit 100; +fi + +if [ "$SECT" = "1" ]; then +############## +# ezmlm-make # +############## + ${ECHO} -n "ezmlm-make (1/2): " + +# edit non-existant list + ${EZBIN}/ezmlm-make -e -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \ + "$LOC" "$HOST" > /dev/null 2>&1 && \ + { ${ECHO} "ezmlm-make failed reject edit of non-existing list:" + exit 100; } + +# make simple test list + ${EZBIN}/ezmlm-make -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \ + "$LOC" "$HOST" || \ + { ${ECHO} "ezmlm-make failed to create test list"; exit 100; } + +# remake simple test list which should fail + ${EZBIN}/ezmlm-make -C${EZBIN}/ezmlmrc "${DIR}" "${DOT}" \ + "$LOC" "$HOST" >/dev/null 2>&1 && \ + { ${ECHO} "failed to reject creation of existing list"; exit 100; } + +# edit the list (add digest) + ${EZBIN}/ezmlm-make -+d -C${EZBIN}/ezmlmrc "${DIR}" || \ + { ${ECHO} "ezmlm-make failed to edit test list"; exit 100; } + +# edit the list (add digest) + ${MV} "${DIR}/config" "${DIR}/config~" + ${EZBIN}/ezmlm-make -ed -C${EZBIN}/ezmlmrc "${DIR}" "$DOT" "$LOC" "$HOST" \ + >/dev/null 2>&1 || \ + { ${ECHO} "failed without DIR/config: 0.313 bug, fixed in 0.314." + ${ECHO} -n "ezmlm-make ...... " + BUG="${BUG} config" + } + ${MV} "${DIR}/config~" "${DIR}/config" + + ${GREP} "ezmlm-weed" "${DIR}/bouncer" >/dev/null 2>&1 || \ + { ${ECHO} "no ezmlm-weed in bouncer"; exit 100; } + ${GREP} "ezmlm-return" "${DIR}/bouncer" >/dev/null 2>&1 || \ + { ${ECHO} "no ezmlm-return in bouncer: 0.32 bug, fixed in 0.321." + ${ECHO} -n "ezmlm-make ...... " + BUG="${BUG} return" + } +# digest/bouncer only for >=0.32 + if [ "$EZVER" != '31' ]; then + if [ ! -f "${DIR}/digest/bouncer" ]; then + echo "failed to create digest/bouncer"; exit 100; + fi + ${GREP} "ezmlm-weed" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \ + { ${ECHO} "no ezmlm-weed in bouncer"; exit 100; } + ${GREP} "ezmlm-return" "${DIR}/digest/bouncer" >/dev/null 2>&1 || \ + { ${ECHO} "no ezmlm-return in digest/bouncer: 0.32 bug, OK in 0.321." + ${ECHO} -n "ezmlm-make ...... " + BUG="${BUG} return" + } + fi + ${ECHO} "OK" + +# Add sql files for sql testing +RDBMS='STD' +${ECHO} -n "Using RDBMS support: " +if [ $USESQL ]; then + ${EZBIN}/ezmlm-make -+6 "$SQLHOST::$SQLUSER:$PW:$DB:$TABLE" \ + -C${EZBIN}/ezmlmrc "${DIR}"|| \ + { ${ECHO} "ezmlm-make failed to add SQL config info"; exit 100; } + + ${STRINGS} ${EZBIN}/ezmlm-sub | ${GREP} -i 'MySQL' >/dev/null 2>&1 && \ + RDBMS='MySQL' + ${STRINGS} ${EZBIN}/ezmlm-sub | ${GREP} -i 'libpq.' >/dev/null 2>&1 && \ + RDBMS='PostgreSQL' + if [ "$RDBMS" = 'STD' ]; then + ${ECHO} "No recognized support. If none, will default to std dbs." + else + ${ECHO} "$RDBMS. Hope empty tables exist." + fi + +else + ${ECHO} "No." +fi + +############################################################### +# set up subscriber/moderator/sender/digest recipient account # +############################################################### + ${MKDIR} "$SINKDIR" "$SINKDIR/new" "$SINKDIR/cur" "$SINKDIR/tmp" || \ + { ${ECHO} "mkdir for sinkdir failed"; exit 100; } + ${ECHO} "${SINKDIR}/" > "$DOT-$SINK" +# link for qmail version testing + ${ECHO} '|echo $DEFAULT >' "${DIR}/default" > "$DOT-$SINK-default" + ${ECHO} "${SINKDIR}/" >> "$DOT-$SINK-default" + + ${MKDIR} "$MODDIR" "$MODDIR/new" "$MODDIR/cur" "$MODDIR/tmp" || \ + { ${ECHO} "mkdir for moddir failed"; exit 100; } + ${ECHO} "${MODDIR}/" > "$DOT-$MODACC" + + ${MKDIR} "$MANDIR" "$MANDIR/new" "$MANDIR/cur" "$MANDIR/tmp" || \ + { ${ECHO} "mkdir for mandir failed"; exit 100; } + ${ECHO} "${MANDIR}/" > "$DOT-$MANAG" + + ${MKDIR} "$DIGDIR" "$DIGDIR/new" "$DIGDIR/cur" "$DIGDIR/tmp" || \ + { ${ECHO} "mkdir for digdir failed"; exit 100; } + ${ECHO} "${DIGDIR}/" > "$DOT-$DIGGG" + +fi + +########################### +# determine qmail version # +########################### + +if [ "$SECT" != "9" ]; then + +${ECHO} "Subject: zzz-test" > "${DIR}/__tmp" +${QMPATH}/bin/qmail-local "$EZTEST" "$HOME" "$SND-zzz" "$DASH" \ + "$LIST-$SINK-zzz" "$HOST" \ + "<>" '' < "${DIR}/__tmp" >"${ERR}" 2>&1 || \ + { ${ECHO} "-failed to deliver message with qmail-local"; exit 100; } + +if [ ! -r "${DIR}/default" ]; then + ${ECHO} "qmail-local failed to deliver the message. Can't determine" + ${ECHO} "qmail version" + exit 99 +fi + +if [ `cat "${DIR}/default"` = "zzz" ]; then + if [ -z "$QMVER" ]; then + QMVER="n" + fi +else + if [ -z "$QMVER" ]; then + QMVER="o" + fi +fi + +${ECHO} -n "testing for qmail: " +if [ "$QMVER" = "n" ]; then + ${ECHO} ">=1.02" +else + ${ECHO} "[any]" +fi + +# if testing for old version, make sure DEFAULT is not defined. If printenv +# is not available, we hope for the best and continue. unset should work ... +# Set BADUNSET if unset doesn't do the job + +A='a' +export A +${UNSET} A +[ -z "$A" ] || BADUNSET='y' + +${UNSET} DEFAULT + +if [ "$QMVER" = "o" ]; then + printenv PATH >/dev/null 2>&1 && \ + printenv DEFAULT > /dev/null 2>&1 && \ + { ${ECHO} "Can't test for old version of qmail if DEFAULT is defined. "; + ${ECHO} "Please undefine it."; exit 99; } +fi + +# correct bouncer for our binaries: +################################### +# NOTE: This is duplicated (and should be) after next ezmlm-make block. + ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/digest/bouncer" + if [ "$EZVER" = "31" ]; then # autodetecting bouncer for 0.31x + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer" + else # split bouncer with args for later versions + # edited for ezmlm-new + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer" + fi + +# if testing qmail>=1.02, remove inlocal/inhost - shouldn't be used + if [ "$QMVER" = "n" ]; then + ${RM} -f "${DIR}/inlocal" "${DIR}/inhost" > /dev/null || \ + { ${ECHO} "failed to remove inlocal/inhost for testlist"; exit 100; } + fi + +########################### +# set up bouncing account # +########################### + ${ECHO} "|${GREP} 'MAILER-DAEMON' >/dev/null && exit 99" > "$DOT-$BOUNCE" + ${ECHO} "|exit 100" > "$DOT-$BOUNCE" + +fi + +################################################### +# account to receive digests and archive excerpts # +################################################### + +if [ "$SECT" = "1" ]; then + +##################### +# test ezmlm-reject # +##################### + ${ECHO} -n "ezmlm-reject: " + FROM="$EZTEST" + TO="$EZTEST-__tstlist@$HOST" + SUBJECT="test" + CONTENT="multipart/mixed" + CC="<>" + BODY='' + +# with directory + make_message | ${EZBIN}/ezmlm-reject "${DIR}" || \ + { ${ECHO} "failed to accept good message with dir"; \ + exit 100; } +# without directory + + make_message | ${EZBIN}/ezmlm-reject || \ + { ${ECHO} "failed to accept good message without dir: $?"; \ + exit 100; } + +#too small + ${ECHO} "5000:1000" > "${DIR}/msgsize" + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject too small message"; \ + exit 100; } + +# just right + ${ECHO} "500:5" > "${DIR}/msgsize" + make_message | ${EZBIN}/ezmlm-reject "${DIR}" || \ + { ${ECHO} "failed to accept message of ok size"; \ + exit 100; } + +#too large + ${ECHO} "20:10" > "${DIR}/msgsize" + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject too large message"; \ + exit 100; } + +# restore + ${RM} -f "${DIR}/msgsize" + +# without subject + SUBJECT='' + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject message without subject"; \ + exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject message without subject"; \ + exit 100; } + +# with empty subject + SUBJECT='(NUll)' + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject null subject"; \ + exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \ + { ${ECHO} "ezmlm-reject failed to reject null subject"; \ + exit 100; } + +# testing -S + OUT=`make_message | ${EZBIN}/ezmlm-reject -S "${DIR}"` || \ + { ${ECHO} "-S switch failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject -S ` || \ + { ${ECHO} "-S switch failed without dir"; exit 100; } + +# with command subject + SUBJECT='REmOVE' + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "failed to reject command subject with dir"; \ + exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject 2>&1` && \ + { ${ECHO} "failed to reject command subject without dir"; \ + exit 100; } + +# testing -C + OUT=`make_message | ${EZBIN}/ezmlm-reject -C "${DIR}"` || \ + { ${ECHO} "-C switch failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject -C ` || \ + { ${ECHO} "-C switch failed without dir"; exit 100; } + + SUBJECT='test' + +# Test with list name in Cc: + CC="$TO" + TO="nobody@$HOST" + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \ + { ${ECHO} "failed to accept good Cc: with dir"; \ + exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "failed to accept good Cc: without dir"; \ + exit 100; } + +# Bad To/Cc + CC="$TO" + OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "failed to reject bad To/Cc with dir"; \ + exit 100; } + if [ "$?" != "100" ]; then + ${ECHO} "failed to exit 100 on error"; exit 100 + fi + OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject -q "${DIR}" 2>&1` && \ + { ${ECHO} "failed to reject bad To/Cc with dir"; \ + exit 100; } + if [ "$?" -ne "99" ]; then + ${ECHO} "-q failed"; exit 100 + fi + +# for backwards-compatibility and since we don't know inlocal@inhost without +# dir, ezmlm-reject doesn't check To/Cc when there is no dir + OUT=`make_message "$MESSAGE" | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "failed to accept bad To/Cc without dir"; \ + exit 100; } + +# testing -T + OUT=`make_message | ${EZBIN}/ezmlm-reject -T "${DIR}"` || \ + { ${ECHO} "-T switch failed with dir"; exit 100; } +OUT=`make_message | ${EZBIN}/ezmlm-reject -T ` || \ + { ${ECHO} "-T switch failed without dir"; exit 100; } + +# restore good TO + TO="$EZTEST-__tstlist@$HOST" + +# if part is mimereject message should be rejected + touch "${DIR}"/mimeremove + ${ECHO} "text/html" > "${DIR}"/mimereject + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "mimereject failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "mimereject without dir"; exit 100; } + +# if part is removed ezmlm-reject should not reject + ${ECHO} "tExt/htMl" > "${DIR}"/mimeremove + ${ECHO} "" > "${DIR}"/mimereject + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \ + { ${ECHO} "mimeremove failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "mimeremove without dir"; exit 100; } + +# test content-type with something after boundary=xxx + AFTERBOUND=';micalg=pgp-md5' + ${ECHO} "text/html" > "${DIR}"/mimereject + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322" + ${ECHO} -n "ezmlm-reject....... " + BUG="${BUG} reject_bound" + } + +# restore + ${RM} "${DIR}"/mimereject + AFTERBOUND='' + +# if entire message is mimeremove type is should be rejected + ${ECHO} "multipart/mixed" > "${DIR}"/mimeremove + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}" 2>&1` && \ + { ${ECHO} "mimereject failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "mimereject without dir"; exit 100; } + +# restore + ${RM} "${DIR}"/mimeremove + +# test headerreject + ${ECHO} "Content-TYPE" > "${DIR}"/headerreject + OUT=`make_message | ${EZBIN}/ezmlm-reject -H "${DIR}"` || \ + { ${ECHO} "headerreject -H failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject -h "${DIR}" 2>&1` && \ + { ${ECHO} "headerreject failed with dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject` || \ + { ${ECHO} "headerreject failed without dir"; exit 100; } + OUT=`make_message | ${EZBIN}/ezmlm-reject -h 2>&1` && \ + { ${ECHO} "-h was accepted without dir"; exit 100; } + +# Suppress content-type header + CONTENT='' + OUT=`make_message | ${EZBIN}/ezmlm-reject "${DIR}"` || \ + { ${ECHO} "headerreject rejected even though header isn't there"; \ + exit 100; } + + CONTENT='multIpart/mIXed' + + ${ECHO} "OK" +############################### +# ezmlm-sub/unsub/list/issubn # +############################### + + ${ECHO} -n "ezmlm-[un|is]sub[n]: " + + SENDER="XYZZY@HOst"; export SENDER + +# With mysql testing, there may be junk left from earlier testing that +# gives false positives in testing. Make sure it's detected + ${EZBIN}/ezmlm-list "${DIR}" >/dev/null || \ + { ${ECHO} "ezmlm-list: failed"; exit 100; } + + ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} '@' >/dev/null 2>&1 && \ + { ${ECHO} "already addresses in table - please remove and start again"; + exit 100; } + + ${EZBIN}/ezmlm-list "${DIR}/digest" | ${GREP} '@' >/dev/null 2>&1 && \ + { ${ECHO} "already addresses in table - please remove and start again"; + exit 100; } + + ${EZBIN}/ezmlm-list "${DIR}/${ALLOW}" | ${GREP} '@' >/dev/null 2>&1 && \ + { ${ECHO} "already addresses in table - please remove and start again"; + exit 100; } + +# not subscriber. Test default + ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" && \ + { ${ECHO} "ezmlm-issubn: failed: exit 0 on non-subscriber"; exit 100; } + +# not subscriber. Test -n + ${EZBIN}/ezmlm-issubn -n "${DIR}" "${DIR}/${ALLOW}" || \ + { ${ECHO} "ezmlm-issubn: -n failed for non-subscriber"; exit 100; } + +# add subscriber + ${EZBIN}/ezmlm-sub "${DIR}" "xyZZy@hoSt" || \ + { ${ECHO} "ezmlm-sub: failed to add subscriber"; exit 100; } + +# is subscriber. Test default + ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" || \ + { ${ECHO} "ezmlm-issubn: failed: exit false for subscriber"; exit 100; } + +# is subscriber. Test -n + ${EZBIN}/ezmlm-issubn -n "${DIR}" "${DIR}/${ALLOW}" && \ + { ${ECHO} "ezmlm-issubn: -n failed for subscriber"; exit 100; } + +# add to allow + ${EZBIN}/ezmlm-sub "${DIR}/${ALLOW}" "ZZtop@hoSt" || \ + { ${ECHO} "ezmlm-sub: failed to add address to ${DIR}/${ALLOW}"; exit 100; } + +# list subscribers + ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} "xyZZy" >"${ERR}" 2>&1 || \ + { ${ECHO} "ezmlm-list: failed to list subscribers"; exit 100; } + +# remove subscriber + ${EZBIN}/ezmlm-unsub "${DIR}" "xYzZy@hOst" || \ + { ${ECHO} "ezmlm-sub: failed to add subscriber"; exit 100; } + +# see that it was removed + ${EZBIN}/ezmlm-list "${DIR}" | ${GREP} "xyZZy" >"${ERR}" 2>&1 && \ + { ${ECHO} "ezmlm-unsub: failed to remove subscriber"; exit 100; } + + SENDER="zztop@HOst"; export SENDER + +# check for address in allow + ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" || \ + { ${ECHO} "ezmlm-sub/issubn: failed to add/look in 2nd db"; exit 100; } + +# remove (multiple) (non)existing addresses from allow + ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "xYzZy@hOst" "zZToP@HOSt" || \ + { ${ECHO} "ezmlm-unsub: failed to remove subscriber"; exit 100; } + +# verify removal + ${EZBIN}/ezmlm-issubn "${DIR}" "${DIR}/${ALLOW}" && \ + { ${ECHO} "ezmlm-unsub/issubn: failed to remove address"; exit 100; } + +# clean up + LOCAL=''; export LOCAL + + ${ECHO} "OK" +############## +# ezmlm-send # +############## + ${ECHO} -n "ezmlm-send (1/2): " + + SENDER="${SND}@$HOST"; export SENDER + ${EZBIN}/ezmlm-sub "${DIR}" "$SENDER" +# set up prefix + ${ECHO} "[PFX]" > "${DIR}/prefix" +# set up trailer + { ${ECHO} "--- TRAILER ---"; ${ECHO}; } > "${DIR}/text/trailer" +# test + { ${ECHO} "X-num: msg1"; make_message; } | \ + ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept normal message"; exit 100; } + if [ `cat "${DIR}/num"` != "1:1" ]; then + ${ECHO} "failed to create num for normal message 1"; exit 100; + fi + if [ ! -x "${DIR}/archive/0/01" ]; then + { ${ECHO} "failed to archive normal message"; exit 100; } + fi + ${GREP} "1:" "${DIR}/archive/0/index" >/dev/null 2>&1 || \ + { ${ECHO} "failed to index archive"; exit 100; } + + ${RM} -f "${DIR}/indexed" + ${RM} -f "${DIR}/archived" + +# test to see that trailer is added to nom-mime messages + CONTENT='' + { echo "X-num: msg5"; make_message; } | \ + ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept non-mime message"; exit 100; } + +# test to see that trailer is suppressed for multipart/signed + CONTENT='multipart/signed' + { echo "X-num: msg6"; make_message; } | \ + ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept multipart/signed message"; exit 100; } + +# restore + CONTENT='multipart/mixed' + +# test content-type with something after boundary=xxx + AFTERBOUND=';micalg=pgp-md5' + ${ECHO} "text/html" > "${DIR}"/mimeremove + make_message | ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "err with text after boundary: 0.30 bug fixed in 0.322" + ${ECHO} -n "ezmlm-send......... " + BUG="${BUG} send_bound" + } +# restore + AFTERBOUND='' + ${ECHO} "1:1" > "${DIR}/num" + ${RM} "${DIR}"/mimeremove + +# -r => don't trim received headers + { ${ECHO} "X-num: msg2"; make_message; } | \ + ${EZBIN}/ezmlm-send -r "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept normal message 2"; exit 100; } + + ${GREP} "2:" "${DIR}/archive/0/index" >/dev/null 2>&1 && \ + { ${ECHO} "indexed message with DIR/indexed missing"; exit 100; } + ${GREP} "msg2" ${DIR}/archive/0/* >/dev/null 2>&1 && \ + { ${ECHO} "archived message with DIR/archived missing"; exit 100; } + +# -C eliminate SENDER from addressees + { ${ECHO} "X-num: msg3"; make_message; } | \ + ${EZBIN}/ezmlm-send -C "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept normal message 3"; exit 100; } + ${EZBIN}/ezmlm-unsub "${DIR}" "$SENDER" + +# make sure headerremove was done + ${GREP} -i 'return-receipt-to' < "${DIR}/archive/0/01" >/dev/null && + { ${ECHO} "failed to remove headerremove"; exit 100; } +# test mimeremove + touch "${DIR}/archived" "${DIR}/indexed" + ${ECHO} "teXT/hTml" > "${DIR}/mimeremove" + { ${ECHO} "X-num: msg4"; make_message; } | \ + ${EZBIN}/ezmlm-send "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed to accept mimeremove message"; exit 100; } + ${GREP} -i 'text/html' < "${DIR}/archive/0/04" >/dev/null && + { ${ECHO} "failed to remove mimeremove part"; exit 100; } + + ${ECHO} "OK" +################ +# ezmlm-tstdig # +################ + ${ECHO} -n "ezmlm-tstdig: " + + ${EZBIN}/ezmlm-tstdig -k2 -m5 -t1 "${DIR}" || \ + { ${ECHO} "-t1 failed"; exit 100; } + ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" && \ + { ${ECHO} "-t0 failed"; exit 100; } + + LOCAL="$LOC-xx"; export LOCAL + if [ "$QMVER" = "n" ]; then + DEFAULT='xx'; export DEFAULT + fi + ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" || \ + { ${ECHO} "problem with -xx in manager position"; exit 100; } + LOCAL="$LOC-dig."; export LOCAL + if [ "$QMVER" = "n" ]; then + DEFAULT='dig.'; export DEFAULT + fi + ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" && \ + { ${ECHO} "problem with -dig in manager position"; exit 100; } + LOCAL="$LOC-digest-"; export LOCAL + if [ "$QMVER" = "n" ]; then + DEFAULT='digest-'; export DEFAULT + fi + ${EZBIN}/ezmlm-tstdig -k2 -m5 -t0 "${DIR}" || \ + { ${ECHO} "err with -digest- in mgr pos: 0.31 bug fixed in 0.321" + ${ECHO} -n "ezmlm-tstdig....... " + BUG="${BUG} digest" + } + LOCAL=''; export LOCAL + if [ "$QMVER" = "n" ]; then + unset DEFAULT + fi + ${EZBIN}/ezmlm-tstdig -k2 -m4 -t1 "${DIR}" || \ + { ${ECHO} "-m failed"; exit 100; } + ${EZBIN}/ezmlm-tstdig -k1 -m5 -t0 "${DIR}" || \ + { ${ECHO} "-k failed"; exit 100; } + LOCAL="$LOC"; export LOCAL + ${EZBIN}/ezmlm-tstdig -k1 -m5 -t0 "${DIR}" > "${ERR}" 2>&1 || \ + { + ${ECHO} "problem with DEFAULT unset: 0.32 bug, OK in 0.321." + ${ECHO} -n "ezmlm-tstdig....... " + BUG="${BUG} tstdig" + } + ${ECHO} "OK" + +############## +# ezmlm-weed # +############## + + ${ECHO} -n "ezmlm-weed: " + + ${ECHO} "Subject: test" | ${EZBIN}/ezmlm-weed || \ + { ${ECHO} "failed to accept good message"; exit 100; } + ${ECHO} "Subject: success notice" | ${EZBIN}/ezmlm-weed >/dev/null 2>&1 && \ + { ${ECHO} "failed to reject bad message"; exit 100; } + + ${ECHO} "OK" + +############## +# ezmlm-make # +############## + ${ECHO} -n "ezmlm-make (2/2): " + +# make sure a few ezmlm-make switches work + ${EZBIN}/ezmlm-make -+qkgu -C${EZBIN}/ezmlmrc "${DIR}" || \ + { ${ECHO} "failed to edit test list to +qkgu"; exit 100; } + ${GREP} "${DENY}" "${DIR}/editor" >/dev/null 2>&1 || \ + { ${ECHO} "failed to implement -k for list"; exit 100; } + ${GREP} "ezmlm-request" "${DIR}/manager" >/dev/null 2>&1 || \ + { ${ECHO} "failed to implement -q for list"; exit 100; } + ${GREP} "ezmlm-get -s" "${DIR}/manager" >/dev/null 2>&1 || \ + { ${ECHO} "failed to implement -g for list"; exit 100; } + ${GREP} "${ALLOW}" "${DIR}/editor" >/dev/null 2>&1 || \ + { ${ECHO} "failed to implement -u for list"; exit 100; } + + ${EZBIN}/ezmlm-make -+QKGU -C${EZBIN}/ezmlmrc "${DIR}" || \ + { ${ECHO} "failed to edit test list to +QKGU"; exit 100; } + ${GREP} "${DENY}" "${DIR}/editor" >/dev/null 2>&1 && \ + { ${ECHO} "failed to implement -K for list"; exit 100; } + ${GREP} "ezmlm-request" "${DIR}/manager" >/dev/null 2>&1 && \ + { ${ECHO} "failed to implement -Q for list"; exit 100; } + ${GREP} "ezmlm-get -s" "${DIR}/manager" >/dev/null 2>&1 && \ + { ${ECHO} "failed to implement -G for list"; exit 100; } + ${GREP} "${ALLOW}" "${DIR}/editor" >/dev/null 2>&1 && \ + { ${ECHO} "failed to implement -U for list"; exit 100; } + +# edit the list (add moderation and remove admin) + ${EZBIN}/ezmlm-make -+rsm -C${EZBIN}/ezmlmrc "${DIR}" || \ + { ${ECHO} "failed to edit test list to +rsm"; exit 100; } +# edit the list (add text file editing and list/log) +${EZBIN}/ezmlm-make -+ln -C${EZBIN}/ezmlmrc "${DIR}" || \ + { ${ECHO} "failed to edit test list to +ln"; exit 100; } + +# Now to create our own manager for later tests: + +${ECHO} "|${GREP} 'req1' >/dev/null 2>&1 && { ${ECHO} \"\$LOCAL\" >> '${REQ}'; exit 99; }; exit 0" > "${DIR}/manager" +${ECHO} "|${EZBIN}/ezmlm-manage -le ${SW_FROM} '${DIR}'" >> "${DIR}/manager" +${ECHO} "OK" + +# correct bouncer for our binaries: +################################### + ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-weed" > "${DIR}/digest/bouncer" + if [ "$EZVER" = "31" ]; then # autodetecting bouncer for 0.31x + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-return '${DIR}'" >> "${DIR}/digest/bouncer" + else # split bouncer with args for later versions + ${ECHO} "|/${EZBIN}/ezmlm-return -D '${DIR}'" >> "${DIR}/bouncer" + ${ECHO} "|/${EZBIN}/ezmlm-return -d '${DIR}'" >> "${DIR}/digest/bouncer" + fi + +# if testing qmail>=1.02, remove inlocal/inhost - shouldn't be used + if [ "$QMVER" = "n" ]; then + ${RM} -f "${DIR}/inlocal" "${DIR}/inhost" > /dev/null || \ + { ${ECHO} "failed to remove inlocal/inhost for testlist"; exit 100; } + fi + + +############### +# ezmlm-clean # +############### + + ${ECHO} -n "ezmlm-clean (1/2): " + +# clean1 should be silently removed (no -x). +# clean2 should result in a message +# clean3 should not since it's time hasn't come +# clean4 should be removed, but not result in a message since we use -R + + ${ECHO} "Return-Path: <${DIG}@$HOST>" > "${DIR}/mod/pending/1" + ${ECHO} "X-num: clean1" >> "${DIR}/mod/pending/1" + ${ECHO} "Return-Path: <${DIG}@${HOST}>" > "${DIR}/mod/pending/2" + ${ECHO} "X-num: clean2" >> "${DIR}/mod/pending/2" + ${ECHO} "Return-Path: <${DIG}@$HOST>" > "${DIR}/mod/pending/999999999" + ${ECHO} "X-num: clean3" >> "${DIR}/mod/pending/999999999" + + chmod +x "${DIR}/mod/pending/2" "${DIR}/mod/pending/999999999" + + ${EZBIN}/ezmlm-clean "${DIR}" >"${ERR}" 2>&1 || + { ${ECHO} "failed first invocation"; exit 100; } + if [ -r "${DIR}/mod/pending/1" ]; then + ${ECHO} "failed to remove non-x moderation queue entry 1" + exit 100 + fi + if [ -r "${DIR}/mod/pending/2" ]; then + ${ECHO} "failed to remove moderation queue entry 2" + exit 100 + fi + if [ ! -r "${DIR}/mod/pending/999999999" ]; then + ${ECHO} "removed mod queue entry 3 that wasn't due" + exit 100 + fi + +${ECHO} < "${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}" "${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 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}" "${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}" "${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}" "${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}" \ + "${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}" \ + "${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 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 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 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 2>&1 || \ + { ${ECHO} "failed to silently ignore re-acceptance"; exit 100; } + +${ECHO} "OK" + +# cleanup +${EZBIN}/ezmlm-unsub "${DIR}" "${SND}@$HOST" + +############## +# ezmlm-warn # +############## +${ECHO} -n "ezmlm-warn (2/3): " + +${EZBIN}/ezmlm-warn -t0 "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed with normal bounce for warning"; exit 100; } + +${EZBIN}/ezmlm-warn -d -t0 "${DIR}" >"${ERR}" 2>&1 || \ + { ${ECHO} "failed with digest bounce for warning"; exit 100; } + +${ECHO} "OK" + +################# +# ezmlm-request # +################# + + ${ECHO} -n "ezmlm-request (2/2): " + + ${GREP} "$LOC-qqqq-$SND=$HOST" "${REQ}" >/dev/null || \ + { ${ECHO} "'qqqq' subject query rewriting failed"; exit 100; } + + ${GREP} "$LOC-unsubscribe-$SND=$HOST" "${REQ}" >/dev/null || \ + { ${ECHO} "ezmlm 'remove' subject query rewriting failed"; exit 100; } + + ${ECHO} "OK" + +######################## +# waiting for delivery # +######################## + send_test 3 +fi # end section 2 + +######################################### start of section 3 +if [ "$SECT" -le "3" ]; then + wait_test 3 + +############### +# ezmlm-split # +############### +if [ "$QMVER" = "n" ]; then + ${ECHO} -n "ezmlm-split (2/2): " + +# we know that ezmlm-manage works. A bounce would go to MODDIR, so a +# message in SINKDIR means that the request was forwarded to ezmlm-manage, +# which replied with a confirmation request. + ${GREP} 'X-num: spl1' $SINKDIR/new/* > /dev/null 2>&1 || \ + { ${ECHO} "failed to receive sub conf req."; + ${ECHO} "this could be a failure of ezmlm-split, but usually,"; + ${ECHO} "it happens because ezmlm binaries when run by qmail"; + ${ECHO} "don't have access to shared libraries required for"; + ${ECHO} "RDBMS access. This happens on systems where RDBMS"; + ${ECHO} "shared libs are installed in the /usr/local hierarchy."; + ${ECHO} "fix: see ld.so man page on how to modify /etc/ld.so.conf"; + ${ECHO} "or compile statically by adding -static to conf-sqlld."; + ${ECHO} + exit 100; } + + ${ECHO} "OK" +fi + +################## +# ezmlm-moderate # +################## + + ${ECHO} -n "ezmlm-moderate (2/2): " + + MOD1=`${GREP} -l "mod1" $SINKDIR/new/* | head -1` || \ + { ${ECHO} "failed to send rejection notice for message mod1"; exit 100; } + +# ${SND}@$HOST means it was rejected, not send through the list + ${GREP} "To: ${SND}@$HOST" "$MOD1" > /dev/null 2>&1 || \ + { ${ECHO} "failed to reject message mod1"; exit 100; } + + MOD3=`${GREP} -l "mod3" $SINKDIR/new/* | head -1` + if [ -z "$MOD3" ]; then + ${ECHO} "failed to post message mod3" + exit 100 + fi + +# ${LOC}@$HOST means it was not rejected, but sent through the list + ${GREP} "To: ${LOC}@$HOST" "$MOD3" > /dev/null 2>&1 || \ + { ${ECHO} "failed to reject message mod3"; exit 100; } + + ${ECHO} "OK" + +################ +# ezmlm-manage # +################ + ${ECHO} -n "ezmlm-manage (3/4): " + + SENDER="${MOD}@$HOST"; export SENDER + ${EZBIN}/ezmlm-issubn "${DIR}" && \ + { ${ECHO} "unsub without mod for moderated list failed"; exit 100; } + + SUB3=`${GREP} -l 'sub3' $MODDIR/new/*` || \ + { ${ECHO} "failed getting subscribe moderation confirm request"; \ + exit 100; } + +# confirm subscription request + LOCAL=`${GREP} "Reply-To:" "$SUB3" | cut -d' ' -f2 | cut -d'@' -f1` || \ + { ${ECHO} "no confirm address in sub3 mod confirm request"; exit 100; } + export LOCAL + if [ "$QMVER" = "n" ]; then + DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT + fi + ${ECHO} "X-num: modR1" > "${DIR}/__tmp" + ${ECHO} "FROM: moderator agrees <$SENDER>" >> "${DIR}/__tmp" + ${ECHO} >> "${DIR}/__tmp" + ${EZBIN}/ezmlm-manage ${SW_FROM} "${DIR}" < "${DIR}/__tmp"\ + >/dev/null 2>&1 || \ + { ${ECHO} "failed to send digest sub mod accept for sub3"; exit 100; } + +# complete edit. SENDER can be any address + SENDER="${MAN}@$HOST"; export SENDER + EDIT3=`${GREP} -l 'edit3' $MODDIR/new/*` || \ + { ${ECHO} "failed getting edit reply for edit3"; \ + exit 100; } + ${GREP} "#TEST_TEXT#" "$EDIT3" >/dev/null 2>&1 || \ + { ${ECHO} "old text missing in edit3 edit reply"; exit 100; } + LOCAL=`${GREP} "Reply-To:" "$EDIT3" | cut -d' ' -f2 | cut -d'@' -f1` || \ + { ${ECHO} "no reply address in edit3 edit reply"; exit 100; } + export LOCAL + if [ "$QMVER" = "n" ]; then + DEFAULT=`${ECHO} "$LOCAL" | cut -c"$LOCLEN"-`; export DEFAULT + fi + ${ECHO} "X-num: edit4" > "${DIR}/__tmp" + ${ECHO} >> "${DIR}/__tmp" + ${ECHO} "%%% START OF TEXT FILE" >> "${DIR}/__tmp" + ${ECHO} "#NEW_TEXT#" >> "${DIR}/__tmp" + ${ECHO} "%%% END OF TEXT FILE" >> "${DIR}/__tmp" + ${EZBIN}/ezmlm-manage -e "${DIR}" < "${DIR}/__tmp" >/dev/null 2>&1 || \ + { ${ECHO} "failed to send edit4 reply for edit3"; exit 100; } + +# check results of log/list + LOG3=`${GREP} -l 'log3' $MODDIR/new/*` || \ + { ${ECHO} "failed getting -log reply to log3"; \ + exit 100; } + ${GREP} "aaa@bbb" "$LOG3" | ${GREP} "+m" > /dev/null 2>&1 || \ + { ${ECHO} "failed to get log reply to log3"; exit 100; } + + LIST3=`${GREP} -l 'list3' $MODDIR/new/*` || \ + { ${ECHO} "failed getting -list reply to list3"; \ + exit 100; } + ${GREP} "aaa@bbb" "$LIST3" > /dev/null 2>&1 || \ + { ${ECHO} "failed to get list reply to list3"; exit 100; } + + ${ECHO} "OK" + +############# +# ezmlm-get # +############# + ${ECHO} -n "ezmlm-get (2/2): " + +# index1/get1/thread1 should bounce and will not be looked for +# index2 ... should be in DIG@HOST's inbox +# get3 - r format to DIG@HST +# get4 - n +# get5 - v +# get6 - x + +# well - just a consistency check + ${GREP} "index1" ${DIGDIR}/new/* >/dev/null 2>&1 && \ + { ${ECHO} "index1 found in wrong mailbox"; exit 100; } + +# now check that they've been delivered. We don't check the formats, +# as this would be quite involved. + ${GREP} "index2" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "index2 failed to return"; exit 100; } + ${GREP} "get2" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "get2 failed to return"; exit 100; } + ${GREP} "get3" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "get3 format 'r' failed to return"; exit 100; } + ${GREP} "get4" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "get3 format 'n' failed to return"; exit 100; } + ${GREP} "get5" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "get3 format 'v' failed to return"; exit 100; } + ${GREP} "get6" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "get3 format 'x' failed to return"; exit 100; } + + ${GREP} "dig1" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig1 from manager wasn't delivered"; exit 100; } + ${GREP} "dig2" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig2 from editor wasn't delivered"; exit 100; } + ${GREP} "dig3" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig3 from command line wasn't delivered"; exit 100; } + ${GREP} "dig4" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig4 format 'r' wasn't delivered"; exit 100; } + ${GREP} "dig5" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig5 format 'n' wasn't delivered"; exit 100; } + ${GREP} "dig6" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig6 format 'x' wasn't delivered"; exit 100; } + ${GREP} "dig6" ${DIGDIR}/new/* >/dev/null 2>&1 || \ + { ${ECHO} "dig6 format 'v' wasn't delivered"; exit 100; } + + ${ECHO} "OK" + + +######################## +# waiting for delivery # +######################## + send_test 4 +fi # end section 3 + +####################################### start of section 4 +if [ "$SECT" -le "4" ]; then + wait_test 4 + +############## +# ezmlm-warn # +############## + ${ECHO} -n "ezmlm-warn (3/3): " + + SENDER="${BNC}@${HOST}" + export SENDER + ${EZBIN}/ezmlm-issubn -n "${DIR}" || \ + { ${ECHO} "failed to remove bouncing subscriber"; exit 100; } + ${EZBIN}/ezmlm-issubn -n "${DIR}/digest" || \ + { ${ECHO} "failed to remove bouncing digest subscriber"; exit 100; } + + ${ECHO} "OK" + +################ +# ezmlm-manage # +################ + ${ECHO} -n "ezmlm-manage (4/4): " + + ${GREP} "#NEW_TEXT#" "${DIR}/text/test" >/dev/null 2>&1 || \ + { ${ECHO} "edit4 failed to update text file"; exit 100; } + + ${ECHO} "OK" + +fi # end section 4 + +########################## start of section 9 (cleanup) +if [ "$SECT" -eq "9" -o -z "$DEBUG" ]; then + +##################### +# remove test files # +##################### + + +# cleanup the mysql sub tables so we can repeat if necessary +# the Log test will pass due to old data once we access the mysql log, +# rather than the file, but what the ... + if [ $USESQL ]; then + ${EZBIN}/ezmlm-unsub "${DIR}/digest" "${MAN}@$HOST" "${DIG}@$HOST" \ + >/dev/null 2>&1 + ${EZBIN}/ezmlm-unsub "${DIR}/mod" "${MOD}@$HOST" \ + >/dev/null 2>&1 + ${EZBIN}/ezmlm-unsub "${DIR}/${ALLOW}" "aaa@bbb" "ccc@ddd" "eee@fff" \ + >/dev/null 2>&1 + fi + ${RM} -rf "${DIR}" ${DOT}* "${ERR}" >/dev/null 2>&1 + +fi +${ECHO} +if [ ! -z "${BUG}" ]; then + ${ECHO} "${BUG}" | ${GREP} "config" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The config bug prevents editing lists created with" + ${ECHO} "ezmlm-idx<0.31 or ezmlm-0.53. 'touch DIR/config' is a work-" + ${ECHO} "around, and upgrading to >=0.314 corrects it." + } + ${ECHO} "${BUG}" | ${GREP} "deny" >/dev/null 2>&1 && \ + { + ${ECHO} + if [ "$EZVER" = '31' ]; then + ${ECHO} "The DENY bug allows users to remove themselves" + ${ECHO} "from DIR/blacklist which is not intended, but OTOH," + ${ECHO} "DIR/blacklist is not intended for this and as a SENDER check" + ${ECHO} "inherently insecure anyway. If you need this feature and the" + ${ECHO} "bug is a problem, upgrade to >=0.321." + else + ${ECHO} "DENY access means that subscribers can remove"; + ${ECHO} "themselves from DIR/deny. This is a bug, but DENY" + ${ECHO} "is easy to circumvent and not intended to keep users from" + ${ECHO} "posting, anyway." + ${ECHO} "The bug is fixed in >=0.321." + fi + } + ${ECHO} "${BUG}" | ${GREP} "return" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The failure to add the ezmlm-return lines means" + ${ECHO} "that old lists will work correctly, but bounce handling" + ${ECHO} "won't work in lists created with this version." + ${ECHO} "The bug is fixed in >=0.321." + } + ${ECHO} "${BUG}" | ${GREP} "tstdig" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The ezmlm-tstdig bug means that DIR/inlocal still needs to be" + ${ECHO} "adjusted for with digests within virtual domains." + ${ECHO} "The bug is fixed in >=0.321." + } + ${ECHO} "${BUG}" | ${GREP} "digest" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The ezmlm-tstdig -digest- bug means that ezmlm-tstdig when" + ${ECHO} "in DIR/manager does not pass on digest subscribe request." + ${ECHO} "Upgrade to ezmlm-idx>=0.321 if you use ezmlm-tstdig in" + ${ECHO} "DIR/manager (this is NOT used except in custom or very" + ${ECHO} "old (ezlm-idx<0.30) digest setups)." + } + ${ECHO} "${BUG}" | ${GREP} "_bound" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The ezmlm-send/reject mimeremove bug caused erroneous" + ${ECHO} "rejection of messages with text after the mime boundary in the" + ${ECHO} "Content-type header when DIR/mimeremove was used. This type" + ${ECHO} "of message is very rare (mainly Mutt with PGP MIME)." + } + ${ECHO} "${BUG}" | ${GREP} "_noself" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The ezmlm-send -C switch 'not to sender' is no longer" + ${ECHO} "supported. For backwards compatibility the switch is" + ${ECHO} "ignored. Instead, implement this feature in the recipients" + ${ECHO} "mailbox by rejecting messages from the list with the" + ${ECHO} "recipient's address in the From: header." + } + ${ECHO} "${BUG}" | ${GREP} "_signed" >/dev/null 2>&1 && \ + { + ${ECHO} + ${ECHO} "The trailer is added as a separate MIME part to multipart" + ${ECHO} "messages, but should be suppressed not only for multipart" + ${ECHO} "alternative, but also for many other multipart types," + ${ECHO} "including multipart/signed." + } + ${ECHO} +fi + +exit 0 + + diff --git a/ezmlm-tstdig.1 b/ezmlm-tstdig.1 new file mode 100644 index 0000000..3bd3185 --- /dev/null +++ b/ezmlm-tstdig.1 @@ -0,0 +1,112 @@ +.TH ezmlm-tstdig 1 +.SH NAME +ezmlm-tstdig \- Tests if a digest should be created +.SH SYNOPSIS +.B ezmlm-tstdig +[ +.B -k +.I kbytes +] [ +.B -m +.I msg +] [ +.B \-t +.I time +] +.I dir + +.B ezmlm-tstdig +reads files in the list directory +.I dir +and determines if any of the criteria specified by the options are met. +If they are, or if all options specified are 0, +.B ezmlm-tstdig +exits with success (0). Otherwise, +.B ezmlm-tstdig +exits (99), or in case of errors, (100) for permanent and (111) for temporary +errors. + +The normal use of +.B ezmlm-tstdig +is to place it in a script so that +.B ezmlm-get(1) +is executed if +.B ezmlm-tstdig +exists 0, but skipped otherwise. + +.B ezmlm-tstdig +uses LOCAL to adapt its behavior so that it +can be used from the command line, a script, or from within +.IR dir\fB/editor , +or +.IR dir\fB/manager . +If invoked from +.IR dir\fB/editor , +the +.B ezmlm-tstdig +line should end in '|| exit 99'. +When used here, +.B ezmlm-tstdig +if digest generation criteria are met +tests a +timestamp in +.IR dir\fB/tstdig . +If +.I dir\fB/tstdig +is more than 1 hour old or a digest has been successfully created since +.I dir\fB/tstdig +was written, +.B ezmlm-tstdig +will set the timestamp to the current time and exit 0. Otherwise it will +exit 99. This is to guard against initiating duplicate digests when messages +arrive while digesting is in progress. +.SH OPTIONS +.TP +.B \-k +Success if more than +.I kbytes +of message body has accumulated since the latest digest. +.TP +.B \-m +Success if more than +.I msg +messages have accumulated since the latest digest. +.TP +.B \-t +Success if more than +.I time +hours have passed since the latest digest. +.SH USAGE +This is an example script for ezmlm-tstdig usage. + +.RS +.nf +#!/bin/sh +#usage: script dir diglist@host +#digest if > 64 kbytes message bodies, +# > 30 messages, or +# > 48 hours since last digest. + +# ezmlm bin path - modify for your setup +EZPATH='/usr/local/bin/ezmlm' + +EZTST="${EZPATH}/ezmlm-tstdig" +EZGET="${EZPATH}/ezmlm-get" +${EZTST} -k64 -m30 -t48 "$1" || exit 0 +${EZGET} -t "'$2'" "'$1'" < /dev/null +# improve by testing exit status +.fi +.RE +.PP +.SH BUGS +Obviously, +.B ezmlm-tstdig +should be integrated into the digesting program so that +.I dir\fB/tstdig +will not be not necessary. This may be done in the next version. +.SH "SEE ALSO" +ezmlm-get(1), +ezmlm-make(1), +ezmlm-manage(1), +ezmlm-send(1), +ezmlm(5) diff --git a/ezmlm-tstdig.c b/ezmlm-tstdig.c new file mode 100644 index 0000000..dc073ea --- /dev/null +++ b/ezmlm-tstdig.c @@ -0,0 +1,176 @@ +/*$Id: ezmlm-tstdig.c,v 1.17 1999/03/20 16:43:42 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include +#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); +} + diff --git a/ezmlm-unsub.1 b/ezmlm-unsub.1 index 7223ae9..8fcfd63 100644 --- a/ezmlm-unsub.1 +++ b/ezmlm-unsub.1 @@ -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 @@ removes each address 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 @@ converts 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) diff --git a/ezmlm-unsub.c b/ezmlm-unsub.c index 3f53890..89eb450 100644 --- a/ezmlm-unsub.c +++ b/ezmlm-unsub.c @@ -1,9 +1,27 @@ #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; @@ -11,24 +29,69 @@ char **argv; { 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); } diff --git a/ezmlm-warn.1 b/ezmlm-warn.1 index 06fd0b0..48048a5 100644 --- a/ezmlm-warn.1 +++ b/ezmlm-warn.1 @@ -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 @@ for the mailing list stored in .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), diff --git a/ezmlm-warn.c b/ezmlm-warn.c index 3140976..7d601e3 100644 --- a/ezmlm-warn.c +++ b/ezmlm-warn.c @@ -1,3 +1,5 @@ +/*$Id: ezmlm-warn.c,v 1.27 1999/08/07 20:47:26 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ #include #include #include "direntry.h" @@ -6,6 +8,7 @@ #include "substdio.h" #include "stralloc.h" #include "slurp.h" +#include "sgetopt.h" #include "getconf.h" #include "byte.h" #include "error.h" @@ -18,22 +21,53 @@ #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; @@ -46,6 +80,7 @@ char hash[COOKIE]; 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; @@ -58,35 +93,29 @@ substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); 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); @@ -95,29 +124,42 @@ int flagw; 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); @@ -126,34 +168,84 @@ int flagw; 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(); @@ -170,8 +262,8 @@ int flagw; 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); @@ -179,76 +271,252 @@ int flagw; 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); } diff --git a/ezmlm-weed.1 b/ezmlm-weed.1 index 5a5911f..4233717 100644 --- a/ezmlm-weed.1 +++ b/ezmlm-weed.1 @@ -7,6 +7,8 @@ ezmlm-weed \- weed out useless messages .B ezmlm-weed reads a mail message from its standard input. If it recognizes the message as an MTA warning message or success message, +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 @@ Generic warning message, recommended for all MTAs: 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 @@ Non-MIME form: .EX THIS IS A WARNING MESSAGE ONLY .EE + +Notification messages from Novell Groupwise: + +.EX + Subject: Message status - delivered +.EE +.br +.EX + Subject: Message status - opened +.EE +.br +.EX + Subject: Out of Office AutoReply: +.EE + .SH "SEE ALSO" ezmlm-return(1), qmail-command(8) diff --git a/ezmlm-weed.c b/ezmlm-weed.c index 777fa03..4ec3906 100644 --- a/ezmlm-weed.c +++ b/ezmlm-weed.c @@ -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 line6 = {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 **"; @@ -40,19 +49,46 @@ int flagsw = 0; int flagsr = 0; int flagas = 0; int flagbw = 0; +int flagdsn = 0; + +int isboundary() +/* returns 1 if line.len contains the mime bondary, 0 otherwise */ +{ + if (line.s[0] == '-' && line.s[1] == '-' && line.len >= boundary.len + 3) + if (!byte_diff(line.s + 2,boundary.len,boundary.s)) /* boundary */ + return 1; + return 0; +} void main() { - 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 = 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); diff --git a/ezmlm.5 b/ezmlm.5 index 2866b91..6ac1cc6 100644 --- a/ezmlm.5 +++ b/ezmlm.5 @@ -21,7 +21,60 @@ manipulate the subscriber list stored under handles administrative requests automatically; .B ezmlm-send sends a message to all subscribers listed in -.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 @@ is a directory containing messages previously sent to subscribers. .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 @@ Message number 100m+n, with n between 0 and 99, is stored in .IR dir\fB/archive/\fIm\fB/\fIn . For example, message number 15307 is stored in .IR dir\fB/archive/153/07 . +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 @@ handles incoming 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. @@ -137,9 +230,266 @@ 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 @@ -187,6 +537,27 @@ Rejecting a bad unsubscription confirmation number. .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 @@ Explaining that .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 @@ in 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 @@ fields. 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 @@ field, showing the contents of .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 +.EE + +This header would result from a +.I dir\fB/listid +file containing ``optional_text ''. 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 @@ is the name of the parent list. 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 @@ is an advisory log of subscription and unsubscription actions. .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) diff --git a/ezmlmglrc b/ezmlmglrc new file mode 100644 index 0000000..54e3809 --- /dev/null +++ b/ezmlmglrc @@ -0,0 +1,97 @@ +# ezmlmglrc file to set up a global "majordomo"-like interface. +# You also need to create DIR/config.cf, for instance with ezmlm-glconf +# +# Usage: ezmlm-make -Cezmlmglrc [-5 owner] dir dot local host +# +# dir - base directory +# dot - qmail file. Usually, ~alias/.qmail-majordomo or such. +# local - local address, e.g. "majordomo" +# host - host +# +# +# These work just like for standard ezmlm-make +# +# directories + +# links - the second for complete command addresses like +# majordomo-which-me=myhost, as well as for our own bounces + + + +|<#B#>/ezmlm-request -f ezdomo.cf '<#D#>' +# standard stuff + +<#L#> + +<#L#> + +<#H#> +# List owner mail + + +&<#5#> + +<#D#>/Mailbox + +return-path +return-receipt-to +content-length +# texts + + +--- 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: + + +To get a complete list of commands for the same list, mail to: + + +--- Enclosed is a copy of the request I received. + + +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. + + +Hi! This is the ezmlm program. I'm managing the +<#L#>@<#H#> address to guide +your request to the appropriate ezmlm mailing list. + + +|<#B#>/ezmlm-request -f '<#D#>/config.cf' '<#D#>' +# that's all folks! + diff --git a/ezmlmglrc.5 b/ezmlmglrc.5 new file mode 100644 index 0000000..a57dafc --- /dev/null +++ b/ezmlmglrc.5 @@ -0,0 +1,71 @@ +.TH ezmlmglrc 5 +.SH NAME +ezmlmglrc \- set up the global ezmlm interface +.SH SYNOPSIS +.B ezmlm-make +.B \-C ezmlmglrc +[ +.B \-5\fI owner +] +.I dir dot local host +.SH DESCRIPTION +.B ezmlmglrc +instructs +.B ezmlm-make(1) +to create +.I dir +and files within it to support the +.I local\fB@\fIhost +address as a global ezmlm interface. +.I dot +and +.I dot\fB-default +are linked to +.I dir\fB/ezdomo +which uses +.B ezmlm-request(1) +to handle requests as well as +bounces and ezmlm-style command addresses for the global interface. +The configuration file +.I dir\fB/config.cf +should be created separately with +.BR ezmlm-glconf(1) . +.SH OPTIONS +.TP +.B -5\fI owner +Forward mail addressed to +.I local\fB-owner@\fIhost +to +.I owner +rather than storing it in a local mailbox. +.SH USAGE +Typical use by ``joe'' to set up +.B joe-\fImajordomo\fB@\fIthis.com: + +.EX +ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo joe-majordomo this.com +.EE + +Typical use by ``alias'' to set up +.I majordomo\fB@\fIthis.com: + +.EX +ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo majordomo this.com +.EE + +Typical use by ``virt'' controlling the virtual domain +.I lists.com +to set up +.I majordomo\fB@\fIlist.com: + +.EX +ezmlm-make -Cezmlmglrc ~/domo ~/.qmail-majordomo majordomo list.com + +echo "virt-majordomo" > ~/domo/inlocal +.EE +The ``echo'' line is required only if used with qmail<1.02. +.SH "SEE ALSO" +ezmlm-glconf(1), +ezmlm-make(1), +ezmlm-request(1), +ezmlm(5) diff --git a/ezmlmrc.5 b/ezmlmrc.5 new file mode 100644 index 0000000..6d30610 --- /dev/null +++ b/ezmlmrc.5 @@ -0,0 +1,746 @@ +.TH ezmlmrc 5 +.UC 4 +.SH NAME +ezmlmrc \- ezmlm-make configuration file +.SH SYNOPSIS +ezmlmrc +.SH DESCRIPTION +.LP +.B .ezmlmrc +is a file that configures +.B ezmlm-make(1) +for setting up new lists. +.B ezmlmrc +if a plain text with four types +of tags. All start in +the first position of the line. +No other text is allowed on the same line. For +security reasons, no periods are allowed anywhere in a tag. +Any line with a ``#'' in position 1 is ignored, +as is any text preceding the first tag. + +The first line +in +.B .ezmlmrc +is unique. It should start in position 1 with ``x.yz'', where +``x'' is the major version number, ``y'' a minor version number, and ``z'' +a bugfix version number. +.B ezmlm-make(1) +will print a warning message if it is used with an +.B .ezmlmrc +file that lacks the version identifier, or +with an +.B ezmlmrc +file that has a version identifier that differs in +either major or minor version numbers from the +.B ezmlm-make +version. + +The +.B .ezmlmrc +file is processed top down. Text preceding the first tag is ignored. +Subsequently, one and only one file is open for writing. Any text encountered +in +.B \.ezmlmrc +is copied to that file as is with a few substitutions (see below). Text +following conditional tags is copied only if the condition is met. A file is +automatically closed when a new file is opened. Opening a file overwrites +any preexisting file with that name. +Tags are: + +.TP +.B +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 +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 +.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 +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 +.B dot\fI\-link +is symlinked to +.I dir/directory +if the flags specified are active, in +this case +.I archived +and not +.IR indexed . +If no flags are specified, the ``#'' can be +omitted. +.PP +In addition, +.I local +is substituted for +.BR <#L#> , +the part of +.I dot +between the first 2 hyphens (if any) for +.BR <#1#> , +the part of +.I dot +between the second and third hyphen (if any) for +.BR <#2#> , +.I host +for +.BR <#H#> , +.I dir +for +.BR <#D#> , +.I dot +for +.BR <#T#> , +.I digestcode +for +.BR <#C#> , +and the path to the +.B ezmlm +binaries for +.BR <#B#> +anywhere in the text. Other tags of this format are copied to the files as is. + +.BR <#l#> , +.BR <#h#> , +.BR <#A#> , +.BR <#R#> , +will be substituted on-the-fly where appropriate for the +.IR local +or +.IR local\fB\-digest +local part of the list address, the +.IR host , +the subscriber address or the moderation accept address, +and the subscription reply address or moderation reject address, respectively. +The use of +.BR <#l#> +is to allow the same text file to be used for requests pertaining to both +the main list and the digest list. + +Before the template file is processed, +.B ezmlm-make +will create the list directory. +.B ezmlm-make +will also create +.IR dir\fB/key . +.SH "DESCRIPTION OF EZMLMRC" +The ezmlmrc file is preconfigured to act upon +.B ezmlm-make(1) +switches to produce the results as described in the +.B ezmlm-make(1) +man page. +A number of files are created via +.B ezmlmrc +independently of any switched. These are +.I dir\fB/text/info +with a short description of the list, +.I dir\fB/text/faq +with frequently asked questions about the list, +.I dir\fB/headeradd +adding ``Precedence: bulk'' and ``X-No-Archive: yes'' to outgoing messages, +.I dir\fB/headerremove +removing ``Return-Path'', ``Return-Receipt-To'', ``Content-length'', + and ``Precedence'' from list messages, and +.I dir\fB/text/sub-ok +with text sent after successful subscription. These files are not overwritten +when lists are edited. + +Also created are the following files within +.IR dir\fB/text/ : +.BR bottom , +.BR bounce-bottom , +.BR bounce-num , +.BR dig-bounce-num , +.BR bounce-probe +.BR bounce-warn , +.BR get-bad , +.BR help , +.BR mod-help , +.BR mod-request , +.BR mod-reject , +.BR mod-timeout , +.BR mod-sub-confirm , +.BR mod-unsub-confirm , +.BR sub-bad , +.BR sub-confirm , +.BR sub-nop +.BR unsub-bad , +.BR unsub-confirm , +.BR unsub-nop , +.BR unsub-ok , +.BR top . + +.I dir\fB/bouncer +is set up to invoke +.B ezmlm-weed(1) +and +.B ezmlm-return(1) +to handle bounces. +In addition to switch-dependent lines, an invocation of +.B ezmlm-warn(1) +is placed at the end of +.IR dir\fB/editor , +.IR dir\fB/manager , +and +.I dir\fB/owner +to process the contents of the bounce directory. +.BR ezmlm-reject(1) +is placed first in +.I dir\fB/editor + (unless the +.B \-0\ mainlist@mainhost +switch is used) to reject undesirable messages. + Below is a description of the switches and the consequences +the have for list creation with the standard +.B ezlmrc +file. +.B emzlm-make(1) +by default sets the +.BR \-a , +and +.B \-p +switches. +.TP +.B \-a +.I dir\fB/archived +and +.I dir\fB/indexed +are created. +.I dir\fB/text/bottom +is adjusted to mention archive access. +.B \-A +.I dir\fB/archived +and +.I dir\fB/indexed +are removed. +.TP +.B \-b +Block archive. The list set up with +.B ezmlm-get -P +to allow only moderators archive access. +.TP +.B \-B +The +.B ezmlm-get -P +switch is not used. +.TP +.B \-d +.I dir\fB/digest/ +is created. +.I dir\fB/digest/lock +is created. +.I dir\fB/digest/lockbounce +is created. +.I dir\fB/digest/bounce/ +is created. +.I dir\fB/digest/subscribers/ +is created. +.I dot\fB-digest-owner +is linked to +.IR dir\fB/owner . +.I dot\fB-digest-return-default +is linked to +.IR dir\fB/bouncer . +An invocation of +.B ezmlm-warn(1) -d +is added to +.I dir\fB/editor +and +.IR dir\fB/manager . +Invocations of +.B ezmlm-tstdig(1) +and +.B ezmlm-get(1) +are added with default arguments to +.IR dir\fB/editor . +A note on digest (un)subscription is added to +.I dir\fB/text/bottom +and to +.IR dir\fB/text/mod-help . +.I dir\fB/text/digest +is created for the ``Administrivia'' section of the digest. +.TP +.B \-D +The items mentioned under switch +.B \-d +are not done. The result is that the references to the digest +in the text files is removed. +.TP +.B \-f +The text ``[\fIlocal\fR]'' is placed in +.I dir\fB/prefix +resulting in the text being used as the list's subject index. +.TP +.B \-F +.I dir\fB/prefix +is removed. +.TP +.B \-g +The -s switch is added to the +.B ezmlm-get(1) +line in +.I dir\fB/manager +so that only subscribers can access the archive. +.TP +.B \-G +The -s switch for +.B ezmlm-get(1) +is not used. Anyone can access the archive if archive (access) in general +is enabled (see +.B \-p +for ``public'', +.B \-a +for ``archived'', and +.B \-i +for ``indexed''. +.TP +.B \-i +.I dir\fB/editor +(for normal lists) +or +.I dir\fB/moderator +(for moderated lists) +are set up to run +.B ezmlm-archive(1) +after messages are posted. This sets up the cross-reference for +.B ezmlm-cgi(1) +WWW access. +.TP +.B \-I +.B ezmlm-archive(1) +is not configured. +.TP +.B \-j +.I dir\fB/manager +uses +.B ezmlm-manage -U +to allow unconfirmed unsubscribe. +.B \-J +The +.B ezmlm-manage -U +switch is not used. +.TP +.B \-k +Blacklist. A +.B ezmlm-issubn(1) +line that tests the envelope sender against the address database in +.I dir\fB/deny +is inserted into +.IR dir\fB/editor . +As a consequence, posts from such senders are rejected. This switch is ignored +for sublists (i.e. if the +.B \-0\ mainlist@mainhost +switch is used). +.TP +.B \-K +The +.B ezmlm-issubn(1) +line testing the envelope sender against the ``blacklist'' in +.I dir\fB/deny +is not used. +.TP +.B \-l +The -l switch is added to the +.B ezmlm-manage(1) +command line in +.I dir\fB/manager +to allow retrieval of subscriber list and list log by remote administrators. +.BR NOTE : +This is pointless, unless the list is also set up for remote administration +with the +.B \-r +switch. +.I dir\fB/text/mod-help +is adjusted. +.TP +.B \-L +Do not allow access to the subscriber list under any circumstances. The +.B ezmlm-manage(1) +\-l switch is not specified. +.TP +.B \-m +Message moderation. +.I dir\fB/modpost +is created. +.I dir\fB/editor +is set up with +.B ezmlm-store(1) +instead of +.BR ezmlm-send(1) .a +.I dir\fB/moderator +is set up with +.BR ezmlm-moderate(1) , +and +.BR ezmlm-clean(1) . +.I dot\fB/\-accept-default +and +.I dot\fB/-reject-default +are linked to +.IR dir\fB/moderator . +.I dir\fB/text/mod-help +is adjusted. +Special action is taken when the +.B \-m +switch is combined with +.BR \-u . +In this case, the setup is as for the +.B \-m +switch alone, but +.I dir\fB/editor +is set up with +.B ezmlm-gate(1) +which will fork +.B ezmlm-send(1) +for posts with an envelope sender that is a subscriber or a moderator, and +for +.B ezmlm-store(1) +for posts with other envelope senders. The consequence is that posts from +subscribers (with the usual caveats for SENDER checks) are posted directly, +whereas other posts are sent for moderation. +.TP +.B \-M +No message moderation. +.I dir\fB/editor +is set up with +.B ezmlm-send(1) +as usual. +.I dir\fB/moderator +is removed. +.TP +.B \-n +Allow text file editing. +.ezmlm-manage(1) +in +.I dir\fB/manager +is set up with the \-e switch to allow remote admins to via E-mail edit +the files in +.IR dir\fB/text/ . +.BR NOTE : +This is pointless, unless the list is also set up for remote administration +with the +.B \-r +switch. +.I dir\fB/text/mod-help +is adjusted. +.TP +.B \-N +Remote editing of files in +.I dir\fB/text +is not allowed. +The -e switch for +.B ezmlm-manage +will not be used. +.TP +.B \-o +For moderated lists, the +.B ezmlm-store -P +switch is used so that posts from non-moderators are rejected rather than +sent for moderation. This is for some announcement lists. +.TP +.B \-O +The +.B ezmlm-store -P +switch is not used. +.TP +.B \-p +Public. +.I dir\fB/public +is created. +.TP +.B \-P +Not public. +.I dir\fB/public +is removed. +.TP +.B \-q +A line with +.B ezmlm-request(1) +is added to +.I dir\manager +to service commands in the ``Subject'' line of messages sent to the +``list-request'' address. +.TP +.B \-Q +.B ezmlm-request(1) +is not used. +.TP +.B \-r +Remote admin. +.I dir\fB/remote +is created. +.I dir\fB/text/mod-help +is adjusted. +.TP +.B \-R +.I dir\fB/remote +is removed. +.TP +.B \-s +Subscription moderation. +.I dir\fB/modsub +is created. +.I dir\fB/text/mod-help +is adjusted. +.I dir\fB/text/sub-confirm +is adjusted. +.TP +.B \-S +.I dir\fB/modsub +is removed. +.TP +.B \-t +.I dir\fB/text/trailer +is created with instructions on how to unsubscribe. +.TP +.B \-T +.I dir\fB/text/trailer +is removed. +.TP +.B \-u +User-only posts. +.I dir\fB/editor +is set up with an +.B ezmlm-issubn(1) +line to check the envelope sender against the subscriber address databases. +If the sender is not found, the post is rejected. This results in +subscriber-only posts, with the usual caveats for SENDER checks. +Special action is taken when the +.B \-u +switch is combined with +.BR \-m . +In this case, the setup is as for the +.B \-m +switch alone, but +.I dir\fB/editor +is set up with +.B ezmlm-gate(1) +which will fork +.B ezmlm-send(1) +for posts with an envelope sender that is a subscriber or a moderator, and +for +.B ezmlm-store(1) +for posts with other envelope senders. +.B ezmlm-clean(1) +is set up with the \-R switch. +The consequence is that posts from +subscribers (with the usual caveats for SENDER checks) are posted directly, +whereas other posts are sent for moderation. +.B ezmlm-clean(1) +is set up with the \-R switch. +Thus, ignored posts are silently +removed rather than returned to sender. +.TP +.B \-U +The +.B ezmlm-issubn(1) +line +restricting posts by envelope sender is not used. +.TP +.B \-w +The +Remove the +.B ezmlm-warn(1) +invocations from the list setup. It is assumed that +.B ezmlm-warn(1) +for both +.I local@host +and +.I local-digest@host +will be run by other means, such as crond. +If the +.B \-6 +switch is used with this switch, the local list name will be added to the +SQL config info for +.I dir\fB/sql +and +.I dir\fB/digest/sql . +This is to support building the main list for a distributed list using +a SQL address database. In addition, +.B ezmlm-receipt(1) +will be set up for bounce handling in +.I dir\fB/bouncer +instead of +.BR ezmlm-return(1). +.TP +.B \-W +No action taken. +.TP +.B \-xyzXYZ +User configurable. By default, if the +.B \-x +switch is specified, +.I dir\fB/mimeremove +is created. This file contains many MIME types not routinely supported. +MIME types in +.I dir\fB/mimeremove are stripped from multipart posts before archiving +and distribution. +To view the list of +MIME types, see +.B ezmlmrc +or create a list and list +.IR dir\fB/mimeremove . +In addition +.I dir\fB/msgsize +is created containing ``40000:2'' causing +.B ezmlm-reject(1) +to reject all posts that have a body of less than 2 bytes (empty) or +more than 40000 bytes (too large). +.TP +.B \-0\fI\ mainlist@mainhost +.I dir\fB/sublist +is created with ``mainlist@mainhost''. +.B dir\fB/ezmlm-reject +is not used in +.I dir\fB/editor +to avoid rejecting messages that the main list has accepted. +.TP +.B \-3\fI\ fromarg +The list is set up to add ``from'' to +.I dir/fB/headerremove +and +.B From:\fI fromarg +to +.IR dir\fB/headeradd . +This replaces the incoming ``From:'' header as desirable for some announcement +lists. +.TP +.B \-4\fI\ tstdigopts +.I tstdigopts +will be used as the arguments for +.ezmlm-tstdig(1) +in +.IR dir\fB/editor . +This must be both switches and their arguments for +.BR ezmlm-tstdig(1) . +.BR NOTE : +This is pointless, unless the list is also set up for digests +with the +.B \-d +switch. +.TP +.B \-5\fI\ owner@ownerhost +.I owner@ownerhost is placed in +.I dir\fB/owner +so that mail to ``list-owner'' is forwarded to that address, rather than +being stored in +.IR dir\fB/Mailbox . +If the address does not start with an underscore or alphanumeric character, +the argument must start with an ampersand. +.TP +.B \-6\fI\ host:port:user:password:datab:table +.TP +The string, followed by the list name is placed in +.IR dir\fB/sql . +The same string with ``table'' suffixed with ``_digest'' and ``_allow'' +is placed in +.I dir\fB/digest/sql +and +.IR dir\fB/allow/sql , +respectively. +.B \-7\fI\ /msgmodPath +.I msgmodPath +is placed in +.IR dir\fB/modpost +is the list is set up for message moderation with the +.B \-m +switch. +.TP +.B \-8\fI\ /submodPath +.I submodPath +is placed in +.IR dir\fB/modsub +is the list is set up for subscription moderation with the +.B \-s +switch. +.TP +.B \-9\fI\ /remoteAdminPath +.I remoteAdminPath +is placed in +.IR dir\fB/remote +is the list is set up for remote administration with the +.B \-r +switch. +.SH "SEE ALSO" +ezmlm(5), +ezmlm-clean(1), +ezmlm-gate(1), +ezmlm-get(1), +ezmlm-issubn(1), +ezmlm-make(1), +ezmlm-manage(1), +ezmlm-moderate(1), +ezmlm-request(1), +ezmlm-return(1), +ezmlm-send(1), +ezmlm-store(1), +ezmlm-tstdig(1), +ezmlm-warn(1), diff --git a/ezmlmrc.ch_GB b/ezmlmrc.ch_GB new file mode 100644 index 0000000..61afeb3 --- /dev/null +++ b/ezmlmrc.ch_GB @@ -0,0 +1,966 @@ +0.324 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.ch_GB,v 1.2 1999/12/23 23:08:19 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post +To + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +list-help: -help@<#h#>> +list-unsubscribe: -unsubscribe@<#h#>> +list-post: @<#H#>> +To:##L@##H +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +È¡Ïû×¢²á£¬½«µç×ÓÓʼþ·¢Ë͵½£º<#L#>-unsubscribe@<#H#>£¬Èç¹ûÐèÒª¸ü¶àµÄ°ïÖú£¬½« +µç×ÓÓʼþ·¢Ë͵½£º<#L#>-help@<#H#>¡£ + + +---<#l#> ÓʼþÁбíµÄ¹ÜÀíÃüÁî--- + +ϵͳÄܹ»×Ô¶¯´¦Àí¶ÔÓʼþÁбíµÄ¹ÜÀíÇëÇó¡£½«ÐèÒª´¦ÀíµÄÃüÁî·¢Ë͵½ÒÔϵĵç×ÓÓʼþ +µØÖ·£º + +×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-subscribe@<#H#>> + +È¡Ïû×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-unsubscribe@<#H#>> + +½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·Äܹ»»ñµÃÓʼþÁбíµÄ½éÉÜÐÅÏ¢£º + <<#L#>-info@<#H#>> + +½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·Äܹ»»ñµÃÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð£¨FAQ£©£º + <<#L#>-faq@<#H#>> + + +×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#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! + +»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢ +Ë͵½£º + <<#L#>-get.123_145@<#H#>> + + +»ñµÃÓʼþÁбíµÚ12ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-get.12@<#H#>> + + +»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-index.123_456@<#H#>> + +# Lists need to be both archived and indexed for -thread to work + +»ñµÃÓëÀúÊ·Óʼþ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. + + +Äã¿ÉÒÔͨ¹ýµç×ÓÓʼþµÄ·½Ê½×¢²áÒ»¸öÆäËüµÄµØÖ·£¬¾ÙÀýÀ´½²£¬ÄãÏ£Íûͨ¹ýµç×ÓÓʼþµÄ·½Ê½×¢ +²á¡°john@host.domain¡±£¬Ö»ÒªÔÚÃüÁîºó£¨subscribe£©Ìí¼Ó¡°-¡±²¢ÇÒÓá°=¡±´úÌæ¡°@¡±£º +<<#L#>-subscribe-john=host.domain@<#H#>> + +È¡Ïû×¢²áÓʼþÁÐ±í£¬½«µç×ÓÓʼþ·¢Ë͵½£º +<<#L#>-unsubscribe-john=host.domain@<#H#>> + +ʹÓÃÕâÖÖ·½Ê½×¢²á¡¢È¡Ïû×¢²áÓʼþÁбíʱ£¬ÏµÍ³½«Ïò¸ÃµØÖ··¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬µ±¸ÃµØÖ· +ÊÕµ½µç×ÓÓʼþʱ£¬Ö»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄܹ»Íê³É×¢²áºÍÈ¡Ïû×¢²á¡£ + + +Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκÎÎÊÌ⣬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß<#L#>-owner@<#H#>¡£ +Èç¹û²»Äܽâ¾öÎÊÌ⣬ÇëÓëϵͳµÄ¹ÜÀíÔ±ÁªÏµ¡£ + + +--- ËæП½ÉϵÄÊÇϵͳÊÕµ½µÄÄã·¢Ë͵ÄÓʼþ¡£ + + + +--- ËæП½ÉϵÄÊÇϵͳÊÕµ½µÄϵͳµ¯»Ø£¨bounce£©µÄÓʼþ¡£ + + + +ϵͳÒѾ­±£´æÁËÒ»·Ý´Ó<#L#>ÓʼþÁÐ±í·¢Ë͵½ÄãµÄµç×ÓÓʼþµØÖ·±»µ¯»Ø£¨bounce£©µç×ÓÓʼþ¡£ + + +ÕâЩµç×ÓÓʼþµÄ¿½±´¿ÉÄÜÒѾ­±£´æÔÚÀúÊ·ÎĵµÖС£ + +»ñµÃÓʼþÁбíµÚ12345ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-get.12345@<#H#>> + + +»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-get.123_145@<#H#>> + +»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-index.123-456@<#H#>> + + +ÏÂÃæÊǵç×ÓÓʼþµÄ±àºÅ£º + + + +ϵͳÒѾ­±£´æÁËÒ»·Ý´Ó<#L#>ÓʼþÁÐ±í·¢Ë͵½ÄãµÄµç×ÓÓʼþµØÖ·±»µ¯»Ø£¨bounce£©µÄÕªÒªÓʼþ¡£ +¶ÔÓÚÄã´í¹ýµÄÿ·ÝÕªÒª£¬ÏµÍ³ÒѾ­°üº¬ÔÚ·¢Ë͸øÄãµÄÕªÒªÓʼþÖеĵÚÒ»¸öÓʼþ¡£ÏµÍ³Ã»Óн«Äã +´í¹ýµÄÕªÒªÓʼþ·¢Ë͸øÄ㣬µ«ÊÇÄã¿ÉÒÔͨ¹ýÓʼþÁбíµÄÀúÊ·ÎĵµÖлñµÃ¡£ + + +»ñµÃÓʼþÁбíµÚ12345ÌõÀúÊ·Óʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-get.12345@<#H#>> + + +»ñµÃÓʼþÁбí´Ó123µ½145µÄÀúÊ·Óʼþ£¨Ã¿´Î×î¶à»ñµÃ100¸öÀúÊ·Óʼþ£©£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-get.123_145@<#H#>> + +»ñµÃÓʼþÁбí´Ó123µ½456µÄÀúÊ·ÓʼþµÄÖ÷ÌâÓë×÷ÕßµÄË÷Òý£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-index@<#H#>> + + +ÏÂÃæÊÇÕªÒªÓʼþµÄ±àºÅ£º + + + +´Ó<#l#>ÓʼþÁÐ±í·¢Ë͸øÄãµÄµç×ÓÓʼþÒѾ­±»µ¯»Ø£¨bounce£©¡£ÏµÍ³ÒѾ­ÏòÄã·¢ËÍÁËÒ»¸ö¾¯¸æµÄ +Óʼþ£¬µ«ÊÇÕâ¸öÓʼþͬÑù±»µ¯»Ø£¨bounce£©¡£ÏµÍ³½«¸½Éϵ¯»Ø£¨bounce£©µÄÓʼþ¡£ + +Õâ¸öÓʼþÊÇϵͳΪ¼ì²âÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñÄܹ»µ½´ï¶ø·¢Ë͵ġ£Èç¹ûÕâ·âÓÃÓÚ¼ì²âµÄµç×ÓÓʼþ +Ò²±»µ¯»Ø£¨bounce£©£¬ÏµÍ³½«°ÑÄãµÄµç×ÓÓʼþµØÖ·´Ó<#l#>@<#H#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á²¢²»ÔÚͨ +ÖªÄ㡣ͬÑùÄãÒ²¿ÉÒÔͨ¹ýÏòÏÂÃæµÄµØÖ··¢Ë͵ç×ÓÓʼþµÄ·½Ê½ÖØÐÂ×¢²áÓʼþÁÐ±í£º + <<#l#>-subscribe@<#H#>> + + + +´Ó<#l#>ÓʼþÁÐ±í·¢Ë͸øÄãµÄµç×ÓÓʼþÒѾ­±»µ¯»Ø£¨bounce£©¡£ÏµÍ³ÒѾ­½«±»µ¯»Ø£¨bounce£©µÄ +µÚÒ»¸öµç×ÓÓʼþ¸½ÉÏ¡£ + +Èç¹ûÕâ¸öµç×ÓÓʼþͬÑù±»µ¯»Ø£¬ÏµÍ³½«ÏòÄãµÄµç×ÓÓʼþµØÖ··¢ËÍÒ»¸ö¼ì²âÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñ +ÕýÈ·µÄµç×ÓÓʼþ£¬Èç¹ûÕâ¸öµç×ÓÓʼþͬÑù±»µ¯»Ø£¬ÏµÍ³½«°ÑÄãµÄµç×ÓÓʼþµØÖ·´Ó<#l#>ÓʼþÁбí +È¡Ïû×¢²á²¢²»ÔÚ֪ͨÄã¡£ + + +×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <#L#>-digest-subscribe@<#H#> + +È¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <#L#>-digest-unsubscribe@<#H#> + +ÏòÓʼþÁÐ±í·¢Ë͵ç×ÓÓʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + <#L#>@<#H#> + + +ÔÚÓʼþÁбíµÄÀúÊ·ÎĵµÖв»ÄÜ·¢ÏÖÕâÌõÓʼþ¡£ + + +ϵͳÊÕµ½µÄµç×ÓÓʼþÖÐûÓаüÀ¨ÏµÍ³Äܹ»´¦ÀíµÄÃüÁî¡£ + + +ÄãÏÖÔÚÒѾ­³ÉΪ<#L#>@<#H#>ÓʼþÁбíµÄ¹ÜÀíÕߣ¨moderator£©£¬ÏÂÃ潫½éÉÜ×÷Ϊһ¸öÓʼþÁбí +µÄËùÓÐÕß»ò¹ÜÀíÕߣ¨moderator£©Äã¿ÉÒÔͨ¹ýÏÂÃæµÄ·½Ê½¶ÔÓʼþÁбíµÄ¸÷¸ö·½Ãæ½øÐйÜÀí¡£ + + +Óû§×¢²áºÍÈ¡Ïû×¢²áµÄ¹ÜÀí +---------------------- +×÷ΪÓʼþÁбíµÄ¹ÜÀíÕߣ¬ÄãÄܹ»×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÈκÎÓû§¡£ÄãÏ£Íûͨ¹ýµç×ÓÓʼþµÄ·½ +ʽע²á¡°john@host.domain¡±£¬Ö»ÒªÔÚÃüÁîºó£¨subscribe£©Ìí¼Ó¡°-¡±²¢ÇÒÓá°=¡±´úÌæ¡°@¡±£¬¾Ù +ÀýÀ´½²£¬×¢²áÉÏÃæËù½²µÄµØÖ·£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-subscribe-john=host.domain@<#H#>> + +ͬÑù£¬È¡Ïû×¢²áÉÏÃæµÄµç×ÓÓʼþµØÖ·£¬½«µç×ÓÓʼþ·¢Ë͵½£º + <<#L#>-unsubscribe-john=host.domain@<#H#>> + + +ͬÑù¶ÔÓÚ×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£º + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +ËùÓеÄ×¢²áºÍÈ¡Ïû×¢²á¶¼²»ÐèÒªÓÐÓʼþÖ÷ÌâºÍÓʼþÄÚÈÝ! + + +ϵͳ½«ÏòÄã·¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬È·ÈÏÊÇÄã·¢Ë͵ÄÇëÇó¡£ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉËùÓеÄÇëÇó¡£ + +ϵͳ½«ÏòÓû§·¢ËÍÈ·Èϵĵç×ÓÓʼþ£¬ÈçÉÏÃæËù˵µÄµç×ÓÓʼþµØÖ·¡£Óû§±ØÐë +»Ø¸´µç×ÓÓʼþ²ÅÄÜÍê³ÉËùÓеÄÇëÇó¡£ + + +È·Èϵķ½Ê½·ÀÖ¹ÁËÆäËûÈËËæÒâµÄÏòÓʼþÁбíÌí¼ÓºÍɾ³ýÓû§¡£ + +ϵͳ½«Í¨ÖªÓû§Ëû/ËýµÄ×¢²á״̬ÒѾ­¸Ä±ä¡£ + +×¢²áºÍÈ¡Ïû×¢²á +------------- + +ÈκÎÓû§¿ÉÒÔͨ¹ýÏòÏÂÃæµÄµØÖ··¢Ë͵ç×ÓÓʼþ½øÐÐ×¢²á»òÈ¡Ïû×¢²á£º + +<#L#>-subscribe@<#H#> +<#L#>-unsubscribe@<#H#> + + +ͬÑù¶ÔÓÚ×¢²áºÍÈ¡Ïû×¢²áÓʼþÁбíµÄÕªÒª£º + +<#L#>-digest-subscribe@<#H#> +<#L#>-digest-unsubscribe@<#H#> + + +Óû§½«´ÓϵͳÊÕµ½È·ÈÏÐÅËû/Ëýµç×ÓÓʼþµØÖ·µÄÈ·ÈÏÐÅ¡£Ò»µ©µç×ÓÓʼþµØÖ·±»È·ÈÏ£¬×¢²á»òÈ¡Ïû×¢²á½«Íê³É¡£ + + +ÒòΪÓʼþÁбí¶ÔÓÚÓû§×¢²áÊÇÐèÒª¾­¹ý¹ÜÀíÕߣ¨moderator£©µÄÅú×¼ºó²ÅÄÜÍê³É£¬ËùÒÔϵͳÔÚÍê³É¶ÔÓû§ +µç×ÓÓʼþµØÖ·µÄÑéÖ¤ºó½«ÏòÓʼþÁбíµÄ¹ÜÀíÕߣ¨moderator£©·¢ËÍÇëÇó¹ÜÀíÕßÈ·ÈϵØÖ·×¢²áÓʼþÁбí +µÄÇëÇó¡£Èç¹ûÄãÏ£ÍûÓû§×¢²áÓʼþÁÐ±í£¬Ö»Òª»Ø¸´µç×ÓÓʼþ½øÐÐÍê³ÉÈ·ÈÏ¡£Èç¹ûÄ㲻ϣÍûÓû§×¢²á +ÓʼþÁÐ±í£¬Äã¿ÉÒÔɾ³ýÕâ·âµç×ÓÓʼþ¡£ + +×¢²áÒ²ÊÇͬÑùµÄ·½Ê½ + + +ͬÑùÓû§Ò²¿ÉÒÔʹÓÃÏÂÃæµÄ·½·¨È¡Ïû×¢²á£º + + <<#L#>-subscribe-mary=host.domain@<#H#>> + <<#L#>-unsubscribe-mary=host.domain@<#H#>> + +"mary@host.domain"½«ÊÕµ½ÏµÍ³·¢Ë͵ÄÈ·ÈÏÈ¡Ïû×¢²áµÄµç×ÓÓʼþ.ÔÚÑéÖ¤Íê³Éºó¾ÍÄÜÈ¡Ïû×¢²á¡£ + + +ͨ¹ýµç×ÓÓʼþµÄ·½Ê½»ñµÃ<#L#>@<#H#>ÓʼþÁбíµÄ×¢²áÓû§£¬½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·: + <<#L#>-list@<#H#>> + +ͨ¹ýµç×ÓÓʼþµÄ·½Ê½»ñµÃ<#L#>@<#H#>ÓʼþÁбíµÄÈÕÖ¾£¨Log£©Îļþ, ½«µç×ÓÓʼþ·¢Ë͵½Ï +ÃæµÄµØÖ·: + <<#L#>-log@<#H#>> + + +ͬÑù£¬Í¨¹ýµç×ÓÓʼþ»ñµÃÓʼþÁбíÕªÒªµÄ×¢²áÓû§£º + <<#L#>-digest-list@<#H#>> +ͬÑù£¬Í¨¹ýµç×ÓÓʼþ»ñµÃÓʼþÁбíÕªÒªµÄÈÕÖ¾Îļþ£º + <<#L#>-digest-log@<#H#>> + + +Äã¿ÉÒÔͨ¹ý¶ÔһЩÎļþµÄ±à¼­À´¶¨ÖÆÓʼþÁбíµÄ»ØÓ¦Óʼþ¡£µÃµ½ÐèÒª±à¼­µÄÎļþ¼°ÈçºÎ±à¼­£¬½«µç×ÓÓʼþ·¢ËÍ +µ½ÏÂÃæµÄµØÖ·£º + <<#L#>-edit@<#H#>> + + +ÓйÜÀíµÄͶµÝ +----------- +µ±Ò»¸öÓʼþÁбíÉèÖóÉËùÓз¢Ë͵½ÓʼþÁбíµÄÓʼþ¶¼Òª¾­¹ý¹ÜÀíÕßµÄÉóºËºó²ÅÄÜ·¢ËÍʱ£¬ÏµÍ³½«±£´æͶµÝµ½ +ÓʼþÁбíµÄÓʼþ²¢½«ÓʼþµÄ¿½±´·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß¡£Õâ·âÓʼþµÄÌØÕ÷ÊÇÔÚÓʼþµÄÖ÷ÌâÖÐÓÐ +¡°MODERATE for ...¡±¡£ + +Èç¹ûÄãÏ£ÍûÔÚÓʼþÁбíÖÐת·¢Óʼþ£¬ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¡£ + +Èç¹ûÄ㲻ϣÍûת·¢Óʼþ²¢ÒªÉ¾³ý´ËÓʼþ£¬½«µç×ÓÓʼþ·¢Ë͵½¡¯·¢¼þÈË£º¡®µÄµç×ÓÓʼþµØÖ·¡£Í¨³£ÄãÖ»Òªµã»÷ +¡°È«²¿»Ø¸´¡±£¬È»ºóɾ³ý³ý¡®reject¡¯ÒÔÍâµÄËùÓеç×ÓÓʼþµØÖ·¡£Í¬Ê±ÄãÒ²¿ÉÒÔÔÚ'%'¼äÌí¼ÓΪʲôûÓÐת +·¢µÄµÄÆÀÂÛ£¬ÏµÍ³½«ÕâЩÆÀÂÛ×Ô¶¯µÄ·¢Ë͵½ÓʼþµÄ·¢¼þÈË¡£ + +ϵͳ½«¶Ô¸ù¾ÝÓʼþÁбí¹ÜÀíÕ߶ÔÓʼþ»Ø¸´µÄÏȺó˳Ðò¶ÔÓʼþ½øÐд¦Àí£¨ÏµÍ³×ÜÊÇ°´ÕÕ×îÏȻظ´µÄ½øÐд¦Àí£©¡£ +Èç¹ûÄãÇëÇó´¦ÀíµÄµç×ÓÓʼþϵͳÒѾ­½øÐÐÁË´¦Àí£¨·¢ËÍ»òɾ³ý£©£¬ÏµÍ³»áÓõç×ÓÓʼþµÄ·½Ê½Í¨ÖªÄã¡£ + +Èç¹ûϵͳÔÚÒ»¶Îʱ¼äÄÚ£¨Í¨³£ÊÇ5Ì죩ûÓÐÊÕµ½Èκδ¦ÀíµÄ·½Ê½£¬ÏµÍ³½«Óʼþ×Ô¶¯µÄÍ˻ص½·¢¼þÈ˲¢½âÊÍΪʲ +ôûÓнøÐд¦Àí¡£Í¬ÑùÄãÒ²¿ÉÒÔÉèÖá°¡±µÄÐÅϢ֪ͨ·¢¼þÈËΪʲôûÓд¦Àí¡£ + + +Íâ³ö +---- +Èç¹ûÄãÖ»ÊÇÁÙʱµÄ¸ü»»µç×ÓÓʼþµØÖ·£¬Ö»Òª½«ÓÐÕýÈ·µÄÓʼþÁбíÍ·(»òÕßÓʼþµÄÖ÷ÌâÊÇÒÔ +'MODERATE for <#L#>@<#H#>'»ò'CONFIRM subscribe to <#L#>@<#H#>'¿ªÍ·µÄµç×ÓÓʼþ) ת·¢µ½Ð嵀 +µç×ÓÓʼþµØÖ·¾Í¿ÉÒÔÁË¡£Äã¿ÉÒÔͨ¹ýеĵØÖ·¶ÔÓʼþÁбí½øÐйÜÀí¡£Í¬Ñù£¬ÄãÒ²¿ÉÒÔ½«µç×ÓÓʼþת·¢µ½Äã +µÄÅóÓѵĵç×ÓÓʼþÐÅÏ䣬ίÍÐËû/ËýÌæÄãÁÙʱ¹ÜÀíÓʼþÁÐ±í¡£ + +µ±ÄãÍâ³öʱ£¬Èç¹ûÄãÏ£Íûϵͳ×Ô¶¯ÑéÖ¤ËùÓеÄÇëÇó£¬ÔÚÄãµÄµç×ÓÓʼþ¿Í»§¶ËÉèÖóÉ×Ô¶¯»Ø¸´·ûºÏÉÏÊöÌõ¼þµÄ +µç×ÓÓʼþ¡£ + + +Èç¹ûÄãÊÔͼͨ¹ýÒ»¸ö²¢²»ÊÇÄãµÄµç×ÓÓʼþµØÖ·¹ÜÀíÄãµÄÓʼþÁÐ±í£¬ÏµÍ³½«ÏòÓû§·¢ËÍÈ·ÈϵÄÓʼþ£¬ÔÚÓʼþÈ· +ÈϺó£¬Ò»·âÒªÇóÓʼþÁбí¹ÜÀíÕß½øÐÐÈ·Èϵĵç×ÓÓʼþ½«·¢Ë͵½ÓʼþÁбíµÄËùÓйÜÀíÕß¡£ÏµÍ³ÕâÑù´¦ÀíÊÇÒòΪ +ϵͳ²»ÄÜÈ·ÈÏÊÇË­·¢Ë͵ÄÇëÇó¡£ + + + +×¢Ò⣺Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκεÄÎÊÌ⣬ÇëÄãÓëÓʼþÁбíµÄËùÓÐÕß(<#L#>-owner@<#H#>)ÁªÏµ¡£ + + +¶Ô²»Æð£¬Äã·¢Ë͵½ÓʼþÁбíµÄÓʼþûÓб»ÓʼþÁбíµÄ¹ÜÀíÕßÅú×¼¡£Èç¹ûÓʼþÁбíµÄ¹ÜÀíÕ߶ÔÄãµÄÓʼþ +×öÁËÆÀÂÛ£¬Ò²¸½ÔÚÕâ·âÓʼþÖС£ + +Õâ·âÓʼþÊÇijÈË·¢Ë͵½<#L#>@<#H#>ÓʼþÁбíÖеġ£Èç¹ûÄãÏ£ÍûÓʼþÁбíµÄ×¢²áÓû§¶¼ÊÕµ½Õâ·âÓʼþ£¬Çë +½«µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!A + +ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄܽ«µç×ÓÓʼþ·¢Ë͵½ÓʼþÁÐ±í¡£µØÖ·µÄ¸ñʽÊÇ"<#L#>-accept"¡£»òÕß +½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#A#> + + +ɾ³ýÕâ·âÓʼþ²¢½«Õâ·âÓʼþÖ±½ÓÍ˻ط¢ÐÅÈË£¬Ç뽫Õâ·âÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ͨ³££¬ÄãÖ»Òªµã»÷¡±È«²¿»Ø¸´¡°£¬²¢½«³ýÁË"<#L#>-reject"µÄµØÖ·È«²¿É¾³ý¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +Èç¹ûÄãÏ£Íû¶ÔÓÚÍ˻صÄÓʼþ¼ÓÉÏÄãµÄÆÀÂÛ£¬ÇëÄ㽫ÄãµÄÆÀÂÛÌí¼ÓÔÚ¡±%%% Start comment¡° +ºÍ¡±%%% End comment¡°Ö®¼ä£º + +%%% Start comment +%%% End comment + +ллÄãµÄ°ïÖú£¡ + +--- ËæП½ÉϵÄÊÇͶµÝµ½ÓʼþÁбíµÄµç×ÓÓʼþ¡£ + + +--- ÓÉÓÚ<#l#>@<#H#>¹ÜÀíÕßµÄÇëÇó£¬ÏµÍ³ÒѾ­½«Äã×¢²á»òÈ¡Ïû×¢²áÓʼþÁÐ±í¡£ + +Èç¹û×¢²á»òÈ¡Ïû×¢²á²¢²»·ûºÏÄãµÄÏë·¨£¬ÇëÄãÖ±½Ó½«µç×ÓÓʼþ·¢Ë͵½ÓʼþÁбíµÄËùÓÐÕß(<#l#>-owner@<#H#>)¡£ + +Èç¹ûÄãÏ£ÍûµÃµ½¸ü¶àµÄ°ïÖú£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½<#L#>-help@<#H#>¡£ + + +¶Ô²»Æð£¬<#L#>ÓʼþÁбíµÄ¹ÜÀíÕß²»Äܹ»´¦ÀíÄãͶµÝµÄÓʼþ¡£ÏµÍ³½«ÓʼþÍ˻ظøÄ㣬ÇëÄãÖØÐÂͶµÝÓʼþ»òÓëÓÊ +¼þÁбíµÄ¹ÜÀíÕßÁªÏµ¡£ + +--- ËæП½ÉϵÄÊÇͶµÝµ½ÓʼþÁбíµÄµç×ÓÓʼþ¡£ + + +Óû§!AÇëÇó×¢²á<#l#>ÓʼþÁÐ±í£¬ +ËûµÄÇëÇó±ØÐëµÃµ½ÄãµÄÈ·ÈϺó²ÅÄÜÍê³É£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +Èç¹ûÄã²»ÏëÈÃÓû§×¢²áÓʼþÁÐ±í£¬ÄãÖ»ÒªºöÂÔÕâ·âÓʼþ¾Í¿ÉÒÔÁË¡£ + +ллÄãµÄ°ïÖú£¡ + + +Óû§!AÇëÇóÈ¡Ïû×¢²á<#l#>ÓʼþÁÐ±í£¬ +ËûµÄÇëÇó±ØÐëµÃµ½ÄãµÄÈ·ÈϺó²ÅÄÜÍê³É£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +Èç¹ûÄã²»ÏëÈÃÓû§´ÓÓʼþÁбíÖÐÈ¡Ïû×¢²á£¬ÄãÖ»ÒªºöÂÔÕâ·âÓʼþ¾Í¿ÉÒÔÁË¡£ + +ллÄãµÄ°ïÖú£¡ + + +ÓÃÓÚÈ·Èϵıê¼ÇÊÇ·Ç·¨µÄ¡£ + +×î´óµÄ¿ÉÄÜÐÔÊÇÒòΪ±ê¼ÇÒѾ­¹ýÆÚ¡£ÓÃÓÚÈ·Èϵıê¼ÇÔÚ10ÌìÄÚÊÇÓÐЧµÄ¡£»¹ÓÐÒ»ÖÖ¿ÉÄÜÊÇÒòΪÓÃÓÚ +È·ÈϵĻظ´Óʼþ²¢Ã»ÓаüÀ¨ËùÓеÄÈ·ÈÏÐÅÏ¢¡£ + +ϵͳÒѾ­Éú³ÉÁËÒ»¸öеÄÈ·Èϱê¼Ç¡£Íê³ÉÈ·ÈÏ + +!A + +¼ÓÈë<#l#>ÓʼþÁÐ±í£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +×¢Ò⣬ÔÚÄãÈ·ÈÏÄãµÄ×¢²áÒÔÇ°ÇëºË¶Ô»Ø¸´µØÖ·¡£ + + <#L#>-Owner <<#l#>-owner@<#H#>> + + +ΪÁËÍê³É×¢²á<#l#>ÓʼþÁÐ±í£¬ÄãÐèҪȷÈÏÏÂÃæµÄµØÖ·ÊÇ·ñÕýÈ· + +!A + +ΪÁËÍê³ÉÈ·ÈÏ£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +ͨ¹ýÈ·ÈÏ£¬ÏµÍ³¿ÉÒÔ£º +1.È·ÈÏÊÇ·ñÄܹ»´ÓÄãµÄµç×ÓÓʼþµØÖ·ÊÕµ½Óʼþ¡£ +2.ËüÄܹ»·ÀֹijЩÈËðÓÃÄãµÄÃûÒå½øÐÐ×¢²á¡£ + + +ÓÐЩµç×ÓÓʼþµÄ¿Í»§¶Ë³ÌÐò²»Äܹ»½âÎöºÜ³¤µÄµØÖ·¡£Èç¹ûÄã²»Äܹ»Ö±½Ó»Ø¸´Õâ·âµç×ÓÓʼþ£¬Äã¿É +ÒÔÏò<<#L#>-request@<#H#>>·¢ËÍÓʼþ²¢½«ÉÏÃæµÄµØÖ··ÅÔÚÓʼþµÄÖ÷ÌâÖС£ + + +Õâ¸öÓʼþÁбíµÄ×¢²áÊÇÐèÒª¾­¹ýÓʼþÁбíµÄ¹ÜÀíÕßÅú×¼µÄ¡£Ò»µ©Äã»Ø¸´ÁËÈ·ÈÏÐÅ£¬×¢²áÇëÇó½«Ö± +½Ó·¢Ë͵½ÓʼþÁбíµÄ¹ÜÀíÕß¡£ÏµÍ³½«Í¨ÖªÄãµ±ÓʼþÁбíµÄ¹ÜÀíÕßͬÒâÄã¼ÓÈëÓʼþÁÐ±í¡£ + + +ÏÂÃæµÄµç×ÓÓʼþµØÖ· + +!A + +ÒѾ­ÊÇ<#l#>ÓʼþÁбíµÄ×¢²áÓû§¡£Äã²»ÄÜÖظ´×¢²áÒ»¸öÓʼþÁÐ±í¡£ + + +ÏÂÃæµÄµç×ÓÓʼþµØÖ· + +!A + +ÒѾ­³É¹¦µÄ×¢²á<#l#>ÓʼþÁÐ±í¡£ + +»¶Ó­¼ÓÈë<#l#>@<#H#>ÓʼþÁбí! + +ÇëÄã±£´æÕâ·âµç×ÓÓʼþ£¬ÒÔ±ãÒÔºóÈ¡Ïû×¢²á»ò¸Ä±ä×¢²áµÄµç×ÓÓʼþµØÖ·¡£ + + +ÓʼþÁбíµÄÃû³ÆÊÇ£º<#l#>@<#H#> + + +ÓʼþÁбíËùÓÐÕߵĵç×ÓÓʼþµØÖ·£º<#l#>-owner@<#H#>. + + +ÓÃÓÚÈ·Èϵıê¼ÇÊÇ·Ç·¨µÄ¡£ + +×î´óµÄ¿ÉÄÜÐÔÊÇÒòΪ±ê¼ÇÒѾ­¹ýÆÚ¡£ÓÃÓÚÈ·Èϵıê¼ÇÔÚ10ÌìÄÚÊÇÓÐЧµÄ¡£»¹ÓÐÒ»ÖÖ¿ÉÄÜÊÇÒòΪÓÃÓÚ +È·ÈϵĻظ´Óʼþ²¢Ã»ÓаüÀ¨ËùÓеÄÈ·Èϱê¼Ç¡£ + +ϵͳÒѾ­Éú³ÉÁËÒ»¸öеÄÈ·Èϱê¼Ç¡£Íê³ÉÈ·ÈÏ + +!A + +´Ó<#l#>ÓʼþÁбíÖÐɾ³ý£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +×¢Ò⣬ÔÚÄãÈ·ÈÏÈ¡ÏûÄãµÄ×¢²áÒÔÇ°ÇëºË¶Ô»Ø¸´µØÖ·¡£ + + <#l#>-Owner <<#l#>-owner@<#H#>> + + +ΪÁËÍê³É´Ó<#l#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á£¬ÄãÐèҪȷÈÏÏÂÃæµÄµØÖ·ÊÇ·ñÕýÈ· + +!A + +ΪÁËÍê³ÉÈ·ÈÏ£¬Ç뽫µç×ÓÓʼþ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ͨ³££¬ÄãÖ»ÒªÖ±½Ó»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ·ÈÏ¡£»òÕß½«µØÖ·Ö±½Ó¿½±´µ½ÓʼþÖеġ±ÊÕ¼þÈË¡°¡£ + + +ͬÑù£¬Ò²¿ÉÒÔµã»÷ÏÂÃæµÄµØÖ·£º + mailto:<#R#> + + +ϵͳ²»ÄÜÈ·ÈÏÄãµÄµç×ÓÓʼþµØÖ·ÊÇ·ñÊÇÓʼþÁбíµÄ×¢²áÓû§¡£Äã¿ÉÒÔʹÓÃÏÂÃæµÄ·½·¨»ñµÃÄãʹÓÃʲô +µØÖ·×¢²áÓʼþÁÐ±í£ºÔÚÄãÊÕµ½µÄ´ÓÓʼþÁÐ±í·¢Ë͵ĵç×ÓÓʼþÖУ¬Ã¿¸öµç×ÓÓʼþµÄÍ˻ط¾¶ +£¨Return path£©ÖаüÀ¨ÁËÄã×¢²áÓõĵç×ÓÓʼþµØÖ·£¬ÀýÈ磬mary@xdd.ff.comÊÕµ½µÄµç×ÓÓʼþÖаü +À¨µÄÍ˻ط¾¶£¨Return path£©ÊÇ<<#l#>-return--mary=xdd.ff.com@<#H#>¡£ + + +ÓÐЩµç×ÓÓʼþµÄ¿Í»§¶Ë³ÌÐò²»Äܹ»½âÎöºÜ³¤µÄµØÖ·¡£Èç¹ûÄã²»Äܹ»Ö±½Ó»Ø¸´Õâ·âµç×ÓÓʼþ£¬Äã¿ÉÒÔÏò +<<#L#>-request@<#H#>>·¢ËÍÓʼþ²¢½«ÉÏÃæµÄµØÖ··ÅÔÚÓʼþµÄÖ÷ÌâÖС£ + + +ÏÂÃæµÄµç×ÓÓʼþµØÖ· + +!A + +²¢Ã»ÓÐ×¢²á<#l#>ÓʼþÁÐ±í¡£ + +Èç¹ûÄãÒѾ­È¡Ïû×¢²á£¬µ«ÊÇÄ㻹ÊÇÊÕµ½´ÓÓʼþÁÐ±í·¢ËÍÀ´µÃµÄµç×ÓÓʼþ£¬ÇëÄãºË¶ÔÕâ·âÓʼþµÄ£º + +'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>' + +ÄãÖ»Òª½«µç×ÓÓʼþ·¢Ë͵½£º +'<#l#>-unsubscribe-user=host.dom@<#H#>'. +¾ÍÄܹ»È¡Ïû×¢²á£¬¡®user=host.dom¡¯ÊÇÄãµÄµç×ÓÓʼþµØÖ·£¬ÔÚÕâ·âÓʼþ·¢³öºó£¬Ä㽫ÊÕµ½ÏµÍ³·¢ +Ë͵ÄÓйØÈ¡Ïû×¢²áµÄÈ·ÈÏÐÅ£¬ÄãÖ»Òª»Ø¸´µç×ÓÓʼþ¾ÍÄÜÍê³ÉÈ¡Ïû×¢²á£¬×îºóϵͳ½«ÏòÄã·¢ËÍÈ¡Ïû +×¢²á³É¹¦µÄµç×ÓÓʼþ¡£ + +Èç¹ûÄãÔÚʹÓõĹý³ÌÖÐÓÐÈκÎÎÊÌ⣬Ç뽫µç×ÓÓʼþ·¢Ë͵½£º + + <#l#>-owner@<#H#> + +Ëû¸ºÔð¹ÜÀíÕâ¸öÓʼþÁÐ±í¡£ + + +ÏÂÃæµÄµØÖ· + +!A + +ÒѾ­³É¹¦µÄ´Ó<#l#>ÓʼþÁбíÖÐÈ¡Ïû×¢²á¡£ + + +ÇëÄã±à¼­ÏÂÃæµÄÎļþ²¢½«ËûÃÇ·¢Ë͵½ÏÂÃæµÄµØÖ·£º + +!R + +ÒÔ'%%%'¿ªÊ¼µÄÎÄ×ÖÊDz»Äܹ»±à¼­µÄ¡£ + + + +<#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 Ìí¼ÓÔÚϵͳ×Ô¶¯·´À¡Óʼþ¶¥²¿µÄÐÅÏ¢¡£ + +trailer Ìí¼ÓÔÚÓʼþÁбíת·¢Óʼþβ²¿µÄÐÅÏ¢¡£ + +unsub_bad Èç¹ûÈ¡Ïû×¢²áµÄÈ·ÈÏÐÅÏ¢Ë𻵣¬·¢Ë͸øÓû§µÄÐÅÏ¢¡£ +unsub_confirm ÐèÒªÓû§È·ÈϵÄÈ¡Ïû×¢²áÐÅÏ¢¡£ +unsub_nop ·¢Ë͸ø²»ÊÇÓʼþÁбí×¢²áÓû§ÒªÇóÈ¡Ïû×¢²áÓʼþÁбíµÄÐÅÏ¢¡£ +unsub_ok È¡Ïû×¢²á³É¹¦ºó·¢Ë͸øÓû§µÄÐÅÏ¢¡£ + + +ÒѾ­³É¹¦µÄ¸üÐÂÅäÖÃÎļþ¡£ + +ÓʼþÁбíµÄ½éÉÜÎļþ²»´æÔÚ¡£ + +FAQ - ÓйØ<#l#>ÓʼþÁбíµÄ³£¼ûÎÊÌâ½â´ð¡£ + diff --git a/ezmlmrc.cs b/ezmlmrc.cs new file mode 100644 index 0000000..7620bec --- /dev/null +++ b/ezmlmrc.cs @@ -0,0 +1,1097 @@ +#$Id: ezmlmrc.cs,v 1.8 1999/05/11 03:28:11 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +# Use Quoted-Printable to make averyone happy. +iso-8859-2:Q + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +List-Post: @<#H#>> +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Pro odhlá¹ení, po¹lete mail na <#L#>-unsubscribe@<#H#> +Dal¹í pøíkazy vypí¹e e-mail: <#L#>-help@<#H#> + + +--- 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#>> + + +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! + +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#>> + + +Zprávu èíslo 12 získáte pomocí následující adresy: + <<#L#>-get.12@<#H#>> + + +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 + +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. + +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èí. + + +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á ;-) + + +--- Pøipojuji kopii po¾adavku, který jsem dostal. + + + +--- Pøipojuji kopii zprávy, která se mi vrátila. + + + +Uschoval jsem si seznam zpráv z listu <#L#>, které se z va¹í adresy +vrátily. + + +Kopie tìchto zpráv mù¾ete získat v archívu. + +Pro získání zprávy 12345 z archívu, po¹lete prázdný mail na adresu + <<#L#>-get.12345@<#H#>> + + +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: + + + +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. + + + +Pro získání zprávy 12345 z archívu, po¹lete prázdný mail na adresu + <<#L#>-get.12345@<#H#>> + + +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: + + + +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#>> + + + +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í. + + +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#> + + +Promiòte, ale tato zpráva v archívu není. + + +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ù. + + +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#>> + + +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! + + +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á. + +Po¹lu ¾ádost o potvrzení, v tomto pøípadì na adresu . +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#> + + +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. + + +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. + +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. + + +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#>> + + +Pro pøihlá¹ené do digestu: + <<#L#>-digest-list@<#H#>> +a + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +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. + +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. + + +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". + + +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. + + +--- 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#>. + + +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. + + +®á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. + + +Mù¾ete také zkusit kliknout zde: + mailto:<#R#> + + +Nesouhlasíte-li, ignorujte tuto zprávu. + +Díky za spolupráci! + + +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. + + +Mù¾ete také zkusit kliknout zde: + mailto:<#R#> + + +Nesouhlasíte-li, ignorujte tuto zprávu. + +Dìkuji za spolupráci! + + +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 + + +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#>> + + +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. + + + +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. + + +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. + + +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. + + +Potvrzení: Adresa + +!A + +byla v ji¾ v listu <#l#>, kdy¾ jsem obdr¾el va¹i ¾ádost, +a zùstává pøihlá¹ena. + + +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. + + +Zdravím, tady je program ezmlm. Spravuji diskusní list +<#l#>@<#H#>. + + +Pracuji pro svého správce, který mù¾e být zasti¾en na adrese +at <#l#>-owner@<#H#>. + + +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 + + +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#>> + + +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. + + +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--jana=domena.cz@<#H#>. + + +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. + + +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. + + +Potvrzení: Zru¹il jsem adresu + +!A + +z listu <#l#>. Tato adresa ji¾ dále není v seznamu +pøihlá¹ených. + + +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). + + +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í. + +trailer pøidá se za ka¾dý pøíspìvek do listu. + +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í. + + +Textový soubor byl úspì¹nì upraven. + +®ádná informace nebyla k tomuto listu poskytnuta. + +FAQ - Èasto kladené dotazy v listu <#l#>@<#H#>. + +[ ®ádné zatím nejsou dostupné ] + + diff --git a/ezmlmrc.da b/ezmlmrc.da new file mode 100644 index 0000000..8733272 --- /dev/null +++ b/ezmlmrc.da @@ -0,0 +1,1097 @@ +0.324 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.da,v 1.17 1999/12/23 23:08:19 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +# Use Quoted-Printable to make averyone happy. +iso-8859-1:Q + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +list-help: -help@<#h#>> +list-unsubscribe: -unsubscribe@<#h#>> +list-post: @<#H#>> +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Vil du fjernes fra listen, så skriv til: <#L#>-unsubscribe@<#H#> +Vil du have en kommandooversigt, skriv til: <#L#>-help@<#H#> + + +--- 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#>> + + + +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! + +Hent alle brevene i intervallet 123 til 145 (max. 100 ad gangen), +send et tomt brev til: + <<#L#>-get.123_145@<#H#>> + + +Hent brev nummer 12, send et tomt brev til: + <<#L#>-get.12@<#H#>> + + +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 + +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. + +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. + + +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. + + +--- Vedlagt: En kopi af det kommando brev du sendte til mig. + + + +--- Vedlagt: En kopi af det brev som ikke kunne afleveres. + + + +Jeg har hold øje med hvilke breve fra <#L> listen der er +kommet retur fordi de ikke kunne afleveres til dig. + + +Kopier af disse brev er muligvis i arkivet. + +Du kan f.eks. hente brev 123 fra arkivet ved at send et tomt +brev til: + <<#L#>-get.123@<#H#>> + + +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: + + + +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#>. + + +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: + + + +<#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#>> + + + +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. + + +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#> + + +Ikke godt. Det brev findes ikke i arkivet. + + +Dette er en generel hjælpetekst. Det brev jeg modtog fra dig var +ikke sendt til nogen af mine kommandoadresser. + + +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 =. + + +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. + + +Jeg sender dig så et brev som du skal kvittere for ved at +sende et tomt svar på tilbage. + +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#> + + +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. + + +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). + + +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. + + +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#>> + + +Over digest tilmeldte: + <<#L#>-digest-list@<#H#>> +og: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +Jeg må desværre meddele at dit brev (vedlagt) ikke er blevet godkendt +af moderator. Hvis moderatoren har skrevet en kommentar, ses den +nedenfor. + +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. + + +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". + + +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. + + +--- 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#>. + + +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. + + +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). + + +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! + + +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. + + +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! + + +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 + + +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#>> + + +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. + + +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. + + +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. + + +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. + + +Anerkendelse: Adressen + +!A + +var allerede tilmeldt <#l#> listen da jeg fik din tilmelding, +og er fortsæt tilmeldt. + + +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. + + +Hej! Dette er ezmlm programmet. Jeg håndterer <#l#>@<#H#> listen. + + +Jeg arbejder for min ejer som kan nås på +<#l#>-owner@<#H#>. + + +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 + + +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#>> + + +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. + + +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--mary=xdd.ff.com@<#H#>. + + +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. + + +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. + + +Anderkendelse: Jeg har fjernet adressen + +!A + +fra <#l#> listen. Adressen er ikke længere tilmeldt. + + +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. + + +<#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. + +trailer tilføjes til alle breve som udsendes fra listen. + +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. + + +Denne text er med held blevet opdateret + +Der findes pt. ingen information om denne liste. + +FAQ - Ofte stillede spørgsmål om <#l#>@<#H#> listen. + +Der ikke lavet nogen endnu. + diff --git a/ezmlmrc.de b/ezmlmrc.de new file mode 100644 index 0000000..cd8f44f --- /dev/null +++ b/ezmlmrc.de @@ -0,0 +1,1412 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.de,v 1.22 1999/12/23 02:43:12 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# Deutsche Übersetzung: Frank Tegtmeyer +# Anmerkungen zur Übersetzung bitte direkt +# an mich +# translation to German: Frank Tegtmeyer +# 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: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +# Use Quoted-Printable to make averyone happy. +iso-8859-1:Q + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean state. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +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#> + + +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#>> + + + Für die Digest-Liste existieren die entsprechenden Adressen: + <<#L#>-digest-subscribe@<#H#>> + <<#L#>-digest-unsubscribe@<#H#>> + + +Beim Löschen oder Eintragen von Abonnenten verschicke ich eine +zusätzliche Kontrollnachricht. Diese muß zur Bestätigung einfach +nur beantwortet werden. + + +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: + + + +--- Anbei eine Kopie der Fehlermeldung (bounce), die ich + erhalten habe: + + + +Ich habe mir gemerkt, welche Nachrichten der Mailingliste + <<#L#>@<#H#>> +nicht an Sie zugestellt werden konnten. + +Eventuell befinden sich noch Kopien dieser Nachrichten +im Archiv. + + +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#> + + +Hier die Nummern der Nachrichten: + + + +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. + + +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#> + + +Hier die Nummern der ersten Nachricht pro Digest: + + + +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. + + + +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. + + +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#> + + +Diese Nachricht ist im Archiv nicht vorhanden. + + +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! + +<<#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. + + +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 :) + + +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#> + + +Entsprechend für die Digest-Liste: + <#L#>-digest-subscribe-ich=lightwerk.de@<#H#> + <#L#>-digest-unsubscribe-ich=lightwerk.de@<#H#> + + +So einfach ist das :) Sie brauchen nicht einmal einen +Betreff oder irgendeinen Nachrichtentext schreiben. + + +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. + +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. + + +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#> + + +Entsprechend für die Digest-Liste: + + <#L#>-digest-subscribe@<#H#> + <#L#>-digest-unsubscribe@<#H#> + + +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. + + +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. + + +Die Nutzer können auch die folgende Adressen benutzen: + + <#L#>-subscribe-ich=lightwerk.de@<#H#> + <#L#>-unsubscribe-ich=lightwerk.de@<#H#> + + +Für Digests: + <#L#>-digest-subscribe-ich=lightwerk.de@<#H#> + <#L#>-digest-unsubscribe-ich=lightwerk.de@<#H#> + + +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. + + +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#>> + + +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#>> + + + +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#>> + + + +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. + + + +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. + + +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. + + +Viel Erfolg! + +PS: Bitte wenden Sie sich an den Listeneigentümer + <#L#>-owner@<#H#> +wenn Sie Probleme irgendwelcher Art mit der Listenadministration +haben. + + +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. + +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. + +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! + + + +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). + + +Wenn Ihr Programm Hyperlinks unterstützt, können Sie auch +hier klicken: + mailto:<#R#> + + + +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. + + +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#> + + +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. + + +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. + +Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier: + mailto:<#R#> + + + +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! + + +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. + +Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier: + mailto:<#R#> + + +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! + + +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 + + +Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier: + mailto:<#R#> + + +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#>> + + +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. + +Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier: + mailto:<#R#> + + +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. + + +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. + + +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. + + +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. + + +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. + + +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#>> + + +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#> + + +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 + + +oder klicken Sie hier, wenn Ihr Programm Hyperlinks unterstützt: + mailto:<#R#> + + +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#>> + + +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. + +Falls Ihr Programm Hyperlinks unterstützt, klicken Sie hier: + mailto:<#R#> + + +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. + + +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. + + +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--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 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 :) + + +Bestätigung: die Adresse + +!A + +wurde von der Mailingliste + <#l#>@<#H#> +abgemeldet. + + +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). + + + +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 + +trailer an alle Listennachrichten angehängt + +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 + + +Der Text wurde erfolgreich abgeändert. + + +Für diese Liste wurde noch keine Beschreibung bereitgestellt. + + +Oft gestellte Fragen+Antworten für die Mailingliste + <#l#>@<#H#> + +Leider hat sich noch niemand die Mühe gemacht, ein entsprechendes +Dokument zu erstellen. diff --git a/ezmlmrc.en_US b/ezmlmrc.en_US new file mode 100644 index 0000000..bf51c12 --- /dev/null +++ b/ezmlmrc.en_US @@ -0,0 +1,1152 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.en_US,v 1.17 1999/12/11 03:30:16 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean state. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#> +For additional commands, e-mail: <#L#>-help@<#H#> + + +--- 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#>> + + +or for the digest to: + <<#L#>-digest-unsubscribe@<#H#>> + + +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. + + +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. + + + +--- Enclosed is a copy of the bounce message I received. + + + +I've kept a list of which messages from the <#L#> mailing list have +bounced from your address. + + +Copies of these messages may be in the 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#>> + + +Here are the message numbers: + + + +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. + + +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#>> + + +Here are the digest message numbers: + + + +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#>> + + + +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. + + +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#>> + + +Sorry, that message is not in the archive. + + +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#>> + + +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! + +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#>> + + +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#>> + + +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#>> + + +For the digest list: + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +That's all. No subject and no message body needed! + + +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. + +I will send a confirmation request to the user address, in this +case . All the user has to do is to reply to +this confirmation request message. + + +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#>> + + +For the digest list: + + <<#L#>-digest-subscribe@<#H#>> + <<#L#>-digest-unsubscribe@<#H#>> + + +The user will receive a confirmation request to make +sure s/he controls the subscription address. Once this +is verified the user is unsubscribed. + + +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. + +Subscriptions work the same way. + + +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. + + +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#>> + + +For digest subscribers: + <<#L#>-digest-list@<#H#>> +and: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +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! + + +Good luck! + +PS: Please contact the list owner (<#L#>-owner@<#H#>) if you +have any questions or problems. + + +I'm sorry, your message (enclosed) was not accepted by the moderator. +If the moderator has made any comments, they are shown below. + +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. + + +Alternatively, click here: + mailto:<#A#> + + +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". + + +Alternatively, click here: + mailto:<#R#> + + +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. + + +--- 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. + + +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. + + +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. + + +or click here: + mailto:<#R#> + + +If you don't approve, simply ignore this message. + +Thank you for your help! + + +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. + + +or click here: + mailto:<#R#> + + +If you don't approve, simply ignore this message. + +Thank you for your help! + + +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 + + +or click here: + mailto:<#R#> + + +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#>> + + +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. + + +or click here: + mailto:<#R#> + + +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. + + +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. + + +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. + + +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. + + +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#>> + + +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#>. + + +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 + + +or click here: + mailto:<#R#> + + +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#>> + + +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. + + +or click here: + mailto:<#R#> + + +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--mary=xdd.ff.com@<#H#>. + + +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. + + +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. + + +Acknowledgment: I have removed the address + +!A + +from the <#l#> mailing list. This address +is no longer a subscriber. + + +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). + + + +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. + +trailer added to all posts sent out from the list. + +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. + + +The text file was successfully updated. + +No information has been provided for this list. + +FAQ - Frequently asked questions of the <#l#>@<#H#> list. + +None available yet. + diff --git a/ezmlmrc.es b/ezmlmrc.es new file mode 100644 index 0000000..5b5cf00 --- /dev/null +++ b/ezmlmrc.es @@ -0,0 +1,1264 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.es,v 1.4 1999/12/22 04:06:38 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc- Traducción de: Vicent Mas, Francesc Alted, Sonia Lorente, Cyndy DePoy +# ####### Servicom2000 +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +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#> + + + +--- 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#>> + + +o, para los resúmenes, a: + + <<#L#>-unsubscribe@<#H#>> + + + +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. + + + +--- Le adjunto una copia del mensaje devuelto que he recibido. + + + +He guardado una lista de todos los mensajes de la lista de correo +<#L#> que han sido devueltos procedentes de su dirección. + + + +Una copia de estos mensajes puede estar en el archivo. + + + +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#>> + + +Aquí están los números de los mensajes: + + + +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. + + + +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#>> + + +Estos son los números de mensaje de los resúmenes: + + + +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#>> + + + +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. + + +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#> + + +Lo siento, ese mensaje no está en el archivo. + + + +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#>> + + +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! + + +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#>> + + + +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#>> + + +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#>> + + +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#>> + + + +Eso es todo. No es necesario poner "Asunto" o cuerpo principal en +el mensaje. + + + +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. Mandaré una petición de confirmación +a la dirección del usuario, en este caso a +. El usuario simplemente debe responder +a este mensaje de confirmación. + +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#> + + +Para la lista de resúmenes: + + <#L#>-digest-subscribe@<#H#> + <#L#>-digest-unsubscribe@<#H#> + + + +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. + + + +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. + + +Las suscripciones funcionan del mismo modo. + + +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. + + + +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#>> + + +Para suscriptores al resumen: + + <<#L#>-digest-list@<#H#>> + +y: + + <<#L#>-digest-log@<#H#>> + + + +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#>> + + +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. + + + +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. + + + +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! + + + +¡Buena suerte! + +PD: Por favor, póngase en contacto con el propietario de la lista +(<#L#>-owner@<#H#>) si tiene preguntas o problemas. + + + +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. + + + +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. + + +Como alternativa haga clic aquí: + + mailto:<#A#> + + +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". + + +Como alternativa, haga clic aquí: + mailto:<#R#> + + +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. + + + +--- 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. + + + +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ó. + + +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. + +o haga clic aquí: + + mailto:<#R#> + + +Si no está de acuerdo, simplemente ignore este mensaje. + +¡Gracias por su ayuda! + + +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. + + +o haga clic aquí: + + mailto:<#R#> + + +Si no está de acuerdo, simplemente ignore este mensaje. + +¡Gracias por su ayuda! + + +¡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 + + +o haga clic aquí: + + mailto:<#R#> + + +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#>> + + +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. + + +o haga clic aquí: + + mailto:<#R#> + + +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. + + + +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:". + + + +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é. + + +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. + + +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#>> + + + +¡Hola! Soy el programa ezmlm. Me ocupo de la lista de correo +<#l#>@<#H#>. + + + +Estoy trabajando para mi propietario, a quien se puede localizar +en <#l#>-owner@<#H#>. + + +¡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 + + +o haga clic aquí: + + mailto:<#R#> + + +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#>> + + +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. + + +o haga clic aquí: + + mailto:<#R#> + + +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--maria=xdd.ff.com@<#H#>>. + + + +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:". + + +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. + + +Acuse de recibo: He dado de baja la dirección + +!A + +de la lista de correo <#l#>. Esta dirección ya no está suscrita. + + + +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). + + + +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. + +trailer añadido a todos los mensajes enviados de la lista. + +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. + + +El fichero de texto fue actualizado correctamente. + +No se ha proporcionado información para esta lista. + +FAQ - Preguntas más comunes para la lista <#l#>@<#H#>. + +Ninguno disponible todavía. + + diff --git a/ezmlmrc.fr b/ezmlmrc.fr new file mode 100644 index 0000000..dd04a17 --- /dev/null +++ b/ezmlmrc.fr @@ -0,0 +1,1226 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.fr,v 1.22 1999/12/22 04:02:15 lindberg Exp $ +#Name:$ +# +# ezmlmrc.fr - Traduction: Frank DENIS "Jedi/Sector One" +# ########## +# 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: +# : ce qui suit sera place dans DIR/nomdefichier. +# : efface DIR/nomdefichier. +# : cree le repertoire DIR/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, cree le fichier si et seulement si la liste est +# archivee (-a) et non publique (-P). Si le repere suitant est +# , 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 , '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. + +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#> + +<#L#> + +<#0#> + + + + +# Repertoires opur les bulletins + + + +# Pour la base de donnees d'adresses supplementaires + + +# Pour la liste noire + + +# 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. + + + + + +# liens: point -> DIR/editor + + + + + + +# Uniquement pour les listes moderees + + +# On se debarasse des commutateurs de configuration pour le mode d'edition +# pour pouvoir debuter sur de bonnes bases. + + + + + + + + + + +# Inutile, si ce n'est pour la moderation des messages. + +# Nous ne nettoyons pas les fichiers de texte pour aider +# les utilisateurs effectuant leur configuration manuellement, +# par exemple en modifiant le repertoire DIR/remote. + +<#8#> +# Administration distante + +<#9#> +# Moderation des messages + +<#7#> +# Adresse du proprietaire de la liste + +<#5#> + +<#D#>/Mailbox + +|<#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. + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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 : + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... et maintenant sans confirmation d'inscription ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... maintenant aucune confirmation pour se desinscrire ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... et finalement aucune confirmation nulle part ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# Le rejet ne devrait pas etre configure pour les sous-listes. + +# 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. + +|<#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. + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# Pour la moderation de messages, l'editeur dispose de store et de clean. + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# Pour les listes non moderees, il y a send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive est ici pour les listes normales. A mettre dans moderator pour +# les listes qui utilisent mess-mod. + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# Toutes les listes peuvent provoquer des avertissements, a moins que +# l'option -w ne soit activee. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# Pour les retours a l'expediteur des bulletins. + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# Retours a l'expediteur pour les listes et bulletins. + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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). + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# Pour les sous-listes, ce qui suit doit etre preserve +list-post +# Retire l'en-tete "from" si -3 est actif. + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +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. + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# Ajoute une nouvelle ligne "From: xxx" si l'on a utilise -3 'xxx' . + +From: <#3#> +# Taille maximale et taille minimale de chaque message. + +30000:2 +# Retire les parties en mime si l'option -x est utilisee. + +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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- Fin de tout ce qui concerne le SQL. + +[<#L#>] + +--------------------------------------------------------------------- +Desinscription: envoyez un message a: <#L#>-unsubscribe@<#H#> +Pour obtenir de l'aide, ecrivez a: <#L#>-help@<#H#> + + +--- 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#>> + + +ou pour une liste qui vous serait envoyee sous forme de bulletin, a : + <<#L#>-unsubscribe@<#H#>> + + +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. + + + +--- Ci-dessous se trouve une copie du message problematique qui m'est revenu : + + + + +J'ai conserve une liste des messages de la liste de diffusion <#L#> qui +n'ont temporairement pas pu etre delivres a votre adresse. + + +Une copie de ces messages doit se trouver dans l'archive. + + +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#>> + + +Voici les numeros des messages en question : + + + +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. + + +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#>> + + +Voici le numero du premier message de chaque bulletin : + + + +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#>> + + + +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#>. + + +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#> + + +Desole, mais ce message est introuvable dans l'archive. + + +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#>> + + +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 ! + +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#>> + + +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#>> + + +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#>> + + +Idem pour les listes presentees sous la forme de bulletins : + <<#L#>-digest-subscribe-john=machine.domaine@<#H#>> + <<#L#>-digest-unsubscribe-john=machine.domaine@<#H#>> + + +C'est tout ! Aucun sujet special ni corps de message n'est requis. + + +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. + +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. + + +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 + + +Et pour les listes presentees sous forme de bulletins : + +<#L#>-digest-subscribe@<#H#> +<#L#>-digest-unsubscribe@<#H#> + + +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. + + +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. + + +Les inscriptions fonctionnent de facon analogue. + + +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. + + +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#>> + + +Pour les abonnes aux bulletins : + <<#L#>-digest-list@<#H#>> +et : + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +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. + + +Bonne chance ! + +PS: Contactez le proprietaire (<#L#>-owner@<#H#>) si vous avez +une question ou des difficultes. + + +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. + +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. + + +Si votre brouteur le permet, vous pouvez aussi cliquer ici : + mailto:<#A#> + + +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". + + +Si votre brouteur prend en compte les liens hypertexte, vous +pouvez aussi cliquer ici : + mailto:<#R#> + + +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: + + +--- 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#>. + + + +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: + + +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. + + +ou, si votre logiciel de messagerie le permet, cliquer ici : + mailto:<#R#> + + +Si vous n'approuvez pas cet abonnement, ne tenez pas compte de +ce message. + +Merci de votre aide ! + + +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. + + + +Le lien suivant pourrait aussi fonctionner : + mailto:<#R#> + + +En cas de desaccord, ne tenez pas compte de ce message. + +Merci de votre aide ! + + + +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 + + +ou suivez ce lien : + mailto:<#R#> + + +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#>> + + + +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. + + +ou suivez ce lien : + mailto:<#R#> + + +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. + + +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". + + +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. + + +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. + + + +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#>> + + +Bonjour ! Je suis le programme ezmlm. Je m'occupe de la liste +de diffusion <#l#>@<#H#>. + + +Je travaille pour mon proprietaire, qui peut etre joint a: +<#l#>-owner@<#H#>. + + +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 + + +ou suivez ce lien : + mailto:<#R#> + + +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#>> + + +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. + + +Vous pouvez aussi tout aussi bien suivre ce lien : + mailto:<#R#> + + +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--dieu=ciel.paradis.com@<#H#>. + + +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". + + +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. + + +Accuse de reception : l'adresse + +!A + +a ete retiree de la liste de diffusion <#l#>. +Cette adresse ne figure donc plus parmis les abonnes. + + +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). + + + + +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. + +trailer ajoute a la fin de chaque contribution a la liste. + +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. + + +Le fichier de texte a ete mis a jour avec succes. + +Aucune information complementaire n'existe pour cette liste. + +FAQ - Reponses aux questions courantes sur la liste <#l#>@<#H#> + +Aucune pour le moment. + + diff --git a/ezmlmrc.id b/ezmlmrc.id new file mode 100644 index 0000000..506918f --- /dev/null +++ b/ezmlmrc.id @@ -0,0 +1,1155 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.id,v 1.5 1999/12/22 04:02:15 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc.id translated By Aria Prima Novianto. +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Untuk berhenti, e-mail: <#L#>-unsubscribe@<#H#> +Untuk perintah yang lain, e-mail: <#L#>-help@<#H#> + + +--- 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#>> + + +atau untuk digest ke: + <<#L#>-unsubscribe@<#H#>> + + +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. + + + +--- Berikut adalah kopi dari e-mail mental yang kami terima. + + + +Kami menyimpan daftar posting dari milis <#L#> yang mental dari +alamat anda. + + +Kopi dari posting-posting ini mungkin masih ada di dalam arsip. + + +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#>> + + +Berikut adalah nomor-nomor posting: + + + +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. + + +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#>> + + +Berikut adalah nomor-nomor posting dari digest: + + + +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#>> + + + +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. + + +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#> + + +Maaf, posting tersebut tidak ada di arsip kami. + + +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#>> + + +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! + +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-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#>> + + +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#>> + + +Untuk list digest: + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +Itu saja. Tidak perlu subjek dan isi dari postingnya! + + +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. + +Kami akan mengirimkan sebuah permohonan konfirmasi ke alamat tersebut, +dalam hal ini . Yang bersangkutan tinggal menjawab +mail konfirmasi tersebut. + + +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#> + + +Untuk list digest: + +<#L#>-digest-subscribe@<#H#> +<#L#>-digest-unsubscribe@<#H#> + + +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. + + +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. + +Untuk berlangganan adalah sama caranya. + + +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. + + +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#>> + + +Untuk pelanggan-pelanggan digest: + <<#L#>-digest-list@<#H#>> +dan: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +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! + + +Semoga sukses! + +PS: Silakan kontak si pemilik list (<#L#>-owner@<#H#>) jika anda +mempunyai pertanyaan-pertanyaan atau masalah-masalah. + + +Maaf, posting anda (terlampir) tidak diterima oleh moderator. Jika ada +komentar-komentar dari moderator, mereka akan terlihat di bawah. + +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. + + +Alternatif lainnya, klik di sini: + mailto:<#A#> + + +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". + + +Alternatif lainnya, klik di sini: + mailto:<#R#> + + +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. + + +--- 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. + + +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. + + +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. + + +atau klik di sini: + mailto:<#R#> + + +Jika anda tidak menyetujuinya, jangan hiraukan posting tersebut. + +Terima kasih atas bantuan anda! + + +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. + + +atau klik di sini: + mailto:<#R#> + + +Jika anda tidak menyetujuinya, jangan hiraukan posting tersebut. + +Terima kasih atas bantuan anda! + + +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 + + +atau klik di sini: + mailto:<#R#> + + +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#>> + + +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. + + +atau klik di sini: + mailto:<#R#> + + +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. + + +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:". + + +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. + + +Untuk diketahui: Alamat berikut + +!A + +sudah terdaftar pada milis <#l#> ketika kami menerima permohonan anda, +dan masih berstatus sebagai pelanggan. + + +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#>> + + +Hai! Ini adalah program ezmlm. +Kami yang mengurus milis <#l#>@<#H#>. + + +Kami bekerja untuk pemilik kami, yang dapat dijangkau pada alamat e-mail +<#l#>-owner@<#H#>. + + +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 + + +atau klik di sini: + mailto:<#R#> + + +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#>> + + +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. + + +atau klik di sini: + mailto:<#R#> + + +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--mary=xdd.ff.com@<#H#>. + + +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:". + + +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. + + +Untuk diketahui: Kami telah menghapus alamat + +!A + +dari milis <#l#>. Alamat tersebut sudah tidak ada lagi di dalam +daftar pelanggan. + + +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). + + + +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. + +trailer ditambahkan ke semua posting yang terkirim. + +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. + + +Teks filenya sudah diupdate dengan sukses. + +Tidak ada informasi yang telah disediakan untuk list ini. + +FAQ - Frequently asked questions untuk milis <#l#>@<#H#>. + +Belum tersedia sampai saat ini. + + diff --git a/ezmlmrc.it b/ezmlmrc.it new file mode 100644 index 0000000..3db0eec --- /dev/null +++ b/ezmlmrc.it @@ -0,0 +1,1155 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.it,v 1.3 1999/12/22 04:02:15 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# translation by Roberto De Carlo rodeca@tiscalinet.it +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Per cancellarsi, scrivi a: <#L#>-unsubscribe@<#H#> +Se vuoi conoscere altri comandi, scrivi a: <#L#>-help@<#H#> + + +--- 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#>> + + +o per le raccolte a: + <<#L#>-unsubscribe@<#H#>> + + + +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. + + + +--- Allego una copia del messaggio di ritorno che ho ricevuto. + + + +Ho tenuto una copia dei messaggi della lista <#L#> che sono tornati +indietro dal tuo indirizzo. + + +Le copie di questi messaggi potrebbero essere nell'archivio. + + + +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#>> + + +Ecco i numeri dei messaggi: + + + +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. + + +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#>> + + +Ecco i numeri delle raccolte: + + + +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#>> + + + +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. + + +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#> + + +Spiacente, questo messaggio non è nell'archivio. + + +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#>> + + +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! + +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#>> + + +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#>> + + +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#>> + + +Per la lista delle raccolte: + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +Questo è tutto. Non sono necessari comandi nell' oggetto o nel corpo del +messaggio! + + +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. + +Spedirò una richiesta di conferma all'indirizzo dell'utente, in questo caso +a . Tutto ciò che l'utente dovrà fare sarà quello di +rispondere alla richiesta di conferma. + + +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#>> + + +Per la lista delle raccolte: + + <<#L#>-digest-subscribe@<#H#>> + <<#L#>-digest-unsubscribe@<#H#>> + + +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. + + +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. + +Le iscrizioni funzionano allo stesso modo. + + +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. + + +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#>> + +Per gli iscritti alle raccolte: + <<#L#>-digest-list@<#H#>> +e: + <<#L#>-digest-log@<#H#>> + + +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#>> + + + +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. + + +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. + + +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! + + +Buona fortuna! + +PS: Per favore contatta l'amministratore della lista (<#L#>-owner@<#H#>) se +hai domande o problemi. + +Spiacente, ma il tuo messaggio (allegato) non è stato accettato dal moderatore. +Se il moderatore ha scritto qualche commento, essi sono riportati qui sotto. + +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. + + +Oppure clicca qui: + mailto:<#A#> + + +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". + + +Oppure clicca qui: + mailto:<#R#> + + +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. + + +--- 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. + + +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. + + +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. + + +oppure clicca qui: + mailto:<#R#> + + +Se non sei d'accordo ti basta ignorare questo messaggio. + +Grazie per il tuo aiuto! + + +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. + + +oppure clicca qui: + mailto:<#R#> + + +Se non sei d'accordo ti basta ignorare questo messaggio. + +Grazie per il tuo aiuto! + + +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 + + +oppure clicca qui: + mailto:<#R#> + + +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#>> + + +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. + + +oppure clicca qui: + mailto:<#R#> + + +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. + + +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:". + + +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. + + +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. + + +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#>> + + +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#>. + + +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 + + +oppure clicca qui: + mailto:<#R#> + + +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#>> + + +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. + + +oppure clicca qui: + mailto:<#R#> + + +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--mary=xdd.ff.com@<#H#>. + + +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:". + + +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. + +Conferma: ho cancellato l'indirizzo + +!A + +dalla mailing list <#l#> . Questo indirizzo non è più iscritto. + + +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). + + + +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. + +trailer aggiunto ai messaggi spediti fuori dalla lista + +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. + + +Il file di testo è stato aggiornato correttamente. + +Non sono state fornite informazioni per questa lista. + +FAQ - Frequently asked questions per la lista <#l#>@<#H#> . + +Non ancora disponibili. diff --git a/ezmlmrc.jp b/ezmlmrc.jp new file mode 100644 index 0000000..a275392 --- /dev/null +++ b/ezmlmrc.jp @@ -0,0 +1,1334 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.jp,v 1.28 1999/12/22 04:02:15 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc.jp - Translated: Masashi Fujita +# ####### +# 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: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#> +For additional commands, e-mail: <#L#>-help@<#H#> + + +--- mailing list <#l#> $B$GMxMQ2DG=$J(B command $B0lMw$G$9(B --- + +ezmlm $B$O0J2<$N(B command $B$r<+F0$G-help@<#H#>> + (Get help and commands) + + * $B9XFI$r3+;O$9$k(B + <<#L#>-subscribe@<#H#>> + (Start subscription) + +$B9XFI$rCf;_$9$k$K$O(B mailing list <#L#> $B$+$i$N(B message $B$N(B header $B$K(B +$B4^$^$l$F$$$k(B ``List-Unsubscribe'' $B9T$,<($9(B address $B$K6u(B message +$B$rAw$C$F$/$@$5$$!#$^$?$O0J2<$N(B address $B08$F$K6u(B message $B$rAw$C$F(B +$B2<$5$$!#(B + <<#L#>-unsubscribe@<#H#>> + (Stop subscription) + + +digest $B$N9XFI$rCf;_$9$k$K$O0J2<$N(B address $B08$F$K6u$N(B message $B$r(B +$BAw$C$F2<$5$$!#(B + <<#L#>-digest-unsubscribe@<#H#>> + (Stop digest subscription) + + +$B9XFI$N3+;O$*$h$SCf;_$N:]$K$O(B ezmlm $B$O3NG'$N0Y$N(B message $B$r(B +$B;XDj$5$l$?(B address $B08$F$KAw?.$7$^$9!#$=$N3NG'$N0Y$N(B message +$B$KBP$7$F!"(Breply $B$rJV$9$3$H$G3NG'$Ne$N;X<($K=>$C$F$b!"K>$s$@7k2L$K$J$i$J$$>l9gEy$O!"(B +mailing list <#L#> $B$N-owner@<#H#> $BKxO"Mm$7$F2<$5$$!#(B +$B!JJV;v$,CY$l$k$+$b$7$l$^$;$s!#$4N;>52<$5$$!K(B + +$BLdBj$N2r@O$r?J$a$d$9$/$9$k0Y$K(B ezmlm $B$+$iAw$i$l$F$-$?(B message $B$r(B +$B!XA4$F$N(B header $B$r4^$a$F!YE:IU$7$F$/$@$5$$!#(B + +--- $B0J2<$KAw$i$l$F$-$?(B message $B$rE:IU$7$F$*$-$^$9(B --- + + + +--- $B0J2<$KJVAw$5$l$F$-$?(B message $B$rE:IU$7$F$*$-$^$9(B --- + + + +mailing list <#L#> $B$,5.J}08$KAw$C$?(B message $B$NFb(B +$BG[Aw$K<:GT$7$?$b$N$NHV9f$rE:IU$7$F$*$-$^$9!#(B + + +message $B$O(B archive $BCf$KJ]B8$5$l$F$$$^$9!#(B + + +$B6u$N(B message $B$r0J2<$N(B command address $B$KAw$k$3$H$G!"5.J}$,-get.123_145@<#H#>> + $B!J0lEY$K-index@<#H#>> + + +$BG[Aw$K<:GT$7$?(B message $B$NHV9f$O0J2<$NDL$j$G$9(B: + + + +$BG[Aw$K<:GT$7$?(B mailing list <#L#> $B$N(B digest $BHG$K(B +$B4^$^$l$F$$$?:G=i$N(B message $BHV9f$rE:IU$7$F$*$-$^$9!#(B + + +ezmlm $B$O(B digest $B<+BN$OJ]B8$7$F$$$^$;$s!#(B +$B$G$9$,!"0J2<$N(B command address $B$K6u$N(B message $B$rAw$k;v$G(B +mailing list <#L#> $BK\BN$N(B +archive $B$+$i!"5.J}$,-get.123_145@<#H#>> + $B!J0lEY$K-index@<#H#>> + + +--- $B0J2<$O(B digest $BHG$N3+;O(B message $BHV9f0lMw$G$9(B --- + + + +$B5.J}08$K(B mailing list <#L#> $B$,Aw$C$?(B +message $B$N4v$D$+$,G[Aw=PMh$:!"3NG'$N0Y$K(B ezmlm $B$,Aw?.$7$?(B +message $B$bG[Aw$K<:GT$7$F$7$^$$$^$7$?!#(B + +$BG[Aw$K<:GT$7$FJVAw$5$l$F$-$?(B message $B$rE:IU$7$F$*$-$^$9!#(B + +$B$3$N(B message $B$O!"5.J}08$KG[Aw$,2DG=$+H]$+$rD4$Y$k$?$a$N$b$N$G$9!#(B +$B$3$N(B message $B$bG[Aw$K<:GT$7$?>l9g$O!"(Bezmlm $B$O5.J}$N(B address $B$r(B +mailing list <#L#>@<#H#> $B$+$i(B +$B<+F0E*$K:o=|$7$^$9!#(B + +$B$b$&0lEY9XFI$r$7$?$$>l9g$O!"0J2<$N(B address + + <<#L#>-subscribe@<#H#>> + +$B08$K6u$N(B message $B$rAw$C$F!"?75,$K9XFI$r$7$J$*$7$F2<$5$$!#(B + + + +$B5.J}08$K(B mailing list <#L#> $B$,Aw$C$?(B message $B$N4v$D$+$G(B +$BG[Aw$K<:GT$7$^$7$?!#(B + +$BG[Aw$K<:GT$7$?(B message $B$N:G=i$N0lDL$rE:IU$7$F$*$-$^$9!#(B + +$B$b$7$b$3$N(B message $B<+BN$bG[Aw$K<:GT$7$?>l9g$K$O(B +ezmlm $B$O3NG'$N(B message $B$rAw$j$^$9!#$=$N(B message $B$bG[Aw$K<:GT$7$?>l9g(B +$B5.J}$N(B address $B$O(B mailing list <#L#> $B$+$i(B +$BL5>r7o$K:o=|$5$l$^$9!#(B + + +digest $B$N9XFI$r4uK>$9$k>l9g$O!"6u$N(B message $B$r(B + + <<#L#>-digest-subscribe@<#H#>> + (To subscribe to the digest) + +$B08$KAw$C$F2<$5$$!#(B + +digest $B$N9XFI$r$d$a$k>l9g$O!"6u$N(B message $B$r(B + + <<#L#>-digest-unsubscribe@<#H#>> + (To unsubscribe from the digest) + +$B08$KAw$C$F2<$5$$!#(B + +mailing list <#L#> $B$X$N(B post $B$O(B + + <<#L#>@<#H#>> + (To post to the list) + +$B08$K$*4j$$$7$^$9!#(B + + +$B?=$7LuM-$j$^$;$s$,!";XDj$5$l$?(B message $B$O(B archive $BCf$K(B +$B$"$j$^$;$s$G$7$?!#(B + + +$B$3$l$OHFMQ$N(B help message $B$G$9!#(B +$B5.J}$N(B message $B$O(B ezmlm $B$N(B command $B$H$7$F$OG'<1$5$l$^$;$s$G$7$?!#(B + +$B0J2<$KMxMQ2DG=$J(B command address $B0J2<$NDL$j$G$9!'(B +$B!J6u(B message $B$r;XDj$5$l$?(B command address $B$KAw?.$9$k$3$H$G $B$N@bL@$r-info@<#H#>> + (Get information) + * mailing list <#l#> $B$N!X$h$/?R$M$i$l$k-faq@<#H#>> + (Get FAQ) + + + * digest list <#L#>-digest $B$N9XFI$r3+;O$9$k(B + <<#L#>-digest-subscribe@<#H#>> + (Start digest subscription) + + * digest list <#L#>-digest $B$N9XFI$rCf;_$9$k(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! + + * 123 $BHV$+$i(B 145 $BHVKx$N(B message $B$r-get.123_145@<#H#>> + $B!J0lEY$K-index.123_456@<#H#>> + + * message 12345 $BHV$N(B Subject: $B$HF1$8(B Subject: $B$r;}$D(B message $B$r(B + $B-thread.12345@<#H#>> + + +command address $B08$F$N(B message $B$O(B address $B$N$_$,I,MW$G$9!#Cf?H$O(B +$B2?$,$"$C$F$bL5;k$5$l$^$9!#(B + +$BI,MW$G$"$l$PDL>o$H$O0[$J$k(B address $B$G(B mailing list <#L#> $B$+$i$N(B +message $B$r '='$B!K(B + john=host.domain + $B"-(B + <<#L#>-subscribe-john=host.domain@<#H#>> + +<#L#>-subscribe-john=host.domain@<#H#> $B08$F$K6u(B message $B$rAw$k$3$H$G(B +john@host.domain $B$G$N9XFI$r3+;O$G$-$^$9!#(B + +$B$3$N>l9g!"9XFI$rCf;_$9$k$K$O(B <#L#>-unsubscribe-john=host.domain@<#H#> +$B08$F$K6u(B message $B$rAw$C$F$/$@$5$$!#(B + + +--- $B4IM}@<#H#> $B$N4IM}$K(B +$B6(NO$7$F$$$?$@$-46$N(B mailing list program $B$H$O46E*$G$"$j!";HMQ$,4JC1$@$H(B +$B;W$($k$G$7$g$&!#(B + +$B0J2<$O(B mailing list $B$N4IM}l9g$O!"(B + + john@host.domain + $B"-(B + john=host.domain + $B"-(B + <<#L#>-subscribe-john=host.domain@<#H#>> + +$B$NMM$K$7$F(B command address $B$r@8@.$7!"$=$N(B address $B$X(B +$B6u$N(B message $B$rAw$C$F2<$5$$!#(B + +$B$^$?!"(Bjohn@host.domain $B$r9XFIl9g$O(B + + <<#L#>-unsubscribe-john=host.domain@<#H#>> + +$B$X6u$N(B message $B$rAw$C$F2<$5$$!#(B + + +digest list $B$K2C$($?$j!&30$7$?$j$9$k>l9g$bF1MM$K$7$F(B + + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + +$B$NMM$K$J$j$^$9!#(B + + +message $B$NCf?H$OI,MW$"$j$^$;$s!#(Baddress $B$@$1$,=EMW$G$9!#(B + + +ezmlm $B$O5.J}$K3NG'$N(B message $B$rAw$j$^$9!#$3$l$O(B request $B$,(B +$BK\Ev$K5.J}$+$i$N$b$N$+$r3NG'$9$k$?$a$G$9!#Aw$i$l$?(B message $B$K(B +reply $B$9$k;v$G +ezmlm $B$O(B user $B$KBP$7$F3NG'$N(B message $B$rAw$j$^$9!#(B +$B>e5-$N>l9g$O(B $B08$K3NG'$N(B message $B$,Aw$i$l$k(B +$B$3$H$K$J$j$^$9!#3NG'$N(B message $B$r + +$B$3$N3NG'$K$h$C$F!"Bh;0uBV$,JQ2=$7$?$3$H$r(B user $B$KDLCN$7$^$9!#(B + + +Subscription +------------ +$B4IM}-subscribe@<#H#>> + (Start subscription) + + <<#L#>-unsubscribe@<#H#>> + (Stop subscription) + + +digest list $B$N9XFI3+;O!&=*N;$O0J2<$N(B command address $B$G$9!#(B + + <<#L#>-digest-subscribe@<#H#>> + (Start digest subscription) + + <<#L#>-digest-unsubscribe@<#H#>> + (Stop digest subscription) + + +$BH/?. +$B$3$N(B mailing list $B$N9XFI3+;O!&C&B`$O4IM}fIW$G$9!#(B + +request $B$,@5Ev$J$b$N$H;W$&$N$G$"$l$P!"(Bezmlm $B$+$iFO$$$?3NG'$N(B +message $B$KBP$7$F(B reply $B$7$F2<$5$$!#@5Ev$G$J$$$H;W$&$N$G$"$l$P(B +ezmlm $B$+$i$N(B message $B$rC1=c$KL5;k$7$F2<$5$$!#$=$7$F!"I,MW$J$i(B +request $B$NH/?. +$B9XFI3+;O!&C&B`$O<+F0$G=hM}$5$l$^$9!#(B + + +$B$^$?!"(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) + +$B$NMM$K$9$k;v$G!"H/?.85$H$O0[$J$k(B address$B!J$3$N>l9g$O(B mary@host.domain$B!K(B +$B$G(B mailing list $B$+$i$N(B message $B$rl9g$N$_9XFI!&C&B`$OM-8z$K$J$j$^$9!#(B + +$B4IM}$N>pJs$O9XFI@\(B mail $B$rAw$C$?>l9g$OJL$G$9!K(B + + +mailing list <#L#>@<#H#> $B$N9VFI-list@<#H#>> +ezmlm $B$N(B log $B$O0J2<$N(B address $B$+$iF@$i$l$^$9!#(B + <<#L#>-log@<#H#>> + + +mailing list <#L#>@<#H#> $B$N(B digest $BHG$N9VFI-digest-list@<#H#>> +digest $BHG$K4X$9$k(B log $B$O0J2<$N(B address $B$G$9!#(B + <<#L#>-digest-log@<#H#>> + + +ezmlm $B$,Aw$j=P$9(B message text $B$rJT=8$9$k$K$O!"0J2<$N(B command address: + + <<#L#>-edit@<#H#>> + +$B08$K6u$N(B e-mail $B$rAw$C$F2<$5$$!#(B +$B!JJT=82DG=$J(B message $B0lMw5Z$S!"JT=8J}K!$OJV?.$K4^$^$l$F$$$^$9!K(B + + +Moderated posts +--------------- +message $B$r?3::$9$kMM$K@_Dj$5$l$F$$$k>l9g$O!"(Bezmlm $B$O(B post $B$5$l$?(B +message $B$r0lC6J]B8$7!"?3::l9g$O!"(Bezmlm $B$,(B "Reply-To:" $B$K@_Dj$7$?(B address +$B08$K(B reply $B$r$7$F2<$5$$!#K\J8$N(B copy $B$OI,MW$"$j$^$;$s!#(B +$B!J(Bezmlm $B$O(B reply $B$NCf?H$O0l@Z8+$F$$$^$;$s!K(B + +post $B$r5qH]$9$k>l9g$O!"(Bezmlm $B$,(B "From:" $B$K@_Dj$7$?(B address $B08$K(B +reply $B$r$7$F2<$5$$!#DL>o(B Mail User Agent (MUA) $B$N(B 'reply-to-all' +$B$N5!G=$r;H$C$F(B message $B$N=`Hw$r$7$?8e$K!"ITMW$J(B address $B$r:o$k(B +$B$@$1$@$H;W$$$^$9!#5qH]$9$kM}M3Ey$r#38D$N(B'%'$B$G;O$^$k9T$N8e$KIU$1(B +$B#38D$N(B'%' $B$GJD$8$k$3$H$GF1:-$9$k;v$,=PMh$^$9!#(B + +$B7+$jJV$7$^$9$,!"4IM}$N>pJs$O(B ezmlm $B7PM3$G$O(B +$BL@$i$+$K$5$l$^$;$s!#(B + +$BJ#?t$N4IM}l9g!"(Bezmlm $B$O:G=i$K4IM}$N4IM}l9g!"5Z$S$=$N5U$N>l9g$O(B ezmlm $B$O(B +$B5.J}08$K(B message $B$rAw$j$^$9!#(B + +ezmlm $B$ODj$a$i$l$?4|8B!JDL>o$O(B 5$BF|!K0JFb$K?3::$N7k2L$rl9g$K$O!"H/?. + +Vacations +--------- +$B0l;~E*$K0[$J$k(B address $B$G4IM}$N:n6H$r$7$?$$>l9g$O!"(B +"Mailing-List: contact <#L#>-help@<#H#>; run by ezmlm" $B$d(B +"Subject: MODERATE for <#L#>@<#H#>" $B$d(B +"Subject: CONFIRM subscribe to <#L#>@<#H#>" $BEy$N(B +$B4IM}$N0Y$N(B message $B$,K>$s$@(B address $B08$KFO$/MM$K@_Dj$9$l$P(B +$B2DG=$G$9!#(B + +$B$^$?$OCN?M08$KAw$jD>$9MM$K$9$k$H$$$&l9g$O;vA0$K5G'$r9T$&$H$$$&$N$G(B +$B$"$l$P!">e5-$N4IM}MQ(B message $B$KBP$7$FE,@Z$J1~Ez$r<+F0@8@.$9$k(B +$BMM$K@_Dj$7$F2<$5$$!#(B + + +$B9XFI3+;O!&=*N;$N:n6H$r4IM}l9g!"9XFI3+;O!&=*N;$NBP>]$K$J$C$?(B address $B08$K3NG'$N(B message +$B$,FO$-$^$9!#$=$N8e$KA44IM}l9g$O!"5.J}$NAw?.$7$?(B message $B$d(B address $B$,BP>]$H$J$C$?(B user +$B08$KAw$i$l$k;v$r3P$($F$*$$$F2<$5$$!#(B + + +$B$*-owner@<#H#> + + $B$KO"Mm$7$F2<$5$$!#(B + + +$B?=$7LuM-$j$^$;$s$,!"5.J}$N(B post $B$7$?(B message $B$O4IM}l9g$O(B +$B0J2<$KE:IU$5$l$F$$$^$9!#(B + +mailing list <#L#> $B$K(B +$B0J2<$KE:IU$5$l$?(B message $B$,(B post $B$5$l$^$7$?!#(B +post $B$rG'$a$k>l9g$O!"0J2<$N(B address + +!A + +$B$X(B reply $B$7$F2<$5$$!#(B + +$BDL>o$O(B Mail User Agent (MUA) $B$N(B reply $B$N5!G=$@$1$G==J,$JH&$G$9!#(B + +$B$&$^$/$$$+$J$$>l9g$O!" + +$B$rIU$1$F(B reply message $B$r:n@.$7$F2<$5$$!#(B + + + +MUA $B$K$h$C$F$O(B + + mailto:<#A#> + +$B$r(B click $B$9$k$@$1$G=`Hw$,=PMh$k>l9g$b$"$k$G$7$g$&!#(B + + +post $B$rG'$a$J$$>l9g$O!"0J2<$N(B address + +!R + +$B08$K(B message $B$rAw$C$F2<$5$$!#(B + +MUA $B$K(B "reply-to-all" $B$N5!G=$,$"$k$N$J$i(B <#L#>-reject $B0J30$G(B +$B;O$^$kB>$N(B address $B$r:o=|$9$k$N$,4JC1$G$7$g$&!#(B + + +MUA $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1$G=`Hw$,=PMh$k>l9g$b$"$k$G$7$g$&!#(B + + +*** post $B$5$l$?(B message $BK\BN$O(B copy $B$9$kI,MW$O$"$j$^$;$s(B *** + +post $B$rG'$a$J$$>l9g$K!"2?$+(B comment $B$rIU$1$?$$$N$G$"$l$P(B +$B0J2<$NMM$J(B marker line + +%%% Start comment +%%% End comment + +$B$N4V$K(B comment $B$r=q$$$F2<$5$$!#(B + +--- $B0J2<$KAw$i$F$-$?(B message $B$rE:IU$7$F$*$-$^$9(B + + +--- $B4IM}@<#H#> $B$G$N(B + $B9XFI$N>uBV$rJQ99$7$^$7$?!#(B + +$B$3$NJQ99$,K>$s$@$b$N$G$J$$>l9gEy$O!"$9$0$K(B + + <#L#>-owner@<#H#> + +$BKxO"Mm$r2<$5$$!#(B + +mailing list <#L#> $B$N(B archive $B$K(B access $B$7$?$$>l9g$O(B + + <#L#>-help@<#H#> + +$BKx!"6u$N(B message $B$rAw$C$F2<$5$$!#(B + + +$B?=$7LuM-$j$^$;$s!#(B +mailing list <#L#> $B$N4IM}@\AjCL$7$F$_$F2<$5$$!#(B + +--- $B5.J}$+$iAw$i$l$?(B message $B$rE:IU$7$F$*$-$^$9(B --- + + +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$N(B +$B9XFIl9g$O!"(B + $BI,MW$J3NG'$O:Q$s$G$$$^$9!K(B + +$B9XFI$rG'$a$k>l9g$O!"6u$N(B message $B$r0J2<$N(B address + +!R + +$B$K(B reply $B$7$F2<$5$$!#(B + +$BDL>o$O(B Mail User Agent (MUA) $B$N(B reply $B$N5!G=$@$1$G==J,$JH&$G$9!#(B +$B$=$l$,$&$^$/9T$+$J$$>l9g$O!"(B + + To: <#R#> + +$B$r + +MUA $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1$G=`Hw$,=PMh$k$G$7$g$&!#(B + + +$B9XFI$rG'$a$J$$>l9g$O!"$3$N(B message $B$rL5;k$7$F$/$@$5$$!#(B + + +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$+$i(B +$B30$9$N$G$"$l$P!"0J2<$N(B address + +!R + +$B08$K(B reply $B$7$F2<$5$$!#(B + +$BDL>o$O(B Mail User Agent (MUA) $B$N(B reply $B$N5!G=$@$1$G==J,$JH&$G$9!#(B +$B$=$l$,$&$^$/9T$+$J$$>l9g$O!"(B + + To: <#R#> + +$B$r + +MUA $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1$G=`Hw$,=PMh$k$G$7$g$&!#(B + + +$BC&B`$rG'$a$J$$>l9g$O!"$3$N(B message $B$rL5;k$7$F2<$5$$!#(B + + +$B3NG'$N0Y$N(B key $B$,IT@5$G$9!#(B + +$B4v$D$+$NM}M3$,9M$($i$l$^$9$,!"$b$C$H$bB?$$$N$,4|8B@Z$l$K(B +$B$h$k$b$N$G$9!#3NG'$OLs(B 10$BF|0JFb$K9T$o$l$J$1$l$P$J$j$^$;$s!#(B +$B$^$?!"(Be-mail $B$r07$&4D6-$K$h$C$F$O(B ezmlm $B$,;H$C$F$$$kD9$$(B +address $B$r@Z$j5M$a$F$7$^$&;v$,$"$k$N$G!"A4$F$N(B address $B$,(B +$B@5$7$/EA$o$C$F$$$k$+$I$&$+3NG'$7$F$_$F2<$5$$!#(B + +$B?7$7$$(B key $B$rMQ0U$7$^$7$?!"0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$K(B +$B2C$($?$$>l9g$O!"6u$N(B message $B$r0J2<$N(B address + +!R + +$B$KAw$C$F2<$5$$!#(B + + +Mail User Agent (MUA) $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1$G3NG'$N(B message $B$rAw$k=`Hw$b=PMh$k$G$7$g$&!#(B + + +$B7+$jJV$9MM$G$9$,!"(Breply $B$N(B address $BA4$F$,@5$7$/-Owner <<#L#>-owner@<#H#>> + +$B$KO"Mm$r2<$5$$!#(B + + +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> +$B$K2C$($k;v$rG'$a$k>l9g$O!"6u$N(B message $B$r(B + +!R + +$B$KJV?.$7$F2<$5$$!#(B + +$BDL>o$O(B Mail User Agent (MUA) $B$N(B reply $B$N5!G=$r;H$&$@$1$G$7$g$&!#(B + +$B$=$l$G$&$^$/9T$+$J$$>l9g$O(B + + To:<#R#> + +$B$H$7$F(B message $B$r:n@.$7$F2<$5$$!#(B + + +MUA $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1=`Hw$,=PMh$k$b$N$b$"$k$G$7$g$&!#(B + + +$B$3$N3NG'$K$O0J2<$NFs$D$N0UL#$,$"$j$^$9!#(B + + * $B;XDj$5$l$?(B address $B$G(B message $B$,Aw?.=PMh$k$+H]$+(B + * $B5.J}$N(B address $B$r56$C$?(B request $B$rGS=|$9$k(B + + +e-mail $B$r07$&4D6-$K$h$C$F$O!"(Bezmlm $B$,;H$&D9$$(B address $B$r(B +$B$&$^$/07$($J$$;v$,$"$j$^$9!#$=$NMM$J>l9g$O0J2<$N(B address + + <<#L#>-request@<#H#>> + +$B$K(B "Subject: <#R#>" $B$H$7$F(B +message $B$rAw$C$F2<$5$$!#(B + + +mailing list <#L#> $B$O(B moderated $B$J(B mailing list $B$G$9!#(B +$B5.J}$,$3$N3NG'$rAw?.$9$k$H!"A4$F$N4IM}5G'$7$?8e!"5.J}08$F$K$=$N;]$NDLCN$,(B +$BFO$/$O$:$G$9!#(B + + +$B0J2<$N(B address + +!A + +$B$O4{$K(B mailing list <#L#> $B$N(B +$B9XFI +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$K2C$($^$7$?!#(B + + - - - - - - - - - + +[[[ Welcome to <#L#>@<#H#>! ]]] + +$B8e$G3NG'$N$?$a$KI,MW$K$J$k;v$,$"$j$^$9$N$G!"$3$N(B message $B$O(B +$BK:$l$:J]B8$7$F$*$$$F2<$5$$!#(B + +$B9XFI$rCf;_$9$k>l9g$O!"0J2<$N(B address $B08$F$K6u$N(B message $B$rAw$C$F2<$5$$(B + + <<#l#>-unsubscribe-<#t#>@<#H#>> + + +$B$3$s$K$A$O!#;d$O(B ezmlm + +mailing list <#L#>@<#H#> $B$r4IM}$7$F$$$^$9!#(B + + +$B$3$N(B mailing list $B$N-owner@<#H#> + +$B$GO"Mm$9$k$3$H$,=PMh$^$9!#(B + + +$BAw$i$l$F$-$?3NG'$N0Y$N(B key $B$,@5$7$/$"$j$^$;$s!#(B + +$B4v$D$+$NM}M3$,9M$($i$l$^$9$,!"$b$C$H$bB?$$$N$,4|8B@Z$l$K(B +$B$h$k$b$N$G$9!#3NG'$OLs(B 10$BF|0JFb$K9T$o$l$J$1$l$P$J$j$^$;$s!#(B +$B$^$?!"(Be-mail $B$r07$&4D6-$K$h$C$F$O(B ezmlm $B$,;H$C$F$$$kD9$$(B +address $B$r@Z$j5M$a$F$7$^$&;v$,$"$k$N$G!"A4$F$N(B address $B$,(B +$B@5$7$/EA$o$C$F$$$k$+$I$&$+3NG'$7$F$_$F2<$5$$!#(B + +$B?7$7$$(B key $B$rMQ0U$7$^$7$?!"0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$+$i(B +$B30$7$?$$>l9g$O!"6u$N(B message $B$r0J2<$N(B address + +!R + +$B$KAw$C$F2<$5$$!#(B + + +Mail User Agent (MUA) $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$9$k$@$1$G3NG'$N(B message $B$rAw$k=`Hw$b=PMh$k$G$7$g$&!#(B + + +$B7+$jJV$9MM$G$9$,!"(Breply $B$N(B address $BA4$F$,@5$7$/-Owner <<#L#>-owner@<#H#>> + +$B$KO"Mm$r2<$5$$!#(B + + +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$N(B +$B9XFIl9g$O!"6u$N(B message $B$r0J2<$N(B address + +!R + +$BKxAw$C$F2<$5$$!#(B + +$BDL>o$O(B Mail User Agent (MUA) $B$N(B reply $B$N5!G=$r;H$($PBg>fIW$G$9!#(B + +$B$b$7!"$=$l$G$&$^$/9T$+$J$$>l9g$O!"(B + + To: <#R#> + +$B$H$7$F(B message $B$r:n@.$7$F2<$5$$!#(B + + +$B$^$?!"(BMail User Agent (MUA) $B$K$h$C$F$O(B + + mailto:<#R#> + +$B$r(B click $B$7$F(B message $B$r:n@.$9$k;v$b=PMh$k$G$7$g$&!#(B + + +$B5.J}$N(B address $B$,9XFI-return--mary=xdd.ff.com@<#H#>> + +$B$H$$$&6q9g$$$G$9!#(B + + +$B4D6-$K$h$C$F$O!"D9$$(B address $B$r$&$^$/07$($J$$>l9g$,M-$j$^$9!#(B +$B$3$N(B message $B$K(B reply $B$r$&$^$/JV$;$J$$MM$J$i!"0J2<$N(B address + + <<#L#>-request@<#H#>> + +$B$K(B "Subject: <#R#>" $B$rIU$1$FAw$C$F2<$5$$!#(B + + +$B0J2<$N(B address + +!A + +$B$O(B mailing list <#L#> $B$N(B +$B9XFI +$B$+$i$N(B mail $B$,FO$/>l9g$O!"5.J}$,8=:_;H$C$F$$$k(B e-mail address $B$H$O(B +$B0c$&(B address $B$G(B mailing list <#L#> $B$r(B +$B9XFI$7$F$$$k$N$+$b$7$l$^$;$s!#(B + +hearder $B$N0J2<$NItJ,$K(B + +'Return-Path: <<#L#>-return-1234-user=host.dom@<#H#>>' + +$B5.J}$,$I$N(B address $B$G9XFI$r$7$F$$$k$N$+$,8=$l$F$$$^$9!#(B +$B!J$3$N>l9g!"(Buser@host.dom $B$G9XFI$r$7$F$$$k$3$H$K$J$j$^$9!K(B + +address $B$rL@<($7$F9XFICf;_$N(B request $B$r=P$9>l9g$O!"0J2<$NMM$K(B + + <<#L#>-unsubscribe-user=host.dom@<#H#>> + +'<#L#>-unsubscribe-' $B$N8e$m$K!"(Buser@host.dom $B$r(B user=host.dom $B$K(B +$B=q$-49$($?J*$r7R$$$G2<$5$$!#(B + +$B4v$D$+$N(B Mail User Agent (MUA) $B$O!"(BReturn-Path $B$r8+$k$?$a$K$O(B +$BFCJL$JA`:n$rI,MW$K$J$j$^$9!#(B + + * Eudora 4.0 $B$@$H!X(BBlah blah ...$B!Y%\%?%s$r(B click $B$9$k(B + * PMMail $B$@$H(B Window menu $B$N!X(BShow entire message/header$B!Y(B + $B%\%?%s$r(B click $B$9$k(B + + - - - - - - - - + +address $B$rL@<($7$?9XFICf;_$b$&$^$/$$$+$J$$>l9g$O!"?=$7Lu$"$j$^$;$s$,(B + + * $B5.J}$,2?$r$7$h$&$H$7$F<:GT$7$?$N$+(B + * ezmlm $B$+$i$N(B message + * $B9XFICf;_$r4uK>$9$k(B address + +$B$rE:IU$7$F!"(Bmailing list <#L#> $B$N(B owner $B$N(B + + <#L#>-owner@<#H#> + +$BKxAw$C$F2<$5$$!#!JJV;v$K;~4V$,$+$+$k$+$b$7$l$^$;$s$,$4N;>52<$5$$!K(B + + +$B0J2<$N(B address + +!A + +$B$r(B mailing list <#L#> $B$N9XFI +$BE:IU$5$l$?(B message text $B$rJT=8$7$F!"0J2<$N(B address + +!R + +$B08$KJVAw$7$F2<$5$$!#(B + +$B!X(B%%%$B!Y$G;O$^$k9T$,(B message text $B3+;O$N(B marker line $B$K(B +$B$J$C$F$$$^$9!#(B + +$B!J$3$N9T$K5.J}$N;H$C$F$$$k(B Mail User Agent (MUA) $B$G$N(B + $B0zMQ$N0u(B (ex. foo>%%%) $B$,IU2C$5$l$F$$$k>l9g$O!"(Bmessage text + $BK\BN$NItJ,$KIU$$$?0zMQ$N0u$O<+F0=|5n$5$l$^$9!K(B + + +$B4IM}-edit.FILE command $B$r;H$&$3$H$G(B ezmlm $B$,=PNO$9$k(B +mailing list <#L#> $B$N0Y$N(B message text $B$rJT=8$9$k$3$H$,=PMh$^$9!#(B + +$B0J2<$OJT=82DG=$J(B FILE $B$H!"$=$NL\E*$G$9!#(Bfile FOO $B$rJT=8$7$?$$(B +$B>l9g$O(B <#L#>-edit.FOO $B08$K6u$N(B message $B$rAw$C$F2<$5$$!#(B +$BJT=8$N;EJ}$OAw?.$5$l$k(B message $B$K4^$^$l$F$$$^$9!#(B + +File Use + +bottom ezmlm $B$N(B command $B0lMw$G$9!#(B + ezmlm $B$,JVAw$9$kA4$F$N(B message $B$KIU2C$5$l$^$9!#(B +digest digest $BHG$N0Y$N(B command $B$N@bL@$G$9!#(B +faq mailing list <#L#> $B$G$N(B FAQ $B$G$9!#(B +get_bad archive $BCf$K;XDj$5$l$?(B message $B$r8+IU$1$i$l$J$+$C$?>l9g$K(B + $BAw$i$l$^$9!#(B +help help message $B$G$9!J(B'top' $B$H(B 'bottom' $B$N4V$KF~$j$^$9!K(B +info mailing list <#L#> $B$N>pJs$G$9!#(B +mod_help $B4IM}l9g(B + $B4IM}l9g$KAw$i$l$^$9!#(B +sub_bad $B9XFI4uK>l9g$KAw$i$l$^$9!#(B +sub_confirm $B9XFI4uK>l9g$K(B + $BAw$i$l$^$9!#(B +sub_ok $B9XFI$N +trailer $B$3$N(B mailing list $B$KBP$9$kA4$F$N(B post $B$NKvHx$K(B + $BIU$1B-$5$l$FAw$i$l$^$9!#(B + +unsub_bad $B9XFIl9g$KAw$i$l$^$9!#(B +unsub_confirm $B9XFI +message text $B$N99?7$K@.8y$7$^$7$?!#(B + + +--- mailing list <#L#>@<#H#> $B$K$D$$$F(B --- +$B!J8=:_9);vCf$G$9!K(B + +--- mailing list <#L#>@<#H#> $B$K4X$7$F!"$h$/?R$M$i$l$k 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: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +ISO-8859-2 + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +List-Post: @<#H#>> +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Wypisanie? wy¶lij list: <#L#>-unsubscribe@<#H#> +Wiêcej pomocy? wy¶lij list: <#L#>-help@<#H#> + + +--- 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#>> + + +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! + + <<#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. + + + <<#L#>-get.12@<#H#>>: + Chêæ otrzymania kopii listu nr 12 z archiwum. + + <<#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 + + <<#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. + + +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. + + +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 ;-) + + +--- Za³±cznik jest kopi± polecenia, które otrzyma³em. + + + +--- Za³±cznik jest kopi± odrzuconego listu, który dosta³em. + + + +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#>. + + +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: + + + +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#>. + + +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: + + + +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. + + + +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. + + +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#> + + + Opiekun listy pocztowej - + - <<#L#>-owner@<#H#>> + + +Przykro mi, tego listu nie ma w archiwum. + + +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. + + +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#> + + +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! + + +Wy¶lê Ci pro¶bê o potwierdzenie +Co zrobiæ z moim listem? +Po prostu odpowiedz na niego i gotowe. + +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#> + + +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ê. + + +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ê. + +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¶æ. + + +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#>> + + +Adresy w³a¶ciwe dla przegl±du listy: + <<#L#>-digest-list@<#H#>> +i: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +Przykro mi, ale Twój list nie zosta³ zaakceptowany przez moderatora. +Je¿eli moderator uczyni³ jakie¶ uwagi, zamieszczam je poni¿ej. + +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 + + +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 + + +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. + + +--- 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#> + + +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ê. + + +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 + + +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! + + +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 + + +mailto:<#R#> + + +Twój program pocztowy powienien automatycznie prawid³owo zaadresowaæ +list, je¿eli u¿yjesz opcji "Odpowiedz/Reply". + +Dziekujê za pomoc! + + +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 + + +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 - + +<#L#>-owner@<#H#> + + + +Aby potwierdziæ chêæ zapisania siê z adresu: + +!A + +na listê dyskusyjn± o nazwie <#L#>, +wy¶lij, proszê, pust± odpowied¼ pod adres: + +!R + + +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ê. + + +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. + + + +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ê. + + +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. + + +Czesæ! Nazywam siê "ezmlm" i zarz±dzam serwerem pocztowych +list dyskusyjnych, miêdzy innymi list± o nazwie: +<#L#>@<#H#> + + +Jestem komputerem, bezdusznym s³ug± opiekuna listy, cz³owieka :-), +którego mo¿na znale¼æ pod adresem: +<#L#>-owner@<#H#>. + + +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 + + +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#> + + +Aby potwierdziæ, ¿e chcesz usunac adres + +!A + +z listy prenumaratorów <#L#>, prze¶lij, proszê, pust± +odpowied¼ na ten list pod adres: + +!R + + +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--Bóg=niebo.prezydent.pl@<#H#>. + + +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: + + +mailto:<#L#>-owner@<#H#> + + <#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). + + +Zawiadomienie: usun±³em adres pocztowy + +!A + +z listy prenumeratorów <#l#>. +Na adres ten nie bêd± ju¿ przychodzi³y przesy³ki z listy. + + +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. + + + +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! + +trailer tekst dodawany do ka¿dego listu, ostro¿nie! + +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. + + +Plik tekstowy zosta³ szczê¶liwie zamieniony. + + +Nie mam ¿adnych informacji na temat listy :-( + +FAQ - najczê¶ciej zadawane pytania na li¶cie +<#l#>@<#H#>. + +Jeszcze nic tu nie ma :-(, przepraszamy! + + diff --git a/ezmlmrc.pt b/ezmlmrc.pt new file mode 100644 index 0000000..a8532a5 --- /dev/null +++ b/ezmlmrc.pt @@ -0,0 +1,1133 @@ +0.324 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.pt_BR,v 1.15 1999/05/06 09:26:00 lindberg Exp $ +#$Name:$ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +ISO-8859-1:Q + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contacte <#L#>-help@<#H#>; gerenciado pelo ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +list-help: -help@<#h#>> +list-unsubscribe: -unsubscribe@<#h#>> +list-post: @<#H#>> +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Para cancelar a subscrição, envie mensagem para: <#L#>-unsubscribe@<#H#> +Para comandos adicionais, envie mensagem para: <#L#>-help@<#H#> + + +--- 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. + + +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! + + <<#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. + + + <<#L#>-get.12@<#H#>>: + Recupera uma cópia da mensagem 12 do arquivo. + + + <<#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 + + <<#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. + +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). + + +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 ;-) + + +--- Abaixo está uma cópia da requisição que eu recebi. + + + +--- Abaixo está uma cópia da mensagem devolvida que eu recebi. + + + +Eu mantenho um controle das mensagens da lista <#L> que não +foram entregues para o seu endereço. + +Cópias destas mensagens podem estar no arquivo. + +Para pegar a mensagem 12345 do arquivo, envie uma mensagem vazia para + <<#L#>-get.12345@<#H#>> + + +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: + + + +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. + + +Para recuperar a mensagem 12345 do arquivo, envie uma mensagem vazia para: + <<#L#>-get.12345@<#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#>> + +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": + + + +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#>> + + + +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. + + +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#> + + +Sinto muito, esta mensagem não está arquivada. + + +Esta é uma mensagem de ajuda genérica. A mensagem que eu recebi +não era para os meus endereços de comando. + + +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#>> + + +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! + + +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. + +Eu enviarei um pedido de confirmação para o endereço do usuário, +neste caso . 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#> + + +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. + + +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. + +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. + + +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#>> + + +Para o cadastro de assinantes da lista digest: + <<#L#>-digest-list@<#H#>> +e: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +Sinto muito, sua mensagem (incluída) não foi aceita pelo moderador. +Se o moderador fez algum comentário, este será mostrado abaixo. + +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. + + +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". + + +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. + + +--- 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#>. + + +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. + + +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. + + +ou clique aqui: + mailto:<#R#> + + +Se você não aprovar, simplesmente ignore esta mensagem. + +Obrigado pela sua ajuda! + + +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. + + +ou clique aqui: + mailto:<#R#> + + +Se você não aprova, simplesmente ignore esta mensagem. + +Obrigado pela sua ajuda! + + +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 + + +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#>> + + +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. + + +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. + + +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:". + + +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. + + +Confirmação: o endereço + +!A + +está na lista <#l#>. Este endereço já estava +cadastrado antes do seu pedido ser recebido. + + +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. + + +Oi! Este é o programa ezmlm. Eu estou gerenciando +a lista <#l#>@<#H#>. + + +Eu estou trabalhando para o meu dono, que pode ser +contactado pelo endereço <#l#>-owner@<#H#>. + + +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 + + +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#>> + + +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. + + +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--mary=xdd.ff.com@<#H#>. + + +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:". + + +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. + + +Confirmação: Eu removi o endereço + +!A + +da lista <#l#>. Este endereço não está +mais na lista. + + +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). + + + +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. + +trailer incluído em todas as mensagens enviadas pela lista. + +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. + + +O arquivo texto foi atualizado com sucesso. + + +Ainda não há informações para esta lista. + +FAQ - Questões mais freqüentes na lista <#l#>@<#H#>. + +Ainda não disponível. + + diff --git a/ezmlmrc.pt_BR b/ezmlmrc.pt_BR new file mode 100644 index 0000000..81aadbf --- /dev/null +++ b/ezmlmrc.pt_BR @@ -0,0 +1,1134 @@ +0.324 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.pt_BR,v 1.16 1999/12/23 23:08:19 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +# Explicitly specify character-set, when this ezmlmrc was used. +ISO-8859-1:Q + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contacte <#L#>-help@<#H#>; gerenciado pelo ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +List-Post: @<#H#>> +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +Para cancelar a subscrição, envie mensagem para: <#L#>-unsubscribe@<#H#> +Para comandos adicionais, envie mensagem para: <#L#>-help@<#H#> + + +--- 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. + + +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! + + <<#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. + + + <<#L#>-get.12@<#H#>>: + Recupera uma cópia da mensagem 12 do arquivo. + + + <<#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 + + <<#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. + +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). + + +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 ;-) + + +--- Abaixo está uma cópia da requisição que eu recebi. + + + +--- Abaixo está uma cópia da mensagem devolvida que eu recebi. + + + +Eu mantenho um controle das mensagens da lista <#L> que não +foram entregues para o seu endereço. + +Cópias destas mensagens podem estar no arquivo. + +Para pegar a mensagem 12345 do arquivo, envie uma mensagem vazia para + <<#L#>-get.12345@<#H#>> + + +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: + + + +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. + + +Para recuperar a mensagem 12345 do arquivo, envie uma mensagem vazia para: + <<#L#>-get.12345@<#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#>> + +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": + + + +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#>> + + + +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. + + +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#> + + +Sinto muito, esta mensagem não está arquivada. + + +Esta é uma mensagem de ajuda genérica. A mensagem que eu recebi +não era para os meus endereços de comando. + + +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#>> + + +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! + + +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. + +Eu enviarei um pedido de confirmação para o endereço do usuário, +neste caso . 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#> + + +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. + + +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. + +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. + + +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#>> + + +Para o cadastro de assinantes da lista digest: + <<#L#>-digest-list@<#H#>> +e: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +Sinto muito, sua mensagem (incluída) não foi aceita pelo moderador. +Se o moderador fez algum comentário, este será mostrado abaixo. + +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. + + +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". + + +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. + + +--- 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#>. + + +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. + + +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. + + +ou clique aqui: + mailto:<#R#> + + +Se você não aprovar, simplesmente ignore esta mensagem. + +Obrigado pela sua ajuda! + + +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. + + +ou clique aqui: + mailto:<#R#> + + +Se você não aprova, simplesmente ignore esta mensagem. + +Obrigado pela sua ajuda! + + +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 + + +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#>> + + +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. + + +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. + + +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:". + + +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. + + +Confirmação: o endereço + +!A + +está na lista <#l#>. Este endereço já estava +cadastrado antes do seu pedido ser recebido. + + +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. + + +Oi! Este é o programa ezmlm. Eu estou gerenciando +a lista <#l#>@<#H#>. + + +Eu estou trabalhando para o meu dono, que pode ser +contactado pelo endereço <#l#>-owner@<#H#>. + + +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 + + +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#>> + + +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. + + +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--mary=xdd.ff.com@<#H#>. + + +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:". + + +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. + + +Confirmação: Eu removi o endereço + +!A + +da lista <#l#>. Este endereço não está +mais na lista. + + +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). + + + +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. + +trailer incluído em todas as mensagens enviadas pela lista. + +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. + + +O arquivo texto foi atualizado com sucesso. + + +Ainda não há informações para esta lista. + +FAQ - Questões mais freqüentes na lista <#l#>@<#H#>. + +Ainda não disponível. + + diff --git a/ezmlmrc.ru b/ezmlmrc.ru new file mode 100644 index 0000000..49e6d34 --- /dev/null +++ b/ezmlmrc.ru @@ -0,0 +1,1015 @@ +0.324 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.ru,v 1.4 1999/12/23 23:08:19 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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 file is a must for russian mailing lists +koi8-r + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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. + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#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. + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-receipt -D '<#D#>' + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +|<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +# Only one allowed +list-help +list-unsubscribe +list-post + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +contact <#L#>-help@<#H#>; run by ezmlm +# Headeradd needs to always exist + +# Good for mailing list stuff (and vacation program) +Precedence: bulk +# To prevent indexing by findmail.com +X-No-Archive: yes +# rfc2369 +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +List-Post: @<#H#>> +X-Comment: <#l#> mailing list (Russian, KOI8-R) +# max & min message size + +40000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +-- +To unsubscribe, e-mail: <#L#>-unsubscribe@<#H#> +For additional commands, e-mail: <#L#>-help@<#H#> + + +--- ëÏÍÁÎÄÙ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> --- + +÷ÓÅ ËÏÍÁÎÄÙ ÏÂÒÁÂÁÔÙ×ÁÀÔÓÑ Á×ÔÏÍÁÔÉÞÅÓËÉ. ðÏÖÁÌÕÊÓÔÁ, +ÎÅ ÐÏÓÙÌÁÊÔÅ ÉÈ ÎÁ ÁÄÒÅÓ ÓÁÍÏÇÏ ÓÐÉÓËÁ, ÔÁÍ ÏÎÉ ÏÂÒÁÂÏÔÁÎÙ +ÎÅ ÂÕÄÕÔ, Á ×ÁÓ ÏÂÒÕÇÁÀÔ ÐÏÄÐÉÓÞÉËÉ. ëÏÍÁÎÄÏÊ Ñ×ÌÑÅÔÓÑ +ÐÉÓØÍÏ (ÎÅÚÁ×ÉÓÉÍÏ ÏÔ ÅÇÏ ÓÏÄÅÒÖÁÎÉÑ), ÐÏÓÌÁÎÎÏÅ ÎÁ +ÏÄÉÎ ÉÚ ÁÄÍÉÎÉÓÔÒÁÔÉ×ÎÙÈ ÁÄÒÅÓÏ×: + +áÄÒÅÓ ÄÌÑ ÐÏÄÐÉÓËÉ: + <<#L#>-subscribe@<#H#>> + +áÄÒÅÓ ÄÌÑ ÏÔËÁÚÁ ÏÔ ÒÁÓÓÙÌËÉ: + <<#L#>-unsubscribe@<#H#>> + +äÌÑ ÐÏÌÕÞÅÎÉÑ ÐÒÁ×ÉÌ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ É FAQ: + <<#L#>-info@<#H#>> + <<#L#>-faq@<#H#>> + + +ôÁË ÖÅ ÐÏÄÄÅÒÖÉ×ÁÀÔÓÑ É ÄÁÊÄÖÅÓÔÙ: + <<#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! + +þÔÏÂÙ ÐÏÌÕÞÉÔØ ÓÏÏÂÝÅÎÉÑ Ó 123 ÐÏ 145 (max 100 ÎÁ ÐÉÓØÍÏ), ÐÉÛÉÔÅ ÓÀÄÁ: + <<#L#>-get.123_145@<#H#>> + + +äÌÑ ÐÏÌÕÞÅÎÉÑ ÐÉÓØÍÁ #12 ÉÚ ÁÒÈÉ×Á ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + <<#L#>-get.12@<#H#>> + + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÉÎÄÅËÓÁ Ó subject É Á×ÔÏÒÁÍÉ ÐÉÓÅÍ 123-456: + <<#L#>-index.123_456@<#H#>> + +# Lists need to be both archived and indexed for -thread to work + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ×ÓÅ ÐÉÓÅÍ, Ó×ÑÚÁÎÎÙÈ Ó ÐÉÓØÍÏÍ #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. + +óÏÄÅÒÖÉÍÏÅ ÐÉÓÅÍ ÒÏÌÉ ÎÅ ÉÇÒÁÅÔ, ×ÁÖÅÎ ÌÉÛØ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ +×Ù ÐÏÓÙÌÁÅÔÅ ÐÉÓØÍÏ. + + +åÓÌÉ ÎÉÞÅÇÏ ÎÅ ÐÏÍÏÇÁÅÔ, ×Ù ÍÏÖÅÔÅ Ó×ÑÚÁÔØÓÑ Ó ×ÌÁÄÅÌØÃÅÍ +ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ ÐÏ ÁÄÒÅÓÕ <#L#>-owner@<#H#>. + + +--- îÉÖÅ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÚÁÐÒÏÓÁ + + + +--- îÉÖÅ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ + + + +óÉÓÔÅÍÏÊ ÓÏÈÒÁÎÅÎ ÓÐÉÓÏË ÐÉÓÅÍ ÉÚ <#L#>, ËÏÔÏÒÙÅ ÎÅ ÄÏÛÌÉ ÄÏ +×ÁÛÅÇÏ ÁÄÒÅÓÁ (Ô.Å. ÎÁ ÎÉÈ ÂÙÌÏ ÐÏÌÕÞÅÎÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ) + + +ëÏÐÉÉ ÜÔÉÈ ÐÉÓÅÍ ÎÁÈÏÄÑÔÓÑ × ÁÒÈÉ×Å. + +þÔÏÂÙ ÐÏÌÕÞÉÔØ ÐÉÓØÍÏ 12345 ÉÚ ÁÒÈÉ×Á, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + <<#L#>-get.12345@<#H#>> + + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÏÏÂÝÅÎÉÊ 123-145 (max 100 ÎÁ ÚÁÐÒÏÓ): + <<#L#>-get.123_145@<#H#>> + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÐÏÓÌÅÄÎÉÈ 100 ÓÏÏÂÝÅÎÉÊ Ó subject É Á×ÔÏÒÏÍ: + <<#L#>-index@<#H#>> + + +HÏÍÅÒÁ ÓÏÏÂÝÅÎÉÊ: + + + +óÉÓÔÅÍÏÊ ÓÏÈÒÁÎÅÎÙ ÓÐÉÓÏË ÄÁÊÄÖÅÓÔÏ× <#L#>, ËÏÔÏÒÙÅ ÎÅ ÄÏÛÌÉ ÄÏ ×ÁÛÅÇÏ +ÁÄÒÅÓÁ (Ô.Å. ÎÁ ÎÉÈ ÂÙÌÉ ÐÏÌÕÞÅÎÙ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ). óÁÍÉ ÄÁÊÄÖÅÓÔÙ +ÎÅ ÈÒÁÎÑÔÓÑ, ÎÏ ÉÚ×ÅÓÔÎÙ ÎÏÍÅÒÁ ÐÉÓÅÍ × ÄÁÊÄÖÅÓÔÁÈ. ôÁËÉÍ ÏÂÒÁÚÏÍ +ÍÏÖÎÏ ÚÁÐÒÏÓÉÔØ ÐÒÏÐÕÝÅÎÎÙÅ ÐÉÓØÍÁ ÉÚ ÁÒÈÉ×Á. + + +þÔÏÂÙ ÐÏÌÕÞÉÔØ ÐÉÓØÍÏ 12345 ÉÚ ÁÒÈÉ×Á, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + <<#L#>-get.12345@<#H#>> + + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÏÏÂÝÅÎÉÊ 123-145 (max 100 ÎÁ ÚÁÐÒÏÓ): + <<#L#>-get.123_145@<#H#>> + +áÄÒÅÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÐÏÓÌÅÄÎÉÈ 100 ÓÏÏÂÝÅÎÉÊ Ó subject É Á×ÔÏÒÏÍ: + <<#L#>-index@<#H#>> + + +ðÏÓÌÅÄÎÉÅ ÎÏÍÅÒÁ ÐÉÓÅÍ × ÄÁÊÄÖÅÓÔÁÈ: + + + +óÏÏÂÝÅÎÉÑ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÎÁ ×ÁÛ ÁÄÒÅÓ +ÐÒÉ×ÏÄÑÔ Ë ÏÛÉÂËÁÍ ÄÏÓÔÁ×ËÉ (bounce). ÷ÁÍ ÂÙÌÏ ÐÏÓÌÁÎÏ ÐÉÓØÍÏ Ó +ÐÒÅÄÕÐÒÅÖÄÅÎÉÅÍ, ÎÏ ÏÎÏ ÔÏÖÅ ÎÅ ÂÙÌÏ ÄÏÓÔÁ×ÌÅÎÏ. ÷ ËÏÎÃÅ ÐÉÓØÍÁ +ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ. + +üÔÏ ÐÉÓØÍÏ Ñ×ÌÑÅÔÓÑ ÔÅÓÔÏÍ ÎÁ ÓÕÝÅÓÔ×Ï×ÁÎÉÅ É ÁËÔÉ×ÎÏÓÔØ ×ÁÛÅÇÏ +ÁÄÒÅÓÁ. åÓÌÉ ÐÏÐÙÔËÁ ÄÏÓÔÁ×ÉÔØ ×ÁÍ ÜÔÏ ÐÉÓØÍÏ ÔÁË ÖÅ ÂÕÄÅÔ ÎÅÕÄÁÞÎÁ, +×ÁÛ ÁÄÒÅÓ ÂÕÄÅÔ ÕÄÁÌÅÎ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÂÅÚ ÄÁÌØÛÅÊÛÉÈ +ÐÒÅÄÕÐÒÅÖÄÅÎÉÊ. ðÏÄÐÉÓÁÔØÓÑ ÚÁÎÏ×Ï ÍÏÖÎÏ ÐÏ ÁÄÒÅÓÕ: + <<#l#>-subscribe@<#H#>> + + + +óÏÏÂÝÅÎÉÑ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#> ÎÁ ×ÁÛ ÁÄÒÅÓ +ÐÒÉ×ÏÄÑÔ Ë ÏÛÉÂËÁÍ ÄÏÓÔÁ×ËÉ (bounce). ÷ ËÏÎÃÅ ÐÉÓØÍÁ ÐÒÉ×ÅÄÅÎÁ ËÏÐÉÑ +ÓÏÏÂÝÅÎÉÑ Ï ÏÛÉÂËÅ. + +åÓÌÉ ÜÔÏ ÐÉÓØÍÏ ÔÁË ÖÅ ÐÒÉ×ÅÄÅÔ Ë ÏÛÉÂËÅ, ×ÁÍ ÂÕÄÅÔ ×ÙÓÌÁÎ ÔÅÓÔ. åÓÌÉ +ÔÅÓÔ ÔÏÖÅ ÐÒÉ×ÅÄÅÔ Ë ÏÛÉÂËÅ, ×ÁÛ ÁÄÒÅÓ ÂÕÄÅÔ ÕÄÁÌÅÎ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ +<#l#>@<#H#> ÂÅÚ ÄÁÌØÎÅÊÛÉÈ ÐÒÅÄÕÐÒÅÖÄÅÎÉÊ. + + +áÄÒÅÓ ÄÌÑ ÐÏÄÐÉÓËÉ ÎÁ ÄÁÊÄÖÅÓÔ: + <#L#>-digest-subscribe@<#H#> + +áÄÒÅÓ ÄÌÑ ÏÔÐÉÓËÉ ÏÔ ÄÁÊÄÖÅÓÔÁ: + <#L#>-digest-unsubscribe@<#H#> + +áÄÒÅÓ ÄÌÑ ÏÔÐÒÁ×ËÉ ÐÉÓÅÍ × ÓÐÉÓÏË ÒÁÓÓÙÌËÉ: + <#L#>@<#H#> + + +éÚ×ÉÎÉÔÅ, ÎÏ ÔÁËÏÇÏ ÐÉÓØÍÁ × ÁÒÈÉ×Å ÎÅÔ. + + +üÔÏ ÐÉÓØÍÏ Ñ×ÌÑÅÔÓÑ ÏÂÝÉÍ ÏÐÉÓÁÎÉÅÍ ÒÁÂÏÔÙ ezmlm. + + +óÐÁÓÉÂÏ, ÞÔÏ ×Ù ÓÏÇÌÁÓÉÌÉÓØ ÍÏÄÅÒÉÒÏ×ÁÔØ <#L#>@<#H#>. + +ëÏÍÁÎÄÙ ezmlm ÎÅÍÎÏÇÏ ÏÔÌÉÞÁÀÔÓÑ ÏÔ ÄÒÕÇÉÈ ÓÉÓÔÅÍ ÓÐÉÓËÏ× +ÒÁÓÓÙÌËÉ ËÁË majordomo, listserver, etc, ÎÏ ÏÎÉ ÌÅÇËÏ +ÚÁÐÏÍÉÎÁÀÔÓÑ É ÉÈ ÌÅÇËÏ ÉÓÐÏÌØÚÏ×ÁÔØ. + +HÉÖÅ ÐÒÉ×ÅÄÅÎÙ ÉÎÓÔÕËÃÉÉ ÐÏ ×ÙÐÏÌÎÅÎÉÀ ÚÁÄÁÞ, ÎÅÏÂÈÏÄÉÍÙÈ +×ÌÁÄÅÌØÃÕ ÓÐÉÓËÁ É/ÉÌÉ ÍÏÄÅÒÁÔÏÒÕ. + +õÄÁÌÅÎÎÁÑ ÐÏÄÐÉÓËÁ +------------------ +ëÁË ÍÏÄÅÒÁÔÏÒ, ×Ù ÍÏÖÅÔÅ ÐÏÄÐÉÓÁÔØ ÉÌÉ ÏÔÐÉÓÁÔØ ÌÀÂÏÊ ÁÄÒÅÓ +× ÓÐÉÓËÅ. äÌÑ ÐÏÄÐÉÓËÉ ÁÄÒÅÓÁ john@host.domain ÄÏÂÁ×ØÔÅ +ÐÅÒÅÎÏÓ ÐÏÓÌÅ ËÏÍÁÎÄÙ, ÐÏÔÏÍ ÁÄÒÅÓ Ó = ×ÍÅÓÔÏ @. HÁÐÒÉÍÅÒ, +ÄÌÑ ÐÏÄÐÉÓËÉ ×ÙÛÅÕËÁÚÁÎÎÏÇÏ ÁÄÒÅÓÁ, ÓÌÅÄÕÅÔ ÐÏÓÌÁÔØ ÐÉÓØÍÏ +ÐÏ ÁÄÒÅÓÕ + <<#L#>-subscribe-john=host.domain@<#H#>> + +ôÏÞÎÏ ÔÁË ÖÅ ÍÏÖÎÏ ÕÄÁÌÉÔØ ÁÄÒÅÓ ÉÚ ÓÐÉÓËÁ: + <<#L#>-unsubscribe-john=host.domain@<#H#>> + + +ôÏ ÖÅ ÓÁÍÏÅ ÄÌÑ ÄÁÊÄÖÅÓÔÏ×: + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +÷ÏÔ É ×ÓÅ. HÅ ÔÒÅÂÕÅÔÓÑ ÎÉÞÅÇÏ ÚÁÐÏÌÎÑÔØ ÎÉ × subject, ÎÉ × ÔÅÌÅ ÐÉÓØÍÁ. + + +÷ÁÍ ÂÕÄÅÔ ×ÙÓÌÁÎ ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÌÉ ×Ù ÈÏÔÅÌÉ +×ÙÐÏÌÎÉÔØ ÐÏÄÐÉÓËÕ/ÏÔÐÉÓËÕ. HÁÄÏ ÐÒÏÓÔÏ ÏÔ×ÅÔÉÔØ ÎÁ ÎÅÇÏ. + +âÕÄÅÔ ×ÙÓÌÁÎ ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÐÏÄÐÉÓËÉ ÐÏ ÁÄÒÅÓÕ . +ðÏÌØÚÏ×ÁÔÅÌÀ ÄÏÓÔÁÔÏÞÎÏ ÂÕÄÅÔ ÏÔ×ÅÔÉÔØ ÎÁ ÚÁÐÒÏÓ. + + +óÉÓÔÅÍÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÁÂÓÏÌÀÔÎÁ ÎÅÏÂÈÏÄÉÍÁ, ÞÔÏÂÙ ÎÅ ÄÁÔØ ÎÅÄÏÂÒÏÖÅÌÁÔÅÌÀ +×ÏÚÍÏÖÎÏÓÔÉ ÄÏÂÁ×ÉÔØ ÉÌÉ ÕÄÁÌÉÔØ ÁÄÒÅÓ × ÓÐÉÓËÅ ÂÅÚ ÖÅÌÁÎÉÑ ×ÌÁÄÅÌØÃÁ +ÁÄÒÅÓÁ. + +ðÏÄÐÉÓËÁ +-------- + +ìÀÂÏÊ ÐÏÌØÚÏ×ÁÔÅÌØ ÍÏÖÅÔ ÐÏÄÐÉÓÁÔØÓÑ ÉÌÉ ÏÔÐÉÓÁÔØÓÑ, +ÐÏÓÌÁ× ÐÉÓØÍÏ ÎÁ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ÁÄÒÅÓ: + +<#L#>-subscribe@<#H#> +<#L#>-unsubscribe@<#H#> + + +äÌÑ ÄÁÊÄÖÅÓÔÏ×: + +<#L#>-digest-subscribe@<#H#> +<#L#>-digest-unsubscribe@<#H#> + + +ðÏÌØÚÏ×ÁÔÅÌØ ÐÏÌÕÞÉÔ ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÞÔÏÂÙ ÕÂÅÄÉÔØÓÑ +× ÔÏÍ, ÞÔÏ ÚÁÐÒÏÓ ÂÙÌ ÓÄÅÌÁÎ ÉÍÅÎÎÏ ÉÍ. + + +ðÏÓËÏÌØËÕ × ÄÁÎÎÏÍ ÓÐÉÓËÅ ËÏÎÔÒÏÌÉÒÕÅÔÓÑ ÐÏÄÐÉÓËÁ/ÏÔÐÉÓËÁ, +ÂÕÄÅÔ ×ÙÓÌÁÎ ÄÏÐÏÌÎÉÔÅÌØÎÙÊ ÚÁÐÒÏÓ ÍÏÄÅÒÁÔÏÒÕ. ðÏÓËÏÌØËÕ +ÐÏÌØÚÏ×ÁÔÅÌØ ÕÖÅ ÐÏÄÔ×ÅÒÄÉÌ Ó×ÏÅ ÖÅÌÁÎÉÅ, ×Ù, ËÁË ÍÏÄÅÒÁÔÏÒ, +ÍÏÖÅÔÅ ÂÙÔØ Õ×ÅÒÅÎÙ, ÞÔÏ ÜÔÏ ÉÍÅÎÎÏ ÅÇÏ ÖÅÌÁÎÉÅ, Á ÁÄÒÅÓ +ÒÁÂÏÔÁÀÝÉÊ. åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ Ó ÐÏÄÐÉÓËÏÊ ÄÁÎÎÏÇÏ ÐÏÌØÚÏ×ÁÔÅÌÑ, +ÐÒÏÓÔÏ ÐÏÛÌÉÔÅ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ. åÓÌÉ ÎÅÔ, ÔÏ ÓÏÔÒÉÔÅ +ÅÇÏ É ×ÓÅ. + + +ïÔÐÉÓËÁ ÒÁÂÏÔÁÅÔ ÔÁËÉÍ ÖÅ ÏÂÒÁÚÏÍ. + + +ðÏÌØÚÏ×ÁÔÅÌØ ÔÁË ÖÅ ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÁÄÒÅÓÁ: + + <<#L#>-subscribe-mary=host.domain@<#H#>> + <<#L#>-unsubscribe-mary=host.domain@<#H#>> + +ÄÌÑ ÐÏÄÐÉÓËÉ mary@host.domain. óÐÉÓÏË ÂÕÄÅÔ ÉÚÍÅÎÅÎ ÔÏÌØËÏ ÅÓÌÉ +ËÔÏ-ÔÏ ÎÁ ÜÔÏÍ ÁÄÒÅÓÅ ÏÔ×ÅÔÉÔ ÎÁ ÚÁÐÒÏÓ. + +÷ÁÛ ÁÄÒÅÓ É ÐÒÏÞÁÑ ÉÎÆÏÒÍÁÃÉÑ ÎÅ ÂÕÄÕÔ ÄÏÓÔÕÐÎÙ ÐÏÄÐÉÓÞÉËÕ, ÒÁÚ×Å +ÞÔÏ ×Ù ÐÏÛÌÅÔÅ ÏÔÄÅÌØÎÏÅ ÐÉÓØÍÏ ÅÍÕ ÎÁÐÒÑÍÕÀ. + + +þÔÏÂÙ ÐÏÌÕÞÉÔØ ÓÐÉÓÏË ÐÏÄÐÉÓÞÉËÏ× <#L#>@<#H#>, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÓÀÄÁ: + <<#L#>-list@<#H#>> + +þÔÏÂÙ ÐÏÌÕÞÉÔØ ÌÏÇ ÔÒÁÎÚÁËÃÉÊ <#L#>@<#H#>, ÐÉÛÉÔÅ ÓÀÄÁ: + <<#L#>-log@<#H#>> + + +äÌÑ ÄÁÊÄÖÅÓÔÏ×: + <<#L#>-digest-list@<#H#>> +É: + <<#L#>-digest-log@<#H#>> + + +÷Ù ÍÏÖÅÔÅ ÒÅÄÁËÔÉÒÏ×ÁÔØ ÐÏ ÐÏÞÔÅ ÔÅËÓÔÏ×ÙÅ ÆÁÊÌÙ ËÏÎÆÉÇÕÒÁÃÉÉ +ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ. äÌÑ ÐÏÌÕÞÅÎÉÑ ÓÐÉÓËÁ ÆÁÊÌÏ× É ÉÎÓÔÒÕËÃÉÊ ÐÏ +ÒÅÄÁËÔÉÒÏ×ÁÎÉÀ, ÐÉÛÉÔÅ ÓÀÄÁ: + <<#L#>-edit@<#H#>> + + +íÏÄÅÒÉÒÏ×ÁÎÉÅ +------------- +ëÏÇÄÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ ÍÏÄÅÒÉÒÕÅÔÓÑ, ÐÉÓØÍÁ ÓÏÈÒÁÎÑÀÔÓÑ É ×ÓÅÍ +ÍÏÄÅÒÁÔÏÒÁÍ ÐÏÓÙÌÁÅÔÓÑ ËÏÐÉÑ ÐÉÓØÍÁ Ó ÉÎÓÔÒÕËÃÉÅÊ. Subject ÓÏÄÅÒÖÉÔ +ÓÔÒÏËÕ "MODERATE for ...". + +ðÉÓØÍÏ ÓÏÄÅÒÖÉÔ Ä×Á ÚÁÇÏÌÏ×ËÁ: "From:" É "Reply-To:". ôÁËÉÍ ÏÂÒÁÚÏÍ, +ËÏÇÄÁ ×Ù ÎÁ ÎÅÇÏ ÏÔ×ÅÞÁÅÔÅ, ×ÁÛÁ ÐÏÞÔÏ×ÁÑ ÐÒÏÇÒÁÍÍÁ ÄÏÌÖÎÁ ÓÐÒÏÓÉÔØ, +ÎÁ ËÁËÏÊ ÉÚ ÁÄÒÅÓÏ× ÏÔ×ÅÞÁÔØ. ïÔ×ÅÔ ÎÁ ÁÄÒÅÓ × Reply-To: ÐÒÉ×ÅÄÅÔ +Ë ÔÏÍÕ, ÞÔÏ ÉÓÈÏÄÎÏÅ ÐÉÓØÍÏ ÂÕÄÅÔ ÐÒÏÐÕÝÅÎÏ × ÓÐÉÓÏË ÒÁÓÓÙÌËÉ. +ïÔ×ÅÔ ÎÁ "From:" ÐÒÉ×ÅÄÅÔ Ë ÏÔËÁÚÕ. ïÂÙÞÎÏ ÐÒÏÇÒÁÍÍÙ ÓÐÒÁÛÉ×ÁÀÔ +"äÁ/ÎÅÔ", Ô.Å. ×Ù ÐÒÏÓÔÏ ÒÅÛÁÅÔÅ, ÐÒÏÐÕÓËÁÔØ ÉÌÉ ÎÅÔ, ÎÁÖÉÍÁÅÔÅ +ÏÔ×ÅÔ É ×ÙÂÉÒÁÅÔÅ "ÄÁ" ÉÌÉ "ÎÅÔ". óÏÄÅÒÖÉÍÏÅ ×ÁÛÅÇÏ ÐÉÓØÍÁ +ÐÒÁËÔÉÞÅÓËÉ ÉÇÎÏÒÉÒÕÅÔÓÑ -- ÚÎÁÞÅÎÉÅ ÉÍÅÀÔ ÔÏÌØËÏ ÁÄÒÅÓÁ, ÏÄÎÁËÏ +ÐÒÉ ÏÔËÁÚÅ ÍÏÖÎÏ ×ÓÔÁ×ÉÔØ × ÔÅÌÏ ÐÉÓØÍÁ ÔÅËÓÔ ÍÅÖÄÕ Ä×ÕÍÑ ÓÔÒÏËÁÍÉ, +ÎÁÞÉÎÁÀÝÉÍÉÓÑ Ó ÓÉÍ×ÏÌÏ× %. üÔÏÔ ÔÅËÓÔ ÂÕÄÅÔ ÐÏÓÌÁÎ ÏÔÐÒÁ×ÉÔÅÌÀ +ÐÉÓØÍÁ, ÎÅ ÏÔËÒÙ×ÁÑ ËÔÏ ÉÚ ÍÏÄÅÒÁÔÏÒÏ× ÅÇÏ ÐÏÓÌÁÌ. HÁÐÒÉÍÅÒ: + +%%% Start comment +×ÁÛÅ ÐÉÓØÍÏ ÓÏÄÅÒÖÉÔ ÍÁÔ +%%% End comment + +åÓÌÉ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ ÐÒÏÇÒÁÍÍÁ ÕÍÅÅÔ ÒÁÂÏÔÁÔØ Ó ÔÅÍÐÌÅÊÔÁÍÉ (ÎÁÐÒÉÍÅÒ, +The Bat!), ÔÏ ÜÔÉ ÓÔÒÏËÉ ÓÔÏÉÔ ÄÏÂÁ×ÉÔØ × ÔÅÍÐÌÅÊÔ ÏÔ×ÅÔÁ. + +úÁÐÒÏÓÙ ÎÁ ÍÏÄÅÒÉÒÏ×ÁÎÉÅ ÏÂÒÁÂÁÔÙ×ÁÀÔÓÑ ÐÏ ÐÅÒ×ÏÍÕ ÐÉÓØÍÕ ÏÔ ÍÏÄÅÒÁÔÏÒÁ, +ÓÒÅÁÇÉÒÏ×Á×ÛÅÇÏ ÒÁÎØÛÅ. åÓÌÉ ËÔÏ-ÔÏ ÉÚ ÍÏÄÅÒÁÔÏÒÏ× ÐÏÚÖÅ ÐÏÛÌÅÔ ÏÔ×ÅÔ +Ó ÐÒÏÔÉ×ÏÐÏÌÏÖÎÙÍ ÒÅÛÅÎÉÅÍ, ÅÍÕ ÂÕÄÅÔ ÓÏÏÂÝÅÎÏ Ï ÔÏÍ, ÞÔÏ ÕÖÅ ÐÒÏÉÚÏÛÌÏ +Ó ÄÁÎÎÙÍ ÐÉÓØÍÏÍ. + +åÓÌÉ × ÔÅÞÅÎÉÉ ÎÅÓËÏÌØËÉÈ ÄÎÅÊ ÎÅ ÂÕÄÅÔ ÐÏÌÕÞÅÎÏ ÏÔ×ÅÔÁ ÎÉ ÏÔ ÏÄÎÏÇÏ +ÍÏÄÅÒÁÔÏÒÁ, ÏÔÐÒÁ×ÉÔÅÌÀ ÂÕÄÅÔ ÐÏÓÌÁÎÏ Õ×ÅÄÏÍÌÅÎÉÅ Ï ÚÁÄÅÒÖËÅ. ôÁË ÖÅ, +ÁÄÍÉÎÉÓÔÒÁÔÏÒ ÓÐÉÓËÁ ÍÏÖÅÔ ÚÁÐÒÅÔÉÔØ ÏÔÓÙÌËÕ ÐÏÄÏÂÎÙÈ Õ×ÅÄÏÍÌÅÎÉÊ. + + +ëÁÎÉËÕÌÙ +-------- +åÓÌÉ ×Ù ÄÏÌÖÎÙ ÓÒÏÞÎÏ ÐÏËÉÎÕÔØ Ó×ÏÊ ÌÀÂÉÍÙÊ ÇÏÒÏÄ, Á ÔÁÍ, ËÕÄÁ +×Ù ÓÏÂÒÁÌÉÓØ, ÉÎÔÅÒÎÅÔÁ ÎÅÔ É ÎÅ ÐÒÅÄ×ÉÄÉÔÓÑ, ×Ù ÍÏÖÅÔÅ ÎÁ ×ÒÅÍÑ +×ËÌÀÞÉÔØ Á×ÔÏÍÁÔÉÞÅÓËÉÊ ÐÒÏÐÕÓË ÐÉÓÅÍ × ÓÐÉÓÏË. ïÄÎÁËÏ ×Ï ÍÎÏÇÉÈ +ÓÐÉÓËÁÈ ÐÏÄÏÂÎÙÅ ÄÅÊÓÔ×ÉÑ ÍÏÇÕÔ ÐÒÉ×ÅÓÔÉ Ë ÂÁÒÄÁËÕ. + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÐÏÓÔÁ×ÉÔØ Á×ÔÏÏÔ×ÅÔÞÉË ÎÁ ×ÁÛÅÍ ÁÄÒÅÓÅ, +ÏÔÐÒÁ×ÌÑÀÝÉÊ ×ÓÅ ÐÉÓØÍÁ Ó subject "MODERATE for .." ÎÁ ÁÄÒÅÓ × +ÚÁÇÏÌÏ×ËÅ "Reply-To:". Hå òåëïíåHäõåôóñ. + + +åÓÌÉ ×Ù ÐÏÐÒÏÂÕÅÔÅ ÐÏÓÌÁÔØ ÁÄÍÉÎÓÔÒÁÔÉ×ÎÙÊ ÚÁÐÒÏÓ ÎÅ Ó Ó×ÏÅÇÏ ÁÄÒÅÓÁ, +ÔÏ ÐÏÄÐÉÓÞÉË, Á ÎÅ ×Ù ÂÕÄÅÔ ÓÐÒÏÛÅÎ, ÐÏÄÐÉÓÙ×ÁÔØ ÉÌÉ ÎÅÔ. üÔÏ ÓÄÅÌÁÎÏ +ÄÌÑ ÔÏÇÏ, ÞÔÏÂÙ ÎÉËÔÏ ÎÅ ÐÏÓÌÁÌ ÐÏÄÄÅÌØÎÙÊ ÚÁÐÒÏÓ ÎÁ ÐÏÄÐÉÓËÕ +ÏÔ ×ÁÛÅÇÏ ÁÄÒÅÓÁ, ÐÏÄÐÉÓÁ× Ó×ÏÅÇÏ ×ÒÁÇÁ ÎÁ ×ÙÓÏËÏÔÒÁææÉËÏ×ÙÊ ÓÐÉÓÏË +ÒÁÓÓÙÌËÉ. + + + +õÄÁÞÉ! + +PS: ÷ ÓÌÕÞÁÅ ÐÒÏÂÌÅÍ Ó×ÑÚÙ×ÁÊÔÅÓØ Ó ×ÌÁÄÅÌØÃÅÍ ÓÐÉÓËÁ +ÒÁÓÓÙÌËÉ (<#L#>-owner@<#H#>). + + +éÚ×ÉÎÉÔÅ, ÎÏ ×ÁÛÅ ÐÉÓØÍÏ (ÎÉÖÅ ÐÒÉ×ÅÄÅÎÎÏÅ) ÎÅ ÂÙÌÏ ÐÒÏÐÕÝÅÎÏ × +ÓÐÉÓÏË ÍÏÄÅÒÁÔÏÒÏÍ. åÓÌÉ ÍÏÄÅÒÁÔÏÒ ÈÏÔÅÌ(Á) ÓÏÏÂÝÉÔØ ÞÔÏ-ÌÉÂÏ ×ÁÍ +ÐÏ ÐÏ×ÏÄÕ ×ÁÛÅÇÏ ÐÉÓØÍÁ, ËÏÍÍÅÎÔÁÒÉÉ ÂÕÄÕÔ ÐÒÉ×ÅÄÅÎÙ ÎÉÖÅ. + +HÉÖÅÐÒÉ×ÅÄÅÎÎÏÅ ÐÉÓØÍÏ ÂÙÌÏ ÏÔÐÒÁ×ÌÅÎÏ × ÓÐÉÓÏË <#L#>@<#H#> +åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ ÅÇÏ ÐÒÏÐÕÓÔÉÔØ, ÐÏÛÌÉÔÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!A + +ïÂÙÞÎÏ ÄÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ" ÄÌÑ +ÄÁÎÎÏÇÏ ÐÉÓØÍÁ. ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ, ÞÔÏÂÙ × ÐÏÌÅ "To:" ÂÙÌ ÔÏÌØËÏ +ÏÄÉÎ ÁÄÒÅÓ. åÓÌÉ ÜÔÏ ÎÅ ÓÒÁÂÏÔÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÁÄÒÅÓ × clipboard É +×ÓÔÁ×ØÔÅ ÅÇÏ × ÐÏÌÅ "To:". + + + +äÌÑ ÏÔËÁÚÁ ÏÔ ÐÒÏÐÕÓËÁ ÐÉÓØÍÁ É ÓÏÏÂÝÅÎÉÑ Ï ÜÔÏÍ ÐÉÛÕÝÅÍÕ ÐÏÛÌÉÔÅ +ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ + +!R + + + +÷ÁÍ ÎÅ ÎÕÖÎÏ ËÏÐÉÒÏ×ÁÔØ ÔÅÌÏ ÉÓÈÏÄÎÏÇÏ ÐÉÓØÍÁ. äÌÑ ÔÏÇÏ, ÞÔÏÂÙ ÐÏÓÌÁÔØ +×ÁÛ ËÏÍÍÅÎÔÁÒÉÊ ÐÏ ÐÏ×ÏÄÕ ÔÏÇÏ, ÐÏÞÅÍÕ ÐÉÓØÍÏ ÎÅ ÂÙÌÏ ÐÒÏÐÕÝÅÎÏ, +×ÓÔÁ×ØÔÅ ×ÁÛ ÔÅËÓÔ ÍÅÖÄÕ Ä×ÕÍÑ ÓÔÒÏËÁÍÉ Ó %%%. + +%%% Start comment +%%% End comment + +ëÏÍÍÅÎÔÁÒÉÉ ÄÏÌÖÎÙ ÎÁÞÉÎÁÔØÓÑ Ó ÎÁÞÁÌÁ ÓÔÒÏËÉ. + +--- éÓÈÏÄÎÏÅ ÐÉÓØÍÏ × ÓÐÉÓÏË. + + +--- ÷ÁÓ ÐÏÄÐÉÓÁÌÉ ÉÌÉ ÏÔÐÉÓÁÌÉ ÐÏ ÚÁÐÒÏÓÕ ÍÏÄÅÒÁÔÏÒÁ +ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>. + +åÓÌÉ ×Ù ÜÔÏÇÏ ÎÅ ÈÏÔÅÌÉ, ×Ù ÍÏÖÅÔÅ ÎÁÐÉÓÁÔØ ÖÁÌÏÂÕ +×ÌÁÄÅÌØÃÕ ÓÐÉÓËÁ ÐÏ ÁÄÒÅÓÕ <#l#>-owner@<#H#>. + +åÓÌÉ ×ÁÓ ÉÎÔÅÒÅÓÕÅÔ ÉÎÆÏÒÍÁÃÉÑ Ï ÓÐÉÓËÅ ÒÁÓÓÙÌËÉ <#L#>, +ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ <#l#>-help@<#H#>. + + +éÚ×ÉÎÉÔÅ, ÎÏ ÍÏÄÅÒÁÔÏÒ(Ù) ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#L#>@<#H#> +ÎÅ ÐÒÅÄÐÒÉÎÉÍÁÀÔ ÄÅÊÓÔ×ÉÊ ÄÌÑ ÐÒÏÐÕÓËÁ ÉÌÉ ÏÔËÁÚÁ ÐÏ ÐÏ×ÏÄÕ +×ÁÛÅÇÏ ÐÉÓØÍÁ × ÓÐÉÓÏË. + +--- éÓÈÏÄÎÏÅ ÐÉÓØÍÏ. + + +üÔÏ ÚÁÐÒÏÓ ×ÁÛÅÇÏ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÄÏÂÁ×ÌÅÎÉÅ ÁÄÒÅÓÁ + +!A + +× ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>. +úÁÐÒÏÓ ÐÒÏÉÚÏÛÅÌ ÐÏÔÏÍÕ, ÞÔÏ ×Ù (ÉÌÉ ÎÅ ×Ù) ÐÏÐÙÔÁÌÉÓØ +ÐÏÄÐÉÓÁÔØ ×ÁÛ ÁÄÒÅÓ ÎÁ ×ÙÛÅÕÐÏÍÑÎÕÔÙÊ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ. + +äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÐÏÄÐÉÓËÉ, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ". +åÓÌÉ ÜÔÏ ÎÅ ÓÒÁÂÏÔÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÁÄÒÅÓ × clipboard É +×ÓÔÁ×ØÔÅ ÅÇÏ × ÐÏÌÅ "To:". + + + +åÓÌÉ ×Ù ÎÅ ÈÏÔÉÔÅ ÐÏÄÐÉÓÙ×ÁÔØÓÑ, ÐÒÏÓÔÏ ÎÅ ÏÔ×ÅÞÁÊÔÅ ÎÁ ÜÔÏ ÐÉÓØÍÏ. + + +úÁÐÒÏÓ ÎÁ ÒÁÚÒÅÛÅÎÉÅ ÕÄÁÌÅÎÉÑ + +!A + +ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>. åÓÌÉ ×Ù ÓÏÇÌÁÓÎÙ, +ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ". +åÓÌÉ ÜÔÏ ÎÅ ÐÏÍÏÇÁÅÔ, ÓËÏÐÉÒÕÊÔÅ ÔÅËÓÔ É ×ÓÔÁ×ØÔÅ ÅÇÏ × +ÐÏÌÅ "To:" ÎÏ×ÏÇÏ ÐÉÓØÍÁ. + + + +åÓÌÉ ×Ù ÎÅ ÓÏÇÌÁÓÎÙ, ÉÇÎÏÒÉÒÕÊÔÅ ÜÔÏ ÐÉÓØÍÏ. + + +ïÊ. ëÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÎÅËÏÒÒÅËÔÅÎ. + +óËÏÒÅÅ ×ÓÅÇÏ ÐÒÏÛÌÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅ ÐÏÌÕÞÅÎÉÑ ×ÁÍÉ +ÚÁÐÒÏÓÁ. íÁËÓÉÍÕÍ 10 ÄÎÅÊ. ôÁË ÖÅ ×ÏÚÍÏÖÎÏ, ÞÔÏ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ +ÐÒÏÇÒÁÍÍÁ ÓßÅÌÁ ÞÁÓÔØ ÁÄÒÅÓÁ, ËÏÔÏÒÙÊ É ÓÏÄÅÒÖÉÔ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. + +äÌÑ ×ÁÓ ÓÏÚÄÁÎ ÎÏ×ÙÊ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. þÔÏÂÙ ÏÄÏÂÒÉÔØ ÐÏÄÐÉÓËÕ + +!A + +ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ +ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + + + +ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ ×Ù ÐÏÓÙÌÁÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ. + + +äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÐÏÄÐÉÓËÉ ÁÄÒÅÓÁ + +!A + +ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ". + + + +üÔÏ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÎÅÏÂÈÏÄÉÍÏ ÐÏ Ä×ÕÍ ÐÒÉÞÉÎÁÍ. ÷Ï-ÐÅÒ×ÙÈ, ÐÒÏ×ÅÒÑÅÔÓÑ, +ÄÏÈÏÄÉÔ ÌÉ ÐÏÞÔÁ ÄÏ ×ÁÛÅÇÏ ÁÄÒÅÓÁ. ÷Ï-×ÔÏÒÙÈ, ÜÔÏ ÚÁÝÉÝÁÅÔ ×ÁÓ ÏÔ +ÐÏÄÐÉÓËÉ, ÅÓÌÉ ËÔÏ-ÔÏ ÐÏÛÌÅÔ ÐÉÓØÍÏ Ó ÐÏÄÄÅÌÁÎÎÙÍ ×ÁÛÉÍ ÉÓÈÏÄÎÙÍ ÁÄÒÅÓÏÍ. + + +HÅËÏÔÏÒÙÅ ÓÔÁÒÙÅ ÐÏÞÔÏ×ÙÅ ÐÒÏÇÒÁÍÍÙ ÎÅ ÍÏÇÕÔ ÓÐÒÁ×ÉÔÓÑ Ó ÄÌÉÎÎÙÍÉ +ÁÄÒÅÓÁÍÉ. åÓÌÉ ×Ù ÎÅ ÍÏÖÅÔÅ ÐÏÓÌÁÔØ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ, ÐÏÛÌÉÔÅ +ÏÔ×ÅÔ ÎÁ <<#L#>-request@<#H#>> É ×ÓÔÁ×ØÔÅ +×ÅÓØ ÁÄÒÅÓ × ÐÏÌÅ subject. + + +üÔÏÔ ÓÐÉÓÏË ÍÏÄÅÒÉÒÕÅÍÙÊ. ëÏÇÄÁ ×Ù ÐÏÛÌÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ, ÍÏÄÅÒÁÔÏÒ(Ù) +ÂÕÄÕÔ ÉÚ×ÅÝÅÎÙ Ï ÜÔÏÍ. ÷ ÓÌÕÞÁÅ ÏÄÏÂÒÅÎÉÑ ×ÁÛÅÊ ÐÏÄÐÉÓËÉ ÍÏÄÅÒÁÔÏÒÁÍ +×ÁÍ ÂÕÄÅÔ ÓÏÏÂÝÅÎÏ. + + +ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ + +!A + +ÕÖÅ ÐÏÄÐÉÓÁÎ ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>. + + +ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ + +!A + +ÐÏÄÐÉÓÁÎ ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>. + +äÏÂÒÏ ÐÏÖÁÌÏ×ÁÔØ! + +ðÏÖÁÌÕÊÓÔÁ, ÓÏÈÒÁÎÉÔÅ ÜÔÏ ÐÉÓØÍÏ, ÞÔÏÂÙ ÎÅ ÚÁÂÙÔØ ÁÄÒÅÓ, ËÏÔÏÒÙÊ +×Ù ÐÏÄÐÉÓÁÌÉ ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ. þÅÒÅÚ ÐÏÌÇÏÄÁ ×Ù ÅÇÏ ÏÂÑÚÁÔÅÌØÎÏ +ÚÁÂÕÄÅÔÅ, Á ÏÔËÁÚÁÔØÓÑ ÏÔ ÐÏÄÐÉÓËÉ, ÎÅ ÚÎÁÑ ÉÓÈÏÄÎÙÊ ÁÄÒÅÓ, ÂÕÄÅÔ +ÏÞÅÎØ ÔÒÕÄÎÏ. + + +äÏÂÒÙÊ ÄÅÎØ/ÕÔÒÏ/×ÅÞÅÒ! üÔÏ ÓÏÏÂÝÅÎÉÅ ÏÔ ÐÒÏÇÒÁÍÍÙ ezmlm, +ÚÁ×ÅÄÕÀÝÅÊ ÓÐÉÓËÏÍ ÒÁÓÓÙÌËÉ <#l#>@<#H#>. + + +ó×ÑÚÁÔØÓÑ Ó ×ÌÁÄÅÌØÃÅÍ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ ÍÏÖÎÏ ÐÏ ÁÄÒÅÓÕ +<#l#>-owner@<#H#>. + + +ïÊ. ëÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ ÎÅËÏÒÒÅËÔÅÎ. + +óËÏÒÅÅ ×ÓÅÇÏ ÐÒÏÛÌÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ×ÒÅÍÅÎÉ ÐÏÓÌÅ ÐÏÌÕÞÅÎÉÑ ×ÁÍÉ +ÚÁÐÒÏÓÁ. íÁËÓÉÍÕÍ 10 ÄÎÅÊ. ôÁË ÖÅ ×ÏÚÍÏÖÎÏ, ÞÔÏ ×ÁÛÁ ÐÏÞÔÏ×ÁÑ +ÐÒÏÇÒÁÍÍÁ ÓßÅÌÁ ÞÁÓÔØ ÁÄÒÅÓÁ, ËÏÔÏÒÙÊ É ÓÏÄÅÒÖÉÔ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. + +äÌÑ ×ÁÓ ÓÏÚÄÁÎ ÎÏ×ÙÊ ËÏÄ ÐÏÄÔ×ÅÒÖÄÅÎÉÑ. þÔÏÂÙ ÏÄÏÂÒÉÔØ ÕÄÁÌÅÎÉÅ +ÁÄÒÅÓÁ + +!A + +ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + + + +ïÂÑÚÁÔÅÌØÎÏ ÐÒÏ×ÅÒØÔÅ ÁÄÒÅÓ, ÎÁ ËÏÔÏÒÙÊ ×Ù ÐÏÓÙÌÁÅÔÅ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ. + + +äÌÑ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÕÄÁÌÅÎÉÑ ÁÄÒÅÓÁ + +!A + +ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>, ÐÏÛÌÉÔÅ ÐÕÓÔÏÅ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ: + +!R + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ". + + + +÷ÎÉÍÁÎÉÅ! þÔÏÂÙ ÕÚÎÁÔØ, ÐÏÄ ËÁËÉÍ ÁÄÒÅÓÏÍ ×Ù ÐÏÄÐÉÓÁÎÙ ÎÁ ÓÐÉÓÏË +ÒÁÓÓÙÌËÉ, ÚÁÇÌÑÎÉÔÅ × ÚÁÇÏÌÏ×ËÉ ÏÄÎÏÇÏ ÉÚ ÐÉÓÅÍ ÉÚ ÓÐÉÓËÁ. ÷ +ËÁÖÄÏÍ ÐÉÓØÍÅ ÅÓÔØ ÚÁÇÏÌÏ×ÏË "Return-Path:", ×ÎÕÔÒÉ ËÏÔÏÒÇÏ +ÎÁÈÏÄÉÔÓÑ ÁÄÒÅÓ ÐÏÌÕÞÁÔÅÌÑ. HÁÐÒÉÍÅÒ, ÐÒÉ ÁÄÒÅÓÅ vassily.pupkin@usa.net +ÚÁÇÏÌÏ×ÏË ÂÕÄÅÔ ×ÙÇÌÑÄÅÔØ ÔÁË: +Return-Path: <<#l#>-return-<ÞÉÓÌÏ>-vassily.pupkin=usa.net@<#H#> + + +HÅËÏÔÏÒÙÅ ÓÔÁÒÙÅ ÐÏÞÔÏ×ÙÅ ÐÒÏÇÒÁÍÍÙ ÎÅ ÍÏÇÕÔ ÓÐÒÁ×ÌÑÔØÓÑ Ó ÄÌÉÎÎÙÍÉ +ÁÄÒÅÓÁÍÉ. åÓÌÉ ×Ù ÎÅ ÍÏÖÅÔÅ ÐÏÓÌÁÔØ ÏÔ×ÅÔ ÎÁ ÄÁÎÎÏÅ ÐÉÓØÍÏ, ÐÏÛÌÉÔÅ +ÏÔ×ÅÔ ÎÁ <<#L#>-request@<#H#>> É ×ÓÔÁ×ØÔÅ +×ÅÓØ ÁÄÒÅÓ × ÐÏÌÅ subject. + + +÷ÎÉÍÁÎÉÅ: ÁÄÒÅÓ + +!A + +ÎÅ ÐÏÄÐÉÓÁÎ ÎÁ ÓÐÉÓÏË ÒÁÓÓÙÌËÉ <#l#>@<#H#>! + +åÓÌÉ ×Ù ÏÔÐÉÓÙ×ÁÅÔÅÓØ ÏÔ ÓÐÉÓËÁ, ÎÏ ÐÒÏÄÏÌÖÁÅÔÅ ÐÏÌÕÞÁÔØ ÓÏÏÂÝÅÎÉÑ, +ÚÎÁÞÉÔ ×Ù ÐÏÄÐÉÓÁÎÙ ÐÏÄ ÄÒÕÇÉÍ ÁÄÒÅÓÏÍ. HÁÊÄÉÔÅ ÚÁÇÏÌÏ×ÏË ×ÉÄÁ + +'Return-Path: <<#l#>-return-1234-user=host.dom@<#H#>>' + +× ÏÄÎÏÍ ÉÚ ÔÁËÉÈ ÐÉÓÅÍ. äÌÑ ÏÔÐÉÓËÉ ÎÁÄÏ ÂÕÄÅÔ ÐÏÓÌÁÔØ ÐÉÓØÍÏ ÐÏ ÁÄÒÅÓÕ +'<#l#>-unsubscribe-user=host.dom@<#H#>'. ðÒÏÓÔÏ ÓÆÏÒÍÉÒÕÊÔÅ ÔÁËÏÊ +ÁÄÒÅÓ, ÚÁÍÅÎÉ× user=host.dom ÎÁ ×ÁÛÉ ÒÅÁÌØÎÙÅ ÄÁÎÎÙÅ (ÐÏÄÓÔÁ×É× ÓÉÍ×ÏÌ += ×ÍÅÓÔÏ @) É ÏÔ×ÅÔØÔÅ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ. + + +ðÏÄÔ×ÅÒÖÄÅÎÉÅ: ÁÄÒÅÓ + +!A + +ÕÄÁÌÅÎ ÉÚ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ <#l#>@<#H#>. + + +ðÏÖÁÌÕÊÓÔÁ, ÏÔÒÅÄÁËÔÉÒÕÊÔÅ ÎÉÖÅÐÒÉ×ÅÄÅÎÎÙÊ ÆÁÊÌ É ÏÔÐÒÁ×ØÔÅ ÅÇÏ +ÐÏ ÁÄÒÅÓÕ: + +!R + +äÌÑ ÜÔÏÇÏ ÄÏÓÔÁÔÏÞÎÏ ÎÁÖÁÔØ ËÎÏÐËÕ "reply" ÉÌÉ "ÏÔ×ÅÔ". + +óÉÍ×ÏÌÙ Ë×ÏÔÉÎÇÁ ÂÕÄÕÔ ÕÄÁÌÅÎÙ ÉÚ ÐÉÓØÍÁ Á×ÔÏÍÁÔÉÞÅÓËÉ, ÅÓÌÉ +×Ù ÎÅ ÂÕÄÅÔÅ ÔÒÏÇÁÔØ ÓÔÒÏËÉ Ó ÍÁÒËÅÒÁÍÉ. íÁÒËÅÒÙ -- ÓÔÒÏËÉ, +ÎÁÞÉÎÁÀÝÉÅÓÑ Ó %%%. + + +áÄÒÅÓ <#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 ×ÅÒÈÎÑÑ ÞÁÓÔØ ×ÓÅÈ ÏÔ×ÅÔÏ×. + +trailer ÔÅËÓÔ, ÄÏÂÁ×ÌÑÅÍÙÊ × ËÏÎÅà ËÁÖÄÏÇÏ ÐÉÓØÍÁ × ÓÐÉÓÏË. + +unsub_bad ÐÏÄÐÉÓÞÉËÕ ÐÒÉ ÎÅÕÄÁÞÎÏÊ ÏÔÐÉÓËÅ. +unsub_confirm ÚÁÐÒÏÓ ÎÁ ÐÏÄÔ×ÅÒÖÄÅÎÉÅ ÏÔÐÉÓËÉ ÐÏÌØÚÏ×ÁÔÅÌÀ. +unsub_nop ÎÅ-ÐÏÄÐÉÓÞÉËÕ Ï ÔÏÍ, ÞÔÏ ÅÇÏ ÁÄÒÅÓÁ × ÓÐÉÓËÅ ÎÅÔ. +unsub_ok ÐÒÉ ÕÓÐÅÛÎÏÊ ÏÔÐÉÓËÅ. + + +ôÅËÓÔÏ×ÙÊ ÆÁÊÌ ÂÙÌ ÕÓÐÅÛÎÏ ÏÂÎÏ×ÌÅÎ ÎÁ ÓÅÒ×ÅÒÅ. + +ðÎÉÔÅ ÁÄÍÉÎÉÓÔÒÁÔÏÒÁ ÓÐÉÓËÁ ÒÁÓÓÙÌËÉ, ÐÕÓÔÏ ÔÕÔ. + +FAQ, ÉÌÉ þÁ÷ï -- þÁÓÔÏ ÚÁÄÁ×ÁÅÍÙÅ ÷ÏÐÒÏÓÙ É ïÔ×ÅÔÙ. + +úÄÅÓØ ÐÏËÁ ÐÕÓÔÏ. íÏÖÅÔ ËÔÏ-ÎÉÂÕÄØ ÎÁÐÉÛÅÔ? + diff --git a/ezmlmrc.sv b/ezmlmrc.sv new file mode 100644 index 0000000..4f6c6b5 --- /dev/null +++ b/ezmlmrc.sv @@ -0,0 +1,1174 @@ +0.40 - This version identifier must be on line 1 and start in pos 1. +# +#$Id: ezmlmrc.sv,v 1.23 1999/12/23 23:08:19 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# +# ezmlmrc +# ####### +# Controls the actions of ezmlm-make as patched with ezmlm-idx-0.31 or later. +# +# The base directory 'DIR' is always created by ezmlm-make, as is DIR/key. +# Everything else is done from here. +# +# ezmlm-make looks for this file, first as .ezmlmrc in the directory that the +# lists .qmail files will be placed in (if you've used the -c command line +# switch), then /etc/ezmlmrc, then ezmlmrc in the ezmlm-make binary directory. +# Thus, you can customize ezmlm-make on a global level by placing a customized +# copy of ezmlmrc in /etc and on a user level by copying it to .ezmlmrc in +# the user's home directory AND use the ezmlm-make -c switch. +# +# Tags are: +# : put succeeding text lines in DIR/filename +# : erase DIR/filename. +# : create directory DIR/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, creates the file if and only if the list is archived +# (-a) and not public (-P). If the next tag is , the file is +# extended with the lines up to the next tag if the list is message moderated +# (-m). If the next tag is , '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 + +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#> + +<#L#> + +<#0#> + + + + +# dirs for digests + + + +# for extra address db + + +# for blacklist + + +# moderator db & mod queue dirs. Needed for -m, -r -s, so we just +# make them by default. + + + + + +# links: dot -> dir/editor + + + + + + +# for message moderation only + + +# Get rid of configuration flags for editing mode so we can start with a +# clean slate. + + + + + + + + + + +# Not needed, except for message moderation. + +# We don't clean out text files to make it easier for users +# doing manual config by e.g. touching dir/remote. +# subscription moderation + +<#8#> +# remote admin + +<#9#> +# message moderation + +<#7#> +# List owner mail + +<#5#> + +<#D#>/Mailbox + +|<#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 + +|<#B#>/ezmlm-get -P '<#D#>' <#C#> + +|<#B#>/ezmlm-get '<#D#>' <#C#> + +|<#B#>/ezmlm-get -s '<#D#>' <#C#> + +|<#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: + +|<#B#>/ezmlm-manage '<#D#>' + +|<#B#>/ezmlm-manage -l '<#D#>' + +|<#B#>/ezmlm-manage -e '<#D#>' + +|<#B#>/ezmlm-manage -le '<#D#>' +# ... now no confirmation for subscribe ... + +|<#B#>/ezmlm-manage -S '<#D#>' + +|<#B#>/ezmlm-manage -lS '<#D#>' + +|<#B#>/ezmlm-manage -eS '<#D#>' + +|<#B#>/ezmlm-manage -leS '<#D#>' +# ... now no confirmation for unsubscribe ... + +|<#B#>/ezmlm-manage -U '<#D#>' + +|<#B#>/ezmlm-manage -lU '<#D#>' + +|<#B#>/ezmlm-manage -eU '<#D#>' + +|<#B#>/ezmlm-manage -leU '<#D#>' +# ... and finally no confirmation at all ... + +|<#B#>/ezmlm-manage -US '<#D#>' + +|<#B#>/ezmlm-manage -lUS '<#D#>' + +|<#B#>/ezmlm-manage -eUS '<#D#>' + +|<#B#>/ezmlm-manage -leUS '<#D#>' + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +# reject shouldn't be configured for sublist. + +# 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. + +|<#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 + +|<#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 ; } + +|<#B#>/ezmlm-gate '<#D#>' '<#D#>' '<#D#>/digest' '<#D#>/allow' '<#D#>/mod' +# For message moderation, editor has store/clean + +|<#B#>/ezmlm-store '<#D#>' + +|<#B#>/ezmlm-store -P '<#D#>' + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 +# for non-message moderated lists, it has send + +|<#B#>/ezmlm-send '<#D#>' +# ezmlm-archive here for normal lists. Put into moderator for mess-mod lists + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 +# all lists have warn unless -w. + +|<#B#>/ezmlm-warn '<#D#>' || exit 0 +# for digest bounces + +|<#B#>/ezmlm-warn -d '<#D#>' || exit 0 + +|<#B#>/ezmlm-tstdig -m30 -k64 -t48 '<#D#>' || exit 99 + +|<#B#>/ezmlm-tstdig <#4#> '<#D#>' || exit 99 + +|<#B#>/ezmlm-get '<#D#>' || exit 0 +# bouncer for list and digest + +|<#B#>/ezmlm-weed +|<#B#>/ezmlm-return -D '<#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. + +|<#B#>/ezmlm-moderate '<#D#>' + +|<#B#>/ezmlm-archive '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean '<#D#>' || exit 0 + +|<#B#>/ezmlm-clean -R '<#D#>' || exit 0 + +return-path +return-receipt-to +content-length +precedence +x-confirm-reading-to +x-pmrqc +list-subscribe +list-unsubscribe +list-help + +# For sublists, these should be left in +list-post +# remove from header if -3 'new_from_line' + +from + + + + + + + + +<#H#> + +<#H#> + +<#L#> + +kontakta <#L#>-help@<#H#>; körs med ezmlm +# Headeradd needs to always exist but leave out stuff for sublists + +# 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: @<#H#>> + +List-Help: -help@<#h#>> +List-Unsubscribe: -unsubscribe@<#h#>> +List-Subscribe: -subscribe@<#h#>> +# add new from line "From: arg" if -3 'arg' + +From: <#3#> +# max & min message size + +30000:2 +# remove mime parts if -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 + + + + +<#6#> + +<#6#>:<#L#>@<#H#> + +<#6#>_digest + +<#6#>_digest:<#L#>_digest@<#H#> + +<#6#>_allow +# -------------------- End sql stuff + +[<#L#>] + +--------------------------------------------------------------------- +För att avsluta prenumerationen skicka e-mail till: +<#L#>-unsubscribe@<#H#> +För ytterligare kommandon, skicka e-mail till: +<#L#>-help@<#H#> + + +--- 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#>> + + +eller för "digest" versionen: + <<#L#>-unsubscribe@<#H#>> + + +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. + + + +--- Nedan finner du en kopia på det "studsade" meddelandet jag fick. + + + +Jag har skapat en lista på de meddelanden från <#L#> listan som +har "studsat" på väg till dig. + + +Kopior av dessa meddelanden kan du finna i arkivet. + + +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#>> + + +Detta är meddelande nummren: + + + +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. + + +"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#>> + + +Här är "digest" meddelande nummren: + + + +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#>> + + + +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. + + +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#> + + +Tyvärr, det meddelandet finns inte i arkivet. + + +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#>> + + +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! + +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#>> + + +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#>> + + +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#>> + + +För "digest" versionen av listan: + <<#L#>-digest-subscribe-john=host.domain@<#H#>> + <<#L#>-digest-unsubscribe-john=host.domain@<#H#>> + + +Det är allt. Titel och innehåll spelar ingen roll! + + +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. + +Jag kommer skicka ett bekräftelsebrev till prenumerantens adress, +i detta fallet . Allt prenumeranten behöver +göra är att svara på brevet. + + +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#> + + +För "digest" versionen av listan: + +<#L#>-digest-subscribe@<#H#> +<#L#>-digest-unsubscribe@<#H#> + + +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. + + +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). + +Prenumeration fungerar på samma sätt. + + +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. + + +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#>> + + +För "digest" prenumeranter: + <<#L#>-digest-list@<#H#>> +och: + <<#L#>-digest-log@<#H#>> + + +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#>> + + +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. + + +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. + + +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. + + +Lycka till! + +PS. Kontakta listägaren (<#L#>-owner@<#H#>) ifall du +har några frågor eller stöter på några problem. + + +Tyvärr, meddelandet (bifogat) accepterades inte av moderatorn. +Ifall moderatorn har bifogat några kommentarer, står de här nedan. + +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. + + +Alternativt, tryck här: + > + + +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". + + +Alternativt, tryck här: + > + + +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. + + +--- 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. + + +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. + + +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. + + +eller tryck här: + > + + +Ifall du inte godkänner detta, ignorera detta meddelande. + +Tack för din hjälp! + + +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. + + +eller tryck här: + > + + +Ifall du inte håller med, ignorera detta brev. + +Tack för din hjälp! + + +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 + + +eller tryck här: + > + + +Var noga med att svarsadresser är riktig när du bekräftar +prenumerationen. + +Ursäkta detta extra besvär. + + <#L#>-Owner <<#l#>-owner@<#H#>> + + +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. + + +eller tryck här: + > + + +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. + + +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. + + +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. + + +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. + + +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#>> + + +Detta är ett meddelande från ezmlm programmet som har hand om +<#l#>@<#H#> listan. + + +Ägaren till listan kan nås på: +<#l#>-owner@<#H#>. + + +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 + + +eller klicka här: + > + + +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#>> + + +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. + + +eller tryck här: + > + + +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--mary=xdd.ff.com@<#H#>>. + + +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. + + +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. + + +Observera: Jag har tagit bort adressen + +!A + +från <#l#> listan. Den adressen är inte längre en prenumerant. + + +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. + + +eller klicka här: + mailto:<#R#> + + +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. + + + +<#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. + +trailer adderas till alla utskick innan de kommer till listan. + +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. + + +Textfilen uppdaterades korrekt. + +Ingen information har antecknats om listan. + +FAQ - vanligt förekommande frågor på <#l#>@<#H#> listan. + +Inga har nedtecknats ännu. + diff --git a/ezmlmsubrc b/ezmlmsubrc new file mode 100644 index 0000000..e8309f7 --- /dev/null +++ b/ezmlmsubrc @@ -0,0 +1,162 @@ +#$Id: ezmlmsubrc,v 1.8 1999/05/11 02:32:40 lindberg Exp $ +#$Name: ezmlm-idx-040 $ +# ezmlm-make -C ezmlmsubrc dir dot local host +# Options: +# -3 mainlist local (required) +# -4 mainlist host (required) +# -6 sql connect info. Format: 'host:port:user:pw:db:table' +# -A main list not archived (affects only bounce texts) +# -I main list not indexed (affects only bounce texts) +# -d this sublist is for a digest list +# +# NOTE: For sublists of a digest list use the list local name for -3, _not_ +# the digest list. Thus, to set up a sublist for list-digest@host, use +# -d -3 list -4 host. This is needed to make the texts refer correctly. +# Also, the "table" in the SQL connect info +# Should be root, where "root" is the table name used for the main list. +# A digest sublist is just like any other sublist, but the parent is +# list-digest, rather than list. You need separate sublists for each and they +# are independent. However, it's convenient to set them up in parallel, and +# they will not interfere with one another. +# +# NOTE: The list address is always added to the SQL connect info to restrict +# addresses to those serviced by this sublist. +# +# For memory + +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 + +<#3#>@<#4#> + + + + + + + +<#6#>:<#L#>@<#H#> + +<#6#>_digest:<#L#>_digest@<#H#> +# links: dot -> dir/editor + + + +|<#B#>/ezmlm-send '<#D#>' +|<#B#>/ezmlm-warn '<#D#>' || exit 0 + +|<#B#>/ezmlm-weed + +|<#B#>/ezmlm-return -D '<#D#>' + +|<#B#>/ezmlm-return -d '<#D#>' + +<#H#> + +<#H#> + +<#L#> + +<#L#> + +contact <#3#>-help@<#4#>; run by ezmlm + +Precedence: bulk + +return-path +return-receipt-to +content-length +precedence + +Hi! This is the ezmlm program. +I'm managing the <#3#>@<#4#> + +and <#3#>-digest@<#4#> +mailing lists. + + +mailing list. + + +--- Enclosed is a copy of the bounce message I received. + + + + +I've kept a list of which messages from the <#3#>@<#4#> +mailing list have bounced from your address. + + +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. + + +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: + + + + +Messages to you from the <#3#>@<#4#> mailing list + +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: + + <<#3#>-subscribe@<#4#>> + + + <<#3#>-digest-subscribe@<#4#>> + + + +Messages to you from the + +<#3#>@<#4#> mailing list seem to + +<#3#>-digest@<#4#> digest list seem to + +have been bouncing. I've attached a copy of the first bounce +message I received. + +If this message bounces too, I will send you a probe. If the probe bounces, +I will remove your address from the mailing list, without further notice. +# End of minimal sublist setup. diff --git a/ezmlmsubrc.5 b/ezmlmsubrc.5 new file mode 100644 index 0000000..c32ad33 --- /dev/null +++ b/ezmlmsubrc.5 @@ -0,0 +1,79 @@ +.TH ezmlmsubrc 5 +.SH NAME +ezmlmsubrc \- set up a minimal sublist +.SH SYNOPSIS +.B ezmlm-make +.B \-C ezmlmsubrc +.B -options +.I dir dot local host +.SH DESCRIPTION +.B ezmlmglrc +instructs +.B ezmlm-make(1) +to create +.I dir +and files within it to support the +.I local\fB@\fIhost +sublist. The sublist handles bounces, but not subscriptions. It is intended +for creation of sublists that are part of an SQL database supported distributed +ezmlm list. For creation of regular sublists, use +.B ezmlm-make(1) +with +.BR ezmlmrc(5) . +.SH "REQUIRED SWITCHES" +While these switches can be omitted, the list will not function unless they +are specified. +.TP +.B \-3\fI mainlocal +Local name of the main list for which this list is a sublist. If the sublist +is a sublist for digests, +.I mainlocal +should refer to the mail list, i.e. stripped of ``-digest''. This is required +in order for the bounce texts to refer to the correct archive. Use the +.B \-d +switch! +.TP +.B \-4\fI mainhost +Host name of the main list for which this list is a sublist. +.TP +.B \-6\fI host:port:user:pass:db:table +SQL connect info. Specifies the host and port to connect to, the user/password +to use, the database name, and the root table name. +The host defaults to ``localhost'', the database and table to ``ezmlm''. The +port default is the default for the particular SQL server type used. For +sublists disseminating a digest, ``table'' will end in ``_digest''. +.SH OPTIONS +.TP +.B \-d +This sublist is a sublist of a digest list. +The +.B \-3 +argment used should be the local name of the main list, rather than +the digest list, i.e. the terminal ``-digest'' should be stripped. +.TP +.B \-5\fI owner +The address to which to redirect mail send to +.IR local-\fBowner@\fIhost . +The default is the owner address for the main list. +.SH USAGE +A common task is to create both a sublist for the main list and a sublist +for the corresponding digest. Note that the local list names are given +as is, whereas the main list name always refers to the main list itself +(and not its digest). The main list is ``mainloc@mainhost'', the local +sublist is ``me-sub1@myhost''; the main digest is ``mainloc-digest@mainhost'' +and the local digest sublist is ``me-sub1-digest@myhost''. + +.EX +ezmlm-make -Cezmlmsubrc -3 mainloc -4 mainhost -6 mainhost::user:pw:db:tab +~/DIR ~me/.qmail-sub1 me-sub1 myhost +.EE + +.EX +ezmlm-make -Cezmlmsubrc -d -3 mainloc -4 mainhost -6 mainhost::user:pw:db:tab +\-d ~/DIR ~me/.qmail-sub1-digest me-sub1-digest myhost +.EE +.SH "SEE ALSO" +ezmlm-make(1), +ezmlm(5), +ezmlmrc(5) + diff --git a/idx.h b/idx.h new file mode 100644 index 0000000..59f7867 --- /dev/null +++ b/idx.h @@ -0,0 +1,354 @@ +/*$Id: idx.h,v 1.57 1999/11/29 04:54:01 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#ifndef IDX_H +#define IDX_H + +/* Version of this release */ +#define EZIDX_VERSION "ezmlm-idx-0.40\n" + +/* Range for '-thread' to protect large archives. A '-thread' search */ +/* will start at most THREAD_BEFORE messages before the action argument */ +/* and go to at most THREAD_AFTER messages after the action argument. */ +#define THREAD_BEFORE 2000 +#define THREAD_AFTER 2000 + +/* Maximum number of messages returned by get */ +/* You also have to update /text/bottom in ezmlmrc if you change this */ +#define MAXGET 100 + +/* Number of messages before latest digest to return for list-get.99999_x */ +/* This is still subject to the MAXGET restriction */ +#define HISTGET 30 + +/* Maximum subject index entries returned by index */ +/* Must be multiple of 100 */ +/* You also have to update /text/bottom in ezmlmrc if you change this */ +#define MAXINDEX 2000 + +/* Max dir/text file size allowed by -edit */ +#define MAXEDIT 10240 + +/* Timeout in seconds before a bounce warning is sent. Default is */ +/* 1000000, i.e. 11.57 days. Setting it lower reduces the number of */ +/* messages in the bouce dir, but makes it more likely that an address */ +/* is unsubscribed due to a temporary error. This compile-time default */ +/* should rarely need changing, as it can be overridden with the ezmlm-warn */ +/* -t switch */ +#define BOUNCE_TIMEOUT 1000000L + +/* ezmlm-limit defaults. Convert to moderation or defer if more than */ +/* LIMMSG messages arrive within LIMSECS */ +#define LIMMSG 30L +#define LIMSECS 3600L + +/* Command names and alternative command names */ +/* all alternates must be defined! */ +/* The language-specific blocks need to undefine and redefine commands */ + +#define ALT_LIST "list" +#define ALT_LISTN "listn" +#define ALT_EDIT "edit" +#define ALT_FAQ "faq" +#define ALT_GET "get" +#define ALT_HELP "help" +#define ALT_INDEX "index" +#define ALT_INFO "info" +#define ALT_LOG "log" +#define ALT_REQUEST "request" +#define ALT_SUBSCRIBE "subscribe" +#define ALT_THREAD "thread" +#define ALT_UNSUBSCRIBE "unsubscribe" +#define ALT_QUERY "query" + +/* to get alternative command names, you need to undefine and redefine */ +/* them. Do this within a language block and send it to the author for */ +/* inclusing in future versions. If it's here already, just uncomment the */ +/* define for the appropriate language. */ +/* #define LANG_FR 1 */ + +/* French Version */ +#ifdef LANG_FR +#undef ALT_SUBSCRIBE +#define ALT_SUBSCRIBE "-inscription" +#undef ALT_UNSUBSCRIBE +#define ALT_UNSUBSCRIBE "-desinscription" +#endif +/* end French Version */ + +/* Text that is used in the outgoing messages (there is some other text, but */ +/* it needs to stay constant in order to comply with rfc1153 */ + +/* Topics (messages nnn through mmm):\n */ +#define TXT_TOP_TOPICS "Topics" +#define TXT_TOP_MESSAGES " (messages " +#define TXT_TOP_THROUGH " through " +#define TXT_TOP_LAST "):\n" + +/* in digest */ +#define TXT_ADMINISTRIVIA "\nAdministrivia:\n\n" +#define TXT_SUPPRESSED "\n\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\n\n" + +/* Subject: MODERATE for inlocal@inhost */ +#define TXT_MODERATE "MODERATE for " + +/* Subject: Returned post for inlocal@inhost */ +/* (used both for rejected and timed-out posts) */ +#define TXT_RETURNED_POST "Returned post for " + +/* Subject: CONFIRM subscribe to | unsubscribe from */ +#define TXT_USRCONFIRM "confirm " +#define TXT_MODCONFIRM "CONFIRM " +#define TXT_SUBSCRIBE_TO "subscribe to " +#define TXT_UNSUBSCRIBE_FROM "unsubscribe from " + +/* Subject: WELCOME to */ +#define TXT_WELCOME "Subject: WELCOME to " + +/* Subject: GOODBYE from */ +#define TXT_GOODBYE "Subject: GOODBYE from " + +/* Subject: ezmlm response\n */ +#define TXT_EZMLM_RESPONSE "Subject: ezmlm response\n" + +/* Subject: majordomo results\n\n [where "majordomo" is outlocal] */ +#define TXT_RESULTS " results\n\n" + +/* Subject: Edit file xxx for list@host */ +#define TXT_EDIT_RESPONSE "Subject: EDIT " +#define TXT_EDIT_FOR " for " + +/* Subject: Editable text files\n */ +#define TXT_EDIT_LIST "Subject: List of editable text files\n" + +/* markers for ezmlm-manage text file edit */ +/* MUST start with '%' */ +#define TXT_EDIT_START "%%% START OF TEXT FILE" +#define TXT_EDIT_END "%%% END OF TEXT FILE" + +#define TXT_EDIT_SUCCESS "Subject: Success editing " + +/* Text for '-list' command */ +#define TXT_LISTMEMBERS "\nSubscribers to this list are:\n\n" + +/* Output formats - letter used to override default */ +#define FORMATS "mrvnx" +#define MIME 'm' +#define RFC1153 'r' +/* ---------------- virgin = MIME without header processing */ +#define VIRGIN 'v' +/* NATIVE 'n' = VIRGIN without threading */ +#define NATIVE 'n' +/* MIXED => multipart/mixed MIME instead of multipart/digest. Needed to bypass*/ +/* pine bug when content-transfer-encoding is used (pine fails to show the */ +/* initial encoded text/plain part of mulpart/digest, but not of ../mixed) */ +#define MIXED 'x' +/* default output format. */ +#define DEFAULT_FORMAT MIME + +/* Use MIME enclosure for message to moderate by default (1) or not (0) */ +/* ezmlm-store switches -m/-M override */ +#define MOD_MIME 1 + +/* Used to add "filname=listname.msgno" to digest part content-type line. + This confuses the heck out of Outlook Express 5.0. To circumvent this + bug the addition has been removed. Uncomment the next line to get it + anyway. */ +/* #define DIGEST_PART_FILENAME */ + +/* Mode of messages in archive. For ezmlm-0.53 this is 0744, but for */ +/* "secret" lists it may make more sense to make it 0700. */ +#define MODE_ARCHIVE 0744 + +/* ezmlm-get actions (ACTION_GET also for -get in ezmlm-manage) */ +#define ACTION_GET "get" +#define ACTION_INDEX "index" +#define ACTION_THREAD "thread" + +/* ezmlm-request actions */ +#define ACTION_REQUEST "request" + +/* actions for post acceptance/rejection */ +#define ACTION_ACCEPT "accept-" +#define ACTION_REJECT "reject-" + +/* ezmlm-manage actions */ +#define ACTION_LIST "list" +#define ACTION_LISTN "listn" +#define ACTION_HELP "help" +#define ACTION_INFO "info" +#define ACTION_FAQ "faq" +#define ACTION_LOG "log" +#define ACTION_SUBSCRIBE "subscribe" +#define ACTION_UNSUBSCRIBE "unsubscribe" +#define ACTION_QUERY "query" +#define ACTION_EDIT "edit" +/* if you change this, you MUST ADJUST LENGTH_ED as well! */ +#define ACTION_ED "ed." +#define LENGTH_ED 3 + +/* ACTION_XC has to be a string "-xc." where x is any letter. All commands */ +/* should have different letters. They no longer have to match the first */ +/* letter of subscribe/unsubscribe. */ +/* The third char of ACTION_SC/TC/UV/VC has to be 'c' */ + +/* user subscription confirm */ +#define ACTION_SC "sc." +/* moderator subscription confirm */ +#define ACTION_TC "tc." +/* user unsubscribe confirm */ +#define ACTION_UC "uc." +/* moderator unsubscribe confirm */ +#define ACTION_VC "vc." + +/* name addition for digest, i.e. list-"digest" Don't change! */ +#define ACTION_DIGEST "digest" + +/* name addition for dir/extra db, i.e. list-"allow" */ +#define ACTION_ALLOW "allow" +/* name addition for dir/blacklist db, i.e. list-"deny" */ +#define ACTION_DENY "deny" + +/* defaults for message time out in moderation queue. If modsub is 0 */ +/* or empty, DELAY_DEFAULT is used. If it is set, it is made to be */ +/* within DELAY_MIN .. DELAY_MAX. All in hours. */ +#define DELAY_MIN 24 +#define DELAY_DEFAULT 120 +#define DELAY_MAX 240 + +/* Mode of messages in moderation queue. The owner mode is |'d with 7.*/ +/* The group/world mode can be set to anything, but it really doesn't */ +/* make sense to make these messages visible to anyone else. */ +#define MODE_MOD_MSG 0700 + +/* name and location of system-wide customized ezmlmrc. This is where */ +/* ezmlm-make looks first (unless the -c switch is specified) before */ +/* falling back to the (usually unchanged) version in the ezmlm bin */ +/* directory. */ +#define TXT_ETC_EZMLMRC "/etc/ezmlm/ezmlmrc" + +/* same name added to auto_bin. Note leading slash! */ +#define TXT_EZMLMRC "/ezmlmrc" + +/* same in dot dir for local config (-c) */ +#define TXT_DOTEZMLMRC ".ezmlmrc" + +/* name of config file for ezmlm-cron */ +#define TXT_EZCRONRC "ezcronrc" + +/* default timestamp for ezmlm-limit */ +#define TXT_LOOPNUM "loopnum" + +/* ezmlm-cgi config file for normal SUID root install */ +#define EZ_CGIRC "/etc/ezmlm/ezcgirc" + +/* ezmlm-cgi config file for local install we expect to find the file in PWD */ +#define EZ_CGIRC_LOC ".ezcgirc" + +/* default charset for ezmlm-cgi [config file overrides per list] */ +#define EZ_CHARSET "iso-8859-1" + +/*------------ Specific to SQL version ------------------------------*/ +/* cookie tag for SQL version of sublisting */ +/* NOTE: Need to include terminal space! */ +#define TXT_TAG "X-Ezauth: " + +/* max no of bounces that ezmlm-receipt stores */ +#define MAX_MAIN_BOUNCES 50 + +/* Length of domain field for SQL version. It does only the text after */ +/* the last '.' in the address, so there is no reason to set it to */ +/* anything other than '3'. We truncate it rather than relying on the */ +/* SQL Server since we can't be sure that the SQL Server doesn't have */ +/* buffer overrun holes and the address is user-controlled */ +#define DOMAIN_LENGTH 3 + +/* programs used for outgoing mail. Normally, qmail-queue is used. Replace */ +/* with qmail-qmqpc to use only qmqp for outgoing mail. QMQPC is for */ +/* large lists when DIR/qmqpservers is present. Only posts and digests will */ +/* use QMQP. If the normal qmail-qmqpc is used the contents of */ +/* DIR/qmqpcservers are ignored. With a patch, qmail-qmqpc will use the */ +/* servers on it's command line. In this case, the IP addresses listed one */ +/* per line in DIR/qmqpservers will be tried until a working one is found. */ +/* the option is mainly to allow large list clusters on a single host to use */ +/* different QMQPC hosts as exploders.*/ +#define PROG_QMAIL_QUEUE "bin/qmail-queue" +#define PROG_QMAIL_QMQPC "bin/qmail-qmqpc" + +/*---------- Things below this line are not configurable -----------*/ +/* file in DIR that has the qmqpc servers (if any) */ +#define QMQPSERVERS "qmqpservers" +/* database types */ +#define FLD_DIGEST 1 +#define FLD_ALLOW 2 +#define FLD_DENY 3 +/* Action types */ +#define AC_NONE 0 +#define AC_GET 1 +#define AC_DIGEST 2 +#define AC_THREAD 3 +#define AC_INDEX 4 +#define AC_LIST 5 +#define AC_HELP 6 +#define AC_EDIT 7 +#define AC_DENY 8 +#define AC_LOG 9 +#define AC_SUBSCRIBE 10 +#define AC_UNSUBSCRIBE 11 +#define AC_SC 12 +#define AC_LISTN 13 + +typedef struct msgentry { /* one per message in range */ + unsigned long subnum; /* subject number */ + unsigned long authnum; /* message author number */ + unsigned int date; /* yyyymm as number */ +} msgentry; + +typedef struct subentry { /* one per unique subject in message range */ + void *higher; + void *lower; + char *sub; /* string with terminating '\0' */ + /* when building, higher/lower=0 marks end */ + /* of branch. When printing, start at the */ + /* beginning of the table and go up until */ + /* sub = 0. */ + unsigned int sublen; + unsigned long firstmsg; /* the first message with this subject*/ + unsigned long lastmsg; /* the last message with this subject*/ + unsigned char msginthread; /* number of messages seen in this thread */ +} subentry; + +typedef struct authentry { /* one per unique author in message range */ + void *higher; + void *lower; + char *auth; /* string with terminating '\0' */ + /* when building, higher/lower=0 marks end */ + /* of branch. When printing, start at the */ + /* beginning of the table and go up until */ + /* auth = 0. */ + unsigned long authlen; + unsigned long firstmsg; /* the first message with this author */ + /* lastmsg not very useful as author are less */ + /* clustered than threads */ +} authentry; + +typedef struct dateentry { /* date yyyymm and 1st message of that date */ + unsigned int date; + unsigned int msg; +} dateentry; + +#endif + diff --git a/idx.patch b/idx.patch new file mode 100644 index 0000000..7fd82fa --- /dev/null +++ b/idx.patch @@ -0,0 +1,3038 @@ +--- ezmlm-warn.1 1998/02/17 00:32:45 1.1 ++++ ezmlm-warn.1 1998/12/21 04:35:16 1.5 +@@ -3,6 +3,15 @@ + ezmlm-warn \- send out bounce warnings + .SH SYNOPSIS + .B ezmlm-warn ++[ ++.B \-dD ++][ ++.B \-t ++.I timeout ++][ ++.B \-l ++.I lockout ++] + .I dir + .SH DESCRIPTION + .B ezmlm-warn +@@ -12,27 +21,91 @@ + + .B ezmlm-warn + scans +-.I dir\fB/bounce +-for bounce messages received by +-.BR ezmlm-return . +-If it sees a distribution bounce for ++.I dir\fB/bounce/d/ ++for directories older than ++.I timeout ++days ago (see ++.BR \-t ). ++The directories are created by ++B ezmlm-return ++and contain bounces. ++If ++.B ezmlm-warn ++sees a distribution bounce for + .I box\fB@\fIdomain +-received more than ten days ago, ++received more than ++.I timeout ++days ago, + it sends + .I box\fB@\fIdomain + a list of all the message numbers missed recently, + and deletes the bounce. + If it sees a warning bounce for + .I box\fB@\fIdomain +-received more than ten days ago, ++received more than ++.I timeout ++days ago, + it sends + .I box\fB@\fIdomain + a probe, + and deletes the bounce. + + .B ezmlm-warn ++uses ++.I dir\fB/bounce/lastd ++to keep track of when it was last run. If insufficient time has ++passed (see ++.BR \-l ) ++.B ezmlm-warn ++exits without further action. ++ ++.B ezmlm-warn ++keeps files with the bounced message numbers in ++.IR dir\fB/bounce/h . ++Expired files are removed and ++.I dir\fB/bounce/lasth ++keeps track of the last subdirectory scanned. ++ ++.B ezmlm-warn + will not send a warning or probe to an address that is + not currently a subscriber. ++.SH OPTIONS ++.TP ++.B \-d ++process bounces for the digest list, rather than for the main list. ++Digest list bounces are stored in ++.I dir\fB/digest/bounce/ ++rather than in ++.IR dir\fB/bounce/ . ++.TP ++.B \-D ++(Default.) ++Process bounces for the main list. ++.TP ++.B \-l \fIlockout ++.B ezmlm-warn ++will abort execution if it was run less than ++.I lockout ++seconds ago. The default is ++.I timeout / ++50, which with the default ++.I timeout ++is 20,000 seconds (approx. 5.6 hours). There is no reason to use this ++switch, except for testing and possibly in combination with ++.BR \-t. ++.TP ++.B \-t \fItimeout ++Bounces received more than ++.I timeout ++days ago are processed. This overrides the default of 1,000,000 ++seconds (approximately 10 days) ++and may possibly be useful for very large busy lists. Also, a ++.I timeout ++of zero can be used to send a warning to all addresses for which ++a bounce has been received and a probe for all addresses for which a ++warning has bounces. ++This is useful to rapidly clear ++out bouncing addresses from a (low quality) address list. + .SH "SEE ALSO" + ezmlm-make(1), + ezmlm-return(1), +--- ezmlm-return.1 1998/02/17 00:33:15 1.1 ++++ ezmlm-return.1 1999/08/19 03:57:54 1.6 +@@ -3,12 +3,16 @@ + ezmlm-return \- handle mailing list bounces + .SH SYNOPSIS + .B ezmlm-return ++[ ++.B \-dD ++] + .I dir + .SH DESCRIPTION + .B ezmlm-return + handles bounces for the mailing list + stored in +-.IR dir . ++.I dir ++and, if it exists, the associated digest list. + + .B ezmlm-return + is normally invoked from a +@@ -21,6 +25,30 @@ + and + .BR HOST + environment variables. ++ ++.B ezmlm-return ++exits 99, not 0, upon success. ++.SH OPTIONS ++.TP ++.B \-d ++.B ezmlm-return ++will assume the bounce is for a digest list. ++Normally, ++.B ezmlm-return ++will autodetect this from the bounce address. Autodetection makes ++.B ezmlm-return ++less flexible and will be removed in future versions. ++.TP ++.B \-D ++.B ezmlm-return ++will assume that the bounce is for a normal (non-digest) list. ++Normally, ++.B ezmlm-return ++will autodetect this from the bounce address. Autodetection makes ++.B ezmlm-return ++less flexible and will be removed in future versions. ++.B \-D ++will become the default. + .SH ADDRESSES + .B ezmlm-return + handles mail sent to any of the following addresses: +@@ -59,6 +87,21 @@ + will remove + .I box\fB@\fIdomain + from the mailing list. ++.TP ++.I local\fB\-return\-receipt\-\fIcookie\-fImsg\- ++A receipt from the list. This is logged. For SQL supporting lists, ++.I cookie ++is verified and receipt logged only if the cookie is correct. The arrival ++of the receipt shows that qmail at the sending host is running. ++ ++For all the above addresses if, ++.I local ++is followed by ++.IR \-digest , ++bounces are assumed to be from the digest list, and are stored in ++.I dir\fB/digest/bounce ++rather than in ++.I dir \fB/bounce . + .SH "SEE ALSO" + ezmlm-manage(1), + ezmlm-make(1), +--- ezmlm-send.1 1997/07/23 18:55:45 1.1 ++++ ezmlm-send.1 1999/08/19 03:13:36 1.27 +@@ -3,6 +3,11 @@ + ezmlm-send \- distribute a message to a mailing list + .SH SYNOPSIS + .B ezmlm-send ++[ ++.B \-cCrRvV ++] [ ++.B \-h\fI header ++] + .I dir + .SH DESCRIPTION + .B ezmlm-send +@@ -14,9 +19,34 @@ + exists, + .B ezmlm-send + records a copy of the message in the +-.I dir\fB/archive ++.I dir\fB/archive/ + directory. + ++If ++.I dir\fB/indexed ++exists, ++.B ezmlm-send ++adds the subject, author and time stamp of the message to the index, kept with ++the message in a subdirectory of ++.IR dir\fB/archive/ . ++The subject is processed to make reply-subject entries identical to ++original ++message subject entries. ++The subject index is used for the archive retrieval functions of ++.BR ezmlm-get(1) . ++Use ++.B ezmlm-idx(1) ++to create a subject index from a preexisting archive. ++ ++Subject and author lines are decoded if they are encoded per rfc2047. When ++split lines are unfolded, the number of escape sequences for ++iso-2022-* character sets is minimized. For instance, two ++consequtive toascii sequences are reduced. ++This processing is done for the character set specified in ++.IR dir\fB/charset . ++The result of this process is the same for a given subject, irrespective ++of encoding. ++ + At the beginning of the message, + .B ezmlm-send + prints a new +@@ -27,10 +57,24 @@ + .B Mailing-List + field. + ++If ++.I dir\fB/listid ++exists, ++.B ezmlm-send ++will assume that the format is correct and ++create a ``List-ID:'' header by placing the contents after the ++text ``List-ID: ''. ++ ++Next, ++.B ezmlm-send ++prints all the new fields listed in ++.IR dir\fB/headeradd . ++Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in these headers ++are replaced by the list host name, list local name, and message number, ++respectively. ++ + .B ezmlm-send +-then prints all the new fields listed in +-.IR dir\fB/headeradd , +-followed by an appropriate ++then prints an appropriate + .B Delivered-To + line. + +@@ -39,6 +83,63 @@ + .IR dir\fB/headerremove . + + .B ezmlm-send ++removes MIME parts specified in ++.I dir\fB/mimeremove ++before archiving and distribution of the message. ++ ++If ++.I dir\fB/text/trailer ++exists, ++.B ezmlm-send ++adds the trailer to simple text/plain messages in the same encoding as used for ++the the message. However, if the encoding is ``base64'' it is not safe ++to do this and the header is suppressed. ++For composite MIME messages, the trailer is added as a separate ++part, with the character set and encoding specified in ++.IR dir\fB/charset . ++The trailer is not added to multipart/alternative messages. ++Any tags, ``<#h#>'', ``<#l#>'', or ``<#n#>'' found in ++.I dir\fB/text/trailer ++are replaced by the list host name, list local name, and message number, ++respectively. ++ ++If ++.I dir\fB/prefix ++exists, ++.B ezmlm-send ++will prefix the subject line with the first line of this ++file. A space will be added to separate ++.B prefix ++from the subject text. ++.B prefix ++is ignored for sublists. If ++.I dir\fB/prefix ++contains a ``#'', the last ``#'' will be replaced by the message number. ++Any prefix starting with text of a ++reply indicator (``Re:'', ``Re[n]:'', etc) will cause problems. ++The prefix may be ++rfc2047 encoded. Rfc2047 Iso-2022-* encoded prefixes ++.I must ++end in ascii. ++ ++The prefix feature and especially the message number feature ++modify the message in violation ++with Internet mail standards. The features have been implemented by popular ++demand. Use at your own peril. ++ ++.I dir\fB/sequence ++is ignored as of ezmlm-idx-0.32. Use ++.I dir\fB/headeradd ++with substitution to achieve the same goal. ++ ++If ++.I dir\fB/qmqpservers ++exists, ++.B ezmlm-send will use ++.B qmail-qmqp(1) ++to send messages. ++ ++.B ezmlm-send + does not distribute bounce messages: + if the environment variable + .B SENDER +@@ -46,6 +147,60 @@ + .BR #@[] , + .B ezmlm-send + rejects the message. ++.SH OPTIONS ++.TP ++.B \-c ++No longer supported. Ignored for backwards compatibility. ++.TP ++.B \-C ++No longer supported. Ignored for backwards compatibility. ++.B ezmlm-send ++has to parse the subscriber database. ++.TP ++.B \-h\fI header ++If the list is a sublist, i.e. ++.I dir\fB/sublist ++exists, ++.I header ++is required in all messages to the list. This option is used ++when ezmlm is used to run a sublist of a lists run by a different ++mailing list ++manager that uses ++.I header ++rather than ``Mailing-List'' to identify messages from the list. ++Anything after the first colon (if present) in ++.I header ++is ignored. ++.TP ++.B \-r ++Copy incoming ``Received:'' headers to the outgoing message. ++.TP ++.B \-R ++(Default.) ++Do not copy incoming ``Received:'' headers, except the one added by ++the (last) listhost, to the outgoing message. ++In some ++cases, especially for sublists, ++the messages can have a large number of ``Received:'' ++headers. This may lead to bounces for some users due to ++sendmail ``hopcounts'' set too low somewhere in the mail path. These users can ++subscribe and receive warning and probe messages, but no list messages, unless ++the number of ``Received:'' headers is reduced. ++ ++Pre-list ``Received:'' headers are of little interest to normal list ++subscribers. ``Received:'' headers are ++still copied to the archive and available ++to anyone from there for message tracking purposes. ++.TP ++.B \-v ++Display ++.B ezmlm-send ++version information. ++.TP ++.B \-V ++Display ++.B ezmlm-send ++version information. + .SH "SUBLISTS" + If + .I dir\fB/sublist +@@ -77,10 +232,71 @@ + does not add its own + .B Mailing-List + field. ++ ++Fourth, ++.B ezmlm-send ++uses the incoming message number for the outgoing message, if the list ++is not archived and the incoming SENDER has the correct format. ++This allows you to refer bounce warning recipients to the main list for ++archive retrieval of the missed messages. If the sublist archives ++message, it is assumed that missed messages will be retrieved from the sublist ++archive. ++ ++The list ++still increments ++.I dir\fB/num ++for each message. If the sublist is archived, use of incoming message number ++for archive storage would be a security risk. In this case, the local sublist ++message number is used. ++.SH "OPTION USAGE" ++In general, the use of a prefix is discouraged. It wastes subject line space, ++creates trouble when MUAs add non-standard reply indicators. However, many ++users expect it not because it is useful, but because they are used to it. ++ ++The ++.B \-C ++switch prevents posts from being set to SENDER. Rather than just copying ++out subscriber address files, ++.B ezmlm-send ++has to parse them to look for SENDER. This makes it less efficient. Also, ++it is useful for the SENDER to see the post to know that it has made it ++to the list, and it's context to other subscribers, i.e. where it came ++within the traffic of messages on the list. ++ ++Avoiding SENDER as a recipient is useful in small lists, such as small ++teams with varying members, where ezmlm serves mainly as an efficient tool ++to keep the team connected without administrator intervention. Here the ++overhead of subscriber list parsing is negligible. ++.SH "CHARACTER SETS" ++If the list is indexed, ++.B ezmlm-send ++will keep a message index. rfc2047-encoded subject and from lines will be ++decoded. ++If ++.I dir\fB/charset ++exists, ++.B ezmlm-send ++will eliminate redundant escape sequences from the headers according to ++the character set specified in this file. ++Only character sets using escape sequences need this support. Currently, ++supported are iso-2022-jp*, iso-2022-kr, and iso-2022-cn*. Only iso-2022-jp ++has been tested extensively. ++ ++The character set can be suffixed ++by ``:'' followed by a code. Recognized codes are ``Q'' ++for ``Quoted-Printable'', and ``B'' for ``base64''. ++ ++For ++.BR ezmlm-send , ++this affects the format of the trailer, if a trailer is specified and if the ++message is a multipart mime message + .SH "SEE ALSO" ++ezmlm-get(1), ++ezmlm-idx(1), + ezmlm-manage(1), + ezmlm-make(1), + ezmlm-sub(1), + ezmlm-unsub(1), + ezmlm-reject(1), +-ezmlm(5) ++ezmlm(5), ++qmail-qmqp(1) +--- ezmlm-sub.1 1998/12/06 16:48:14 1.1 ++++ ezmlm-sub.1 1999/08/19 03:22:14 1.5 +@@ -3,9 +3,20 @@ + ezmlm-sub \- manually add addresses to a mailing list + .SH SYNOPSIS + .B ezmlm-sub ++[ ++.B \-HmMnNsSvV ++][ ++.B \-h ++.I hash ++] ++.B + .I dir + [ +-.I box\fB@\fIdomain ... ++.I box\fB@\fIdomain ++[ ++.I name ++] ++.I ... + ] + .SH DESCRIPTION + .B ezmlm-sub +@@ -13,12 +24,20 @@ + .I box\fB@\fIdomain + to the mailing list stored in + .IR dir . ++.I name ++is added as a comment to the subscription log, if the ++.B \-n ++switch is used. ++ ++If no argument is given on the command line, ++.B ezmlm-sub ++processes stdin. + + If + .I box\fB@\fIdomain + is already on the mailing list, + .B ezmlm-sub +-leaves it there. ++leaves it there and does not modify the subscription log. + + .B ezmlm-sub + converts +@@ -28,11 +47,61 @@ + to the mailing list. + + .I box\fB@\fIdomain +-cannot be longer than 400 characters. ++cannot be longer than 400 characters (255 characters with mysql support). ++.SH "GENERAL OPTIONS" ++.TP ++.B \-n ++Assume arguments are pairs of ++.I box\fB@\fIdomain ++and ++.IR name ++(or other subscriber info) ++rather than addresses alone. ++.B ezmlm-sub(1) ++will add the first argument in each pair to the subscriber list. If it is ++a new address, ++.I name ++will be added to the subscription log. ++.TP ++.B \-N ++(Default.) ++Arguments are all addresses of the type ++.IR box\fB@\fIdomain . ++.TP ++.B \-v ++Display ++.B ezmlm-sub(1) ++version information. ++.TP ++.B \-V ++Display ++.B ezmlm-sub(1) ++version information. ++.SH "MYSQL OPTIONS" ++These option is silently ignored in the absence of mysql support. ++.TP ++.B \-h \fIhash ++With mysql support the argument is used as the hash. The argument should ++be between 1 and 99. The hash is used in ++in the distribution of addresses between sublists. As the hash is normally ++between 0 and 52, controlling the hash makes it possible to add addresses ++that cannot be manipulated remotely. ++.TP ++.B \-m ++(Default.) ++Use SQL support if available. ++.TP ++.B \-M ++Do not use SQL support even if available. This option can be used to build ++a normal local subscriber database even for lists with SQL support. Use ++in combination with ++.B ezmlm-list(1) ++to convert an SQL address db to a ezmlm standard address database. + .SH "SEE ALSO" + ezmlm-list(1), + ezmlm-manage(1), + ezmlm-make(1), ++ezmlm-receipt(1), + ezmlm-send(1), + ezmlm-unsub(1), + ezmlm(5) +--- ezmlm-unsub.1 1998/12/06 16:48:14 1.1 ++++ ezmlm-unsub.1 1999/08/19 03:22:14 1.5 +@@ -3,6 +3,11 @@ + ezmlm-unsub \- manually remove addresses from a mailing list + .SH SYNOPSIS + .B ezmlm-unsub ++[ ++.B \-mMHvV ++] [ ++.B \-h\fBhash ++] + .I dir + [ + .I box\fB@\fIdomain ... +@@ -14,6 +19,10 @@ + from the mailing list stored in + .IR dir . + ++If no command line argument is given, ++.B ezmlm-unsub ++will process stdin instead. ++ + If + .I box\fB@\fIdomain + is not on the mailing list, +@@ -26,10 +35,46 @@ + to lowercase before removing + .I box\fB@\fIdomain + from the mailing list. ++.SH "GENERAL OPTIONS" ++.TP ++.B \-v ++Display ++.B ezmlm-unsub(1) ++version information. ++.TP ++.B \-V ++Display ++.B ezmlm-unsub(1) ++version information. ++.SH "MYSQL OPTIONS" ++These option is silently ignored in the absence of mysql support. ++.TP ++.B \-h \fIhash ++With mysql support the argument is used as the hash. The argument should ++be between 1 and 99. The hash is used in ++in the distribution of addresses between sublists. As the hash is normally ++between 0 and 52, controlling the hash makes it possible to remove addresses ++that cannot be manipulated remotely. A hash of 99 is reserved for sublists, ++and a hash of 98 is reserved for ``receipt'' addresses serviced by ++.B ezmlm-receipt(1). ++.TP ++.B \-H ++(Default.) ++The address can be removed if it has a hash in the normal range (0..52). ++.TP ++.B \-m ++(Default.) ++Use SQL support if available. ++.TP ++.B \-M ++Do not use SQL support even if available. ++This option can be used to manipulate ++a normal local subscriber database even for lists with SQL support. + .SH "SEE ALSO" + ezmlm-list(1), + ezmlm-manage(1), + ezmlm-make(1), ++ezmlm-receipt(1), + ezmlm-send(1), + ezmlm-sub(1), + ezmlm(5) +--- ezmlm-list.1 1998/12/06 16:48:14 1.1 ++++ ezmlm-list.1 1999/08/19 03:40:27 1.5 +@@ -3,6 +3,11 @@ + ezmlm-list \- show the addresses on a mailing list + .SH SYNOPSIS + .B ezmlm-list ++[ ++.B \-n\fI msgnum ++] [ ++.B \-aAmMnNvV ++] + .I dir + .SH DESCRIPTION + .B ezmlm-list +@@ -16,6 +21,40 @@ + of a possibly malicious remote user. + .B ezmlm-list + does not strip control characters. ++.SH "GENERAL OPTIONS" ++.TP ++.B \-m ++(Default.) ++Use SQL support if available. ++.TP ++.B \-M ++Do not use SQL support even if available. ++This option can be used to manipulate ++a normal local subscriber database even for lists with SQL support. ++.TP ++.B \-n ++Print only the number of subscribers. ++.TP ++.B \-N ++(Default.) ++List subscriber addresses, one per line. ++.TP ++.B \-v ++Display ++.B ezmlm-list(1) ++version information. ++.TP ++.B \-V ++Display ++.B ezmlm-list(1) ++version information. ++.SH "SEE ALSO" ++ezmlm-list(1), ++ezmlm-manage(1), ++ezmlm-make(1), ++ezmlm-send(1), ++ezmlm-sub(1), ++ezmlm(5) + .SH "SEE ALSO" + ezmlm-sub(1), + ezmlm-unsub(1), +--- ezmlm.5 1997/07/13 22:01:50 1.1 ++++ ezmlm.5 1999/05/12 22:41:46 1.24 +@@ -21,7 +21,60 @@ + handles administrative requests automatically; + .B ezmlm-send + sends a message to all subscribers listed in +-.IR dir . ++.I dir ++and also maintains a message archive and message subject index if the list ++is configured to do so. ++.B ezmlm-reject ++rejects messages that have an empty subject, or a subject consisting of ++only a command word; ++.B ezmlm-return ++handles bounces; ++.B ezmlm-warn ++warns users for which messages bounce and eventually removes them from ++the subscriber list. ++.B ezmlm-idx ++can create a subject index from an existing list archive. ++.B ezmlm-get ++manages message, index, and thread retrieval from the archive, as well ++as the generation of message digests; ++.B ezmlm-cron ++provides a restricted interface to cron for the generation of ++digest generation trigger messages; ++.B ezmlm-store ++queues messages of moderated lists and sends a moderation request to ++the moderator(s); ++.B ezmlm-moderate ++processes moderation requests to accept the queued message to the list ++via ++.B ezmlm-send, ++or to return the message to the sender; ++.B ezmlm-clean ++cleans up the moderation queue and returns to the sender ++any messages that have timed-out; ++.B ezmlm-gate ++posts messages that come from a SENDER in an address database, and sends ++remaining messages out for moderation; ++.B ezmlm-check ++is used to diagnose problems with ezmlm mailing list configuration; ++.B ezmlm-issub ++and ++.B ezmlm-issubn ++determine if a SENDER is a subscriber or a member of a ++collection of addresses; ++.B ezmlm-tstdig ++determines if it is time to create a new digest based on the number and ++volume of messages and the amount of time that has passed since the last ++digest was issued; ++.B ezmlm-request ++can be used to answer ++.B ezmlm ++commands in the subject line easing migration from other mailing list ++managers. It can also function as a global interface mimicking ++the interface of other mailing list manager. ++.B ezmlm-glmake ++can set up the global interface, and ++.B ezmlm-glconf ++can create a configuration file for the global interface from your lists. + .SH SUBSCRIBERS + .I dir\fB/subscribers + is a directory containing the subscriber list. +@@ -69,12 +122,19 @@ + .B ezmlm-send + archives all new messages if + .I dir\fB/archived +-exists. ++exists. If ++.I dir\fB/indexed ++exists, ++.B ezmlm-send ++also maintains a message subject and author index. + + Messages sent to the mailing list are numbered from 1 upwards, + whether or not they are archived. + .I dir\fB/num +-is the number of messages sent so far. ++is the number of messages sent so far followed by ':', followed by the ++cumulative amount of message body that has passed ++.B ezmlm-send ++stored as kbytes * 4 (4 corresponds to 1kb). + + .I dir\fB/archive + has subdirectories, +@@ -83,11 +143,43 @@ + .IR dir\fB/archive/\fIm\fB/\fIn . + For example, message number 15307 is stored in + .IR dir\fB/archive/153/07 . ++The message index is stored in the file ++.B index ++in the same subdirectory of ++.I dir\fB/archive ++holding the corresponding messages. ++Thus, the subject index contains up to 100 entries. ++ ++The subject index contains message subjects that are normalized so that ++the original message and all replies have the same entry. The subject index ++is used for advanced message retrieval functions. For safety, the subject ++index is created under a temporary name ++inside ++.I dir\fB/archive ++and then moved into place. + + .B ezmlm-manage + will ignore message files without the owner-execute bit set. + .B ezmlm-send + turns on the owner-execute bit after safely writing the message to disk. ++ ++.B ezmlm-make ++by default adds ++.B ezmlm-get ++to ++.I dir\fB/manager ++to handle ++.I \-get, \-index, ++and ++.I \-thread ++requests. If ++.B ezmlm-make ++is invoked with a ++.I digcode ++command line argument, digest creation ++is enabled by putting this argument on the ++.B ezmlm-get ++command line. + .SH BOUNCES + .I dir\fB/bounce + is a directory containing bounce messages. +@@ -127,9 +219,10 @@ + sets up + .I dir\fB/bouncer + to invoke +-.B ezmlm-return +-and then +-.BR ezmlm-warn . ++.BR ezmlm-return . ++.B ezmlm-warn ++is no longer invoked here due to the load it places on systems with many ++large lists with many bounces. + + .I dir\fB/manager + handles incoming administrative requests. +@@ -137,9 +230,266 @@ + sets up + .I dir\fB/manager + to invoke +-.B ezmlm-manage ++.BR ezmlm-get , ++.BR ezmlm-manage , + and then + .BR ezmlm-warn . ++ ++.I dir\fB/moderator ++handles incoming message ++.I accept ++and ++.I reject ++requests for moderated lists. ++.B ezmlm-make ++sets up ++.I dir\fB/moderator ++to invoke ++.BR ezmlm-moderate , ++and .BR ezmlm-clean . ++.SH DIGESTS ++.B ezmlm-get ++can create digests if it is invoked from the command line, from ++.IR dir\fB/editor , ++or from ++.IR dir\fB/manager . ++The program functions in slightly different ways in these 3 settings (see ++.BR ezmlm-get(1) ). ++ ++To enable automatic digests for a mailing list, use the ++.B ezmlm-make \-d ++switch. To also enable the generation of digests at specific times dictated ++by mailed trigger messages, a ++.I digcode ++should be specified on the ++.B ezmlm-get ++command line. ++This can be done by specifying ++.I digcode ++as a fifth argument to ++.B ezmlm-make ++when setting up the list. ++.I digcode ++must be alphanumeric and is case-insensitive. ++ ++To generate trigger messages, use ++.B ezmlm-cron(1) ++as an interface to ++.B crond(8) ++or use ++.B crond ++directly. ++ ++.I dir\fB/num ++contains the number of the last message processed, followed by ':' and a ++number that is increased by 1 for each 256 bytes of message body text ++processed. The latter number is used by ++.B ezmlm-tstdig ++to determine if a new digest is due. ++ ++.I dir\fB/dignum ++contains the contents of ++.I dir\fB/num ++at the time of the last regular digest creation, followed by a ':', ++followed by a timestamp. ++It is updated after each regular digest is sent. ++ ++.I dir\fB/digissue ++contains the issue number of the last regular digest. It is incremented ++for each regular digest sent. ++ ++The following user crontab entry (all on one line) ++generates a digest of the list ++.I list@host.domain ++at 1600 every day: ++ ++.EX ++ 00 16 * * * /var/qmail/bin/qmail-inject list-dig.digcode ++.EE ++ ++Alternatively, ++.B ezmlm-cron ++can be used: ++ ++.EX ++ % ezmlm-cron -t 16:00 list@host digcode ++.EE ++ ++.B ezmlm-get ++can also be run from the shell: To generate a digest to ++.I list-digest@host ++from the list housed in ++.IR ~joe/list : ++ ++.EX ++ % ezmlm-get ~joe/list ++.EE ++ ++Like other ++.B ezmlm-get ++replies, digest can be sent in several formats. See ++.B ezmlm-get(1) ++for more info. ++.SH MODERATION ++There are three aspects of moderation: moderation of posts, moderation ++of subscriptions, and "remote administration", i.e. giving the ++moderator the right to (un)subscribe any user. ++.B ezmlm ++handles these three aspects separately. The two first aspects enhance ++security, while the third decreases security, but makes list administration ++considerably easier. By default, the moderator database is the same for all ++three functions. While "remote administration" and subscription moderation ++always use the same database, the moderators for message moderation can ++be different. ++ ++Even with subscription moderation, the user has to verify the request. This ++is to ensure that the user initiating the request really controls the address. ++.B ezmlm-manage ++options exist to disable the user handshake, which may be useful in some ++circumstances. ++ ++For moderation options, the moderators are by stored in a subscriber ++list in ++.IR moddir\fB/subscribers . ++By default ++.I moddir ++is ++.IR dir\fB/mod . ++ ++Moderators can be added and removed with: ++ ++.EX ++.B ezmlm-sub ++.I moddir ++.I moderator@host ++.EE ++ ++.EX ++.B ezmlm-unsub ++.I moddir ++.I moderator@host ++.EE ++ ++For subscription moderation, touch ++.IR dir\fB/modsub ++after adding moderator(s). ++For remote administration, touch ++.IR dir\fB/remote . ++If the contents of these files start with a leading forward slash, it is ++assumed to be the name of ++.B moddir ++subscription ++moderation. If both files exist and start with a forward slash, the ++.I dir\fB/remote ++contents are ignored. Moderators are stored in a subscriber list in the ++.B subscribers ++subdirectory of ++.BR moddir . ++If no directory names are specified, ++the default, ++.IR dir\fB/mod , ++is used. ++In all cases, the ++.I subscribers ++subdirectory of the base directory must exists/be created. ++ ++Moderation of messages is achieved by ++creating ++.I dir\fB/modpost ++and modifying ++.IR dir\fB/editor ++to invoke ++.B ezmlm-store. ++.B ezmlm-store ++stores the message in ++.IR dir\fB/mod/pending ++and sends a moderation request to all moderators stored in ++.IR moddir . ++ ++If ++.I dir\fB/modpost ++does not exist, ++.B ezmlm-store ++posts messages directly, and ++.B ezmlm-clean ++does nothing. ++ ++If ++.I dir\fB/modpost ++contains a directory name starting with a forward slash, ++this directory is used as ++.I moddir ++for message moderation. ++Moderators are stored in a subscriber list in the ++.I subscribers ++subdirectory of ++.IR moddir . ++If no directory names are specified, ++the default, ++.IR dir\fB/mod , ++is used. ++ ++.IR dir\fB/moderator ++is linked to ++.IR dot\fB\-accept-default ++and ++.IR dot\fB\-reject-default . ++It handles replies from the moderators. ++ ++In addition to a moderator list, the directories ++.IR dir\fB/mod/pending , ++.IR dir\fB/mod/accepted , ++and ++.IR dir\fB/mod/rejected ++must exist. These directories contain the message moderation queue. ++ ++If ++.IR dir\fB/mod/modtime ++it determines the minimal time in hours that messages wait in the moderation ++queue, before they are returned to sender with the message in ++.IR dir\fB/text/mod-timeout . ++ ++If a ++.I \-help ++command is send for a moderator and ++.IR dir\fB/modsub ++or ++.IR dir\fB/remote ++exist, a more detailed help message stored in ++.I dir\fB/text/mod-help ++will be sent together with the regular help. This text should not contain ++secrets. ++If ++.I dir\fB/text/mod-help ++does not exist, ++.I dir\fB/text/help ++will be sent. ++ ++If a ++.I \-list ++command is sent for a moderator and ++.IR dir\fB/modsub ++or ++.IR dir\fB/remote ++exist, and the ++.B ezmlm-manage \-l ++command line switch is specified, a subscriber list will be returned. ++ ++If an ++.I \-edit.file ++command is sent for a moderator and ++.IR dir\fB/remote ++exist, and the ++.B ezmlm-manage \-d ++command line switch is specified, ++.B text\fB/file ++is returned together with an ++.B ezmlm ++cookie. The remote administrator may return an edited version of the ++file, which will be stored, provided that the cookie is valid. ++See ++.B ezmlm-manage(1) ++for more info. + .SH TEXT + .I dir\fB/text + is a directory +@@ -187,6 +537,27 @@ + .B get-bad + Rejecting a bad archive retrieval request. + .TP ++.B digest ++Text copied into the ++.I Administrativia ++section of the digest. Usually, this will contain subscription info ++for the digest, as well as information on how to post to the list. ++.TP ++.B trailer ++If this files exists, it is copied to the end of all messages to the list. ++.TP ++.B faq ++Sent in response to the ++.I faq ++command. Usually contains frequently asked questions and answers specific ++for the mailing list. ++.TP ++.B info ++Sent in response to the ++.I info ++command. Usually contains a descripition, policy, etc, for the list. The ++first line should in itself be a very brief description of the list. ++.TP + .B bounce-warn + Pointing out that messages have bounced. + .TP +@@ -198,9 +569,96 @@ + .B ezmlm-return + has kept a list of bounced message numbers. + .TP ++.B dig-bounce-num ++Explaining that digest messages have bounced. All other text files are used ++for both the main list and the digest list. ++.TP + .B bounce-bottom + Separating the bounce message. ++.TP ++.B mod-help ++is set to list moderators issuing a ++.I \-help ++command. It contains instructions for moderators, but it is relatively ++trivial for a non-moderator to read it. Don't put secrets here. ++.TP ++.B mod-reject ++is the returned to the sender of a rejected post. ++.TP ++.B mod-timeout ++is returned if the message timed-out without moderator action. ++.TP ++.B mod-sub ++is added to the text confirming subscription and unsubscription ++instead of ++.B bottom ++and the requesting message, for actions that were approved ++by a moderator. Not copying the requesting message ++hides the moderator identity ++from the subscriber. ++.TP ++.B mod-request ++is the text sent to the moderators to request moderator action on ++a posted message. ++.TP ++.B mod-unsub-confirm ++Requesting that the moderator confirm a request to subscribe. ++If this file does not exist, ++.B sub-confirm ++will be used. ++.TP ++.B mod-unsub-confirm ++Requesting that the moderator confirm a request to unsubscribe. ++If this file does not exist, ++.B unsub-confirm ++will be used. ++.TP ++.B edit-do ++Instructions sent to the remote administrator together with a copy ++of a ++.I dir\fB/text ++file and editing instructions. ++.TP ++.B edit-list ++A list of editable files in ++.I dir\fB/text ++with a one-line description send to a remote administrator in response to a ++.I -edit ++command. ++.TP ++.B edit-done ++Sent to the remote administrator after an edited ++.I dir\fB/text ++file has been successfully saved. ++.PP ++Several tags in the text files are replaced by ezmlm programs. ++All programs replace the tag ++.B <#l#> ++with the name of the list or the list-digest, as appropriate for the request, ++and ++.B <#h#> ++with the hostname for the list. ++.B ezmlm-send ++and ++.B ezmlm-get ++replace ++.B <#n#> ++with the current message number in added headers from ++.I dir\fB/headeradd ++and text files. ++.B ezmlm-get ++does this for digest messages, where the current message is the number of ++the first message in the digest. ++.B ezmlm-manage ++replaces the tag ++.B <#A#> ++anywhere on a line with the subscription address, and ++.B <#R#> ++anywhere on a line ++with the address the subscriber must reply to. Only the first tag on any ++line is processed. + .PP ++For backwards compatibility, + .B ezmlm-manage + replaces the line + .B !A +@@ -213,6 +671,23 @@ + and + .B unsub-confirm + with the address that the subscriber must reply to. ++.PP ++.B ezmlm-store ++replaces the tag ++.B <#A#> ++anywhere on a line with the address for accepting the message, and ++.B <#R#> ++anywhere on a line ++with the address for rejecting the message. ++Only the first tag on any line is processed. ++.PP ++For backwards compatibility, ++.B ezmlm-store ++also replaces the line ++.B !A ++with the address for accepting the message and the line ++.B !R ++with the address for rejecting the message. + .SH "OUTGOING MESSAGE EDITING" + .I dir\fB/headerremove + is a list of bad header field names, +@@ -233,10 +708,61 @@ + is a list of new header fields. + .B ezmlm-send + adds these fields to every outgoing message. +-.B ezmlm-make ++.B ezmlm-send + sets up + .I dir\fB/headeradd +-with no new fields. ++to add ++.B X-No-Archive: yes ++and ++.BR Precedence: bulk . ++ ++If ++.I dir\fB/mimeremove ++exists, ++.B ezmlm-send ++removed parts with the corresponding content-types from composite MIME ++messages. If the ++.B ezmlm-reject ++.I dir ++argument is specified, ++simple MIME messages of these content-types are rejected. ++ ++If ++.I dir\fB/mimereject ++exists, and the ++.B ezmlm-reject ++.I dir ++argument is specified, ++simple MIME messages of these content-types, or ++composite MIME messages with any body part of these content-types are rejected. ++ ++If ++.I dir\fB/sequence ++exists, the first line is added as a header to all outgoing messages, followed ++by a space and the message number. The message number is useful for archive ++retrievals, since some mail systems do not reveal the return-path to the user. ++.B NOTE: ++Sublists have their own message counter. Adding a sequence header from a ++sublists will give you the sublist message number which is different from ++the main list message number. ++ ++.I dir\fB/prefix ++is a subject prefix. If this file exists, its contents are prefixed to the ++subject of the post in the outgoing message. The archived message is not ++processed. Attempts are made to not duplicate an existing prefix in replies. ++Think twice before using this option. ++A prefix takes unnecessary space on the subject line and most mail clients ++can easily filter on other headers, such as 'Mailing-List:'. If ++.I dir\fB/prefix contains a single '#', this will be replaced by the message ++number. The use of this feature is inadvisable and violates internet mail ++standards. However, it is very popular in e.g. Japan. If you must use this ++feature, make sure you are aware that you may be causing problems to users, ++sublists, etc. ++ ++.I dir\fB/text/trailer ++is a message trailer. If this file exists, it's contents are copied to the ++end of outgoing messages. Only lines terminated with new-line are copied. ++No trailer is copied to the archived version of the message. + .SH MISCELLANY + The first line of + .I dir\fB/mailinglist +@@ -248,6 +774,27 @@ + .IR dir\fB/mailinglist , + in every outgoing message. + ++If ++.I dir\fB/listid ++exists, ++ezmlm programs create a new ++.B List-ID ++field, showing the contents of the first line of ++.IR dir\fB/listid , ++in every outgoing message. The list-id should be unique and within name ++space controlled by the owner. It should remain constant even if lists ++move and be of the format ++ ++.EX ++List-ID: optional_text ++.EE ++ ++This header would result from a ++.I dir\fB/listid ++file containing ``optional_text ''. 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 = dsnline.len) break; ++ if (case_startb(dsnline.s + i,dsnline.len - i,"report-type=")) { ++ i += 12; ++ while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t' || dsnline.s[i] =='"') ++ if (++i >= dsnline.len) break; ++ if (case_startb(dsnline.s + i,dsnline.len - i,"delivery-status")) ++ flagdsn = 1; ++ } else if (case_startb(dsnline.s + i,dsnline.len - i,"boundary=")) { ++ i += 9; ++ while (dsnline.s[i] ==' ' || dsnline.s[i] =='\t') ++ if (++i >= dsnline.len) break; ++ if (dsnline.s[i] == '"') { ++ if (++i >= dsnline.len) break; ++ j = i + byte_chr(dsnline.s + i,dsnline.len - i,'"'); ++ if (j >= dsnline.len) break; ++ } else { ++ j = i; ++ while (dsnline.s[j] !=' ' && dsnline.s[j] !='\t' && ++ dsnline.s[j] !=';') ++ if (++j >= dsnline.len) break; ++ } /* got boundary */ ++ if (!stralloc_copyb(&boundary,dsnline.s+i,j-i)) die_nomem(); ++ } ++ } ++ } ++ if (flagdsn && boundary.len) { /* parse DSN message */ ++ get(&line); /* if bad format we exit(0) via get() */ ++ for (;;) { ++ if (isboundary()) { ++ if (line.len == boundary.len + 5 && line.s[line.len - 1] == '-' ++ && line.s[line.len - 2] == '-') ++ _exit(99); /* end: not failure report */ ++ get(&line); /* Content-type */ ++ if (case_startb(line.s,line.len,"content-type:")) { ++ i = 13; ++ while (line.s[i] == ' ' || line.s[i] == '\t') ++ if (++i >= line.len) break; ++ if (case_startb(line.s+i,line.len-i,"message/delivery-status")) { ++ for (;;) { ++ get(&line); ++ if (isboundary()) break; ++ if (case_startb(line.s,line.len,"action:")) { ++ i = 8; ++ while (line.s[i] == ' ' || line.s[i] == '\t') ++ if (++i >= line.len) break; ++ if (case_startb(line.s + i, line.len - i,"failed")) ++ _exit(0); /* failure notice */ ++ else ++ _exit(99); /* there shouldn't be more than 1 action */ ++ } ++ } ++ } ++ } ++ } else ++ get(&line); ++ } + } + + get(&line1); +--- ezmlm-weed.1 1999/08/01 16:45:46 1.1 ++++ ezmlm-weed.1 1999/12/19 16:53:18 1.3 +@@ -7,6 +7,8 @@ + .B ezmlm-weed + reads a mail message from its standard input. + If it recognizes the message as an MTA warning message or success message, ++or as a message with precedence ``bulk'' or ``junk'' as generated by ++vacation autoresponders, + it exits 99; + this will cause + .B qmail-alias +@@ -33,6 +35,13 @@ + Subject: deferral notice + .EE + ++Delivery-status notification (DSN, rfc1891). All DSN messages with ``Action'' ++other than ``failed'': ++ ++.EX ++ Content-type: multipart/report ++.EE ++ + Warning message from sendmail, MIME form: + + .EX +@@ -104,6 +113,21 @@ + .EX + THIS IS A WARNING MESSAGE ONLY + .EE ++ ++Notification messages from Novell Groupwise: ++ ++.EX ++ Subject: Message status - delivered ++.EE ++.br ++.EX ++ Subject: Message status - opened ++.EE ++.br ++.EX ++ Subject: Out of Office AutoReply: ++.EE ++ + .SH "SEE ALSO" + ezmlm-return(1), + qmail-command(8) diff --git a/idxthread.c b/idxthread.c new file mode 100644 index 0000000..b8ed2b0 --- /dev/null +++ b/idxthread.c @@ -0,0 +1,682 @@ +/*$Id: idxthread.c,v 1.35 1999/11/22 01:47:45 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +/* idxthread.c contains routines to from the ezmlm-idx subject index build */ +/* a structure of unique subjects as well as a table of messages with */ +/* pointers to the subject. This leads to information on message threads */ +/* arranged chronologically within the thread, and with the threads */ +/* arranged chronologically by the first message within the range. */ +/* idx_mkthreads() will arrange the author list in a similar manner. This */ +/* saves some space, and takes a little extra time. It's needed when */ +/* generating an author index. */ + +#include +#include +#include "error.h" +#include "alloc.h" +#include "str.h" +#include "stralloc.h" +#include "strerr.h" +#include "lock.h" +#include "idx.h" +#include "errtxt.h" +#include "substdio.h" +#include "fmt.h" +#include "readwrite.h" +#include "makehash.h" +#include "yyyymm.h" + +#define DATENO 100 +static stralloc line = {0}; /* primary input */ +static stralloc authline = {0}; /* second line of primary input */ +static stralloc dummyind = {0}; + +static substdio ssindex; +static char indexbuf[1024]; + +static char strnum[FMT_ULONG]; + +struct stat st; + /* if no data, these may be the entire table, so */ + /* need to be static */ +static subentry sdummy; +static authentry adummy; + + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +int fdlock; + +/* NOTE: These do NOT prevent double locking */ +static void lockup(fatal) +char *fatal; +{ + fdlock = open_append("lock"); + if (fdlock == -1) + strerr_die2sys(111,fatal,ERR_OPEN_LOCK); + if (lock_ex(fdlock) == -1) { + close(fdlock); + strerr_die2sys(111,fatal,ERR_OBTAIN_LOCK); + } +} + +static void unlock() +{ + close(fdlock); +} + +static void newsub(psubt,subject,sublen,msg,fatal) +/* Initializes subentry pointed to by psubt, adds a '\0' to subject, */ +/* allocates space and copies in subject, and puts a pointer to it in */ +/* the entry. */ +subentry *psubt; +char *subject; +unsigned int sublen; +unsigned long msg; +char *fatal; +{ + register char *cpfrom, *cpto; + register unsigned int cpno; + + psubt->higher = (subentry *) 0; + psubt->lower = (subentry *) 0; + psubt->firstmsg = msg; + psubt->lastmsg = msg; + psubt->msginthread = 1; + if (!(psubt->sub = alloc ((sublen) * sizeof(char)))) + die_nomem(fatal); + cpto = psubt->sub; + cpno = sublen; + cpfrom = subject; + while (cpno--) *(cpto++) = *(cpfrom++); + psubt->sublen = sublen; +} + +static void newauth(pautht,author,authlen,msg,fatal) +/* Allocates space for author of length authlen+1 adding a terminal '\0' */ +/* and puts the pointer in pautht->auth. Analog to newsub(). */ +authentry *pautht; /* entry for current message */ +char *author; /* pointer to author string (not sz!) */ +unsigned int authlen; /* lenth of author */ +unsigned long msg; +char *fatal; /* sz */ + +{ + register char *cpfrom, *cpto; + register unsigned int cpno; + + pautht->higher = (subentry *) 0; + pautht->lower = (subentry *) 0; + pautht->firstmsg = msg; + if (!(pautht->auth = alloc ((authlen) * sizeof(char)))) + die_nomem(fatal); + cpto = pautht->auth; + cpno = authlen; + cpfrom = author; + while (cpno--) *(cpto++) = *(cpfrom++); + pautht->authlen = authlen; +} + +static void init_dummy(fatal) +char *fatal; +{ + unsigned int i; + + if (!stralloc_ready(&dummyind,HASHLEN + 1)) die_nomem(fatal); + for (i = 0; i< HASHLEN; i++) + dummyind.s[i] = 'a'; + dummyind.len = HASHLEN; + if (!stralloc_append(&dummyind," ")) die_nomem(fatal); +} + +void idx_mkthreads(pmsgtable,psubtable,pauthtable,pdatetable, + msg_from,msg_to,msg_latest,locked,fatal) +/* Threads messages msg_from -> msg_to into pmsgtable & psubtable. When */ +/* reading the latest index file (containing msg_latest) it locks the */ +/* directory, unless it is already locked (as in digest creation). */ +/* msgtable has the subject number 1.. (0 if there is no subject match, */ +/* which should happen only if the subject index is corrupt.) */ + +/* 19971107 Changed to deal with index files that are missing, or have */ +/* missing entries, not necessarily reflecting missing archive files. */ +/* This all to make ezmlm-get more robust to get maximal info out of */ +/* corrupted archives. */ + + msgentry **pmsgtable; /* table of message<->subject */ + subentry **psubtable; /* subject no, len, str char * */ + authentry **pauthtable; /* author no, len, str char * */ + dateentry **pdatetable; /* message per date */ + unsigned long msg_from; /* first message in range */ + unsigned long msg_to; /* last message in range */ + unsigned long msg_latest; /* latest message in archive (for locking) */ + int locked; /* if already locked */ + char *fatal; /* Program-specific */ + +{ + unsigned long idxlatest; /* need to lock for this (last) index file */ + unsigned long msg; /* current msg number */ + unsigned long endmsg; /* max msg in this idx file */ + unsigned long tmpmsg; /* index entry's msg number */ + unsigned long idx; /* current index file no */ + unsigned long idxto; /* index containing end of range */ + unsigned long ulmrange; /* total # of messages in range */ + char *subject; /* subject on line */ + unsigned int sublen; /* length of subject */ + char *auth; + unsigned int authlen; + unsigned int pos,posa; + unsigned long submax; /* max subject num in subtable */ + subentry *psubnext; /* points to next entry in subtable */ + subentry *psubt; /* points to entry in subtable */ + authentry *pauthnext; /* points to next entry in authtable */ + authentry *pautht; /* points to entry in authtable */ + int fd; /* index file handle */ + int flagmissingindex; /* current index file is missing */ + int flagauth; /* read index entry has author info */ + int hasauth; /* current msg's entry has author info */ + msgentry *pmsgt; + int res; + int match; + unsigned int datepos,datemax; + unsigned int datetablesize,datetableunit; + unsigned int lastdate = 0; + unsigned int thisdate; + register msgentry *x, *y; + + /* a few unnecessary sanity checks */ + if (msg_to > msg_latest) + msg_to = msg_latest; + if (msg_to < msg_from) + strerr_die2x(100,fatal,"Program error: bad range in idx_mkthreads"); + ulmrange = msg_to - msg_from + 1; + if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry)))) + die_nomem(fatal); + y = *pmsgtable; + x = y + ulmrange; /* clear */ + while (--x >= y) { + x->subnum = 0; + x->authnum = 0; + x->date = 0; + } + /* max entries - acceptable waste for now */ + if (!(*psubtable = (subentry *) alloc((ulmrange+1) * sizeof(subentry)))) + die_nomem(fatal); + + if (!(*pauthtable = (authentry *) alloc((ulmrange+1) * sizeof(authentry)))) + die_nomem(fatal); + datetableunit = DATENO * sizeof(dateentry); + datetablesize = datetableunit; + if (!(*pdatetable = (dateentry *) alloc(datetablesize))) + die_nomem(fatal); + datepos = 0; + datemax = DATENO - 2; /* entry 0 and end marker */ + lastdate = 0; + + idxlatest = msg_latest / 100; + idxto = msg_to / 100; + submax = 0; + psubnext = *psubtable; /* dummy node to get tree going. Basically, */ + psubt = &sdummy; /* assure that subject > psubt-sub and that */ + init_dummy(fatal); /* below ok unless HASHLEN > 40 */ + psubt->sub = " "; + psubt->sublen = 40; /* there is something to hold psubt->higher */ + psubt->higher = (subentry *) 0; + psubt->lower = (subentry *) 0; + pauthnext = *pauthtable; + pautht = &adummy; + pautht->auth = psubt->sub; + pautht->authlen = psubt->sublen; + pautht->higher = (authentry *) 0; + pautht->lower = (authentry *) 0; + for (idx = msg_from / 100; idx <= idxto; idx++) { + /* make index file name */ + if (!stralloc_copys(&line,"archive/")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal); + if (!stralloc_cats(&line,"/index")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + if (!locked && idx == idxlatest) + lockup(fatal); + flagmissingindex = 0; + fd = open_read(line.s); + if (fd == -1) { + if (errno == error_noent) { /* this means the index is not here */ + /* but the lists is supposedly indexed*/ + flagmissingindex = 1; + } else + strerr_die4sys(111,fatal,ERR_OPEN,line.s,": "); + } else + substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf)); + + msg = 100L * idx; /* current msg# */ + endmsg = msg + 99L; /* max msg in this index */ + if (!msg) msg = 1L; /* for start to make msg > tmpmsg */ + tmpmsg = 0L; /* msg number of read index line */ + if (endmsg > msg_to) /* skip non-asked for subjects */ + endmsg = msg_to; + for (; msg <= endmsg; msg++) { + if (!flagmissingindex && (msg > tmpmsg)) { + flagauth = 0; + if (getln(&ssindex,&line,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_READ,"index: "); + if (!match) + flagmissingindex = 1; + else { + pos = scan_ulong(line.s,&tmpmsg); + if (line.s[pos++] == ':') { + if (getln(&ssindex,&authline,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_READ,"index: "); + if (!match) + flagmissingindex = 1; + else { + flagauth = 1; + } + pos++; + } + } + } + if (msg < msg_from) /* Nothing before start of range */ + continue; + if (msg == tmpmsg) { + subject = line.s + pos; + sublen = line.len - pos; + if (sublen <= HASHLEN) + strerr_die2x(100,fatal,ERR_BAD_INDEX); + hasauth = flagauth; + } else { + subject = dummyind.s; + sublen = dummyind.len; + hasauth = 0; + } + for(;;) { /* search among already known subjects */ + res = str_diffn(psubt->sub,subject,HASHLEN); + if (res < 0) { + if (psubt->higher) + psubt = psubt->higher; + else { + newsub(psubnext,subject,sublen,msg,fatal); + psubt->higher = psubnext; + psubt = psubnext; + psubnext++; + break; + } + } else if (res > 0) { + if (psubt->lower) + psubt = psubt->lower; + else { + newsub(psubnext,subject,sublen,msg,fatal); + psubt->lower = psubnext; + psubt = psubnext; + psubnext++; + break; + } + } else { + psubt->lastmsg = msg; + (psubt->msginthread)++; /* one more message in thread */ + break; + } + } + /* first subnum =1 (=0 is empty for thread) */ + pmsgt = *pmsgtable + msg - msg_from; + pmsgt->subnum = (unsigned int) (psubt - *psubtable + 1); + pmsgt->date = lastdate; + if (hasauth) { + pos = 0; + while (authline.s[pos] && authline.s[pos] != ' ') pos++; + if (authline.s[++pos]) { + thisdate = date2yyyymm(authline.s + pos); + if (thisdate) pmsgt->date = thisdate; + if (pmsgt->date > lastdate) { + lastdate = pmsgt->date; + if (datepos >= datemax) { /* more space */ + datemax += DATENO; + if (!(*pdatetable = (dateentry *) alloc_re(*pdatetable, + datetablesize,datetablesize+datetableunit))) + die_nomem(fatal); + } + (*pdatetable)[datepos].msg = msg; /* first msg this mo */ + (*pdatetable)[datepos].date = lastdate; + datepos++; + } + posa = byte_chr(authline.s,authline.len,';'); + if (authline.len > posa + HASHLEN + 1 && authline.s[pos+1] != ' ') { + /* old: "; auth", new: ";hash auth" */ + auth = authline.s + posa + 1; + authlen = authline.len - posa - 1; + } else { + auth = dummyind.s; + authlen = dummyind.len; + } + } + /* allright! Same procedure, but for author */ + for (;;) { /* search among already known authors */ + res = str_diffn(pautht->auth,auth,HASHLEN); + if (res < 0) { + if (pautht->higher) + pautht = pautht->higher; + else { + newauth(pauthnext,auth,authlen,msg,fatal); + pautht->higher = pauthnext; + pautht = pauthnext; + pauthnext++; + break; + } + } else if (res > 0) { + if (pautht->lower) + pautht = pautht->lower; + else { + newauth(pauthnext,auth,authlen,msg,fatal); + pautht->lower = pauthnext; + pautht = pauthnext; + pauthnext++; + break; + } + } else { + break; + } + } /* link from message to this author */ + pmsgt->authnum = (unsigned int) (pautht - *pauthtable + 1); + pautht = *pauthtable; + } + + psubt = *psubtable; /* setup psubt. Done here rather than before */ + /* the for loop, so that we can start off */ + /* the dummy node. */ + } + if (fd != -1) + close(fd); + if (!locked && idx == idxlatest) + unlock(); /* 'locked' refers to locked before calling */ + } + psubnext->sub = (char *) 0; /* end of table marker */ + pauthnext->auth = (char *) 0; /* end of table marker */ + (*pdatetable)[datepos].msg = msg_to + 1; + (*pdatetable)[datepos].date = lastdate + 1; +} + + +void idx_mkthread(pmsgtable,psubtable,pauthtable,msg_from,msg_to,msg_master, + msg_latest,locked,fatal) +/* Works like idx_mkthreads, except that it finds the subject for message */ +/* msg_master, then identifies messages in the range that have the same */ +/* subject. msgtable entries with subject 0 do not match, with '1' do match.*/ + +msgentry **pmsgtable; /* pointer to table of message<->subject */ +subentry **psubtable; /* ptr to tbl of subject no, len, str char * */ +authentry **pauthtable; +unsigned long msg_from; /* first message in range */ +unsigned long msg_to; /* last message in range */ +unsigned long msg_latest; /* latest message in archive (for locking) */ +unsigned long msg_master; /* master message for single thread, else 0*/ +int locked; /* if already locked */ +char *fatal; /* Program-specific */ + +{ + unsigned long idxlatest; /* need to lock for this (last) index file */ + unsigned long idxto; /* index for last msg in range */ + unsigned long idx; /* current index file no */ + unsigned long msg; /* index entry's msg number */ + unsigned long ulmrange; /* total # of messages in range */ + subentry *psubt; /* points to last entry in subtable */ + int ffound; /* msg subject was found in subtable */ + int flagauth; /* there is author info */ + int firstfound = 1; /* = 1 until first message in thread found */ + int res; /* comparison result */ + char *auth; + unsigned int authlen; + authentry *pauthnext; /* points to next entry in authtable */ + authentry *pautht; /* points to entry in authtable */ + unsigned int pos; + int fd; /* index file handle */ + int match; + msgentry *pmsgt; + register msgentry *x,*y; + + if ((ulmrange = msg_to - msg_from +1) <= 0) + strerr_die2x(100,fatal,"Program error: bad range in idx_mkthreads"); + if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry)))) + die_nomem(fatal); + y = *pmsgtable; + x = y + ulmrange; + while (--x >= y) { + x->subnum = 0; + x->authnum = 0; + x->date = 0; + } + + if (!(*psubtable = (subentry *) alloc(2 * sizeof(subentry)))) + die_nomem(fatal); + + if (!(*pauthtable = (authentry *) alloc((ulmrange + 1) * sizeof(authentry)))) + die_nomem(fatal); + + pauthnext = *pauthtable; + pautht = &adummy; + init_dummy(); + pautht->auth = " "; + pautht->authlen = 21; + pautht->higher = (authentry *) 0; + pautht->lower = (authentry *) 0; + idxlatest = msg_latest / 100; + idxto = msg_to / 100; + idx = msg_master / 100; /* index for master subject */ + + /* Get master subject */ + if (!stralloc_copys(&line,"archive/")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal); + if (!stralloc_cats(&line,"/index")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + ffound = 0; + if (!locked && idx == idxlatest) + lockup(fatal); + fd = open_read(line.s); + psubt = *psubtable; + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,line.s,": "); + else + strerr_die2x(111,fatal,ERR_NOINDEX); /* temp - admin can fix! */ + } else { + substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf)); + for(;;) { + if (getln(&ssindex,&line,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_OPEN,"index: "); + if (!match) + break; + pos=scan_ulong(line.s,&msg); + if (line.s[pos++] == ':') { /* marker for author info */ + pos++; + flagauth = 1; + } else + flagauth = 0; + if (msg == msg_master) { + newsub(psubt,line.s+pos,line.len-pos,msg,fatal); + /* need to update msg later! */ + ffound = 1; + break; + } + if (flagauth) { /* skip author line */ + if (getln(&ssindex,&line,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_OPEN,"index: "); + if (!match) + break; + } + } + close(fd); + } + if (!locked && idx == idxlatest) + unlock(); + if (!ffound) + strerr_die2x(100,fatal,ERR_NOINDEX); + for (idx = msg_from / 100; idx <= idxto; idx++) { + /* make index file name */ + if (!stralloc_copys(&line,"archive/")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,idx))) die_nomem(fatal); + if (!stralloc_cats(&line,"/index")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + if (!locked && idx == idxlatest) + lockup(fatal); + fd = open_read(line.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,line.s,": "); + } else { + substdio_fdbuf(&ssindex,read,fd,indexbuf,sizeof(indexbuf)); + for(;;) { + if (getln(&ssindex,&line,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_READ,"index: "); + if (!match) + break; + pos=scan_ulong(line.s,&msg); + if (line.s[pos++] == ':') { + pos++; + flagauth = 1; + if (getln(&ssindex,&authline,&match,'\n') == -1) + strerr_die3sys(111,fatal,ERR_READ,"index: "); + if (!match) + break; + } else + flagauth = 0; + if (msg < msg_from) /* Nothing before start of range */ + continue; + if (msg > msg_to) /* Don't do anything after range */ + break; + if (!str_diffn(psubt->sub,line.s+pos,HASHLEN)) { + pmsgt = *pmsgtable + msg - msg_from; + if (firstfound) { /* update to first message with this subj */ + psubt->firstmsg = msg; + firstfound = 0; + } + psubt->lastmsg = msg; + pmsgt->subnum = 1; + if (flagauth) { + if (*authline.s) + pmsgt->date = date2yyyymm(authline.s + 1); + pos = byte_chr(authline.s,authline.len,';'); + if (authline.len > pos + HASHLEN + 1 && authline.s[pos+1] != ' ') { + /* old: "; auth", new: ";hash auth" */ + auth = authline.s + pos + 1; + authlen = authline.len - pos - 1; + } else { + auth = dummyind.s; + authlen = dummyind.len; + } + for (;;) { /* search among already known authors */ + res = str_diffn(pautht->auth,auth,HASHLEN); + if (res < 0) { + if (pautht->higher) + pautht = pautht->higher; + else { + newauth(pauthnext,auth,authlen,msg,fatal); + pautht->higher = pauthnext; + pautht = pauthnext; + pauthnext++; + break; + } + } else if (res > 0) { + if (pautht->lower) + pautht = pautht->lower; + else { + newauth(pauthnext,auth,authlen,msg,fatal); + pautht->lower = pauthnext; + pautht = pauthnext; + pauthnext++; + break; + } + } else { + break; + } + } /* link from message to this author */ + pmsgt->authnum = (unsigned int) (pautht - *pauthtable + 1); + pautht = *pauthtable; + } + + } + } + close(fd); + } + if (!locked && idx == idxlatest) + unlock(); + } + ++psubt; + psubt->sub = (char *) 0; /* end of table marker */ + pauthnext->auth = (char *) 0; /* end of table marker */ +} + +void idx_mklist(pmsgtable,psubtable,pauthtable,msg_from,msg_to,fatal) +/* Like mkthreads, except that it works without a subject index. The result */ +/* is just a dummy subject and a sequential list of messages. This to allow */ +/* use of the same routines when creating digest from lists that have no */ +/* subject index (for whatever reason). */ +msgentry **pmsgtable; /* pointer to table of message<->subject */ +subentry **psubtable; /* ptr to tbl of subject no, len, str char * */ +authentry **pauthtable; +unsigned long msg_from; /* first message in range */ +unsigned long msg_to; /* last message in range */ +char *fatal; /* Program-specific */ +{ + unsigned long ulmrange; + register msgentry *x,*y; + subentry *psubt; + authentry *pautht; + + if ((ulmrange = msg_to - msg_from +1) <= 0) + strerr_die2x(111,fatal,"bad range in idx_mkthreads :"); + + if (!(*pmsgtable = (msgentry *) alloc(ulmrange * sizeof(msgentry)))) + die_nomem(fatal); + + y = *pmsgtable; + x = y + ulmrange; + while (--x >= y) { + x->subnum = 1; + x->authnum = 0; + x->date = 0; + } + + if (!(*psubtable = (subentry *) alloc(2 * sizeof(subentry)))) + die_nomem(fatal); + psubt = *psubtable; + newsub(psubt,dummyind.s,dummyind.len,msg_from,fatal); + psubt->lastmsg = msg_to; + ++psubt; + psubt->sub = (char *) 0; + if (!(*pauthtable = (authentry *) alloc(sizeof(authentry)))) + die_nomem(fatal); /* nodata. Avoid dangling ptr. */ + pautht = *pauthtable; + pautht->auth = 0; /* tells app that there are no author data */ + pautht->higher = (authentry *) 0; + pautht->lower = (authentry *) 0; +} + +void idx_destroythread(msgtable,subtable,authtable) +/* Frees space allocated by idxthread routines. This is needed only if */ +/* one does several threadings in one program run. Otherwise, exit() */ +/* should free all allocated memory, which will be faster. */ +msgentry *msgtable; subentry *subtable; authentry *authtable; +{ + subentry *psubt; + authentry *pautht; + + psubt = subtable; /* free subjects */ + while(psubt->sub) { + alloc_free(psubt->sub); + psubt++; + } + + pautht = authtable; /* free authors */ + while(pautht->auth) { + alloc_free(pautht->auth); + pautht++; + } + + alloc_free(subtable); /* free subtable */ + alloc_free(authtable); /* free authtable */ + alloc_free(msgtable); /* free msgtable */ + subtable = (subentry *) 0; /* kill pointers */ + authtable = (authentry *) 0; + msgtable = (msgentry *) 0; +} diff --git a/idxthread.h b/idxthread.h new file mode 100644 index 0000000..dc7ff4d --- /dev/null +++ b/idxthread.h @@ -0,0 +1,11 @@ + +#ifndef IDXTHREAD_H +#define IDXTHREAD_H + +/* threading */ +extern void idx_mkthread(); +extern void idx_mkthreads(); +extern void idx_mklist(); +extern void idx_destroythread(); + +#endif diff --git a/issub.c b/issub.c deleted file mode 100644 index 81ab6ad..0000000 --- a/issub.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "stralloc.h" -#include "getln.h" -#include "readwrite.h" -#include "substdio.h" -#include "open.h" -#include "byte.h" -#include "case.h" -#include "lock.h" -#include "error.h" -#include "issub.h" -#include "uint32.h" - -static stralloc addr = {0}; -static stralloc line = {0}; -static stralloc fn = {0}; -static int fd; -static substdio ss; -static char ssbuf[256]; - -static int doit(userhost) -char *userhost; -{ - int j; - uint32 h; - char ch; - int match; - - if (!stralloc_copys(&addr,"T")) return -2; - if (!stralloc_cats(&addr,userhost)) return -2; - - j = byte_rchr(addr.s,addr.len,'@'); - if (j == addr.len) return 0; - case_lowerb(addr.s + j + 1,addr.len - j - 1); - - h = 5381; - for (j = 0;j < addr.len;++j) - h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; - ch = 64 + (h % 53); - - if (!stralloc_0(&addr)) return -2; - - if (!stralloc_copys(&fn,"subscribers/")) return -2; - if (!stralloc_catb(&fn,&ch,1)) return -2; - if (!stralloc_0(&fn)) return -2; - - fd = open_read(fn.s); - if (fd == -1) { - if (errno != error_noent) return -3; - return 0; - } - substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); - - for (;;) { - if (getln(&ss,&line,&match,'\0') == -1) { close(fd); return -3; } - if (!match) break; - if (line.len == addr.len) - if (!byte_diff(line.s,line.len,addr.s)) { close(fd); return 1; } - } - - close(fd); - return 0; -} - -struct strerr issub_err; - -int issub(userhost) -char *userhost; -{ - int fdlock; - int r; - - fdlock = open_append("lock"); - if (fdlock == -1) - STRERR_SYS(-1,issub_err,"unable to open lock: ") - if (lock_ex(fdlock) == -1) { - close(fdlock); - STRERR_SYS(-1,issub_err,"unable to obtain lock: ") - } - - r = doit(userhost); - close(fdlock); - - if (r == -2) STRERR(-1,issub_err,"out of memory") - if (r == -3) STRERR_SYS3(-1,issub_err,"unable to read ",fn.s,": ") - - return r; -} diff --git a/issub.c b/issub.c new file mode 120000 index 0000000..8d7ce9e --- /dev/null +++ b/issub.c @@ -0,0 +1 @@ +sub_std/issub.c \ No newline at end of file diff --git a/log.c b/log.c index 15e732e..bf3c7a3 100644 --- a/log.c +++ b/log.c @@ -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 @@ char *addr; 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); diff --git a/logmsg.c b/logmsg.c new file mode 120000 index 0000000..e540bca --- /dev/null +++ b/logmsg.c @@ -0,0 +1 @@ +sub_std/logmsg.c \ No newline at end of file diff --git a/makehash.c b/makehash.c new file mode 100644 index 0000000..efa4971 --- /dev/null +++ b/makehash.c @@ -0,0 +1,136 @@ +/*Id:$*/ +/*Name:$*/ + +#include "stralloc.h" +#include "surf.h" +#include "uint32.h" +#include "makehash.h" + +typedef struct { + uint32 seed[32]; + uint32 sum[8]; + uint32 out[8]; + uint32 in[12]; + int todo; +} surfpcs; + +#define SURFPCS_LEN 32 + +static void surfpcs_init(s,k) +surfpcs *s; +uint32 k[32]; +{ + int i; + for (i = 0;i < 32;++i) s->seed[i] = k[i]; + for (i = 0;i < 8;++i) s->sum[i] = 0; + for (i = 0;i < 12;++i) s->in[i] = 0; + s->todo = 0; +} + +static uint32 littleendian[8] = { + 50462976, 117835012, 185207048, 252579084, + 319951120, 387323156, 454695192, 522067228 +} ; +#define end ((unsigned char *) littleendian) + +#define data ((unsigned char *) s->in) +#define outdata ((unsigned char *) s->out) + +static void surfpcs_addlc(s,x,n) + /* modified from Dan's surfpcs_add by skipping ' ' & '\t' and */ + /* case-independence */ +surfpcs *s; +unsigned char *x; +unsigned int n; +{ + register unsigned char ch; + int i; + while (n--) { + ch = *x++; + if (ch == ' ' || ch == '\t') continue; + if (ch >= 'A' && ch <= 'Z') + data[end[s->todo++]] = ch - 'A' + 'a'; + else + data[end[s->todo++]] = ch; + if (s->todo == 32) { + s->todo = 0; + if (!++s->in[8]) + if (!++s->in[9]) + if (!++s->in[10]) + ++s->in[11]; + surf(s->out,s->in,s->seed); + for (i = 0;i < 8;++i) + s->sum[i] += s->out[i]; + } + } +} + +static void surfpcs_out(s,h) +surfpcs *s; +unsigned char h[32]; +{ + int i; + surfpcs_addlc(s,".",1); + while (s->todo) surfpcs_addlc(s,"",1); + for (i = 0;i < 8;++i) s->in[i] = s->sum[i]; + for (;i < 12;++i) s->in[i] = 0; + surf(s->out,s->in,s->seed); + for (i = 0;i < 32;++i) h[i] = outdata[end[i]]; +} + +void makehash(indata,inlen,hash) +char *indata; +unsigned int inlen; +char *hash; + /* makes hash[COOKIE=20] from stralloc *indata, ignoring case and */ + /* SPACE/TAB */ +{ + unsigned char h[32]; + surfpcs s; + uint32 seed[32]; + int i; + + for (i = 0;i < 32;++i) seed[i] = 0; + surfpcs_init(&s,seed); + surfpcs_addlc(&s,indata,inlen); + surfpcs_out(&s,h); + for (i = 0;i < 20;++i) + hash[i] = 'a' + (h[i] & 15); +} + +static stralloc dummy = {0}; + +void mkauthhash(s,len,h) +char *s; unsigned int len; char *h; +/* This is a string that should be the same for all messages from a given */ +/* author. Doesn't have to be the real rfc822 address. We look for a '@' */ +/* and grab everything up to the next '>', ' ', or ';'. We go back the same */ +/* way, then take everything up to the '@' or the first '-'. The latter */ +/* avoids problems with posters that band their addresses. */ +{ + unsigned int i,j,k,l; + register char ch; + + j = k = l = 0; + i = byte_rchr(s,len,'@'); + if (i < len) { /* if not then i=sa->len, j=k=l=0 */ + j = i; + while (++j < len) { /* if not found, then j=sa->len */ + ch = s[j]; + if (ch == '>' || ch == ' ' || ch == ';') break; + } + k = i; + while (k > 0) { /* k <= i */ + ch = s[--k]; + if (ch == '<' || ch == ' ' || ch == ';') break; + } + l = k; /* k <= l <= i; */ + while (l < i && s[l] != '-') ++l; + if (!stralloc_copyb(&dummy,s + k, l - k)) die_nomem(); + if (!stralloc_catb(&dummy,s + i, j - i)) die_nomem(); + makehash(dummy.s,dummy.len,h); + } else /* use entire line if no '@' found */ + makehash(s,len,h); +} + + diff --git a/makehash.h b/makehash.h new file mode 100644 index 0000000..2d947e1 --- /dev/null +++ b/makehash.h @@ -0,0 +1,10 @@ +#ifndef MAKEHASH_H +#define MAKEHASH_H + +#define HASHLEN 20 + +extern void makehash(); +extern void mkauthhash(); + +#endif + diff --git a/mime.h b/mime.h new file mode 100644 index 0000000..27626a0 --- /dev/null +++ b/mime.h @@ -0,0 +1,81 @@ +#ifndef MIME_H +#define MIME_H + +#include "stralloc.h" + +extern void decodeQ(); +extern void decodeB(); +extern void encodeQ(); +extern void encodeB(); +extern void decodeHDR(); +extern void concatHDR(); +extern int unfoldHDR(); + +#ifdef WITH_PROTO +extern unsigned int author_name(char **,char *,unsigned int); +#else +extern unsigned int author_name(); +#endif + +/* Characters */ +#define ESC 0x1B +#define SI 0x0F +#define SO 0x0E +/* iso-2022-jp back-to-ascii seq */ +#define TOASCII "\x1B(B" +/* to JP. Last char [B|@] must be added */ +#define TOJP "\x1B$" + +/* iso-2022 SI sequence as string */ +#define TOSI "\x0F" +/* SI \n SO */ +#define SI_LF_SO "\x0F\n\x0E" + +/* in these bit 0 determines the number of bytes (1 or 2) in ss2/ss3 codes */ +/* it is 2 for CN,1 for JP, and they are not used for KR bit 3 for */ +/* iso-2022 */ +#define CS_2022_MASK 0x08 +#define CS_2022_JP 0x08 +#define CS_2022_KR 0xA0 +#define CS_NONE 0 +#define CS_BAD 0xffff + +#define CS_2022_CN 0x09 +/* Other Chinese ones. bit 7 set means MSB of 2-byte seq. No ss2/ss3 consid*/ +#define CS_CN 0x10 + +#define MIME_NONE 0 +#define MIME_APPLICATION_OCTETSTREAM 1 +#define MIME_MULTI 0x80 +#define MIME_MULTI_ALTERNATIVE 0x81 +#define MIME_MULTI_MIXED 0x82 +#define MIME_MULTI_DIGEST 0x83 +#define MIME_MULTI_SIGNED 0x84 + +#define MIME_TEXT 0x40 +#define MIME_TEXT_PLAIN 0x41 +#define MIME_TEXT_HTML 0x42 +#define MIME_TEXT_ENRICHED 0x43 +#define MIME_TEXT_VCARD 0x44 + +#define MIME_MESSAGE 0x20 +#define MIME_MESSAGE_RFC822 0x21 + +#define CTENC_NONE 0 +#define CTENC_QP 1 +#define CTENC_BASE64 2 + +/* this is a linked list of mime type info. */ +typedef struct { + int level; + unsigned int mimetype; + unsigned int ctenc; + unsigned int cs; /* charset flag - expand later */ + void *previous; + void *next; + stralloc boundary; + stralloc charset; + stralloc ctype; +} mime_info; + +#endif diff --git a/opensql.c b/opensql.c new file mode 120000 index 0000000..5a27e82 --- /dev/null +++ b/opensql.c @@ -0,0 +1 @@ +sub_std/opensql.c \ No newline at end of file diff --git a/putsubs.c b/putsubs.c new file mode 120000 index 0000000..79ffb49 --- /dev/null +++ b/putsubs.c @@ -0,0 +1 @@ +sub_std/putsubs.c \ No newline at end of file diff --git a/qmail-qmqpc.tar.gz b/qmail-qmqpc.tar.gz new file mode 100644 index 0000000..4d70ee1 Binary files /dev/null and b/qmail-qmqpc.tar.gz differ diff --git a/qmail-verh.tar.gz b/qmail-verh.tar.gz new file mode 100644 index 0000000..8c8196b Binary files /dev/null and b/qmail-verh.tar.gz differ diff --git a/qmail.c b/qmail.c index 7484331..1ee257b 100644 --- a/qmail.c +++ b/qmail.c @@ -6,18 +6,25 @@ #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]); @@ -28,8 +35,24 @@ struct qmail *qq; close(pie[1]); if (fd_move(0,pim[0]) == -1) _exit(120); if (fd_move(1,pie[0]) == -1) _exit(120); - 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); } @@ -53,11 +76,17 @@ void qmail_fail(qq) struct qmail *qq; void qmail_put(qq,s,len) struct qmail *qq; char *s; int len; { if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1; + 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; @@ -77,27 +106,49 @@ void qmail_to(qq,s) struct qmail *qq; char *s; qmail_put(qq,"",1); } -int qmail_close(qq) +char *qmail_close(qq) struct qmail *qq; { int wstat; + int exitcode; qmail_put(qq,"",1); if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; close(qq->fde); - if (wait_pid(&wstat,qq->pid) != qq->pid) return QMAIL_WAITPID; - if (wait_crashed(wstat)) return QMAIL_CRASHED; - switch(wait_exitcode(wstat)) { - case 0: if (qq->flagerr) return QMAIL_BUG; return 0; - case 112: return QMAIL_USAGE; - case 115: return QMAIL_TOOLONG; - case 103: case 104: case 105: case 106: case 108: return QMAIL_SYS; - case 121: return QMAIL_READ; - case 122: return QMAIL_WRITE; - case 123: return QMAIL_NOMEM; - case 124: return QMAIL_TIMEOUT; - case 120: return QMAIL_EXECSOFT; - default: /* 101 or 102 */ return QMAIL_BUG; + if (wait_pid(&wstat,qq->pid) != qq->pid) + return "Zqq waitpid surprise (#4.3.0)"; + if (wait_crashed(wstat)) + return "Zqq crashed (#4.3.0)"; + exitcode = wait_exitcode(wstat); + + switch(exitcode) { + case 115: /* compatibility */ + case 11: return "Denvelope address too long for qq (#5.1.3)"; + case 31: return "Dmail server permanently rejected message (#5.3.0)"; + case 51: return "Zqq out of memory (#4.3.0)"; + case 52: return "Zqq timeout (#4.3.0)"; + case 53: return "Zqq write error or disk full (#4.3.0)"; + case 0: if (!qq->flagerr) return ""; /* fall through */ + case 54: return "Zqq read error (#4.3.0)"; + case 55: return "Zqq unable to read configuration (#4.3.0)"; + case 56: return "Zqq trouble making network connection (#4.3.0)"; + case 61: return "Zqq trouble in home directory (#4.3.0)"; + case 63: + case 64: + case 65: + case 66: + case 62: return "Zqq trouble creating files in queue (#4.3.0)"; + case 71: return "Zmail server temporarily rejected message (#4.3.0)"; + case 72: return "Zconnection to mail server timed out (#4.4.1)"; + case 73: return "Zconnection to mail server rejected (#4.4.1)"; + case 74: return "Zcommunication with mail server failed (#4.4.2)"; + case 91: /* fall through */ + case 81: return "Zqq internal bug (#4.3.0)"; + case 120: return "Zunable to exec qq (#4.3.0)"; + default: + if ((exitcode >= 11) && (exitcode <= 40)) + return "Dqq permanent problem (#5.3.0)"; + return "Zqq temporary problem (#4.3.0)"; } } diff --git a/qmail.h b/qmail.h index 7864ea1..8906ab0 100644 --- a/qmail.h +++ b/qmail.h @@ -2,35 +2,39 @@ #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 diff --git a/searchlog.c b/searchlog.c new file mode 120000 index 0000000..c6f1952 --- /dev/null +++ b/searchlog.c @@ -0,0 +1 @@ +sub_std/searchlog.c \ No newline at end of file diff --git a/sub_mysql/README b/sub_mysql/README new file mode 100644 index 0000000..28d028e --- /dev/null +++ b/sub_mysql/README @@ -0,0 +1,153 @@ +$Id: README,v 1.3 1999/02/20 20:05:19 lindberg Exp $ +$Name: ezmlm-idx-040 $ +INFORMATION ON BUILDING/USING EZMLM WITH MYSQL SUPPORT + +(c) 1999, Frederik Lindberg, + lindberg@id.wustl.edu + You may use under GPL. + +For information on MySQL, see http://www.tcx.se. + +Most of this information is available in FAQ.idx. + +If you are interested in contributing/testing a subscriber db interface +for another SQL server, please see sub_std/README and the routines here, +and contact lindberg@id.wustl.edu (it may already be in process). See end +of this file for other ways to contribute. + +conf-mysql must be edited to reflect your system. On many systems, you +also need to include ``-lsocket'', as well as change the paths to the +/usr/local equivalents. For the i386.rpm-based systems, you need at +least MySQL-devel to build the files. Look at your mysql docs for more info. + +TABLES USED FOR (My)SQL SUPPORT + +The basic philosophy is that the database can be on any host (if you use +SENDER restrictions, connectivity to the main host is more important than +to the sublists), and you choose the database and "table root" names. The +default database is ``ezmlm'' and the default table root is ``list''. Each +list has a separate table root. Any number of lists can share a database. + +The main list address table is named with the table root only, others have +that name with various suffixes. In the following ``list'' is used as the +table root. + +ADDRESS TABLES +list subscriber addresses +list_slog subscriber address log +list_allow subscriber aliases for posts on SENDER checked lists. +list_allow_slog subscriber log for list_allow +list_deny blacklisted addresses for posts on SENDER checked lists. +list_deny_slog log for list_deny. +list_mod moderator addresses +list_mod_slog log for list_mod +list_digest subscriber log for digest list. +list_digest_slog log for list_digest + +MESSAGE LOGGING TABLES +list_cookie message cookie table for main list +list_mlog message logging table for main list +list_digest_cookie message cookie table for digest list +list_digest_mlog message logging table for digest list + +SUBLIST SPLIT TABLES +list_name sublist split table for main list +list_digest_name sublist split table for digest list. + + +ezmlm-mktab(1) is a script that outputs the table definintions. Look at +the output for a detailed field description. + +The address tables contain (address,domain,hash,h,num). For normal +lists only the address field is used. For main->sublist clusters, the other +fields are used for load splitting. The domain is the first up to 3 characters +of the last part of the domain name. The hash is a address hash [0-52] differnt +from the one used by ezmlm for splitting within DIR/subscribers. When using +the address field as a primary key, the size of the index was unreasonable. +Therefore, ``num'' is used as a dummy primary key, and ``h'' (a 32 bit hash +of the address) is used as an index. This markedly speeds up (un)sub with +large (>30,000 rows) subscriber tables. + +The *_slog tables contain the same info as DIR/Log, i.e. address, timestamp, +entry-type, entry-direction, and fromline. The entry-type is the first letter +of the type of entry (probe, manual, `` '' for normal), entry-direction is +``+'' for addition, ``-'' for removal. Fromline is the From: header contents +taken from the subscribe confirm message or from ezmlm-sub (if used with -n). +It is blank for all address removals, and may be blank also for additions. It +is used by the list-log.xx command. It is trivial to JOIN this table with the +address table to get e.g. subsciber names, subscription dates, etc. These +tables also have the 32-bit hash ``h'' as an index. Joins should be done on +``h'' as well as ``address'' for better performance. + +The *_cookie tables contain message number, timestamp, and cookie. For each +message a pseudo-random cookie is generated that is ``impossible'' to guess +beforehand. For lists with sublists, this is used as basic authentication, +i.e. the sublist will refuse to process a message that doesn't contain the +correct cookie or that the sublist has already successfully processed. + +The *_mlog tables contain log entries from main and sublists. These are +timestamp, listno, done. Listno is the lowest listnumber for an active list +entry with the name of this sublist as looked up in the *_name table. Done +is -1 for bounce, 0 for arrived, 1 for finished processing, and 2 for receipt +received. The routines are set up so that only the first attempt for each +combination (listno,code) is logged. + +The *_name tables contain listno,name,domain,hash_lo,hash_hi,msgnum_lo, +msgnum_hi,notuse. Listno is auto_increment and unique. Name is the name of the +sublist. domain is the last up to 3 characters of the top domain name for +addresses served by this list (default = ''). It is is '', the list servers +all_domains_that_are_not_served_by_another list (in addition to domain ''). +Of the addresses that match the domain criterion, the list serves the subset +with hash between hash_lo and hash_hi (defaults 0, 52). Any entry is ingnored if +notuse != 0 OR the current message number is not between msgnum_lo and +msgnum_hi. + +For normal lists that are not distributed (i.e. they are a single list), +entries in the *_name tables are not needed and logging is not very +relevant. + +For most lists, the only addresses that are stored in the SQL database are +the subscribers of list and digest, and the ``allow'' aliases. It is NOT +normally advisable to store moderator addresses there, since they are +needed only at the main list and secrecy is more important. ``Deny'' addresses +are few and again only needed at the main list. ``Allow'' are put in the +SQL database when using the default ezmlmrc file only to make all relevant +addresses manipulatable via the SQL server. The other tables are created, in +case they are wanted (the cost for having them as empty table is zero). The +basedir/sql file is the decision point. If it exists, an SQL table is used; +if not a local ezmlm db is used. + +CONTRIBUTIONS REQESTED + +I would be very grateful if there are users out there willing to do any of +the following and contribute it to this package. Please check with me first +(lindberg@id.wustl.edu), as the project may already be in progress/done. + +1. Interfaces for other SQL servers. Oracle, SyBase, ... + +2. A GUI admin utility to add/remove/manipulate the sublist split, essentially + by modifying list_[digest_]name in a safe way. Ideally WWW if it can be + done securely. If you use some standard interface (JDBC/DBD) it would be + useful also with other SQL severs. This could even be an Access program + using ODBC, although writing it for a platform running qmail/ezmlm makes + most sense. + +3. a WWW GUI that allows users to subscribe/unsubscribe in a safe way. A random + password would be created the first time and stored in a new address->pw + table and mailed to the subscriber address. With that password, the user + would be able to [un]subscribe to lists, edit the name (for compatibility + implemented by adding a subscribe line to list_[digest]slog). Add/remove + aliases. Ideally, it should also allow searching by subscriber name. This + would search *_slog.fromline. If less that 'x' alternatives are found, the + user would be presented with names (not addresses), allowing the user to + cause the subscription name and password to be sent to the respective + subscription address. With that info, the subscriber can then unsubscribe, + even if s/he has forgotten the subscription address. It is complicated + slightly by the fact that ``fromline'' is the crude line and needs to be + rfc822 parsed. Again, use of a standard interface is encouraged to make it + compatible also with other SQL servers. + +The aim of all this is to make it easy to use ezmlm to run very large lists, +easy to set up sites that handle subscriber interaction, archive access, etc, +and hopefully easier to integrate many ezmlm as done by some WWW sites today. + diff --git a/sub_mysql/checktag.c b/sub_mysql/checktag.c new file mode 100644 index 0000000..05de3ce --- /dev/null +++ b/sub_mysql/checktag.c @@ -0,0 +1,104 @@ +/*$Id: checktag.c,v 1.11 1999/11/10 04:08:27 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "cookie.h" +#include "makehash.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" +#include + +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; + } +} diff --git a/sub_mysql/conf-sqlcc b/sub_mysql/conf-sqlcc new file mode 100644 index 0000000..45507d5 --- /dev/null +++ b/sub_mysql/conf-sqlcc @@ -0,0 +1,4 @@ +-I/usr/include/mysql + +# the top line will be used when compiling. Edit to reflect your mysql +# installation. This is for a the MySQL-3.22.10.i386 rpm. diff --git a/sub_mysql/conf-sqlld b/sub_mysql/conf-sqlld new file mode 100644 index 0000000..0e0a69f --- /dev/null +++ b/sub_mysql/conf-sqlld @@ -0,0 +1,4 @@ +-L/usr/lib/mysql -lmysqlclient -lnsl -lm + +# the top line will be used when linking. Edit to reflect your mysql +# installation. This is for a the MySQL-3.22.10.i386 rpm. diff --git a/sub_mysql/ezmlm-mktab b/sub_mysql/ezmlm-mktab new file mode 100755 index 0000000..8fea02b --- /dev/null +++ b/sub_mysql/ezmlm-mktab @@ -0,0 +1,200 @@ +#!/bin/sh +# Simple script to generate input to mysql to generate tables for a list +# All tables are created, even though it is not advisable to put e.g. the +# moderator table in the SQL database nor is it very useful to put the +# blacklist/deny table there. The subscriber lists for the main and digest +# lists should be there, and it's reasonable to put the "extra" list there +# if used. +ECHO='echo' +CAT='cat' +CUT='cut' + + +CREATE='y' +DROP='n' +TROOT='list' +# size of std cookie +COOKIE='20' + + # not everyone has getopt :-( +while [ "`${ECHO} "$1" | ${CUT} -c1`" = "-" ]; do + case "$1" in + -c) CREATE='y'; shift;; + -C) CREATE='n'; shift;; + -d) DROP='y'; shift;; + -D) DROP='n'; shift;; + -cd|-dc) CREATE='y'; DROP='y'; shift;; + -cD|-Dc) CREATE='y'; DROP='n'; shift;; + -Cd|-dC) CREATE='n'; DROP='y'; shift;; + -CD|-DC) CREATE='n'; DROP='n'; shift;; + --) shift; break;; + *) echo "usage: emzlm-mktab [-cCdD] table_toot"; exit 100;; + esac +done + +[ ! -z "$1" ] && TROOT="$1"; + + +if [ "$DROP" = "y" ]; then + cat < fixed length, as opposed to varchar */ +/* Always select on domain and hash, so that one index should do */ +/* primary key(address) is very inefficient for MySQL. */ +/* MySQL tables do not need a primary key. Other RDBMS require one. For */ +/* the log tables, just add an INT AUTO_INCREMENT. For the address table,*/ +/* do that or use address as a primary key. */ + +create TABLE ${TROOT} ( + hash TINYINT UNSIGNED NOT NULL, + address VARCHAR(255) NOT NULL, + INDEX h (hash), + INDEX a (address(12))); + +/* Subscription log table. No addr idx to make insertion fast, since that is */ +/* almost the only thing we do with this table */ +create TABLE ${TROOT}_slog ( + tai TIMESTAMP, + address VARCHAR(255) NOT NULL, + fromline VARCHAR(255) NOT NULL, + edir CHAR(1) NOT NULL, + etype CHAR(1) NOT NULL, + INDEX (tai)); + +/* digest list table */ +create TABLE ${TROOT}_digest ( + hash TINYINT UNSIGNED NOT NULL, + address VARCHAR(255) NOT NULL, + INDEX h (hash), + INDEX a (address(12))); + +/* digest list subscription log */ +create TABLE ${TROOT}_digest_slog ( + tai TIMESTAMP, + address VARCHAR(255) NOT NULL, + fromline VARCHAR(255) NOT NULL, + edir CHAR(1) NOT NULL, + etype CHAR(1) NOT NULL, + INDEX (tai)); + +/* moderator addresses */ +create TABLE ${TROOT}_mod ( + hash TINYINT UNSIGNED NOT NULL, + address VARCHAR(255) NOT NULL, + INDEX h(hash), + INDEX a(address(12))); + +/* moderator subscription log */ +create TABLE ${TROOT}_mod_slog ( + tai TIMESTAMP, + address VARCHAR(255) NOT NULL, + fromline VARCHAR(255) NOT NULL, + edir CHAR(1) NOT NULL, + etype CHAR(1) NOT NULL, + INDEX (tai)); + +/* "allow" address table */ +create TABLE ${TROOT}_allow ( + hash TINYINT UNSIGNED NOT NULL, + address VARCHAR(255) NOT NULL, + INDEX h(hash), + INDEX a(address(12))); + +/* extra address table log */ +create TABLE ${TROOT}_allow_slog ( + tai TIMESTAMP, + address VARCHAR(255) NOT NULL, + fromline VARCHAR(255) NOT NULL, + edir CHAR(1) NOT NULL, + etype CHAR(1) NOT NULL, + INDEX (tai)); + +/* blacklist address table */ +create TABLE ${TROOT}_deny ( + hash TINYINT UNSIGNED NOT NULL, + address VARCHAR(255) NOT NULL, + INDEX h(hash), + INDEX a(address(12))); + +/* blacklist subscription log */ +create TABLE ${TROOT}_deny_slog ( + tai TIMESTAMP, + address VARCHAR(255) NOT NULL, + fromline VARCHAR(255) NOT NULL, + edir CHAR(1) NOT NULL, + etype CHAR(1) NOT NULL, + INDEX (tai)); + +/* main list inserts a cookie here. Sublists check it */ +CREATE TABLE ${TROOT}_cookie ( + msgnum INTEGER UNSIGNED NOT NULL, + tai TIMESTAMP NOT NULL, + cookie CHAR($COOKIE) NOT NULL, + chunk TINYINT UNSIGNED NOT NULL DEFAULT 0, + bodysize INTEGER UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (msgnum)); + +/* main and sublist log here when the message is done */ +/* done=0 for arrived, done=4 for sent, 5 for receit. */ +/* tai reflects last change */ +CREATE TABLE ${TROOT}_mlog ( + msgnum INTEGER UNSIGNED NOT NULL, + listno INTEGER UNSIGNED NOT NULL, + tai TIMESTAMP, + subs INTEGER UNSIGNED NOT NULL DEFAULT 0, + done TINYINT NOT NULL DEFAULT 0, + PRIMARY KEY listmsg (listno,msgnum,done)); + +/* ezmlm-get when creating a digests inserts a cookie here. Sublists check it */ +CREATE TABLE ${TROOT}_digest_cookie ( + msgnum INTEGER UNSIGNED NOT NULL, + tai TIMESTAMP NOT NULL, + cookie CHAR($COOKIE) NOT NULL, + chunk TINYINT UNSIGNED NOT NULL DEFAULT 0, + bodysize INTEGER UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY (msgnum)); + +/* ezmlm-get and digest sublists log here when the message is done */ +/* done=0 for arrived, done=4 for sent, 5 for receit. */ +/* tai reflects last change */ +CREATE TABLE ${TROOT}_digest_mlog ( + msgnum INTEGER UNSIGNED NOT NULL, + listno INTEGER UNSIGNED NOT NULL, + tai TIMESTAMP, + subs INT UNSIGNED NOT NULL DEFAULT 0, + done TINYINT NOT NULL DEFAULT 0, + PRIMARY KEY listmsg (listno,msgnum,done)); + +EOF + +fi +exit 0 + diff --git a/sub_mysql/issub.c b/sub_mysql/issub.c new file mode 100644 index 0000000..a2b760c --- /dev/null +++ b/sub_mysql/issub.c @@ -0,0 +1,174 @@ +/*$Id: issub.c,v 1.16 1999/12/11 03:04:19 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "strerr.h" +#include "error.h" +#include "uint32.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" +#include + +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; + } +} diff --git a/sub_mysql/logmsg.c b/sub_mysql/logmsg.c new file mode 100644 index 0000000..ca601e8 --- /dev/null +++ b/sub_mysql/logmsg.c @@ -0,0 +1,54 @@ +/*$Id: logmsg.c,v 1.10 1999/11/10 04:08:27 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" +#include +#include + +static stralloc logline = {0}; +static char strnum[FMT_ULONG]; + +char *logmsg(dir,num,listno,subs,done) +/* creates an entry for message num and the list listno and code "done". */ +/* Returns NULL on success, "" if dir/sql was not found, and the error */ +/* string on error. NOTE: This routine does nothing for non-sql lists! */ +char *dir; +unsigned long num; +unsigned long listno; +unsigned long subs; +int done; +{ + char *table = (char *) 0; + char *ret; + + if ((ret = opensql(dir,&table))) { + if (*ret) + return ret; + else + return (char *) 0; /* no SQL => success */ + } + if (!stralloc_copys(&logline,"INSERT INTO ")) return ERR_NOMEM; + if (!stralloc_cats(&logline,table)) return ERR_NOMEM; + if (!stralloc_cats(&logline,"_mlog (msgnum,listno,subs,done) VALUES (")) + return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno))) + return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,subs))) return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (done < 0) { + done = - done; + if (!stralloc_append(&logline,"-")) return ERR_NOMEM; + } + if (!stralloc_catb(&logline,strnum,fmt_uint(strnum,done))) return ERR_NOMEM; + if (!stralloc_append(&logline,")")) return ERR_NOMEM; + + if (mysql_real_query((MYSQL *) psql,logline.s,logline.len)) /* log query */ + if (mysql_errno((MYSQL *) psql) != ER_DUP_ENTRY) /* ignore dups */ + return mysql_error((MYSQL *) psql); + return (char *) 0; +} diff --git a/sub_mysql/opensql.c b/sub_mysql/opensql.c new file mode 100644 index 0000000..4b903a9 --- /dev/null +++ b/sub_mysql/opensql.c @@ -0,0 +1,112 @@ +/*$Id: opensql.c,v 1.6 1999/11/14 21:29:29 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" +#include + +static stralloc myp = {0}; +static stralloc ers = {0}; +static stralloc fn = {0}; +static stralloc ourdb = {0}; +static char *ourtable = (char *) 0; + +char *opensql(dbname,table) +/* reads the file dbname/sql, and if the file exists, parses it into the */ +/* components. The string should be host:port:user:pw:db:table. If */ +/* the file does not exists, returns "". On success returns NULL. On error */ +/* returns error string for temporary error. If table is NULL it is */ +/* left alone. If *table is not null, it overrides the table in the sql */ +/* file. If we already opended dbname the cached info is used, rather than */ +/* rereading the file. Note that myp is static and all pointers point to it.*/ +char *dbname; /* database directory */ +char **table; /* table root_name */ + +{ + char *host = (char *) 0; + unsigned long port = 0L; + char *db = "ezmlm"; /* default */ + char *user = (char *) 0; + char *pw = (char *) 0; + unsigned int j; + char *cp; + + if (!stralloc_copys(&fn,dbname)) return ERR_NOMEM; + if (fn.len == ourdb.len && !str_diffn(ourdb.s,fn.s,fn.len)) { + if (table) { + if (*table) ourtable = *table; + else *table = ourtable; + } + return 0; + } + if (!stralloc_cats(&fn,"/sql")) return ERR_NOMEM; + if (!stralloc_0(&fn)) return ERR_NOMEM; + /* host:port:db:table:user:pw:name */ + + myp.len = 0; + switch (slurp(fn.s,&myp,128)) { + case -1: if (!stralloc_copys(&ers,ERR_READ)) return ERR_NOMEM; + if (!stralloc_cat(&ers,&fn)) return ERR_NOMEM; + if (!stralloc_0(&ers)) return ERR_NOMEM; + return ers.s; + case 0: return ""; + } + if (!stralloc_copy(&ourdb,&fn)) return ERR_NOMEM; + if (!stralloc_append(&myp,"\n")) return ERR_NOMEM; + for (j=0; j< myp.len; ++j) { + if (myp.s[j] == '\n') { myp.s[j] = '\0'; break; } + } + /* get connection parameters */ + if (!stralloc_0(&myp)) return ERR_NOMEM; + host = myp.s; + if (myp.s[j = str_chr(myp.s,':')]) { + cp = myp.s + j++; + *(cp++) = '\0'; + scan_ulong(cp,&port); + if (myp.s[j += str_chr(myp.s+j,':')]) { + j++; + user = myp.s + j; + if (myp.s[j += str_chr(myp.s+j,':')]) { + pw = myp.s + j++; + *(pw++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + db = myp.s + j++; + *(db++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + ourtable = myp.s + j++; + *(ourtable++) = '\0'; + } + } + } + } + } + if (host && !*host) host = (char *) 0; + if (user && !*user) user = (char *) 0; + if (pw && !*pw) pw = (char *) 0; + if (db && !*db) db = (char *) 0; + if (ourtable && !*ourtable) ourtable = (char *) 0; + if (table) { + if (*table) ourtable = *table; + else *table = ourtable; + if (!*table) return ERR_NO_TABLE; + } + if (!psql) { + if (!((MYSQL *) psql = mysql_init((MYSQL *) 0))) + return ERR_NOMEM; /* init */ + if (!(mysql_real_connect((MYSQL *) psql, host, user, pw, db, + (unsigned int) port, 0, CLIENT_COMPRESS))) /* conn */ + return mysql_error((MYSQL *) psql); + } + return (char *) 0; +} + +void closesql() +/* close connection to SQL server, if open */ +{ + if (psql) mysql_close((MYSQL *) psql); + psql = (void *) 0; /* destroy pointer */ + ourdb.len = 0; /* destroy cache */ + return; +} + diff --git a/sub_mysql/putsubs.c b/sub_mysql/putsubs.c new file mode 100644 index 0000000..2a98dfc --- /dev/null +++ b/sub_mysql/putsubs.c @@ -0,0 +1,128 @@ +#include "error.h" +#include "strerr.h" +#include "readwrite.h" +#include "str.h" +#include "fmt.h" +#include "stralloc.h" +#include "open.h" +#include "substdio.h" +#include "case.h" +#include "errtxt.h" +#include "subscribe.h" +#include "qmail.h" +#include + +static substdio ssin; +static char inbuf[512]; +char strnum[FMT_ULONG]; +static stralloc line = {0}; +static stralloc domains = {0}; +static stralloc quoted = {0}; +static stralloc fn = {0}; + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static void die_write(fatal) +char *fatal; +{ + strerr_die3x(111,fatal,ERR_WRITE,"stdout"); +} + +unsigned long putsubs(dbname,hash_lo,hash_hi, + subwrite,flagsql,fatal) +/* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */ +/* that userhost is excluded. 'dbname' is the base directory name. For the */ +/* mysql version, dbname is the directory where the file "sql" with mysql */ +/* access info is found. If this file is not present or if flagmysql is not */ +/* set, the routine falls back to the old database style. subwrite must be a*/ +/* function returning >=0 on success, -1 on error, and taking arguments */ +/* (char* string, unsigned int length). It will be called once per address */ +/* and should take care of newline or whatever needed for the output form. */ + +char *dbname; /* database base dir */ +unsigned long hash_lo; +unsigned long hash_hi; +int subwrite(); /* write function. */ +int flagsql; +char *fatal; /* fatal error string */ + +{ + MYSQL_RES *result; + MYSQL_ROW row; + char *table = (char *) 0; + unsigned long *lengths; + + unsigned int i; + int fd; + unsigned long no = 0L; + int match; + unsigned int pos = 0; + unsigned int hashpos; + char *ret = (char *) 0; + + if (!flagsql || (ret = opensql(dbname,&table))) { + if (flagsql && *ret) strerr_die2x(111,fatal,ret); + /* fallback to local db */ + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal); + /* NOTE: Also copies terminal '\0' */ + hashpos = fn.len - 2; + if (hash_lo > 52) hash_lo = 52; + if (hash_hi > 52) hash_hi = 52; + if (hash_hi < hash_lo) hash_hi = hash_lo; + + for (i = hash_lo;i <= hash_hi;++i) { + fn.s[hashpos] = 64 + i; /* hash range 0-52 */ + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + } else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&ssin,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) + break; + if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal); + no++; + } + close(fd); + } + } + return no; + + } else { /* SQL Version */ + + /* main query */ + if (!stralloc_copys(&line,"SELECT address FROM ")) + die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," WHERE hash BETWEEN ")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_lo))) + die_nomem(fatal); + if (!stralloc_cats(&line," AND ")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash_hi))) + die_nomem(fatal); + if (mysql_real_query((MYSQL *) psql,line.s,line.len)) /* query */ + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (!(result = mysql_use_result((MYSQL *) psql))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + no = 0; + while ((row = mysql_fetch_row(result))) { + /* this is safe even if someone messes with the address field def */ + if (!(lengths = mysql_fetch_lengths(result))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (subwrite(row[0],lengths[0]) == -1) die_write(fatal); + no++; /* count for list-list fxn */ + } + if (!mysql_eof(result)) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + mysql_free_result(result); + return no; + } +} diff --git a/sub_mysql/searchlog.c b/sub_mysql/searchlog.c new file mode 100644 index 0000000..8d8278f --- /dev/null +++ b/sub_mysql/searchlog.c @@ -0,0 +1,163 @@ +/*$Id: searchlog.c,v 1.15 1999/11/10 04:08:27 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "case.h" +#include "scan.h" +#include "stralloc.h" +#include "str.h" +#include "open.h" +#include "datetime.h" +#include "date822fmt.h" +#include "substdio.h" +#include "readwrite.h" +#include "strerr.h" +#include "error.h" +#include "errtxt.h" +#include "subscribe.h" +#include + +static stralloc line = {0}; +static stralloc outline = {0}; +static char date[DATE822FMT]; +static datetime_sec when; +static struct datetime dt; +static substdio ssin; +static char inbuf[256]; + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static void lineout(subwrite,fatal) +int subwrite(); +char *fatal; +{ + (void) scan_ulong(line.s,&when); + datetime_tai(&dt,when); /* there is always at least a '\n' */ + if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1)) + die_nomem(fatal); + if (!stralloc_cats(&outline,": ")) die_nomem(fatal); + if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal); + if (subwrite(outline.s,outline.len) == -1) + strerr_die3x(111,fatal,ERR_WRITE,"output"); + return; +} + +void searchlog(dir,search,subwrite,fatal) +/* opens dir/Log, and outputs via subwrite(s,len) any line that matches */ +/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */ +/* is replaced by a '_'. mysql version. Falls back on "manual" search of */ +/* local Log if no mysql connect info. */ + +char *dir; /* work directory */ +char *search; /* search string */ +int subwrite(); /* output fxn */ +char *fatal; /* fatal */ +{ + + register unsigned char x; + register unsigned char y; + register unsigned char *cp; + register unsigned char *cpsearch; + unsigned register char *cps; + unsigned register char ch; + unsigned char *cplast, *cpline; + unsigned int searchlen; + int fd,match; + char *ret; + + MYSQL_RES *result; + MYSQL_ROW row; + char *table = (char *) 0; + char **ptable = &table; + char *sublist = (char *) 0; + unsigned long *lengths; + + if (!search) search = ""; /* defensive */ + searchlen = str_len(search); + case_lowerb(search,searchlen); + cps = (unsigned char *) search; + while ((ch = *(cps++))) { /* search is potentially hostile */ + if (ch >= 'a' && ch <= 'z') continue; + if (ch >= '0' && ch <= '9') continue; + if (ch == '.' || ch == '_') continue; + *(cps - 1) = '_'; /* will match char specified as well */ + } + + if ((ret = opensql(dir,ptable))) { + if (*ret) strerr_die2x(111,fatal,ret); + /* fallback to local log */ + if (!stralloc_copys(&line,dir)) die_nomem(fatal); + if (!stralloc_cats(&line,"/Log")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + fd = open_read(line.s); + if (fd == -1) + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,line.s,": "); + else + strerr_die3x(100,fatal,line.s,ERR_NOEXIST); + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,fatal,ERR_READ_INPUT); + if (!match) break; + if (!searchlen) { + lineout(subwrite,fatal); + } else { + cpline = (unsigned char *) line.s - 1; + cplast = cpline + line.len - searchlen; /* line has \0 at the end */ + while ((cp = ++cpline) <= cplast) { + cpsearch = (unsigned char *) search; + for (;;) { + x = *cpsearch++; + if (!x) break; + y = *cp++ - 'A'; + if (y <= (unsigned char) ('Z' - 'A')) y += 'a'; else y += 'A'; + if (x != y && x != '_') break; /* '_' = wildcard */ + } + if (!x) { + lineout(subwrite,fatal); + break; + } + } + } + } + close(fd); + } else { + +/* SELECT (*) FROM list_slog WHERE fromline LIKE '%search%' OR address */ +/* LIKE '%search%' ORDER BY tai; */ +/* The '*' is formatted to look like the output of the non-mysql version */ +/* This requires reading the entire table, since search fields are not */ +/* indexed, but this is a rare query and time is not of the essence. */ + + if (!stralloc_cats(&line,"SELECT CONCAT(FROM_UNIXTIME(UNIX_TIMESTAMP(tai))," + "'-0000: ',UNIX_TIMESTAMP(tai),' ',edir,etype,' ',address,' '," + "fromline) FROM ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line,"_slog ")) die_nomem(fatal); + if (*search) { /* We can afford to wait for LIKE '%xx%' */ + if (!stralloc_cats(&line,"WHERE fromline LIKE '%")) die_nomem(fatal); + if (!stralloc_cats(&line,search)) die_nomem(fatal); + if (!stralloc_cats(&line,"%' OR address LIKE '%")) die_nomem(fatal); + if (!stralloc_cats(&line,search)) die_nomem(fatal); + if (!stralloc_cats(&line,"%'")) die_nomem(fatal); + } /* ordering by tai which is an index */ + if (!stralloc_cats(&line," ORDER by tai")) die_nomem(fatal); + + if (mysql_real_query((MYSQL *) psql,line.s,line.len)) /* query */ + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (!(result = mysql_use_result((MYSQL *) psql))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + while ((row = mysql_fetch_row(result))) { + if (!(lengths = mysql_fetch_lengths(result))) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + if (subwrite(row[0],lengths[0]) == -1) die_write(fatal); + } + if (!mysql_eof(result)) + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); + mysql_free_result(result); + } +} diff --git a/sub_mysql/subscribe.c b/sub_mysql/subscribe.c new file mode 100644 index 0000000..f309253 --- /dev/null +++ b/sub_mysql/subscribe.c @@ -0,0 +1,376 @@ +/*$Id: subscribe.c,v 1.22 1999/11/10 04:08:27 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "strerr.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "subscribe.h" +#include "uint32.h" +#include "fmt.h" +#include "errtxt.h" +#include "log.h" +#include "idx.h" +#include +#include + +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 */ + } +} diff --git a/sub_mysql/tagmsg.c b/sub_mysql/tagmsg.c new file mode 100644 index 0000000..55b57e7 --- /dev/null +++ b/sub_mysql/tagmsg.c @@ -0,0 +1,92 @@ +/*$Id: tagmsg.c,v 1.11 1999/11/10 04:08:27 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "strerr.h" +#include "cookie.h" +#include "slurp.h" +#include "errtxt.h" +#include "subscribe.h" +#include "makehash.h" +#include +#include + +static stralloc line = {0}; +static stralloc key = {0}; +static char hash[COOKIE]; +static char strnum[FMT_ULONG]; /* message number as sz */ + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(100,fatal,ERR_NOMEM); +} + +void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal) +/* This routine creates a cookie from num,seed and the */ +/* list key and returns that cookie in hashout. The use of sender/num and */ +/* first char of action is used to make cookie differ between messages, */ +/* the key is the secret list key. The cookie will be inserted into */ +/* table_cookie where table and other data is taken from dir/sql. We log */ +/* arrival of the message (done=0). */ + +char *dir; /* db base dir */ +unsigned long msgnum; /* number of this message */ +char *seed; /* seed. NULL ok, but less entropy */ +char *action; /* to make it certain the cookie differs from*/ + /* one used for a digest */ +char *hashout; /* calculated hash goes here */ +unsigned long bodysize; +unsigned long chunk; +char *fatal; +{ + char *table = (char *) 0; + char *ret; + unsigned int i; + + strnum[fmt_ulong(strnum,msgnum)] = '\0'; /* message nr ->string*/ + + switch(slurp("key",&key,32)) { + case -1: + strerr_die3sys(111,fatal,ERR_READ,"key: "); + case 0: + strerr_die3x(100,fatal,"key",ERR_NOEXIST); + } + cookie(hash,key.s,key.len,strnum,seed,action); + for (i = 0; i < COOKIE; i++) + hashout[i] = hash[i]; + + if ((ret = opensql(dir,&table))) { + if (*ret) strerr_die2x(111,fatal,ret); + return; /* no sql => success */ + + } else { + if (chunk >= 53L) chunk = 0L; /* sanity */ + + /* INSERT INTO table_cookie (msgnum,cookie) VALUES (num,cookie) */ + /* (we may have tried message before, but failed to complete, so */ + /* ER_DUP_ENTRY is ok) */ + if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line,"_cookie (msgnum,cookie,bodysize,chunk) VALUES (")) + die_nomem(fatal); + if (!stralloc_cats(&line,strnum)) die_nomem(fatal); + if (!stralloc_cats(&line,",'")) die_nomem(fatal); + if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(fatal); + if (!stralloc_cats(&line,"',")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,bodysize))) + die_nomem(fatal); + if (!stralloc_cats(&line,",")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,chunk))) die_nomem(fatal); + if (!stralloc_cats(&line,")")) die_nomem(fatal); + if (mysql_real_query((MYSQL *) psql,line.s,line.len) != 0) + if (mysql_errno((MYSQL *) psql) != ER_DUP_ENTRY) /* ignore dups */ + strerr_die2x(111,fatal,mysql_error((MYSQL *) psql)); /* cookie query */ + + if (! (ret = logmsg(dir,msgnum,0L,0L,1))) return; /* log done=1*/ + if (*ret) strerr_die2x(111,fatal,ret); + } + + return; +} diff --git a/sub_mysql/to40x b/sub_mysql/to40x new file mode 100755 index 0000000..5f6f872 --- /dev/null +++ b/sub_mysql/to40x @@ -0,0 +1,15 @@ +#!/bin/sh +cat <sublist clusters, the other +fields are used for load splitting. The domain is the first up to 3 characters +of the last part of the domain name. The hash is a address hash [0-52] differnt +from the one used by ezmlm for splitting within DIR/subscribers. When using +the address field as a primary key, the size of the index was unreasonable. +Therefore, ``num'' is used as a dummy primary key, and ``h'' (a 32 bit hash +of the address) is used as an index. This markedly speeds up (un)sub with +large (>30,000 rows) subscriber tables. + +The *_slog tables contain the same info as DIR/Log, i.e. address, timestamp, +entry-type, entry-direction, and fromline. The entry-type is the first letter +of the type of entry (probe, manual, `` '' for normal), entry-direction is +``+'' for addition, ``-'' for removal. Fromline is the From: header contents +taken from the subscribe confirm message or from ezmlm-sub (if used with -n). +It is blank for all address removals, and may be blank also for additions. It +is used by the list-log.xx command. It is trivial to JOIN this table with the +address table to get e.g. subsciber names, subscription dates, etc. These +tables also have the 32-bit hash ``h'' as an index. Joins should be done on +``h'' as well as ``address'' for better performance. + +The *_cookie tables contain message number, timestamp, and cookie. For each +message a pseudo-random cookie is generated that is ``impossible'' to guess +beforehand. For lists with sublists, this is used as basic authentication, +i.e. the sublist will refuse to process a message that doesn't contain the +correct cookie or that the sublist has already successfully processed. + +The *_mlog tables contain log entries from main and sublists. These are +timestamp, listno, done. Listno is the lowest listnumber for an active list +entry with the name of this sublist as looked up in the *_name table. Done +is -1 for bounce, 0 for arrived, 1 for finished processing, and 2 for receipt +received. The routines are set up so that only the first attempt for each +combination (listno,code) is logged. + +The *_name tables contain listno,name,domain,hash_lo,hash_hi,msgnum_lo, +msgnum_hi,notuse. Listno is auto_increment and unique. Name is the name of the +sublist. domain is the last up to 3 characters of the top domain name for +addresses served by this list (default = ''). It is is '', the list servers +all_domains_that_are_not_served_by_another list (in addition to domain ''). +Of the addresses that match the domain criterion, the list serves the subset +with hash between hash_lo and hash_hi (defaults 0, 52). Any entry is ingnored if +notuse != 0 OR the current message number is not between msgnum_lo and +msgnum_hi. + +For normal lists that are not distributed (i.e. they are a single list), +entries in the *_name tables are not needed and logging is not very +relevant. + +For most lists, the only addresses that are stored in the SQL database are +the subscribers of list and digest, and the ``allow'' aliases. It is NOT +normally advisable to store moderator addresses there, since they are +needed only at the main list and secrecy is more important. ``Deny'' addresses +are few and again only needed at the main list. ``Allow'' are put in the +SQL database when using the default ezmlmrc file only to make all relevant +addresses manipulatable via the SQL server. The other tables are created, in +case they are wanted (the cost for having them as empty table is zero). The +basedir/sql file is the decision point. If it exists, an SQL table is used; +if not a local ezmlm db is used. + +CONTRIBUTIONS REQESTED + +I would be very grateful if there are users out there willing to do any of +the following and contribute it to this package. Please check with me first +(lindberg@id.wustl.edu), as the project may already be in progress/done. + +1. Interfaces for other SQL servers. Oracle, SyBase, ... + +2. A GUI admin utility to add/remove/manipulate the sublist split, essentially + by modifying list_[digest_]name in a safe way. Ideally WWW if it can be + done securely. If you use some standard interface (JDBC/DBD) it would be + useful also with other SQL severs. This could even be an Access program + using ODBC, although writing it for a platform running qmail/ezmlm makes + most sense. + +3. a WWW GUI that allows users to subscribe/unsubscribe in a safe way. A random + password would be created the first time and stored in a new address->pw + table and mailed to the subscriber address. With that password, the user + would be able to [un]subscribe to lists, edit the name (for compatibility + implemented by adding a subscribe line to list_[digest]slog). Add/remove + aliases. Ideally, it should also allow searching by subscriber name. This + would search *_slog.fromline. If less that 'x' alternatives are found, the + user would be presented with names (not addresses), allowing the user to + cause the subscription name and password to be sent to the respective + subscription address. With that info, the subscriber can then unsubscribe, + even if s/he has forgotten the subscription address. It is complicated + slightly by the fact that ``fromline'' is the crude line and needs to be + rfc822 parsed. Again, use of a standard interface is encouraged to make it + compatible also with other SQL servers. + +The aim of all this is to make it easy to use ezmlm to run very large lists, +easy to set up sites that handle subscriber interaction, archive access, etc, +and hopefully easier to integrate many ezmlm as done by some WWW sites today. + diff --git a/sub_pgsql/checktag.c b/sub_pgsql/checktag.c new file mode 100644 index 0000000..330c236 --- /dev/null +++ b/sub_pgsql/checktag.c @@ -0,0 +1,106 @@ +/*$Id: checktag.c,v 1.3 1999/12/23 02:40:57 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "cookie.h" +#include "makehash.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" +#include +#include + +static stralloc key = {0}; +static stralloc line = {0}; +static strnum[FMT_ULONG]; +static newcookie[COOKIE]; + +char *checktag (dir,num,listno,action,seed,hash) +/* reads dir/sql. If not present, returns success (NULL). If dir/sql is */ +/* present, checks hash against the cookie table. If match, returns success*/ +/* (NULL), else returns "". If error, returns error string. */ + + +char *dir; /* the db base dir */ +unsigned long num; /* message number */ +unsigned long listno; /* bottom of range => slave */ +char *action; +char *seed; /* cookie base */ +char *hash; /* cookie */ +{ + PGresult *result; + /* int row; */ + char *table = (char *) 0; + char *r; + + if ((r = opensql(dir,&table))) { + if (*r) return r; + if (!seed) return (char *) 0; /* no data - accept */ + + strnum[fmt_ulong(strnum,num)] = '\0'; /* message nr ->string*/ + + switch(slurp("key",&key,32)) { + case -1: + return ERR_READ_KEY; + case 0: + return ERR_NOEXIST_KEY; + } + + cookie(newcookie,key.s,key.len,strnum,seed,action); + if (byte_diff(hash,COOKIE,newcookie)) return ""; + else return (char *) 0; + + } else { + + /* SELECT msgnum FROM table_cookie WHERE msgnum=num and cookie='hash' */ + /* succeeds only is everything correct. 'hash' is quoted since it is */ + /* potentially hostile. */ + if (listno) { /* only for slaves */ + if (!stralloc_copys(&line,"SELECT listno FROM ")) return ERR_NOMEM; + if (!stralloc_cats(&line,table)) return ERR_NOMEM; + if (!stralloc_cats(&line,"_mlog WHERE listno=")) return ERR_NOMEM; + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,listno))) + return ERR_NOMEM; + if (!stralloc_cats(&line," AND msgnum=")) return ERR_NOMEM; + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM; + if (!stralloc_cats(&line," AND done > 3")) return ERR_NOMEM; + + if (!stralloc_0(&line)) return ERR_NOMEM; + result = PQexec( psql, line.s ); + if(result == NULL) + return (PQerrorMessage(psql)); + if( PQresultStatus(result) != PGRES_TUPLES_OK) + return (char *) (PQresultErrorMessage(result)); + if( PQntuples(result) > 0 ) { + PQclear(result); + return(""); + } else + PQclear(result); + } + + if (!stralloc_copys(&line,"SELECT msgnum FROM ")) return ERR_NOMEM; + if (!stralloc_cats(&line,table)) return ERR_NOMEM; + if (!stralloc_cats(&line,"_cookie WHERE msgnum=")) return ERR_NOMEM; + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM; + if (!stralloc_cats(&line," and cookie='")) return ERR_NOMEM; + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,hash))) return ERR_NOMEM; + if (!stralloc_cats(&line,"'")) return ERR_NOMEM; + + if (!stralloc_0(&line)) return ERR_NOMEM; + result = PQexec(psql,line.s); + if (result == NULL) + return (PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_TUPLES_OK) + return (char *) (PQresultErrorMessage(result)); + if(PQntuples(result) < 0) { + PQclear( result ); + return(""); + } + + PQclear(result); + if (listno) + (void) logmsg(dir,num,listno,0L,3); /* non-ess mysql logging */ + return (char *)0; + } +} diff --git a/sub_pgsql/conf-sqlcc b/sub_pgsql/conf-sqlcc new file mode 100644 index 0000000..886cf2f --- /dev/null +++ b/sub_pgsql/conf-sqlcc @@ -0,0 +1,6 @@ +-I/usr/include/pgsql + +# the top line will be used when compiling. Edit to reflect your PostgreSQL +# installation. The above is correct for RedHat rpms. +# -I/usr/local/pgsql/include would be correct for BSD installations. + diff --git a/sub_pgsql/conf-sqlld b/sub_pgsql/conf-sqlld new file mode 100644 index 0000000..610f5cd --- /dev/null +++ b/sub_pgsql/conf-sqlld @@ -0,0 +1,4 @@ +-L/usr/local/pgsql/lib -lpq -lcrypt + +# the top line will be used when linking. Edit to reflect your PostgreSQL +# installation. diff --git a/sub_pgsql/ezmlm-mktab b/sub_pgsql/ezmlm-mktab new file mode 100755 index 0000000..9ac2b33 --- /dev/null +++ b/sub_pgsql/ezmlm-mktab @@ -0,0 +1,216 @@ +#!/bin/sh +# Simple script to generate input to psql to generate tables for a list +# All tables are created, even though it is not advisable to put e.g. the +# moderator table in the SQL database nor is it very useful to put the +# blacklist/deny table there. The subscriber lists for the main and digest +# lists should be there, and it's reasonable to put the "extra" list there +# if used. +ECHO='echo' +CAT='cat' +CUT='cut' + +CREATE='y' +DROP='n' +TROOT='list' +# size of std cookie +COOKIE='20' + + # not everyone has getopt :-( +while [ "`${ECHO} "$1" | ${CUT} -c1`" = "-" ]; do + case "$1" in + -c) CREATE='y'; shift;; + -C) CREATE='n'; shift;; + -d) DROP='y'; shift;; + -D) DROP='n'; shift;; + -cd|-dc) CREATE='y'; DROP='y'; shift;; + -cD|-Dc) CREATE='y'; DROP='n'; shift;; + -Cd|-dC) CREATE='n'; DROP='y'; shift;; + -CD|-DC) CREATE='n'; DROP='n'; shift;; + --) shift; break;; + *) echo "usage: emzlm-mktab [-cCdD] table_toot"; exit 100;; + esac +done + +[ ! -z "$1" ] && TROOT="$1"; + +if [ "$DROP" = "y" ]; then + cat < defer message. = 0 => process message */ +/* no reason for index - will always be small */ +create TABLE ${TROOT}_name ( + listno SERIAL, + name VARCHAR(255) NOT NULL, + notuse INT4 NOT NULL DEFAULT 0, + msgnum_lo INT8 NOT NULL DEFAULT 0, + msgnum_hi INT8 NOT NULL DEFAULT 4294967295, + hash_lo INT4 NOT NULL DEFAULT 0, + hash_hi INT4 NOT NULL DEFAULT 52, + domain CHAR(3) NOT NULL DEFAULT '', + PRIMARY KEY (listno)); + +/* main list inserts a cookie here. Sublists check it */ +CREATE TABLE ${TROOT}_cookie ( + msgnum INT4 NOT NULL, + tai TIMESTAMP NOT NULL DEFAULT now(), + cookie CHAR(20) NOT NULL, + chunk INT4 NOT NULL DEFAULT 0, + bodysize INT4 NOT NULL DEFAULT 0, + PRIMARY KEY (msgnum)); + +/* main and sublist log here when the message is done */ +/* done=0 for arrived, done=1 for sent. tai reflects last change, as e.g. */ +/* done=0 may be overwritten in case first delivery to the list fails. */ +CREATE TABLE ${TROOT}_mlog ( + msgnum INT4 NOT NULL, + listno INT4 NOT NULL, + tai TIMESTAMP DEFAULT now(), + subs INT4 NOT NULL DEFAULT 0, + done INT4 NOT NULL DEFAULT 0, + PRIMARY KEY (listno,msgnum,done)); + +/* digest sublist restriction table */ +/* notuse != 0 => defer message. = 0 => process message */ +/* no index, since table unlikely to have >30 or so rows */ +create TABLE ${TROOT}_digest_name ( + listno SERIAL, + name VARCHAR(255) NOT NULL, + notuse INT4 NOT NULL DEFAULT 0, + msgnum_lo INT8 NOT NULL DEFAULT 0, + msgnum_hi INT8 NOT NULL DEFAULT 4294967295, + hash_lo INT4 NOT NULL DEFAULT 0, + hash_hi INT4 NOT NULL DEFAULT 52, + domain CHAR(3) NOT NULL DEFAULT '', + PRIMARY KEY (listno)); + +/* ezmlm-get when creating a digests inserts a cookie here. Sublists check it*/ +CREATE TABLE ${TROOT}_digest_cookie ( + msgnum INT4 NOT NULL, + tai TIMESTAMP NOT NULL DEFAULT now(), + cookie CHAR(20) NOT NULL, + chunk INT4 NOT NULL DEFAULT 0, + bodysize INT4 NOT NULL DEFAULT 0, + PRIMARY KEY (msgnum)); + +/* ezmlm-get and digest sublists log here when the message is done */ +/* done=0 for arrived, done=1 for sent. tai reflects last change */ +CREATE TABLE ${TROOT}_digest_mlog ( + msgnum INT4 NOT NULL, + listno INT4 NOT NULL, + tai TIMESTAMP DEFAULT now(), + subs INT4 NOT NULL DEFAULT 0, + done INT4 NOT NULL DEFAULT 0, + PRIMARY KEY (listno,msgnum,done)); + +EOF + +fi +exit 0 + + diff --git a/sub_pgsql/issub.c b/sub_pgsql/issub.c new file mode 100644 index 0000000..42b744d --- /dev/null +++ b/sub_pgsql/issub.c @@ -0,0 +1,165 @@ +/*$Id: issub.c,v 1.4 1999/12/11 03:04:03 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "strerr.h" +#include "error.h" +#include "uint32.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" +#include +#include + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static stralloc addr = {0}; +static stralloc lcaddr = {0}; +static stralloc line = {0}; +static stralloc fn = {0}; +static substdio ss; +static char ssbuf[512]; + +char *issub(dbname,userhost,tab,fatal) +/* Returns (char *) to match if userhost is in the subscriber database */ +/* dbname, 0 otherwise. dbname is a base directory for a list and may NOT */ +/* be NULL */ +/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/ + +char *dbname; /* directory to basedir */ +char *userhost; +char *tab; /* override table name */ +char *fatal; + +{ + PGresult *result; + char *ret; + char *table; + + int fd; + unsigned int j; + uint32 h,lch; + char ch,lcch; + int match; + + table = tab; + if ((ret = opensql(dbname,&table))) { + if (*ret) strerr_die2x(111,fatal,ret); + /* fallback to local db */ + + if (!stralloc_copys(&addr,"T")) die_nomem(fatal); + if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return 0; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */ + + h = 5381; + lch = h; /* make hash for both for backwards comp */ + for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */ + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + ch = 64 + (h % 53); + lcch = 64 + (lch % 53); + + if (!stralloc_0(&addr)) die_nomem(fatal); + if (!stralloc_0(&lcaddr)) die_nomem(fatal); + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); + if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); + if (!stralloc_0(&fn)) die_nomem(fatal); + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + } else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == lcaddr.len) + if (!case_diffb(line.s,line.len,lcaddr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + } + /* here if file not found or (file found && addr not there) */ + + if (ch == lcch) return 0; + + /* try case sensitive hash for backwards compatibility */ + fn.s[fn.len - 2] = ch; + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + return 0; + } + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + + return 0; + } else { /* SQL version */ + /* SELECT address FROM list WHERE address = 'userhost' AND hash */ + /* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */ + /* even easier to defeat. Just faking sender to the list name would*/ + /* work. Since sender checks for posts are bogus anyway, I don't */ + /* know if it's worth the cost of the "WHERE ...". */ + + if (!stralloc_copys(&addr,userhost)) die_nomem(fatal); + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return 0; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + + if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal); + if (!stralloc_cat(&line,&addr)) die_nomem(fatal); + if (!stralloc_cats(&line,"$'")) die_nomem(fatal); + + if (!stralloc_0(&line)) die_nomem(fatal); + result = PQexec(psql,line.s); + if (result == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_TUPLES_OK ) + strerr_die2x(111,fatal,PQresultErrorMessage(result)); + + /* No data returned in QUERY */ + if (PQntuples(result) < 1) + return (char *)0; + + if (!stralloc_copyb(&line,PQgetvalue(result,0,0),PQgetlength(result,0,0))) + die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + + PQclear(result); + return line.s; + } +} + diff --git a/sub_pgsql/logmsg.c b/sub_pgsql/logmsg.c new file mode 100644 index 0000000..8f734ec --- /dev/null +++ b/sub_pgsql/logmsg.c @@ -0,0 +1,83 @@ +/*$Id: logmsg.c,v 1.3 1999/12/23 02:40:57 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" +#include +#include + +static stralloc logline = {0}; +static strnum[FMT_ULONG]; + +char *logmsg(dir,num,listno,subs,done) +/* creates an entry for message num and the list listno and code "done". */ +/* Returns NULL on success, "" if dir/sql was not found, and the error */ +/* string on error. NOTE: This routine does nothing for non-sql lists! */ +char *dir; +unsigned long num; +unsigned long listno; +unsigned long subs; +int done; +{ + char *table = (char *) 0; + char *ret; + + PGresult *result; + PGresult *result2; + + if ((ret = opensql(dir,&table))) { + if (*ret) + return ret; + else + return (char *) 0; /* no SQL => success */ + } + if (!stralloc_copys(&logline,"INSERT INTO ")) return ERR_NOMEM; + if (!stralloc_cats(&logline,table)) return ERR_NOMEM; + if (!stralloc_cats(&logline,"_mlog (msgnum,listno,subs,done) VALUES (")) + return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num))) return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno))) + return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,subs))) return ERR_NOMEM; + if (!stralloc_cats(&logline,",")) return ERR_NOMEM; + if (done < 0) { + done = - done; + if (!stralloc_append(&logline,"-")) return ERR_NOMEM; + } + if (!stralloc_catb(&logline,strnum,fmt_uint(strnum,done))) return ERR_NOMEM; + if (!stralloc_append(&logline,")")) return ERR_NOMEM; + + if (!stralloc_0(&logline)) return ERR_NOMEM; + result = PQexec(psql,logline.s); + if(result==NULL) + return (PQerrorMessage(psql)); + if(PQresultStatus(result) != PGRES_COMMAND_OK) { /* Check if duplicate */ + if (!stralloc_copys(&logline,"SELECT msgnum FROM ")) return ERR_NOMEM; + if (!stralloc_cats(&logline,table)) return ERR_NOMEM; + if (!stralloc_cats(&logline,"_mlog WHERE msgnum = ")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,num))) + return ERR_NOMEM; + if (!stralloc_cats(&logline," AND listno = ")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,listno))) + return ERR_NOMEM; + if (!stralloc_cats(&logline," AND done = ")) return ERR_NOMEM; + if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,done))) + return ERR_NOMEM; + /* Query */ + if (!stralloc_0(&logline)) return ERR_NOMEM; + result2 = PQexec(psql,logline.s); + if (result2 == NULL) + return (PQerrorMessage(psql)); + if (PQresultStatus(result2) != PGRES_TUPLES_OK) + return (char *) (PQresultErrorMessage(result2)); + /* No duplicate, return ERROR from first query */ + if (PQntuples(result2)<1) + return (char *) (PQresultErrorMessage(result)); + PQclear(result2); + } + PQclear(result); + return (char *) 0; +} diff --git a/sub_pgsql/opensql.c b/sub_pgsql/opensql.c new file mode 100644 index 0000000..265822a --- /dev/null +++ b/sub_pgsql/opensql.c @@ -0,0 +1,111 @@ +/*$Id: opensql.c,v 1.4 1999/11/28 19:55:31 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" +#include +#include + +static stralloc myp = {0}; +static stralloc ers = {0}; +static stralloc fn = {0}; +static stralloc ourdb = {0}; +static char *ourtable = (char *) 0; + +char *opensql(dbname,table) +/* reads the file dbname/sql, and if the file exists, parses it into the */ +/* components. The string should be host:port:user:pw:db:table. If */ +/* the file does not exists, returns "". On success returns NULL. On error */ +/* returns error string for temporary error. If table is NULL it is */ +/* left alone. If *table is not null, it overrides the table in the sql */ +/* file. If we already opended dbname the cached info is used, rather than */ +/* rereading the file. Note that myp is static and all pointers point to it.*/ +char *dbname; /* database directory */ +char **table; /* table root_name */ + +{ + char *host = (char *) 0; + char *port = (char *) 0; + char *db = "ezmlm"; /* default */ + char *user = (char *) 0; + char *pw = (char *) 0; + unsigned int j; + + if (!stralloc_copys(&fn,dbname)) return ERR_NOMEM; + if (fn.len == ourdb.len && !str_diffn(ourdb.s,fn.s,fn.len)) { + if (table) { + if (*table) ourtable = *table; + else *table = ourtable; + } + return 0; + } + if (!stralloc_cats(&fn,"/sql")) return ERR_NOMEM; + if (!stralloc_0(&fn)) return ERR_NOMEM; + /* host:port:db:table:user:pw:name */ + + myp.len = 0; + switch (slurp(fn.s,&myp,128)) { + case -1: if (!stralloc_copys(&ers,ERR_READ)) return ERR_NOMEM; + if (!stralloc_cat(&ers,&fn)) return ERR_NOMEM; + if (!stralloc_0(&ers)) return ERR_NOMEM; + return ers.s; + case 0: return ""; + } + if (!stralloc_copy(&ourdb,&fn)) return ERR_NOMEM; + if (!stralloc_append(&myp,"\n")) return ERR_NOMEM; + for (j=0; j< myp.len; ++j) { + if (myp.s[j] == '\n') { myp.s[j] = '\0'; break; } + } + /* get connection parameters */ + if (!stralloc_0(&myp)) return ERR_NOMEM; + host = myp.s; + if (myp.s[j = str_chr(myp.s,':')]) { + port = myp.s + j++; + *(port++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + user = myp.s + j++; + *(user++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + pw = myp.s + j++; + *(pw++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + db = myp.s + j++; + *(db++) = '\0'; + if (myp.s[j += str_chr(myp.s+j,':')]) { + ourtable = myp.s + j++; + *(ourtable++) = '\0'; + } + } + } + } + } + + if (host && !*host) host = (char *) 0; + if (user && !*user) user = (char *) 0; + if (pw && !*pw) pw = (char *) 0; + if (db && !*db) db = (char *) 0; + if (ourtable && !*ourtable) ourtable = (char *) 0; + if (table) { + if (*table) ourtable = *table; + else *table = ourtable; + if (!*table) return ERR_NO_TABLE; + } + if (!psql) { + /* Make connection to database */ + psql = PQsetdbLogin( host, port, NULL, NULL, db, user, pw); + /* Check to see that the backend connection was successfully made */ + if (PQstatus(psql) == CONNECTION_BAD) + return PQerrorMessage(psql); + } + return (char *) 0; +} + +void closesql() +/* close connection to SQL server, if open */ +{ + if (psql) PQfinish(psql); + psql = (void *) 0; /* Destroy pointer */ + return; +} + diff --git a/sub_pgsql/putsubs.c b/sub_pgsql/putsubs.c new file mode 100644 index 0000000..c53213c --- /dev/null +++ b/sub_pgsql/putsubs.c @@ -0,0 +1,128 @@ +#include "error.h" +#include "strerr.h" +#include "readwrite.h" +#include "str.h" +#include "fmt.h" +#include "stralloc.h" +#include "open.h" +#include "substdio.h" +#include "case.h" +#include "errtxt.h" +#include "subscribe.h" +#include "qmail.h" +#include +#include + +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 +#include + +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 +#include +#include + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static stralloc addr = {0}; +static stralloc lcaddr = {0}; +static stralloc line = {0}; +static stralloc domain = {0}; +static stralloc logline = {0}; +static stralloc fnnew = {0}; +static stralloc fn = {0}; +static stralloc fnlock = {0}; + +void die_read(fatal) +char *fatal; +{ + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); +} + +void die_write(fatal) +char *fatal; +{ + strerr_die4sys(111,fatal,ERR_WRITE,fnnew.s,": "); +} + +static int fd; +static substdio ss; +static char ssbuf[256]; +static int fdnew; +static substdio ssnew; +static char ssnewbuf[256]; + +int subscribe(dbname,userhost,flagadd,comment,event,flagsql, + forcehash,tab,fatal) +/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database */ +/* dbname. Comment is e.g. the subscriber from line or name. It is added to */ +/* the log. Event is the action type, e.g. "probe", "manual", etc. The */ +/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0 */ +/* on failure. If flagmysql is set and the file "sql" is found in the */ +/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */ +/* >=0 it is used in place of the calculated hash. This makes it possible to */ +/* add addresses with a hash that does not exist. forcehash has to be 0..99. */ +/* for unsubscribes, the address is only removed if forcehash matches the */ +/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/ +/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */ +/* used for sublist addresses (to avoid removal) and sublist aliases (to */ +/* prevent users from subscribing them (although the cookie mechanism would */ +/* prevent the resulting duplicate message from being distributed. */ + +char *dbname; +char *userhost; +int flagadd; +char *comment; +char *event; +int flagsql; +int forcehash; +char *tab; +char *fatal; +{ + int fdlock; + + PGresult *result; + + char *cpat; + char szhash[3] = "00"; + char *r = (char *) 0; + char *table = (char *) 0; + char **ptable = &table; + + unsigned int j; + uint32 h,lch; + unsigned char ch,lcch; + int match; + int flagwasthere; + + if (userhost[str_chr(userhost,'\n')]) + strerr_die2x(100,fatal,ERR_ADDR_NL); + + if (tab) ptable = &tab; + + if (!flagsql || (r = opensql(dbname,ptable))) { + if (r && *r) strerr_die2x(111,fatal,r); + /* fallback to local db */ + if (!stralloc_copys(&addr,"T")) die_nomem(fatal); + if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); + if (addr.len > 401) + strerr_die2x(100,fatal,ERR_ADDR_LONG); + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) + strerr_die2x(100,fatal,ERR_ADDR_AT); + case_lowerb(addr.s + j + 1,addr.len - j - 1); + if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s + 1,j - 1); /* make all-lc version of address */ + + if (forcehash >= 0 && forcehash <= 52) { + ch = lcch = (unsigned char) forcehash; + } else { + h = 5381; + lch = h; + for (j = 0;j < addr.len;++j) { + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + lcch = 64 + (lch % 53); + ch = 64 + (h % 53); + } + + if (!stralloc_0(&addr)) die_nomem(fatal); + if (!stralloc_0(&lcaddr)) die_nomem(fatal); + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_copys(&fnlock,dbname)) die_nomem(fatal); + + if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); + if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); + if (!stralloc_copy(&fnnew,&fn)) die_nomem(fatal); + /* code later depends on fnnew = fn + 'n' */ + if (!stralloc_cats(&fnnew,"n")) die_nomem(fatal); + if (!stralloc_cats(&fnlock,"/lock")) die_nomem(fatal); + if (!stralloc_0(&fnnew)) die_nomem(fatal); + if (!stralloc_0(&fn)) die_nomem(fatal); + if (!stralloc_0(&fnlock)) die_nomem(fatal); + + fdlock = open_append(fnlock.s); + if (fdlock == -1) + strerr_die4sys(111,fatal,ERR_OPEN,fnlock.s,": "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,fatal,ERR_OBTAIN,fnlock.s,": "); + + /* do lower case hashed version first */ + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) die_write(fatal); + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + flagwasthere = 0; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); die_read(fatal); } + } + else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { + close(fd); close(fdnew); die_read(fatal); + } + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) { + flagwasthere = 1; + if (!flagadd) + continue; + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) { + close(fd); close(fdnew); die_write(fatal); + } + } + + close(fd); + } + + if (flagadd && !flagwasthere) + if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { + close(fdnew); die_write(fatal); + } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); } + if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) + strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": "); + + if ((ch == lcch) || flagwasthere) { + close(fdlock); + if (flagadd ^ flagwasthere) { + if (!stralloc_0(&addr)) die_nomem(fatal); + log(dbname,event,addr.s+1,comment); + return 1; + } + return 0; + } + + /* If unsub and not found and hashed differ, OR */ + /* sub and not found (so added with new hash) */ + /* do the 'case-dependent' hash */ + + fn.s[fn.len - 2] = ch; + fnnew.s[fnnew.len - 3] = ch; + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) die_write(fatal); + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); die_read(fatal); } + } else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + { close(fd); close(fdnew); die_read(fatal); } + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) { + flagwasthere = 1; + continue; /* always want to remove from case-sensitive hash */ + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) + { close(fd); close(fdnew); die_write(fatal); } + } + + close(fd); + } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); } + if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) + strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": "); + + close(fdlock); + if (flagadd ^ flagwasthere) { + if (!stralloc_0(&addr)) die_nomem(fatal); + log(dbname,event,addr.s+1,comment); + return 1; + } + return 0; + + } else { /* SQL version */ + domain.len = 0; /* clear domain */ + /* lowercase and check address */ + if (!stralloc_copys(&addr,userhost)) die_nomem(fatal); + if (addr.len > 255) /* this is 401 in std ezmlm. 255 */ + /* should be plenty! */ + strerr_die2x(100,fatal,ERR_ADDR_LONG); + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) + strerr_die2x(100,fatal,ERR_ADDR_AT); + cpat = addr.s + j; + case_lowerb(cpat + 1,addr.len - j - 1); + + if (forcehash < 0) { + if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s,j); /* make all-lc version of address */ + h = 5381; + for (j = 0;j < lcaddr.len;++j) { + h = (h + (h << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + ch = (h % 53); /* 0 - 52 */ + } else + ch = (forcehash % 100); + + szhash[0] = '0' + ch / 10; /* hash for sublist split */ + szhash[1] = '0' + (ch % 10); + + if (flagadd) { + if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal); + if (!stralloc_cat(&line,&addr)) die_nomem(fatal); /* addr */ + if (!stralloc_cats(&line,"$'")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + result = PQexec(psql,line.s); + if (result == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_TUPLES_OK) + strerr_die2x(111,fatal,PQresultErrorMessage(result)); + + if (PQntuples(result)>0) { /* there */ + PQclear(result); + return 0; /* there */ + } else { /* not there */ + PQclear(result); + if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," (address,hash) VALUES ('")) + die_nomem(fatal); + if (!stralloc_cat(&line,&addr)) die_nomem(fatal); /* addr */ + if (!stralloc_cats(&line,"',")) die_nomem(fatal); + if (!stralloc_cats(&line,szhash)) die_nomem(fatal); /* hash */ + if (!stralloc_cats(&line,")")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + result = PQexec(psql,line.s); + if (result == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_COMMAND_OK) + strerr_die2x(111,fatal,PQresultErrorMessage(result)); + } + } else { /* unsub */ + if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line," WHERE address ~* '^")) die_nomem(fatal); + if (!stralloc_cat(&line,&addr)) die_nomem(fatal); /* addr */ + if (forcehash >= 0) { + if (!stralloc_cats(&line,"$' AND hash=")) die_nomem(fatal); + if (!stralloc_cats(&line,szhash)) die_nomem(fatal); + } else { + if (!stralloc_cats(&line,"$' AND hash BETWEEN 0 AND 52")) + die_nomem(fatal); + } + + if (!stralloc_0(&line)) die_nomem(fatal); + result = PQexec(psql,line.s); + if (result == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_COMMAND_OK) + strerr_die2x(111,fatal,PQresultErrorMessage(result)); + if (atoi(PQcmdTuples(result))<1) + return 0; /* address wasn't there*/ + PQclear(result); + } + + /* log to subscriber log */ + /* INSERT INTO t_slog (address,edir,etype,fromline) */ + /* VALUES('address',{'+'|'-'},'etype','[comment]') */ + + if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem(fatal); + if (!stralloc_cats(&logline,table)) die_nomem(fatal); + if (!stralloc_cats(&logline, + "_slog (address,edir,etype,fromline) VALUES ('")) die_nomem(fatal); + if (!stralloc_cat(&logline,&addr)) die_nomem(fatal); + if (flagadd) { /* edir */ + if (!stralloc_cats(&logline,"','+','")) die_nomem(fatal); + } else { + if (!stralloc_cats(&logline,"','-','")) die_nomem(fatal); + } + if (*(event + 1)) /* ezmlm-0.53 uses '' for ezmlm-manage's work */ + if (!stralloc_catb(&logline,event+1,1)) die_nomem(fatal); /* etype */ + if (!stralloc_cats(&logline,"','")) die_nomem(fatal); + if (comment && *comment) { + if (!stralloc_cats(&logline,comment)) die_nomem(fatal); + } + if (!stralloc_cats(&logline,"')")) die_nomem(fatal); + + if (!stralloc_0(&logline)) die_nomem(fatal); + result = PQexec(psql,logline.s); /* log (ignore errors) */ + PQclear(result); + + if (!stralloc_0(&addr)) + ; /* ignore errors */ + log(dbname,event,addr.s,comment); /* also log to old log */ + return 1; /* desired effect */ + } +} diff --git a/sub_pgsql/tagmsg.c b/sub_pgsql/tagmsg.c new file mode 100644 index 0000000..a99797a --- /dev/null +++ b/sub_pgsql/tagmsg.c @@ -0,0 +1,115 @@ +/*$Id: tagmsg.c,v 1.2 1999/10/07 23:31:01 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "strerr.h" +#include "cookie.h" +#include "slurp.h" +#include "errtxt.h" +#include "subscribe.h" +#include "makehash.h" +#include +#include + +static stralloc line = {0}; +static stralloc key = {0}; +static char hash[COOKIE]; +static char strnum[FMT_ULONG]; /* message number as sz */ + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(100,fatal,ERR_NOMEM); +} + +void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal) +/* This routine creates a cookie from num,seed and the */ +/* list key and returns that cookie in hashout. The use of sender/num and */ +/* first char of action is used to make cookie differ between messages, */ +/* the key is the secret list key. The cookie will be inserted into */ +/* table_cookie where table and other data is taken from dir/sql. We log */ +/* arrival of the message (done=0). */ + +char *dir; /* db base dir */ +unsigned long msgnum; /* number of this message */ +char *seed; /* seed. NULL ok, but less entropy */ +char *action; /* to make it certain the cookie differs from*/ + /* one used for a digest */ +char *hashout; /* calculated hash goes here */ +unsigned long bodysize; +unsigned long chunk; +char *fatal; +{ + PGresult *result; + PGresult *result2; /* Need for dupicate check */ + char *table = (char *) 0; + char *ret; + unsigned int i; + + strnum[fmt_ulong(strnum,msgnum)] = '\0'; /* message nr ->string*/ + + switch(slurp("key",&key,32)) { + case -1: + strerr_die3sys(111,fatal,ERR_READ,"key: "); + case 0: + strerr_die3x(100,fatal,"key",ERR_NOEXIST); + } + cookie(hash,key.s,key.len,strnum,seed,action); + for (i = 0; i < COOKIE; i++) + hashout[i] = hash[i]; + + if ((ret = opensql(dir,&table))) { + if (*ret) strerr_die2x(111,fatal,ret); + return; /* no sql => success */ + + } else { + if (chunk >= 53L) chunk = 0L; /* sanity */ + + /* INSERT INTO table_cookie (msgnum,cookie) VALUES (num,cookie) */ + /* (we may have tried message before, but failed to complete, so */ + /* ER_DUP_ENTRY is ok) */ + if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line,"_cookie (msgnum,cookie,bodysize,chunk) VALUES (")) + die_nomem(fatal); + if (!stralloc_cats(&line,strnum)) die_nomem(fatal); + if (!stralloc_cats(&line,",'")) die_nomem(fatal); + if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(fatal); + if (!stralloc_cats(&line,"',")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,bodysize))) + die_nomem(fatal); + if (!stralloc_cats(&line,",")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,chunk))) die_nomem(fatal); + if (!stralloc_cats(&line,")")) die_nomem(fatal); + + if (!stralloc_0(&line)) die_nomem(fatal); + result = PQexec(psql,line.s); + if (result == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result) != PGRES_COMMAND_OK) { /* Possible tuplicate */ + if (!stralloc_copys(&line,"SELECT msgnum FROM ")) die_nomem(fatal); + if (!stralloc_cats(&line,table)) die_nomem(fatal); + if (!stralloc_cats(&line,"_cookie WHERE msgnum = ")) die_nomem(fatal); + if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) + die_nomem(fatal); + /* Query */ + if (!stralloc_0(&line)) die_nomem(fatal); + result2 = PQexec(psql,line.s); + if (result2 == NULL) + strerr_die2x(111,fatal,PQerrorMessage(psql)); + if (PQresultStatus(result2) != PGRES_TUPLES_OK) + strerr_die2x(111,fatal,PQresultErrorMessage(result2)); + /* No duplicate, return ERROR from first query */ + if (PQntuples(result2)<1) + strerr_die2x(111,fatal,PQresultErrorMessage(result)); + PQclear(result2); + } + PQclear(result); + + if (! (ret = logmsg(dir,msgnum,0L,0L,1))) return; /* log done=1*/ + if (*ret) strerr_die2x(111,fatal,ret); + } + + return; +} diff --git a/sub_std/README b/sub_std/README new file mode 100644 index 0000000..d721a22 --- /dev/null +++ b/sub_std/README @@ -0,0 +1,31 @@ +$Id: README,v 1.2 1999/02/20 20:03:11 lindberg Exp $ +$Name: ezmlm-idx-040 $ +STANDARD EZMLM DATABASE INTERFACE + +These files comprise the ezmlm subscriber database interface. issub.c and +subscribe.c are backwards compatible with ezmlm-0.53 in terms of function, +but use a case-insensitive hash for address storage, and take a few +extra args to be plug-in compatible with alternative interfaces. Logging to +the subscriber log (DIR/Log) is done from subscribe.c rather than externally, +and the subscriber from line is logged as well. + +searchlog.c allows access to DIR/Log. + +putsubs.c does all output of subscriber addresses, both to qmail for subscibers, +moderator sendouts, etc, and to list subscribers in reply to the -list command. + +Alternative subscriber db interface routines should perform equivalent services, +and fall back to these services if the alternative interface is not configured, +e.g. if DIR/sql doe not exist. + +HOW TO SET UP A CLUSTER OF LIST AND SUBLISTS WITH STD DBS + +See FAQ.idx. + +See SQL-enabled ezmlm list documentation in FAQ.idx for a different +trade-off between these points. + + + + + diff --git a/sub_std/checktag.c b/sub_std/checktag.c new file mode 100644 index 0000000..f84350a --- /dev/null +++ b/sub_std/checktag.c @@ -0,0 +1,46 @@ +/*$Id: checktag.c,v 1.4 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "cookie.h" +#include "makehash.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" + +static stralloc key = {0}; +static stralloc line = {0}; +static stralloc quoted = {0}; +static char strnum[FMT_ULONG]; +static char newcookie[COOKIE]; + +char *checktag (dir,num,listno,action,seed,hash) +/* reads dir/sql. If not present, checks that the hash of seed matches */ +/* hash and returns success (NULL). If not match returns "". If error, */ +/* returns error string */ + +char *dir; /* the db base dir */ +unsigned long num; /* message number */ +unsigned long listno; /* bottom of range => slave */ +char *action; +char *seed; /* cookie base */ +char *hash; /* cookie */ +{ + + if (!seed) return (char *) 0; /* no data - accept */ + + strnum[fmt_ulong(strnum,num)] = '\0'; /* message nr ->string*/ + + switch(slurp("key",&key,32)) { + case -1: + return ERR_READ_KEY; + case 0: + return ERR_NOEXIST_KEY; + } + + cookie(newcookie,key.s,key.len,strnum,seed,action); + if (byte_diff(hash,COOKIE,newcookie)) return ""; + else return (char *) 0; + +} diff --git a/sub_std/conf-sqlcc b/sub_std/conf-sqlcc new file mode 100644 index 0000000..ce074b1 --- /dev/null +++ b/sub_std/conf-sqlcc @@ -0,0 +1,4 @@ + + +# the top line will be used when compiling. This version is for +# linking without mysql support. diff --git a/sub_std/conf-sqlld b/sub_std/conf-sqlld new file mode 100644 index 0000000..dcfa3d1 --- /dev/null +++ b/sub_std/conf-sqlld @@ -0,0 +1,4 @@ + + +# the top line will be used when linking. This version is for +# linking without mysql support. diff --git a/sub_std/ezmlm-mktab b/sub_std/ezmlm-mktab new file mode 100755 index 0000000..828448a --- /dev/null +++ b/sub_std/ezmlm-mktab @@ -0,0 +1,7 @@ +#!/bin/sh +echo +echo "This is the standard database version. You do not need to" +echo "create any separate databases for this version." +echo +exit 1 + diff --git a/sub_std/issub.c b/sub_std/issub.c new file mode 100644 index 0000000..22e6367 --- /dev/null +++ b/sub_std/issub.c @@ -0,0 +1,120 @@ +/*$Id: issub.c,v 1.4 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "strerr.h" +#include "error.h" +#include "uint32.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static stralloc addr = {0}; +static stralloc lcaddr = {0}; +static stralloc line = {0}; +static stralloc quoted = {0}; +static stralloc fn = {0}; +static substdio ss; +static char ssbuf[512]; +static char szh[FMT_ULONG]; + +char *issub(dbname,userhost,tab,fatal) +/* Returns (char *) to match if userhost is in the subscriber database */ +/* dbname, 0 otherwise. dbname is a base directory for a list and may NOT */ +/* be NULL */ +/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/ + +char *dbname; /* directory to basedir */ +char *userhost; +char *tab; /* override table name */ +char *fatal; + +{ + + int fd; + unsigned int j; + uint32 h,lch; + char ch,lcch; + int match; + + if (!stralloc_copys(&addr,"T")) die_nomem(fatal); + if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) return (char *) 0; + case_lowerb(addr.s + j + 1,addr.len - j - 1); + if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s + 1,j - 1); /* totally lc version of addr */ + + h = 5381; + lch = h; /* make hash for both for backwards comp */ + for (j = 0;j < addr.len;++j) { /* (lcaddr.len == addr.len) */ + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + ch = 64 + (h % 53); + lcch = 64 + (lch % 53); + + if (!stralloc_0(&addr)) die_nomem(fatal); + if (!stralloc_0(&lcaddr)) die_nomem(fatal); + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); + if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); + if (!stralloc_0(&fn)) die_nomem(fatal); + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + } else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == lcaddr.len) + if (!case_diffb(line.s,line.len,lcaddr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + } + /* here if file not found or (file found && addr not there) */ + + if (ch == lcch) return (char *) 0; + + /* try case sensitive hash for backwards compatibility */ + fn.s[fn.len - 2] = ch; + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,fn.s,": "); + return (char *) 0; + } + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) + { close(fd); return line.s+1; } + } + + close(fd); + + return (char *) 0; +} diff --git a/sub_std/logmsg.c b/sub_std/logmsg.c new file mode 100644 index 0000000..594a96a --- /dev/null +++ b/sub_std/logmsg.c @@ -0,0 +1,19 @@ +/*$Id: logmsg.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "fmt.h" +#include "subscribe.h" +#include "errtxt.h" + +static stralloc logline = {0}; +static strnum[FMT_ULONG]; + +char *logmsg(dir,num,listno,subs,done) +char *dir; +unsigned long num; +unsigned long listno; +unsigned long subs; +int done; +{ + return (char *) 0; /* no SQL => success */ +} diff --git a/sub_std/opensql.c b/sub_std/opensql.c new file mode 100644 index 0000000..9601da3 --- /dev/null +++ b/sub_std/opensql.c @@ -0,0 +1,27 @@ +/*$Id: opensql.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "strerr.h" +#include "errtxt.h" +#include "subscribe.h" + +static stralloc myp = {0}; +static stralloc ers = {0}; +static stralloc fn = {0}; +static stralloc ourdb = {0}; +static char *ourtable = (char *) 0; + +char *opensql(dbname,table) +char *dbname; /* database directory */ +char **table; /* table root_name */ + +{ + return 0; +} + +void closesql() +/* close connection to SQL server, if open */ +{ + return; +} + diff --git a/sub_std/putsubs.c b/sub_std/putsubs.c new file mode 100644 index 0000000..d3de6bc --- /dev/null +++ b/sub_std/putsubs.c @@ -0,0 +1,86 @@ +#include "error.h" +#include "strerr.h" +#include "readwrite.h" +#include "str.h" +#include "fmt.h" +#include "stralloc.h" +#include "open.h" +#include "substdio.h" +#include "case.h" +#include "errtxt.h" +#include "subscribe.h" +#include "qmail.h" + +static substdio ssin; +static char inbuf[512]; +char strnum[FMT_ULONG]; +static stralloc line = {0}; +static stralloc domains = {0}; +static stralloc quoted = {0}; +static stralloc fn = {0}; + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static void die_write(fatal) +char *fatal; +{ + strerr_die3x(111,fatal,ERR_WRITE,"stdout"); +} + +unsigned long putsubs(dbname,hash_lo,hash_hi, + subwrite,flagsql,fatal) +/* Outputs all userhostesses in 'dbname' to stdout. If userhost is not null */ +/* that userhost is excluded. 'dbname' is the base directory name. */ +/* subwrite must be a*/ +/* function returning >=0 on success, -1 on error, and taking arguments */ +/* (char* string, unsigned int length). It will be called once per address */ +/* and should take care of newline or whatever needed for the output form. */ + +char *dbname; /* database base dir */ +unsigned long hash_lo; +unsigned long hash_hi; +int subwrite(); /* write function. */ +int flagsql; +char *fatal; /* fatal error string */ + +{ + + unsigned int i; + int fd; + unsigned long no = 0L; + int match; + unsigned int hashpos; + + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_catb(&fn,"/subscribers/?",15)) die_nomem(fatal); + /* NOTE: Also copies terminal '\0' */ + hashpos = fn.len - 2; + if (hash_lo > 52) hash_lo = 52; + if (hash_hi > 52) hash_hi = 52; + if (hash_hi < hash_lo) hash_hi = hash_lo; + + for (i = hash_lo;i <= hash_hi;++i) { + fn.s[hashpos] = 64 + i; /* hash range 0-52 */ + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + } else { + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + for (;;) { + if (getln(&ssin,&line,&match,'\0') == -1) + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); + if (!match) + break; + if (subwrite(line.s + 1,line.len - 2) == -1) die_write(fatal); + no++; + } + close(fd); + } + } + return no; +} diff --git a/sub_std/searchlog.c b/sub_std/searchlog.c new file mode 100644 index 0000000..1cee6f9 --- /dev/null +++ b/sub_std/searchlog.c @@ -0,0 +1,114 @@ +/*$Id: searchlog.c,v 1.6 1999/10/09 14:22:38 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "case.h" +#include "scan.h" +#include "stralloc.h" +#include "str.h" +#include "open.h" +#include "datetime.h" +#include "date822fmt.h" +#include "substdio.h" +#include "readwrite.h" +#include "strerr.h" +#include "error.h" +#include "errtxt.h" +#include "subscribe.h" + +static stralloc line = {0}; +static stralloc outline = {0}; +static char date[DATE822FMT]; +static datetime_sec when; +static struct datetime dt; +static substdio ssin; +static char inbuf[256]; + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(100,fatal,ERR_NOMEM); +} + +static void lineout(subwrite,fatal) +int subwrite(); +char *fatal; +{ + (void) scan_ulong(line.s,&when); + datetime_tai(&dt,when); /* there is always at least a '\n' */ + if (!stralloc_copyb(&outline,date,date822fmt(date,&dt) - 1)) + die_nomem(fatal); + if (!stralloc_cats(&outline,": ")) die_nomem(fatal); + if (!stralloc_catb(&outline,line.s,line.len - 1)) die_nomem(fatal); + if (subwrite(outline.s,outline.len) == -1) + strerr_die3x(111,fatal,ERR_WRITE,"output"); + return; +} + +void searchlog(dir,search,subwrite,fatal) +/* opens dir/Log, and outputs via subwrite(s,len) any line that matches */ +/* search. A '_' is search is a wildcard. Any other non-alphanum/'.' char */ +/* is replaced by a '_' */ + +char *dir; /* work directory */ +char *search; /* search string */ +int subwrite(); /* output fxn */ +char *fatal; /* fatal */ +{ + + register unsigned char x; + register unsigned char y; + register unsigned char *cp; + register unsigned char *cpsearch; + unsigned register char *cps; + unsigned register char ch; + unsigned char *cplast, *cpline; + unsigned int searchlen; + int fd,match; + + searchlen = str_len(search); + case_lowerb(search,searchlen); + cps = (unsigned char *) search; + while ((ch = *(cps++))) { /* search is potentially hostile */ + if (ch >= 'a' && ch <= 'z') continue; + if (ch >= '0' && ch <= '9') continue; + if (ch == '.' || ch == '_') continue; + *(cps - 1) = '_'; /* will [also] match char specified */ + } + + if (!stralloc_copys(&line,dir)) die_nomem(fatal); + if (!stralloc_cats(&line,"/Log")) die_nomem(fatal); + if (!stralloc_0(&line)) die_nomem(fatal); + fd = open_read(line.s); + if (fd == -1) + if (errno != error_noent) + strerr_die4sys(111,fatal,ERR_OPEN,line.s,": "); + else + strerr_die3x(100,fatal,line.s,ERR_NOEXIST); + substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); + + for (;;) { + if (getln(&ssin,&line,&match,'\n') == -1) + strerr_die2sys(111,fatal,ERR_READ_INPUT); + if (!match) break; + if (!searchlen) { + lineout(subwrite,fatal); + } else { /* simple case-insensitive search */ + cpline = (unsigned char *) line.s - 1; + cplast = cpline + line.len - searchlen; /* line has \0 at the end */ + while ((cp = ++cpline) <= cplast) { + cpsearch = (unsigned char *) search; + for (;;) { + x = *cpsearch++; + if (!x) break; + y = *cp++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y && x != '_') break; /* '_' = wildcard */ + } + if (!x) { + lineout(subwrite,fatal); + break; + } + } + } + } + close(fd); +} diff --git a/sub_std/subscribe.c b/sub_std/subscribe.c new file mode 100644 index 0000000..278bc8e --- /dev/null +++ b/sub_std/subscribe.c @@ -0,0 +1,244 @@ +/*$Id: subscribe.c,v 1.5 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "getln.h" +#include "readwrite.h" +#include "substdio.h" +#include "strerr.h" +#include "open.h" +#include "byte.h" +#include "case.h" +#include "lock.h" +#include "error.h" +#include "subscribe.h" +#include "uint32.h" +#include "fmt.h" +#include "errtxt.h" +#include "log.h" +#include "idx.h" + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(111,fatal,ERR_NOMEM); +} + +static stralloc addr = {0}; +static stralloc lcaddr = {0}; +static stralloc line = {0}; +static stralloc domain = {0}; +static stralloc logline = {0}; +static stralloc quoted = {0}; +static stralloc fnnew = {0}; +static stralloc fn = {0}; +static stralloc fnlock = {0}; +static char szh[FMT_ULONG]; + +void die_read(fatal) +char *fatal; +{ + strerr_die4sys(111,fatal,ERR_READ,fn.s,": "); +} + +void die_write(fatal) +char *fatal; +{ + strerr_die4sys(111,fatal,ERR_WRITE,fnnew.s,": "); +} + +static int fd; +static substdio ss; +static char ssbuf[256]; +static int fdnew; +static substdio ssnew; +static char ssnewbuf[256]; + +int subscribe(dbname,userhost,flagadd,comment,event,flagmysql, + forcehash,tab,fatal) +/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database */ +/* dbname. Comment is e.g. the subscriber from line or name. It is added to */ +/* the log. Event is the action type, e.g. "probe", "manual", etc. The */ +/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0 */ +/* on failure. If flagmysql is set and the file "sql" is found in the */ +/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */ +/* >=0 it is used in place of the calculated hash. This makes it possible to */ +/* add addresses with a hash that does not exist. forcehash has to be 0..99. */ +/* for unsubscribes, the address is only removed if forcehash matches the */ +/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/ +/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */ +/* used for sublist addresses (to avoid removal) and sublist aliases (to */ +/* prevent users from subscribing them (although the cookie mechanism would */ +/* prevent the resulting duplicate message from being distributed. */ + +char *dbname; +char *userhost; +int flagadd; +char *comment; +char *event; +int flagmysql; +int forcehash; +char *tab; +char *fatal; +{ + int fdlock; + + char szhash[3] = "00"; + + unsigned int j; + uint32 h,lch; + unsigned char ch,lcch; + int match; + int flagwasthere; + + if (userhost[str_chr(userhost,'\n')]) + strerr_die2x(100,fatal,ERR_ADDR_NL); + + if (!stralloc_copys(&addr,"T")) die_nomem(fatal); + if (!stralloc_cats(&addr,userhost)) die_nomem(fatal); + if (addr.len > 401) + strerr_die2x(100,fatal,ERR_ADDR_LONG); + + j = byte_rchr(addr.s,addr.len,'@'); + if (j == addr.len) + strerr_die2x(100,fatal,ERR_ADDR_AT); + case_lowerb(addr.s + j + 1,addr.len - j - 1); + if (!stralloc_copy(&lcaddr,&addr)) die_nomem(fatal); + case_lowerb(lcaddr.s + 1,j - 1); /* make all-lc version of address */ + + if (forcehash >= 0 && forcehash <= 52) { + ch = lcch = (unsigned char) forcehash; + } else { + h = 5381; + lch = h; + for (j = 0;j < addr.len;++j) { + h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; + lch = (lch + (lch << 5)) ^ (uint32) (unsigned char) lcaddr.s[j]; + } + lcch = 64 + (lch % 53); + ch = 64 + (h % 53); + } + + if (!stralloc_0(&addr)) die_nomem(fatal); + if (!stralloc_0(&lcaddr)) die_nomem(fatal); + if (!stralloc_copys(&fn,dbname)) die_nomem(fatal); + if (!stralloc_copys(&fnlock,dbname)) die_nomem(fatal); + + if (!stralloc_cats(&fn,"/subscribers/")) die_nomem(fatal); + if (!stralloc_catb(&fn,&lcch,1)) die_nomem(fatal); + if (!stralloc_copy(&fnnew,&fn)) die_nomem(fatal); + /* code later depends on fnnew = fn + 'n' */ + if (!stralloc_cats(&fnnew,"n")) die_nomem(fatal); + if (!stralloc_cats(&fnlock,"/lock")) die_nomem(fatal); + if (!stralloc_0(&fnnew)) die_nomem(fatal); + if (!stralloc_0(&fn)) die_nomem(fatal); + if (!stralloc_0(&fnlock)) die_nomem(fatal); + + fdlock = open_append(fnlock.s); + if (fdlock == -1) + strerr_die4sys(111,fatal,ERR_OPEN,fnlock.s,": "); + if (lock_ex(fdlock) == -1) + strerr_die4sys(111,fatal,ERR_OBTAIN,fnlock.s,": "); + + /* do lower case hashed version first */ + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) die_write(fatal); + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + flagwasthere = 0; + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); die_read(fatal); } + } + else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) { + close(fd); close(fdnew); die_read(fatal); + } + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) { + flagwasthere = 1; + if (!flagadd) + continue; + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) { + close(fd); close(fdnew); die_write(fatal); + } + } + + close(fd); + } + + if (flagadd && !flagwasthere) + if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { + close(fdnew); die_write(fatal); + } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); } + if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) + strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": "); + + if ((ch == lcch) || flagwasthere) { + close(fdlock); + if (flagadd ^ flagwasthere) { + if (!stralloc_0(&addr)) die_nomem(fatal); + log(dbname,event,addr.s+1,comment); + return 1; + } + return 0; + } + + /* If unsub and not found and hashed differ, OR */ + /* sub and not found (so added with new hash) */ + /* do the 'case-dependent' hash */ + + fn.s[fn.len - 2] = ch; + fnnew.s[fnnew.len - 3] = ch; + fdnew = open_trunc(fnnew.s); + if (fdnew == -1) die_write(fatal); + substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); + + fd = open_read(fn.s); + if (fd == -1) { + if (errno != error_noent) { close(fdnew); die_read(fatal); } + } else { + substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); + + for (;;) { + if (getln(&ss,&line,&match,'\0') == -1) + { close(fd); close(fdnew); die_read(fatal); } + if (!match) break; + if (line.len == addr.len) + if (!case_diffb(line.s,line.len,addr.s)) { + flagwasthere = 1; + continue; /* always want to remove from case-sensitive hash */ + } + if (substdio_bput(&ssnew,line.s,line.len) == -1) + { close(fd); close(fdnew); die_write(fatal); } + } + + close(fd); + } + + if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(fatal); } + if (fsync(fdnew) == -1) { close(fdnew); die_write(fatal); } + close(fdnew); + + if (rename(fnnew.s,fn.s) == -1) + strerr_die6sys(111,fatal,ERR_MOVE,fnnew.s," to ",fn.s,": "); + + close(fdlock); + if (flagadd ^ flagwasthere) { + if (!stralloc_0(&addr)) die_nomem(fatal); + log(dbname,event,addr.s+1,comment); + return 1; + } + return 0; + +} diff --git a/sub_std/tagmsg.c b/sub_std/tagmsg.c new file mode 100644 index 0000000..0919346 --- /dev/null +++ b/sub_std/tagmsg.c @@ -0,0 +1,55 @@ +/*$Id: tagmsg.c,v 1.3 1999/10/12 23:38:36 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ +#include "stralloc.h" +#include "scan.h" +#include "fmt.h" +#include "strerr.h" +#include "cookie.h" +#include "slurp.h" +#include "errtxt.h" +#include "subscribe.h" +#include "makehash.h" + +static stralloc line = {0}; +static stralloc key = {0}; +static char hash[COOKIE]; +static char strnum[FMT_ULONG]; /* message number as sz */ + +static void die_nomem(fatal) +char *fatal; +{ + strerr_die2x(100,fatal,ERR_NOMEM); +} + +void tagmsg(dir,msgnum,seed,action,hashout,bodysize,chunk,fatal) +/* This routine creates a cookie from num,seed and the */ +/* list key and returns that cookie in hashout. The use of sender/num and */ +/* first char of action is used to make cookie differ between messages, */ +/* the key is the secret list key. */ + +char *dir; /* db base dir */ +unsigned long msgnum; /* number of this message */ +char *seed; /* seed. NULL ok, but less entropy */ +char *action; /* to make it certain the cookie differs from*/ + /* one used for a digest */ +char *hashout; /* calculated hash goes here */ +unsigned long bodysize; +unsigned long chunk; +char *fatal; +{ + unsigned int i; + + strnum[fmt_ulong(strnum,msgnum)] = '\0'; /* message nr ->string*/ + + switch(slurp("key",&key,32)) { + case -1: + strerr_die3sys(111,fatal,ERR_READ,"key: "); + case 0: + strerr_die3x(100,fatal,"key",ERR_NOEXIST); + } + cookie(hash,key.s,key.len,strnum,seed,action); + for (i = 0; i < COOKIE; i++) + hashout[i] = hash[i]; + + return; +} diff --git a/subscribe.c b/subscribe.c deleted file mode 100644 index fee21e2..0000000 --- a/subscribe.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "stralloc.h" -#include "getln.h" -#include "readwrite.h" -#include "substdio.h" -#include "strerr.h" -#include "open.h" -#include "byte.h" -#include "case.h" -#include "lock.h" -#include "error.h" -#include "uint32.h" -#include "subscribe.h" - -static stralloc addr = {0}; -static stralloc line = {0}; -static stralloc fnnew = {0}; -static stralloc fn = {0}; - -static int fd; -static substdio ss; -static char ssbuf[256]; -static int fdnew; -static substdio ssnew; -static char ssnewbuf[256]; - -static int doit(userhost,flagadd) -char *userhost; -int flagadd; -{ - int j; - uint32 h; - char ch; - int match; - int flagwasthere; - - if (userhost[str_chr(userhost,'\n')]) return -8; - if (!stralloc_copys(&addr,"T")) return -2; - if (!stralloc_cats(&addr,userhost)) return -2; - if (addr.len > 401) return -7; - - j = byte_rchr(addr.s,addr.len,'@'); - if (j == addr.len) return -6; - case_lowerb(addr.s + j + 1,addr.len - j - 1); - - h = 5381; - for (j = 0;j < addr.len;++j) - h = (h + (h << 5)) ^ (uint32) (unsigned char) addr.s[j]; - ch = 64 + (h % 53); - - if (!stralloc_0(&addr)) return -2; - - if (!stralloc_copys(&fn,"subscribers/")) return -2; - if (!stralloc_catb(&fn,&ch,1)) return -2; - if (!stralloc_copy(&fnnew,&fn)) return -2; - if (!stralloc_cats(&fnnew,"n")) return -2; - if (!stralloc_0(&fnnew)) return -2; - if (!stralloc_0(&fn)) return -2; - - fdnew = open_trunc(fnnew.s); - if (fdnew == -1) return -4; - substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf)); - - flagwasthere = 0; - - fd = open_read(fn.s); - if (fd == -1) { - if (errno != error_noent) { close(fdnew); return -3; } - } - else { - substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf)); - - for (;;) { - if (getln(&ss,&line,&match,'\0') == -1) { close(fd); close(fdnew); return -3; } - if (!match) break; - if (line.len == addr.len) - if (!byte_diff(line.s,line.len,addr.s)) { - flagwasthere = 1; - if (!flagadd) - continue; - } - if (substdio_bput(&ssnew,line.s,line.len) == -1) { close(fd); close(fdnew); return -4; } - } - - close(fd); - } - - if (flagadd && !flagwasthere) - if (substdio_bput(&ssnew,addr.s,addr.len) == -1) { close(fdnew); return -4; } - - if (substdio_flush(&ssnew) == -1) { close(fdnew); return -4; } - if (fsync(fdnew) == -1) { close(fdnew); return -4; } - close(fdnew); - - if (rename(fnnew.s,fn.s) == -1) return -5; - return flagadd ^ flagwasthere; -} - -struct strerr subscribe_err; - -int subscribe(userhost,flagadd) -char *userhost; -int flagadd; -{ - int fdlock; - int r; - - fdlock = open_append("lock"); - if (fdlock == -1) - STRERR_SYS(-1,subscribe_err,"unable to open lock: ") - if (lock_ex(fdlock) == -1) { - close(fdlock); - STRERR_SYS(-1,subscribe_err,"unable to obtain lock: ") - } - - r = doit(userhost,flagadd); - close(fdlock); - - if (r == -2) STRERR(-1,subscribe_err,"out of memory") - if (r == -3) STRERR_SYS3(-1,subscribe_err,"unable to read ",fn.s,": ") - if (r == -4) STRERR_SYS3(-1,subscribe_err,"unable to write ",fnnew.s,": ") - if (r == -5) STRERR_SYS3(-1,subscribe_err,"unable to move temporary file to ",fn.s,": ") - if (r == -6) STRERR(-2,subscribe_err,"address does not contain @") - if (r == -7) STRERR(-2,subscribe_err,"address is too long") - if (r == -8) STRERR(-2,subscribe_err,"address contains newline") - - return r; -} diff --git a/subscribe.c b/subscribe.c new file mode 120000 index 0000000..1c16bae --- /dev/null +++ b/subscribe.c @@ -0,0 +1 @@ +sub_std/subscribe.c \ No newline at end of file diff --git a/subscribe.h b/subscribe.h index 48a2f1c..ee43887 100644 --- a/subscribe.h +++ b/subscribe.h @@ -1,10 +1,60 @@ +/*$Id: subscribe.h,v 1.14 1999/10/03 19:23:31 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ #ifndef SUBSCRIBE_H #define SUBSCRIBE_H -#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 diff --git a/tagmsg.c b/tagmsg.c new file mode 120000 index 0000000..4f795c9 --- /dev/null +++ b/tagmsg.c @@ -0,0 +1 @@ +sub_std/tagmsg.c \ No newline at end of file diff --git a/unfoldHDR.c b/unfoldHDR.c new file mode 100644 index 0000000..6004f0b --- /dev/null +++ b/unfoldHDR.c @@ -0,0 +1,303 @@ +/*$Id: unfoldHDR.c,v 1.14 1999/11/06 05:25:14 lindberg Exp $*/ +/*$Name: ezmlm-idx-040 $*/ + +#include "stralloc.h" +#include "strerr.h" +#include "case.h" +#include "byte.h" +#include "errtxt.h" +#include "mime.h" + +static stralloc tmpdata = {0}; + +static int trimre(cpp,cpend,prefix,fatal) +char **cpp; +char *cpend; +stralloc *prefix; +char *fatal; + +{ + int r = 0; + register char *cp; + char *cpnew; + int junk; + unsigned int i,j; + unsigned int serial; + + cp = *cpp; + serial = prefix->len; /* pointer to serial number */ + if (serial) + serial = byte_rchr(prefix->s,prefix->len,'#'); + + junk = 1; + while (junk) { + junk = 0; + while (cp <= cpend && (*cp == ' ' || *cp == '\t')) cp++; + cpnew = cp; + while (++cpnew <= cpend) { /* /(..+:\s)/ is a reply indicator */ + if (*cpnew == ' ') { + if (cpnew < cp + 3) break; /* at least 3 char before ' ' */ + if (*(cpnew - 1) != ':') break; /* require ':' before ' ' */ + if (cpnew > cp + 5) { /* if > 4 char before ':' require */ + register char ch; + ch = *(cpnew - 2); /* XX^3, XX[3], XX(3) */ + if (ch != ')' && ch != ']' && (ch < '0' || ch > '9')) + break; + } + junk = 1; + r |= 1; + cp = cpnew + 1; + break; + } + } + /* prefix removal is complicated by the inconsistent handling of ' ' */ + /* when there are rfc2047-encoded words in the subject. We first */ + /* compare prefix before "serial" ignoring space, then skip the */ + /* number, then compare after "serial". If both matched we've found */ + /* the prefix. */ + if (serial) { + cpnew = cp; + i = 0; + while (i < serial && cpnew <= cpend) { + if (*cpnew != ' ') { + if (prefix->s[i] == ' ') { + ++i; + continue; + } + if (*cpnew != prefix->s[i]) break; + ++i; + } + ++cpnew; + } + if (i == serial) { /* match before serial */ + j = prefix->len; + if (serial != j) { /* got a '#' */ + while (cpnew <= cpend && /* skip number/space */ + *cpnew == ' ' || (*cpnew <= '9' && *cpnew >= '0')) ++cpnew; + i = serial + 1; + while (i < j && cpnew <= cpend) { + if (*cpnew != ' ') { + if (prefix->s[i] == ' ') { + ++i; + continue; + } + if (*cpnew != prefix->s[i]) break; + ++i; + } + ++cpnew; + } + } + if (i == j) { + cp = cpnew; + junk = 1; + r |= 2; + } + } + } + } + *cpp = cp; + return r; +} + +static int trimend(indata,np,fatal) +char *indata; +unsigned int *np; +char *fatal; + /* looks at indata of length n from the end removing LWSP & '\n' */ + /* and any trailing '-Reply'. Sets n to new length and returns: */ + /* 0 - not reply, 1 - reply. */ +{ + char *cplast; + int junk; + int r = 0; + + if (*np == 0) return 0; + cplast = indata + *np - 1; /* points to last char on line */ + junk = 1; + while (junk) { + junk = 0; + while (cplast >= indata && + (*cplast == ' ' || *cplast == '\t' || + *cplast == '\r' || *cplast == '\n')) + --cplast; + if (cplast - indata >= 5 && case_startb(cplast - 5,6,"-Reply")) { + cplast -= 6; + r = 1; + junk = 1; + } + } + *np = (unsigned int) (cplast - indata + 1); /* new length */ + return r; +} + +int unfoldHDR(indata,n,outdata,charset,prefix,flagtrimsub,fatal) +char *indata; +unsigned int n; +stralloc *outdata; +char *charset; +stralloc *prefix; +int flagtrimsub; +char *fatal; + /* takes a header as indata. Removal of reply-indicators is done */ + /* but removal of line breaks and Q and B decoding should have */ + /* been done. Returns a */ + /* single line header without trailing \n or \0. Mainly, we */ + /* remove redundant shift codes */ + /* returns 0 = no reply no prefix */ + /* 1 = reply no prefix */ + /* 2 = no reply, prefix */ + /* 3 = reply & pefix */ +{ + int r = 0; + char *cp,*cpesc,*cpnext,*cpend,*cpout; + char state,cset,newcset; + int reg,newreg; + + cp = indata; /* JIS X 0201 -> ISO646 us-ascii */ + cpend = cp + n - 1; + cpnext = cp; + if (!stralloc_copys(&tmpdata,"")) die_nomem(fatal); + if (!stralloc_ready(&tmpdata,n)) die_nomem(fatal); + + if(!case_diffb(charset,11,"iso-2022-jp")) { + /* iso-2022-jp-2 (rfc1554) and its subset iso-2022-jp. The reg #s */ + /* are from the rfc. Don't ask why they have multiple length G0 */ + /* charset designations ... JIS X 0201-roman is identical to */ + /* iso646 us-ascii except for currency and tilde. Making them the */ + /* same increases hits without significant loss. JIS X 0208-1978 */ + /* is superceded by JIS X 0208-1983 and converted here as well. */ + + while (cp < cpend) { + if (*cp++ != ESC) continue; + if (*cp == '(') { + if (++cp > cpend) break; + if (*cp == 'J') *cp = 'B'; + ++cp; + } else if (*cp == '$') { + if (++cp > cpend) break; + if (*cp == '@') *cp = 'B'; + ++cp; + } + } + /* eliminate redundant ESC seqs */ + cp = indata; + cpnext = cp; + reg = 6; + while (cp < cpend) { + if (*cp++ != ESC) continue; + cpesc = cp - 1; + if (*cp == '$') { + if (++cp > cpend) break; + if (*cp == 'B') newreg = 87; + else if (*cp == 'A') newreg = 58; + else if (*cp == '(') { + if (++cp > cpend) break; + if (*cp == 'C') newreg = 149; + else if (*cp == 'D') newreg = 159; + else continue; + } else continue; + } else if (*cp == '(') { + if (++cp > cpend) break; + if (*cp == 'B') newreg = 6; + else continue; + } else continue; + if (++cp > cpend) break; + while (*cp == ' ' || *cp == '\t') + if (++cp >= cpend) break; /* skip space */ + if (*cp == ESC) /* maybe another G0 designation */ + if (*(cp+1) == '(' || *(cp+1) == '$') { /* yep! */ + if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal); + cpnext = cp; + continue; + } + if (reg == newreg) { + if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal); + cpnext = cp; + } else { + reg = newreg; + } /* copy remainder of line */ + } + if (!stralloc_catb(&tmpdata,cpnext,cpend - cpnext + 1)) die_nomem(fatal); + if (reg != 6) { /* need to return to us-ascii at the end of the line */ + if (!stralloc_cats(&tmpdata,TOASCII)) die_nomem(fatal); + } else { /* maybe "-Reply at the end?" */ + r = trimend(tmpdata.s,&(tmpdata.len),fatal); + } + + } else if (!case_diffb(charset,11,"iso-2022-cn") || + !case_diffb(charset,11,"iso-2022-kr")) { + /* these use SI/SO and ESC $ ) x as the SO designation. In -cn and */ + /* -cn-ext, 'x' can be a number of different letters. In -kr it's */ + /* always 'C'. This routine may work also for other iso-2022 sets */ + /* also handles iso-2022-cn-ext */ + cpesc = (char *) 0; /* points to latest ESC */ + state = SI; /* us-ascii */ + --cp; /* set up for loop */ + + while (++cp <= cpend) { + if (*cp == SI || *cp == SO) { + if (state == *cp) { /* already in state. Skip shift seq */ + if (!stralloc_catb(&tmpdata,cpnext,cp-cpnext-1)) die_nomem(fatal); + cpnext = cp; + } else /* set new state */ + state = *cp; + if (++cp > cpend) break; + continue; + } + if (*cp != ESC) continue; + if (cp + 3 > cpend) break; /* not space for full SO-designation */ + cpesc = cp; + if (*cp != '$') continue; + if (++cp > cpend) break; + if (*cp != ')') continue; + if (++cp > cpend) break; + newcset = *cp; + if (++cp > cpend) break; + while (cp <= cpend && (*cp == ' ' || *cp == '\t')) ++cp; + if (cp + 3 > cpend) break; /* no space for full SO-designation */ + if ((*cp == ESC && *(cp+1) == '$' && *(cp+2) == ')') + || (newcset == cset)) { + /* skip if a second SO-designation right after or */ + /* this SO-designation is already active, skip */ + if (!stralloc_catb(&tmpdata,cpnext,cpesc-cpnext)) die_nomem(fatal); + --cp; /* "unpeek" so that next iteration will see char */ + cpnext = cpesc + 4; + continue; + } else { + cset = newcset; + continue; + } + } + /* get remainder of line */ + if (!stralloc_catb(&tmpdata,cpnext,cpend - cpnext + 1)) die_nomem(fatal); + if (state != SI) /* need to end in ascii */ + if (!stralloc_cats(&tmpdata,TOSI)) die_nomem(fatal); + else /* ascii end; maybe "-Reply" at the end? */ + r = trimend(tmpdata.s,&(tmpdata.len),fatal); + + } else { /* other character sets = no special treatment */ + r = trimend(cp,&n,fatal); /* -reply */ + if (!stralloc_copyb(&tmpdata,cp,n)) die_nomem(fatal); + } + + cp = tmpdata.s; + n = tmpdata.len; + cpend = cp + n - 1; + if (flagtrimsub) { /* remove leading reply indicators & prefix*/ + r |= trimre(&cp,cpend,prefix,fatal); + n = (unsigned int) (cpend-cp+1); + } + /* there shouldn't be '\0' or '\n', but make sure as */ + /* it would break the message index */ + if (!stralloc_copys(outdata,"")) die_nomem(fatal); + if (!stralloc_ready(outdata,n)) die_nomem(fatal); + outdata->len = n; + cpout = outdata->s; + while (n--) { /* '\n' and '\0' would break the subject index */ + if (!*cp || *cp == '\n') *cpout = ' '; + else *cpout = *cp; + ++cp; ++cpout; + } + return r; +} + diff --git a/yyyymm.h b/yyyymm.h new file mode 100644 index 0000000..ffbf6b8 --- /dev/null +++ b/yyyymm.h @@ -0,0 +1,15 @@ +#ifndef YYYYMM_H +#define YYYYMM_H + +#ifdef WITH_PROTO +#include "stralloc.h" + +extern unsigned int date2yyyymm(char *); +extern int dateline(stralloc *, unsigned long); +#else +extern unsigned int date2yyyymm(); +extern int dateline(); +#endif + +#endif +